source: TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/provider/authninterface/basic.py @ 5280

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/provider/authninterface/basic.py@5280
Revision 5280, 7.8 KB checked in by pjkersha, 10 years ago (diff)

Further improvements to the authorization middleware:

  • PEPFilter no longer explicitly calls the PEPResultHandlerMiddleware (This latter class is the WSGI component which handles the access denied response that the server returns). This is not necessary as it can set a 403 response in order to trigger multiHandlerIntercept callback function set in the MultiHandler? instance. This responds to all 403 type status codes by invoking the PEPResultHandlerMiddleware.
  • ndg.security.common.authz.msi: improvements to the PDP, PIP and Response classes.
  • ndg.security.test.integration.dap: added integration test for secured pyDAP service
Line 
1"""NDG Security Basic OpenID Authentication Interface.
2
3A demonstration implementation of an authentication interface for
4OpenIDProviderMiddleware WSGI.  Username/password and OpenId user identifier
5details are read from a config file and passed as keywords.  This class is not
6intended for production use.
7
8NERC DataGrid Project
9
10"""
11__author__ = "P J Kershaw"
12__date__ = "01/08/08"
13__copyright__ = "(C) 2009 Science and Technology Facilities Council"
14__contact__ = "Philip.Kershaw@stfc.ac.uk"
15__revision__ = "$Id$"
16import logging
17log = logging.getLogger(__name__)
18
19from ndg.security.server.wsgi.openid.provider import AbstractAuthNInterface, \
20    AuthNInterfaceInvalidCredentials, AuthNInterfaceRetrieveError, \
21    AuthNInterfaceConfigError, AuthNInterfaceUsername2IdentifierMismatch
22 
23   
24class BasicAuthNInterface(AbstractAuthNInterface):
25    '''Basic Authentication interface class for OpenIDProviderMiddleware
26   
27    it uses username/password details retrieved from config file / keyword
28    entry.  This class is for testing only.  NOT for production use'''
29   
30    propertyKeyNames = ('userCreds', 'username2UserIdentifiers')
31   
32    def __init__(self, **prop):
33        """Make any initial settings
34       
35        Settings are held in a dictionary which can be set from **prop,
36        a call to setProperties() or by passing settings in an XML file
37        given by propFilePath
38       
39        @type **prop: dict
40        @param **prop: set properties via keywords
41        @raise AuthNInterfaceConfigError: error with configuration
42        """
43        # Test/Admin username/password set from ini/kw args
44        userCreds = prop.get('userCreds')
45        if userCreds:
46            self._userCreds = dict([i.strip().split(':')
47                                    for i in userCreds.split(',')])
48        else:
49            raise AuthNInterfaceConfigError('No "userCreds" config option '
50                                            "found")
51           
52        user2Identifier = prop.get('username2UserIdentifiers')
53        if user2Identifier:
54            self._username2Identifier = {}
55            for i in user2Identifier.split():
56                username, identifierStr = i.strip().split(':')
57                identifiers = tuple(identifierStr.split(','))
58                self._username2Identifier[username] = identifiers
59        else:
60            raise AuthNInterfaceConfigError('No "user2Identifier" config '
61                                            'option found')
62       
63        userCredNames = self._userCreds.keys()
64        userCredNames.sort()
65        username2IdentifierNames = self._username2Identifier.keys()
66        username2IdentifierNames.sort()
67        if userCredNames != username2IdentifierNames:
68            raise AuthNInterfaceConfigError('Mismatch between usernames in '
69                                            '"userCreds" and '
70                                            '"username2UserIdentifiers" '
71                                            'options')   
72   
73    def logon(self, environ, userIdentifier, username, password):
74        """Interface login method
75       
76        @type environ: dict
77        @param environ: standard WSGI environ parameter
78
79        @type username: basestring
80        @param username: user identifier
81       
82        @type password: basestring
83        @param password: corresponding password for username givens
84       
85        @raise AuthNInterfaceInvalidCredentials: invalid username/password
86        @raise AuthNInterfaceUsername2IdentifierMismatch: no OpenID matching
87        the given username
88        """
89        if self._userCreds.get(username) != password:
90            raise AuthNInterfaceInvalidCredentials()
91       
92        if userIdentifier is not None and \
93           userIdentifier not in self._username2Identifier.get(username):
94            raise AuthNInterfaceUsername2IdentifierMismatch()
95
96    def logout(self):
97        pass
98       
99    def username2UserIdentifiers(self, environ, username):
100        """Map the login username to an identifier which will become the
101        unique path suffix to the user's OpenID identifier.  The
102        OpenIDProviderMiddleware takes self.urls['id_url'] and adds it to this
103        identifier:
104       
105            identifier = self._authN.username2UserIdentifiers(environ,username)
106            identityURL = self.urls['url_id'] + '/' + identifier
107       
108        @type environ: dict
109        @param environ: standard WSGI environ parameter
110
111        @type username: basestring
112        @param username: user identifier
113       
114        @rtype: tuple
115        @return: identifiers to be used to make OpenID user identity URLs.
116       
117        @raise AuthNInterfaceRetrieveError: error with retrieval of information
118        to identifier e.g. error with database look-up.
119        """
120        try:
121            return self._username2Identifier[username]
122        except KeyError:
123            raise AuthNInterfaceRetrieveError('No entries for "%s" user' % 
124                                              username)
125
126
127from ndg.security.server.wsgi.utils.sessionmanagerclient import \
128    WSGISessionManagerClient, AuthNServiceInvalidCredentials
129   
130class BasicSessionManagerOpenIDAuthNInterface(BasicAuthNInterface):
131    '''Authentication interface class for OpenIDProviderMiddleware to enable
132    authentication to a Session Manager instance running in the same WSGI
133    stack or via a SOAP call to a remote service.  This is a basic test
134    interface.  See sessionmanager module for a full implementation linking to
135    a database via SQLAlchemy
136    '''
137   
138    def __init__(self, **prop):
139        """Extends BasicAuthNInterface initialising Session Manager Client
140       
141        @type **prop: dict
142        @param **prop: set properties via keywords
143        @raise AuthNInterfaceConfigError: error with configuration
144        """
145        user2Identifier = prop.pop('username2UserIdentifiers')
146        if user2Identifier:
147            self._username2Identifier = {}
148            for i in user2Identifier.split():
149                username, identifierStr = i.strip().split(':')
150                identifiers = tuple(identifierStr.split(','))
151                self._username2Identifier[username] = identifiers
152        else:
153            raise AuthNInterfaceConfigError('No "user2Identifier" config '
154                                            'option found')
155
156        self._client = WSGISessionManagerClient(**prop)
157       
158        # This is set at login
159        self.sessionId = None
160       
161    def logon(self, environ, userIdentifier, username, password):
162        """Interface login method
163       
164        @type environ: dict
165        @param environ: standard WSGI environ parameter
166       
167        @type username: basestring
168        @param username: user identifier
169       
170        @type password: basestring
171        @param password: corresponding password for username givens
172       
173        @raise AuthNInterfaceUsername2IdentifierMismatch: no OpenID
174        identifiers match the given username
175        @raise AuthNInterfaceInvalidCredentials: invalid username/password
176        """       
177        if userIdentifier is not None and \
178           userIdentifier not in self._username2Identifier.get(username):
179            raise AuthNInterfaceUsername2IdentifierMismatch()
180       
181        try:
182            self._client.environ = environ
183            connectResp = self._client.connect(username, passphrase=password)
184            self.sessionId = connectResp[-1]
185            log.debug("Connected to Session Manager with session ID: %s", 
186                      self.sessionId)
187
188        except AuthNServiceInvalidCredentials, e:
189            log.exception(e)
190            raise AuthNInterfaceInvalidCredentials()
191
192    def logout(self):
193        """logout from the Session Manager
194        """
195        try:
196            self._client.disconnect(sessID=self.sessionId)
197           
198        except Exception, e:
199            log.exception(e)
200            raise AuthNInterfaceInvalidCredentials()
Note: See TracBrowser for help on using the repository browser.