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

Last change on this file since 6933 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
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    """
[6661]21    pau.credentialsPlugins = ('No Challenge if Authenticated', 'credentials')
[6672]22    pau.authenticatorPlugins = ('users',)
[4073]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
[6673]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
[4073]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):
[4109]60    grok.implements(IUserAccount)
[4129]61
[6180]62    _local_roles = dict()
63
[4125]64    def __init__(self, name, password, title=None, description=None,
65                 roles = []):
[4073]66        self.name = name
[4087]67        if title is None:
68            title = name
69        if description is None:
70            description = title
71        self.title = title
72        self.description = description
[4073]73        self.setPassword(password)
[4129]74        self.setRoles(roles)
[6180]75        # We don't want to share this dict with other accounts
76        self._local_roles = dict()
[4073]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
[4129]86    def getRoles(self):
[6673]87        prm = get_principal_role_manager()
[4129]88        roles = [x[0] for x in prm.getRolesForPrincipal(self.name)
89                 if x[0].startswith('waeup.')]
90        return roles
[5055]91
[4129]92    def setRoles(self, roles):
[6673]93        prm = get_principal_role_manager()
[5055]94
[4129]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
[6180]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]
[6182]118        self._p_changed = True
[6180]119        return
120
[4073]121class UserAuthenticatorPlugin(grok.GlobalUtility):
[6625]122    grok.implements(IAuthenticatorPlugin)
[4073]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,
[4612]138                             title=account.title,
139                             description=account.description)
[4073]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,
[4612]146                             title=account.title,
147                             description=account.description)
[4073]148
149    def getAccount(self, login):
[4087]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
[4091]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)
[5055]168
[4087]169    def getUserContainer(self):
170        site = grok.getSite()
[4743]171        return site['users']
[6203]172
173@grok.subscribe(IUserAccount, grok.IObjectRemovedEvent)
[6839]174def handle_account_removed(account, event):
[6203]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.