diff --git a/organize/README.txt b/organize/README.txt index a92e36a..68b8f8b 100644 --- a/organize/README.txt +++ b/organize/README.txt @@ -230,6 +230,15 @@ We need a principal for testing the login stuff: False +Pure Person-based Authentication +================================ + +The person-based authenticator provides authentication without having to +store a persistent (internal) principal object. + + >>> from loops.organize.auth import PersonBasedAuthenticator + + Security ======== diff --git a/organize/auth.py b/organize/auth.py new file mode 100644 index 0000000..c87c677 --- /dev/null +++ b/organize/auth.py @@ -0,0 +1,76 @@ +# +# Copyright (c) 2009 Helmut Merz helmutm@cy55.de +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +Specialized authentication components. + +$Id$ +""" + +from persistent import Persistent +from zope.app.container.contained import Contained +from zope import component +from zope.interface import implements +from zope.app.authentication.interfaces import IAuthenticatorPlugin +from zope.app.authentication.principalfolder import PrincipalInfo +from zope.app.principalannotation.interfaces import IPrincipalAnnotationUtility +from zope.app.security.interfaces import IAuthentication +from zope.cachedescriptors.property import Lazy + + +class PersonBasedAuthenticator(Persistent, Contained): + + implements(IAuthenticatorPlugin) + + def __init__(self, prefix=''): + self.prefix = unicode(prefix) + + def authenticateCredentials(self, credentials): + if not isinstance(credentials, dict): + return None + login = credentials.get('login') + password = credentials.get('password') + if not login or not password : + return None + id = self.prefix + login + if self._checkPassword(id, password): + return PrincipalInfo(id, login, login, u'') + return None + + def principalInfo(self, id): + if id.startswith(self.prefix): + login = id[len(self.prefix):] + if login: + return PrincipalInfo(id, login, login, u'') + + def setPassword(self, login, password): + id = self.prefix + login + pa = self.getPrincipalAnnotations(id) + pa['loops.organize.password'] = password + + @Lazy + def principalAnnotations(self): + return component.getUtility(IPrincipalAnnotationUtility) + + def getPrincipalAnnotations(id): + return self.principalAnnotations.getAnnotationsById(id) + + def _checkPassword(self, id, password): + pa = self.getPrincipalAnnotations(id) + return pa.get('loops.organize.password') == password + diff --git a/organize/member.py b/organize/member.py index b9cbd9a..4d7907b 100644 --- a/organize/member.py +++ b/organize/member.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2008 Helmut Merz helmutm@cy55.de +# Copyright (c) 2009 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -58,6 +58,9 @@ class MemberRegistrationManager(object): groups=[], useExisting=False, **kw): # step 1: create an internal principal in the loops principal folder: pFolder = getPrincipalFolder(self.context) + # if isinstance(pFolder, PersonBasedAuthenticator): + # pFolder.setPassword(userId, password) + # else: title = firstName and ' '.join((firstName, lastName)) or lastName principal = InternalPrincipal(userId, password, title) if useExisting: diff --git a/organize/party.py b/organize/party.py index 022600a..495aa27 100644 --- a/organize/party.py +++ b/organize/party.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2006 Helmut Merz helmutm@cy55.de +# Copyright (c) 2009 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -24,7 +24,6 @@ $Id$ from persistent.mapping import PersistentMapping from zope import interface, component -from zope.app import zapi from zope.app.principalannotation import annotations from zope.app.security.interfaces import IAuthentication, PrincipalLookupError from zope.component import adapts @@ -33,6 +32,7 @@ from zope.cachedescriptors.property import Lazy from zope.schema.interfaces import ValidationError from zope.app.form.interfaces import WidgetInputError from zope.security.proxy import removeSecurityProxy +from zope.traversing.api import getName from cybertools.organize.party import Person as BasePerson from cybertools.relation.interfaces import IRelationRegistry @@ -91,7 +91,7 @@ class Person(AdapterBase, BasePerson): if person is not None and person != self.context: raise ValueError( 'There is alread a person (%s) assigned to user %s.' - % (zapi.getName(person), userId)) + % (getName(person), userId)) pa = annotations(principal) loopsId = util.getUidForObject(self.context.getLoopsRoot()) ann = pa.get(ANNOTATION_KEY)