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

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

Refactoring of SOAP and WS-Security middleware for better error handling and abstraction of functions

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    def __init__(self, app, app_conf):
33        self.app = app
34        self.app_conf = app_conf
35
36class WSSecuritySignatureFilter(WSSecurityFilter):
37    """Base class for WS-Security signature and signature verification filters
38    """
39    def __init__(self, app, app_conf):
40        super(WSSecuritySignatureFilter).__init__(app, app_conf)
41       
42        wsseCfgFilePath = self.app_conf.get('wsseCfgFilePath')
43        if not wsseCfgFilePath:
44            raise WSSecurityFilterConfigError("No configuration file set")
45       
46        self.signatureHandler = SignatureHandler(cfg=wsseCfgFilePath)
47           
48   
49class SignatureFilter(WSSecuritySignatureFilter):
50    '''Apply WS-Security digital signature to SOAP message'''
51    def __call__(self, environ, start_response):
52        if not self.isSOAPMessage(environ):
53            return self.app(environ, start_response)
54       
55        log.debug('Signing outbound message ...')
56        app = self.app(environ, start_response)
57
58        sw = self.getSOAPWriter(environ)
59        self.signatureHandler.sign(sw)
60        soapOut_ = str(sw)
61       
62        def start_response_wrapper(status, response_hdrs, exc_info=None):
63            '''Ensure correct content length'''
64           
65            log.debug("Altering content-length to allow for signature...")
66            contentKeys = ('content-length', )
67            response_hdrs_alt = [(name, val) for name, val in response_hdrs\
68                                 if name.lower() not in contentKeys]
69           
70            response_hdrs_alt += [('content-length', str(len(soapOut_)))]
71     
72            return start_response(status, response_hdrs_alt, exc_info)
73
74        def app(environ, start_response_wrapper):
75            return soapOut_
76       
77        return app
78   
79
80class SignatureVerificationFilter(WSSecuritySignatureFilter):
81    '''Verify WS-Security digital signature in SOAP message'''
82   
83    def __call__(self, environ, start_response):
84        if not self.isSOAPMessage(environ):
85            log.debug("Non-SOAP request: Skipping signature verification")
86            return self.app(environ, start_response)
87
88        log.debug("Verifying inbound message signature...")
89       
90        ps = self.parse(environ)
91        self.signatureHandler.verify(ps)
92       
93        # Pass on in environment as an efficiency measure for any following
94        # SOAP Middleware
95        return self.app(environ, start_response)
96
97
98def makeSignatureVerificationFilter(app, global_conf):
99    return SignatureVerificationFilter(app, global_conf) 
100
101def makeSignatureFilter(app, global_conf):
102    return SignatureFilter(app, global_conf)
Note: See TracBrowser for help on using the repository browser.