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

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/authninterface/basic.py@7077
Revision 7077, 8.1 KB checked in by pjkersha, 9 years ago (diff)
  • Property svn:keywords set to Id
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.authninterface import \
20    AbstractAuthNInterface, AuthNInterfaceInvalidCredentials, \
21    AuthNInterfaceRetrieveError, AuthNInterfaceConfigError, \
22    AuthNInterfaceUsername2IdentifierMismatch
23 
24   
25class BasicAuthNInterface(AbstractAuthNInterface):
26    '''Basic Authentication interface class for OpenIDProviderMiddleware
27   
28    it uses username/password details retrieved from config file / keyword
29    entry.  This class is for testing only.  NOT for production use'''
30   
31    IDENTITY_URI_TMPL_KEYNAME = 'identityUriTemplate'
32    USERCREDS_PROPERTY_KEYNAME = 'userCreds'
33    USERCREDS_KEYNAMES = ('password', 'identifiers')
34   
35    propertyKeyNames = (
36        USERCREDS_PROPERTY_KEYNAME
37    )
38   
39    getUserIdentifier = staticmethod(lambda identityURI: 
40                                     identityURI.rsplit('/')[-1])
41   
42    def __init__(self, **prop):
43        """Make any initial settings
44       
45        Settings are held in a dictionary which can be set from **prop,
46        a call to setProperties() or by passing settings in an XML file
47        given by propFilePath
48       
49        @type **prop: dict
50        @param **prop: set properties via keywords
51        @raise AuthNInterfaceConfigError: error with configuration
52        """
53        # Test/Admin username/password set from ini/kw args
54        self._identityUriTemplate = prop.get(
55                                BasicAuthNInterface.IDENTITY_URI_TMPL_KEYNAME)
56        userCredsField = prop.get(
57                                BasicAuthNInterface.USERCREDS_PROPERTY_KEYNAME)
58        if not userCredsField:
59            raise AuthNInterfaceConfigError('No "%s" config option found' %
60                                BasicAuthNInterface.USERCREDS_PROPERTY_KEYNAME)
61
62        self._userCreds = {}
63        for userEntry in userCredsField.split(): 
64            # Split username, password and OpenID name list 
65            userCreds = userEntry.strip().split(':')
66           
67            # Split OpenID name list
68            userCreds[-1] = tuple(userCreds[-1].split(','))
69           
70            # Convert into a dictionary indexed by username
71            userCredsKeys = BasicAuthNInterface.USERCREDS_KEYNAMES
72            self._userCreds[userCreds[0]] = dict(zip(userCredsKeys, 
73                                                     userCreds[1:])) 
74   
75    def logon(self, environ, identityURI, username, password):
76        """Interface login method
77       
78        @type environ: dict
79        @param environ: standard WSGI environ parameter
80
81        @type identityURI: basestring
82        @param identityURI: user's identity URL e.g.
83        'https://joebloggs.somewhere.ac.uk/'
84
85        @type username: basestring
86        @param username: username
87       
88        @type password: basestring
89        @param password: corresponding password for username givens
90       
91        @raise AuthNInterfaceInvalidCredentials: invalid username/password
92        @raise AuthNInterfaceUsername2IdentifierMismatch: no OpenID matching
93        the given username
94        """
95        if self._userCreds.get(username, {}).get('password') != password:
96            raise AuthNInterfaceInvalidCredentials()
97       
98        # Assume identifier is at the end of the URI
99        if identityURI is not None:
100            userIdentifier = BasicAuthNInterface.getUserIdentifier(identityURI)
101       
102            if userIdentifier not in self._userCreds[username]['identifiers']:
103                raise AuthNInterfaceUsername2IdentifierMismatch()
104
105    def logout(self):
106        pass
107       
108    def username2UserIdentifiers(self, environ, username):
109        """Map the login username to an identifier which will become the
110        unique path suffix to the user's OpenID identifier.  The
111        OpenIDProviderMiddleware takes self.urls['id_url'] and adds it to this
112        identifier:
113       
114            identifier = self._authN.username2UserIdentifiers(environ,username)
115            identityURL = self.urls['url_id'] + '/' + identifier
116       
117        @type environ: dict
118        @param environ: standard WSGI environ parameter
119
120        @type username: basestring
121        @param username: user identifier
122       
123        @rtype: tuple
124        @return: identifiers to be used to make OpenID user identity URLs.
125       
126        @raise AuthNInterfaceRetrieveError: error with retrieval of information
127        to identifier e.g. error with database look-up.
128        """
129        try:
130            return self._userCreds[username]['identifiers']
131        except KeyError:
132            raise AuthNInterfaceRetrieveError('No entries for "%s" user' % 
133                                              username)
134
135
136from ndg.security.server.wsgi.utils.sessionmanagerclient import \
137    WSGISessionManagerClient, AuthNServiceInvalidCredentials
138   
139class BasicSessionManagerOpenIDAuthNInterface(BasicAuthNInterface):
140    '''Authentication interface class for OpenIDProviderMiddleware to enable
141    authentication to a Session Manager instance running in the same WSGI
142    stack or via a SOAP call to a remote service.  This is a basic test
143    interface.  See sessionmanager module for a full implementation linking to
144    a database via SQLAlchemy
145    '''
146   
147    def __init__(self, **prop):
148        """Extends BasicAuthNInterface initialising Session Manager Client
149       
150        @type **prop: dict
151        @param **prop: set properties via keywords
152        @raise AuthNInterfaceConfigError: error with configuration
153        """
154        user2Identifier = prop.pop('username2UserIdentifiers')
155        if user2Identifier:
156            self._username2Identifier = {}
157            for i in user2Identifier.split():
158                username, identifierStr = i.strip().split(':')
159                identifiers = tuple(identifierStr.split(','))
160                self._username2Identifier[username] = identifiers
161        else:
162            raise AuthNInterfaceConfigError('No "user2Identifier" config '
163                                            'option found')
164
165        self._client = WSGISessionManagerClient(**prop)
166       
167        # This is set at login
168        self.sessionId = None
169       
170    def logon(self, environ, userIdentifier, username, password):
171        """Interface login method
172       
173        @type environ: dict
174        @param environ: standard WSGI environ parameter
175       
176        @type username: basestring
177        @param username: user identifier
178       
179        @type password: basestring
180        @param password: corresponding password for username givens
181       
182        @raise AuthNInterfaceUsername2IdentifierMismatch: no OpenID
183        identifiers match the given username
184        @raise AuthNInterfaceInvalidCredentials: invalid username/password
185        """       
186        if userIdentifier is not None and \
187           userIdentifier not in self._username2Identifier.get(username):
188            raise AuthNInterfaceUsername2IdentifierMismatch()
189       
190        try:
191            self._client.environ = environ
192            connectResp = self._client.connect(username, passphrase=password)
193            self.sessionId = connectResp[-1]
194            log.debug("Connected to Session Manager with session ID: %s", 
195                      self.sessionId)
196
197        except AuthNServiceInvalidCredentials, e:
198            log.exception(e)
199            raise AuthNInterfaceInvalidCredentials()
200
201    def logout(self):
202        """logout from the Session Manager
203        """
204        try:
205            self._client.disconnect(sessID=self.sessionId)
206           
207        except Exception, e:
208            log.exception(e)
209            raise AuthNInterfaceInvalidCredentials()
Note: See TracBrowser for help on using the repository browser.