[Checkins] SVN: Sandbox/ulif/grok-adminui/s Added session based
login.
Uli Fouquet
uli at gnufix.de
Tue Jul 24 08:22:49 EDT 2007
Log message for revision 78307:
Added session based login.
Changed:
U Sandbox/ulif/grok-adminui/setup.py
U Sandbox/ulif/grok-adminui/src/grok/admin/__init__.py
U Sandbox/ulif/grok-adminui/src/grok/admin/view.py
A Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/loginform.pt
U Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/macros.pt
U Sandbox/ulif/grok-adminui/src/grok/ftests/admin/apps.py
-=-
Modified: Sandbox/ulif/grok-adminui/setup.py
===================================================================
--- Sandbox/ulif/grok-adminui/setup.py 2007-07-24 11:24:41 UTC (rev 78306)
+++ Sandbox/ulif/grok-adminui/setup.py 2007-07-24 12:22:48 UTC (rev 78307)
@@ -22,6 +22,9 @@
'ZODB3',
'zope.annotation',
'zope.app.apidoc',
+ 'zope.app.applicationcontrol',
+ 'zope.app.appsetup',
+ 'zope.app.authentication',
'zope.app.catalog',
'zope.app.component',
'zope.app.container',
@@ -31,7 +34,11 @@
'zope.app.publication',
'zope.app.publisher',
'zope.app.renderer',
+ 'zope.app.security',
+ 'zope.app.securitypolicy',
'zope.app.testing',
+ 'zope.app.twisted',
+ 'zope.app.zcmlfiles',
'zope.component',
'zope.configuration',
'zope.dottedname',
@@ -41,15 +48,13 @@
'zope.interface',
'zope.lifecycleevent',
'zope.pagetemplate',
+ 'zope.proxy',
'zope.publisher',
'zope.schema',
'zope.security',
'zope.testing',
'zope.traversing',
'zope.testbrowser',
- 'zope.app.twisted',
- 'zope.app.securitypolicy',
- 'zope.app.zcmlfiles',
'zc.catalog',
'z3c.flashmessage >=1.0dev-r77761',
],
Modified: Sandbox/ulif/grok-adminui/src/grok/admin/__init__.py
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/__init__.py 2007-07-24 11:24:41 UTC (rev 78306)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/__init__.py 2007-07-24 12:22:48 UTC (rev 78307)
@@ -1 +1,131 @@
-#make this a package
+"""Initialize grok admin application.
+
+The grok admin application provides a session based login, which
+eventually must be enabled using Pluggable Authentication
+Utilities. This is done here.
+"""
+
+from zope.component import adapter, provideHandler
+from zope.app.appsetup.interfaces import IDatabaseOpenedWithRootEvent
+
+
+def getPrincipalCredentialsFromZCML():
+ """Read all principals' attributes from site.zcml.
+ """
+ import xml.sax
+ from zope.app.appsetup.appsetup import getConfigSource
+
+ class SAXPrincipalFinder(xml.sax.ContentHandler):
+ """Parse an XML file and get attributes of ``principal`` tags.
+
+ The principal tags of site.xml contain the credentials of
+ principals as attributes. The attributes usually are 'id',
+ 'login', 'password', 'title' and other more. And usually only
+ one pricipal is defined: the manager.
+ """
+ result = []
+
+ def startElement(self, name, attrs):
+ if name != 'principal':
+ return
+ self.result.append(dict(attrs.copy()))
+
+ site_zcml_file = getConfigSource()
+ principal_finder = SAXPrincipalFinder()
+ xml.sax.parse(site_zcml_file, principal_finder)
+ return principal_finder.result
+
+
+def setupSessionAuthentication(root_folder=None,
+ principal_credentials=[{u'id': u'zope.manager',
+ u'login': u'grok',
+ u'password': u'grok',
+ u'title': u'Manager'
+ }],
+ auth_foldername=u'authentication',
+ userfolder_name=u'Users',
+ userfolder_prefix=u'grokadmin'
+ ):
+ """Add session authentication PAU to root_folder.
+
+ Add a PluggableAuthentication in site manager of
+ root_folder. ``auth_foldername`` gives the name of the PAU to
+ install, userfolder_prefix the prefix of the authenticator plugin
+ (a simple ``PrincipalFolder``), which will be created in the PAU
+ and gets name ``userfolder_name``. ``principal_credentials`` is a
+ list of dicts with, well, principal_credentials. The keys ``id``,
+ ``login``, ``password`` and ``title`` are required for each
+ element of this list.
+ """
+ from zope.component import getUtilitiesFor
+ from zope.security.proxy import removeSecurityProxy
+ from zope.app.security.interfaces import IAuthentication
+ from zope.app.securitypolicy.interfaces import IPrincipalRoleManager
+ from zope.app.securitypolicy.interfaces import IRole
+ from zope.app.authentication import PluggableAuthentication
+ from zope.app.authentication.interfaces import IAuthenticatorPlugin
+ from zope.app.authentication.principalfolder import PrincipalFolder
+ from zope.app.authentication.principalfolder import InternalPrincipal
+
+ sm = root_folder.getSiteManager()
+ if auth_foldername in sm.keys():
+ # There is already a folder of this name.
+ return
+
+ pau = PluggableAuthentication()
+ users = PrincipalFolder(userfolder_prefix)
+
+ # Add users into principals folder to enable login...
+ for user in principal_credentials:
+ # XXX make sure, the keys exist...
+ user['id'] = user['id'].rsplit('.',1)[-1]
+ user_title = user['title']
+ principal = InternalPrincipal(user['login'],
+ user['password'],
+ user['title'])
+ users[user['id']] = principal
+
+ # Configure the PAU...
+ pau.authenticatorPlugins = (userfolder_name,)
+ pau.credentialsPlugins = ("No Challenge if Authenticated",
+ "Session Credentials")
+
+ # Add the pau and its plugin to the root_folder...
+ sm[auth_foldername] = pau
+ sm[auth_foldername][userfolder_name] = users
+ pau.authenticatorPlugins = (users.__name__,)
+
+ # Register the PAU with the site...
+ sm.registerUtility(pau, IAuthentication)
+ sm.registerUtility(users, IAuthenticatorPlugin, name=userfolder_name)
+
+ # Add manager roles to new users...
+ # XXX the real roles could be obtained from site.zcml.
+ role_ids = [name for name, util in getUtilitiesFor(IRole, root_folder)]
+ user_ids = [users.prefix + p['id'] for p in principal_credentials]
+ role_manager = IPrincipalRoleManager(root_folder)
+ role_manager = removeSecurityProxy(role_manager)
+ for role in role_ids:
+ for user_id in user_ids:
+ role_manager.assignRoleToPrincipal(role,user_id)
+
+
+
+# If a new database is created, initialize a session based
+# authentication.
+#
+# First create an eventhandler `adminSetup`, that is
+# called, whenever a database is opened...
+ at adapter(IDatabaseOpenedWithRootEvent)
+def adminSetup(event):
+ from zope.app.appsetup.bootstrap import getInformationFromEvent
+
+ db, connection, root, root_folder = getInformationFromEvent(event)
+ principal_credentials = getPrincipalCredentialsFromZCML()
+ setupSessionAuthentication(root_folder = root_folder,
+ principal_credentials = principal_credentials)
+
+
+# ...then install the event handler:
+provideHandler(adminSetup)
+
Modified: Sandbox/ulif/grok-adminui/src/grok/admin/view.py
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view.py 2007-07-24 11:24:41 UTC (rev 78306)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view.py 2007-07-24 12:22:48 UTC (rev 78307)
@@ -25,6 +25,7 @@
from zope.app.apidoc.codemodule.text import TextFile
from zope.app.apidoc.codemodule.zcml import ZCMLFile
+from zope.app.security.interfaces import IUnauthenticatedPrincipal
from zope.proxy import removeAllProxies
@@ -202,6 +203,28 @@
self.redirect(self.url('applications'))
+class loginForm(GAIAView):
+ """A login screen for session based authentication.
+
+ To activate loginForm, i.e. session based authentication, an
+ appropriate PluggableAuthenticationUtility (PAU) must be set up in
+ the applications root folder (which happens here to be the global
+ root folder). The setup is done for the admin app in __init__.py.
+ """
+ # 'loginForm.html' is the page template name, that standard
+ # session based authentication looks for. The form must provide an
+ # input field 'login' for the username and another input field
+ # 'password'.
+ grok.name('loginForm.html')
+
+ def update(self, login=None, password=None, camefrom=None):
+ request = self.request
+ if (not IUnauthenticatedPrincipal.providedBy(request.principal)):
+ camefrom = request.get('camefrom', '.')
+ self.redirect(camefrom)
+ return
+
+
class Applications(GAIAView):
"""View for application management."""
Added: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/loginform.pt
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/loginform.pt (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/loginform.pt 2007-07-24 12:22:48 UTC (rev 78307)
@@ -0,0 +1,32 @@
+<html metal:use-macro="context/@@macros/gaia-page">
+ <head>
+ <title metal:fill-slot="title">Grok Login</title>
+ </head>
+ <body>
+ <div metal:fill-slot="menu-links" />
+ <div metal:fill-slot="content">
+ <h1>Welcome to Grok</h1>
+ <form method="post">
+ <fieldset>
+ <legend>Login</legend>
+
+ <table>
+ <tr>
+ <td><label for="login">Username:</label></td>
+ <td><input id="login" type="text" name="login" /></td>
+ </tr>
+ <tr>
+ <td><label for="password">Password:</label></td>
+ <td><input id="password" type="password" name="password" /></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td><input type="submit" value="Login"/></td>
+ </tr>
+ </table>
+
+ </fieldset>
+ </form>
+ </div>
+ </body>
+</html>
\ No newline at end of file
Modified: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/macros.pt
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/macros.pt 2007-07-24 11:24:41 UTC (rev 78306)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/macros.pt 2007-07-24 12:22:48 UTC (rev 78307)
@@ -28,7 +28,9 @@
<img alt="grok_relax_image" src="images/grok-relax5.gif"
tal:attributes="src view/static/grok-relax5.gif" />
</div>
- <div id="menu-links" tal:define="currview python:view.url()">
+ <div id="menu-links"
+ metal:define-slot="menu-links"
+ tal:define="currview python:view.url()">
<span class="menu-link-inactive"
tal:define="target string:${view/root_url}/applications">
<a href="applications"
Modified: Sandbox/ulif/grok-adminui/src/grok/ftests/admin/apps.py
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/ftests/admin/apps.py 2007-07-24 11:24:41 UTC (rev 78306)
+++ Sandbox/ulif/grok-adminui/src/grok/ftests/admin/apps.py 2007-07-24 12:22:48 UTC (rev 78307)
@@ -1,15 +1,64 @@
"""
-
-We fetch the standard page, which should provide us a menu to get all
-installable grok applications/components.
>>> import grok
>>> grok.grok('grok.ftests.admin.apps')
+First setup the pluggable authentication system for session based
+authentication. This is normaly invoked by an event
+handler. Unfortunately the event handler seems not to be called, if
+the ftesting setup is set up. We therefore set up the PAU manually.
+
+ >>> root = getRootFolder()
+ >>> root is not None
+ True
+
+ >>> import grok.admin
+ >>> principal_credentials = grok.admin.getPrincipalCredentialsFromZCML()
+ >>> principal_credentials
+ [{u'login': u'mgr', u'password': u'mgrpw', u'id': u'zope.mgr', u'title': u'Manager'}]
+
+ >>> grok.admin.setupSessionAuthentication(root_folder = root, principal_credentials = principal_credentials)
+
+We should get a login page if trying to get something unauthenticated.
+
>>> from zope.testbrowser.testing import Browser
>>> browser = Browser()
+ >>> browser.handleErrors = True
+ >>> browser.open("http://localhost/")
+
+ >>> print browser.contents
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ ... <title>Grok Login</title>
+ ...
+
+Now try to log in using *wrong* credentials
+
+ >>> browser.getControl(name='login').value = 'dumbtry'
+ >>> browser.getControl('Login').click()
+ >>> print browser.contents
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ ... <title>Grok Login</title>
+ ...
+
+Okay, we got the login screen again. What about the correct credentials?
+
+ >>> browser.getControl(name='login').value = 'mgr'
+ >>> browser.getControl(name='password').value = 'mgrpw'
+ >>> browser.getControl('Login').click()
+ >>> print browser.contents
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ ... <title>grok administration interface</title>
+ ...
+
+Fine. Now we are authorized and can do, whatever we want. To stay
+authenticated, we set a header here.
+
>>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
- >>> browser.handleErrors = False
+
+
+We fetch the standard page, which should provide us a menu to get all
+installable grok applications/components.
+
>>> browser.open("http://localhost/")
>>> print browser.contents
<html xmlns="http://www.w3.org/1999/xhtml">
More information about the Checkins
mailing list