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

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@5223
Revision 5223, 7.4 KB checked in by pjkersha, 11 years ago (diff)

Updates following initial release on ndg3beta - release is now 1.0.1rc1:

  • Added additional test authN interface class for OpenID Provider BasicSessionManagerOpenIDAuthNInterface. This links to a session manager for authN but uses a simple look-up in the ini file to resolve usernames to OpenID identifiers. This is useful for testing. The production version SessionManagerOpenIDAuthNInterface uses a table in a database to do the same function.
  • improved ndg.security.server.wsgi.authn.AuthenticationRedirectMiddleware? log messaging for checker intercept method.
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 
21   
22class BasicAuthNInterface(AbstractAuthNInterface):
23    '''Basic Authentication interface class for OpenIDProviderMiddleware
24   
25    it uses username/password details retrieved from config file / keyword
26    entry.  This class is for testing only.  NOT for production use'''
27   
28    propertyKeyNames = ('userCreds', 'username2UserIdentifiers')
29   
30    def __init__(self, **prop):
31        """Make any initial settings
32       
33        Settings are held in a dictionary which can be set from **prop,
34        a call to setProperties() or by passing settings in an XML file
35        given by propFilePath
36       
37        @type **prop: dict
38        @param **prop: set properties via keywords
39        @raise AuthNInterfaceConfigError: error with configuration
40        """
41        # Test/Admin username/password set from ini/kw args
42        userCreds = prop.get('userCreds')
43        if userCreds:
44            self._userCreds = dict([i.strip().split(':')
45                                    for i in userCreds.split(',')])
46        else:
47            raise AuthNInterfaceConfigError('No "userCreds" config option '
48                                            "found")
49           
50        user2Identifier = prop.get('username2UserIdentifiers')
51        if user2Identifier:
52            self._username2Identifier = {}
53            for i in user2Identifier.split():
54                username, identifierStr = i.strip().split(':')
55                identifiers = tuple(identifierStr.split(','))
56                self._username2Identifier[username] = identifiers
57        else:
58            raise AuthNInterfaceConfigError('No "user2Identifier" config '
59                                            'option found')
60       
61        userCredNames = self._userCreds.keys()
62        userCredNames.sort()
63        username2IdentifierNames = self._username2Identifier.keys()
64        username2IdentifierNames.sort()
65        if userCredNames != username2IdentifierNames:
66            raise AuthNInterfaceConfigError('Mismatch between usernames in '
67                                            '"userCreds" and '
68                                            '"username2UserIdentifiers" '
69                                            'options')   
70   
71    def logon(self, environ, userIdentifier, username, password):
72        """Interface login method
73       
74        @type environ: dict
75        @param environ: standard WSGI environ parameter
76
77        @type username: basestring
78        @param username: user identifier
79       
80        @type password: basestring
81        @param password: corresponding password for username givens
82       
83        @raise AuthNInterfaceInvalidCredentials: invalid username/password
84        """
85        if self._userCreds.get(username) != password:
86            raise AuthNInterfaceInvalidCredentials()
87       
88        if userIdentifier is not None and \
89           userIdentifier not in self._username2Identifier.get(username):
90            raise AuthNInterfaceUsername2IdentifierMismatch()
91
92    def logout(self):
93        pass
94       
95    def username2UserIdentifiers(self, environ, username):
96        """Map the login username to an identifier which will become the
97        unique path suffix to the user's OpenID identifier.  The
98        OpenIDProviderMiddleware takes self.urls['id_url'] and adds it to this
99        identifier:
100       
101            identifier = self._authN.username2UserIdentifiers(environ,username)
102            identityURL = self.urls['url_id'] + '/' + identifier
103       
104        @type environ: dict
105        @param environ: standard WSGI environ parameter
106
107        @type username: basestring
108        @param username: user identifier
109       
110        @rtype: tuple
111        @return: identifiers to be used to make OpenID user identity URLs.
112       
113        @raise AuthNInterfaceRetrieveError: error with retrieval of information
114        to identifier e.g. error with database look-up.
115        """
116        try:
117            return self._username2Identifier[username]
118        except KeyError:
119            raise AuthNInterfaceRetrieveError('No entries for "%s" user' % 
120                                              username)
121
122
123from ndg.security.server.wsgi.utils.sessionmanagerclient import \
124    WSGISessionManagerClient, AuthNServiceInvalidCredentials
125   
126class BasicSessionManagerOpenIDAuthNInterface(BasicAuthNInterface):
127    '''Authentication interface class for OpenIDProviderMiddleware to enable
128    authentication to a Session Manager instance running in the same WSGI
129    stack or via a SOAP call to a remote service.  This is a basic test
130    interface.  See sessionmanager module for a full implementation linking to
131    a database via SQLAlchemy
132    '''
133   
134    def __init__(self, **prop):
135        """Extends BasicAuthNInterface initialising Session Manager Client
136       
137        @type **prop: dict
138        @param **prop: set properties via keywords
139        @raise AuthNInterfaceConfigError: error with configuration
140        """
141        user2Identifier = prop.pop('username2UserIdentifiers')
142        if user2Identifier:
143            self._username2Identifier = {}
144            for i in user2Identifier.split():
145                username, identifierStr = i.strip().split(':')
146                identifiers = tuple(identifierStr.split(','))
147                self._username2Identifier[username] = identifiers
148        else:
149            raise AuthNInterfaceConfigError('No "user2Identifier" config '
150                                            'option found')
151
152        self._client = WSGISessionManagerClient(**prop)
153       
154       
155    def logon(self, environ, userIdentifier, username, password):
156        """Interface login method
157       
158        @type environ: dict
159        @param environ: standard WSGI environ parameter
160       
161        @type username: basestring
162        @param username: user identifier
163       
164        @type password: basestring
165        @param password: corresponding password for username givens
166       
167        @raise AuthNInterfaceUsername2IdentifierMismatch: no OpenID
168        identifiers match the given username
169        @raise AuthNInterfaceInvalidCredentials: invalid username/password
170        """       
171        if userIdentifier is not None and \
172           userIdentifier not in self._username2Identifier.get(username):
173            raise AuthNInterfaceUsername2IdentifierMismatch()
174       
175        try:
176            self._client.environ = environ
177            self.sessionId = self._client.connect(username, 
178                                                  passphrase=password)[-1]
179           
180        except AuthNServiceInvalidCredentials, e:
181            log.exception(e)
182            raise AuthNInterfaceInvalidCredentials()
183
184    def logout(self):
185        """logout from the Session Manager
186        """
187        try:
188            self._client.disconnect(sessID=self.sessionId)
189           
190        except Exception, e:
191            log.exception(e)
192            raise AuthNInterfaceInvalidCredentials()
Note: See TracBrowser for help on using the repository browser.