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

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

Remove BBB import.

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.provides(IAuthenticatorPlugin)
118    grok.name('users')
119
120    def authenticateCredentials(self, credentials):
121        if not isinstance(credentials, dict):
122            return None
123        if not ('login' in credentials and 'password' in credentials):
124            return None
125        account = self.getAccount(credentials['login'])
126
127        if account is None:
128            return None
129        if not account.checkPassword(credentials['password']):
130            return None
131        return PrincipalInfo(id=account.name,
132                             title=account.title,
133                             description=account.description)
134
135    def principalInfo(self, id):
136        account = self.getAccount(id)
137        if account is None:
138            return None
139        return PrincipalInfo(id=account.name,
140                             title=account.title,
141                             description=account.description)
142
143    def getAccount(self, login):
144        # ... look up the account object and return it ...
145        usercontainer = self.getUserContainer()
146        if usercontainer is None:
147            return
148        return usercontainer.get(login, None)
149
150    def addAccount(self, account):
151        usercontainer = self.getUserContainer()
152        if usercontainer is None:
153            return
154        # XXX: complain if name already exists...
155        usercontainer.addAccount(account)
156
157    def addUser(self, name, password, title=None, description=None):
158        usercontainer = self.getUserContainer()
159        if usercontainer is None:
160            return
161        usercontainer.addUser(name, password, title, description)
162
163    def getUserContainer(self):
164        site = grok.getSite()
165        return site['users']
166
167@grok.subscribe(IUserAccount, grok.IObjectRemovedEvent)
168def handle_account_removal(account, event):
169    """When an account is removed, local roles might have to be deleted.
170    """
171    local_roles = account.getLocalRoles()
172    principal = account.name
173    for role_id, object_list in local_roles.items():
174        for object in object_list:
175            try:
176                role_manager = IPrincipalRoleManager(object)
177            except TypeError:
178                # No role manager, no roles to remove
179                continue
180            role_manager.unsetRoleForPrincipal(role_id, principal)
181    return
Note: See TracBrowser for help on using the repository browser.