source: TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/utils/clientbase.py @ 5181

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

Added a Policy Information Point to encapsulate subject attribute retrieval.

Line 
1"""NDG Security
2
3Functionality for client interface to WSGI based applications. 
4
5NERC DataGrid Project
6"""
7__author__ = "P J Kershaw"
8__date__ = "30/01/09"
9__copyright__ = "(C) 2009 Science and Technology Facilities Council"
10__license__ = "BSD - see LICENSE file in top-level directory"
11__contact__ = "Philip.Kershaw@stfc.ac.uk"
12__revision__ = "$Id$"
13import logging
14log = logging.getLogger(__name__)
15
16class WSGIClientBase(object):
17    '''Base class for client interface to WSGI based applications.  The client
18    can access the service via a key in the WSGI environ dictionary or by
19    instantiating a proxy to some remote service.  By wrapping this choice,
20    clients can potentially avoid calls over the wire to services that are
21    otherwise available locally.  At the same time, the client can be
22    agnostic as to whether the call was made locally or over the network.
23    '''
24
25    defaultEnvironKeyName = ''
26   
27    def __init__(self, environKeyName=None, environ={}, **clientKw):
28        """Initialise an interface to a service accessible either via a
29        keyword to a WSGI environ dictionary or via a web service call
30       
31        @type environKeyName: basestring or None
32        @param environKeyName: dict key reference to service object to be
33        invoked.  This may be set later using the environKeyName property
34        or may be omitted altogether if the service is to be invoked via a
35        web service call
36        @type environ: dict
37        @param environ: WSGI environment dictionary containing a reference to
38        the service object.  This may not be known at instantiation of this
39        class.  environ is not required if the service is to be invoked over
40        a web service interface
41        @type clientKw: dict
42        @param clientKw: custom keywords to instantiate a web service client
43        interface.  Derived classes are responsible for instantiating this
44        from an extended version of this __init__ method.
45        """
46       
47        self._environKeyName = environKeyName or \
48                               WSGICLientBase.defaultEnvironKeyName
49                       
50        # Standard WSGI environment dict
51        self._environ = environ   
52       
53        # Derived class could instantiate required client type if a 'uri'
54        # key is set in clientKw   
55        self._wsClient = None
56       
57    def _getWSClient(self):
58        return getattr(self, '_wsClient', None)
59   
60    def _setWSClient(self, wsClient):
61        self._wsClient = wsClient
62   
63    wsClient = property(fget=_getWSClient,
64                        fset=_setWSClient, 
65                        doc="Web service client to service to be invoked")
66   
67    def _getWSClientURI(self):
68        return getattr(self.wsClient, 'uri', None)
69
70    uri = property(fget=_getWSClientURI,
71                   doc="URI for web service or None if no WS Client is set")
72
73    def _setEnvironKeyName(self, keyName):
74        if not isinstance(keyName, (None.__class__, basestring)):
75            raise TypeError("environKeyName must be string or None type; got "
76                            "%s" % keyName)
77           
78        self._environKeyName = keyName
79
80    def _getEnvironKeyName(self):
81        return self._environKeyName
82   
83    environKeyName = property(fget=_getEnvironKeyName,
84                              fset=_setEnvironKeyName,
85                              doc="key in environ dict holding reference to "
86                                  "service to be invoked.  This may be None "
87                                  "if the service is to be invoked via the "
88                                  "web service client")
89   
90    def _setEnviron(self, environ):
91        if not isinstance(environ, dict):
92            raise TypeError("Expecting dict type for 'environ' property")
93        self._environ = environ
94       
95    def _getEnviron(self):
96        return self._environ
97   
98    environ = property(fget=_getEnviron, 
99                       fset=_setEnviron, 
100                       doc="WSGI environ dictionary")
101
102    def _getLocalClient(self):
103        """Get reference to WSGI service instance in environ"""
104        raise NotImplementedError()
105   
106    localClient = property(fget=_getLocalClient, doc="local instance")
107   
108    def _localClientInEnviron(self):
109        '''Check whether a reference is present in the WSGI environ to the
110        service to be queried.  Check also that if a URI was specified by the
111        client, it matches the URI the local WSGI service is published under.
112       
113        This method is critical to the purpose of this class ie. enables
114        clients to optimize calls to local services by avoiding calling them
115        over the network and instead accessing them locally through the WSGI
116        stack.
117       
118        The client class must have a uri attribute and the WSGI service
119        referenced must have a published URI attribute
120        '''
121        if self._environKeyName not in self._environ:
122            log.debug("Checking for referenced WSGI service in environ: "
123                      "the given key was not found in the environ dictionary")
124            return False
125       
126        if self._wsClient:
127            # A SOAP client was initialised - check to see if its URI matches
128            # the URI for the service referenced in environ
129            requestedURI = getattr(self._wsClient, 'uri', None)
130            if requestedURI is None:
131                log.debug("Checking for referenced WSGI service in environ: "
132                          "No URI was set in the client request - assuming "
133                          "call to local service")
134                return True
135           
136            serviceURI = getattr(self._environ[self._environKeyName], 
137                                 'publishedURI',
138                                 None)
139            if serviceURI is None:
140                log.debug("Checking for referenced WSGI service in environ: "
141                          "no service URI was set")
142                return False
143            else:
144                log.debug("Checking for referenced WSGI service in environ: "
145                          "testing requested URI equals the referenced WSGI "
146                          "service's URI")
147                return requestedURI == serviceURI
148        else:
149            log.debug("Checking for referenced WSGI service in environ: "
150                      "no client is set - a local instance must be referenced")
151            return True
152   
153    # Define as property for convenient call syntax
154    localClientInEnviron = property(fget=_localClientInEnviron,
155                                    doc="return True if referenced instance "
156                                        "is available in WSGI environ")
Note: See TracBrowser for help on using the repository browser.