source: TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/wssecurity.py @ 4238

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/wssecurity.py@4238
Revision 4238, 4.1 KB checked in by pjkersha, 11 years ago (diff)

Working unit tests for WSGI based Attribute Authority. TODO:

  • test with Attribute Authority properties picked up from ini file instead of XML properties file (code supports both methods)
  • refactor unit test config to use standard WS-Security config section
Line 
1"""WSGI Middleware for WS-Security
2
3Implements Digital Signature handling based around ZSI
4
5NERC Data Grid Project"""
6__author__ = "P J Kershaw"
7__date__ = "11/06/08"
8__copyright__ = "(C) 2008 STFC & NERC"
9__license__ = \
10"""This software may be distributed under the terms of the Q Public
11License, version 1.0 or later."""
12__contact__ = "P.J.Kershaw@rl.ac.uk"
13__revision__ = '$Id$'
14
15import logging
16log = logging.getLogger(__name__)
17
18from ZSI.parse import ParsedSoap
19
20from ZSI.writer import SoapWriter
21from ndg.security.common.wssecurity.dom import SignatureHandler
22from ndg.security.server.wsgi.soap import SOAPMiddleware
23
24class WSSecurityFilterError(Exception):
25    """Base exception class for WS-Security WSGI Filter"""
26   
27class WSSecurityFilterConfigError(WSSecurityFilterError):
28    """WS-Security Filter Config Error"""
29 
30class WSSecurityFilter(SOAPMiddleware):
31    """Base class for WS-Security filters
32   
33    Overload pathMatch lambda so that it is more inclusive: the default is
34    for all paths to be processed by the handlers"""
35    pathMatch = lambda self, environ: \
36                        environ['PATH_INFO'].startswith(self.app_conf['path'])
37
38class SignatureFilter(WSSecurityFilter):
39    """Base class for WS-Security signature and signature verification filters
40    """
41    def __init__(self, app, app_conf, **kw):
42        super(SignatureFilter, self).__init__(app, app_conf, **kw)
43       
44        wsseCfgFilePath = self.app_conf.get('wsseCfgFilePath')       
45        wsseCfgFileSection = self.app_conf.get('wsseCfgFileSection')
46       
47        self.signatureHandler = SignatureHandler(cfg=wsseCfgFilePath,
48                                            cfgFileSection=wsseCfgFileSection)
49           
50   
51class ApplySignatureFilter(SignatureFilter):
52    '''Apply WS-Security digital signature to SOAP message'''
53    def __call__(self, environ, start_response):
54        '''Sign message'''
55        if not self.isSOAPMessage(environ) or \
56           not self.pathMatch(environ):
57            log.debug("ApplySignatureFilter.__call__: Non-SOAP "
58                      "request or path doesn't match SOAP endpoint specified "
59                      "- skipping signature verification")
60            return self.app(environ, start_response)
61       
62        log.debug('Signing outbound message ...')
63        if self.isSOAPFaultSet(environ):
64            # TODO: If the Signature handler is signing any sub-elements in the
65            # message body this is going to run into problems because the
66            # fault content is obviously going to be different.
67            # TODO: Should SOAP faults be signed at all?
68            log.warning("Attempting to sign a SOAP fault message...")
69           
70        try:
71            sw = self.getSOAPWriter(environ)
72        except Exception, e:
73            sw = self.exception2SOAPFault(environ, e)
74            self.setSOAPWriter(environ, sw)
75           
76        try:
77            self.signatureHandler.sign(sw)
78        except Exception, e:
79            sw = self.exception2SOAPFault(environ, e)
80            self.setSOAPWriter(environ, sw)
81       
82        return self.writeResponse(environ, start_response)
83   
84
85class SignatureVerificationFilter(SignatureFilter):
86    '''Verify WS-Security digital signature in SOAP message'''
87   
88    def __call__(self, environ, start_response):
89        '''Verify message signature'''
90        if not self.isSOAPMessage(environ) or \
91           not self.pathMatch(environ):
92            log.debug("SignatureVerificationFilter.__call__: Non-SOAP "
93                      "request or path doesn't match SOAP endpoint specified "
94                      "- skipping signature verification")
95            return self.app(environ, start_response)
96
97        log.debug("Verifying inbound message signature...")
98
99        # Add a reference to this filter in environ so that other middleware
100        # can reference it
101        self.addFilter2Environ(environ)
102       
103        try:
104            ps = self.parseRequest(environ)
105            self.signatureHandler.verify(ps)
106        except Exception, e:
107            sw = self.exception2SOAPFault(environ, e)
108            self.setSOAPWriter(environ, sw)
109           
110        return self.writeResponse(environ, start_response)
Note: See TracBrowser for help on using the repository browser.