source: TI12-security/trunk/python/ndg.security.common/ndg/security/common/SessionMgr/__init__.py @ 3145

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.common/ndg/security/common/SessionMgr/__init__.py@3145
Revision 3145, 20.3 KB checked in by pjkersha, 12 years ago (diff)

python/www/html/sessionMgr.wsdl,
python/ndg.security.common/ndg/security/common/SessionMgr/SessionMgr_services.py,
python/ndg.security.common/ndg/security/common/SessionMgr/SessionMgr_services_types.py,
python/ndg.security.server/ndg/security/server/SessionMgr/SessionMgr_services_server.py:

  • remove refs to proxy certs - using MyProxy? as CA proxy certs aren't generated.
  • make issuingCert nillable as it won't be set if calling MyProxy? in Simple CA mode

python/ndg.security.server/ndg/security/server/conf/sessionMgr.tac: removes refs to proxy cert - replace with user cert

python/ndg.security.server/ndg/security/server/conf/sessionMgrProperties.xml: fix MyProxy? cert times - these are in seconds NOT hours

python/ndg.security.server/ndg/security/server/MyProxy.py: remove '\0's from get and info commands

python/ndg.security.test/ndg/security/test/sessionMgrClient/SessionMgrClientTest.py: fixed for tests with new MyProxy? config as SimpleCA

python/ndg.security.test/ndg/security/test/sessionMgrClient/server.sh: get rid of --pidfile arg to twistd - not needed.

python/ndg.security.test/ndg/security/test/sessionMgrClient/sm-clnt.crt,
python/ndg.security.test/ndg/security/test/sessionMgrClient/sm-clnt.key,

python/ndg.security.test/ndg/security/test/sessionMgr/sessionMgrProperties.xml,
python/ndg.security.test/ndg/security/test/sessionMgr/sessionMgrTest.cfg,
python/ndg.security.test/ndg/security/test/sessionMgrClient/sessionMgrProperties.xml,
python/ndg.security.test/ndg/security/test/sessionMgrClient/sessionMgrClientTest.cfg: altered for tests with multiple CAs

python/ndg.security.common/ndg/security/common/SessionMgr/init.py:

  • removed addUser method - not needed
  • switched refs to proxy cert -> user cert
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
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__ = "P.J.Kershaw@rl.ac.uk"
14__revision__ = "$Id$"
15__all__ = ['SessionMgr_services', 'SessionMgr_services_types']
16
17import sys
18import os
19
20# Determine https http transport
21import urlparse
22
23from ZSI.wstools.Utility import HTTPResponse
24
25from ndg.security.common.SessionCookie import SessionCookie
26from ndg.security.common.wsSecurity import SignatureHandler
27from ndg.security.common.X509 import *
28from ndg.security.common.AttCert import AttCert, AttCertParse
29from ndg.security.common.m2CryptoSSLUtility import HTTPSConnection, \
30    HostCheck
31from SessionMgr_services import SessionMgrServiceLocator
32
33
34#_____________________________________________________________________________
35class SessionMgrClientError(Exception):
36    """Exception handling for SessionMgrClient class"""
37
38#_____________________________________________________________________________
39class SessionNotFound(SessionMgrClientError):
40    """Raise when a session ID input doesn't match with an active session on
41    the Session Manager"""
42
43#_____________________________________________________________________________
44class SessionCertTimeError(SessionMgrClientError):
45    """Session's X.509 Cert. not before time is BEFORE the system time -
46    usually caused by server's clocks being out of sync.  Fix by all servers
47    running NTP"""
48
49#_____________________________________________________________________________
50class SessionExpired(SessionMgrClientError):
51    """Session's X.509 Cert. has expired"""
52
53#_____________________________________________________________________________
54class InvalidSession(SessionMgrClientError):
55    """Session is invalid"""
56 
57#_____________________________________________________________________________
58class AttributeRequestDenied(SessionMgrClientError):
59    """Raise when a getAttCert call to the Attribute Authority is denied"""
60   
61    def __init__(self, *args, **kw):
62        """Raise exception for attribute request denied with option to give
63        caller hint to certificates that could used to try to obtain a
64        mapped certificate
65       
66        @type extAttCertList: list
67        @param extAttCertList: list of candidate Attribute Certificates that
68        could be used to try to get a mapped certificate from the target
69        Attribute Authority"""
70       
71        # Prevent None type setting
72        self.__extAttCertList = []
73        if 'extAttCertList' in kw and kw['extAttCertList'] is not None:
74            for ac in kw['extAttCertList']:
75                if isinstance(ac, basestring):
76                    ac = AttCertParse(ac)
77                elif not isinstance(ac, AttCert):
78                    raise SessionMgrClientError, \
79                        "Input external Attribute Cert. must be AttCert type"
80                         
81                self.__extAttCertList += [ac]
82               
83            del kw['extAttCertList']
84           
85        Exception.__init__(self, *args, **kw)
86
87       
88    def __getExtAttCertList(self):
89        """Return list of candidate Attribute Certificates that could be used
90        to try to get a mapped certificate from the target Attribute Authority
91        """
92        return self.__extAttCertList
93
94    extAttCertList = property(fget=__getExtAttCertList,
95                              doc="list of candidate Attribute " + \
96                              "Certificates that could be used " + \
97                              "to try to get a mapped certificate " + \
98                              "from the target Attribute Authority")
99
100#_____________________________________________________________________________       
101class SessionMgrClient(object):
102    """Client interface to Session Manager Web Service
103   
104    @type excepMap: dict
105    @cvar excepMap: map exception strings returned from SOAP fault to client
106    Exception class to call"""
107
108    excepMap = {'SessionNotFound': SessionNotFound,
109                'UserSessionX509CertNotBeforeTimeError': SessionCertTimeError,
110                'UserSessionExpired': SessionExpired,
111                'InvalidUserSession': InvalidSession
112                }
113   
114    #_________________________________________________________________________
115    def __init__(self, 
116                 uri=None, 
117                 tracefile=None,
118                 sslCACertList=[],
119                 sslCACertFilePathList=[],
120                 sslPeerCertCN=None, 
121                 setSignatureHandler=True,
122                 **signatureHandlerKw):
123        """
124        @type uri: string
125        @param uri: URI for Session Manager WS.  Setting it will set the
126        Service user
127               
128        @type tracefile: file stream type
129        @param tracefile: set to file object such as sys.stderr to give extra
130        WS debug information
131       
132        @type sslCACertList: list
133        @param sslCACertList: This keyword is for use with SSL connections
134        only.  Set a list of one or more CA certificates.  The peer cert.
135        must verify against at least one of these otherwise the connection
136        is dropped.
137       
138        @type sslCACertFilePathList: list
139        @param sslCACertFilePathList: the same as the above except CA certs
140        can be passed as a list of file paths to read from
141       
142        @type sslPeerCertCN: string
143        @param sslPeerCertCN: set an alternate CommonName to match with peer
144        cert.  This keyword is for use with SSL connections only.
145       
146        @type setSignatureHandler: bool
147        @param setSignatureHandler: flag to determine whether to apply
148        WS-Security Signature Handler or not
149
150        @type signatureHandlerKw: dict
151        @param signatureHandlerKw: keywords to configure signature handler"""
152
153        self.__srv = None
154        self.__uri = None
155        self._transdict = {}       
156       
157        if uri:
158            self.__setURI(uri)
159
160        if sslPeerCertCN:
161            self.__setSSLPeerCertCN(sslPeerCertCN)
162       
163        if sslCACertList:
164            self.__setSSLCACertList(sslCACertList)
165        elif sslCACertFilePathList:
166            self.__setSSLCACertFilePathList(sslCACertFilePathList)
167
168        # WS-Security Signature handler - set only if any of the keywords were
169        # set
170        if setSignatureHandler:
171            self.__signatureHandler = SignatureHandler(**signatureHandlerKw)
172        else:
173            self.__signatureHandler = None
174       
175        self.__tracefile = tracefile
176
177         
178        # Instantiate Session Manager WS ZSI client
179        if self.__uri:
180            self.initService()
181       
182
183    #_________________________________________________________________________
184    def __setURI(self, uri):
185        """Set URI for service
186        @type uri: string
187        @param uri: URI for service to connect to"""
188       
189        if not isinstance(uri, basestring):
190            raise SessionMgrClientError, \
191                             "Session Manager WSDL URI must be a valid string"
192       
193        self.__uri = uri
194        try:
195            scheme = urlparse.urlparse(self.__uri)[0]
196        except TypeError:
197            raise AttributeAuthorityClientError, \
198                "Error parsing transport type from URI"
199               
200        if scheme == "https":
201            self._transport = HTTPSConnection
202        else:
203            self._transport = None
204           
205            # Ensure SSL settings are cancelled
206            self.__setSSLPeerCertCN(None)
207
208    #_________________________________________________________________________
209    def __getURI(self):
210        """Get URI for service
211        @rtype: string
212        @return: uri for service to be invoked"""
213        return self.__uri
214       
215    uri = property(fset=__setURI, fget=__getURI, doc="Session Manager URI")
216
217
218    #_________________________________________________________________________
219    def __setSSLPeerCertCN(self, cn):
220        """For use with HTTPS connections only.  Specify the Common
221        Name to match with Common Name of the peer certificate.  This is not
222        needed if the peer cert CN = peer hostname"""
223        if self._transport != HTTPSConnection:
224            return
225       
226        if self._transdict.get('postConnectionCheck'):
227            self._transdict['postConnectionCheck'].peerCertCN = cn
228        else:
229            self._transdict['postConnectionCheck'] = HostCheck(peerCertCN=cn)
230
231    sslPeerCertCN = property(fset=__setSSLPeerCertCN, 
232doc="for https connections, set CN of peer cert if other than peer hostname")
233
234
235    #_________________________________________________________________________
236    def __setSSLCACertList(self, caCertList):
237        """For use with HTTPS connections only.  Specify CA certs to one of
238        which the peer cert must verify its signature against"""
239        if self._transport != HTTPSConnection:
240            return
241       
242        if self._transdict.get('postConnectionCheck'):
243            self._transdict['postConnectionCheck'].caCertList = caCertList
244        else:
245            self._transdict['postConnectionCheck'] = \
246                                            HostCheck(caCertList=caCertList)
247
248    sslCACertList = property(fset=__setSSLCACertList, 
249doc="for https connections, set list of CA certs from which to verify peer cert")
250
251
252    #_________________________________________________________________________
253    def __setSSLCACertFilePathList(self, caCertFilePathList):
254        """For use with HTTPS connections only.  Specify CA certs to one of
255        which the peer cert must verify its signature against"""
256        if self._transport != HTTPSConnection:
257            return
258       
259        if self._transdict.get('postConnectionCheck'):
260            self._transdict['postConnectionCheck'].caCertFilePathList = \
261                                            caCertFilePathList
262        else:
263            self._transdict['postConnectionCheck'] = \
264                            HostCheck(caCertFilePathList=caCertFilePathList)
265
266    sslCACertFilePathList = property(fset=__setSSLCACertFilePathList, 
267                                     doc=\
268"for https connections, set list of CA cert files from which to verify peer cert")
269
270
271    #_________________________________________________________________________
272    def __setSignatureHandler(self, signatureHandler):
273        """Set SignatureHandler object property method - set to None to for no
274        digital signature and verification"""
275        if signatureHandler is not None and \
276           not isinstance(signatureHandler, SignatureHandler):
277            raise AttributeError, \
278    "Signature Handler must be %s type or None for no message security" % \
279        "ndg.security.common.wsSecurity.SignatureHandler"
280                           
281        self.__signatureHandler = signatureHandler
282
283
284    #_________________________________________________________________________
285    def __getSignatureHandler(self):
286        "Get SignatureHandler object property method"
287        return self.__signatureHandler
288   
289    signatureHandler = property(fget=__getSignatureHandler,
290                                fset=__setSignatureHandler,
291                                doc="SignatureHandler object")
292   
293       
294    #_________________________________________________________________________
295    def initService(self, uri=None):
296        """Set the WS client for the Session Manager"""
297        if uri:
298            self.__setURI(uri)
299   
300        # WS-Security Signature handler object is passed to binding
301        try:
302            locator = SessionMgrServiceLocator()
303            self.__srv = locator.getSessionMgr(self.__uri,
304                                         sig_handler=self.__signatureHandler,
305                                         tracefile=self.__tracefile,
306                                         transport=self._transport,
307                                         transdict=self._transdict)
308        except HTTPResponse, e:
309            raise SessionMgrClientError, \
310                "Initialising Service for \"%s\": %s %s" % \
311                (self.__uri, e.status, e.reason)
312   
313       
314    #_________________________________________________________________________   
315    def connect(self,
316                username,
317                passphrase=None,
318                passphraseFilePath=None,
319                createServerSess=True):
320        """Request a new user session from the Session Manager
321       
322        @type username: string
323        @param username: the username of the user to connect
324       
325        @type passphrase: string
326        @param passphrase: user's pass-phrase
327       
328        @type passphraseFilePath: string
329        @param passphraseFilePath: a file containing the user's pass-phrase. 
330        Use this as an alternative to passphrase keyword.
331                                 
332        @type createServerSess: bool
333        @param createServerSess: If set to True, the SessionMgr will create
334        and manage a session for the user.  For non-browser client case, it's
335        possible to choose to have a client or server side session using this
336        keyword.  If set to False sessID returned will be None
337       
338        @rtype: tuple
339        @return user cert, user private key, issuing cert and sessID all as
340        strings but sessID will be None if the createServerSess keyword is
341        False"""
342   
343        if passphrase is None:
344            try:
345                passphrase = open(passphraseFilePath).read().strip()
346           
347            except Exception, e:
348                raise SessionMgrClientError, "Pass-phrase not defined: " + \
349                                             str(e)
350
351        # Make connection
352        res = self.__srv.connect(username, passphrase, createServerSess)
353
354        # Convert from unicode because unicode causes problems with
355        # M2Crypto private key load
356        return tuple([isinstance(i,unicode) and str(i) or i for i in res])
357   
358       
359    #_________________________________________________________________________   
360    def disconnect(self, userCert=None, sessID=None):
361        """Delete an existing user session from the Session Manager
362       
363        disconnect([userCert=c]|[sessID=i])
364       
365        @type userCert: string                 
366        @param userCert: user's certificate used to identifier which session
367        to disconnect.  This arg is not needed if the message is signed with
368        the user cert or if sessID is set. 
369                               
370        @type sessID: string
371        @param sessID: session ID.  Input this as an alternative to userCert
372        This arg is not needed if the message is signed with the user cert or
373        if userCert keyword is."""
374
375        # Make connection
376        self.__srv.disconnect(userCert, sessID)
377   
378       
379    #_________________________________________________________________________   
380    def getSessionStatus(self, userDN=None, sessID=None):
381        """Check for the existence of a session with a given
382        session ID / user certificate Distinguished Name
383       
384        disconnect([sessID=id]|[userDN=dn])
385       
386        @type userCert: string                 
387        @param userCert: user's certificate used to identifier which session
388        to disconnect.  This arg is not needed if the message is signed with
389        the user cert or if sessID is set. 
390                               
391        @type sessID: string
392        @param sessID: session ID.  Input this as an alternative to userCert
393        This arg is not needed if the message is signed with the user cert or
394        if userCert keyword is."""
395       
396        if sessID and userDN:
397            raise SessionMgrClientError, \
398                            'Only "SessID" or "userDN" keywords may be set'
399
400        # Make connection
401        return self.__srv.getSessionStatus(userDN, sessID)
402
403   
404    #_________________________________________________________________________
405    def getAttCert(self,
406                   userCert=None,
407                   sessID=None,
408                   attAuthorityURI=None,
409                   attAuthorityCert=None,
410                   reqRole=None,
411                   mapFromTrustedHosts=True,
412                   rtnExtAttCertList=False,
413                   extAttCertList=[],
414                   extTrustedHostList=[]):   
415        """Request NDG Session Manager Web Service to retrieve an Attribute
416        Certificate from the given Attribute Authority and cache it in the
417        user's credential wallet held by the session manager.
418       
419        ac = getAttCert([sessID=i]|[userCert=p][key=arg, ...])
420         
421        @raise AttributeRequestDenied: this is raised if the request is
422        denied because the user is not registered with the Attribute
423        Authority.  In this case, a list of candidate attribute certificates
424        may be returned which could be used to retry with a request for a
425        mapped AC.  These are assigned to the raised exception's
426        extAttCertList attribute
427             
428        @type userCert: string
429        @param userCert: user certificate - use as ID instead of session
430        ID.  This can be omitted if the message is signed with a user
431        certificate.  In this case the user certificate is passed in the
432        BinarySecurityToken of the WS-Security header
433       
434        @type sessID: string
435        @param sessID: session ID.  Input this as an alternative to
436        userCert in the case of a browser client.
437       
438        @type attAuthorityURI: string
439        @param attAuthorityURI: URI for Attribute Authority WS.
440       
441        @type attAuthorityCert: string
442        @param attAuthorityCert: The Session Manager uses the Public key of
443        the Attribute Authority to encrypt requests to it.
444       
445        @type reqRole: string
446        @param reqRole: The required role for access to a data set.  This
447        can be left out in which case the Attribute Authority just returns
448        whatever Attribute Certificate it has for the user
449       
450        @type mapFromTrustedHosts: bool
451        @param mapFromTrustedHosts: Allow a mapped Attribute Certificate to
452        be created from a user certificate from another trusted host.
453       
454        @type rtnExtAttCertList: bool
455        @param rtnExtAttCertList: Set this flag True so that if the
456        attribute request is denied, a list of potential attribute
457        certificates for mapping may be returned.
458       
459        @type extAttCertList: list
460        @param extAttCertList: A list of Attribute Certificates from other
461        trusted hosts from which the target Attribute Authority can make a
462        mapped certificate
463       
464        @type extTrustedHostList: list
465        @param extTrustedHostList: A list of trusted hosts that can be used
466        to get Attribute Certificates for making a mapped AC.
467       
468        @rtype: ndg.security.common.AttCert.AttCert
469        @return: if successful, an attribute certificate."""
470       
471        # Make request
472        try:
473            attCert, msg, extAttCertList = self.__srv.getAttCert(userCert,
474                                                       sessID, 
475                                                       attAuthorityURI,
476                                                       attAuthorityCert,
477                                                       reqRole,
478                                                       mapFromTrustedHosts,
479                                                       rtnExtAttCertList,
480                                                       extAttCertList,
481                                                       extTrustedHostList)
482        except Exception, e:
483            # Try to detect exception type from SOAP fault message
484            errMsg = str(e)
485            for excep in self.excepMap:
486                if excep in errMsg:
487                    raise self.excepMap[excep]
488       
489            # Catch all in case none of the known types matched
490            raise e
491       
492        if not attCert:
493            raise AttributeRequestDenied(msg, extAttCertList=extAttCertList)
494       
495        return AttCertParse(attCert)
496   
497                                   
498    #_________________________________________________________________________
499    def getX509Cert(self):
500        """Retrieve the public key of the Session Manager"""
501        return self.__srv.getX509Cert()
502                           
Note: See TracBrowser for help on using the repository browser.