[Checkins] SVN: Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/ ongoing spike: integration of PlainLoginDemo code

Luciano Ramalho luciano at ramalho.org
Mon Feb 18 21:13:39 EST 2008


Log message for revision 84042:
  ongoing spike: integration of PlainLoginDemo code
  

Changed:
  U   Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/__init__.py
  A   Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/configure.zcml
  A   Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/directives.py
  A   Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/form.pt
  A   Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views.py
  A   Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/
  A   Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/index.pt
  A   Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/listing.pt
  A   Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/login.pt
  A   Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/master.pt

-=-
Modified: Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/__init__.py
===================================================================
--- Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/__init__.py	2008-02-19 00:34:52 UTC (rev 84041)
+++ Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/__init__.py	2008-02-19 02:13:37 UTC (rev 84042)
@@ -0,0 +1,2 @@
+from megrok.simpleauth.directives import setup_authentication_if_it_pleases_you_mr_grok 
+import views
\ No newline at end of file

Added: Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/configure.zcml
===================================================================
--- Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/configure.zcml	                        (rev 0)
+++ Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/configure.zcml	2008-02-19 02:13:37 UTC (rev 84042)
@@ -0,0 +1,5 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:grok="http://namespaces.zope.org/grok">
+  <include package="megrok.simpleauth" />
+  <grok:grok package="." />
+</configure>

Added: Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/directives.py
===================================================================
--- Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/directives.py	                        (rev 0)
+++ Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/directives.py	2008-02-19 02:13:37 UTC (rev 84042)
@@ -0,0 +1,34 @@
+from zope.app.authentication import PluggableAuthentication
+from zope.app.security.interfaces import IAuthentication
+from zope.app.authentication.principalfolder import PrincipalFolder
+from zope.app.authentication.session import SessionCredentialsPlugin
+
+from grok.directive import MultipleTimesDirective, ClassDirectiveContext, LocalUtilityInfo
+
+def setup_pau(pau):
+    '''
+    Callback to setup the Pluggable Authentication Utility
+    
+    A reference to this function is passed as a parameter in the
+    declaration of the PAU (see PlainLoginDemo class)
+    '''
+    # the principal source is a PrincipalFolder, stored in ZODB
+    pau['principals'] = PrincipalFolder() 
+    pau.authenticatorPlugins = ('principals',)
+    # the SessionCredentialsPlugin isused for cookie-based authentication
+    pau['session'] = session = SessionCredentialsPlugin()
+    session.loginpagename = 'login' # the page to redirect for login
+    # configuration of the credentials plugin
+    pau.credentialsPlugins = ('No Challenge if Authenticated', 'session',)
+
+class SetupAuthenticationDirective(MultipleTimesDirective):
+    def check_arguments(self):
+        pass
+        
+    def value_factory(self):
+        
+        return LocalUtilityInfo(PluggableAuthentication, provides=IAuthentication, name=u'',
+                     setup=setup_pau, public=False, name_in_container=None)
+    
+setup_authentication_if_it_pleases_you_mr_grok = SetupAuthenticationDirective('grok.local_utility',
+                                      ClassDirectiveContext())
\ No newline at end of file

Added: Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/form.pt
===================================================================
--- Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/form.pt	                        (rev 0)
+++ Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/form.pt	2008-02-19 02:13:37 UTC (rev 84042)
@@ -0,0 +1,75 @@
+<html metal:use-macro="context/@@master/macros/page">
+<body>
+    
+    <div metal:fill-slot="main">
+
+<!-- the code of the form element below was copied verbatim from
+     src/grok/templates/default_edit_form.pt-->
+<!-- XXX: is a better way of rendering Groks's default forms inside
+     a master template?-->
+
+<form action="." tal:attributes="action request/URL" method="post"
+      class="edit-form" enctype="multipart/form-data">
+
+  <h1 i18n:translate=""
+    tal:condition="view/label"
+    tal:content="view/label">Label</h1>
+
+  <div class="form-status"
+    tal:define="status view/status"
+    tal:condition="status">
+
+    <div i18n:translate="" tal:content="view/status">
+      Form status summary
+    </div>
+
+    <ul class="errors" tal:condition="view/errors">
+      <li tal:repeat="error view/error_views">
+         <span tal:replace="structure error">Error Type</span>
+      </li>
+    </ul>
+  </div>
+
+  <table class="form-fields">
+    <tbody>
+      <tal:block repeat="widget view/widgets">
+        <tr>
+          <td class="label" tal:define="hint widget/hint">
+            <label tal:condition="python:hint"
+                   tal:attributes="for widget/name">
+              <span class="required" tal:condition="widget/required"
+              >*</span><span i18n:translate=""
+                             tal:content="widget/label">label</span>
+            </label>
+            <label tal:condition="python:not hint"
+                   tal:attributes="for widget/name">
+              <span class="required" tal:condition="widget/required"
+              >*</span><span i18n:translate=""
+                             tal:content="widget/label">label</span>
+            </label>
+          </td>
+          <td class="field">
+            <div class="widget" tal:content="structure widget">
+              <input type="text" />
+            </div>
+            <div class="error" tal:condition="widget/error">
+              <span tal:replace="structure widget/error">error</span>
+            </div>
+          </td>
+        </tr>
+      </tal:block>
+    </tbody>
+  </table>
+
+  <div id="actionsView">
+    <span class="actionButtons" tal:condition="view/availableActions">
+      <input tal:repeat="action view/actions"
+             tal:replace="structure action/render"
+             />
+    </span>
+  </div>
+</form>
+
+    </div><!--/slot main-->
+</body>
+</html>

Added: Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views.py
===================================================================
--- Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views.py	                        (rev 0)
+++ Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views.py	2008-02-19 02:13:37 UTC (rev 84042)
@@ -0,0 +1,179 @@
+import grok
+
+from urllib import urlencode
+
+from zope.interface import Interface, implements
+from zope.component import getUtility, getUtilitiesFor
+from zope.app.authentication import PluggableAuthentication
+from zope.app.authentication.interfaces import IPasswordManager
+from zope.app.authentication.principalfolder import PrincipalFolder
+from zope.app.authentication.principalfolder import InternalPrincipal
+from zope.app.authentication.principalfolder import IInternalPrincipal
+from zope.app.authentication.session import SessionCredentialsPlugin
+from zope.app.container.interfaces import DuplicateIDError
+from zope.app.security.interfaces import IAuthentication
+from zope.app.security.interfaces import IUnauthenticatedPrincipal
+from zope.app.form.browser import RadioWidget, TextWidget
+from zope.security.management import checkPermission
+from zope.app.securitypolicy.interfaces import IPrincipalPermissionManager
+from zope.schema import getFieldNamesInOrder, ValidationError
+from zope.schema.interfaces import IField, IIterableSource
+from zope.i18n import MessageFactory
+
+_ = MessageFactory('megrok.simpleauth')
+
+class ViewMemberListing(grok.Permission):
+    ''' Permission to see the member listing '''
+    grok.name('plainlogindemo.ViewMemberListing')
+
+class Master(grok.View):
+    """
+    The master page template macro.
+    
+    The template master.pt is used as page macro in most views. Since this
+    template uses the logged_in method and message attributes below, it's best
+    to make all other views in this app subclasses of Master.
+    """
+    grok.context(Interface)  # register this view for all objects
+
+    message = '' # used to give feedback
+
+    def logged_in(self):
+        # this is the canonical way to tell whether the user is authenticated
+        # in Zope 3: check if the principal provides IUnauthenticatedPrincipal
+        return not IUnauthenticatedPrincipal.providedBy(self.request.principal)
+    
+class Index(Master):
+    """
+    The main page, showing user data and member count.
+    """
+
+    def member_count(self):
+        # get the authentication utility
+        pau = getUtility(IAuthentication)
+        return len(pau['principals'])
+
+    
+class Login(Master):
+    """
+    Login form and handler.
+    """
+    def update(self, login_submit=None):
+        if login_submit is not None: # we are handling the login submission
+            if self.logged_in(): # if the login was accepted then...
+                # redirect to where the user came from, or to the main page
+                dest = self.request.get('camefrom', self.application_url())
+                self.redirect(dest)
+            else: # if the user is still not logged in...
+                # then an incorrect login or password was provided
+                self.message = _(u'Invalid login name and/or password')
+
+class Logout(grok.View):
+    """
+    Logout handler.
+    """
+    grok.context(Interface)
+    def render(self):
+        # get the session plugin and tell it to logout
+        session = getUtility(IAuthentication)['session']
+        session.logout(self.request)
+        # redirect to the main page
+        self.redirect(self.application_url())
+        
+class FullNameWidget(TextWidget):
+    """
+    Simple customization: change field label from 'Title' to 'Full Name',
+    which makes more sense for a user record.
+    """
+
+    label = _(u'Full Name')
+
+class PasswordManagerChoices(RadioWidget):
+    """
+    Widget to select the passwordManager in charge of hashing or encrypting
+    the user's password before storing it.
+    """
+
+    label = _(u'Password protection')
+
+    def __init__(self, field, request):
+        # the IInternalPrincipal.passwordManagerName field comes with a
+        # vocabulary which provides the available utilities providing
+        # IPasswordManager; here we just pass that vocabulary to the widget
+        super(PasswordManagerChoices, self).__init__(
+            field, field.vocabulary, request)
+        
+class Join(grok.AddForm, Master):
+    """
+    User registration form.
+    """
+
+    form_fields = grok.AutoFields(IInternalPrincipal)
+    # use our customized widgets
+    form_fields['title'].custom_widget = FullNameWidget
+    form_fields['passwordManagerName'].custom_widget = PasswordManagerChoices
+
+    label = _(u'User registration')
+    template = grok.PageTemplateFile('form.pt')
+    
+    @grok.action('Save')
+    def save(self, **data):
+        '''
+        Create an InternalPrincipal with the user data.
+        
+        This method also grants the ViewMemberListing permission to the user.
+        '''
+        login = data['login']
+        pau = getUtility(IAuthentication)
+        principals = pau['principals']
+        # create an instance of InternalPrincipal
+        principal = InternalPrincipal(**data)
+        try:
+            principals[login] = principal
+        except DuplicateIDError:
+            # create a validation exception and assign it to the login field
+            msg = _(u'Login name taken. Please choose a different one.') 
+            self.widgets['login']._error = ValidationError(msg)
+            self.form_reset = False # preserve the values in the fields
+        else:
+            # grant the user permission to view the member listing
+            permission_mngr = IPrincipalPermissionManager(grok.getSite())
+            permission_mngr.grantPermissionToPrincipal(
+               'plainlogindemo.ViewMemberListing', principals.prefix + login)
+            self.redirect(self.url('login')+'?'+urlencode({'login':login}))
+                    
+class Account(grok.View):
+    
+    def render(self):
+        return 'Not implemented'
+    
+class Listing(Master):
+    '''
+    Member listing view.
+    
+    This demonstrates how to require a permission to view, and also how to
+    obtain a list of annotated principals.
+    '''
+
+    grok.require('plainlogindemo.ViewMemberListing')
+
+    def field_names(self):        
+        return getFieldNamesInOrder(IInternalPrincipal)
+
+    def members(self):
+        pau = getUtility(IAuthentication)
+        principals = pau['principals']
+        roster = []
+        for id in sorted(principals.keys()):
+            user = principals[id]
+            fields = {}
+            for field in self.field_names():
+                fields[field] = getattr(user, field)
+            roster.append(fields)
+        return roster
+    
+    def delete_allowed(self):
+        # XXX: this is not the right way to do it... it's just a test
+        return self.request.principal.id.endswith('.manager')
+
+    
\ No newline at end of file

Added: Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/index.pt
===================================================================
--- Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/index.pt	                        (rev 0)
+++ Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/index.pt	2008-02-19 02:13:37 UTC (rev 84042)
@@ -0,0 +1,42 @@
+<html metal:use-macro="context/@@master/macros/page">
+<body>
+<div metal:fill-slot="main">
+    <h1>Login Demo Main Page</h1>
+    
+    <table><tr>
+        <td valign="top">
+            <h2>User information</h2>
+            <dl>
+                <dt>principal.id</dt>
+                    <dd tal:content="request/principal/id" />
+                
+            </dl>
+            <dl>
+                <dt>principal.title</dt>
+                    <dd tal:content="request/principal/title" />
+                
+            </dl>
+            
+            <p>
+                You are <em tal:condition="not:view/logged_in">not </em>logged in.
+            </p>
+            
+            <tal:not_logged_in condition="not:view/logged_in">
+          
+                <form metal:use-macro="context/@@login/macros/loginform" />
+                
+            </tal:not_logged_in>
+        </td>
+        <td width="30%"></td>
+        <td valign="top">
+            <h2>Membership</h2>
+            
+            <h3>Member accounts: <span tal:replace="view/member_count" /></h3>
+            
+            <p><a href="listing">View member listing</a> (requires login)</p>
+            
+        </td>
+    </tr></table>
+</div>
+</body>
+</html>

Added: Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/listing.pt
===================================================================
--- Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/listing.pt	                        (rev 0)
+++ Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/listing.pt	2008-02-19 02:13:37 UTC (rev 84042)
@@ -0,0 +1,22 @@
+<html metal:use-macro="context/@@master/macros/page">
+<body>
+<div metal:fill-slot="main">
+    <h1>Member Listing</h1>
+    
+    <table>
+        <tr><th tal:repeat="field view/field_names"
+                tal:content="field">Field name</th></tr>
+        <tr valign="top" tal:repeat="member view/members">
+            <td bgcolor="lightgray"
+                tal:repeat="field view/field_names"
+                tal:content="python:member[field]"></td>
+            <td tal:condition="view/delete_allowed">
+                <form tal:attributes="action view/url" method="post">
+                    <input type="submit" value="Delete" />
+                </form>
+            </td>
+        </tr>
+    </table>
+</div>
+</body>
+</html>

Added: Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/login.pt
===================================================================
--- Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/login.pt	                        (rev 0)
+++ Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/login.pt	2008-02-19 02:13:37 UTC (rev 84042)
@@ -0,0 +1,36 @@
+<html metal:use-macro="context/@@master/macros/page">
+<body>
+<div metal:fill-slot="main">
+    <h1>Login</h1>
+        
+    <form metal:define-macro="loginform" action="login" method="post">
+        <input type="hidden" name="camefrom"
+            tal:condition="exists:request/camefrom"
+            tal:attributes="value request/camefrom" />
+        
+        <table>
+            <tr>
+                <th>Login</th>
+                <td>
+                    <input type="text" name="login" id="login"
+                        tal:attributes="value request/login|nothing"/>
+                </td>
+            </tr>
+            <tr>
+                <th>Password</th>
+                <td>
+                    <input type="password" name="password" id="password" />
+                </td>
+            </tr>
+            <tr>
+                <td></td>
+                <td>
+                    <input type="submit" name="login_submit" value="Log in" />
+                </td>
+            </tr>
+        </table>
+    </form>
+    
+</div>  
+</body>
+</html>

Added: Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/master.pt
===================================================================
--- Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/master.pt	                        (rev 0)
+++ Sandbox/lra/megrok.simpleauth/src/megrok/simpleauth/views_templates/master.pt	2008-02-19 02:13:37 UTC (rev 84042)
@@ -0,0 +1,34 @@
+<html metal:define-macro="page">
+<head>
+<title>Grok Login Sample Application</title>
+</head>
+<body>
+    <table bgcolor="lightgray" width="100%">
+        <tr tal:condition="not:view/logged_in">
+            <td width="10%"><a href="index">main</a></td>
+            <td width="70%">you are not logged in</td>
+            <td width="10%"><a href="join">join</a></td>
+            <td width="10%"><a href="login">login</a></td>
+        </tr>
+        <tr tal:condition="view/logged_in">
+            <td width="10%"><a href="index">main</a></td>
+            <td width="70%">logged in as
+                <span tal:replace="string:${request/principal/title}
+                                         (${request/principal/id})">
+                    principal.title (principal.id)
+                </span>
+            </td>
+            <td width="10%"><a href="account">account</a></td>
+            <td width="10%"><a href="logout">logout</a></td>
+        </tr>
+    </table>
+    <div style="background: yellow;"
+         tal:condition="view/message"
+         tal:content="view/message"
+    />
+    <div metal:define-slot="main">
+    Here goes the main content of the page
+    </div>
+  
+</body>
+</html>



More information about the Checkins mailing list