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

Last change on this file since 6376 was 6203, checked in by uli, 13 years ago

#38

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