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

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

Add local roles dicts for user accounts. That seems to
need pretty much machinery, but seems also to work. So,
why not?

We have a new event type, that should be fired when
a local role is set or unset somewhere.

We have also two new event subscribers, one listening
to the new event (and then updates the user account
local roles listings), and another one listening to
IObjectRemoved events.

The latter is the trick to keep the local role listings
in user accounts more or less up-to-date. Without it
these lists would grow and grow, not noticing that
the objects they refer to, have gone already.

We now must think about subscribing to other events.
What happens, when an object is moved or copied.
Will the local roles then be copied as well? And would
that fact be reflected in user accounts?

Beside this we have to find all places in sources
where local roles are set/unset and trigger the new
LocalRoleSetEvent? defined in users.py.

Samples for the whole new stuff are in authentication.txt.

File size: 5.8 KB
Line 
1"""Authentication for WAeUP portals.
2"""
3import grok
4from zope.component import getUtility, getUtilitiesFor
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)
19from zope.securitypolicy.interfaces import IPrincipalRoleManager
20from zope.securitypolicy.principalrole import principalRoleManager
21from waeup.sirp.interfaces import IUserAccount, IAuthPluginUtility
22
23def setup_authentication(pau):
24    """Set up plugguble authentication utility.
25
26    Sets up an IAuthenticatorPlugin and
27    ICredentialsPlugin (for the authentication mechanism)
28
29    Then looks for any external utilities that want to modify the PAU.
30    """
31    pau.credentialsPlugins = ['No Challenge if Authenticated', 'credentials']
32    pau.authenticatorPlugins = ['users']
33
34    # Give any third-party code and subpackages a chance to modify the PAU
35    auth_plugin_utilities = getUtilitiesFor(IAuthPluginUtility)
36    for name, util in auth_plugin_utilities:
37        util.register(pau)
38
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):
59    grok.implements(IUserAccount)
60
61    _local_roles = dict()
62
63    def __init__(self, name, password, title=None, description=None,
64                 roles = []):
65        self.name = name
66        if title is None:
67            title = name
68        if description is None:
69            description = title
70        self.title = title
71        self.description = description
72        self.setPassword(password)
73        self.setRoles(roles)
74        # We don't want to share this dict with other accounts
75        self._local_roles = dict()
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
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
90
91    def setRoles(self, roles):
92        prm = self._getPrincipalRoleManager()
93
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
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]
117        return
118
119    def _getPrincipalRoleManager(self):
120        portal = grok.getSite()
121        if portal is not None:
122            return IPrincipalRoleManager(portal)
123        return principalRoleManager
124
125class UserAuthenticatorPlugin(grok.GlobalUtility):
126    grok.provides(IAuthenticatorPlugin)
127    grok.name('users')
128
129    def authenticateCredentials(self, credentials):
130        if not isinstance(credentials, dict):
131            return None
132        if not ('login' in credentials and 'password' in credentials):
133            return None
134        account = self.getAccount(credentials['login'])
135
136        if account is None:
137            return None
138        if not account.checkPassword(credentials['password']):
139            return None
140        return PrincipalInfo(id=account.name,
141                             title=account.title,
142                             description=account.description)
143
144    def principalInfo(self, id):
145        account = self.getAccount(id)
146        if account is None:
147            return None
148        return PrincipalInfo(id=account.name,
149                             title=account.title,
150                             description=account.description)
151
152    def getAccount(self, login):
153        # ... look up the account object and return it ...
154        usercontainer = self.getUserContainer()
155        if usercontainer is None:
156            return
157        return usercontainer.get(login, None)
158
159    def addAccount(self, account):
160        usercontainer = self.getUserContainer()
161        if usercontainer is None:
162            return
163        # XXX: complain if name already exists...
164        usercontainer.addAccount(account)
165
166    def addUser(self, name, password, title=None, description=None):
167        usercontainer = self.getUserContainer()
168        if usercontainer is None:
169            return
170        usercontainer.addUser(name, password, title, description)
171
172    def getUserContainer(self):
173        site = grok.getSite()
174        return site['users']
Note: See TracBrowser for help on using the repository browser.