source: TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/zsi.py @ 6440

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg-security/TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/zsi.py@6440
Revision 6440, 25.3 KB checked in by pjkersha, 11 years ago (diff)
  • #1088 Important fix to AuthnRedirectResponseMiddleware? to set redirect ONLY when SSL client authentication has just succeeded in the upstream middleware AuthKitSSLAuthnMiddleware. This bug was causing the browser to redirect to the wrong place following OpenID sign in in the case where the user is already logged into their provider and selects a new relying party to sign into.
    • Improvements to Provider decide page interface: leave out messages about attributes that the provider can't retrieve for the RP. Also included NDG style help icon.
Line 
1"""WSGI SOAP Middleware utilising the ZSI Python SOAP Package
2
3NERC DataGrid Project
4
5"""
6__author__ = "P J Kershaw"
7__date__ = "19/08/09"
8__copyright__ = "(C) 2009 Science and Technology Facilities Council"
9__contact__ = "Philip.Kershaw@stfc.ac.uk"
10__license__ = "BSD - see LICENSE file in top-level directory"
11__revision__ = "$Id: $"
12import logging
13log = logging.getLogger(__name__)
14
15import sys
16
17from ZSI.parse import ParsedSoap
18from ZSI.writer import SoapWriter
19from ZSI import fault
20from ZSI.ServiceContainer import ServiceSOAPBinding
21
22from ndg.security.server.wsgi.soap import SOAPMiddleware, SOAPMiddlewareError,\
23    SOAPMiddlewareConfigError, SOAPMiddlewareReadError
24from ndg.security.common.wssecurity.utils import DomletteReader, \
25    DomletteElementProxy
26from ndg.security.common.utils.classfactory import instantiateClass, \
27    importClass
28
29     
30class ZSIMiddlewareError(SOAPMiddlewareError):
31    """Base class for ZSI Middleware type exceptions"""
32
33   
34class ZSIMiddlewareReadError(SOAPMiddlewareReadError):
35    """ZSI Middleware read error"""
36
37
38class ZSIMiddlewareConfigError(SOAPMiddlewareConfigError):
39    """ZSI middleware configuration error"""
40
41     
42class ZSIMiddleware(SOAPMiddleware):
43    '''Middleware configurable to a given ZSI SOAP binding
44
45     @type SOAP_WRITER_KEYNAME: basestring
46     @cvar SOAP_WRITER_KEYNAME: environ key for ZSI SoapWriter instance
47     @type PARSED_SOAP_KEYNAME: basestring
48     @cvar PARSED_SOAP_KEYNAME: environ key for ZSI ParsedSoap instance
49     @type CHARSET_OPTNAME: basestring
50     @cvar CHARSET_OPTNAME: option name to for character set for output
51     @type DEFAULT_CHARSET: basestring
52     @cvar DEFAULT_CHARSET: default character setting is utf-8
53     @type PATH_OPTNAME: basestring
54     @cvar PATH_OPTNAME: option to set path for this endpoint (not including
55     domain name)
56     @type WRITE_RESPONSE_OPTNAME: basestring
57     @cvar WRITE_RESPONSE_OPTNAME: option name for flag to middleware to
58     serialise and output the SoapWriter instance
59     @type REFERENCED_FILTERS_OPTNAME: basestring
60     @cvar REFERENCED_FILTERS_OPTNAME: name for option to enable dereferencing
61     of other middleware via these environ keys
62     @type FILTER_ID_OPTNAME: basestring
63     @cvar FILTER_ID_OPTNAME: option name for environ key to enable other
64     middleware to reference this Filter
65     @type PUBLISHED_URI_OPTNAME: basestring
66     @cvar PUBLISHED_URI_OPTNAME: option name to define path for this endpoint
67     including domain name
68     @type READER_CLASS_OPTNAME: basestring
69     @cvar READER_CLASS_OPTNAME: option name for SOAP reader class
70     @type WRITERCLASS_OPTNAME: basestring
71     @cvar WRITERCLASS_OPTNAME: option name for SOAP writer class
72     ''' 
73   
74    SOAP_WRITER_KEYNAME = 'ZSI.writer.SoapWriter'
75    PARSED_SOAP_KEYNAME = 'ZSI.parse.ParsedSoap'
76   
77    CHARSET_OPTNAME = 'charset'
78    DEFAULT_CHARSET = '; charset=utf-8'
79    PATH_OPTNAME = 'path'
80    WRITE_RESPONSE_OPTNAME = 'writeResponse'
81    REFERENCED_FILTERS_OPTNAME = 'referencedFilters'
82    FILTER_ID_OPTNAME = 'filterID'
83    PUBLISHED_URI_OPTNAME = 'publishedURI'
84    READER_CLASS_OPTNAME = 'readerclass'
85    WRITERCLASS_OPTNAME = 'writerclass'
86   
87    def __init__(self, app):
88        log.debug("ZSIMiddleware.__init__ ...")
89        super(ZSIMiddleware, self).__init__()
90       
91        self._app = app
92        self.__charset = ZSIMiddleware.DEFAULT_CHARSET
93        self.__path = None
94        self.__referencedFilterKeys = None
95        self.__publishedURI = None
96        self.__readerClass = None
97        self.__writerClass = None
98        self.__writeResponseSet = None
99        self.__filterID = None
100
101    def _getCharset(self):
102        return self.__charset
103
104    def _setCharset(self, value):
105        if not isinstance(value, basestring):
106            raise TypeError('Expecting string type for "charset" got %r' %
107                            type(value))
108        self.__charset = value
109
110    def _getPath(self):
111        return self.__path
112
113    def _setPath(self, value):
114        if not isinstance(value, basestring):
115            raise TypeError('Expecting string type for "path" got %r' %
116                            type(value))
117        self.__path = value
118
119    def _getPublishedURI(self):
120        return self.__publishedURI
121
122    def _setPublishedURI(self, value):
123        if not isinstance(value, (basestring, type(None))):
124            raise TypeError('Expecting string or None type for "publishedURI" '
125                            'got %r' % type(value))
126        self.__publishedURI = value
127
128    def _getReaderClass(self):
129        return self.__readerClass
130
131    def _setReaderClass(self, value):
132        self.__readerClass = value
133
134    def _getWriterClass(self):
135        return self.__writerClass
136
137    def _setWriterClass(self, value):
138        self.__writerClass = value
139
140    def _getWriteResponseSet(self):
141        return self.__writeResponseSet
142
143    def _setWriteResponseSet(self, value):
144        if not isinstance(value, bool):
145            raise TypeError('Expecting %r for "writeResponseSet" type got %r' %
146                            (bool, type(value)))
147       
148        self.__writeResponseSet = value
149
150    def _getFilterID(self):
151        return self.__filterID
152
153    def _setFilterID(self, value):
154        if not isinstance(value, (basestring, type(None))):
155            raise TypeError('Expecting string or None type for "filterID" got '
156                            '%r' % type(value))
157        self.__filterID = value
158
159    charset = property(_getCharset, _setCharset, 
160                       doc="character set for response")
161
162    path = property(_getPath, _setPath, doc="Path for endpoint")
163
164    publishedURI = property(_getPublishedURI, _setPublishedURI, 
165                            doc="fully qualified path for endpoint")
166
167    readerClass = property(_getReaderClass, _setReaderClass, 
168                           doc="ZSI Reader class")
169
170    writeResponseSet = property(_getWriteResponseSet, _setWriteResponseSet, 
171                                doc="boolean set to True to write out a "
172                                    "response from this middleware")
173
174    writerClass = property(_getWriterClass, _setWriterClass, 
175                           doc="ZSI Writer Class")
176
177    filterID = property(_getFilterID, _setFilterID, 
178                        doc="enable the instance of this middleware to be "
179                            "referenced in environ by this identifier")
180
181    def initialise(self, global_conf, prefix='', **app_conf):
182        """Set-up ZSI middleware interface attributes.  Overloaded base class
183        method to enable custom settings from app_conf
184       
185        @type global_conf: dict       
186        @param global_conf: PasteDeploy global configuration dictionary
187        @type prefix: basestring
188        @param prefix: prefix for configuration items
189        @type app_conf: dict       
190        @param app_conf: PasteDeploy application specific configuration
191        dictionary
192        """
193        charsetOptName = prefix + ZSIMiddleware.CHARSET_OPTNAME
194        if charsetOptName in app_conf:
195            self.charset = '; charset=' + app_conf[charsetOptName]
196        else:
197            self.charset = '; charset=utf-8'
198           
199        pathOptName = prefix + ZSIMiddleware.PATH_OPTNAME
200        if pathOptName in app_conf:
201            if app_conf[pathOptName] != '/':
202                self.path = app_conf[pathOptName].rstrip('/')
203            else:
204                self.path = app_conf[pathOptName]
205        else:
206            self.path = '/'
207
208        # This flag if set to True causes this handler to call the
209        # start_response method and output the SOAP response
210        writeResponseOptName = prefix + ZSIMiddleware.WRITE_RESPONSE_OPTNAME
211        self.writeResponseSet = ZSIMiddleware.str2Bool(app_conf.get(
212                                                    writeResponseOptName, ''))
213
214        # Check for a list of other filters to be referenced by this one
215        referencedFiltersOptName = prefix + \
216                                    ZSIMiddleware.REFERENCED_FILTERS_OPTNAME
217        if referencedFiltersOptName in app_conf:
218            # __call__  may reference any filters in environ keyed by these
219            # keywords
220            self.referencedFilterKeys = app_conf.pop(
221                                            referencedFiltersOptName).split()
222
223       
224        filterIdOptName = prefix + ZSIMiddleware.FILTER_ID_OPTNAME
225        self.filterID = app_conf.pop(filterIdOptName, None)
226       
227        # The endpoint that this services will be referenced from externally.
228        # e.g. the Session Manager client running locally can check the
229        # input URI and compare with this value to see if the request is
230        # actually to the local Session Manager instance
231        publishedUriOptName = prefix + ZSIMiddleware.PUBLISHED_URI_OPTNAME
232        self.publishedURI = app_conf.pop(publishedUriOptName, None)
233       
234        readerClassOptName = prefix + ZSIMiddleware.READER_CLASS_OPTNAME
235        if readerClassOptName in app_conf:
236            readerClassName = app_conf.pop(readerClassOptName)
237            self.readerClass = importClass(readerClassName)
238        else:
239            self.readerClass = DomletteReader
240           
241        writerClassOptName = prefix + ZSIMiddleware.WRITERCLASS_OPTNAME
242        if writerClassOptName in app_conf:
243            writerClassName = app_conf.pop(writerClassOptName)
244            self.writerClass = importClass(writerClassName)
245        else:
246            self.writerClass = DomletteElementProxy
247
248    def __call__(self, environ, start_response):
249        log.debug("ZSIMiddleware.__call__")
250                       
251        # Derived class must implement SOAP Response via overloaded version of
252        # this method.  ParsedSoap object is available as a key in environ via
253        # the parseRequest method
254       
255        return self.writeResponse(environ, start_response)
256
257   
258    def _initCall(self, environ, start_response):
259        '''Sub-divided out from __call__ to enable derived classes to easily
260        include this functionality:
261         - Set a reference to this WSGI filter in environ if filterID was
262        set in the config and
263         - check the request to see if this filter should handle it
264        '''
265       
266        # Add any filter references for this WSGI component regardless of the
267        # current request ID.  This ensures that other WSGI components called
268        # may reference it if they need to.
269        self.addFilter2Environ(environ)
270       
271        # Apply filter for calls
272        if not self.__class__.isSOAPMessage(environ):
273            log.debug("ZSIMiddleware.__call__: skipping non-SOAP call")
274            return self._app(environ, start_response)
275       
276        elif not self.pathMatch(environ):
277            log.debug("ZSIMiddleware.__call__: path doesn't match SOAP "
278                      "service endpoint")
279            return self._app(environ, start_response)
280       
281        elif self.__class__.isSOAPFaultSet(environ):
282            # This MUST be checked in a overloaded version especially in
283            # consideration of security: e.g. an upstream signature
284            # verification may have found an error in a signature
285            log.debug("ZSIMiddleware.__call__: SOAP fault set by previous "
286                      "SOAP middleware filter")
287            return self._app(environ, start_response)
288
289        # Parse input into a ZSI ParsedSoap object set as a key in environ
290        try:
291            self.parseRequest(environ)
292        except Exception, e:
293            sw = self.exception2SOAPFault(environ, e)
294            self.setSOAPWriter(environ, sw)
295            return self.writeResponse(environ, start_response)
296       
297        # Return None to __call__ to indicate that it can proceed with
298        # processing the input
299        return None
300
301    def exception2SOAPFault(self, environ, exception):
302        '''Convert an exception into a SOAP fault message'''
303        soapFault = fault.FaultFromException(exception, 
304                                             None,
305                                             tb=sys.exc_info()[2])
306        sw = SoapWriter(outputclass=self.writerClass)
307        soapFault.serialize(sw)
308        environ[ZSIMiddleware.SOAP_FAULT_SET_KEYNAME] = True
309        return sw
310   
311    pathMatch = lambda self, environ: environ['PATH_INFO'] == self.path
312   
313    def parseRequest(self, environ):
314        '''Parse SOAP message from environ['wsgi.input']
315       
316        Reading from environ['wsgi.input'] may be a destructive process so the
317        content is saved in a ZSI.parse.ParsedSoap object for use by SOAP
318        handlers which follow in the chain
319       
320        environ['ZSI.parse.ParsedSoap'] may be set to a ParsedSoap object
321        parsed by a SOAP handler ahead of the current one in the chain.  In
322        this case, don't re-parse.  If NOT parsed, parse and set
323        'ZSI.parse.ParsedSoap' environ key'''
324       
325        # Check for ParsedSoap object set in environment, if not present,
326        # make one
327        ps = environ.get(ZSIMiddleware.PARSED_SOAP_KEYNAME)
328        if ps is None:
329            # TODO: allow for chunked data
330            contentLength = int(environ['CONTENT_LENGTH'])
331            soapIn = environ['wsgi.input'].read(contentLength)
332            if len(soapIn) < contentLength:
333                raise ZSIMiddlewareReadError("Expecting %d content length; "
334                                             "received %d instead." % 
335                                             (contentLength, len(soapIn)))
336           
337            log.debug("SOAP Request for handler %r" % ZSIMiddleware)
338            log.debug("_" * 80)
339            log.debug(soapIn)
340            log.debug("_" * 80)
341           
342            ps = ParsedSoap(soapIn, readerclass=self.readerClass)
343            environ[ZSIMiddleware.PARSED_SOAP_KEYNAME] = ps
344           
345        return environ[ZSIMiddleware.PARSED_SOAP_KEYNAME]
346
347
348    def writeResponse(self, environ, start_response, errorCode=None):
349        '''This method serializes the SOAP output and sets the response header.
350        It's the final step and should be called in the last SOAP handler in
351        a chain of handlers or else specify it in the ini file as the last
352        SOAP handler'''
353       
354        # This flag must be set to True to write out the final response from
355        # this handler
356        if self.writeResponseSet == False:
357            return self._app(environ, start_response)
358       
359        sw = self.getSOAPWriter(environ)
360        soapOut = str(sw)
361       
362        if errorCode is None:
363            if self.__class__.isSOAPFaultSet(environ):
364                errorCode = "500 Internal Server Error"
365            else:
366                errorCode = "200 OK"
367               
368        log.debug("SOAP Response for handler %r" % self.__class__)
369        log.debug("_" * 80)
370        log.debug(soapOut)
371        log.debug("_" * 80)
372        start_response(errorCode,
373                       [('content-type', 'text/xml' + self.charset),
374                        ('content-length', str(len(soapOut)))])
375        return soapOut
376
377    @classmethod
378    def getSOAPWriter(cls, environ):
379        '''Access SoapWriter object set in environment by this classes' call
380        method'''
381       
382        sw = environ.get(ZSIMiddleware.SOAP_WRITER_KEYNAME)
383        if sw is None:
384            raise KeyError("Expecting '%s' key in environ: missing call to "
385                           "ZSIMiddleware?" % ZSIMiddleware.SOAP_WRITER_KEYNAME)
386        return sw
387   
388    @classmethod
389    def setSOAPWriter(cls, environ, sw):
390        '''Set SoapWriter object in environment'''   
391        environ[ZSIMiddleware.SOAP_WRITER_KEYNAME] = sw
392
393    def addFilter2Environ(self, environ):
394        '''Add a key to the current application in the environment so that
395        other middleware can reference it.  This is dependent on filterID set
396        in app_conf'''
397        if self.filterID is not None:           
398            if self.filterID in environ:
399                raise ZSIMiddlewareConfigError("An filterID key '%s' is "
400                                                "already set in environ" % 
401                                                self.filterID)
402            environ[self.filterID] = self
403
404
405class SOAPBindingMiddleware(ZSIMiddleware): 
406    '''Interface to apply a ZSI ServiceSOAPBinding type SOAP service'''
407   
408    SERVICE_SOAP_BINDING_CLASSNAME_OPTNAME = 'serviceSOAPBindingClass'
409    SERVICE_SOAP_BINDING_PROPPREFIX_OPTNAME = 'serviceSOAPBindingPropPrefix'
410    DEFAULT_SERVICE_SOAP_BINDING_PROPPREFIX_OPTNAME = \
411                            'ndg.security.server.wsgi.zsi.serviceSOAPBinding.'
412                           
413    SERVICE_SOAP_BINDING_ENVIRON_KEYNAME_OPTNAME = \
414                            'serviceSOAPBindingEnvironKeyName' 
415    DEFAULT_SERVICE_SOAP_BINDING_ENVIRON_KEYNAME = \
416                            'ndg.security.servier.wsgi.zsi.serviceSOAPBinding'
417    ENABLE_WSDL_QUERY_OPTNAME = 'enableWSDLQuery' 
418    DEFAULT_ENABLE_WSDL_QUERY_VALUE = False
419    SOAP_METHOD_STRING = 'soap_%s'
420   
421    def __init__(self, app):
422        super(SOAPBindingMiddleware, self).__init__(app)
423        self.__serviceSOAPBindingKeyName = None
424        self.__serviceSOAPBinding = None
425        self.__enableWSDLQuery = False
426       
427    def _getServiceSOAPBinding(self):
428        return self.__serviceSOAPBinding
429
430    def _setServiceSOAPBinding(self, value):
431        """Instance must be ZSI ServiceSOAPBinding derived type"""
432        if not isinstance(value, ServiceSOAPBinding):
433            raise TypeError('Expecting %r type for "serviceSOAPBinding"; got '
434                            '%r' % (ServiceSOAPBinding, type(value)))
435        self.__serviceSOAPBinding = value
436
437    serviceSOAPBinding = property(fget=_getServiceSOAPBinding, 
438                                  fset=_setServiceSOAPBinding, 
439                                  doc="Instance of ZSI ServiceSOAPBinding "
440                                      "derived type determines the behaviour "
441                                      "of the SOAP callbacks")
442
443    def _getServiceSOAPBindingKeyName(self):
444        return self.__serviceSOAPBindingKeyName
445
446    def _setServiceSOAPBindingKeyName(self, value):
447        """Instance must be ZSI ServiceSOAPBindingKeyName derived type"""
448        if not isinstance(value, basestring):
449            raise TypeError('Expecting bool type for "enableWSDLQuery"; got '
450                            '%r' % type(value))
451        self.__serviceSOAPBindingKeyName = value
452
453    serviceSOAPBindingKeyName = property(fget=_getServiceSOAPBindingKeyName, 
454                                         fset=_setServiceSOAPBindingKeyName, 
455                                         doc="Keyword to key WSGI environ for "
456                                             "SOAP Binding middleware instance")
457
458    def _getEnableWSDLQuery(self):
459        return self.__enableWSDLQuery
460
461    def _setEnableWSDLQuery(self, value):
462        if not isinstance(value, bool):
463            raise TypeError('Expecting bool type for "enableWSDLQuery"; got '
464                            '%r' % type(value))
465        self.__enableWSDLQuery = value
466       
467    enableWSDLQuery = property(fget=_getEnableWSDLQuery, 
468                               fset=_setEnableWSDLQuery, 
469                               doc="Enable service to publish the WSDL via "
470                                   "the ?wsdl query argument appended to the "
471                                   "endpoint")
472
473    def initialise(self, global_conf, prefix='', **app_conf):
474        """Set-up ZSI SOAP Binding middleware interface attributes.
475         Overloaded base class method to enable custom settings from app_conf
476       
477        @type global_conf: dict       
478        @param global_conf: PasteDeploy global configuration dictionary
479        @type prefix: basestring
480        @param prefix: prefix for configuration items
481        @type app_conf: dict       
482        @param app_conf: PasteDeploy application specific configuration
483        dictionary
484        """
485        super(SOAPBindingMiddleware, self).initialise(global_conf, 
486                                                      prefix=prefix,
487                                                      **app_conf)
488       
489        serviceSOAPBindingEnvironKeyNameOptName = prefix + \
490            SOAPBindingMiddleware.SERVICE_SOAP_BINDING_ENVIRON_KEYNAME_OPTNAME
491        serviceSOAPBindingClassNameOptName = prefix + \
492            SOAPBindingMiddleware.SERVICE_SOAP_BINDING_CLASSNAME_OPTNAME
493                           
494        if serviceSOAPBindingEnvironKeyNameOptName in app_conf and \
495           serviceSOAPBindingClassNameOptName in app_conf:
496            raise ZSIMiddlewareConfigError('Only "%s" or "%s" may be set; not '
497                                           ' both' % 
498            (SOAPBindingMiddleware.SERVICE_SOAP_BINDING_ENVIRON_KEYNAME_OPTNAME,
499             SOAPBindingMiddleware.SERVICE_SOAP_BINDING_CLASSNAME_OPTNAME))
500           
501        if serviceSOAPBindingClassNameOptName in app_conf:
502            # Instantiate the binding from the config settings
503            modName, className = app_conf[
504                            serviceSOAPBindingClassNameOptName].rsplit('.', 1)
505               
506            # Filter
507            prefixOptName = prefix + \
508                SOAPBindingMiddleware.SERVICE_SOAP_BINDING_PROPPREFIX_OPTNAME
509            prefix = app_conf.get(prefixOptName,
510                            SOAPBindingMiddleware.
511                            DEFAULT_SERVICE_SOAP_BINDING_PROPPREFIX_OPTNAME)
512           
513            serviceSOAPBindingKw = dict([(k.replace(prefix, ''), v)
514                                         for k, v in app_conf.items()
515                                         if k.startswith(prefix)])
516   
517            self.serviceSOAPBinding = instantiateClass(modName,
518                                       className,
519                                       objectType=ServiceSOAPBinding,
520                                       classProperties=serviceSOAPBindingKw)           
521        else: 
522            # Alternatively, reference another binding instance made available
523            # by upstream middleware via environ
524            self.serviceSOAPBindingKeyName = app_conf.get(
525                            serviceSOAPBindingEnvironKeyNameOptName,
526                            SOAPBindingMiddleware.
527                            DEFAULT_SERVICE_SOAP_BINDING_ENVIRON_KEYNAME)
528       
529       
530        # Flag to enable display of WSDL via wsdl query arg in a GET request
531        enableWSDLQueryOptName = prefix + \
532                                SOAPBindingMiddleware.ENABLE_WSDL_QUERY_OPTNAME
533        self.enableWSDLQuery = SOAPBindingMiddleware.str2Bool(
534                                    app_conf.get(enableWSDLQueryOptName, ''))   
535   
536    def __call__(self, environ, start_response):
537        log.debug("SOAPBindingMiddleware.__call__ ...")
538             
539        # Get a reference to the service SOAP binding from environ or if not,
540        # from the binding instantiated at initialisation
541        serviceSOAPBinding = environ.get(self.serviceSOAPBindingKeyName,
542                                         self.serviceSOAPBinding)
543        if serviceSOAPBinding is None:
544            raise ZSIMiddlewareConfigError('No SOAP service binding set in '
545                                           'environ or configured from start'
546                                           '-up')
547             
548        if self.pathMatch(environ) and self.enableWSDLQuery and \
549           environ.get('REQUEST_METHOD', '') == 'GET' and \
550           environ.get('QUERY_STRING', '') == 'wsdl':
551            wsdl = serviceSOAPBinding._wsdl
552            start_response("200 OK", [('Content-type', 'text/xml'),
553                                      ('Content-length', str(len(wsdl)))])
554            return wsdl
555               
556        # Apply filter for calls
557        response = self._initCall(environ, start_response)
558        if response is not None:
559            return response
560         
561        try:
562            # Other filters in the middleware chain may be passed by setting
563            # a reference to them in the config.  This is useful if the SOAP
564            # binding code needs to access results from upstream middleware
565            # e.g. check output from signature verification filter
566            if hasattr(self, 'referencedFilterKeys'):
567                try:
568                    serviceSOAPBinding.referencedWSGIFilters = \
569                                    dict([(i, environ[i]) 
570                                          for i in self.referencedFilterKeys])
571                except KeyError:
572                    raise ZSIMiddlewareConfigError('No filter ID "%s" found '
573                                                   'in environ' % i)   
574            ps = self.parseRequest(environ)
575               
576            # Map SOAP Action to method in binding class
577            soapActionName = environ[
578                            SOAPBindingMiddleware.SOAP_ACTION_ENVIRON_KEYNAME
579                            ].strip('"')
580            soapMethodName = SOAPBindingMiddleware.SOAP_METHOD_STRING % \
581                            soapActionName
582                   
583           
584            method = getattr(serviceSOAPBinding, soapMethodName)           
585            resp = method(ps)
586        except Exception, e:
587            sw = self.exception2SOAPFault(environ, e)
588        else: 
589            # Serialize output using SOAP writer class
590            sw = SoapWriter(outputclass=self.writerClass)
591            sw.serialize(resp)
592       
593        # Make SoapWriter object available to any SOAP filters that follow
594        self.setSOAPWriter(environ, sw)
595        soapOut = str(sw)
596
597        return self.writeResponse(environ, start_response)
Note: See TracBrowser for help on using the repository browser.