Changeset 5766


Ignore:
Timestamp:
24/09/09 15:07:54 (10 years ago)
Author:
pjkersha
Message:

Working unit tests for Authentication redirect handler with SSL Client based authentication.

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

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/Tests/wsgiStack/test_multihandler.py

    r5579 r5766  
    4747    """Handler for HTTP 401 Unauthorized responses""" 
    4848 
    49     triggerStatus = "401 Unauthorized" 
     49    TRIGGER_HTTP_STATUS_CODE = "401 Unauthorized" 
    5050     
    5151    def __init__(self, global_conf, **app_conf): 
     
    6161    @classmethod 
    6262    def trigger(cls, environ, status, headers): 
    63         if status == cls.triggerStatus: 
     63        if status == cls.TRIGGER_HTTP_STATUS_CODE: 
    6464            log.info("Authentication Trigger caught status [%s]",  
    65                      cls.triggerStatus) 
     65                     cls.TRIGGER_HTTP_STATUS_CODE) 
    6666            return True 
    6767        else: 
     
    7272    """Handler for HTTP 403 Forbidden responses""" 
    7373     
    74     triggerStatus = "403 Forbidden" 
     74    TRIGGER_HTTP_STATUS_CODE = "403 Forbidden" 
    7575     
    7676    def __init__(self, global_conf, **app_conf): 
     
    8686    @classmethod 
    8787    def trigger(cls, environ, status, headers): 
    88         if status == cls.triggerStatus: 
     88        if status == cls.TRIGGER_HTTP_STATUS_CODE: 
    8989            log.info("Authorisation Trigger caught status [%s]",  
    90                      cls.triggerStatus) 
     90                     cls.TRIGGER_HTTP_STATUS_CODE) 
    9191            return True 
    9292        else: 
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/__init__.py

    r5675 r5766  
    2020     
    2121class NDGSecurityMiddlewareBase(object): 
    22     """Base class for NDG Security Middleware classes""" 
     22    """Base class for NDG Security Middleware classes 
     23    @cvar USERNAME_ENVIRON_KEYNAME: environ key name for user id as used by 
     24    AuthKit 
     25    @type USERNAME_ENVIRON_KEYNAME: string 
     26    """ 
     27    USERNAME_ENVIRON_KEYNAME = 'REMOTE_USER' 
     28    USERDATA_ENVIRON_KEYNAME = 'REMOTE_USER_DATA' 
     29     
    2330    propertyDefaults = { 
    2431        'mountPath': '/', 
    2532    } 
    2633 
     34    USERNAME_ENVIRON_KEYNAME = 'REMOTE_USER' 
     35     
    2736    def __init__(self, app, app_conf, prefix='', **local_conf): 
    2837        ''' 
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/authn.py

    r5757 r5766  
    1515import logging 
    1616log = logging.getLogger(__name__) 
     17   
     18import urllib 
     19from urlparse import urlsplit 
     20from paste.request import construct_url 
    1721from paste.request import parse_querystring 
    18 from authkit.permissions import UserIn 
    19  
    20 from ndg.security.server.wsgi.utils.sessionmanagerclient import \ 
    21     WSGISessionManagerClient 
    22  
     22from beaker.middleware import SessionMiddleware 
     23import authkit.authenticate 
     24 
     25from ndg.security.server.wsgi import NDGSecurityMiddlewareBase, \ 
     26    NDGSecurityMiddlewareConfigError         
     27 
     28 
     29class AuthenticationMiddlewareBase(NDGSecurityMiddlewareBase): 
     30    """Base class for Authentication redirect middleware and Session Handler 
     31    middleware 
     32     
     33    @type propertyDefaults: dict 
     34    @cvar propertyDefaults: valid configuration property keywords  
     35    """    
     36    propertyDefaults = { 
     37        'sessionKey': 'beaker.session.ndg.security' 
     38    } 
     39    USERNAME_SESSION_KEYNAME = 'username' 
     40     
     41    _isAuthenticated = lambda self: \ 
     42        AuthenticationMiddlewareBase.USERNAME_SESSION_KEYNAME in \ 
     43        self.environ.get(self.sessionKey, ()) 
     44         
     45    isAuthenticated = property(fget=_isAuthenticated, 
     46                               doc='boolean to indicate is user logged in') 
     47 
     48         
     49class AuthnRedirectMiddleware(AuthenticationMiddlewareBase): 
     50    """Base class for Authentication HTTP redirect initiator and redirect 
     51    response WSGI middleware 
     52 
     53    @type RETURN2URI_ARGNAME: basestring 
     54    @cvar RETURN2URI_ARGNAME: name of URI query argument used to pass the  
     55    return to URI between initiator and consumer classes""" 
     56    RETURN2URI_ARGNAME = 'ndg.security.r' 
     57#     
     58#    _isAuthenticated = lambda self: \ 
     59#            AuthnRedirectMiddleware.USERNAME_ENVIRON_KEYNAME in self.environ 
     60#             
     61#    isAuthenticated = property(fget=_isAuthenticated, 
     62#                               doc='boolean for, "is user logged in?"') 
     63 
     64class AuthnRedirectInitiatorMiddleware(AuthnRedirectMiddleware): 
     65    '''Middleware to initiate a redirect to another URI if a user is not  
     66    authenticated i.e. security cookie is not set 
     67     
     68    AuthKit.authenticate.middleware must be in place upstream of this  
     69    middleware.  AuthenticationMiddleware wrapper handles this. 
     70     
     71    @type propertyDefaults: dict 
     72    @cvar propertyDefaults: valid configuration property keywords     
     73    ''' 
     74    propertyDefaults = { 
     75        'redirectURI': None, 
     76    } 
     77    propertyDefaults.update(AuthnRedirectMiddleware.propertyDefaults) 
     78     
     79 
     80    TRIGGER_HTTP_STATUS_CODE = '401' 
     81    MIDDLEWARE_ID = 'AuthnRedirectInitiatorMiddleware' 
     82 
     83    def __init__(self, app, global_conf, **app_conf): 
     84        ''' 
     85        @type app: callable following WSGI interface 
     86        @param app: next middleware application in the chain       
     87        @type global_conf: dict         
     88        @param global_conf: PasteDeploy global configuration dictionary 
     89        @type prefix: basestring 
     90        @param prefix: prefix for configuration items 
     91        @type app_conf: dict         
     92        @param app_conf: PasteDeploy application specific configuration  
     93        dictionary 
     94        ''' 
     95        self._redirectURI = None 
     96        super(AuthnRedirectInitiatorMiddleware, self).__init__(app,  
     97                                                               global_conf,  
     98                                                               **app_conf) 
     99         
     100    @NDGSecurityMiddlewareBase.initCall 
     101    def __call__(self, environ, start_response): 
     102        '''Invoke redirect if user is not authenticated''' 
     103         
     104        log.debug("AuthnRedirectInitiatorMiddleware.__call__ ...") 
     105         
     106        if self.isAuthenticated: 
     107            # Call next app in stack 
     108            return self._app(environ, start_response)         
     109        else: 
     110            # User is not authenticated - Redirect to OpenID Relying Party URI 
     111            # for user OpenID entry 
     112            return self._setRedirectResponse() 
     113    
     114    def _setRedirectURI(self, uri): 
     115        if not isinstance(uri, basestring): 
     116            raise TypeError("Redirect URI must be set to string type")    
     117          
     118        self._redirectURI = uri 
     119         
     120    def _getRedirectURI(self): 
     121        return self._redirectURI 
     122     
     123    redirectURI = property(fget=_getRedirectURI, 
     124                       fset=_setRedirectURI, 
     125                       doc="URI to redirect to if user is not authenticated") 
     126 
     127    def _setRedirectResponse(self): 
     128        """Construct a redirect response adding in a return to address in a 
     129        URI query argument 
     130         
     131        @rtype: basestring 
     132        @return: redirect response 
     133        """        
     134        return2URI = construct_url(self.environ) 
     135        quotedReturn2URI = urllib.quote(return2URI, safe='') 
     136        return2URIQueryArg = urllib.urlencode( 
     137                    {AuthnRedirectInitiatorMiddleware.RETURN2URI_ARGNAME:  
     138                     quotedReturn2URI}) 
     139 
     140        redirectURI = self.redirectURI 
     141         
     142        if '?' in redirectURI: 
     143            if redirectURI.endswith('&'): 
     144                redirectURI += return2URIQueryArg 
     145            else: 
     146                redirectURI += '&' + return2URIQueryArg 
     147        else: 
     148            if redirectURI.endswith('?'): 
     149                redirectURI += return2URIQueryArg 
     150            else: 
     151                redirectURI += '?' + return2URIQueryArg 
     152           
     153        # Call NDGSecurityMiddlewareBase.redirect utility method       
     154        return self.redirect(redirectURI) 
     155         
     156    @classmethod 
     157    def checker(cls, environ, status, headers): 
     158        """Set the MultiHandler checker function for triggering this  
     159        middleware.  In this case, it's a HTTP 401 Unauthorized response  
     160        detected in the middleware chain 
     161        """ 
     162        if status.startswith(cls.TRIGGER_HTTP_STATUS_CODE): 
     163            log.debug("%s.checker caught status [%s]: invoking authentication" 
     164                      " handler", cls.__name__, cls.TRIGGER_HTTP_STATUS_CODE) 
     165            return True 
     166        else: 
     167            log.debug("%s.checker skipping status [%s]", cls.__name__, status) 
     168            return False 
     169 
     170 
     171class AuthnRedirectResponseMiddleware(AuthnRedirectMiddleware): 
     172    """Compliment to AuthnRedirectInitiatorMiddleware  
     173    functioning as the opposite end of the HTTP redirect interface.  It  
     174    performs the following tasks: 
     175    - Detect a redirect URI set in a URI query argument and copy it into 
     176    a user session object.  
     177    - Redirect back to the redirect URI once a user is authenticated 
     178     
     179    Also see, 
     180    ndg.security.server.wsgi.openid.relyingparty.OpenIDRelyingPartyMiddleware  
     181    which performs a similar function. 
     182    """ 
     183    @NDGSecurityMiddlewareBase.initCall 
     184    def __call__(self, environ, start_response): 
     185        session = environ[self.sessionKey] 
     186         
     187        # Check for return to address in URI query args set by  
     188        # AuthnRedirectInitiatorMiddleware in application code stack 
     189        if environ['REQUEST_METHOD'] == "GET": 
     190            params = dict(parse_querystring(environ)) 
     191        else: 
     192            params = {} 
     193         
     194        quotedReferrer = params.get(self.__class__.RETURN2URI_ARGNAME, '') 
     195        referrerURI = urllib.unquote(quotedReferrer) 
     196        if referrerURI: 
     197            session[self.__class__.RETURN2URI_ARGNAME] = referrerURI 
     198            session.save() 
     199             
     200        return2URI = session.get(self.__class__.RETURN2URI_ARGNAME)     
     201        if self.isAuthenticated and return2URI: 
     202            del session[self.__class__.RETURN2URI_ARGNAME] 
     203            session.save() 
     204            return self.redirect(return2URI) 
     205 
     206        return self._app(environ, start_response) 
     207 
     208 
     209class SessionHandlerMiddlewareConfigError(Exception): 
     210    """Configuration errors from SessionHandlerMiddleware""" 
     211     
     212     
     213class SessionHandlerMiddleware(AuthenticationMiddlewareBase): 
     214    '''Middleware to handle: 
     215    - establish user session details following redirect from OpenID Relying  
     216    Party sign-in or SSL Client authentication 
     217    - end session redirecting back to referrer URI following call to a logout 
     218    URI as implemented in AuthKit 
     219    ''' 
     220     
     221    SM_URI_SESSION_KEYNAME = 'sessionManagerURI' 
     222    ID_SESSION_KEYNAME = 'sessionId' 
     223    PEP_CTX_SESSION_KEYNAME = 'pepCtx' 
     224    CREDENTIAL_WALLET_SESSION_KEYNAME = 'credentialWallet' 
     225     
     226    SESSION_KEYNAMES = ( 
     227        AuthenticationMiddlewareBase.USERNAME_SESSION_KEYNAME,  
     228        SM_URI_SESSION_KEYNAME,  
     229        ID_SESSION_KEYNAME,  
     230        PEP_CTX_SESSION_KEYNAME,  
     231        CREDENTIAL_WALLET_SESSION_KEYNAME 
     232    ) 
     233     
     234    AX_KEYNAME = 'ax' 
     235    SM_URI_AX_KEYNAME = 'value.sessionManagerURI.1' 
     236    SESSION_ID_AX_KEYNAME = 'value.sessionId.1' 
     237     
     238    AUTHKIT_COOKIE_SIGNOUT_PARAMNAME = 'authkit.cookie.signoutpath' 
     239    SIGNOUT_PATH_PARAMNAME = 'signoutPath' 
     240    SESSION_KEY_PARAMNAME = 'sessionKey' 
     241    propertyDefaults = { 
     242        SIGNOUT_PATH_PARAMNAME: None, 
     243        SESSION_KEY_PARAMNAME: 'beaker.session.ndg.security' 
     244    } 
     245     
     246    AUTH_TKT_SET_USER_ENVIRON_KEYNAME = 'paste.auth_tkt.set_user' 
     247     
     248    PARAM_PREFIX = 'sessionHandler.' 
     249     
     250    def __init__(self, app, global_conf, prefix=PARAM_PREFIX, **app_conf): 
     251        ''' 
     252        @type app: callable following WSGI interface 
     253        @param app: next middleware application in the chain       
     254        @type global_conf: dict         
     255        @param global_conf: PasteDeploy global configuration dictionary 
     256        @type prefix: basestring 
     257        @param prefix: prefix for configuration items 
     258        @type app_conf: dict         
     259        @param app_conf: PasteDeploy application specific configuration  
     260        dictionary 
     261        ''' 
     262        signoutPathParamName = prefix + \ 
     263                                SessionHandlerMiddleware.SIGNOUT_PATH_PARAMNAME 
     264         
     265        if signoutPathParamName not in app_conf: 
     266            authKitSignOutPath = app_conf.get( 
     267                    SessionHandlerMiddleware.AUTHKIT_COOKIE_SIGNOUT_PARAMNAME) 
     268             
     269            if authKitSignOutPath: 
     270                app_conf[signoutPathParamName] = authKitSignOutPath 
     271                 
     272                log.info('Set signoutPath=%s from "%s" setting',  
     273                     authKitSignOutPath, 
     274                     SessionHandlerMiddleware.AUTHKIT_COOKIE_SIGNOUT_PARAMNAME) 
     275            else: 
     276                raise SessionHandlerMiddlewareConfigError( 
     277                                        '"signoutPath" parameter is not set') 
     278             
     279        super(SessionHandlerMiddleware, self).__init__(app, 
     280                                                       global_conf, 
     281                                                       prefix=prefix,  
     282                                                       **app_conf) 
     283         
     284    @NDGSecurityMiddlewareBase.initCall 
     285    def __call__(self, environ, start_response): 
     286        """Manage setting of session from AuthKit following OpenID Relying 
     287        Party sign in and manage logout 
     288         
     289        @type environ: dict 
     290        @param environ: WSGI environment variables dictionary 
     291        @type start_response: function 
     292        @param start_response: standard WSGI start response function 
     293        """ 
     294        log.debug("SessionHandlerMiddleware.__call__ ...") 
     295         
     296        session = environ.get(self.sessionKey) 
     297        if session is None: 
     298            raise SessionHandlerMiddlewareConfigError( 
     299                   'SessionHandlerMiddleware.__call__: No beaker session key ' 
     300                   '"%s" found in environ' % self.sessionKey) 
     301         
     302        if self.signoutPath and self.pathInfo == self.signoutPath: 
     303            log.debug("SessionHandlerMiddleware.__call__: caught sign out " 
     304                      "path [%s]", self.signoutPath) 
     305             
     306            referrer = environ.get('HTTP_REFERER') 
     307            if referrer is not None: 
     308                def _start_response(status, header, exc_info=None): 
     309                    """Alter the header to send a redirect to the logout 
     310                    referrer address""" 
     311                    filteredHeader = [(field, val) for field, val in header  
     312                                      if field.lower() != 'location']         
     313                    filteredHeader.extend([('Location', referrer)]) 
     314                    return start_response(self.getStatusMessage(302),  
     315                                          filteredHeader, 
     316                                          exc_info) 
     317                     
     318            else: 
     319                log.error('No referrer set for redirect following logout') 
     320                _start_response = start_response 
     321                 
     322            # Clear user details from beaker session 
     323            for keyName in self.__class__.SESSION_KEYNAMES: 
     324                session.pop(keyName, None) 
     325            session.save() 
     326        else: 
     327            log.debug("SessionHandlerMiddleware.__call__: checking for " 
     328                      "REMOTE_* environment variable settings set by OpenID " 
     329                      "Relying Party signin...") 
     330             
     331            if SessionHandlerMiddleware.USERNAME_SESSION_KEYNAME not in session\ 
     332               and SessionHandlerMiddleware.USERNAME_ENVIRON_KEYNAME in environ: 
     333                log.debug("SessionHandlerMiddleware: updating session " 
     334                          "username=%s", environ[ 
     335                            SessionHandlerMiddleware.USERNAME_ENVIRON_KEYNAME]) 
     336                 
     337                session[SessionHandlerMiddleware.USERNAME_SESSION_KEYNAME 
     338                        ] = environ[ 
     339                            SessionHandlerMiddleware.USERNAME_ENVIRON_KEYNAME] 
     340                session.save() 
     341                 
     342            remoteUserData = environ.get( 
     343                        SessionHandlerMiddleware.USERDATA_ENVIRON_KEYNAME, '')     
     344            if remoteUserData: 
     345                log.debug("SessionHandlerMiddleware: found REMOTE_USER_DATA=" 
     346                          "%s, set from OpenID Relying Party signin", 
     347                          environ[ 
     348                          SessionHandlerMiddleware.USERDATA_ENVIRON_KEYNAME]) 
     349                 
     350                # eval is safe here because AuthKit cookie is signed and  
     351                # AuthKit middleware checks for tampering 
     352                if SessionHandlerMiddleware.SM_URI_SESSION_KEYNAME not in \ 
     353                   session or \ 
     354                   SessionHandlerMiddleware.ID_SESSION_KEYNAME not in session: 
     355                     
     356                    axData = eval(remoteUserData) 
     357                    if isinstance(axData, dict) and \ 
     358                       SessionHandlerMiddleware.AX_KEYNAME in axData: 
     359                         
     360                        sessionManagerURI = axData[ 
     361                            SessionHandlerMiddleware.AX_KEYNAME].get( 
     362                                SessionHandlerMiddleware.SM_URI_AX_KEYNAME) 
     363                             
     364                        session[SessionHandlerMiddleware.SM_URI_SESSION_KEYNAME 
     365                                ] = sessionManagerURI 
     366     
     367                        sessionId = axData[ 
     368                            SessionHandlerMiddleware.AX_KEYNAME].get( 
     369                                SessionHandlerMiddleware.SESSION_ID_AX_KEYNAME) 
     370                        session[SessionHandlerMiddleware.ID_SESSION_KEYNAME 
     371                                ] = sessionId 
     372                        session.save() 
     373                         
     374                        log.debug("SessionHandlerMiddleware: updated session " 
     375                                  "with sessionManagerURI=%s and " 
     376                                  "sessionId=%s",  
     377                                  sessionManagerURI,  
     378                                  sessionId) 
     379                     
     380                # Reset cookie removing user data 
     381                environ[ 
     382                    SessionHandlerMiddleware.AUTH_TKT_SET_USER_ENVIRON_KEYNAME]( 
     383                        session[SessionHandlerMiddleware.ID_SESSION_KEYNAME]) 
     384 
     385            _start_response = start_response 
     386             
     387        return self._app(environ, _start_response) 
     388 
     389 
     390from authkit.authenticate.multi import MultiHandler 
     391 
     392class AuthenticationMiddlewareConfigError(NDGSecurityMiddlewareConfigError): 
     393    '''Authentication Middleware Configuration error''' 
     394 
     395 
     396class AuthenticationMiddleware(MultiHandler, NDGSecurityMiddlewareBase): 
     397    '''Top-level class encapsulates session and authentication handlers 
     398    in this module 
     399     
     400    Handler to intercept 401 Unauthorized HTTP responses and redirect to an 
     401    authentication URI.  This class also implements a redirect handler to 
     402    redirect back to the referrer if logout is invoked. 
     403    ''' 
     404 
     405    def __init__(self, app, global_conf, prefix='', **app_conf): 
     406        ''' 
     407        @type app: callable following WSGI interface 
     408        @param app: next middleware application in the chain       
     409        @type global_conf: dict         
     410        @param global_conf: PasteDeploy global configuration dictionary 
     411        @type prefix: basestring 
     412        @param prefix: prefix for configuration items 
     413        @type app_conf: dict         
     414        @param app_conf: PasteDeploy application specific configuration  
     415        dictionary 
     416        ''' 
     417         
     418        # Set logout URI parameter from AuthKit settings if not otherwise set 
     419        sessionHandlerPrefix = prefix + SessionHandlerMiddleware.PARAM_PREFIX         
     420        app = SessionHandlerMiddleware(app,  
     421                                       global_conf,  
     422                                       prefix=sessionHandlerPrefix, 
     423                                       **app_conf) 
     424         
     425        # Remove session handler middleware specific parameters 
     426        for k in app_conf.keys(): 
     427            if k.startswith(sessionHandlerPrefix): 
     428                del app_conf[k] 
     429         
     430        app = authkit.authenticate.middleware(app, app_conf)         
     431         
     432        MultiHandler.__init__(self, app) 
     433 
     434        # Redirection middleware is invoked based on a check method which  
     435        # catches HTTP 401 responses. 
     436        self.add_method(AuthnRedirectInitiatorMiddleware.MIDDLEWARE_ID,  
     437                        AuthnRedirectInitiatorMiddleware.filter_app_factory,  
     438                        global_conf, 
     439                        prefix=prefix, 
     440                        **app_conf) 
     441         
     442        self.add_checker(AuthnRedirectInitiatorMiddleware.MIDDLEWARE_ID,  
     443                         AuthnRedirectInitiatorMiddleware.checker) 
     444 
     445 
     446# AuthKit based HTTP basic authentication not currently needed but may need 
     447# resurrecting 
     448 
     449#from authkit.permissions import UserIn 
     450#from ndg.security.server.wsgi.utils.sessionmanagerclient import \ 
     451#    WSGISessionManagerClient 
    23452#class HTTPBasicAuthNMiddleware(NDGSecurityMiddlewareBase): 
    24453#    '''HTTP Basic Authentication Middleware 
     
    46475#        else: 
    47476#            return self._app(environ, start_response) 
    48              
    49 class HTTPBasicAuthentication(object): 
    50     '''Authkit based HTTP Basic Authentication.   __call__ defines a  
    51     validation function to fit with the pattern for the AuthKit interface 
    52     ''' 
    53      
    54     def __init__(self): 
    55         self._userIn = UserIn([]) 
    56          
    57     def __call__(self, environ, username, password): 
    58         """validation function""" 
    59         try: 
    60             client = WSGISessionManagerClient(environ=environ, 
    61                                 environKeyName=self.sessionManagerFilterID) 
    62             res = client.connect(username, passphrase=password) 
    63  
    64             if username not in self._userIn.users: 
    65                 self._userIn.users += [username] 
    66              
    67             # TODO: set session 
    68                  
    69         except Exception, e: 
    70             return False 
    71         else: 
    72             return True 
    73  
    74  
    75 import urllib 
    76 from urlparse import urlsplit 
    77 from paste.request import construct_url 
    78 from beaker.middleware import SessionMiddleware 
    79 import authkit.authenticate 
    80  
    81 from ndg.security.server.wsgi import NDGSecurityMiddlewareBase, \ 
    82     NDGSecurityMiddlewareConfigError         
    83  
    84          
    85 class AuthnRedirectMiddleware(NDGSecurityMiddlewareBase): 
    86     """Base class for Authentication HTTP redirect initiator and consumer WSGI  
    87     middleware 
    88  
    89     @type propertyDefaults: dict 
    90     @cvar propertyDefaults: valid configuration property keywords     
    91     @type RETURN2URI_ARGNAME: basestring 
    92     @cvar RETURN2URI_ARGNAME: name of URI query argument used to pass the  
    93     return to URI between initiator and consumer classes""" 
    94     propertyDefaults = { 
    95         'sessionKey': 'beaker.session.ndg.security' 
    96     } 
    97     propertyDefaults.update(NDGSecurityMiddlewareBase.propertyDefaults) 
    98     RETURN2URI_ARGNAME = 'ndg.security.r' 
    99     USERNAME_ENVIRON_KEYNAME = 'REMOTE_USER' 
    100      
    101     _isAuthenticated = lambda self: \ 
    102             AuthnRedirectMiddleware.USERNAME_ENVIRON_KEYNAME in self.environ 
    103              
    104     isAuthenticated = property(fget=_isAuthenticated, 
    105                                doc='boolean for, "is user logged in?"') 
    106  
    107 class AuthnRedirectInitiatorMiddleware(AuthnRedirectMiddleware): 
    108     '''Middleware to initiate a redirect to another URI if a user is not  
    109     authenticated i.e. security cookie is not set 
    110      
    111     AuthKit.authenticate.middleware must be in place upstream of this  
    112     middleware.  AuthenticationMiddleware wrapper handles this. 
    113      
    114     @type propertyDefaults: dict 
    115     @cvar propertyDefaults: valid configuration property keywords     
    116     ''' 
    117     propertyDefaults = { 
    118         'redirectURI': None, 
    119     } 
    120     propertyDefaults.update(AuthnRedirectMiddleware.propertyDefaults) 
    121      
    122  
    123     triggerStatus = '401' 
    124     id = 'AuthnRedirectInitiatorMiddleware' 
    125  
    126     def __init__(self, app, global_conf, **app_conf): 
    127         ''' 
    128         @type app: callable following WSGI interface 
    129         @param app: next middleware application in the chain       
    130         @type global_conf: dict         
    131         @param global_conf: PasteDeploy global configuration dictionary 
    132         @type prefix: basestring 
    133         @param prefix: prefix for configuration items 
    134         @type app_conf: dict         
    135         @param app_conf: PasteDeploy application specific configuration  
    136         dictionary 
    137         ''' 
    138         self._redirectURI = None 
    139         super(AuthnRedirectInitiatorMiddleware, self).__init__(app,  
    140                                                                global_conf,  
    141                                                                **app_conf) 
    142          
    143     @NDGSecurityMiddlewareBase.initCall 
    144     def __call__(self, environ, start_response): 
    145         '''Invoke redirect if user is not authenticated''' 
    146          
    147         log.debug("AuthnRedirectInitiatorMiddleware.__call__ ...") 
    148          
    149         if self.isAuthenticated: 
    150             # Call next app in stack 
    151             return self._app(environ, start_response)         
    152         else: 
    153             # User is not authenticated - Redirect to OpenID Relying Party URI 
    154             # for user OpenID entry 
    155             return self._setRedirectResponse() 
    156     
    157     def _setRedirectURI(self, uri): 
    158         if not isinstance(uri, basestring): 
    159             raise TypeError("Redirect URI must be set to string type")    
    160           
    161         self._redirectURI = uri 
    162          
    163     def _getRedirectURI(self): 
    164         return self._redirectURI 
    165      
    166     redirectURI = property(fget=_getRedirectURI, 
    167                        fset=_setRedirectURI, 
    168                        doc="URI to redirect to if user is not authenticated") 
    169  
    170     def _setRedirectResponse(self): 
    171         """Construct a redirect response adding in a return to address in a 
    172         URI query argument 
    173          
    174         @rtype: basestring 
    175         @return: redirect response 
    176         """ 
    177          
    178         return2URI = construct_url(self.environ) 
    179         quotedReturn2URI = urllib.quote(return2URI, safe='') 
    180         return2URIQueryArg = urllib.urlencode( 
    181                     {AuthnRedirectInitiatorMiddleware.RETURN2URI_ARGNAME:  
    182                      quotedReturn2URI}) 
    183  
    184         redirectURI = self.redirectURI 
    185          
    186         if '?' in redirectURI: 
    187             if redirectURI.endswith('&'): 
    188                 redirectURI += return2URIQueryArg 
    189             else: 
    190                 redirectURI += '&' + return2URIQueryArg 
    191         else: 
    192             if redirectURI.endswith('?'): 
    193                 redirectURI += return2URIQueryArg 
    194             else: 
    195                 redirectURI += '?' + return2URIQueryArg 
    196            
    197         # Call NDGSecurityMiddlewareBase.redirect utility method       
    198         return self.redirect(redirectURI) 
    199          
    200     @classmethod 
    201     def checker(cls, environ, status, headers): 
    202         """Set the MultiHandler checker function for triggering this  
    203         middleware.  In this case, it's a HTTP 401 Unauthorized response  
    204         detected in the middleware chain 
    205         """ 
    206         if status.startswith(cls.triggerStatus): 
    207             log.debug("%s.checker caught status [%s]: invoking authentication" 
    208                       " handler", cls.__name__, cls.triggerStatus) 
    209             return True 
    210         else: 
    211             log.debug("%s.checker skipping status [%s]", cls.__name__, status) 
    212             return False 
    213  
    214  
    215 class AuthnRedirectResponseMiddleware(AuthnRedirectMiddleware): 
    216     """Compliment to AuthnRedirectInitiatorMiddleware  
    217     functioning as the opposite end of the HTTP redirect interface.  It  
    218     performs the following tasks: 
    219     - Detect a redirect URI set in a URI query argument and copy it into 
    220     a user session object.  
    221     - Redirect back to the redirect URI once a user is authenticated 
    222      
    223     Also see, 
    224     ndg.security.server.wsgi.openid.relyingparty.OpenIDRelyingPartyMiddleware  
    225     which performs a similar function. 
    226     """ 
    227     @NDGSecurityMiddlewareBase.initCall 
    228     def __call__(self, environ, start_response): 
    229         session = environ[self.sessionKey] 
    230          
    231         # Check for return to address in URI query args set by  
    232         # AuthnRedirectInitiatorMiddleware in application code stack 
    233         if environ['REQUEST_METHOD'] == "GET": 
    234             params = dict(parse_querystring(environ)) 
    235         else: 
    236             params = {} 
    237          
    238         quotedReferrer = params.get(self.__class__.RETURN2URI_ARGNAME, '') 
    239         referrerURI = urllib.unquote(quotedReferrer) 
    240         if referrerURI: 
    241             session[self.__class__.RETURN2URI_ARGNAME] = referrerURI 
    242             session.save() 
    243              
    244         if self.isAuthenticated: 
    245             return2URI = session.get(self.__class__.RETURN2URI_ARGNAME) 
    246             if return2URI is None: 
    247                 log.warning("user is authenticated but no return2URI has been " 
    248                             "set") 
    249             else: 
    250                 return self.redirect(return2URI) 
    251  
    252         return self._app(environ, start_response) 
    253  
    254  
    255 class SessionHandlerMiddlewareConfigError(Exception): 
    256     """Configuration errors from SessionHandlerMiddleware""" 
    257      
    258      
    259 class SessionHandlerMiddleware(NDGSecurityMiddlewareBase): 
    260     '''Middleware to handle: 
    261     - set user session details following redirect from OpenID Relying Party 
    262     signin 
    263     - redirect back to referrer URI following call to a logout 
    264     URI as implemented in AuthKit''' 
    265     prefix = 'sessionHandler.' 
    266      
    267     sessionKeyNames = ( 
    268         'username',  
    269         'sessionManagerURI',  
    270         'sessionId',  
    271         'pepCtx',  
    272         'credentialWallet' 
    273     ) 
    274     AUTHKIT_COOKIE_SIGNOUT_PARAMNAME = 'authkit.cookie.signoutpath' 
    275     SIGNOUT_PATH_PARAMNAME = 'signoutPath' 
    276     SESSION_KEY_PARAMNAME = 'sessionKey' 
    277     propertyDefaults = { 
    278         SIGNOUT_PATH_PARAMNAME: None, 
    279         SESSION_KEY_PARAMNAME: 'beaker.session.ndg.security' 
    280     } 
    281     propertyDefaults.update(NDGSecurityMiddlewareBase.propertyDefaults) 
    282  
    283  
    284     def __init__(self, app, global_conf, prefix='sessionhandler.', **app_conf): 
    285         ''' 
    286         @type app: callable following WSGI interface 
    287         @param app: next middleware application in the chain       
    288         @type global_conf: dict         
    289         @param global_conf: PasteDeploy global configuration dictionary 
    290         @type prefix: basestring 
    291         @param prefix: prefix for configuration items 
    292         @type app_conf: dict         
    293         @param app_conf: PasteDeploy application specific configuration  
    294         dictionary 
    295         ''' 
    296         signoutPathParamName = prefix + \ 
    297                                 SessionHandlerMiddleware.SIGNOUT_PATH_PARAMNAME 
    298          
    299         if signoutPathParamName not in app_conf: 
    300             authKitSignOutPath = app_conf.get( 
    301                     SessionHandlerMiddleware.AUTHKIT_COOKIE_SIGNOUT_PARAMNAME) 
    302              
    303             if authKitSignOutPath: 
    304                 app_conf[signoutPathParamName] = authKitSignOutPath 
    305                  
    306                 log.info('Set signoutPath=%s from "%s" setting',  
    307                      authKitSignOutPath, 
    308                      SessionHandlerMiddleware.AUTHKIT_COOKIE_SIGNOUT_PARAMNAME) 
    309             else: 
    310                 raise SessionHandlerMiddlewareConfigError( 
    311                                         '"signoutPath" parameter is not set') 
    312              
    313         super(SessionHandlerMiddleware, self).__init__(app, 
    314                                                        global_conf, 
    315                                                        prefix=prefix,  
    316                                                        **app_conf) 
    317          
    318     @NDGSecurityMiddlewareBase.initCall 
    319     def __call__(self, environ, start_response): 
    320         """Manage setting of session from AuthKit following OpenID Relying 
    321         Party sign in and manage logout 
    322          
    323         @type environ: dict 
    324         @param environ: WSGI environment variables dictionary 
    325         @type start_response: function 
    326         @param start_response: standard WSGI start response function 
    327         """ 
    328         log.debug("SessionHandlerMiddleware.__call__ ...") 
    329          
    330         session = environ.get(self.sessionKey) 
    331         if session is None: 
    332             raise SessionHandlerMiddlewareConfigError( 
    333                    'SessionHandlerMiddleware.__call__: No beaker session key ' 
    334                    '"%s" found in environ' % self.sessionKey) 
    335          
    336         if self.signoutPath and self.pathInfo == self.signoutPath: 
    337             log.debug("SessionHandlerMiddleware.__call__: caught sign out " 
    338                       "path [%s]", self.signoutPath) 
    339              
    340             referrer = environ.get('HTTP_REFERER') 
    341             if referrer is not None: 
    342                 def _start_response(status, header, exc_info=None): 
    343                     """Alter the header to send a redirect to the logout 
    344                     referrer address""" 
    345                     filteredHeader = [(field, val) for field, val in header  
    346                                       if field.lower() != 'location']         
    347                     filteredHeader.extend([('Location', referrer)]) 
    348                     return start_response(self.getStatusMessage(302),  
    349                                           filteredHeader, 
    350                                           exc_info) 
    351                      
    352             else: 
    353                 log.error('No referrer set for redirect following logout') 
    354                 _start_response = start_response 
    355                  
    356             # Clear user details from beaker session 
    357             for keyName in self.__class__.sessionKeyNames: 
    358                 session.pop(keyName, None) 
    359             session.save() 
    360         else: 
    361             log.debug("SessionHandlerMiddleware.__call__: checking for " 
    362                       "REMOTE_* environment variable settings set by OpenID " 
    363                       "Relying Party signin...") 
    364              
    365             if 'username' not in session and 'REMOTE_USER' in environ: 
    366                 log.debug("SessionHandlerMiddleware: updating session with " 
    367                           "username=%s", environ['REMOTE_USER']) 
    368                  
    369                 session['username'] = environ['REMOTE_USER'] 
    370                 session.save() 
    371                  
    372             remoteUserData = environ.get('REMOTE_USER_DATA', '')     
    373             if remoteUserData: 
    374                 log.debug("SessionHandlerMiddleware: found REMOTE_USER_DATA=" 
    375                           "%s, set from OpenID Relying Party signin", 
    376                           environ['REMOTE_USER_DATA']) 
    377                  
    378                 # eval is safe here because AuthKit cookie is signed and  
    379                 # AuthKit middleware checks for tampering 
    380                 if 'sessionManagerURI' not in session or \ 
    381                    'sessionId' not in session: 
    382                      
    383                     axData = eval(remoteUserData) 
    384                     if isinstance(axData, dict) and 'ax' in axData: 
    385                         sessionManagerURI = \ 
    386                                 axData['ax'].get('value.sessionManagerURI.1') 
    387                         session['sessionManagerURI'] = sessionManagerURI 
    388      
    389                         sessionId = axData['ax'].get('value.sessionId.1') 
    390                         session['sessionId'] = sessionId 
    391                         session.save() 
    392                          
    393                         log.debug("SessionHandlerMiddleware: updated session " 
    394                                   "with sessionManagerURI=%s and " 
    395                                   "sessionId=%s",  
    396                                   sessionManagerURI,  
    397                                   sessionId) 
    398                      
    399                 # Reset cookie removing user data 
    400                 environ['paste.auth_tkt.set_user'](session['username']) 
    401  
    402             _start_response = start_response 
    403              
    404         return self._app(environ, _start_response) 
    405  
    406  
    407 from authkit.authenticate.multi import MultiHandler 
    408  
    409 class AuthenticationMiddlewareConfigError(NDGSecurityMiddlewareConfigError): 
    410     '''Authentication Middleware Configuration error''' 
    411  
    412  
    413 class AuthenticationMiddleware(MultiHandler, NDGSecurityMiddlewareBase): 
    414     '''Handler to intercept 401 Unauthorized HTTP responses and redirect to an 
    415     authentication URI.  This class also implements a redirect handler to 
    416     redirect back to the referrer if logout is invoked. 
    417     ''' 
    418  
    419     def __init__(self, app, global_conf, prefix='', **app_conf): 
    420         ''' 
    421         @type app: callable following WSGI interface 
    422         @param app: next middleware application in the chain       
    423         @type global_conf: dict         
    424         @param global_conf: PasteDeploy global configuration dictionary 
    425         @type prefix: basestring 
    426         @param prefix: prefix for configuration items 
    427         @type app_conf: dict         
    428         @param app_conf: PasteDeploy application specific configuration  
    429         dictionary 
    430         ''' 
    431          
    432         # Set logout URI parameter from AuthKit settings if not otherwise set 
    433         sessionHandlerPrefix = prefix + SessionHandlerMiddleware.prefix         
    434         app = SessionHandlerMiddleware(app,  
    435                                        global_conf,  
    436                                        prefix=sessionHandlerPrefix, 
    437                                        **app_conf) 
    438          
    439         # Remove session handler middleware specific parameters 
    440         for k in app_conf.keys(): 
    441             if k.startswith(sessionHandlerPrefix): 
    442                 del app_conf[k] 
    443          
    444         app = authkit.authenticate.middleware(app, app_conf)         
    445          
    446         MultiHandler.__init__(self, app) 
    447  
    448         self.add_method(AuthnRedirectInitiatorMiddleware.id,  
    449                         AuthnRedirectInitiatorMiddleware.filter_app_factory,  
    450                         global_conf, 
    451                         prefix=prefix, 
    452                         **app_conf) 
    453          
    454         self.add_checker(AuthnRedirectInitiatorMiddleware.id,  
    455                          AuthnRedirectInitiatorMiddleware.checker) 
    456  
     477#             
     478#class HTTPBasicAuthentication(object): 
     479#    '''Authkit based HTTP Basic Authentication.   __call__ defines a  
     480#    validation function to fit with the pattern for the AuthKit interface 
     481#    ''' 
     482#     
     483#    def __init__(self): 
     484#        self._userIn = UserIn([]) 
     485#         
     486#    def __call__(self, environ, username, password): 
     487#        """validation function""" 
     488#        try: 
     489#            client = WSGISessionManagerClient(environ=environ, 
     490#                                environKeyName=self.sessionManagerFilterID) 
     491#            res = client.connect(username, passphrase=password) 
     492# 
     493#            if username not in self._userIn.users: 
     494#                self._userIn.users += [username] 
     495#             
     496#            # TODO: set session 
     497#                 
     498#        except Exception, e: 
     499#            return False 
     500#        else: 
     501#            return True 
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/authz.py

    r5549 r5766  
    105105    403 Forbidden HTTP response without the application middleware executing 
    106106    """ 
    107     triggerStatus = '403' 
    108     id = 'PEPFilter' 
     107    TRIGGER_HTTP_STATUS_CODE = '403' 
     108    MIDDLEWARE_ID = 'PEPFilter' 
    109109     
    110110    propertyDefaults = { 
     
    236236             
    237237            # Trigger AuthZResultHandlerMiddleware by setting a response  
    238             # with HTTP status code equal to the triggerStatus class attribute 
     238            # with HTTP status code equal to the TRIGGER_HTTP_STATUS_CODE class attribute 
    239239            # value 
    240             return self._setErrorResponse(code=int(PEPFilter.triggerStatus)) 
     240            return self._setErrorResponse(code=int(PEPFilter.TRIGGER_HTTP_STATUS_CODE)) 
    241241 
    242242    def _getMatchingTargets(self, resourceURI): 
     
    276276            @param headers: HTTP response header content""" 
    277277             
    278             if status.startswith(PEPFilter.triggerStatus): 
     278            if status.startswith(PEPFilter.TRIGGER_HTTP_STATUS_CODE): 
    279279                log.info("PEPFilter: found [%s] status for URI path [%s]: " 
    280280                         "invoking access denied response", 
    281                          PEPFilter.triggerStatus, 
     281                         PEPFilter.TRIGGER_HTTP_STATUS_CODE, 
    282282                         environ['PATH_INFO']) 
    283283                return True 
     
    288288                          status, 
    289289                          environ['PATH_INFO'], 
    290                           PEPFilter.triggerStatus) 
     290                          PEPFilter.TRIGGER_HTTP_STATUS_CODE) 
    291291                return False 
    292292         
     
    522522                                        objectType=PEPResultHandlerMiddleware) 
    523523             
    524         app.add_method(PEPFilter.id, 
     524        app.add_method(PEPFilter.MIDDLEWARE_ID, 
    525525                       pepResultHandler.filter_app_factory, 
    526526                       global_conf, 
     
    528528                       **app_conf) 
    529529         
    530         app.add_checker(PEPFilter.id, pepInterceptFunc)                 
     530        app.add_checker(PEPFilter.MIDDLEWARE_ID, pepInterceptFunc)                 
    531531         
    532532        super(AuthorizationMiddleware, self).__init__(app, 
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/openid/relyingparty/__init__.py

    r5757 r5766  
    2727from ndg.security.common.utils.classfactory import instantiateClass 
    2828 
     29 
    2930class OpenIDRelyingPartyMiddlewareError(Exception): 
    3031    """OpenID Relying Party WSGI Middleware Error""" 
     32 
    3133 
    3234class OpenIDRelyingPartyConfigError(OpenIDRelyingPartyMiddlewareError): 
    3335    """OpenID Relying Party Configuration Error""" 
    3436   
     37 
    3538class OpenIDRelyingPartyMiddleware(NDGSecurityMiddlewareBase): 
    3639    '''OpenID Relying Party middleware which wraps the AuthKit implementation. 
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/wsgi/authn/ssl-test.ini

    r5757 r5766  
    1616pipeline = SSLClientAuthNFilter  
    1717                   BeakerSessionFilter 
     18                   AuthnRedirectInitiatorFilter  
    1819                   AuthnRedirectResponseFilter  
    19                    AuthnRedirectInitiatorFilter  
    2020                   TestApp 
    2121 
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/wsgi/authn/test.ini

    r5757 r5766  
    55# 
    66[DEFAULT] 
     7beakerSessionKeyName = beaker.session.ndg.security 
    78 
    89[server:main] 
     
    1213 
    1314[pipeline:main] 
    14 pipeline = AuthNRedirectFilter TestApp 
     15pipeline = BeakerSessionFilter AuthnRedirectInitiatorFilter TestApp 
    1516 
    1617[app:TestApp] 
    1718paste.app_factory = ndg.security.test.unit.wsgi.authn.test_authn:TestAuthnApp 
    1819 
    19 [filter:AuthNRedirectFilter] 
    20 paste.filter_app_factory = ndg.security.server.wsgi.authn:AuthnRedirectInitiatorMiddleware 
     20[filter:BeakerSessionFilter] 
     21paste.filter_app_factory = beaker.middleware:SessionMiddleware 
     22 
     23# Cookie name 
     24beaker.session.key = ndg.security.session 
     25 
     26# WSGI environ key name 
     27environ_key = %(beakerSessionKeyName)s 
     28beaker.session.secret = rBIvKXLa+REYB8pM/8pdPoorVpKQuaOW 
     29beaker.cache.data_dir = %(here)s/authn/beaker/cache 
     30beaker.session.data_dir = %(here)s/authn/beaker/sessions 
     31 
     32 
     33# Redirect HTTPS based endpoint for SSL client Based authentication 
     34[filter:AuthnRedirectInitiatorFilter] 
     35paste.filter_app_factory = ndg.security.server.wsgi.authn:AuthenticationMiddleware 
    2136prefix = authN. 
    22 authN.redirectURI = /redirect2here 
     37authN.redirectURI = /redirect2Here 
    2338#authN.redirectURI = http://localhost:5800/verify 
     39 
     40# AuthKit Set-up 
     41authkit.setup.method=cookie 
     42 
     43# This cookie name and secret MUST agree with the name used by the security web 
     44# services app 
     45authkit.cookie.name=ndg.security.auth 
     46authkit.cookie.secret=9wvZObs9anUEhSIAnJNoY2iJq59FfYZr 
     47authkit.cookie.signoutpath = /logout 
     48 
     49# Disable inclusion of client IP address from cookie signature due to  
     50# suspected problem with AuthKit setting it when a HTTP Proxy is in place 
     51authkit.cookie.includeip = False 
     52 
     53# environ key name for beaker session 
     54authkit.session.middleware = %(beakerSessionKeyName)s 
     55 
     56#[filter:AuthNRedirectFilter] 
     57#paste.filter_app_factory = ndg.security.server.wsgi.authn:AuthnRedirectInitiatorMiddleware 
     58#prefix = authN. 
     59#authN.redirectURI = /redirect2Here 
     60##authN.redirectURI = http://localhost:5800/verify 
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/wsgi/authn/test_authn.py

    r5757 r5766  
    3636    '''Test Application for the Authentication handler to protect''' 
    3737    response = "Test Authentication redirect application" 
    38         
     38     
     39    loggedIn = lambda self, environ: 'username' in environ.get( 
     40                                                self.beakerSessionKeyName, {}) 
     41     
    3942    def __init__(self, app_conf, **local_conf): 
    40         pass 
     43        self.beakerSessionKeyName = app_conf.get('beakerSessionKeyName') 
    4144     
    4245    def __call__(self, environ, start_response): 
     
    5457            environ['REMOTE_USER'] = 'testuser' 
    5558            status = "200 OK" 
     59         
     60        elif environ['PATH_INFO'] == '/test_sslClientAuthn': 
     61            if self.loggedIn(environ): 
     62                status = "200 OK" 
     63            else: 
     64                status = "401 Unauthorized" 
    5665        else: 
    5766            status = "404 Not found" 
     
    7483         
    7584    def test01Catch401WithNotLoggedIn(self): 
    76         response = self.app.get('/test_401WithNotLoggedIn') 
    77         self.assert_(response.status == 302) 
     85        response = self.app.get('/test_401WithNotLoggedIn', status=302) 
     86        redirectResponse = response.follow(status=404) 
    7887         
    79         try: 
    80             redirectResponse = response.follow() 
    81         except paste.fixture.AppError, e: 
    82             self.failIf('404 Not found' not in str(e),  
    83                         "Expecting 404 Not found") 
    84  
    8588    def test02Skip200WithLoggedIn(self): 
    8689        response = self.app.get('/test_200WithLoggedIn', 
    87                                 extra_environ={'REMOTE_USER': 'testuser'}) 
     90                                extra_environ={'REMOTE_USER': 'testuser'}, 
     91                                status=200) 
     92        print(response.body) 
    8893 
    8994    def test03Catch401WithLoggedIn(self): 
     
    9196                                extra_environ={'REMOTE_USER': 'testuser'}, 
    9297                                status=401) 
     98        print(response.body) 
    9399         
    94100    def test04Catch200WithNotLoggedIn(self): 
    95         response = self.app.get('/test_200WithNotLoggedIn') 
    96         self.assert_(response.status == 302) 
    97          
    98         try: 
    99             redirectResponse = response.follow() 
    100         except paste.fixture.AppError, e: 
    101             self.failIf('404 Not found' not in str(e),  
    102                         "Expecting 404 Not found") 
     101        response = self.app.get('/test_200WithNotLoggedIn', status=200) 
    103102 
    104103 
     
    114113        BaseTestCase.__init__(self, *arg, **kw) 
    115114         
    116     def test01Catch401WithNotLoggedIn(self): 
     115    def test01(self): 
    117116        thisDir = os.path.dirname(__file__) 
    118117        sslClientCertFilePath = os.path.join( 
     
    123122        extra_environ = {'HTTPS':'1', 'SSL_CLIENT_CERT': sslClientCert} 
    124123 
    125         response = self.app.get('/test_401WithNotLoggedIn', 
     124        print("request secured URI '/test_sslClientAuthn' ...") 
     125        response = self.app.get('/test_sslClientAuthn', 
    126126                                extra_environ=extra_environ, 
    127127                                status=302) 
    128128         
     129        print("Redirect to SSL Client Authentication endpoint %r ..." % 
     130              response.header_dict['location']) 
     131         
     132        # Redirect to SSL Client Authentication endpoint 
    129133        redirectResponse = response.follow(extra_environ=extra_environ, 
    130134                                           status=302) 
     135 
     136        print("Redirect back to secured URI with authenticated session %r ..."% 
     137              redirectResponse.header_dict['location']) 
    131138         
    132         finalResponse = redirectResponse.follow(extra_environ=extra_environ) 
    133          
     139        finalResponse = redirectResponse.follow(extra_environ=extra_environ, 
     140                                                status=200) 
    134141        print finalResponse 
    135142         
Note: See TracChangeset for help on using the changeset viewer.