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

Last change on this file since 6643 was 6625, checked in by uli, 13 years ago

Make failing authentication test shut up.

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