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

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

ndg.security.test/ndg/security/test/AttAuthority/siteAMapConfig.xml: altered
in conjunction with integration testing

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

  • fix to setSSLCACertFilePathList call and to body - return if not https

rather than raising an exception. This agrees with AttAuthorityClient?
implementation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/usr/bin/env python
2"""NDG Security client - client interface classes to Session Manager
3
4Make requests for authentication and authorisation
5
6NERC Data Grid Project
7
8P J Kershaw 24/04/06
9
10Copyright (C) 2006 CCLRC & NERC
11
12This software may be distributed under the terms of the Q Public License,
13version 1.0 or later.
14"""
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 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 AttributeRequestDenied(Exception):
40    """Raise when a getAttCert call to the Attribute Authority is denied"""
41
42#_____________________________________________________________________________       
43class SessionMgrClient(object):
44    """Client interface to Session Manager Web Service"""
45   
46    #_________________________________________________________________________
47    def __init__(self, 
48                 uri=None, 
49                 tracefile=None,
50                 sslCACertList=[],
51                 sslCACertFilePathList=[],
52                 sslPeerCertCN=None, 
53                 setSignatureHandler=True,
54                 **signatureHandlerKw):
55        """
56        @type uri: string
57        @keyword uri: URI for Session Manager WS.  Setting it will set the
58        Service Proxy
59               
60        @type tracefile: file stream type
61        @param tracefile: set to file object such as sys.stderr to give extra
62        WS debug information
63       
64        @type sslCACertList: list
65        @keyword sslCACertList: This keyword is for use with SSL connections
66        only.  Set a list of one or more CA certificates.  The peer cert.
67        must verify against at least one of these otherwise the connection
68        is dropped.
69       
70        @type sslCACertFilePathList: list
71        @keyword sslCACertFilePathList: the same as the above except CA certs
72        can be passed as a list of file paths to read from
73       
74        @type sslPeerCertCN: string
75        @keyword sslPeerCertCN: set an alternate CommonName to match with peer
76        cert.  This keyword is for use with SSL connections only.
77       
78        @type setSignatureHandler: bool
79        @param setSignatureHandler: flag to determine whether to apply
80        WS-Security Signature Handler or not
81
82        @type signatureHandlerKw: dict
83        @param signatureHandlerKw: keywords to configure signature handler"""
84
85        self.__srv = None
86        self.__uri = None
87        self._transdict = {}       
88       
89        if uri:
90            self.__setURI(uri)
91
92        if sslPeerCertCN:
93            self.__setSSLPeerCertCN(sslPeerCertCN)
94       
95        if sslCACertList:
96            self.__setSSLCACertList(sslCACertList)
97        elif sslCACertFilePathList:
98            self.__setSSLCACertFilePathList(sslCACertFilePathList)
99
100        # WS-Security Signature handler - set only if any of the keywords were
101        # set
102        if setSignatureHandler:
103            self.__signatureHandler = SignatureHandler(**signatureHandlerKw)
104        else:
105            self.__signatureHandler = None
106       
107        self.__tracefile = tracefile
108
109         
110        # Instantiate Session Manager WS ZSI client
111        if self.__uri:
112            self.initService()
113       
114
115    #_________________________________________________________________________
116    def __setURI(self, uri):
117        """Set URI for service
118        @type uri: string
119        @param uri: URI for service to connect to"""
120       
121        if not isinstance(uri, basestring):
122            raise SessionMgrClientError, \
123                             "Session Manager WSDL URI must be a valid string"
124       
125        self.__uri = uri
126        try:
127            scheme = urlparse.urlparse(self.__uri)[0]
128        except TypeError:
129            raise AttributeAuthorityClientError, \
130                "Error parsing transport type from URI"
131               
132        if scheme == "https":
133            self._transport = HTTPSConnection
134        else:
135            self._transport = None
136           
137            # Ensure SSL settings are cancelled
138            self.__setSSLPeerCertCN(None)
139       
140    uri = property(fset=__setURI, doc="Set Session Manager URI")
141
142
143    #_________________________________________________________________________
144    def __setSSLPeerCertCN(self, cn):
145        """For use with HTTPS connections only.  Specify the Common
146        Name to match with Common Name of the peer certificate.  This is not
147        needed if the peer cert CN = peer hostname"""
148        if self._transport != HTTPSConnection:
149            return
150       
151        if self._transdict.get('postConnectionCheck'):
152            self._transdict['postConnectionCheck'].peerCertCN = cn
153        else:
154            self._transdict['postConnectionCheck'] = HostCheck(peerCertCN=cn)
155
156    sslPeerCertCN = property(fset=__setSSLPeerCertCN, 
157doc="for https connections, set CN of peer cert if other than peer hostname")
158
159
160    #_________________________________________________________________________
161    def __setSSLCACertList(self, caCertList):
162        """For use with HTTPS connections only.  Specify CA certs to one of
163        which the peer cert must verify its signature against"""
164        if self._transport != HTTPSConnection:
165            return
166       
167        if self._transdict.get('postConnectionCheck'):
168            self._transdict['postConnectionCheck'].caCertList = caCertList
169        else:
170            self._transdict['postConnectionCheck'] = \
171                                            HostCheck(caCertList=caCertList)
172
173    sslCACertList = property(fset=__setSSLCACertList, 
174doc="for https connections, set list of CA certs from which to verify peer cert")
175
176
177    #_________________________________________________________________________
178    def __setSSLCACertFilePathList(self, caCertFilePathList):
179        """For use with HTTPS connections only.  Specify CA certs to one of
180        which the peer cert must verify its signature against"""
181        if self._transport != HTTPSConnection:
182            return
183       
184        if self._transdict.get('postConnectionCheck'):
185            self._transdict['postConnectionCheck'].caCertFilePathList = \
186                                            caCertFilePathList
187        else:
188            self._transdict['postConnectionCheck'] = \
189                            HostCheck(caCertFilePathList=caCertFilePathList)
190
191    sslCACertFilePathList = property(fset=__setSSLCACertFilePathList, 
192                                     doc=\
193"for https connections, set list of CA cert files from which to verify peer cert")
194
195
196    #_________________________________________________________________________
197    def __setSignatureHandler(self, signatureHandler):
198        """Set SignatureHandler object property method - set to None to for no
199        digital signature and verification"""
200        if signatureHandler is not None and \
201           not isinstance(signatureHandler, SignatureHandler):
202            raise AttributeError, \
203    "Signature Handler must be %s type or None for no message security" % \
204        "ndg.security.common.wsSecurity.SignatureHandler"
205                           
206        self.__signatureHandler = signatureHandler
207
208
209    #_________________________________________________________________________
210    def __getSignatureHandler(self):
211        "Get SignatureHandler object property method"
212        return self.__signatureHandler
213   
214    signatureHandler = property(fget=__getSignatureHandler,
215                                fset=__setSignatureHandler,
216                                doc="SignatureHandler object")
217   
218       
219    #_________________________________________________________________________
220    def initService(self, uri=None):
221        """Set the WS client for the Session Manager"""
222        if uri:
223            self.__setURI(uri)
224   
225        # WS-Security Signature handler object is passed to binding
226        try:
227            locator = SessionMgrServiceLocator()
228            self.__srv = locator.getSessionMgr(self.__uri,
229                                       sig_handler=self.__signatureHandler,
230                                       tracefile=self.__tracefile,
231                                         transport=self._transport,
232                                         transdict=self._transdict)
233        except HTTPResponse, e:
234            raise SessionMgrClientError, \
235                "Initialising Service for \"%s\": %s %s" % \
236                (self.__uri, e.status, e.reason)
237
238                                   
239    #_________________________________________________________________________
240    def addUser(self,
241                username,
242                passphrase=None,
243                passphraseFilePath=None,
244                clntPriKeyPwd=None):
245        """Register a new user
246       
247        username:                the username for the new user
248        passphrase:                 user's pass-phrase
249        passphraseFilePath:         a file containing the user's pass-phrase. 
250                                 Use this as an alternative to passphrase keyword
251        clntPriKeyPwd:           pass-phrase if any for the client's private
252                                 key used to decrypt response from
253                                 Session Manager
254        """
255   
256        if passphrase is None:
257            try:
258                passphrase = open(passphraseFilePath).read().strip()
259           
260            except Exception, e:
261                raise SessionMgrClientError, "Pass-phrase not defined: " + \
262                                            str(e)
263           
264   
265        # Make request for new user
266        try:   
267            self.__srv.addUser(username, passphrase)
268
269        except Exception, e:
270            raise SessionMgrClientError, "Adding new user: " + str(e)
271   
272       
273    #_________________________________________________________________________   
274    def connect(self,
275                username,
276                passphrase=None,
277                passphraseFilePath=None,
278                createServerSess=True):
279        """Request a new user session from the Session Manager
280       
281        @type username: string
282        @param username: the username of the user to connect
283       
284        @type passphrase: string
285        @keyword passphrase: user's pass-phrase
286       
287        @type passphraseFilePath: string
288        @keyword passphraseFilePath: a file containing the user's pass-phrase. 
289        Use this as an alternative to passphrase keyword.
290                                 
291        @type createServerSess: bool
292        @keyword createServerSess: If set to True, the SessionMgr will create
293        and manage a session for the user.  For non-browser client case, it's
294        possible to choose to have a client or server side session using this
295        keyword.  If set to False sessID returned will be None
296       
297        @rtype: tuple
298        @return proxy cert, proxy private key, user cert and sessID all as
299        strings but sessID will be None if the createServerSess keyword is
300        False"""
301   
302        if passphrase is None:
303            try:
304                passphrase = open(passphraseFilePath).read().strip()
305           
306            except Exception, e:
307                raise SessionMgrClientError, "Pass-phrase not defined: " + \
308                                             str(e)
309
310        # Make connection
311        res = self.__srv.connect(username, passphrase, createServerSess)
312
313        # Convert from unicode because unicode causes problems with
314        # M2Crypto private key load
315        return tuple([isinstance(i,unicode) and str(i) or i for i in res])
316   
317       
318    #_________________________________________________________________________   
319    def disconnect(self, userCert=None, sessID=None):
320        """Delete an existing user session from the Session Manager
321       
322        disconnect([userCert=c]|[sessID=i])
323       
324        @type userCert: string                 
325        @keyword userCert: user's certificate used to identifier which session
326        to disconnect.  This arg is not needed if the message is signed with
327        the user cert or if sessID is set. 
328                               
329        @type sessID: string
330        @keyword sessID: session ID.  Input this as an alternative to userCert
331        This arg is not needed if the message is signed with the user cert or
332        if userCert keyword is."""
333
334        # Make connection
335        self.__srv.disconnect(userCert, sessID)
336   
337   
338    #_________________________________________________________________________
339    def getAttCert(self,
340                   proxyCert=None,
341                   sessID=None,
342                   attAuthorityURI=None,
343                   attAuthorityCert=None,
344                   reqRole=None,
345                   mapFromTrustedHosts=True,
346                   rtnExtAttCertList=False,
347                   extAttCertList=[],
348                   extTrustedHostList=[]):   
349        """Request NDG Session Manager Web Service to retrieve an Attribute
350        Certificate from the given Attribute Authority and cache it in the
351        user's credential wallet held by the session manager.
352       
353        getAttCert([sessID=i]|[proxyCert=p][key=arg, ...])
354                   
355        proxyCert:             proxy certificate - use as ID instead of
356                               session ID.  This can be omitted if the
357                               message is signed with a proxy certificate.
358                               In this case the proxy certificate is passed
359                               in the BinarySecurityToken of the WS-Security
360                               header
361        sessID:                session ID.  Input this as an alternative to
362                               proxyCert in the case of a browser client.
363        attAuthorityURI:       URI for Attribute Authority WS.
364        attAuthorityCert:      The Session Manager uses the Public key of the
365                               Attribute Authority to encrypt requests to it.
366        reqRole:               The required role for access to a data set.
367                               This can be left out in which case the
368                               Attribute Authority just returns whatever
369                               Attribute Certificate it has for the user
370        mapFromTrustedHosts:   Allow a mapped Attribute Certificate to be
371                               created from a user certificate from another
372                               trusted host.
373        rtnExtAttCertList:     Set this flag True so that if authorisation is
374                               denied, a list of potential attribute
375                               certificates for mapping may be returned.
376        extAttCertList:        A list of Attribute Certificates from other
377                               trusted hosts from which the target Attribute
378                               Authority can make a mapped certificate
379        extTrustedHostList:    A list of trusted hosts that can be used to
380                               get Attribute Certificates for making a mapped
381                               AC.
382        """
383       
384        # Make request
385        attCert, msg, extAttCertList = self.__srv.getAttCert(proxyCert,
386                                                       sessID, 
387                                                       attAuthorityURI,
388                                                       attAuthorityCert,
389                                                       reqRole,
390                                                       mapFromTrustedHosts,
391                                                       rtnExtAttCertList,
392                                                       extAttCertList,
393                                                       extTrustedHostList)
394        if not attCert:
395            raise AttributeRequestDenied, msg
396       
397        return attCert, extAttCertList
398   
399                                   
400    #_________________________________________________________________________
401    def getX509Cert(self):
402        """Retrieve the public key of the Session Manager"""
403        return self.__srv.getX509Cert()
404                           
Note: See TracBrowser for help on using the repository browser.