source: TI12-security/trunk/python/NDG/SessionClient.py @ 712

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/NDG/SessionClient.py@712
Revision 712, 17.2 KB checked in by pjkersha, 14 years ago (diff)

ndgSessionClient.py: fixed client private key password file read.

AttAuthority?.py: changed X509Cert.isValidTime() calls to give more error info.

XMLSecDoc.py: metaclass for XMLSec initialisation didn't work - do initialisation in class
init as before.

SessionClient?.py: removed test code - this is kept in a separate file in Tests/.

Session.py: modified SessionMgr?.reqAuthorisation() to create a fresh AuthorisationResp? object
from the return from redirectAuthorisationReq() to avoid confusion with encrypted output
message.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/usr/bin/env python
2
3"""NDG Session client - makes requests for authentication and authorisation
4
5NERC Data Grid Project
6
7P J Kershaw 16/08/05
8
9Copyright (C) 2005 CCLRC & NERC
10
11This software may be distributed under the terms of the Q Public License,
12version 1.0 or later.
13"""
14
15cvsID = '$Id$'
16
17from ZSI import ServiceProxy
18import sys
19import os
20from Cookie import SimpleCookie
21
22from X509 import *
23from SessionMgrIO import *
24
25# Handle retrieval of public key cert for Session Manager at remote location
26import tempfile
27import urllib
28
29#_____________________________________________________________________________
30class SessionClientError(Exception):
31    """Exception handling for SessionClient class"""
32    def __init__(self, msg):
33        self.__msg = msg
34         
35    def __str__(self):
36        return self.__msg
37
38
39#_____________________________________________________________________________       
40class SessionClient(object):
41    """Client interface to Session Manager Web Service"""
42   
43    #_________________________________________________________________________
44    def __init__(self, 
45                 smWSDL=None, 
46                 smPubKeyURI=None,
47                 clntPubKeyFilePath=None,
48                 clntPriKeyFilePath=None,
49                 traceFile=None):
50        """
51        smWSDL:                  WSDL URI for Session Manager WS.  Setting it
52                                 will set the Service Proxy
53        smPubKeyURI:   
54                                 Public key of Session Manager used to encrypt
55                                 the outgoing message if required - set as a
56                                 path on the local file system or as a URI
57        clntPubKeyFilePath:      Public key of client.  This is passed to the
58                                 Session Manager so that it can encrypt
59                                 responses.  WARNING: if not set, responses
60                                 are returned as clear text
61        clntPriKeyFilePath:      Private key of client.  If clntPubKeyFilePath
62                                 is set, the private key is needed to decrypt
63                                 the response from the Session Manager
64        traceFile:               set to file object such as sys.stderr to
65                                 give extra WS debug information"""
66
67        self.__smSrv = None
68        self.__smWSDL = None
69        self.__smPubKeyFilePath = None
70        self.__smPubKeyURI = None
71        self.__clntPubKeyFilePath = None
72        self.__clntPubKey = None
73        self.__clntPriKeyFilePath = None
74       
75        self.__smPubKeyTempFile = None
76       
77       
78        if smWSDL:
79            self.__setSMwsdl(smWSDL)
80           
81        if smPubKeyURI:
82            self.__setSMpubKeyURI(smPubKeyURI)
83           
84        if clntPriKeyFilePath:
85            self.__setClntPriKeyFilePath(clntPriKeyFilePath)
86           
87        if clntPubKeyFilePath:
88            if clntPriKeyFilePath is None:
89                raise SessionClientError(\
90                    "A Client private key file is required as well a " + \
91                    "public key")
92                   
93            self.__setClntPubKeyFilePath(clntPubKeyFilePath)
94
95           
96        self.__traceFile = traceFile
97
98         
99        # Instantiate Session Manager WS proxy
100        if self.__smWSDL:
101            self.serviceProxy()
102       
103
104    #_________________________________________________________________________
105    def __setSMwsdl(self, smWSDL):
106       
107        if not isinstance(smWSDL, basestring):
108            raise SessionClientError(\
109                            "Session Manager WSDL URI must be a valid string")
110       
111        self.__smWSDL = smWSDL
112       
113    smWSDL = property(fset=__setSMwsdl, doc="Set Session Manager WSDL URI")
114
115
116    #_________________________________________________________________________
117    def __setSMpubKeyURI(self, smPubKeyURI):
118       
119        if not isinstance(smPubKeyURI, basestring):
120            raise SessionClientError(\
121                "Session Manager public key URI must be a valid string")
122       
123        self.__smPubKeyURI = smPubKeyURI
124        self.__smPubKeyFilePath = None
125       
126    smPubKeyURI = property(fset=__setSMpubKeyURI,
127                           doc="Set Session Manager public key URI")
128
129 
130    #_________________________________________________________________________
131    def __setClntPubKeyFilePath(self, clntPubKeyFilePath):
132       
133        if not isinstance(clntPubKeyFilePath, basestring):
134            raise SessionClientError(\
135                "Client public key file path must be a valid string")
136       
137        self.__clntPubKeyFilePath = clntPubKeyFilePath
138        try:
139            self.__clntPubKey = open(self.__clntPubKeyFilePath).read()
140           
141        except IOError, (errNo, errMsg):
142            raise optparse.OptionValueError(\
143                    "Reading certificate file \"%s\": %s" % (value, errMsg))
144                               
145        except Exception, e:
146            raise optparse.OptionValueError(\
147                    "Reading certificate file \"%s\": %s" % (value, str(e)))
148       
149    clntPubKeyFilePath = property(fset=__setClntPubKeyFilePath,
150                                  doc="File path for client public key")
151
152 
153    #_________________________________________________________________________
154    def __setClntPriKeyFilePath(self, clntPriKeyFilePath):
155       
156        if not isinstance(clntPriKeyFilePath, basestring):
157            raise SessionClientError(\
158                "Client public key file path must be a valid string")
159       
160        self.__clntPriKeyFilePath = clntPriKeyFilePath
161       
162    clntPriKeyFilePath = property(fset=__setClntPriKeyFilePath,
163                                  doc="File path for client private key")
164
165
166    #_________________________________________________________________________
167    def __convSMpubKeyURI2File(self):
168        """Retrieve the public key from the URI"""
169       
170        # Don't proceed unless URI was set - user may have set public key via
171        # smPubKeyFilePath instead
172        if self.__smPubKeyURI is None:
173            return
174       
175        # If no http prefix, assume a local file
176        if self.__smPubKeyURI[:5] != "http:":
177            self.__smPubKeyFilePath = self.__smPubKeyURI
178            return
179       
180        try:
181            self.__smPubKeyTempFile = tempfile.NamedTemporaryFile()
182           
183            (self.__smPubKeyFilePath, httpResp) = \
184                            urllib.urlretrieve(self.__smPubKeyURI,
185                                               self.__smPubKeyTempFile.name)
186                                         
187        except Exception, e:
188            raise SessionClientError("Error retrieving Session Manager "+\
189                                     "public key from \"%s\": %s" % \
190                                     (self.__smPubKeyURI, str(e)))
191
192        # Expecting plain text format for returned public key file
193        # 404 error would come back as 'text/html'
194        if 'text/plain' not in httpResp['Content-type']:
195            raise SessionClientError("Error retrieving Session Manager "+\
196                "public key from \"%s\": expecting \"plain/text\"" % \
197                self.__smPubKeyURI)
198   
199       
200    #_________________________________________________________________________
201    def serviceProxy(self, smWSDL=None):
202        """Set the WS proxy for the Session Manager"""
203        if smWSDL:
204            self.__setSMwsdl(smWSDL)
205
206        try:
207            self.__smSrv = ServiceProxy(self.__smWSDL, 
208                                        use_wsdl=True, 
209                                        tracefile=self.__traceFile)
210        except Exception, e:
211            raise SessionClientError("Initialising WSDL Service Proxy: " + \
212                                     str(e))
213
214                                   
215    #_________________________________________________________________________
216    def addUser(self,
217                userName,
218                pPhrase=None,
219                pPhraseFilePath=None,
220                clntPriKeyPwd=None):
221        """Register a new user
222       
223        userName:                the username for the new user
224        pPhrase:                 user's pass-phrase
225        pPhraseFilePath:         a file containing the user's pass-phrase. 
226                                 Use this as an alternative to pPhrase keyword
227        clntPriKeyPwd:           pass-phrase if any for the client's private
228                                 key used to decrypt response from
229                                 Session Manager
230        """
231   
232        if pPhrase is None:
233            try:
234                pPhrase = open(pPhraseFilePath).read().strip()
235           
236            except Exception, e:
237                raise SessionClientError("Pass-phrase not defined: " + str(e))
238
239
240        # If Public key was set by URI, retrieve to local temp file
241        self.__convSMpubKeyURI2File()
242           
243   
244        # Make request for new user
245        try:   
246            addUserReq = AddUserReq(userName=userName, 
247                                pPhrase=pPhrase,
248                                encrCert=self.__clntPubKey,
249                                encrPubKeyFilePath=self.__smPubKeyFilePath) 
250
251            # Pass encrypted request
252            resp = self.__smSrv.addUser(addUserReq=addUserReq())
253                       
254            addUserResp = AddUserResp(xmlTxt=resp['addUserResp'],
255                                encrPriKeyFilePath=self.__clntPriKeyFilePath,
256                                encrPriKeyPwd=clntPriKeyPwd)
257                           
258            if 'errMsg' in addUserResp and addUserResp['errMsg']:
259                raise SessionClientError(addUserResp['errMsg'])
260           
261        except Exception, e:
262            raise SessionClientError("Error adding new user: " + str(e))
263   
264       
265    #_________________________________________________________________________   
266    def connect(self,
267                userName,
268                pPhrase=None,
269                pPhraseFilePath=None,
270                getCookie=True,
271                createServerSess=False,
272                clntPriKeyPwd=None):
273        """Request a new user session from the Session Manager
274       
275        userName:                the username of the user to connect
276        pPhrase:                 user's pass-phrase
277        pPhraseFilePath:         a file containing the user's pass-phrase. 
278                                 Use this as an alternative to pPhrase
279                                 keyword.
280                                 
281        getCookie:               If set to true, return a cookie to be set in
282                                 a web browser client.  Otherwise, return a
283                                 proxy certificate.
284                                 
285        createServerSess:        If set to True, the SessionMgr will create
286                                 and manage a session for the user but note,
287                                 this flag is ignored and set to True if
288                                 getCookie is set. 
289                                 
290                                 For command line case, where getCookie is
291                                 False, it's possible to choose to have a
292                                 client or server side session using this
293                                 keyword.
294        clntPriKeyPwd:           pass-phrase if any for the client's private
295                                 key used to decrypt response from
296                                 Session Manager."""
297   
298        if pPhrase is None:
299            try:
300                pPhrase = open(pPhraseFilePath).read().strip()
301           
302            except Exception, e:
303                raise SessionClientError("Pass-phrase not defined: " + str(e))
304
305
306        # If Public key was set by URI, retrieve otherwise get from
307        # smPubKeyFilePath
308        self.__convSMpubKeyURI2File()
309
310       
311        # Make connection
312        try: 
313            connectReq = ConnectReq(userName=userName, 
314                                pPhrase=pPhrase,
315                                getCookie=getCookie,
316                                createServerSess=createServerSess,
317                                encrCert=self.__clntPubKey,
318                                encrPubKeyFilePath=self.__smPubKeyFilePath) 
319   
320            # Pass encrypted request
321            resp = self.__smSrv.connect(connectReq=connectReq())
322           
323            connectResp = ConnectResp(xmlTxt=resp['connectResp'],
324                                encrPriKeyFilePath=self.__clntPriKeyFilePath,
325                                encrPriKeyPwd=clntPriKeyPwd)
326                           
327            if 'errMsg' in connectResp and connectResp['errMsg']:
328                raise Exception(connectResp['errMsg'])
329           
330            if 'sessCookie' in connectResp:
331                return connectResp['sessCookie']
332           
333            elif 'proxyCert' in connectResp:
334                return connectResp['proxyCert']
335           
336            else:
337               raise SessionClientError(\
338               "Neither \"sessCookie\" or \"proxyCert\" found in response")
339               
340        except Exception, e:
341            raise SessionClientError(\
342                            "Error connecting to Session Manager: " + str(e))
343   
344   
345    #_________________________________________________________________________
346    def reqAuthorisation(self,
347                         sessCookie=None,
348                         proxyCert=None,
349                         aaWSDL=None,
350                         reqRole=None,
351                         mapFromTrustedHosts=False,
352                         rtnExtAttCertList=False,
353                         extAttCertList=None,
354                         extTrustedHostList=None,
355                         clntPriKeyPwd=None):   
356        """Request authorisation from NDG Session Manager Web Service.
357       
358        sessCookie:            session cookie returned from call to connect()
359                               for a browser client.  Input as a string or
360                               SimpleCookie type.
361        proxyCert:             proxy certificate - use as ID instead of
362                               a cookie in the case of a command line client.
363        aaWSDL:                WSDL URI for Attribute Authority WS.
364        reqRole:               The required role for access to a data set.
365                               This can be left out in which case the
366                               Attribute Authority just returns whatever
367                               Attribute Certificate it has for the user
368        mapFromTrustedHosts:   Allow a mapped Attribute Certificate to be
369                               created from a user certificate from another
370                               trusted host.
371        rtnExtAttCertList:     Set this flag True so that if authorisation is
372                               denied, a list of potential attribute
373                               certificates for mapping may be returned.
374        extAttCertList:        A list of Attribute Certificates from other
375                               trusted hosts from which the target Attribute
376                               Authority can make a mapped certificate
377        extTrustedHostList:    A list of trusted hosts that can be used to
378                               get Attribute Certificates for making a mapped
379                               AC.
380        clntPriKeyPwd:         pass-phrase if any for the client's private
381                               key used to decrypt response from
382                               Session Manager.
383        """
384
385        if sessCookie and isinstance(sessCookie, basestring):
386            try:
387                sessCookie = SimpleCookie(sessCookie)
388            except Exception, e:
389                raise SessionClientError("Error parsing session cookie: " + \
390                                         str(e))
391
392
393        # If Public key was set by URI, retrieve otherwise get from
394        # smPubKeyFilePath
395        self.__convSMpubKeyURI2File()
396
397           
398        # Make authorisation request
399        try:
400            authReq = AuthorisationReq(aaWSDL=aaWSDL,
401                             sessID=sessCookie['NDG-ID1'].value, 
402                             encrSessMgrWSDLuri=sessCookie['NDG-ID2'].value,
403                             encrSessMgrPubKeyURI=sessCookie['NDG-ID3'].value,
404                             proxyCert=proxyCert,
405                             reqRole=reqRole,
406                             mapFromTrustedHosts=mapFromTrustedHosts,
407                             rtnExtAttCertList=rtnExtAttCertList,
408                             extAttCertList=extAttCertList,
409                             extTrustedHostList=extTrustedHostList,
410                             encrCert=self.__clntPubKey,
411                             encrPubKeyFilePath=self.__smPubKeyFilePath) 
412                                           
413            resp = self.__smSrv.reqAuthorisation(authorisationReq=authReq())
414           
415            authResp = AuthorisationResp(xmlTxt=resp['authorisationResp'],
416                                encrPriKeyFilePath=self.__clntPriKeyFilePath,
417                                encrPriKeyPwd=clntPriKeyPwd)
418            return authResp
419           
420        except Exception, e:
421            raise SessionClientError(\
422                                "Error in authorisation request: " + str(e))
Note: See TracBrowser for help on using the repository browser.