Changeset 5516


Ignore:
Timestamp:
24/07/09 14:57:03 (10 years ago)
Author:
pjkersha
Message:

Started work on SAML Attribute Interface SOAP Binding

  • added new ndg.security.common.soap module for ElementTree based SOAP handling. This will allow easy integration with ElementTree based SAML implementation.
Location:
TI12-security/trunk/python
Files:
4 added
3 edited

Legend:

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

    r5343 r5516  
    4141 
    4242class SOAPMiddleware(object): 
     43    """SOAP WSGI base class""" 
     44    soapFaultSetKey = 'ndg.security.server.wsgi.soap.soapFault' 
     45         
     46    @staticmethod 
     47    def isSOAPMessage(environ): 
     48        '''Generic method to filter out non-soap messages 
     49         
     50        TODO: is HTTP_SOAPACTION only set for WSDL doc-literal wrapped style 
     51        generated content? - If so this test should be moved''' 
     52        return environ.get('REQUEST_METHOD', '') == 'POST' and \ 
     53               environ.get('HTTP_SOAPACTION') is not None 
     54 
     55    @classmethod 
     56    def isSOAPFaultSet(cls, environ): 
     57        '''Check environment for SOAP fault flag set.  This variable is set 
     58        from exception2SOAPFault''' 
     59        return bool(environ.get(cls.soapFaultSetKey, False)) == True 
     60          
     61class ZSIMiddlewareError(SOAPMiddlewareError): 
     62    pass 
     63     
     64class ZSIMiddlewareReadError(SOAPMiddlewareReadError): 
     65    """ZSI Middleware read error""" 
     66 
     67class ZSIMiddlewareConfigError(SOAPMiddlewareConfigError): 
     68    """ZSI middleware configuration error""" 
     69      
     70class ZSIMiddleware(object): 
    4371    '''Middleware configurable to a given ZSI SOAP binding'''   
    4472     
     
    4876     
    4977    def __init__(self, app, app_conf, **kw): 
    50         log.debug("SOAPMiddleware.__init__ ...") 
     78        log.debug("ZSIMiddleware.__init__ ...") 
    5179        self.app = app 
    5280        self.app_conf = app_conf 
     
    98126 
    99127    def __call__(self, environ, start_response): 
    100         log.debug("SOAPMiddleware.__call__") 
     128        log.debug("ZSIMiddleware.__call__") 
    101129                         
    102130        # Derived class must implement SOAP Response via overloaded version of 
     
    122150        # Apply filter for calls 
    123151        if not self.isSOAPMessage(environ): 
    124             log.debug("SOAPMiddleware.__call__: skipping non-SOAP call") 
     152            log.debug("ZSIMiddleware.__call__: skipping non-SOAP call") 
    125153            return self.app(environ, start_response) 
    126154         
    127155        elif not self.pathMatch(environ): 
    128             log.debug("SOAPMiddleware.__call__: path doesn't match SOAP " 
     156            log.debug("ZSIMiddleware.__call__: path doesn't match SOAP " 
    129157                      "service endpoint") 
    130158            return self.app(environ, start_response) 
     
    134162            # consideration of security: e.g. an upstream signature  
    135163            # verification may have found an error in a signature 
    136             log.debug("SOAPMiddleware.__call__: SOAP fault set by previous " 
     164            log.debug("ZSIMiddleware.__call__: SOAP fault set by previous " 
    137165                      "SOAP middleware filter") 
    138166            return self.app(environ, start_response) 
     
    157185        sw = SoapWriter(outputclass=self.writerclass) 
    158186        soapFault.serialize(sw) 
    159         environ[SOAPMiddleware.soapFaultSetKey] = 'True' 
     187        environ[ZSIMiddleware.soapFaultSetKey] = 'True' 
    160188        return sw 
    161189     
    162190    pathMatch = lambda self,environ:environ['PATH_INFO']==self.app_conf['path'] 
    163          
    164     @staticmethod 
    165     def isSOAPMessage(environ): 
    166         '''Generic method to filter out non-soap messages 
    167          
    168         TODO: is HTTP_SOAPACTION only set for WSDL doc-literal wrapped style 
    169         generated content? - If so this test should be moved''' 
    170         return environ.get('REQUEST_METHOD', '') == 'POST' and \ 
    171                environ.get('HTTP_SOAPACTION') is not None 
    172  
    173     @classmethod 
    174     def isSOAPFaultSet(cls, environ): 
    175         '''Check environment for SOAP fault flag set.  This variable is set 
    176         from exception2SOAPFault''' 
    177         return bool(environ.get(cls.soapFaultSetKey, False)) == True 
    178191     
    179192    def parseRequest(self, environ): 
     
    191204        # Check for ParsedSoap object set in environment, if not present, 
    192205        # make one 
    193         ps = environ.get(SOAPMiddleware.parsedSOAPKey) 
     206        ps = environ.get(ZSIMiddleware.parsedSOAPKey) 
    194207        if ps is None: 
    195208            # TODO: allow for chunked data 
     
    197210            soapIn = environ['wsgi.input'].read(contentLength) 
    198211            if len(soapIn) < contentLength: 
    199                 raise SOAPMiddlewareReadError("Expecting %d content length; " 
     212                raise ZSIMiddlewareReadError("Expecting %d content length; " 
    200213                                              "received %d instead." %  
    201214                                              (contentLength, len(soapIn))) 
    202215             
    203             log.debug("SOAP Request for handler %r" % SOAPMiddleware) 
     216            log.debug("SOAP Request for handler %r" % ZSIMiddleware) 
    204217            log.debug("_" * 80) 
    205218            log.debug(soapIn) 
     
    207220             
    208221            ps = ParsedSoap(soapIn, readerclass=self.readerclass) 
    209             environ[SOAPMiddleware.parsedSOAPKey] = ps 
    210              
    211         return environ[SOAPMiddleware.parsedSOAPKey] 
     222            environ[ZSIMiddleware.parsedSOAPKey] = ps 
     223             
     224        return environ[ZSIMiddleware.parsedSOAPKey] 
    212225 
    213226 
     
    247260        method''' 
    248261         
    249         sw = environ.get(SOAPMiddleware.soapWriterKey) 
     262        sw = environ.get(ZSIMiddleware.soapWriterKey) 
    250263        if sw is None: 
    251264            raise KeyError("Expecting '%s' key in environ: missing call to " 
    252                            "SOAPMiddleware?" % SOAPMiddleware.soapWriterKey) 
     265                           "ZSIMiddleware?" % ZSIMiddleware.soapWriterKey) 
    253266        return sw 
    254267     
     
    256269    def setSOAPWriter(cls, environ, sw): 
    257270        '''Set SoapWriter object in environment'''    
    258         environ[SOAPMiddleware.soapWriterKey] = sw 
     271        environ[ZSIMiddleware.soapWriterKey] = sw 
    259272 
    260273    def addFilter2Environ(self, environ): 
     
    265278        if filterID is not None:            
    266279            if filterID in environ: 
    267                 raise SOAPMiddlewareConfigError("An filterID key '%s' is " 
     280                raise ZSIMiddlewareConfigError("An filterID key '%s' is " 
    268281                                                "already set in environ" %  
    269282                                                filterID) 
    270283            environ[filterID] = self 
    271              
    272          
    273 class SOAPBindingMiddleware(SOAPMiddleware):   
     284 
     285 
     286class SOAPBindingMiddleware(ZSIMiddleware):   
    274287    '''Apply a ZSI ServiceSOAPBinding type SOAP service''' 
    275288          
     
    338351                                          for i in self.referencedFilterKeys]) 
    339352                except KeyError: 
    340                     raise SOAPMiddlewareConfigError('No filter ID "%s" found ' 
     353                    raise ZSIMiddlewareConfigError('No filter ID "%s" found ' 
    341354                                                    'in environ' % i)     
    342355            ps = self.parseRequest(environ) 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/wssecurity.py

    r5063 r5516  
    1818from ZSI.writer import SoapWriter 
    1919from ndg.security.common.wssecurity.signaturehandler.foursuite import SignatureHandler 
    20 from ndg.security.server.wsgi.soap import SOAPMiddleware, SOAPMiddlewareError 
     20from ndg.security.server.wsgi.soap import ZSIMiddleware, ZSIMiddlewareError 
    2121 
    22 class WSSecurityFilterError(SOAPMiddlewareError): 
     22class WSSecurityFilterError(ZSIMiddlewareError): 
    2323    """Base exception class for WS-Security WSGI Filter""" 
    2424    _log = log 
     
    2727    """WS-Security Filter Config Error""" 
    2828  
    29 class WSSecurityFilter(SOAPMiddleware): 
     29class WSSecurityFilter(ZSIMiddleware): 
    3030    """Base class for WS-Security filters 
    3131     
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/unit/attributeauthority/saml/test_samlinterface.py

    r5513 r5516  
    3535    pass 
    3636 
     37class SamlSoapBindingMiddleware(object): 
     38    def __call__(self, environ, start_response): 
     39        pass 
    3740 
    38 class SamlAttributeAuthorityInterfaceTestCase(BaseTestCase): 
     41         
     42class SamlAttributeAuthorityInterfaceTestCase(unittest.TestCase): 
    3943    """TODO: test SAML Attribute Authority interface""" 
    4044    thisDir = os.path.dirname(os.path.abspath(__file__)) 
     45 
     46    def __init__(self, *args, **kwargs): 
     47        wsgiApp = SamlSoapBindingMiddleware() 
     48        self.app = paste.fixture.TestApp(wsgiApp) 
     49          
     50        unittest.TestCase.__init__(self, *args, **kwargs) 
     51         
     52 
     53    def test01Catch401WithNotLoggedIn(self): 
     54        response = self.app.get('/test_401WithNotLoggedIn') 
     55        self.assert_(response.status == 302) 
     56         
     57        try: 
     58            redirectResponse = response.follow() 
     59        except paste.fixture.AppError, e: 
     60            self.failIf('404 Not found' not in str(e),  
     61                        "Expecting 404 Not found") 
     62 
     63    def test02Skip200WithLoggedIn(self): 
     64        response = self.app.get('/test_200WithLoggedIn', 
     65                                extra_environ={'REMOTE_USER': 'testuser'}) 
     66 
     67    def test03Catch401WithLoggedIn(self): 
     68        response = self.app.get('/test_401WithLoggedIn',  
     69                                extra_environ={'REMOTE_USER': 'testuser'}, 
     70                                status=401) 
     71         
     72    def test04Catch200WithNotLoggedIn(self): 
     73        response = self.app.get('/test_200WithNotLoggedIn') 
     74        self.assert_(response.status == 302) 
     75         
     76        try: 
     77            redirectResponse = response.follow() 
     78        except paste.fixture.AppError, e: 
     79            self.failIf('404 Not found' not in str(e),  
     80                        "Expecting 404 Not found") 
    4181     
    42     def test01(self): 
    43         pass 
    4482     
    4583 
Note: See TracChangeset for help on using the changeset viewer.