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

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

More work on WSGI version of Attribute Authority unit tests. TODO: complete code to enable WS-Security config to be picked up from within the Paste ini file.

Line 
1"""WSGI Middleware for WS-Security
2
3Currently implements 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        wsseCfg = app_conf.copy()
47        wsseCfg.update(kw)
48       
49        self.signatureHandler = SignatureHandler(cfg=wsseCfgFilePath,
50                                            cfgFileSection=wsseCfgFileSection,
51                                            **wsseCfg)
52           
53   
54class ApplySignatureFilter(SignatureFilter):
55    '''Apply WS-Security digital signature to SOAP message'''
56    def __call__(self, environ, start_response):
57        '''Sign message'''
58        if not self.isSOAPMessage(environ) or \
59           not self.pathMatch(environ):
60            log.debug("ApplySignatureFilter.__call__: Non-SOAP "
61                      "request or path doesn't match SOAP endpoint specified "
62                      "- skipping signature verification")
63            return self.app(environ, start_response)
64       
65        log.debug('Signing outbound message ...')
66        if self.isSOAPFaultSet(environ):
67            # TODO: If the Signature handler is signing any sub-elements in the
68            # message body this is going to run into problems because the
69            # fault content is obviously going to be different.
70            # TODO: Should SOAP faults be signed at all?
71            log.warning("Attempting to sign a SOAP fault message...")
72           
73        try:
74            sw = self.getSOAPWriter(environ)
75        except Exception, e:
76            sw = self.exception2SOAPFault(environ, e)
77            self.setSOAPWriter(environ, sw)
78           
79        try:
80            self.signatureHandler.sign(sw)
81        except Exception, e:
82            sw = self.exception2SOAPFault(environ, e)
83            self.setSOAPWriter(environ, sw)
84       
85        return self.writeResponse(environ, start_response)
86   
87
88class SignatureVerificationFilter(SignatureFilter):
89    '''Verify WS-Security digital signature in SOAP message'''
90   
91    def __call__(self, environ, start_response):
92        '''Verify message signature'''
93        if not self.isSOAPMessage(environ) or \
94           not self.pathMatch(environ):
95            log.debug("SignatureVerificationFilter.__call__: Non-SOAP "
96                      "request or path doesn't match SOAP endpoint specified "
97                      "- skipping signature verification")
98            return self.app(environ, start_response)
99
100        log.debug("Verifying inbound message signature...")
101
102        # Add a reference to this filter in environ so that other middleware
103        # can reference it
104        self.addFilter2Environ(environ)
105       
106        try:
107            ps = self.parseRequest(environ)
108            self.signatureHandler.verify(ps)
109        except Exception, e:
110            sw = self.exception2SOAPFault(environ, e)
111            self.setSOAPWriter(environ, sw)
112           
113        return self.writeResponse(environ, start_response)
Note: See TracBrowser for help on using the repository browser.