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

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

Use common and coherent naming convention for all event handlers.

File size: 6.3 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
29def get_principal_role_manager():
30    """Get a role manager for principals.
31
32    If we are currently 'in a site', return the role manager for the
33    portal or the global rolemanager else.
34    """
35    portal = grok.getSite()
36    if portal is not None:
37        return IPrincipalRoleManager(portal)
38    return principalRoleManager
39
40class WAeUPSessionCredentialsPlugin(grok.GlobalUtility,
41                                    SessionCredentialsPlugin):
42    grok.provides(ICredentialsPlugin)
43    grok.name('credentials')
44
45    loginpagename = 'login'
46    loginfield = 'form.login'
47    passwordfield = 'form.password'
48
49class PrincipalInfo(object):
50    grok.implements(IPrincipalInfo)
51
52    def __init__(self, id, title, description):
53        self.id = id
54        self.title = title
55        self.description = description
56        self.credentialsPlugin = None
57        self.authenticatorPlugin = None
58
59class Account(grok.Model):
60    grok.implements(IUserAccount)
61
62    _local_roles = dict()
63
64    def __init__(self, name, password, title=None, description=None,
65                 roles = []):
66        self.name = name
67        if title is None:
68            title = name
69        if description is None:
70            description = title
71        self.title = title
72        self.description = description
73        self.setPassword(password)
74        self.setRoles(roles)
75        # We don't want to share this dict with other accounts
76        self._local_roles = dict()
77
78    def setPassword(self, password):
79        passwordmanager = getUtility(IPasswordManager, 'SHA1')
80        self.password = passwordmanager.encodePassword(password)
81
82    def checkPassword(self, password):
83        passwordmanager = getUtility(IPasswordManager, 'SHA1')
84        return passwordmanager.checkPassword(self.password, password)
85
86    def getRoles(self):
87        prm = get_principal_role_manager()
88        roles = [x[0] for x in prm.getRolesForPrincipal(self.name)
89                 if x[0].startswith('waeup.')]
90        return roles
91
92    def setRoles(self, roles):
93        prm = get_principal_role_manager()
94
95        old_roles = self.getRoles()
96        for role in old_roles:
97            # Remove old roles, not to be set now...
98            if role.startswith('waeup.') and role not in roles:
99                prm.unsetRoleForPrincipal(role, self.name)
100
101        for role in roles:
102            prm.assignRoleToPrincipal(role, self.name)
103
104    roles = property(getRoles, setRoles)
105
106    def getLocalRoles(self):
107        return self._local_roles
108
109    def notifyLocalRoleChanged(self, obj, role_id, granted=True):
110        objects = self._local_roles.get(role_id, [])
111        if granted and obj not in objects:
112            objects.append(obj)
113        if not granted and obj in objects:
114            objects.remove(obj)
115        self._local_roles[role_id] = objects
116        if len(objects) == 0:
117            del self._local_roles[role_id]
118        self._p_changed = True
119        return
120
121class UserAuthenticatorPlugin(grok.GlobalUtility):
122    grok.implements(IAuthenticatorPlugin)
123    grok.provides(IAuthenticatorPlugin)
124    grok.name('users')
125
126    def authenticateCredentials(self, credentials):
127        if not isinstance(credentials, dict):
128            return None
129        if not ('login' in credentials and 'password' in credentials):
130            return None
131        account = self.getAccount(credentials['login'])
132
133        if account is None:
134            return None
135        if not account.checkPassword(credentials['password']):
136            return None
137        return PrincipalInfo(id=account.name,
138                             title=account.title,
139                             description=account.description)
140
141    def principalInfo(self, id):
142        account = self.getAccount(id)
143        if account is None:
144            return None
145        return PrincipalInfo(id=account.name,
146                             title=account.title,
147                             description=account.description)
148
149    def getAccount(self, login):
150        # ... look up the account object and return it ...
151        usercontainer = self.getUserContainer()
152        if usercontainer is None:
153            return
154        return usercontainer.get(login, None)
155
156    def addAccount(self, account):
157        usercontainer = self.getUserContainer()
158        if usercontainer is None:
159            return
160        # XXX: complain if name already exists...
161        usercontainer.addAccount(account)
162
163    def addUser(self, name, password, title=None, description=None):
164        usercontainer = self.getUserContainer()
165        if usercontainer is None:
166            return
167        usercontainer.addUser(name, password, title, description)
168
169    def getUserContainer(self):
170        site = grok.getSite()
171        return site['users']
172
173@grok.subscribe(IUserAccount, grok.IObjectRemovedEvent)
174def handle_account_removed(account, event):
175    """When an account is removed, local roles might have to be deleted.
176    """
177    local_roles = account.getLocalRoles()
178    principal = account.name
179    for role_id, object_list in local_roles.items():
180        for object in object_list:
181            try:
182                role_manager = IPrincipalRoleManager(object)
183            except TypeError:
184                # No role manager, no roles to remove
185                continue
186            role_manager.unsetRoleForPrincipal(role_id, principal)
187    return
Note: See TracBrowser for help on using the repository browser.