source: TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/utils/sessionmanagerclient.py @ 4501

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

New ndg.security.server.wsgi.utils package to hold Session Manager and Attribute Authority client wrappers. These check environ for a local SM/AA instance or call a remote service if a URI is given.

  • Added a test for Combined Services unit test to try out a Session Manager connect using the new wrapper.
Line 
1"""NDG Security client - client interface classes to Session Manager
2
3Make requests for authentication and authorisation
4
5NERC Data Grid Project
6
7This software may be distributed under the terms of the Q Public License,
8version 1.0 or later.
9"""
10__author__ = "P J Kershaw"
11__date__ = "24/04/06"
12__copyright__ = "(C) 2007 STFC & NERC"
13__contact__ = "Philip.Kershaw@stfc.ac.uk"
14__revision__ = "$Id:sessionmanager.py 4373 2008-10-29 09:54:39Z pjkersha $"
15
16import logging
17log = logging.getLogger(__name__)
18
19import sys
20import os
21
22# Determine https http transport
23import urlparse
24
25from ZSI.wstools.Utility import HTTPResponse
26
27from ndg.security.common.wssecurity.dom import SignatureHandler
28from ndg.security.common.X509 import *
29from ndg.security.common.AttCert import AttCert, AttCertParse
30from ndg.security.common.m2CryptoSSLUtility import HTTPSConnection, \
31    HostCheck
32from ndg.security.common.zsi.httpproxy import ProxyHTTPConnection
33from ndg.security.common.zsi.sessionmanager.SessionManager_services import \
34                                                SessionManagerServiceLocator
35
36
37
38class SessionManagerClientError(Exception):
39    """Exception handling for WSGISessionManagerClient class"""
40
41class SessionNotFound(SessionManagerClientError):
42    """Raise when a session ID input doesn't match with an active session on
43    the Session Manager"""
44
45class SessionCertTimeError(SessionManagerClientError):
46    """Session's X.509 Cert. not before time is BEFORE the system time -
47    usually caused by server's clocks being out of sync.  Fix by all servers
48    running NTP"""
49
50class SessionExpired(SessionManagerClientError):
51    """Session's X.509 Cert. has expired"""
52
53class InvalidSession(SessionManagerClientError):
54    """Session is invalid"""
55
56class InvalidSessionManagerClientCtx(SessionManagerClientError):
57    """Session Manager ZSI Client is not initialised"""
58 
59class AttributeRequestDenied(SessionManagerClientError):
60    """Raise when a getAttCert call to the Attribute Authority is denied"""
61   
62    def __init__(self, *args, **kw):
63        """Raise exception for attribute request denied with option to give
64        caller hint to certificates that could used to try to obtain a
65        mapped certificate
66       
67        @type extAttCertList: list
68        @param extAttCertList: list of candidate Attribute Certificates that
69        could be used to try to get a mapped certificate from the target
70        Attribute Authority"""
71       
72        # Prevent None type setting
73        self.__extAttCertList = []
74        if 'extAttCertList' in kw and kw['extAttCertList'] is not None:
75            for ac in kw['extAttCertList']:
76                if isinstance(ac, basestring):
77                    ac = AttCertParse(ac)
78                elif not isinstance(ac, AttCert):
79                    raise SessionManagerClientError(
80                        "Input external Attribute Cert. must be AttCert type")
81                         
82                self.__extAttCertList += [ac]
83               
84            del kw['extAttCertList']
85           
86        Exception.__init__(self, *args, **kw)
87
88       
89    def __getExtAttCertList(self):
90        """Return list of candidate Attribute Certificates that could be used
91        to try to get a mapped certificate from the target Attribute Authority
92        """
93        return self.__extAttCertList
94
95    extAttCertList = property(fget=__getExtAttCertList,
96                              doc="list of candidate Attribute Certificates "
97                                  "that could be used to try to get a mapped "
98                                  "certificate from the target Attribute "
99                                  "Authority")
100
101class WSGISessionManagerClient(object):
102    """Client interface to Session Manager for WSGI based applications
103   
104    This class wraps the SOAP based web service client and alternate access to
105    a Session Manager in the same code stack via an environ keyword
106    """
107    environKey = "ndg.security.server.sessionmanager.SessionManager"
108   
109    def __init__(self, environKey=None, environ={}, 
110                 **SessionManagerClientKw):
111        """"""
112
113        log.debug("WSGISessionManagerClient.__init__ ...")
114       
115        self._environKey = environKey or WSGISessionManagerClient.environKey
116       
117        # Standard WSGI environment dict
118        self._environ = environ
119       
120        if 'uri' in SessionManagerClientKw:
121            self._soapClient = SessionManagerClient(**SessionManagerClientKw)
122
123    _sessionManagerInEnviron = lambda self: self._environKey in self._environ
124   
125    # Define as property for convenient call syntax
126    sessionManagerInEnviron = property(fget=_sessionManagerInEnviron,
127                                       doc="return True if a Session Manager "
128                                           "instance is available in "
129                                           "WSGI environ")
130   
131    _getSessionManager = lambda self:\
132                        self._environ[self._environKey].serviceSOAPBinding.sm
133    sessionManager = property(fget=_getSessionManager,
134                              doc="Session Manager local instance")
135   
136    def connect(self, username, **kw):
137        """Request a new user session from the Session Manager
138       
139        @type username: string
140        @param username: the username of the user to connect
141        """
142   
143        if self.sessionManagerInEnviron:
144            # Connect to local instance
145            res = self.sessionManager.connect(username=username, **kw)
146        else:
147            # Filter out keywords which apply to a Session Manager local
148            # instance call
149            kw.pop('userX509Cert', None)
150           
151            # Make connection to remote service
152            res = self._soapClient.connect(**kw)
153   
154            # Convert from unicode because unicode causes problems with
155            # M2Crypto private key load
156            res = tuple([isinstance(i,unicode) and str(i) or i for i in res])
157           
158        return res
159   
160   
161    def disconnect(self, userCert=None, sessID=None):
162        """Delete an existing user session from the Session Manager
163       
164        disconnect([userCert=c]|[sessID=i])
165       
166        @type userCert: string                 
167        @param userCert: user's certificate used to identifier which session
168        to disconnect.  This arg is not needed if the message is signed with
169        the user cert or if sessID is set. 
170                               
171        @type sessID: string
172        @param sessID: session ID.  Input this as an alternative to userCert
173        This arg is not needed if the message is signed with the user cert or
174        if userCert keyword is."""
175   
176        if not self.__srv:
177            raise InvalidSessionManagerClientCtx("Client binding is not "
178                                                 "initialised")
179
180        # Make connection
181        self.__srv.disconnect(userCert, sessID)
182   
183    def getSessionStatus(self, userDN=None, sessID=None):
184        """Check for the existence of a session with a given
185        session ID / user certificate Distinguished Name
186       
187        disconnect([sessID=id]|[userDN=dn])
188       
189        @type userCert: string                 
190        @param userCert: user's certificate used to identifier which session
191        to disconnect.  This arg is not needed if the message is signed with
192        the user cert or if sessID is set. 
193                               
194        @type sessID: string
195        @param sessID: session ID.  Input this as an alternative to userCert
196        This arg is not needed if the message is signed with the user cert or
197        if userCert keyword is."""
198   
199        if not self.__srv:
200            raise InvalidSessionManagerClientCtx("Client binding is not "
201                                                 "initialised")
202       
203        if sessID and userDN:
204            raise SessionManagerClientError(
205                            'Only "SessID" or "userDN" keywords may be set')
206           
207        if not sessID and not userDN:
208            raise SessionManagerClientError(
209                            'A "SessID" or "userDN" keyword must be set')         
210           
211        # Make connection
212        return self.__srv.getSessionStatus(userDN, sessID)
213
214    def getAttCert(self,
215                   userCert=None,
216                   sessID=None,
217                   attAuthorityURI=None,
218                   reqRole=None,
219                   mapFromTrustedHosts=True,
220                   rtnExtAttCertList=False,
221                   extAttCertList=[],
222                   extTrustedHostList=[]):   
223        """Request NDG Session Manager Web Service to retrieve an Attribute
224        Certificate from the given Attribute Authority and cache it in the
225        user's credential wallet held by the session manager.
226       
227        ac = getAttCert([sessID=i]|[userCert=p][key=arg, ...])
228         
229        @raise AttributeRequestDenied: this is raised if the request is
230        denied because the user is not registered with the Attribute
231        Authority.  In this case, a list of candidate attribute certificates
232        may be returned which could be used to retry with a request for a
233        mapped AC.  These are assigned to the raised exception's
234        extAttCertList attribute
235             
236        @type userCert: string
237        @param userCert: user certificate - use as ID instead of session
238        ID.  This can be omitted if the message is signed with a user
239        certificate.  In this case the user certificate is passed in the
240        BinarySecurityToken of the WS-Security header
241       
242        @type sessID: string
243        @param sessID: session ID.  Input this as an alternative to
244        userCert in the case of a browser client.
245       
246        @type attAuthorityURI: string
247        @param attAuthorityURI: URI for Attribute Authority WS.
248       
249        @type reqRole: string
250        @param reqRole: The required role for access to a data set.  This
251        can be left out in which case the Attribute Authority just returns
252        whatever Attribute Certificate it has for the user
253       
254        @type mapFromTrustedHosts: bool
255        @param mapFromTrustedHosts: Allow a mapped Attribute Certificate to
256        be created from a user certificate from another trusted host.
257       
258        @type rtnExtAttCertList: bool
259        @param rtnExtAttCertList: Set this flag True so that if the
260        attribute request is denied, a list of potential attribute
261        certificates for mapping may be returned.
262       
263        @type extAttCertList: list
264        @param extAttCertList: A list of Attribute Certificates from other
265        trusted hosts from which the target Attribute Authority can make a
266        mapped certificate
267       
268        @type extTrustedHostList: list
269        @param extTrustedHostList: A list of trusted hosts that can be used
270        to get Attribute Certificates for making a mapped AC.
271       
272        @rtype: ndg.security.common.AttCert.AttCert
273        @return: if successful, an attribute certificate."""
274   
275        if not self.__srv:
276            raise InvalidSessionManagerClientCtx("Client binding is not "
277                                                 "initialised")
278       
279        # Make request
280        try:
281            attCert, msg, extAttCertList = self.__srv.getAttCert(userCert,
282                                                           sessID, 
283                                                           attAuthorityURI,
284                                                           reqRole,
285                                                           mapFromTrustedHosts,
286                                                           rtnExtAttCertList,
287                                                           extAttCertList,
288                                                           extTrustedHostList)
289        except Exception, e:
290            # Try to detect exception type from SOAP fault message
291            errMsg = str(e)
292            for excep in self.excepMap:
293                if excep in errMsg:
294                    raise self.excepMap[excep]
295       
296            # Catch all in case none of the known types matched
297            raise e
298       
299        if not attCert:
300            raise AttributeRequestDenied(msg, extAttCertList=extAttCertList)
301       
302        return AttCertParse(attCert)
Note: See TracBrowser for help on using the repository browser.