Changeset 4528


Ignore:
Timestamp:
03/12/08 17:14:46 (11 years ago)
Author:
pjkersha
Message:

Added an Authentication interface for the OpenID Provider to enable authentication method to be customised. TODO:

  • add plugin for link Session Manager WSGI based Authentication
  • Provide capability for defining OpenID identifier from authentication interface.
Location:
TI12-security/trunk/python
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/sessionmanager.py

    r4520 r4528  
    11401140        given by propFilePath 
    11411141         
    1142         @param propertiesFile:   set properties via a configuration file 
    1143         @param **prop:         set properties via keywords - see __validKeys 
     1142        @type propertiesFile: basestring 
     1143        @param propertiesFile: set properties via a configuration file 
     1144        @type **prop: dict 
     1145        @param **prop: set properties via keywords - see __validKeys 
    11441146        class variable for a list of these 
    11451147        @raise AuthNServiceInitError: error with initialisation 
     
    11481150        specific exception types. 
    11491151        """ 
    1150         pass 
    11511152     
    11521153    def setProperties(self, **prop): 
     
    11561157                            self.setProperties.__doc__.replace('\n       ','')) 
    11571158         
    1158     def logon(self, username, passphrase, lifetime=None): 
    1159         """ 
    1160         Retrieve a proxy credential from a proxy server 
     1159    def logon(self, username, passphrase): 
     1160        """Interface login method 
    11611161         
    11621162        @type username: basestring 
     
    11641164         
    11651165        @type passphrase: basestring 
    1166         @param passphrase: pass-phrase for private key of credential held on 
    1167         server 
    1168          
    1169         @type lifetime: int 
    1170         @param lifetime: lifetime for generated certificate 
    1171          
     1166        @param passphrase: passphrase corresponding to username  
    11721167        @raise AuthNServiceInvalidCredentials: invalid username/passphrase 
    11731168        @raise AuthNServiceError: error  
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid_provider.py

    r4526 r4528  
    3333quoteattr = lambda s: '"%s"' % cgi.escape(s, 1) 
    3434 
     35 
     36class AuthNInterfaceError(Exception): 
     37    """Base class for AbstractAuthNInterface exceptions 
     38     
     39    A standard message is raised set by the msg class variable but the actual 
     40    exception details are logged to the error log.  The use of a standard  
     41    message enbales callers to use its content for user error messages. 
     42     
     43    @type msg: basestring 
     44    @cvar msg: standard message to be raised for this exception""" 
     45    msg = "An error occured with login" 
     46    def __init__(self, *arg, **kw): 
     47        Exception.__init__(self, AuthNInterfaceError.msg, *arg, **kw) 
     48        if len(arg) > 0: 
     49            msg = arg[0] 
     50        else: 
     51            msg = AuthNInterfaceError.msg 
     52             
     53        log.error(msg) 
     54         
     55class AuthNInterfaceInvalidCredentials(AuthNInterfaceError): 
     56    """User has provided incorrect username/password.  Raise from logon""" 
     57    msg = "Invalid username/password provided" 
     58     
     59class AuthNInterfaceRetrieveError(AuthNInterfaceError): 
     60    """Error with retrieval of information to authenticate user e.g. error with 
     61    database look-up.  Raise from logon""" 
     62    msg = \ 
     63    "An error occured retrieving information to check the login credentials" 
     64 
     65class AuthNInterfaceInitError(AuthNInterfaceError): 
     66    """Error with initialisation of AuthNInterface.  Raise from __init__""" 
     67    msg = "An error occured with the initialisation of the OpenID " + \ 
     68        "Provider's Authentication Service" 
     69     
     70class AuthNInterfaceConfigError(AuthNInterfaceError): 
     71    """Error with Authentication configuration.  Raise from __init__""" 
     72    msg = "An error occured with the OpenID Provider's Authentication " + \ 
     73        "Service configuration" 
     74     
     75class AbstractAuthNInterface(object): 
     76    '''OpenID Provider abstract base class for authentication configuration. 
     77    Derive from this class to define the authentication interface for users 
     78    logging into the OpenID Provider''' 
     79     
     80    def __init__(self, **prop): 
     81        """Make any initial settings 
     82         
     83        Settings are held in a dictionary which can be set from **prop, 
     84        a call to setProperties() or by passing settings in an XML file 
     85        given by propFilePath 
     86         
     87        @type **prop: dict 
     88        @param **prop: set properties via keywords  
     89        @raise AuthNInterfaceInitError: error with initialisation 
     90        @raise AuthNInterfaceConfigError: error with configuration 
     91        @raise AuthNInterfaceError: generic exception not described by the  
     92        other specific exception types. 
     93        """ 
     94 
     95     
     96    def logon(self, username, password): 
     97        """Interface login method 
     98         
     99        @type username: basestring 
     100        @param username: user identifier 
     101         
     102        @type password: basestring 
     103        @param password: corresponding password for username givens 
     104         
     105        @raise AuthNInterfaceInvalidCredentials: invalid username/password 
     106        @raise AuthNInterfaceError: error  
     107        @raise AuthNInterfaceRetrieveError: error with retrieval of information 
     108        to authenticate user e.g. error with database look-up. 
     109        @raise AuthNInterfaceError: generic exception not described by the  
     110        other specific exception types. 
     111        """ 
     112        raise NotImplementedError(self.logon.__doc__.replace('\n       ','')) 
     113     
     114     
     115class BasicAuthNInterface(AbstractAuthNInterface): 
     116    '''Basic Authentication interface class for OpenIDProviderMiddleware  
     117     
     118    it uses username/password details retrieved from config file / keyword 
     119    entry.  This class is for testing only.  NOT for production use''' 
     120     
     121    def __init__(self, **prop): 
     122        """Make any initial settings 
     123         
     124        Settings are held in a dictionary which can be set from **prop, 
     125        a call to setProperties() or by passing settings in an XML file 
     126        given by propFilePath 
     127         
     128        @type **prop: dict 
     129        @param **prop: set properties via keywords  
     130        @raise AuthNInterfaceConfigError: error with configuration 
     131        """ 
     132        # Test/Admin username/password set from ini/kw args 
     133        userCreds = prop.get('usercreds') 
     134        if userCreds: 
     135            self._userCreds = dict([i.strip().split(':') \ 
     136                                    for i in userCreds.split(',')]) 
     137        else: 
     138            raise AuthNInterfaceConfigError('No "userCreds" config option ' 
     139                                            "found") 
     140     
     141    def logon(self, username, password): 
     142        """Interface login method 
     143         
     144        @type username: basestring 
     145        @param username: user identifier 
     146         
     147        @type password: basestring 
     148        @param password: corresponding password for username givens 
     149         
     150        @raise AuthNInterfaceInvalidCredentials: invalid username/password 
     151        """ 
     152        if self._userCreds.get(username, '') != password: 
     153            raise AuthNInterfaceInvalidCredentials() 
     154         
     155         
    35156class OpenIDProviderMiddlewareError(Exception): 
    36157    """OpenID Provider WSGI Middleware Error""" 
     
    89210        sregResponseHandler=None, 
    90211        axResponseHandler=None, 
    91         usercreds=None) 
     212        authNInterface=AbstractAuthNInterface) 
    92213     
    93214    defPaths=dict([(k,v) for k,v in defOpt.items() if k.startswith('path_')]) 
     
    139260            opt['axResponseHandler'] = None 
    140261 
     262        # Authentication interface to OpenID Provider - interface to for  
     263        # example a user database or other means of authentication 
     264        authNInterfaceName = opt.get('authNInterface') 
     265        if authNInterfaceName: 
     266            authNInterfaceClass = eval_import(authNInterfaceName) 
     267            if not issubclass(authNInterfaceClass, AbstractAuthNInterface): 
     268                raise OpenIDProviderMiddlewareError("Authentication interface " 
     269                                                    "class %r is not a %r " 
     270                                                    "derived type" %  
     271                                                    (authNInterfaceClass,  
     272                                                     AbstractAuthNInterface)) 
     273        else: 
     274            authNInterfaceClass = AbstractAuthNInterface 
     275         
     276        # Extract Authentication interface specific properties 
     277        authNInterfaceProperties = dict([(k.replace('authN_', ''), v)  
     278                                         for k,v in opt.items()  
     279                                         if k.startswith('authN_')])  
     280          
     281        try: 
     282            self._authN = authNInterfaceClass(**authNInterfaceProperties) 
     283        except Exception, e: 
     284            log.error("Error instantiating authentication interface...") 
     285            raise 
     286 
    141287        # Paths relative to base URL - Nb. remove trailing '/' 
    142288        self.paths = dict([(k, opt[k].rstrip('/')) \ 
     
    164310        # If True and debug log level is set display content of response 
    165311        self._trace = opt['trace'] 
    166  
    167         # Test/Admin username/password set from ini/kw args 
    168         userCreds = opt.get('usercreds') 
    169         if userCreds: 
    170             self._userCreds = dict([i.strip().split(':') \ 
    171                                     for i in userCreds.split(',')]) 
    172         else: 
    173             self._userCreds = {} 
    174  
    175         # TODO: revise this once a link an authN mechanism has been included. 
    176         if not self._userCreds: 
    177             raise OpenIDProviderConfigError("No username/password config " 
    178                                             "set-up") 
    179312 
    180313        log.debug("opt=%r", opt)         
     
    243376            if k.startswith(prefix): 
    244377                subK = k.replace(prefix, '')                     
    245                 filtK = '_'.join(subK.split('.'))    
    246                 if filtK not in cls.defOpt: 
     378                filtK = '_'.join(subK.split('.'))   
     379                 
     380                # Allow for authN.* properties used by the Authentication 
     381                # Interface  
     382                if filtK not in cls.defOpt and not filtK.startswith('authN_'): 
    247383                    badOpt += [k]                 
    248384                else: 
     
    489625                    return self._redirect(start_response,self.query['fail_to']) 
    490626                 
    491                 # TODO: revise this once a link an authN mechanism has been  
    492                 # included. 
    493                 if self._userCreds: 
    494                     username = self.query['username'] 
    495                     password = self.query.get('password') 
    496                     if username not in self._userCreds or \ 
    497                        password != self._userCreds[username]: 
    498                         log.error("Invalid username/password entered") 
    499                         msg = "<p>Invalid username/password entered.  " + \ 
    500                             "Please try again or if the problems persists " + \ 
    501                             "contact your system administrator.</p>" 
    502                         response = self._render.login(environ, start_response, 
    503                                           msg=msg, 
    504                                           success_to=self.urls['url_decide']) 
    505                         return response 
     627                # Invoke custom authentication interface plugin 
     628                try: 
     629                    self._authN.logon(self.query['username'], 
     630                                      self.query.get('password', '')) 
     631                     
     632                except AuthNInterfaceError, e: 
     633                    # A known exception was raised 
     634                    log.error("Authenticating: %s" % e) 
     635                    msg = "<p>%s.  " + \ 
     636                        "Please try again or if the problems persists " + \ 
     637                        "contact your system administrator.</p>" % e 
     638                         
     639                    response = self._render.login(environ, start_response, 
     640                                      msg=msg, 
     641                                      success_to=self.urls['url_decide']) 
     642                    return response 
     643                         
     644                except Exception, e: 
     645                    log.error("Unexpected exception raised during " 
     646                              "authentication: %s" % e) 
     647                    msg = "<p>An internal error occured.  " + \ 
     648                        "Please try again or if the problems persists " + \ 
     649                        "contact your system administrator.</p>" % e 
     650 
     651                    response = self._render.login(environ, start_response, 
     652                                      msg=msg, 
     653                                      success_to=self.urls['url_decide']) 
     654                    return response 
    506655                        
    507656                self.session['username'] = self.query['username'] 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/combinedservices/services.ini

    r4527 r4528  
    325325openid.provider.sregResponseHandler=ndg.security.server.pylons.container.lib.openid_provider_util:esgSRegResponseHandler 
    326326openid.provider.axResponseHandler=ndg.security.server.pylons.container.lib.openid_provider_util:esgAXResponseHandler 
     327openid.provider.authNInterface=ndg.security.server.wsgi.openid_provider.BasicAuthNInterface 
     328openid.provider.authN.usercreds=pjk:test 
    327329 
    328330# Basic authentication for testing/admin - comma delimited list of  
    329331# <username>:<password> pairs 
    330 openid.provider.usercreds=pjk:test 
     332#openid.provider.usercreds=pjk:test 
    331333 
    332334#______________________________________________________________________________ 
Note: See TracChangeset for help on using the changeset viewer.