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

Last change on this file since 6412 was 6203, checked in by uli, 14 years ago

#38

File size: 6.4 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        self._p_changed = True
118        return
119
120    def _getPrincipalRoleManager(self):
121        portal = grok.getSite()
122        if portal is not None:
123            return IPrincipalRoleManager(portal)
124        return principalRoleManager
125
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,
142                             title=account.title,
143                             description=account.description)
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,
150                             title=account.title,
151                             description=account.description)
152
153    def getAccount(self, login):
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
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)
172
173    def getUserContainer(self):
174        site = grok.getSite()
175        return site['users']
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.