[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/authentication/
Removed factory methods from authenticators. The PAU is now
using the factory adapters directly.
Garrett Smith
garrett at mojave-corp.com
Tue Mar 29 17:07:44 EST 2005
Log message for revision 29722:
Removed factory methods from authenticators. The PAU is now using the factory adapters directly.
Changed:
U Zope3/trunk/src/zope/app/authentication/README.txt
U Zope3/trunk/src/zope/app/authentication/authentication.py
U Zope3/trunk/src/zope/app/authentication/groupfolder.py
U Zope3/trunk/src/zope/app/authentication/interfaces.py
U Zope3/trunk/src/zope/app/authentication/principalfolder.py
U Zope3/trunk/src/zope/app/authentication/tests.py
-=-
Modified: Zope3/trunk/src/zope/app/authentication/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/authentication/README.txt 2005-03-29 20:07:16 UTC (rev 29721)
+++ Zope3/trunk/src/zope/app/authentication/README.txt 2005-03-29 22:07:44 UTC (rev 29722)
@@ -3,7 +3,7 @@
================================
The Pluggable-Authentication Utility (PAU) provides a framework for
-authenticating principals and associating information with them. It uses
+authenticating principals and associating information with them. It uses
plugins and subscribers to get its work done.
Authentication
@@ -13,11 +13,11 @@
plug-ins in its work:
- Credentials Plugins
-
+
- Authenticator Plugins
-
-Credentials plugins are responsible for extracting user credentials from a
-request. A credentials plugin may in some cases issue a 'challenge' to obtain
+
+Credentials plugins are responsible for extracting user credentials from a
+request. A credentials plugin may in some cases issue a 'challenge' to obtain
credentials. For example, a 'session' credentials plugin reads credentials
from a session (the "extraction"). If it cannot find credentials, it will
redirect the user to a login form in order to provide them (the "challenge").
@@ -26,12 +26,12 @@
extracted by a credentials plugin. They are also typically able to create
principal objects for credentials they successfully authenticate.
-Given a request object, the PAU returns a principal object, if it can. The PAU
+Given a request object, the PAU returns a principal object, if it can. The PAU
does this by first iterateing through its credentials plugins to obtain a
set of credentials. If it gets credentials, it iterates through its
authenticator plugins to authenticate them.
-If an authenticator succeeds in authenticating a set of credentials, the PAU
+If an authenticator succeeds in authenticating a set of credentials, the PAU
uses the authenticator to create a principal corresponding to the credentials.
The authenticator notifies subscribers if an authenticated princiapl is created.
Subscribers are responsible for adding data, especially groups, to the
@@ -77,13 +77,13 @@
... if credentials == 'secretcode':
... return principalfolder.PrincipalInfo('bob', 'Bob', '')
...
- ... def createAuthenticatedPrincipal(self, info, request):
+ ... def createAuthenticatedPrincipal_XXX(self, info, request):
... principal = principalfolder.Principal(info.id)
... notify(interfaces.AuthenticatedPrincipalCreated(
... principal, info, request))
... return principal
...
- ... def createFoundPrincipal(self, info):
+ ... def createFoundPrincipal_XXX(self, info):
... principal = principalfolder.Principal(info.id)
... notify(interfaces.FoundPrincipalCreated(principal, info))
... return principal
@@ -96,6 +96,21 @@
>>> provideUtility(MyAuthenticatorPlugin(), name='My Authenticator Plugin')
+Principal Factories
+-------------------
+While authenticator plugins provide principal info, they are not responsible
+for creating principals. This function is performed by factory adapters. For
+these tests we will register factories for creating both 'authenticated'
+principals:
+
+ >>> provideAdapter(principalfolder.AuthenticatedPrincipalFactory)
+
+and 'found' principals:
+
+ >>> provideAdapter(principalfolder.FoundPrincipalFactory)
+
+For more information on these factories, see their docstrings.
+
Configuring a PAU
-----------------
Finally, we'll create the PAU itself:
@@ -247,13 +262,13 @@
credentials. Specifically, the PAU went through these steps:
- Get credentials using 'Form Credentials Plugin'
-
- - Got 'hiddenkey' credentials using 'Form Credentials Plugin', try to
+
+ - Got 'hiddenkey' credentials using 'Form Credentials Plugin', try to
authenticate using 'My Authenticator Plugin'
-
+
- Failed to authenticate 'hiddenkey' with 'My Authenticator Plugin', try
'My Authenticator Plugin 2'
-
+
- Succeeded in authenticating with 'My Authenticator Plugin 2'
Let's try a different scenario:
@@ -264,13 +279,13 @@
In this case, the PAU went through these steps:
- Get credentials using 'Form Credentials Plugin'
-
+
- Failed to get credentials using 'Form Credentials Plugin', try
'My Credentials Plugin'
-
+
- Got 'scecretcode' credentials using 'My Credentials Plugin', try to
authenticate using 'My Authenticator Plugin'
-
+
- Succeeded in authenticating with 'My Authenticator Plugin'
Let's try a slightly more complex scenario:
@@ -282,7 +297,7 @@
This highlights PAU's ability to use multiple plugins for authentication:
- Get credentials using 'Form Credentials Plugin'
-
+
- Got 'bogusvalue' credentials using 'Form Credentials Plugin', try to
authenticate using 'My Authenticator Plugin'
@@ -294,10 +309,10 @@
plugin for some new credentials
- Get credentials using 'My Credentials Plugin'
-
+
- Got 'hiddenkey' credentials using 'My Credentials Plugin', try to
authenticate using 'My Authenticator Plugin'
-
+
- Failed to authenticate 'hiddenkey' using 'My Authenticator Plugin', try
'My Authenticator Plugin 2'
@@ -309,16 +324,16 @@
===================
As a component that provides IAuthentication2, a PAU lets you lookup a
-principal with a principal ID. The PAU looks up a principal by delegating to
+principal with a principal ID. The PAU looks up a principal by delegating to
its authenticators. In out example, none of the authenticators implement this
search capability, so when we look for a principal:
>>> print pau.getPrincipal('bob')
None
-
+
>>> print pau.getPrincipal('white')
None
-
+
>>> print pau.getPrincipal('black')
None
@@ -342,13 +357,13 @@
... if id is not None:
... return self.infos[id]
...
- ... def createAuthenticatedPrincipal(self, info, request):
+ ... def createAuthenticatedPrincipal_XXX(self, info, request):
... principal = principalfolder.Principal(info.id)
... notify(interfaces.AuthenticatedPrincipalCreated(
... principal, info, request))
... return principal
...
- ... def createFoundPrincipal(self, info):
+ ... def createFoundPrincipal_XXX(self, info):
... principal = principalfolder.Principal(info.id)
... notify(interfaces.FoundPrincipalCreated(principal, info))
... return principal
@@ -364,7 +379,7 @@
are less typical.
As with any plugin, we need to register it as a utility:
-
+
>>> searchable = SearchableAuthenticatorPlugin()
>>> provideUtility(searchable, name='Searchable Authentication Plugin')
@@ -403,11 +418,11 @@
True
>>> event.info
PrincipalInfo('white')
-
+
As we have seen with authenticated principals, it is common to subscribe to
principal created events to add information to the newly created principal.
In this case, we need to subscribe to IFoundPrincipalCreated events:
-
+
>>> subscribe([interfaces.IFoundPrincipalCreated], None, add_info)
Now when a principal is created as a result of a search, it's title and
@@ -471,10 +486,10 @@
functionality is driven by the following use case:
- A user attempts to perform an operation he is not authorized to perform.
-
+
- A handler responds to the unauthorized error by calling IAuthentication2
'unauthorized'.
-
+
- The authentication component (in our case, a PAU) issues a challenge to
the user to collect new credentials (typically in the form of logging in
as a new user).
@@ -482,7 +497,7 @@
The PAU handles the credentials challenge by delegating to its credentials
plugins.
-Currently, the PAU is configured with the credentials plugins that don't
+Currently, the PAU is configured with the credentials plugins that don't
perform any action when asked to challenge (see above the 'challenge' methods).
To illustrate challenges, we'll subclass an existing credentials plugin and
Modified: Zope3/trunk/src/zope/app/authentication/authentication.py
===================================================================
--- Zope3/trunk/src/zope/app/authentication/authentication.py 2005-03-29 20:07:16 UTC (rev 29721)
+++ Zope3/trunk/src/zope/app/authentication/authentication.py 2005-03-29 22:07:44 UTC (rev 29722)
@@ -59,8 +59,8 @@
info = authplugin.authenticateCredentials(credentials)
if info is None:
continue
- principal = authplugin.createAuthenticatedPrincipal(
- info, request)
+ principal = component.getMultiAdapter((info, request),
+ interfaces.IAuthenticatedPrincipalFactory)()
principal.id = self.prefix + info.id
return principal
return None
@@ -78,7 +78,7 @@
info = authplugin.principalInfo(id)
if info is None:
continue
- principal = authplugin.createFoundPrincipal(info=info)
+ principal = interfaces.IFoundPrincipalFactory(info)()
principal.id = self.prefix + info.id
return principal
next = queryNextUtility(self, IAuthentication2)
Modified: Zope3/trunk/src/zope/app/authentication/groupfolder.py
===================================================================
--- Zope3/trunk/src/zope/app/authentication/groupfolder.py 2005-03-29 20:07:16 UTC (rev 29721)
+++ Zope3/trunk/src/zope/app/authentication/groupfolder.py 2005-03-29 22:07:44 UTC (rev 29722)
@@ -171,14 +171,6 @@
return principalfolder.PrincipalInfo(id, info.title,
info.description)
- def createAuthenticatedPrincipal(self, info, request):
- return component.getMultiAdapter((info, request),
- interfaces.IAuthenticatedPrincipalFactory)()
-
- def createFoundPrincipal(self, info):
- return interfaces.IFoundPrincipalFactory(info)()
-
-
class GroupCycle(Exception):
"""There is a cyclic relationship among groups
"""
Modified: Zope3/trunk/src/zope/app/authentication/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/app/authentication/interfaces.py 2005-03-29 20:07:16 UTC (rev 29721)
+++ Zope3/trunk/src/zope/app/authentication/interfaces.py 2005-03-29 22:07:44 UTC (rev 29722)
@@ -102,25 +102,6 @@
If the plugin cannot find information for the id, returns None.
"""
- def createAuthenticatedPrincipal(info, request):
- """Creates a principal authenticated against a request.
-
- `info` provides IPrincipalInfo and is used create a principal.
-
- If a principal is created, an AuthenticatedPrincipalCreated event is
- published and the principal is returned. If no principal is created,
- returns None.
- """
-
- def createFoundPrincipal(info):
- """Creates a principal with info from a search operation.
-
- `info` provides IPrincipalInfo and is to create the principal.
-
- If a principal is created, a FoundPrincipalCreated is published and
- the principal is returned. If no principal is created, returns None.
- """
-
class IPrincipalInfo(zope.interface.Interface):
"""Minimal information about a principal."""
Modified: Zope3/trunk/src/zope/app/authentication/principalfolder.py
===================================================================
--- Zope3/trunk/src/zope/app/authentication/principalfolder.py 2005-03-29 20:07:16 UTC (rev 29721)
+++ Zope3/trunk/src/zope/app/authentication/principalfolder.py 2005-03-29 22:07:44 UTC (rev 29722)
@@ -127,9 +127,9 @@
class PrincipalInfo:
"""A basic implementation of interfaces.IPrincipalInfo.
-
+
A principal info is created with id, title, and description:
-
+
>>> info = PrincipalInfo('foo', 'Foo', 'An over-used term.')
>>> info
PrincipalInfo('foo')
@@ -142,7 +142,7 @@
"""
interface.implements(interfaces.IPrincipalInfo)
-
+
def __init__(self, id, title, description):
self.id = id
self.title = title
@@ -151,10 +151,10 @@
def __repr__(self):
return 'PrincipalInfo(%r)' % self.id
-
+
class PrincipalFolder(BTreeContainer):
"""A Persistent Principal Folder and Authentication plugin.
-
+
See principalfolder.txt for details.
"""
@@ -211,7 +211,7 @@
if principal.password != credentials['password']:
return None
return PrincipalInfo(
- id=self.prefix + id,
+ id=self.prefix + id,
title=principal.title,
description=principal.description)
@@ -239,14 +239,7 @@
yield self.prefix + value.__name__
i += 1
- def createAuthenticatedPrincipal(self, info, request):
- return component.getMultiAdapter((info, request),
- interfaces.IAuthenticatedPrincipalFactory)()
- def createFoundPrincipal(self, info):
- return interfaces.IFoundPrincipalFactory(info)()
-
-
class Principal:
"""A group-aware implementation of zope.security.interfaces.IPrincipal.
@@ -257,7 +250,7 @@
Principal(1)
>>> p.id
1
-
+
title and description may also be provided:
>>> p = Principal('george', 'George', 'A site member.')
@@ -269,10 +262,10 @@
'George'
>>> p.description
'A site member.'
-
+
"""
interface.implements(IGroupAwarePrincipal)
-
+
def __init__(self, id, title=u'', description=u''):
self.id = id
self.title = title
@@ -285,29 +278,29 @@
class AuthenticatedPrincipalFactory:
"""Creates 'authenticated' principals.
-
+
An authenticated principal is created as a result of an authentication
operation.
-
+
To use the factory, create it with the info (interfaces.IPrincipalInfo) of
the principal to create and a request:
-
+
>>> info = PrincipalInfo('mary', 'Mary', 'The site admin.')
>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
>>> factory = AuthenticatedPrincipalFactory(info, request)
>>> principal = factory()
-
+
The factory uses the info to create a principal with the same ID, title,
and description:
-
+
>>> principal.id
'mary'
>>> principal.title
'Mary'
>>> principal.description
'The site admin.'
-
+
It also fires an AuthenticatedPrincipalCreatedEvent:
>>> from zope.app.event.tests.placelesssetup import getEvents
@@ -318,7 +311,7 @@
PrincipalInfo('mary')
>>> event.request is request
True
-
+
Listeners can subscribe to this event to perform additional operations
when the authenticated principal is created.
@@ -328,7 +321,7 @@
component.adapts(interfaces.IPrincipalInfo, IBrowserRequest)
interface.implements(interfaces.IAuthenticatedPrincipalFactory)
-
+
def __init__(self, info, request):
self.info = info
self.request = request
@@ -339,30 +332,30 @@
notify(interfaces.AuthenticatedPrincipalCreated(
principal, self.info, self.request))
return principal
-
+
class FoundPrincipalFactory:
"""Creates 'found' principals.
-
+
A 'found' principal is created as a result of a principal lookup.
-
+
To use the factory, create it with the info (interfaces.IPrincipalInfo) of
the principal to create:
-
+
>>> info = PrincipalInfo('sam', 'Sam', 'A site user.')
>>> factory = FoundPrincipalFactory(info)
>>> principal = factory()
-
+
The factory uses the info to create a principal with the same ID, title,
and description:
-
+
>>> principal.id
'sam'
>>> principal.title
'Sam'
>>> principal.description
'A site user.'
-
+
It also fires a FoundPrincipalCreatedEvent:
>>> from zope.app.event.tests.placelesssetup import getEvents
@@ -371,17 +364,17 @@
True
>>> event.info
PrincipalInfo('sam')
-
+
Listeners can subscribe to this event to perform additional operations
when the 'found' principal is created.
-
+
For information on how factories are used in the authentication process,
see README.txt.
- """
+ """
component.adapts(interfaces.IPrincipalInfo)
interface.implements(interfaces.IFoundPrincipalFactory)
-
+
def __init__(self, info):
self.info = info
Modified: Zope3/trunk/src/zope/app/authentication/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/authentication/tests.py 2005-03-29 20:07:16 UTC (rev 29721)
+++ Zope3/trunk/src/zope/app/authentication/tests.py 2005-03-29 22:07:44 UTC (rev 29722)
@@ -21,7 +21,7 @@
from zope.testing import doctest
from zope.interface import implements
-from zope.component import provideUtility
+from zope.component import provideUtility, provideAdapter
from zope.publisher.interfaces import IRequest
from zope.publisher.tests.httprequest import TestRequest
@@ -73,6 +73,7 @@
setUp=siteSetUp,
tearDown=siteTearDown,
globs={'provideUtility': provideUtility,
+ 'provideAdapter': provideAdapter,
'getEvents': getEvents,
'clearEvents': clearEvents,
'subscribe': ztapi.subscribe,
More information about the Zope3-Checkins
mailing list