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

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

Make failing authentication test shut up.

File size: 6.2 KB
Line 
1"""Authentication for WAeUP portals.
2"""
3import grok
4from zope.component import getUtility, getUtilitiesFor
5from zope.pluggableauth.plugins.session import SessionCredentialsPlugin
6from zope.pluggableauth.interfaces import (
7        ICredentialsPlugin, IAuthenticatorPlugin, IPrincipalInfo)
8from zope.password.interfaces import IPasswordManager
9from zope.securitypolicy.interfaces import IPrincipalRoleManager
10from zope.securitypolicy.principalrole import principalRoleManager
11from waeup.sirp.interfaces import IUserAccount, IAuthPluginUtility
12
13def setup_authentication(pau):
14    """Set up plugguble authentication utility.
15
16    Sets up an IAuthenticatorPlugin and
17    ICredentialsPlugin (for the authentication mechanism)
18
19    Then looks for any external utilities that want to modify the PAU.
20    """
21    pau.credentialsPlugins = ['No Challenge if Authenticated', 'credentials']
22    pau.authenticatorPlugins = ['users']
23
24    # Give any third-party code and subpackages a chance to modify the PAU
25    auth_plugin_utilities = getUtilitiesFor(IAuthPluginUtility)
26    for name, util in auth_plugin_utilities:
27        util.register(pau)
28
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):
49    grok.implements(IUserAccount)
50
51    _local_roles = dict()
52
53    def __init__(self, name, password, title=None, description=None,
54                 roles = []):
55        self.name = name
56        if title is None:
57            title = name
58        if description is None:
59            description = title
60        self.title = title
61        self.description = description
62        self.setPassword(password)
63        self.setRoles(roles)
64        # We don't want to share this dict with other accounts
65        self._local_roles = dict()
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
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
80
81    def setRoles(self, roles):
82        prm = self._getPrincipalRoleManager()
83
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
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]
107        self._p_changed = True
108        return
109
110    def _getPrincipalRoleManager(self):
111        portal = grok.getSite()
112        if portal is not None:
113            return IPrincipalRoleManager(portal)
114        return principalRoleManager
115
116class UserAuthenticatorPlugin(grok.GlobalUtility):
117    grok.implements(IAuthenticatorPlugin)
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,
133                             title=account.title,
134                             description=account.description)
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,
141                             title=account.title,
142                             description=account.description)
143
144    def getAccount(self, login):
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
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)
163
164    def getUserContainer(self):
165        site = grok.getSite()
166        return site['users']
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.