source: main/waeup.sirp/trunk/src/waeup/sirp/authentication.py @ 7156

Last change on this file since 7156 was 7147, checked in by Henrik Bettermann, 13 years ago

Implement PasswordValidator? global utility as suggested by Uli.

  • Property svn:keywords set to Id
File size: 6.7 KB
RevLine 
[4073]1"""Authentication for WAeUP portals.
2"""
3import grok
[5900]4from zope.component import getUtility, getUtilitiesFor
[6610]5from zope.pluggableauth.plugins.session import SessionCredentialsPlugin
6from zope.pluggableauth.interfaces import (
[5055]7        ICredentialsPlugin, IAuthenticatorPlugin, IPrincipalInfo)
[6610]8from zope.password.interfaces import IPasswordManager
[4129]9from zope.securitypolicy.interfaces import IPrincipalRoleManager
10from zope.securitypolicy.principalrole import principalRoleManager
[7147]11from waeup.sirp.interfaces import (
12    IUserAccount, IAuthPluginUtility, IPasswordValidator)
[4073]13
14def setup_authentication(pau):
15    """Set up plugguble authentication utility.
16
17    Sets up an IAuthenticatorPlugin and
18    ICredentialsPlugin (for the authentication mechanism)
[5900]19
20    Then looks for any external utilities that want to modify the PAU.
[4073]21    """
[6661]22    pau.credentialsPlugins = ('No Challenge if Authenticated', 'credentials')
[6672]23    pau.authenticatorPlugins = ('users',)
[4073]24
[5900]25    # Give any third-party code and subpackages a chance to modify the PAU
26    auth_plugin_utilities = getUtilitiesFor(IAuthPluginUtility)
[5901]27    for name, util in auth_plugin_utilities:
[5900]28        util.register(pau)
29
[6673]30def get_principal_role_manager():
31    """Get a role manager for principals.
32
33    If we are currently 'in a site', return the role manager for the
34    portal or the global rolemanager else.
35    """
36    portal = grok.getSite()
37    if portal is not None:
38        return IPrincipalRoleManager(portal)
39    return principalRoleManager
40
[4073]41class WAeUPSessionCredentialsPlugin(grok.GlobalUtility,
42                                    SessionCredentialsPlugin):
43    grok.provides(ICredentialsPlugin)
44    grok.name('credentials')
45
46    loginpagename = 'login'
47    loginfield = 'form.login'
48    passwordfield = 'form.password'
49
50class PrincipalInfo(object):
51    grok.implements(IPrincipalInfo)
52
53    def __init__(self, id, title, description):
54        self.id = id
55        self.title = title
56        self.description = description
57        self.credentialsPlugin = None
58        self.authenticatorPlugin = None
59
60class Account(grok.Model):
[4109]61    grok.implements(IUserAccount)
[4129]62
[6180]63    _local_roles = dict()
64
[4125]65    def __init__(self, name, password, title=None, description=None,
66                 roles = []):
[4073]67        self.name = name
[4087]68        if title is None:
69            title = name
70        if description is None:
71            description = title
72        self.title = title
73        self.description = description
[4073]74        self.setPassword(password)
[4129]75        self.setRoles(roles)
[6180]76        # We don't want to share this dict with other accounts
77        self._local_roles = dict()
[4073]78
79    def setPassword(self, password):
80        passwordmanager = getUtility(IPasswordManager, 'SHA1')
81        self.password = passwordmanager.encodePassword(password)
82
83    def checkPassword(self, password):
84        passwordmanager = getUtility(IPasswordManager, 'SHA1')
85        return passwordmanager.checkPassword(self.password, password)
86
[4129]87    def getRoles(self):
[6673]88        prm = get_principal_role_manager()
[4129]89        roles = [x[0] for x in prm.getRolesForPrincipal(self.name)
90                 if x[0].startswith('waeup.')]
91        return roles
[5055]92
[4129]93    def setRoles(self, roles):
[6673]94        prm = get_principal_role_manager()
[5055]95
[4129]96        old_roles = self.getRoles()
97        for role in old_roles:
98            # Remove old roles, not to be set now...
99            if role.startswith('waeup.') and role not in roles:
100                prm.unsetRoleForPrincipal(role, self.name)
101
102        for role in roles:
103            prm.assignRoleToPrincipal(role, self.name)
104
105    roles = property(getRoles, setRoles)
106
[6180]107    def getLocalRoles(self):
108        return self._local_roles
109
110    def notifyLocalRoleChanged(self, obj, role_id, granted=True):
111        objects = self._local_roles.get(role_id, [])
112        if granted and obj not in objects:
113            objects.append(obj)
114        if not granted and obj in objects:
115            objects.remove(obj)
116        self._local_roles[role_id] = objects
117        if len(objects) == 0:
118            del self._local_roles[role_id]
[6182]119        self._p_changed = True
[6180]120        return
121
[4073]122class UserAuthenticatorPlugin(grok.GlobalUtility):
[6625]123    grok.implements(IAuthenticatorPlugin)
[4073]124    grok.provides(IAuthenticatorPlugin)
125    grok.name('users')
126
127    def authenticateCredentials(self, credentials):
128        if not isinstance(credentials, dict):
129            return None
130        if not ('login' in credentials and 'password' in credentials):
131            return None
132        account = self.getAccount(credentials['login'])
133
134        if account is None:
135            return None
136        if not account.checkPassword(credentials['password']):
137            return None
138        return PrincipalInfo(id=account.name,
[4612]139                             title=account.title,
140                             description=account.description)
[4073]141
142    def principalInfo(self, id):
143        account = self.getAccount(id)
144        if account is None:
145            return None
146        return PrincipalInfo(id=account.name,
[4612]147                             title=account.title,
148                             description=account.description)
[4073]149
150    def getAccount(self, login):
[4087]151        # ... look up the account object and return it ...
152        usercontainer = self.getUserContainer()
153        if usercontainer is None:
154            return
155        return usercontainer.get(login, None)
156
157    def addAccount(self, account):
158        usercontainer = self.getUserContainer()
159        if usercontainer is None:
160            return
161        # XXX: complain if name already exists...
162        usercontainer.addAccount(account)
163
[4091]164    def addUser(self, name, password, title=None, description=None):
165        usercontainer = self.getUserContainer()
166        if usercontainer is None:
167            return
168        usercontainer.addUser(name, password, title, description)
[5055]169
[4087]170    def getUserContainer(self):
171        site = grok.getSite()
[4743]172        return site['users']
[6203]173
[7147]174class PasswordValidator(grok.GlobalUtility):
175
176  grok.implements(IPasswordValidator)
177
178  def validate_password(self, pw, pw_repeat):
179       errors = []
180       if len(pw) < 3:
181         errors.append('Password must have at least 3 chars.')
182       if pw != pw_repeat:
183         errors.append('Passwords do not match.')
184       return errors
185
[6203]186@grok.subscribe(IUserAccount, grok.IObjectRemovedEvent)
[6839]187def handle_account_removed(account, event):
[6203]188    """When an account is removed, local roles might have to be deleted.
189    """
190    local_roles = account.getLocalRoles()
191    principal = account.name
192    for role_id, object_list in local_roles.items():
193        for object in object_list:
194            try:
195                role_manager = IPrincipalRoleManager(object)
196            except TypeError:
197                # No role manager, no roles to remove
198                continue
199            role_manager.unsetRoleForPrincipal(role_id, principal)
200    return
Note: See TracBrowser for help on using the repository browser.