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

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

1.0.1 rc2

Added capability for Policy Information Point to query an Attribute Authority directly without a remote Session Manager intermediary to cache credentials. This is the use case for ESG based IdP connecting to NDG services.

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       
65    def logon(self, environ, userIdentifier, username, password):
66        """Interface login method
67       
68        @type environ: dict
69        @param environ: standard WSGI environ parameter
70       
71        @type username: basestring
72        @param username: user identifier
73       
74        @type password: basestring
75        @param password: corresponding password for username givens
76       
77        @raise AuthNInterfaceUsername2IdentifierMismatch: no OpenID
78        identifiers match the given username
79        @raise AuthNInterfaceInvalidCredentials: invalid username/password
80        """
81        if userIdentifier is not None:
82            # Check for a match between the OpenID user identifier and the
83            # username
84            try:
85                dbEngine = create_engine(self.connectionString)
86                connection = dbEngine.connect()
87            except Exception, e:
88                log.error('Connecting database for user logon query : %s' % e)
89                raise
90           
91            try:
92                try:
93                    queryInputs = dict(username=username,
94                                       userIdentifier=userIdentifier)
95                    query=Template(self.logonSQLQuery).substitute(queryInputs)
96                    result = connection.execute(query)
97                except Exception, e:
98                    log.error('Connecting database for user logon query : %s'%
99                              e)
100                    raise
101               
102                if not result.rowcount:
103                    raise AuthNInterfaceUsername2IdentifierMismatch()
104            finally:
105                connection.close()
106       
107        try:
108            self._client.environ = environ
109            self.sessionId = self._client.connect(username, 
110                                                  passphrase=password)[-1]
111           
112        except AuthNServiceInvalidCredentials, e:
113            log.exception(e)
114            raise AuthNInterfaceInvalidCredentials()
115       
116   
117    def username2UserIdentifiers(self, environ, username):
118        """Map the login username to an identifier which will become the
119        unique path suffix to the user's OpenID identifier.  The
120        OpenIDProviderMiddleware takes the ID URL template and adds it to this
121        identifier e.g.
122       
123            identifier = self._authN.username2UserIdentifiers(username)
124            identityURL = http://mysite/openid/${userIdentifier}
125       
126        @type environ: dict
127        @param environ: standard WSGI environ parameter
128       
129        @type username: basestring
130        @param username: user identifier
131       
132        @rtype: tuple
133        @return: identifiers to be used to make OpenID user identity URLs.
134       
135        @raise AuthNInterfaceRetrieveError: error with retrieval of information
136        to identifier e.g. error with database look-up.
137        """
138        try:
139            dbEngine = create_engine(self.connectionString)
140            connection = dbEngine.connect()
141        except Exception, e:
142            log.error('Connecting database for user identifiers query : %s'%e)
143            raise
144           
145        try:
146            try:
147                tmpl = Template(self.userIdentifiersSQLQuery)
148                sqlQuery = tmpl.substitute(dict(username=username))
149                result = connection.execute(sqlQuery)
150                if not result.rowcount:
151                    raise AuthNInterfaceRetrieveError()
152               
153                userIdentifiers = tuple([row.values()[0] for row in result])
154            except Exception, e:
155                log.error('Querying database for user identifiers for user '
156                          '"%s": %s' (username, e))
157                raise
158        finally:
159            connection.close()
160           
161        return userIdentifiers
162
163    def logout(self):
164        """logout from the Session Manager
165        """
166        try:
167            self._client.disconnect(sessID=self.sessionId)
168           
169        except Exception, e:
170            log.exception(e)
171            raise AuthNInterfaceInvalidCredentials()
Note: See TracBrowser for help on using the repository browser.