Changeset 5838


Ignore:
Timestamp:
13/10/09 16:30:41 (10 years ago)
Author:
pjkersha
Message:

Unit tested HTTPBasicAuthMiddleware. This will be used together MyProxyClientMiddleware? to make a myproxy-logon web service interface.

Location:
TI12-security/trunk/python
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/authn.py

    r5830 r5838  
    1515import logging 
    1616log = logging.getLogger(__name__) 
    17    
     17 
     18import base64 
     19import httplib 
    1820import urllib 
    1921from urlparse import urlsplit 
     
    2426 
    2527from ndg.security.server.wsgi import NDGSecurityMiddlewareBase, \ 
    26     NDGSecurityMiddlewareConfigError         
     28    NDGSecurityMiddlewareError, NDGSecurityMiddlewareConfigError         
     29 
     30class AuthnException(NDGSecurityMiddlewareError): 
     31    """Base exception for this module""" 
     32     
     33     
     34class HTTPBasicAuthMiddlewareError(AuthnException): 
     35    """Base exception type for HTTPBasicAuthMiddleware""" 
     36     
     37     
     38class HTTPBasicAuthMiddlewareConfigError(NDGSecurityMiddlewareConfigError): 
     39    """Configuration error with HTTP Basic Auth middleware""" 
     40 
     41 
     42class HTTPBasicAuthUnauthorized(HTTPBasicAuthMiddlewareError):   
     43    """Raise from custom authentication interface in order to set HTTP  
     44    401 Unuathorized response""" 
     45     
     46     
     47class HTTPBasicAuthMiddleware(NDGSecurityMiddlewareBase): 
     48    '''HTTP Basic Authentication Middleware 
     49     
     50    ''' 
     51     
     52    AUTHN_FUNC_ENV_KEYNAME = ('ndg.security.server.wsgi.authn.' 
     53                              'HTTPBasicAuthMiddleware.authenticate') 
     54    AUTHN_FUNC_ENV_KEYNAME_PARAMNAME = 'authnFunc'        
     55    PARAM_PREFIX = 'http.auth.basic' 
     56    HTTP_HDR_FIELDNAME = 'basic' 
     57    FIELD_SEP = ':' 
     58    AUTHZ_ENV_KEYNAME = 'HTTP_AUTHORIZATION' 
     59     
     60    def __init__(self, app, app_conf, prefix=PARAM_PREFIX, **local_conf): 
     61        self.__authnFuncEnvironKeyName = None 
     62         
     63        super(HTTPBasicAuthMiddleware, self).__init__(app, app_conf,  
     64                                                      **local_conf) 
     65        paramName = prefix + \ 
     66                    HTTPBasicAuthMiddleware.AUTHN_FUNC_ENV_KEYNAME_PARAMNAME 
     67                     
     68        self.authnFuncEnvironKeyName = local_conf.get(paramName, 
     69                                HTTPBasicAuthMiddleware.AUTHN_FUNC_ENV_KEYNAME) 
     70 
     71    def _getAuthnFuncEnvironKeyName(self): 
     72        return self.__authnFuncEnvironKeyName 
     73 
     74    def _setAuthnFuncEnvironKeyName(self, value): 
     75        if not isinstance(value, basestring): 
     76            raise TypeError('Expecting string type for ' 
     77                            '"authnFuncEnvironKeyName"; got %r type' %  
     78                            type(value)) 
     79        self.__authnFuncEnvironKeyName = value 
     80 
     81    authnFuncEnvironKeyName = property(fget=_getAuthnFuncEnvironKeyName,  
     82                                       fset=_setAuthnFuncEnvironKeyName,  
     83                                       doc="key name in environ for the " 
     84                                           "custom authentication function " 
     85                                           "used by this class") 
     86 
     87    def _parseCredentials(self): 
     88        """Extract username and password from HTTP_AUTHORIZATION environ key 
     89         
     90        @rtype: tuple 
     91        @return: username and password.  If the key is not set or the auth 
     92        method is not basic return a two element tuple with elements both set 
     93        to None 
     94        """ 
     95        basicAuthHdr = self.environ.get( 
     96                                    HTTPBasicAuthMiddleware.AUTHZ_ENV_KEYNAME) 
     97        if basicAuthHdr is None: 
     98            log.debug("No %r setting in environ: skipping HTTP Basic Auth", 
     99                      HTTPBasicAuthMiddleware.AUTHZ_ENV_KEYNAME) 
     100            return None, None 
     101                        
     102        method, encodedCreds = basicAuthHdr.split(None, 1) 
     103        if method.lower() != HTTPBasicAuthMiddleware.HTTP_HDR_FIELDNAME: 
     104            log.debug("Auth method is %r not %r: skipping request", 
     105                      method, HTTPBasicAuthMiddleware.HTTP_HDR_FIELDNAME) 
     106            return None, None 
     107             
     108        creds = base64.decodestring(encodedCreds) 
     109        username, password = creds.split(HTTPBasicAuthMiddleware.FIELD_SEP, 1) 
     110        return username, password 
     111 
     112    @NDGSecurityMiddlewareBase.initCall 
     113    def __call__(self, environ, start_response): 
     114        """Authenticate based HTTP header elements as specified by the HTTP 
     115        Basic Authentication spec.""" 
     116        log.debug("HTTPBasicAuthNMiddleware.__call__ ...") 
     117         
     118        authenticate = environ.get(self.authnFuncEnvironKeyName) 
     119        if authenticate is None: 
     120            # HTTP 500 default is right for this error 
     121            raise HTTPBasicAuthMiddlewareConfigError("No authentication " 
     122                                                     "function set in environ") 
     123             
     124        username, password = self._parseCredentials() 
     125        if username is None: 
     126            return self._setErrorResponse(code=httplib.UNAUTHORIZED) 
     127         
     128        try: 
     129            authenticate(environ, username, password) 
     130                 
     131        except HTTPBasicAuthUnauthorized, e: 
     132            log.error(e) 
     133            return self._setErrorResponse(code=httplib.UNAUTHORIZED) 
     134        else: 
     135            return self._app(environ, start_response) 
     136 
     137 
     138# AuthKit based HTTP basic authentication plugin not currently needed but may  
     139# need resurrecting 
     140 
     141#from authkit.permissions import UserIn 
     142#from ndg.security.server.wsgi.utils.sessionmanagerclient import \ 
     143#    WSGISessionManagerClient 
     144#             
     145#class HTTPBasicAuthentication(object): 
     146#    '''Authkit based HTTP Basic Authentication.   __call__ defines a  
     147#    validation function to fit with the pattern for the AuthKit interface 
     148#    ''' 
     149#     
     150#    def __init__(self): 
     151#        self._userIn = UserIn([]) 
     152#         
     153#    def __call__(self, environ, username, password): 
     154#        """validation function""" 
     155#        try: 
     156#            client = WSGISessionManagerClient(environ=environ, 
     157#                                environKeyName=self.sessionManagerFilterID) 
     158#            res = client.connect(username, passphrase=password) 
     159# 
     160#            if username not in self._userIn.users: 
     161#                self._userIn.users += [username] 
     162#             
     163#            # TODO: set session 
     164#                 
     165#        except Exception, e: 
     166#            return False 
     167#        else: 
     168#            return True 
    27169 
    28170 
     
    224366        
    225367 
    226 class SessionHandlerMiddlewareError(Exception): 
     368class SessionHandlerMiddlewareError(AuthnException): 
    227369    """Base exception for SessionHandlerMiddleware""" 
    228370             
     
    517659        self.add_checker(AuthnRedirectInitiatorMiddleware.MIDDLEWARE_ID,  
    518660                         AuthnRedirectInitiatorMiddleware.checker) 
    519  
    520  
    521 class AuthnInterfaceBase(object): 
    522     def logon(self, environ, username, password): 
    523         raise NotImplementedError() 
    524     
    525   
    526 class EnvironAuthnInterface(AuthnInterfaceBase): 
    527     """Implementation of HTTP Basic Auth authentication plugin which simply 
    528     passes the username to downstream middleware via environ 
    529     """ 
    530     def logon(self, environ, username, password): 
    531         # TODO: implement... 
    532         raise NotImplementedError() 
    533      
    534      
    535 class HTTPBasicAuthMiddleware(NDGSecurityMiddlewareBase): 
    536     '''HTTP Basic Authentication Middleware 
    537      
    538     TODO: implement authN interface and username/password retrieval from 
    539     HTTP header.''' 
    540      
    541     def __init__(self, app, app_conf, **local_conf): 
    542  
    543         self.__authnInterface = None 
    544         super(HTTPBasicAuthMiddleware).__init__(self,  
    545                                                 app,  
    546                                                 app_conf,  
    547                                                 **local_conf) 
    548          
    549     def __call__(self, environ, start_response): 
    550         """Authenticate based HTTP header elements as specified by the HTTP 
    551         Basic Authentication spec.""" 
    552         log.debug("HTTPBasicAuthNMiddleware.__call__ ...") 
    553          
    554         try: 
    555             self.authnInterface.logon(environ, username, password) 
    556                  
    557         except Exception, e: 
    558             return self._errorResponse(code=401) 
    559         else: 
    560             return self._app(environ, start_response) 
    561  
    562 # AuthKit based HTTP basic authentication not currently needed but may need 
    563 # resurrecting 
    564  
    565 #from authkit.permissions import UserIn 
    566 #from ndg.security.server.wsgi.utils.sessionmanagerclient import \ 
    567 #    WSGISessionManagerClient 
    568 #             
    569 #class HTTPBasicAuthentication(object): 
    570 #    '''Authkit based HTTP Basic Authentication.   __call__ defines a  
    571 #    validation function to fit with the pattern for the AuthKit interface 
    572 #    ''' 
    573 #     
    574 #    def __init__(self): 
    575 #        self._userIn = UserIn([]) 
    576 #         
    577 #    def __call__(self, environ, username, password): 
    578 #        """validation function""" 
    579 #        try: 
    580 #            client = WSGISessionManagerClient(environ=environ, 
    581 #                                environKeyName=self.sessionManagerFilterID) 
    582 #            res = client.connect(username, passphrase=password) 
    583 # 
    584 #            if username not in self._userIn.users: 
    585 #                self._userIn.users += [username] 
    586 #             
    587 #            # TODO: set session 
    588 #                 
    589 #        except Exception, e: 
    590 #            return False 
    591 #        else: 
    592 #            return True 
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/myproxy.py

    r5830 r5838  
    1515 
    1616from myproxy.client import MyProxyClient 
     17from ndg.security.server.wsgi.authn import HTTPBasicAuthMiddleware 
    1718 
    1819class MyProxyClientMiddleware(object): 
     
    3536 
    3637        rePathMatchListParamName = prefix + \ 
    37                     MyProxyClientMiddleware.RE_PATH_MATCH_LIST_OPTNAME 
     38                            MyProxyClientMiddleware.RE_PATH_MATCH_LIST_OPTNAME 
    3839        rePathMatchListVal = app_conf.get(rePathMatchListParamName, '') 
    3940         
     
    108109        return False    
    109110         
     111         
     112class MyProxyLogonMiddleware(NDGSecurityMiddlewareBase): 
     113    """HTTP Basic Auth interface to MyProxy logon""" 
     114    PARAM_PREFIX = 'myproxy.logon.' 
     115     
     116    def __init__(self, app, app_conf, prefix=PARAM_PREFIX, **local_conf): 
     117        app = HTTPBasicAuthMiddleware(app, app_conf, **local_conf) 
     118        app = MyProxyClientMiddleware(app, app_conf, **local_conf) 
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/soap/test_soap.py

    r5779 r5838  
    8888    def test03Urllib2Client(self): 
    8989         
    90         # Paster based service must be running in separate script 
     90        # Paster based service is threaded from this call 
    9191        self.addService(app=SOAPBindingMiddleware(),  
    9292                        port=SOAPTestCase.SOAP_SERVICE_PORTNUM) 
Note: See TracChangeset for help on using the changeset viewer.