Changeset 4545 for TI12-security


Ignore:
Timestamp:
05/12/08 16:07:27 (11 years ago)
Author:
pjkersha
Message:

OpenID Provider Authentication interface:

  • added AuthN extension to enable Session Manager based authentication for OpenID Provider.

OpenID Provider, Session Manager and Attribute Authority WSGI filters now integrated running in a single PAste instance.

Location:
TI12-security/trunk/python
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/Tests/openid-provider/op/op/config/middleware.py

    r4122 r4545  
    1313from op.config.environment import load_environment 
    1414 
    15 from ndg.security.server.wsgi.openid_provider import OpenIDProviderMiddleware 
     15from ndg.security.server.wsgi.openid.provider import OpenIDProviderMiddleware 
    1616from beaker.middleware import SessionMiddleware 
    1717import authkit.authenticate 
  • TI12-security/trunk/python/Tests/openid-provider/op/op/lib/rendering.py

    r4526 r4545  
    4949config['pylons.g'].helpIcon = config['pylons.g'].server+'/layout/icons/help.png' 
    5050 
    51 from ndg.security.server.wsgi.openid_provider import RenderingInterface 
     51from ndg.security.server.wsgi.openid.provider import RenderingInterface 
    5252 
    5353class OpenIDProviderKidRendering(RenderingInterface): 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/sessionmanager.py

    r4513 r4545  
    369369        @return user cert, user private key, issuing cert and sessID all as 
    370370        strings but sessID will be None if the createServerSess keyword is  
    371         False""" 
     371        False 
     372         
     373        @raise InvalidSessionManagerClientCtx: no client binding to service has 
     374        been set up 
     375        @raise SessionManagerClientError: error reading passphrase file""" 
    372376     
    373377        if not self.__srv: 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/authnservice/dbauthn.py

    r4500 r4545  
    5959            passwd = passphrase 
    6060 
    61         pgDb = create_engine(self.connectionString) 
    62         connection = pgDb.connect() 
     61        dbEngine = create_engine(self.connectionString) 
     62        connection = dbEngine.connect() 
    6363         
    6464        try: 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/pylons/container/config/middleware.py

    r4153 r4545  
    1414    load_environment 
    1515     
    16 from ndg.security.server.wsgi.openid_provider import OpenIDProviderMiddleware 
     16from ndg.security.server.wsgi.openid.provider import OpenIDProviderMiddleware 
    1717from beaker.middleware import SessionMiddleware 
    1818import authkit.authenticate 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/pylons/container/lib/openid_provider_util.py

    r4526 r4545  
    7171# Rendering classes for OpenID Provider must derive from generic render  
    7272# interface 
    73 from ndg.security.server.wsgi.openid_provider import RenderingInterface 
     73from ndg.security.server.wsgi.openid.provider import RenderingInterface 
    7474 
    7575class OpenIDProviderKidRendering(RenderingInterface): 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/sessionmanager.py

    r4528 r4545  
    707707        session ID respectively.  Session ID will be none if createUserSess  
    708708        keyword is set to False 
     709         
     710        @raise AuthNServiceError: error with response from Authentication 
     711        service.  An instance of this class or derived class instance may be 
     712        raised. 
    709713        """ 
    710714         
     
    728732        else: 
    729733            # Create a fresh session 
    730             try:             
     734            try: 
    731735                # Get a proxy certificate to represent users ID for the new 
    732736                # session 
     
    784788        is available.  In this case, the Session Manager server certificate 
    785789        is used to secure connections to Attribute Authorities and other  
    786         services where required""" 
     790        services where required 
     791         
     792        @raise SessionManagerError: session ID added already exists in session 
     793        list""" 
    787794         
    788795        log.debug("Calling SessionManager._createUserSession ...") 
     
    881888        @type sessID: string 
    882889        @param sessID: similiarly, a web browser session ID linking to an 
    883         an existing session.""" 
     890        an existing session. 
     891         
     892        @raise SessionNotFound: no matching session to the inputs 
     893        @raise UserSessionExpired: existing session has expired 
     894        @raise InvalidUserSession: user credential wallet is invalid 
     895        @raise UserSessionX509CertNotBeforeTimeError: """ 
    884896         
    885897        log.debug("Calling SessionManager._connect2UserSession ...") 
     
    940952                                    userDN)) 
    941953        else: 
    942             raise SessionManagerError('"username", "sessID" or "userX509Cert" ' 
    943                                       'keywords must be set') 
     954            raise KeyError('"username", "sessID" or "userX509Cert" keywords ' 
     955                           'must be set') 
    944956             
    945957        # Check that the Credentials held in the wallet are still valid             
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/__init__.py

    r4539 r4545  
     1"""WSGI Middleware components - OpenID package containing an OpenID Provider 
     2WSGI implementation 
     3 
     4NERC Data Grid Project""" 
     5__author__ = "P J Kershaw" 
     6__date__ = "05/12/08" 
     7__copyright__ = "(C) 2008 STFC & NERC" 
     8__license__ = \ 
     9"""This software may be distributed under the terms of the Q Public  
     10License, version 1.0 or later.""" 
     11__contact__ = "Philip.Kershaw@stfc.ac.uk" 
     12__revision__ = '$Id$' 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/provider/__init__.py

    r4543 r4545  
    105105        """ 
    106106     
    107     def logon(self, userIdentifier, username, password): 
     107    def logon(self, environ, userIdentifier, username, password): 
    108108        """Interface login method 
     109         
     110        @type environ: dict 
     111        @param environ: standard WSGI environ parameter 
    109112         
    110113        @type userIdentifier: basestring or None 
     
    134137        raise NotImplementedError(self.logon.__doc__.replace('\n       ','')) 
    135138     
    136     def username2UserIdentifiers(self, username): 
     139    def username2UserIdentifiers(self, environ, username): 
    137140        """Map the login username to an identifier which will become the 
    138141        unique path suffix to the user's OpenID identifier.  The  
     
    140143        identifier: 
    141144         
    142             identifier = self._authN.username2UserIdentifiers(username) 
     145            identifier = self._authN.username2UserIdentifiers(environ,username) 
    143146            identityURL = self.urls['url_id'] + '/' + identifier 
    144147         
     148        @type environ: dict 
     149        @param environ: standard WSGI environ parameter 
     150 
    145151        @type username: basestring 
    146152        @param username: user identifier 
     
    206212                                            '"username2UserIdentifiers" options')    
    207213     
    208     def logon(self, userIdentifier, username, password): 
     214    def logon(self, environ, userIdentifier, username, password): 
    209215        """Interface login method 
    210216         
     217        @type environ: dict 
     218        @param environ: standard WSGI environ parameter 
     219 
    211220        @type username: basestring 
    212221        @param username: user identifier 
     
    224233            raise AuthNInterfaceUsername2IdentifierMismatch() 
    225234     
    226     def username2UserIdentifiers(self, username): 
     235    def username2UserIdentifiers(self, environ, username): 
    227236        """Map the login username to an identifier which will become the 
    228237        unique path suffix to the user's OpenID identifier.  The  
     
    230239        identifier: 
    231240         
    232             identifier = self._authN.username2UserIdentifiers(username) 
     241            identifier = self._authN.username2UserIdentifiers(environ,username) 
    233242            identityURL = self.urls['url_id'] + '/' + identifier 
    234243         
     244        @type environ: dict 
     245        @param environ: standard WSGI environ parameter 
     246 
    235247        @type username: basestring 
    236248        @param username: user identifier 
     
    746758                              "found in session") 
    747759                    return self._render.errorPage(environ, start_response, 
    748                                                   "An internal error occured " 
    749                                                   "during login.  Please " 
    750                                                   "report the problem to your " 
    751                                                   "site administrator.") 
     760                        "An internal error occured possibly due to a request " 
     761                        "that's expired.  Please retry from the site where " 
     762                        "you entered your OpenID.  If the problem persists " 
     763                        "report it to your site administrator.") 
    752764                     
    753765                # Get user identifier to check against credentials provided 
     
    762774                # Invoke custom authentication interface plugin 
    763775                try: 
    764                     self._authN.logon(userIdentifier, 
     776                    self._authN.logon(environ, 
     777                                      userIdentifier, 
    765778                                      self.query['username'], 
    766779                                      self.query.get('password', '')) 
     
    879892            return True 
    880893         
    881         identifiers = self._authN.username2UserIdentifiers(username) 
     894        identifiers = self._authN.username2UserIdentifiers(self.environ, 
     895                                                           username) 
    882896        idURLBase = self.urls['url_id']+'/' 
    883897        identityURLs = [idURLBase+i for i in identifiers] 
     
    15341548         
    15351549        if oidRequest.idSelect(): # We are being asked to select an ID 
    1536             userIdentifier = self._authN.username2UserIdentifiers(username)[0] 
     1550            userIdentifier = self._authN.username2UserIdentifiers(environ, 
     1551                                                                  username)[0] 
    15371552            identity = idURLBase + userIdentifier 
    15381553             
     
    15671582''' % fdata 
    15681583             
    1569         elif userIdentifier in self._authN.username2UserIdentifiers(username): 
     1584        elif userIdentifier in self._authN.username2UserIdentifiers(environ, 
     1585                                                                    username): 
    15701586            msg = '''\ 
    15711587            <p>A new site has asked to confirm your identity.  If you 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/provider/authninterface/__init__.py

    r4542 r4545  
     1"""WSGI Middleware components - OpenID package Authentication Interface 
     2plugins sub-package 
     3 
     4NERC Data Grid Project""" 
     5__author__ = "P J Kershaw" 
     6__date__ = "05/12/08" 
     7__copyright__ = "(C) 2008 STFC & NERC" 
     8__license__ = \ 
     9"""This software may be distributed under the terms of the Q Public  
     10License, version 1.0 or later.""" 
     11__contact__ = "Philip.Kershaw@stfc.ac.uk" 
     12__revision__ = '$Id$' 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/provider/authninterface/sessionmanager.py

    r4542 r4545  
     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 
     9This software may be distributed under the terms of the Q Public License, 
     10version 1.0 or later. 
     11""" 
     12__author__ = "P J Kershaw" 
     13__date__ = "01/08/08" 
     14__copyright__ = "(C) 2008 STFC & NERC" 
     15__contact__ = "Philip.Kershaw@stfc.ac.uk" 
     16__revision__ = "$Id$" 
     17import logging 
     18log = logging.getLogger(__name__) 
     19from string import Template 
     20from sqlalchemy import create_engine 
     21 
     22from ndg.security.server.wsgi.openid.provider import AbstractAuthNInterface, \ 
     23    AuthNInterfaceConfigError, AuthNInterfaceInvalidCredentials, \ 
     24    AuthNInterfaceUsername2IdentifierMismatch 
     25     
     26from ndg.security.server.wsgi.utils.sessionmanagerclient import \ 
     27    WSGISessionManagerClient, AuthNServiceInvalidCredentials 
     28     
     29     
     30class SessionManagerOpenIDAuthNInterface(AbstractAuthNInterface): 
     31    '''Authentication interface class for OpenIDProviderMiddleware to enable 
     32    authentication to a Session Manager instance running in the same WSGI 
     33    stack or via a SOAP call to a remote service''' 
     34     
     35    dbParamNames = ( 
     36        'connectionString', 
     37        'logonSQLQuery',  
     38        'userIdentifiersSQLQuery') 
     39     
     40    def __init__(self, **prop): 
     41        """Make any initial settings 
     42         
     43        Settings are held in a dictionary which can be set from **prop, 
     44        a call to setProperties() or by passing settings in an XML file 
     45        given by propFilePath 
     46         
     47        @type **prop: dict 
     48        @param **prop: set properties via keywords  
     49        @raise AuthNInterfaceConfigError: error with configuration 
     50        """ 
     51        try: 
     52            for name in SessionManagerOpenIDAuthNInterface.dbParamNames: 
     53                setattr(self, name, prop.pop(name)) 
     54                 
     55        except KeyError, e: 
     56            raise AuthNInterfaceConfigError("Missing property setting for " 
     57                                            "database connection: %s" % e) 
     58 
     59        self._client = WSGISessionManagerClient(**prop) 
     60         
     61         
     62    def logon(self, environ, userIdentifier, username, password): 
     63        """Interface login method 
     64         
     65        @type environ: dict 
     66        @param environ: standard WSGI environ parameter 
     67         
     68        @type username: basestring 
     69        @param username: user identifier 
     70         
     71        @type password: basestring 
     72        @param password: corresponding password for username givens 
     73         
     74        @raise AuthNInterfaceUsername2IdentifierMismatch: no OpenID identifiers 
     75        match the given username 
     76        @raise AuthNInterfaceInvalidCredentials: invalid username/password 
     77        """ 
     78        if userIdentifier is not None: 
     79            # Check for a match between the OpenID user identifier and the  
     80            # username 
     81            try: 
     82                dbEngine = create_engine(self.connectionString) 
     83                connection = dbEngine.connect() 
     84            except Exception, e: 
     85                log.error('Connecting database for user logon query : %s' % e) 
     86                raise 
     87             
     88            try: 
     89                queryInputs = dict(username=username, 
     90                                   userIdentifier=userIdentifier) 
     91                query = Template(self.logonSQLQuery).substitute(queryInputs) 
     92                result = connection.execute(query) 
     93                if not result.rowcount: 
     94                    raise AuthNInterfaceUsername2IdentifierMismatch() 
     95            finally: 
     96                connection.close() 
     97         
     98        try: 
     99            self._client.environ = environ 
     100            self._client.connect(username, passphrase=password) 
     101             
     102        except AuthNServiceInvalidCredentials, e: 
     103            log.exception(e) 
     104            raise AuthNInterfaceInvalidCredentials() 
     105         
     106     
     107    def username2UserIdentifiers(self, environ, username): 
     108        """Map the login username to an identifier which will become the 
     109        unique path suffix to the user's OpenID identifier.  The  
     110        OpenIDProviderMiddleware takes self.urls['id_url'] and adds it to this 
     111        identifier: 
     112         
     113            identifier = self._authN.username2UserIdentifiers(username) 
     114            identityURL = self.urls['url_id'] + '/' + identifier 
     115         
     116        @type environ: dict 
     117        @param environ: standard WSGI environ parameter 
     118         
     119        @type username: basestring 
     120        @param username: user identifier 
     121         
     122        @rtype: tuple 
     123        @return: identifiers to be used to make OpenID user identity URLs.  
     124         
     125        @raise AuthNInterfaceRetrieveError: error with retrieval of information 
     126        to identifier e.g. error with database look-up. 
     127        """ 
     128        try: 
     129            dbEngine = create_engine(self.connectionString) 
     130            connection = dbEngine.connect() 
     131        except Exception, e: 
     132            log.error('Connecting database for user identifiers query : %s'%e) 
     133            raise 
     134             
     135        try: 
     136            try: 
     137                tmpl = Template(self.userIdentifiersSQLQuery) 
     138                sqlQuery = tmpl.substitute(dict(username=username)) 
     139                result = connection.execute(sqlQuery) 
     140                if not result.rowcount: 
     141                    raise AuthNInterfaceRetrieveError() 
     142                 
     143                userIdentifiers = tuple([row.values()[0] for row in result]) 
     144            except Exception, e: 
     145                log.error('Querying database for user identifiers for user ' 
     146                          '"%s": %s' (username, e)) 
     147                raise 
     148        finally: 
     149            connection.close() 
     150             
     151        return userIdentifiers 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/utils/__init__.py

    r4501 r4545  
    11"""WSGI Middleware utilities - Session Manager and Attribute Authority 
    2 client interface access via objects placed in environ 
     2client interface access via objects placed in environ or external SOAP calls 
    33 
    44NERC Data Grid Project""" 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/utils/attributeauthorityclient.py

    r4521 r4545  
    4848        if 'uri' in soapClientKw: 
    4949            self._soapClient = AttributeAuthorityClient(**soapClientKw) 
    50              
     50        else: 
     51            self._soapClient = None 
     52              
     53    def _setEnviron(self, environ): 
     54        if not isinstance(environ, dict): 
     55            raise TypeError("Expecting dict type for 'environ' property") 
     56        self._environ = environ 
     57         
     58    def _getEnviron(self, environ): 
     59        return self._environ 
     60     
     61    environ = property(fget=_getEnviron,  
     62                       fset=_setEnviron,  
     63                       doc="WSGI environ dictionary") 
    5164             
    5265    def getHostInfo(self): 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/utils/sessionmanagerclient.py

    r4521 r4545  
    2323    WSGIAttributeAuthorityClient 
    2424 
     25# Import exception types from Session Manager and Session Manager client to 
     26# give caller some capability to trap errors 
     27# Session Manager Authentication interface ... 
     28from ndg.security.server.sessionmanager import AuthNServiceError, \ 
     29    AuthNServiceInvalidCredentials, AuthNServiceRetrieveError, \ 
     30    AuthNServiceInitError, AuthNServiceConfigError 
     31 
     32from ndg.security.common.sessionmanager import InvalidSessionManagerClientCtx 
     33 
    2534class WSGISessionManagerClientError(Exception): 
    2635    """Base class exception for WSGI Session Manager client errors""" 
     
    6069        if 'uri' in soapClientKw: 
    6170            self._soapClient = SessionManagerClient(**soapClientKw) 
    62      
     71        else: 
     72            self._soapClient = None 
     73     
     74    def _setEnviron(self, environ): 
     75        if not isinstance(environ, dict): 
     76            raise TypeError("Expecting dict type for 'environ' property") 
     77        self._environ = environ 
     78         
     79    def _getEnviron(self, environ): 
     80        return self._environ 
     81     
     82    environ = property(fget=_getEnviron,  
     83                       fset=_setEnviron,  
     84                       doc="WSGI environ dictionary") 
    6385     
    6486    def connect(self, username, **kw): 
     
    7092     
    7193        if self.refInEnviron: 
     94            log.debug("Connecting to local Session Manager instance") 
    7295            if 'username' in kw: 
    7396                raise TypeError("connect() got an unexpected keyword argument " 
     
    77100            res = self.ref.connect(username=username, **kw) 
    78101        else: 
     102            log.debug("Connecting to remote Session Manager service") 
     103             
    79104            # Filter out keywords which apply to a Session Manager local  
    80105            # instance call 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/combinedservices/services.ini

    r4537 r4545  
    307307# OpenID Provider WSGI Settings 
    308308[filter:OpenIDProviderFilter] 
    309 paste.filter_app_factory=ndg.security.server.wsgi.openid_provider:OpenIDProviderMiddleware 
     309paste.filter_app_factory=ndg.security.server.wsgi.openid.provider:OpenIDProviderMiddleware 
    310310openid.provider.path.openidserver=/openid/endpoint 
    311311openid.provider.path.login=/openid/login 
     
    327327openid.provider.trace=False 
    328328#openid.provider.renderingClass=ndg.security.server.pylons.container.lib.openid_provider_util.OpenIDProviderKidRendering 
    329 openid.provider.renderingClass=ndg.security.server.wsgi.openid_provider.DemoRenderingInterface 
     329openid.provider.renderingClass=ndg.security.server.wsgi.openid.provider.DemoRenderingInterface 
    330330openid.provider.sregResponseHandler=ndg.security.server.pylons.container.lib.openid_provider_util:esgSRegResponseHandler 
    331331openid.provider.axResponseHandler=ndg.security.server.pylons.container.lib.openid_provider_util:esgAXResponseHandler 
    332 openid.provider.authNInterface=ndg.security.server.wsgi.openid_provider.BasicAuthNInterface 
    333 openid.provider.authN.userCreds=pjk:test 
    334 openid.provider.authN.username2UserIdentifiers=pjk:PhilipKershaw,P.J.Kershaw 
     332 
     333# Basic Authentication interface to demonstrate capabilities 
     334#openid.provider.authNInterface=ndg.security.server.wsgi.openid.provider.BasicAuthNInterface 
     335#openid.provider.authN.userCreds=pjk:test 
     336#openid.provider.authN.username2UserIdentifiers=pjk:PhilipKershaw,P.J.Kershaw 
     337 
     338# Link Authentication to a Session Manager instance running in the same WSGI 
     339# stack or on a remote service 
     340openid.provider.authNInterface=ndg.security.server.wsgi.openid.provider.authninterface.sessionmanager.SessionManagerOpenIDAuthNInterface 
     341 
     342# Omit or leave as blank if the Session Manager is accessible locally in the 
     343# same WSGI stack. 
     344openid.provider.authN.sessionManagerURI= 
     345 
     346# environ dictionary key to Session Manager WSGI instance held locally.  The 
     347# setting below is the default and can be omitted if it matches the filterID 
     348# set for the Session Manager 
     349#openid.provider.authN.environKey=ndg.security.server.wsgi.sessionManagerFilter 
     350 
     351# Database connection to enable check between username and OpenID identifier 
     352openid.provider.authN.connectionString: postgres://postgres:testpassword@localhost/testUserDb 
     353openid.provider.authN.logonSQLQuery: select username from openid where username = '$username' and ident = '$userIdentifier' 
     354openid.provider.authN.userIdentifiersSQLQuery: select distinct ident from openid where username = '$username' 
    335355 
    336356# Basic authentication for testing/admin - comma delimited list of  
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/combinedservices/test_combinedservices.py

    r4521 r4545  
    1515__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1616__revision__ = '$Id: test_sessionmanagerclient.py 4437 2008-11-18 12:34:25Z pjkersha $' 
     17import logging 
     18logging.basicConfig(level=logging.DEBUG) 
    1719 
    1820import unittest 
Note: See TracChangeset for help on using the changeset viewer.