[Zope3-checkins]
SVN: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/
Initial reorganize the pluggableauth package
Roger Ineichen
roger at projekt01.ch
Sat Jul 10 16:45:08 EDT 2004
Log message for revision 26408:
Initial reorganize the pluggableauth package
Move PluggableAuthenticationService code to pluggableauth.py
Move BTreePrincipalSource code to gtreesource.py
Move SimplePrincipalcode to principal.py
Move PrincipalAuthenticationView to a browser package
Reorganize Interfaces and imports
Added IPluggableAuthentication for to provide a constraints
Remove dependency to BTreePrincipalSource
Added IPrincipalSourceContained interface
-=-
Modified: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/__init__.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/__init__.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/__init__.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -15,582 +15,11 @@
$Id$
"""
-import random
-import sys
-import time
-import random
-import zope.schema
+from exception import LoginNameTaken
+from principal import SimplePrincipal
+from interfaces import IBTreePrincipalSource
+from interfaces import IBTreePrincipalSourceContained
+from btreesource import BTreePrincipalSource
+from pluggableauth import PluggableAuthenticationService
+from pluggableauth import PluggableAuthenticationServiceAddSubscriber
-from warnings import warn
-from persistent import Persistent
-from BTrees.IOBTree import IOBTree
-from BTrees.OIBTree import OIBTree
-
-from zope.interface import implements
-from zope.component.interfaces import IViewFactory
-from zope.exceptions import NotFoundError
-
-from zope.app import zapi
-from zope.app.location import locate
-from zope.app.traversing.api import getPath
-
-from zope.app.container.interfaces import IOrderedContainer
-from zope.app.container.interfaces import IContainerNamesContainer, INameChooser
-from zope.app.container.interfaces import IContained
-from zope.app.container.constraints import ItemTypePrecondition
-from zope.app.container.constraints import ContainerTypesConstraint
-from zope.app.container.contained import Contained, setitem, uncontained
-from zope.app.container.ordered import OrderedContainer
-
-from zope.app.servicenames import Authentication
-from zope.app.security.interfaces import ILoginPassword
-from zope.app.site.interfaces import ISimpleService
-from zope.app.component.localservice import queryNextService
-
-from interfaces import IUserSchemafied, IPluggableAuthenticationService
-from interfaces import \
- IPrincipalSource, ILoginPasswordPrincipalSource, IContainerPrincipalSource
-
-def gen_key():
- """Return a random int (1, MAXINT), suitable for use as a BTree key."""
-
- return random.randint(0, sys.maxint-1)
-
-class PluggableAuthenticationService(OrderedContainer):
-
- implements(IPluggableAuthenticationService, ISimpleService,
- IOrderedContainer)
-
- def __init__(self, earmark=None):
- self.earmark = earmark
- # The earmark is used as a token which can uniquely identify
- # this authentication service instance even if the service moves
- # from place to place within the same context chain or is renamed.
- # It is included in principal ids of principals which are obtained
- # from this auth service, so code which dereferences a principal
- # (like getPrincipal of this auth service) needs to take the earmark
- # into account. The earmark cannot change once it is assigned. If it
- # does change, the system will not be able to dereference principal
- # references which embed the old earmark.
- OrderedContainer.__init__(self)
-
- def authenticate(self, request):
- """ See IAuthenticationService. """
- for ps_key, ps in self.items():
- loginView = zapi.queryView(ps, "login", request)
- if loginView is not None:
- principal = loginView.authenticate()
- if principal is not None:
- return principal
-
- next = queryNextService(self, Authentication, None)
- if next is not None:
- return next.authenticate(request)
-
- return None
-
- def unauthenticatedPrincipal(self):
- # It's safe to assume that the global auth service will
- # provide an unauthenticated principal, so we won't bother.
- return None
-
- def unauthorized(self, id, request):
- """ See IAuthenticationService. """
-
- next = queryNextService(self, Authentication, None)
- if next is not None:
- return next.unauthorized(id, request)
-
- return None
-
- def getPrincipal(self, id):
- """ See IAuthenticationService.
-
- For this implementation, an 'id' is a string which can be
- split into a 3-tuple by splitting on tab characters. The
- three tuple consists of (auth_service_earmark,
- principal_source_id, principal_id).
-
- In the current strategy, the principal sources that are members
- of this authentication service cannot be renamed; if they are,
- principal references that embed the old name will not be
- dereferenceable.
-
- """
-
- next = None
-
- try:
- auth_svc_earmark, principal_src_id, principal_id = id.split('\t',2)
- except (TypeError, ValueError, AttributeError):
- auth_svc_earmark, principal_src_id, principal_id = None, None, None
- next = queryNextService(self, Authentication, None)
-
- if auth_svc_earmark != self.earmark:
- # this is not our reference because its earmark doesnt match ours
- next = queryNextService(self, Authentication, None)
-
- if next is not None:
- return next.getPrincipal(id)
-
- source = self.get(principal_src_id)
- if source is None:
- raise NotFoundError, principal_src_id
- return source.getPrincipal(id)
-
- def getPrincipals(self, name):
- """ See IAuthenticationService. """
-
- for ps_key, ps in self.items():
- for p in ps.getPrincipals(name):
- yield p
-
- next = queryNextService(self, Authentication, None)
- if next is not None:
- for p in next.getPrincipals(name):
- yield p
-
- def addPrincipalSource(self, id, principal_source):
- """ See IPluggableAuthenticationService.
-
- >>> pas = PluggableAuthenticationService()
- >>> sps = BTreePrincipalSource()
- >>> pas.addPrincipalSource('simple', sps)
- >>> sps2 = BTreePrincipalSource()
- >>> pas.addPrincipalSource('not_quite_so_simple', sps2)
- >>> pas.keys()
- ['simple', 'not_quite_so_simple']
- """
-
- if not IPrincipalSource.providedBy(principal_source):
- raise TypeError("Source must implement IPrincipalSource")
- locate(principal_source, self, id)
- self[id] = principal_source
-
- def removePrincipalSource(self, id):
- """ See IPluggableAuthenticationService.
-
- >>> pas = PluggableAuthenticationService()
- >>> sps = BTreePrincipalSource()
- >>> pas.addPrincipalSource('simple', sps)
- >>> sps2 = BTreePrincipalSource()
- >>> pas.addPrincipalSource('not_quite_so_simple', sps2)
- >>> sps3 = BTreePrincipalSource()
- >>> pas.addPrincipalSource('simpler', sps3)
- >>> pas.keys()
- ['simple', 'not_quite_so_simple', 'simpler']
- >>> pas.removePrincipalSource('not_quite_so_simple')
- >>> pas.keys()
- ['simple', 'simpler']
- """
-
- del self[id]
-
-
-def PluggableAuthenticationServiceAddSubscriber(self, event):
- r"""Generates an earmark if one is not provided.
-
- Define a stub for PluggableAuthenticationService
-
- >>> from zope.app.traversing.interfaces import IPhysicallyLocatable
- >>> class PluggableAuthStub:
- ... implements(IPhysicallyLocatable)
- ... def __init__(self, earmark=None):
- ... self.earmark = earmark
- ... def getName(self):
- ... return 'PluggableAuthName'
-
- The subscriber generates an earmark for the auth service if one is not
- set in the init.
-
- >>> stub = PluggableAuthStub()
- >>> event = ''
- >>> PluggableAuthenticationServiceAddSubscriber(stub, event)
- >>> stub.earmark is not None
- True
-
- The subscriber does not modify an earmark for the auth service if one
- exists already.
-
- >>> earmark = 'my sample earmark'
- >>> stub = PluggableAuthStub(earmark=earmark)
- >>> event = ''
- >>> PluggableAuthenticationServiceAddSubscriber(stub, event)
- >>> stub.earmark == earmark
- True
- """
- if self.earmark is None:
- # we manufacture what is intended to be a globally unique
- # earmark if one is not provided in __init__
- myname = zapi.name(self)
- rand_id = gen_key()
- t = int(time.time())
- self.earmark = '%s-%s-%s' % (myname, rand_id, t)
-
-
-class IBTreePrincipalSource(
- ILoginPasswordPrincipalSource,
- IContainerPrincipalSource,
- INameChooser,
- IContainerNamesContainer,
- ):
-
- def __setitem__(name, principal):
- """Add a principal
-
- The name must be the same as the principal login
- """
-
- __setitem__.precondition = ItemTypePrecondition(IUserSchemafied)
-
-class IBTreePrincipalSourceContained(IContained):
-
- __parent__ = zope.schema.Field(
- constraint = ContainerTypesConstraint(IBTreePrincipalSource),
- )
-
-class BTreePrincipalSource(Persistent, Contained):
- """An efficient, scalable provider of Authentication Principals."""
-
- implements(IBTreePrincipalSource)
-
- def __init__(self):
-
- self._principals_by_number = IOBTree()
- self._numbers_by_login = OIBTree()
-
- # IContainer-related methods
-
- def __delitem__(self, login):
- """ See IContainer.
-
- >>> sps = BTreePrincipalSource()
- >>> prin = SimplePrincipal('fred', 'fred', '123')
- >>> sps['fred'] = prin
- >>> int(sps.get('fred') == prin)
- 1
- >>> del sps['fred']
- >>> int(sps.get('fred') == prin)
- 0
-
- """
- number = self._numbers_by_login[login]
-
- uncontained(self._principals_by_number[number], self, login)
- del self._principals_by_number[number]
- del self._numbers_by_login[login]
-
- def __setitem__(self, login, ob):
- """ See IContainerNamesContainer
-
- >>> sps = BTreePrincipalSource()
- >>> prin = SimplePrincipal('gandalf', 'shadowfax')
- >>> sps['doesntmatter'] = prin
- >>> sps.get('doesntmatter')
- """
- setitem(self, self.__setitem, login, ob)
-
- def __setitem(self, login, ob):
- store = self._principals_by_number
-
- key = gen_key()
- while not store.insert(key, ob):
- key = gen_key()
-
- ob.id = key
- self._numbers_by_login[ob.login] = key
-
- def keys(self):
- """ See IContainer.
-
- >>> sps = BTreePrincipalSource()
- >>> sps.keys()
- []
- >>> prin = SimplePrincipal('arthur', 'tea')
- >>> sps['doesntmatter'] = prin
- >>> sps.keys()
- ['arthur']
- >>> prin = SimplePrincipal('ford', 'towel')
- >>> sps['doesntmatter'] = prin
- >>> sps.keys()
- ['arthur', 'ford']
- """
-
- return list(self._numbers_by_login.keys())
-
- def __iter__(self):
- """ See IContainer.
-
- >>> sps = BTreePrincipalSource()
- >>> sps.keys()
- []
- >>> prin = SimplePrincipal('trillian', 'heartOfGold')
- >>> sps['doesntmatter'] = prin
- >>> prin = SimplePrincipal('zaphod', 'gargleblaster')
- >>> sps['doesntmatter'] = prin
- >>> [i for i in sps]
- ['trillian', 'zaphod']
- """
-
- return iter(self.keys())
-
- def __getitem__(self, key):
- """ See IContainer
-
- >>> sps = BTreePrincipalSource()
- >>> prin = SimplePrincipal('gag', 'justzisguy')
- >>> sps['doesntmatter'] = prin
- >>> sps['gag'].login
- 'gag'
- """
-
- number = self._numbers_by_login[key]
- return self._principals_by_number[number]
-
- def get(self, key, default=None):
- """ See IContainer
-
- >>> sps = BTreePrincipalSource()
- >>> prin = SimplePrincipal(1, 'slartibartfast', 'fjord')
- >>> sps['slartibartfast'] = prin
- >>> principal = sps.get('slartibartfast')
- >>> sps.get('marvin', 'No chance, dude.')
- 'No chance, dude.'
- """
-
- try:
- number = self._numbers_by_login[key]
- except KeyError:
- return default
-
- return self._principals_by_number[number]
-
- def values(self):
- """ See IContainer.
-
- >>> sps = BTreePrincipalSource()
- >>> sps.keys()
- []
- >>> prin = SimplePrincipal('arthur', 'tea')
- >>> sps['doesntmatter'] = prin
- >>> [user.login for user in sps.values()]
- ['arthur']
- >>> prin = SimplePrincipal('ford', 'towel')
- >>> sps['doesntmatter'] = prin
- >>> [user.login for user in sps.values()]
- ['arthur', 'ford']
- """
-
- return [self._principals_by_number[n]
- for n in self._numbers_by_login.values()]
-
- def __len__(self):
- """ See IContainer
-
- >>> sps = BTreePrincipalSource()
- >>> int(len(sps) == 0)
- 1
- >>> prin = SimplePrincipal(1, 'trillian', 'heartOfGold')
- >>> sps['trillian'] = prin
- >>> int(len(sps) == 1)
- 1
- """
-
- return len(self._principals_by_number)
-
- def items(self):
- """ See IContainer.
-
- >>> sps = BTreePrincipalSource()
- >>> sps.keys()
- []
- >>> prin = SimplePrincipal('zaphod', 'gargleblaster')
- >>> sps['doesntmatter'] = prin
- >>> [(k, v.login) for k, v in sps.items()]
- [('zaphod', 'zaphod')]
- >>> prin = SimplePrincipal('marvin', 'paranoid')
- >>> sps['doesntmatter'] = prin
- >>> [(k, v.login) for k, v in sps.items()]
- [('marvin', 'marvin'), ('zaphod', 'zaphod')]
- """
-
- # We're being expensive here (see values() above) for convenience
- return [(p.login, p) for p in self.values()]
-
- def __contains__(self, key):
- """ See IContainer.
-
- >>> sps = BTreePrincipalSource()
- >>> prin = SimplePrincipal('slinkp', 'password')
- >>> sps['doesntmatter'] = prin
- >>> int('slinkp' in sps)
- 1
- >>> int('desiato' in sps)
- 0
- """
- return self._numbers_by_login.has_key(key)
-
- has_key = __contains__
-
- # PrincipalSource-related methods
-
- def getPrincipal(self, id):
- """ See IPrincipalSource.
-
- 'id' is the id as returned by principal.getId(),
- not a login.
-
- """
-
- id = id.split('\t')[2]
- id = int(id)
-
- try:
- return self._principals_by_number[id]
- except KeyError:
- raise NotFoundError, id
-
- def getPrincipals(self, name):
- """ See IPrincipalSource.
-
- >>> sps = BTreePrincipalSource()
- >>> prin1 = SimplePrincipal('gandalf', 'shadowfax')
- >>> sps['doesntmatter'] = prin1
- >>> prin1 = SimplePrincipal('frodo', 'ring')
- >>> sps['doesntmatter'] = prin1
- >>> prin1 = SimplePrincipal('pippin', 'pipe')
- >>> sps['doesntmatter'] = prin1
- >>> prin1 = SimplePrincipal('sam', 'garden')
- >>> sps['doesntmatter'] = prin1
- >>> prin1 = SimplePrincipal('merry', 'food')
- >>> sps['doesntmatter'] = prin1
- >>> [p.login for p in sps.getPrincipals('a')]
- ['gandalf', 'sam']
- >>> [p.login for p in sps.getPrincipals('')]
- ['frodo', 'gandalf', 'merry', 'pippin', 'sam']
- >>> [p.login for p in sps.getPrincipals('sauron')]
- []
- """
-
- for k in self.keys():
- if k.find(name) != -1:
- yield self[k]
-
- def authenticate(self, login, password):
- """ See ILoginPasswordPrincipalSource. """
- number = self._numbers_by_login.get(login)
- if number is None:
- return
- user = self._principals_by_number[number]
- if user.password == password:
- return user
-
-
- def checkName(self, name, object):
- """Check to make sure the name is valid
-
- Don't allow suplicate names:
-
- >>> sps = BTreePrincipalSource()
- >>> prin1 = SimplePrincipal('gandalf', 'shadowfax')
- >>> sps['gandalf'] = prin1
- >>> sps.checkName('gandalf', prin1)
- Traceback (most recent call last):
- ...
- LoginNameTaken: gandalf
-
- """
- if name in self._numbers_by_login:
- raise LoginNameTaken(name)
-
- def chooseName(self, name, object):
- """Choose a name for the principal
-
- Always choose the object's existing name:
-
- >>> sps = BTreePrincipalSource()
- >>> prin1 = SimplePrincipal('gandalf', 'shadowfax')
- >>> sps.chooseName(None, prin1)
- 'gandalf'
-
- """
- return object.login
-
-class LoginNameTaken(Exception):
- """A login name is in use
- """
-
-
-class SimplePrincipal(Persistent, Contained):
- """A no-frills IUserSchemafied implementation."""
-
- implements(IUserSchemafied, IBTreePrincipalSourceContained)
-
- def __init__(self, login, password, title='', description=''):
- self._id = ''
- self.login = login
- self.password = password
- self.title = title
- self.description = description
-
- def _getId(self):
- source = self.__parent__
- auth = source.__parent__
- return "%s\t%s\t%s" %(auth.earmark, source.__name__, self._id)
-
- def _setId(self, id):
- self._id = id
-
- id = property(_getId, _setId)
-
- def getTitle(self):
- warn("Use principal.title instead of principal.getTitle().",
- DeprecationWarning, 2)
- return self.title
-
- def getDescription(self):
- warn("Use principal.description instead of principal.getDescription().",
- DeprecationWarning, 2)
- return self.description
-
- def getLogin(self):
- """See IReadUser."""
- return self.login
-
- def validate(self, test_password):
- """ See IReadUser.
-
- >>> pal = SimplePrincipal('gandalf', 'shadowfax', 'The Grey Wizard',
- ... 'Cool old man with neato fireworks. '
- ... 'Has a nice beard.')
- >>> pal.validate('shdaowfax')
- False
- >>> pal.validate('shadowfax')
- True
- """
- return test_password == self.password
-
-class PrincipalAuthenticationView:
- """Simple basic authentication view
-
- This only handles requests which have basic auth credentials
- in them currently (ILoginPassword-based requests).
- If you want a different policy, you'll need to write and register
- a different view, replacing this one.
-
- """
- implements(IViewFactory)
-
- def __init__(self, context, request):
- self.context = context
- self.request = request
-
- def authenticate(self):
- a = ILoginPassword(self.request, None)
- if a is None:
- return
- login = a.getLogin()
- password = a.getPassword()
-
- p = self.context.authenticate(login, password)
- return p
Modified: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/__init__.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/__init__.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/__init__.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -1 +1,2 @@
#
+#from zope.app.pluggableauth.browser.authentication import PrincipalAuthenticationView
Added: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/authentication.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/authentication.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/authentication.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -0,0 +1,31 @@
+#
+from zope.interface import implements
+from zope.component.interfaces import IViewFactory
+from zope.app.security.interfaces import ILoginPassword
+
+
+
+class PrincipalAuthenticationView:
+ """Simple basic authentication view
+
+ This only handles requests which have basic auth credentials
+ in them currently (ILoginPassword-based requests).
+ If you want a different policy, you'll need to write and register
+ a different view, replacing this one.
+
+ """
+ implements(IViewFactory)
+
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def authenticate(self):
+ a = ILoginPassword(self.request, None)
+ if a is None:
+ return
+ login = a.getLogin()
+ password = a.getPassword()
+
+ p = self.context.authenticate(login, password)
+ return p
Property changes on: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/authentication.py
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/configure.zcml
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/configure.zcml 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/configure.zcml 2004-07-10 20:45:08 UTC (rev 26408)
@@ -2,6 +2,14 @@
xmlns="http://namespaces.zope.org/browser"
xmlns:zope="http://namespaces.zope.org/zope">
+<!-- Login view -->
+
+ <view
+ name="login"
+ for="zope.app.pluggableauth.interfaces.ILoginPasswordPrincipalSource"
+ class=".authentication.PrincipalAuthenticationView"
+ permission="zope.Public" />
+
<!-- Pluggable Authentication Service -->
<addMenuItem
Added: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/tests/__init__.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/tests/__init__.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/tests/__init__.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
Property changes on: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/tests/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/tests/test_authentication.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/tests/test_authentication.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/tests/test_authentication.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -0,0 +1,40 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Pluggable Auth Browser Tests
+
+$Id: test_authentication.py 25177 2004-06-02 13:17:31Z jim $
+"""
+from unittest import TestCase, TestSuite, main, makeSuite
+from zope.app.pluggableauth.browser.authentication import \
+ PrincipalAuthenticationView
+from zope.app.pluggableauth.tests.authsetup import AuthSetup
+
+
+
+class PrincipalAuthenticationViewTest(AuthSetup, TestCase):
+
+ def test_authenticate(self):
+ request = self.getRequest('srichter', 'hello')
+ view = PrincipalAuthenticationView(self._one, request)
+ self.assertEqual(self._srichter, view.authenticate())
+
+
+def test_suite():
+ t1 = makeSuite(PrincipalAuthenticationViewTest)
+ return TestSuite((t1,))
+
+
+if __name__=='__main__':
+ main(defaultTest='test_suite')
+
Property changes on: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/browser/tests/test_authentication.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/btreesource.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/btreesource.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/btreesource.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -0,0 +1,309 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Pluggable Authentication service implementation.
+
+$Id: __init__.py 26176 2004-07-07 18:34:31Z jim $
+"""
+import sys
+import random
+
+from persistent import Persistent
+from BTrees.IOBTree import IOBTree
+from BTrees.OIBTree import OIBTree
+
+from zope.interface import implements
+from zope.exceptions import NotFoundError
+
+from zope.app.container.contained import Contained, setitem, uncontained
+
+from interfaces import IContainerPrincipalSource
+from interfaces import IBTreePrincipalSource
+
+from exception import LoginNameTaken
+from principal import SimplePrincipal
+
+
+
+def gen_key():
+ """Return a random int (1, MAXINT), suitable for use as a BTree key."""
+
+ return random.randint(0, sys.maxint-1)
+
+
+class BTreePrincipalSource(Persistent, Contained):
+ """An efficient, scalable provider of Authentication Principals."""
+
+ implements(IBTreePrincipalSource)
+
+ def __init__(self):
+
+ self._principals_by_number = IOBTree()
+ self._numbers_by_login = OIBTree()
+
+ # IContainer-related methods
+
+ def __delitem__(self, login):
+ """ See IContainer.
+
+ >>> sps = BTreePrincipalSource()
+ >>> prin = SimplePrincipal('fred', 'fred', '123')
+ >>> sps['fred'] = prin
+ >>> int(sps.get('fred') == prin)
+ 1
+ >>> del sps['fred']
+ >>> int(sps.get('fred') == prin)
+ 0
+
+ """
+ number = self._numbers_by_login[login]
+
+ uncontained(self._principals_by_number[number], self, login)
+ del self._principals_by_number[number]
+ del self._numbers_by_login[login]
+
+ def __setitem__(self, login, ob):
+ """ See IContainerNamesContainer
+
+ >>> sps = BTreePrincipalSource()
+ >>> prin = SimplePrincipal('gandalf', 'shadowfax')
+ >>> sps['doesntmatter'] = prin
+ >>> sps.get('doesntmatter')
+ """
+ setitem(self, self.__setitem, login, ob)
+
+ def __setitem(self, login, ob):
+ store = self._principals_by_number
+
+ key = gen_key()
+ while not store.insert(key, ob):
+ key = gen_key()
+
+ ob.id = key
+ self._numbers_by_login[ob.login] = key
+
+ def keys(self):
+ """ See IContainer.
+
+ >>> sps = BTreePrincipalSource()
+ >>> sps.keys()
+ []
+ >>> prin = SimplePrincipal('arthur', 'tea')
+ >>> sps['doesntmatter'] = prin
+ >>> sps.keys()
+ ['arthur']
+ >>> prin = SimplePrincipal('ford', 'towel')
+ >>> sps['doesntmatter'] = prin
+ >>> sps.keys()
+ ['arthur', 'ford']
+ """
+
+ return list(self._numbers_by_login.keys())
+
+ def __iter__(self):
+ """ See IContainer.
+
+ >>> sps = BTreePrincipalSource()
+ >>> sps.keys()
+ []
+ >>> prin = SimplePrincipal('trillian', 'heartOfGold')
+ >>> sps['doesntmatter'] = prin
+ >>> prin = SimplePrincipal('zaphod', 'gargleblaster')
+ >>> sps['doesntmatter'] = prin
+ >>> [i for i in sps]
+ ['trillian', 'zaphod']
+ """
+
+ return iter(self.keys())
+
+ def __getitem__(self, key):
+ """ See IContainer
+
+ >>> sps = BTreePrincipalSource()
+ >>> prin = SimplePrincipal('gag', 'justzisguy')
+ >>> sps['doesntmatter'] = prin
+ >>> sps['gag'].login
+ 'gag'
+ """
+
+ number = self._numbers_by_login[key]
+ return self._principals_by_number[number]
+
+ def get(self, key, default=None):
+ """ See IContainer
+
+ >>> sps = BTreePrincipalSource()
+ >>> prin = SimplePrincipal(1, 'slartibartfast', 'fjord')
+ >>> sps['slartibartfast'] = prin
+ >>> principal = sps.get('slartibartfast')
+ >>> sps.get('marvin', 'No chance, dude.')
+ 'No chance, dude.'
+ """
+
+ try:
+ number = self._numbers_by_login[key]
+ except KeyError:
+ return default
+
+ return self._principals_by_number[number]
+
+ def values(self):
+ """ See IContainer.
+
+ >>> sps = BTreePrincipalSource()
+ >>> sps.keys()
+ []
+ >>> prin = SimplePrincipal('arthur', 'tea')
+ >>> sps['doesntmatter'] = prin
+ >>> [user.login for user in sps.values()]
+ ['arthur']
+ >>> prin = SimplePrincipal('ford', 'towel')
+ >>> sps['doesntmatter'] = prin
+ >>> [user.login for user in sps.values()]
+ ['arthur', 'ford']
+ """
+
+ return [self._principals_by_number[n]
+ for n in self._numbers_by_login.values()]
+
+ def __len__(self):
+ """ See IContainer
+
+ >>> sps = BTreePrincipalSource()
+ >>> int(len(sps) == 0)
+ 1
+ >>> prin = SimplePrincipal(1, 'trillian', 'heartOfGold')
+ >>> sps['trillian'] = prin
+ >>> int(len(sps) == 1)
+ 1
+ """
+
+ return len(self._principals_by_number)
+
+ def items(self):
+ """ See IContainer.
+
+ >>> sps = BTreePrincipalSource()
+ >>> sps.keys()
+ []
+ >>> prin = SimplePrincipal('zaphod', 'gargleblaster')
+ >>> sps['doesntmatter'] = prin
+ >>> [(k, v.login) for k, v in sps.items()]
+ [('zaphod', 'zaphod')]
+ >>> prin = SimplePrincipal('marvin', 'paranoid')
+ >>> sps['doesntmatter'] = prin
+ >>> [(k, v.login) for k, v in sps.items()]
+ [('marvin', 'marvin'), ('zaphod', 'zaphod')]
+ """
+
+ # We're being expensive here (see values() above) for convenience
+ return [(p.login, p) for p in self.values()]
+
+ def __contains__(self, key):
+ """ See IContainer.
+
+ >>> sps = BTreePrincipalSource()
+ >>> prin = SimplePrincipal('slinkp', 'password')
+ >>> sps['doesntmatter'] = prin
+ >>> int('slinkp' in sps)
+ 1
+ >>> int('desiato' in sps)
+ 0
+ """
+ return self._numbers_by_login.has_key(key)
+
+ has_key = __contains__
+
+ # PrincipalSource-related methods
+
+ def getPrincipal(self, id):
+ """ See IPrincipalSource.
+
+ 'id' is the id as returned by principal.getId(),
+ not a login.
+
+ """
+
+ id = id.split('\t')[2]
+ id = int(id)
+
+ try:
+ return self._principals_by_number[id]
+ except KeyError:
+ raise NotFoundError, id
+
+ def getPrincipals(self, name):
+ """ See IPrincipalSource.
+
+ >>> sps = BTreePrincipalSource()
+ >>> prin1 = SimplePrincipal('gandalf', 'shadowfax')
+ >>> sps['doesntmatter'] = prin1
+ >>> prin1 = SimplePrincipal('frodo', 'ring')
+ >>> sps['doesntmatter'] = prin1
+ >>> prin1 = SimplePrincipal('pippin', 'pipe')
+ >>> sps['doesntmatter'] = prin1
+ >>> prin1 = SimplePrincipal('sam', 'garden')
+ >>> sps['doesntmatter'] = prin1
+ >>> prin1 = SimplePrincipal('merry', 'food')
+ >>> sps['doesntmatter'] = prin1
+ >>> [p.login for p in sps.getPrincipals('a')]
+ ['gandalf', 'sam']
+ >>> [p.login for p in sps.getPrincipals('')]
+ ['frodo', 'gandalf', 'merry', 'pippin', 'sam']
+ >>> [p.login for p in sps.getPrincipals('sauron')]
+ []
+ """
+
+ for k in self.keys():
+ if k.find(name) != -1:
+ yield self[k]
+
+ def authenticate(self, login, password):
+ """ See ILoginPasswordPrincipalSource. """
+ number = self._numbers_by_login.get(login)
+ if number is None:
+ return
+ user = self._principals_by_number[number]
+ if user.password == password:
+ return user
+
+
+ def checkName(self, name, object):
+ """Check to make sure the name is valid
+
+ Don't allow suplicate names:
+
+ >>> sps = BTreePrincipalSource()
+ >>> prin1 = SimplePrincipal('gandalf', 'shadowfax')
+ >>> sps['gandalf'] = prin1
+ >>> sps.checkName('gandalf', prin1)
+ Traceback (most recent call last):
+ ...
+ LoginNameTaken: gandalf
+
+ """
+ if name in self._numbers_by_login:
+ raise LoginNameTaken(name)
+
+ def chooseName(self, name, object):
+ """Choose a name for the principal
+
+ Always choose the object's existing name:
+
+ >>> sps = BTreePrincipalSource()
+ >>> prin1 = SimplePrincipal('gandalf', 'shadowfax')
+ >>> sps.chooseName(None, prin1)
+ 'gandalf'
+
+ """
+ return object.login
Property changes on: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/btreesource.py
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/configure.zcml
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/configure.zcml 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/configure.zcml 2004-07-10 20:45:08 UTC (rev 26408)
@@ -62,12 +62,6 @@
/>
</content>
- <browser:view
- name="login"
- for=".interfaces.ILoginPasswordPrincipalSource"
- class="zope.app.pluggableauth.PrincipalAuthenticationView"
- permission="zope.Public" />
-
<include package=".browser" />
</configure>
Added: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/exception.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/exception.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/exception.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -0,0 +1,19 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Pluggable Authentication service implementation.
+
+$Id: exception.py 26176 2004-07-07 18:34:31Z jim $
+"""
+class LoginNameTaken(Exception):
+ """Exception for to raise if a login name is allready in use."""
Property changes on: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/exception.py
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/interfaces.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/interfaces.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/interfaces.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -17,12 +17,16 @@
"""
from zope.app.i18n import ZopeMessageIDFactory as _
from zope.app.container.interfaces import IContainer, IContained
+from zope.app.container.interfaces import IContainerNamesContainer, INameChooser
from zope.app.container.constraints import ItemTypePrecondition
from zope.app.container.constraints import ContainerTypesConstraint
from zope.app.security.interfaces import IAuthenticationService, IPrincipal
from zope.interface import Interface
+import zope.schema
from zope.schema import Text, TextLine, Password, Field
+
+
class IUserSchemafied(IPrincipal):
"""A User object with schema-defined attributes."""
@@ -41,10 +45,17 @@
"""Confirm whether 'password' is the password of the user."""
-class IPrincipalSource(Interface):
- """A read-only source of IPrincipals.
+class IPluggableAuthentication(Interface):
+ """A marker for to mix in a constraints."""
+
+
+class IPrincipalSource(IContained):
+ """A read-only source of IPrincipals where can be added to a auth service.
"""
+ __parent__= Field(
+ constraint = ContainerTypesConstraint(IPluggableAuthentication))
+
def getPrincipal(id):
"""Get principal meta-data.
@@ -72,8 +83,29 @@
"""
-class IPluggableAuthenticationService(IAuthenticationService, IContainer):
+class ILoginPasswordPrincipalSource(IPrincipalSource):
+ """ A principal source which can authenticate a user given a
+ login and a password """
+
+ def authenticate(login, password):
+ """ Return a principal matching the login/password pair.
+
+ If there is no principal in this principal source which
+ matches the login/password pair, return None.
+
+ Note: A login is different than an id. Principals may have
+ logins that differ from their id. For example, a user may
+ have a login which is his email address. He'd like to be able
+ to change his login when his email address changes without
+ effecting his security profile on the site.
+ """
+
+
+class IPluggableAuthenticationService(IPluggableAuthentication, \
+ IAuthenticationService, IContainer):
"""An AuthenticationService that can contain multiple pricipal sources.
+
+ Inherit from IPluggableAuthentication for to provide a constraints.
"""
def __setitem__(id, principal_source):
@@ -87,26 +119,43 @@
"""
-class ILoginPasswordPrincipalSource(IPrincipalSource):
- """ A principal source which can authenticate a user given a
- login and a password """
+class IContainerPrincipalSource(IPrincipalSource):
+ """This is a marker interface for specifying principal sources that are
+ also containers. """
- def authenticate(login, password):
- """ Return a principal matching the login/password pair.
- If there is no principal in this principal source which
- matches the login/password pair, return None.
+class IPrincipalSourceContained(IContained):
+ """Make shure we just let object add to IPrincipalSource
+ porvided instances. """
- Note: A login is different than an id. Principals may have
- logins that differ from their id. For example, a user may
- have a login which is his email address. He'd like to be able
- to change his login when his email address changes without
- effecting his security profile on the site. """
+ __parent__ = zope.schema.Field(
+ constraint = ContainerTypesConstraint(IPrincipalSource),
+ )
-class IContainerPrincipalSource(IPrincipalSource, IContained):
- """This is a marker interface for specifying principal sources that are
- also containers. """
+class IBTreePrincipalSource(
+ ILoginPasswordPrincipalSource,
+ IContainerPrincipalSource,
+ INameChooser,
+ IContainerNamesContainer,
+ ):
- __parent__= Field(
- constraint = ContainerTypesConstraint(IPluggableAuthenticationService))
+ def __setitem__(name, principal):
+ """Add a principal
+
+ The name must be the same as the principal login
+ """
+
+ __setitem__.precondition = ItemTypePrecondition(IUserSchemafied)
+
+
+class IBTreePrincipalSourceContained(IPrincipalSourceContained):
+ """Set own constarints to the BTreePrincipalSource.
+
+ Make shure we just let object add to IBTreePrinicpalSource
+ porvided instances.
+ """
+
+ __parent__ = zope.schema.Field(
+ constraint = ContainerTypesConstraint(IBTreePrincipalSource),
+ )
\ No newline at end of file
Added: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/pluggableauth.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/pluggableauth.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/pluggableauth.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -0,0 +1,154 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Pluggable Authentication service implementation.
+
+$Id: __init__.py 26176 2004-07-07 18:34:31Z jim $
+"""
+import time
+
+from zope.interface import implements
+from zope.exceptions import NotFoundError
+
+from zope.app import zapi
+from zope.app.location import locate
+
+from zope.app.container.interfaces import IOrderedContainer
+from zope.app.container.ordered import OrderedContainer
+
+from zope.app.servicenames import Authentication
+from zope.app.site.interfaces import ISimpleService
+from zope.app.component.localservice import queryNextService
+
+from interfaces import IPluggableAuthenticationService
+from interfaces import IPrincipalSource
+from btreesource import gen_key
+
+
+class PluggableAuthenticationService(OrderedContainer):
+
+ implements(IPluggableAuthenticationService, ISimpleService,
+ IOrderedContainer)
+
+ def __init__(self, earmark=None):
+ self.earmark = earmark
+ # The earmark is used as a token which can uniquely identify
+ # this authentication service instance even if the service moves
+ # from place to place within the same context chain or is renamed.
+ # It is included in principal ids of principals which are obtained
+ # from this auth service, so code which dereferences a principal
+ # (like getPrincipal of this auth service) needs to take the earmark
+ # into account. The earmark cannot change once it is assigned. If it
+ # does change, the system will not be able to dereference principal
+ # references which embed the old earmark.
+ OrderedContainer.__init__(self)
+
+ def authenticate(self, request):
+ """ See IAuthenticationService. """
+ for ps_key, ps in self.items():
+ loginView = zapi.queryView(ps, "login", request)
+ if loginView is not None:
+ principal = loginView.authenticate()
+ if principal is not None:
+ return principal
+
+ next = queryNextService(self, Authentication, None)
+ if next is not None:
+ return next.authenticate(request)
+
+ return None
+
+ def unauthenticatedPrincipal(self):
+ # It's safe to assume that the global auth service will
+ # provide an unauthenticated principal, so we won't bother.
+ return None
+
+ def unauthorized(self, id, request):
+ """ See IAuthenticationService. """
+
+ next = queryNextService(self, Authentication, None)
+ if next is not None:
+ return next.unauthorized(id, request)
+
+ return None
+
+ def getPrincipal(self, id):
+ """ See IAuthenticationService.
+
+ For this implementation, an 'id' is a string which can be
+ split into a 3-tuple by splitting on tab characters. The
+ three tuple consists of (auth_service_earmark,
+ principal_source_id, principal_id).
+
+ In the current strategy, the principal sources that are members
+ of this authentication service cannot be renamed; if they are,
+ principal references that embed the old name will not be
+ dereferenceable.
+
+ """
+
+ next = None
+
+ try:
+ auth_svc_earmark, principal_src_id, principal_id = id.split('\t',2)
+ except (TypeError, ValueError, AttributeError):
+ auth_svc_earmark, principal_src_id, principal_id = None, None, None
+ next = queryNextService(self, Authentication, None)
+
+ if auth_svc_earmark != self.earmark:
+ # this is not our reference because its earmark doesnt match ours
+ next = queryNextService(self, Authentication, None)
+
+ if next is not None:
+ return next.getPrincipal(id)
+
+ source = self.get(principal_src_id)
+ if source is None:
+ raise NotFoundError, principal_src_id
+ return source.getPrincipal(id)
+
+ def getPrincipals(self, name):
+ """ See IAuthenticationService. """
+
+ for ps_key, ps in self.items():
+ for p in ps.getPrincipals(name):
+ yield p
+
+ next = queryNextService(self, Authentication, None)
+ if next is not None:
+ for p in next.getPrincipals(name):
+ yield p
+
+ def addPrincipalSource(self, id, principal_source):
+ """ See IPluggableAuthenticationService."""
+
+ if not IPrincipalSource.providedBy(principal_source):
+ raise TypeError("Source must implement IPrincipalSource")
+ locate(principal_source, self, id)
+ self[id] = principal_source
+
+ def removePrincipalSource(self, id):
+ """ See IPluggableAuthenticationService."""
+ del self[id]
+
+
+def PluggableAuthenticationServiceAddSubscriber(self, event):
+ """Generates an earmark if one is not provided."""
+
+ if self.earmark is None:
+ # we manufacture what is intended to be a globally unique
+ # earmark if one is not provided in __init__
+ myname = zapi.name(self)
+ rand_id = gen_key()
+ t = int(time.time())
+ self.earmark = '%s-%s-%s' % (myname, rand_id, t)
Property changes on: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/pluggableauth.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/pluggableauth.txt
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/pluggableauth.txt 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/pluggableauth.txt 2004-07-10 20:45:08 UTC (rev 26408)
@@ -0,0 +1,77 @@
+==============================
+PluggableAuthenticationService
+==============================
+
+Adapter registries provide a way to register objects that depend on
+one or more interface specifications and provide (perhaps indirectly)
+some interface. In addition, the registrations have names. (You can
+think of the names as qualifiers of the provided interfaces.)
+
+The term "interface specification" refers both to interfaces and to
+interface declarations, such as declarations of interfaces implemented
+by a class.
+
+
+Let's test the service
+======================
+
+ >>> from zope.interface import implements
+ >>> from zope.app.pluggableauth.btreesource import BTreePrincipalSource
+ >>> from zope.app.pluggableauth.pluggableauth import PluggableAuthenticationService
+ >>> from zope.app.pluggableauth.pluggableauth import PluggableAuthenticationServiceAddSubscriber
+
+Let's look at a simple example, using a pluggableauth service::
+
+ >>> pas = PluggableAuthenticationService()
+ >>> sps = BTreePrincipalSource()
+ >>> pas.addPrincipalSource('simple', sps)
+ >>> sps2 = BTreePrincipalSource()
+ >>> pas.addPrincipalSource('not_quite_so_simple', sps2)
+ >>> pas.keys()
+ ['simple', 'not_quite_so_simple']
+
+
+remove a principal source
+
+ >>> pas = PluggableAuthenticationService()
+ >>> sps = BTreePrincipalSource()
+ >>> pas.addPrincipalSource('simple', sps)
+ >>> sps2 = BTreePrincipalSource()
+ >>> pas.addPrincipalSource('not_quite_so_simple', sps2)
+ >>> sps3 = BTreePrincipalSource()
+ >>> pas.addPrincipalSource('simpler', sps3)
+ >>> pas.keys()
+ ['simple', 'not_quite_so_simple', 'simpler']
+ >>> pas.removePrincipalSource('not_quite_so_simple')
+ >>> pas.keys()
+ ['simple', 'simpler']
+
+Generates an earmark if one is not provided.
+Define a stub for PluggableAuthenticationService
+
+ >>> from zope.app.traversing.interfaces import IPhysicallyLocatable
+ >>> class PluggableAuthStub:
+ ... implements(IPhysicallyLocatable)
+ ... def __init__(self, earmark=None):
+ ... self.earmark = earmark
+ ... def getName(self):
+ ... return 'PluggableAuthName'
+
+ The subscriber generates an earmark for the auth service if one is not
+ set in the init.
+
+ >>> stub = PluggableAuthStub()
+ >>> event = ''
+ >>> PluggableAuthenticationServiceAddSubscriber(stub, event)
+ >>> stub.earmark is not None
+ True
+
+ The subscriber does not modify an earmark for the auth service if one
+ exists already.
+
+ >>> earmark = 'my sample earmark'
+ >>> stub = PluggableAuthStub(earmark=earmark)
+ >>> event = ''
+ >>> PluggableAuthenticationServiceAddSubscriber(stub, event)
+ >>> stub.earmark == earmark
+ True
Property changes on: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/pluggableauth.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/principal.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/principal.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/principal.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -0,0 +1,76 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Pluggable Authentication service implementation.
+
+$Id: principal.py 26176 2004-07-07 18:34:31Z jim $
+"""
+from warnings import warn
+from persistent import Persistent
+from zope.interface import implements
+from zope.app.container.contained import Contained
+from interfaces import IUserSchemafied
+from interfaces import IPrincipalSourceContained
+
+
+
+class SimplePrincipal(Persistent, Contained):
+ """A no-frills IUserSchemafied implementation."""
+
+ implements(IUserSchemafied, IPrincipalSourceContained)
+
+ def __init__(self, login, password, title='', description=''):
+ self._id = ''
+ self.login = login
+ self.password = password
+ self.title = title
+ self.description = description
+
+ def _getId(self):
+ source = self.__parent__
+ auth = source.__parent__
+ return "%s\t%s\t%s" %(auth.earmark, source.__name__, self._id)
+
+ def _setId(self, id):
+ self._id = id
+
+ id = property(_getId, _setId)
+
+ def getTitle(self):
+ warn("Use principal.title instead of principal.getTitle().",
+ DeprecationWarning, 2)
+ return self.title
+
+ def getDescription(self):
+ warn("Use principal.description instead of principal.getDescription().",
+ DeprecationWarning, 2)
+ return self.description
+
+ def getLogin(self):
+ """See IReadUser."""
+ return self.login
+
+ def validate(self, test_password):
+ """ See IReadUser.
+
+ >>> pal = SimplePrincipal('gandalf', 'shadowfax', 'The Grey Wizard',
+ ... 'Cool old man with neato fireworks. '
+ ... 'Has a nice beard.')
+ >>> pal.validate('shdaowfax')
+ False
+ >>> pal.validate('shadowfax')
+ True
+ """
+ return test_password == self.password
+
+
Property changes on: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/principal.py
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/authsetup.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/authsetup.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/authsetup.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -26,9 +26,10 @@
from zope.publisher.interfaces.http import IHTTPCredentials
from zope.app.security.interfaces import ILoginPassword
from zope.app.security.basicauthadapter import BasicAuthAdapter
-from zope.app.pluggableauth import \
- PrincipalAuthenticationView, PluggableAuthenticationService, \
+from zope.app.pluggableauth import PluggableAuthenticationService, \
BTreePrincipalSource, SimplePrincipal
+from zope.app.pluggableauth.browser.authentication import \
+ PrincipalAuthenticationView
from zope.app.pluggableauth.interfaces import IPrincipalSource
class AuthSetup(placefulsetup.PlacefulSetup):
Added: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/test_btreesource.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/test_btreesource.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/test_btreesource.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -0,0 +1,30 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Pluggable Auth Tests
+
+$Id: test_source.py 25177 2004-06-02 13:17:31Z jim $
+"""
+from unittest import TestCase, TestSuite, main, makeSuite
+from zope.testing.doctestunit import DocTestSuite
+from zope.app.tests.placelesssetup import setUp, tearDown
+
+
+def test_suite():
+ t1 = DocTestSuite('zope.app.pluggableauth.btreesource',
+ setUp=setUp, tearDown=tearDown)
+ return TestSuite((t1,))
+
+
+if __name__=='__main__':
+ main(defaultTest='test_suite')
\ No newline at end of file
Property changes on: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/test_btreesource.py
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/test_pluggableauth.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/test_pluggableauth.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/test_pluggableauth.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -28,15 +28,16 @@
from zope.app.tests import setup
from zope.exceptions import NotFoundError
-from zope.app.pluggableauth import BTreePrincipalSource, \
- SimplePrincipal, PluggableAuthenticationService, \
- PrincipalAuthenticationView
-from zope.app.pluggableauth.interfaces import IPrincipalSource
-
-from zope.app.pluggableauth.interfaces import IUserSchemafied
from zope.app.security.interfaces import IPrincipal, ILoginPassword
from zope.app.security.basicauthadapter import BasicAuthAdapter
+from zope.app.pluggableauth.interfaces import IUserSchemafied
+from zope.app.pluggableauth.interfaces import IPrincipalSource
+from zope.app.pluggableauth import BTreePrincipalSource, \
+ SimplePrincipal, PluggableAuthenticationService
+from zope.app.pluggableauth.browser.authentication import \
+ PrincipalAuthenticationView
+
from zope.publisher.browser import TestRequest as Request
from zope.app.tests.placelesssetup import setUp, tearDown
@@ -151,21 +152,16 @@
p = self._slinkp
self.assertEqual(p, one.getPrincipal(p.id))
-class PrincipalAuthenticationViewTest(Setup):
- def test_authenticate(self):
- request = self.getRequest('chrism', '123')
- view = PrincipalAuthenticationView(self._one, request)
- self.assertEqual(self._chrism, view.authenticate())
-
-
def test_suite():
+ import zope.testing.doctestunit as doctestunit
+ import zope.app.pluggableauth as package
t1 = makeSuite(AuthServiceTest)
- t2 = DocTestSuite('zope.app.pluggableauth',
- setUp=setUp, tearDown=tearDown)
+ t2 = doctestunit.DocFileSuite(package, 'pluggableauth.txt')
+ #t2 = DocTestSuite('zope.app.pluggableauth.pluggableauth.txt',
+ # setUp=setUp, tearDown=tearDown)
t3 = makeSuite(BTreePrincipalSourceTest)
- t4 = makeSuite(PrincipalAuthenticationViewTest)
- return TestSuite((t1, t2, t3, t4))
+ return TestSuite((t1, t2, t3))
if __name__=='__main__':
Added: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/test_principal.py
===================================================================
--- Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/test_principal.py 2004-07-10 17:45:38 UTC (rev 26407)
+++ Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/test_principal.py 2004-07-10 20:45:08 UTC (rev 26408)
@@ -0,0 +1,31 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Pluggable Auth Tests
+
+$Id: test_principal.py 25177 2004-06-02 13:17:31Z jim $
+"""
+from unittest import TestCase, TestSuite, main, makeSuite
+from zope.testing.doctestunit import DocTestSuite
+from zope.app.tests.placelesssetup import setUp, tearDown
+
+
+def test_suite():
+ t1 = DocTestSuite('zope.app.pluggableauth.principal',
+ setUp=setUp, tearDown=tearDown)
+ return TestSuite((t1,))
+
+
+if __name__=='__main__':
+ main(defaultTest='test_suite')
+
Property changes on: Zope3/branches/roger-ldapauth/src/zope/app/pluggableauth/tests/test_principal.py
___________________________________________________________________
Name: svn:eol-style
+ native
More information about the Zope3-Checkins
mailing list