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

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@5080
Revision 5080, 6.0 KB checked in by pjkersha, 12 years ago (diff)

ndg.security.test.integration.openid: working combined OpenID Provider and Relying Party in same WSGI stack

  • Removed call to paste.request.parse_formvars in ndg.security.server.wsgi.openid.relyingparty.OpenIDRelyingPartyMiddleware.__call__: for Paste 1.7.1 this seems to gobbled up environwsgi.input? such that a 2nd call to it yields nothing!
  • TODO: add login to OpenID Relying Party template so that for a given site, home users can skip OpenID URI entry and login directly.
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 Data Grid Project
8
9"""
10__author__ = "P J Kershaw"
11__date__ = "01/08/08"
12__copyright__ = "(C) 2009 Science and Technology Facilities Council"
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 identifiers
78        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._client.connect(username, passphrase=password)
110           
111        except AuthNServiceInvalidCredentials, e:
112            log.exception(e)
113            raise AuthNInterfaceInvalidCredentials()
114       
115   
116    def username2UserIdentifiers(self, environ, username):
117        """Map the login username to an identifier which will become the
118        unique path suffix to the user's OpenID identifier.  The
119        OpenIDProviderMiddleware takes the ID URL template and adds it to this
120        identifier e.g.
121       
122            identifier = self._authN.username2UserIdentifiers(username)
123            identityURL = http://mysite/openid/${userIdentifier}
124       
125        @type environ: dict
126        @param environ: standard WSGI environ parameter
127       
128        @type username: basestring
129        @param username: user identifier
130       
131        @rtype: tuple
132        @return: identifiers to be used to make OpenID user identity URLs.
133       
134        @raise AuthNInterfaceRetrieveError: error with retrieval of information
135        to identifier e.g. error with database look-up.
136        """
137        try:
138            dbEngine = create_engine(self.connectionString)
139            connection = dbEngine.connect()
140        except Exception, e:
141            log.error('Connecting database for user identifiers query : %s'%e)
142            raise
143           
144        try:
145            try:
146                tmpl = Template(self.userIdentifiersSQLQuery)
147                sqlQuery = tmpl.substitute(dict(username=username))
148                result = connection.execute(sqlQuery)
149                if not result.rowcount:
150                    raise AuthNInterfaceRetrieveError()
151               
152                userIdentifiers = tuple([row.values()[0] for row in result])
153            except Exception, e:
154                log.error('Querying database for user identifiers for user '
155                          '"%s": %s' (username, e))
156                raise
157        finally:
158            connection.close()
159           
160        return userIdentifiers
Note: See TracBrowser for help on using the repository browser.