source: TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/soap.py @ 4152

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

Changed ndgPage.kid in pylons container to allow for Pylons 0.9.7 - some helpers have moved to a sub-package 'rails'

ndg.security.server.wsgi.soap,
ndg.security.server.wsgi.wssecurity: more work on SOAP middleware - add filtering for GET reqests

Line 
1"""NDG Security SOAP Service Middleware
2
3NERC Data Grid Project
4
5This software may be distributed under the terms of the Q Public License,
6version 1.0 or later.
7"""
8__author__ = "P J Kershaw"
9__date__ = "27/05/08"
10__copyright__ = "(C) 2008 STFC & NERC"
11__contact__ = "P.J.Kershaw@rl.ac.uk"
12__revision__ = "$Id$"
13import logging
14log = logging.getLogger(__name__)
15
16import paste.request
17from ZSI import EvaluateException, ParseException
18from ZSI.parse import ParsedSoap
19from ZSI.writer import SoapWriter
20from ZSI import fault
21
22from ZSI.ServiceContainer import ServiceSOAPBinding
23       
24class SOAPMiddleware(object):
25    '''Middleware configurable to a given ZSI SOAP binding''' 
26   
27    def __init__(self, app, app_conf, **kw):
28        log.debug("SOAPMiddleware.__init__ ...")
29        self.app = app
30        self.app_conf = app_conf
31        self.app_conf.update(kw)
32           
33        if 'path' not in self.app_conf:
34            self.app_conf['path'] = '/'
35       
36        if 'ServiceSOAPBindingClass' in self.app_conf:
37            modName, dot, className = \
38                self.app_conf['ServiceSOAPBindingClass'].rpartition('.')
39           
40            module = __import__(modName, globals(), locals(), [className])
41            serviceSOAPBindingClass = eval('module.' + className)
42           
43            # Check class inherits from ServiceSOAPBinding
44            if not issubclass(serviceSOAPBindingClass, ServiceSOAPBinding):
45                raise TypeError(
46                    "%s class must be derived from ServiceSOAPBinding" % \
47                    self.app_conf['ServiceSOAPBindingClass'])
48        else: 
49            serviceSOAPBindingClass = ServiceSOAPBinding
50                 
51        self.serviceSOAPBinding = serviceSOAPBindingClass()
52        self.enableWSDLQuery = bool()
53        if self.app_conf.get('enableWSDLQuery', False) and \
54           hasattr(self.serviceSOAPBinding, '_wsdl'):
55            self.enableWSDLQuery = True
56
57       
58    def __call__(self, environ, start_response):
59        log.debug("SOAPMiddleware.__call__")
60
61        def start_response_wrapper(status, response_hdrs, exc_info=None):
62            '''Ensure text/xml content type and set content length'''
63           
64            contentKeys = ('content-type', 'content-length')
65            response_hdrs_alt = [(name, val) for name, val in response_hdrs\
66                                 if name.lower() not in contentKeys]
67           
68            response_hdrs_alt += [('content-type', 'text/xml'),
69                                  ('content-length', str(len(self.soapOut)))]
70                           
71            return start_response(status, response_hdrs_alt, exc_info)
72       
73        if environ.get('REQUEST_METHOD') == 'GET' and \
74           'wsdl' in dict(paste.request.parse_querystring(environ)):
75            if self.enableWSDLQuery:
76                wsdl = self.serviceSOAPBinding._wsdl
77                start_response("200 OK", [('Content-type', 'text/xml'),
78                                          ('Content-length', str(len(wsdl)))])
79                return wsdl
80               
81               
82        # Apply filter for calls
83        if not self.isSOAPMessage(environ) or \
84           not environ['PATH_INFO'].startswith(self.app_conf['path']):
85            return self.app(environ, start_response)
86
87        # Check for ParsedSoap object set in environment, if not present,
88        # make one
89        if 'ZSI.parse.ParsedSoap' in environ:
90            ps = environ['ZSI.parse.ParsedSoap']
91        else:
92            # TODO: allow for chunked data
93            soapIn = environ['wsgi.input'].read(environ['CONTENT_LENGTH'])
94            log.debug("SOAP Request")
95            log.debug("_"*80)
96            log.debug(soapIn)
97            log.debug("_"*80)
98           
99            ps = ParsedSoap(soapIn)
100       
101        # Map SOAP Action to method in binding class
102        method = getattr(self.serviceSOAPBinding, 
103                         'soap_%s' % environ['HTTP_SOAPACTION'].strip('"'))
104       
105        # TODO: change method to return response only: request, response tuple
106        # is carry over from Twisted based code
107        try:
108            req, resp = method(ps)
109        except Exception, e:
110            self._writeFault(req, resp)
111       
112        # Serialize output using SOAP writer class
113        sw = SoapWriter()
114        sw.serialize(resp)
115       
116        # Make SoapWriter object available to any SOAP filters that follow
117        environ['ZSI.writer.SoapWriter'] = sw
118        self.soapOut = str(sw)
119       
120        log.debug("SOAP Response")
121        log.debug("_"*80)
122        log.debug(self.soapOut)
123        log.debug("_"*80)
124#               
125#        if soap is not None:
126#            return self._writeResponse(request, soap)
127       
128        app = self.app(environ, start_response_wrapper)
129        #start_response("200 OK", [('Content-type', 'text/xml')])
130        return self.soapOut
131
132    @classmethod
133    def isSOAPMessage(cls, environ):
134        '''Generic method to filter out non-soap messages'''
135        return environ.get('REQUEST_METHOD', '') == 'POST' and \
136               environ.get('HTTP_SOAPACTION') is not None
137       
138       
139def makeFilter(app, app_conf): 
140    from ndgsecurity.config.attributeauthority import AttributeAuthorityWS
141   
142    return SOAPMiddleware(app, app_conf,
143                          ServiceSOAPBinding=AttributeAuthorityWS(),
144                          path='/AttributeAuthority')
Note: See TracBrowser for help on using the repository browser.