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

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

Added additional debug logging and improved error handling

Line 
1"""NDG Security OpenID Authentication Interface to a Session Manager.
2
3This enables an OpenID Provider's signin to link to a Session Manager running
4in the same WSGI stack or else running as a separate service via the Session
5Manager SOAP interface
6
7NERC DataGrid Project
8"""
9__author__ = "P J Kershaw"
10__date__ = "01/08/08"
11__copyright__ = "(C) 2009 Science and Technology Facilities Council"
12__license__ = "BSD - see LICENSE file in top-level directory"
13__contact__ = "Philip.Kershaw@stfc.ac.uk"
14__revision__ = "$Id$"
15import logging
16log = logging.getLogger(__name__)
17from string import Template
18from sqlalchemy import create_engine
19
20from ndg.security.server.wsgi.openid.provider import AbstractAuthNInterface, \
21    AuthNInterfaceConfigError, AuthNInterfaceInvalidCredentials, \
22    AuthNInterfaceUsername2IdentifierMismatch
23   
24from ndg.security.server.wsgi.utils.sessionmanagerclient import \
25    WSGISessionManagerClient, AuthNServiceInvalidCredentials
26   
27
28class SessionManagerOpenIDAuthNInterface(AbstractAuthNInterface):
29    '''Authentication interface class for OpenIDProviderMiddleware to enable
30    authentication to a Session Manager instance running in the same WSGI
31    stack or via a SOAP call to a remote service
32   
33    @type dbParamNames: tuple
34    @cvar dbParamNames: permitted config keywords.  Nb. SQL queries takes
35    String Template style '$' substitutions for username, password and OpenID
36    identifier'''
37   
38    dbParamNames = (
39        'connectionString',
40        'logonSQLQuery', 
41        'userIdentifiersSQLQuery')
42   
43    def __init__(self, **prop):
44        """Make any initial settings
45       
46        Settings are held in a dictionary which can be set from **prop,
47        a call to setProperties() or by passing settings in an XML file
48        given by propFilePath
49       
50        @type **prop: dict
51        @param **prop: set properties via keywords
52        @raise AuthNInterfaceConfigError: error with configuration
53        """
54        try:
55            for name in SessionManagerOpenIDAuthNInterface.dbParamNames:
56                setattr(self, name, prop.pop(name))
57               
58        except KeyError, e:
59            raise AuthNInterfaceConfigError("Missing property setting for "
60                                            "database connection: %s" % e)
61
62        self._client = WSGISessionManagerClient(**prop)
63       
64        # Set at login
65        self.sessionId = None
66       
67    def logon(self, environ, userIdentifier, username, password):
68        """Interface login method
69       
70        @type environ: dict
71        @param environ: standard WSGI environ parameter
72       
73        @type username: basestring
74        @param username: user identifier
75       
76        @type password: basestring
77        @param password: corresponding password for username givens
78       
79        @raise AuthNInterfaceUsername2IdentifierMismatch: no OpenID
80        identifiers match the given username
81        @raise AuthNInterfaceInvalidCredentials: invalid username/password
82        """
83        if userIdentifier is not None:
84            # Check for a match between the OpenID user identifier and the
85            # username
86            try:
87                dbEngine = create_engine(self.connectionString)
88                connection = dbEngine.connect()
89            except Exception, e:
90                log.error('Connecting database for user logon query : %s' % e)
91                raise
92           
93            try:
94                try:
95                    queryInputs = dict(username=username,
96                                       userIdentifier=userIdentifier)
97                    query=Template(self.logonSQLQuery).substitute(queryInputs)
98                    result = connection.execute(query)
99                except Exception, e:
100                    log.error('Connecting database for user logon query : %s'%
101                              e)
102                    raise
103               
104                if not result.rowcount:
105                    raise AuthNInterfaceUsername2IdentifierMismatch()
106            finally:
107                connection.close()
108       
109        try:
110            self._client.environ = environ
111            self.sessionId = self._client.connect(username, 
112                                                  passphrase=password)[-1]
113           
114        except AuthNServiceInvalidCredentials, e:
115            log.exception(e)
116            raise AuthNInterfaceInvalidCredentials()
117       
118   
119    def username2UserIdentifiers(self, environ, username):
120        """Map the login username to an identifier which will become the
121        unique path suffix to the user's OpenID identifier.  The
122        OpenIDProviderMiddleware takes the ID URL template and adds it to this
123        identifier e.g.
124       
125            identifier = self._authN.username2UserIdentifiers(username)
126            identityURL = http://mysite/openid/${userIdentifier}
127       
128        @type environ: dict
129        @param environ: standard WSGI environ parameter
130       
131        @type username: basestring
132        @param username: user identifier
133       
134        @rtype: tuple
135        @return: identifiers to be used to make OpenID user identity URLs.
136       
137        @raise AuthNInterfaceRetrieveError: error with retrieval of information
138        to identifier e.g. error with database look-up.
139        """
140        try:
141            dbEngine = create_engine(self.connectionString)
142            connection = dbEngine.connect()
143        except Exception, e:
144            log.error('Connecting database for user identifiers query : %s'%e)
145            raise
146           
147        try:
148            try:
149                tmpl = Template(self.userIdentifiersSQLQuery)
150                sqlQuery = tmpl.substitute(dict(username=username))
151                result = connection.execute(sqlQuery)
152                if not result.rowcount:
153                    raise AuthNInterfaceRetrieveError()
154               
155                userIdentifiers = tuple([row.values()[0] for row in result])
156            except Exception, e:
157                log.error('Querying database for user identifiers for user '
158                          '"%s": %s' (username, e))
159                raise
160        finally:
161            connection.close()
162           
163        return userIdentifiers
164
165    def logout(self):
166        """logout from the Session Manager
167        """
168        try:
169            self._client.disconnect(sessID=self.sessionId)
170           
171        except Exception, e:
172            log.exception(e)
173            raise AuthNInterfaceInvalidCredentials()
Note: See TracBrowser for help on using the repository browser.