source: TI12-security/trunk/python/ndg.security.client/ndg/security/client/ndgSessionClient.py @ 4680

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.client/ndg/security/client/ndgSessionClient.py@4680
Revision 4680, 14.9 KB checked in by pjkersha, 11 years ago (diff)

Global replace to fix copyright from STFC & NERC to STFC alone because it's not possible to have copyright held by two orgs.

  • Property svn:executable set to *
  • Property svn:keywords set to Id
Line 
1#!/usr/bin/env python
2
3"""NDG Session client script - makes requests for authentication and
4authorisation
5
6NERC Data Grid Project
7
8This software may be distributed under the terms of the Q Public License,
9version 1.0 or later.
10"""
11__author__ = "P J Kershaw"
12__date__ = "08/03/06"
13__copyright__ = "(C) 2007 STFC"
14__license__ = \
15"""This software may be distributed under the terms of the Q Public
16License, version 1.0 or later."""
17__contact__ = "Philip.Kershaw@stfc.ac.uk"
18__revision__ = "$Id$"
19
20# Command line processing
21import sys
22import os
23import optparse
24import re
25import getpass
26
27from Cookie import SimpleCookie
28
29from ndg.security.client.SecurityClient import *
30
31
32#_____________________________________________________________________________
33def setSoapDebug(option, optStr, value, parser):
34    """Parser Callback function for enabling SOAP debug output"""
35    parser.values.soapDebug = sys.stderr
36
37   
38#_____________________________________________________________________________
39def setSessCookie(option, optStr, value, parser):
40    """Parser Callback function for reading session cookie from command line
41    """
42    try:
43        parser.values.sessCookie = SimpleCookie(open(value).read().strip())
44       
45    except IOError, (errNo, errMsg):
46        raise optparse.OptionValueError(\
47                    "Reading cookie from file \"%s\": %s" % (value, errMsg))
48                           
49    except Exception, e:
50        raise optparse.OptionValueError(\
51                    "Reading cookie from file \"%s\": %s" % (value, str(e)))
52
53
54#_____________________________________________________________________________
55def setSessCookieFromStdin(option, optStr, value, parser):
56    """Parser Callback function for reading cookie from stdin"""
57    try:
58        # Read from standard input
59        parser.values.sessCookie = SimpleCookie(sys.stdin.read().strip())
60
61    except KeyboardInterrupt:
62        raise optparse.OptionValueError(\
63                    "option \"%s\": expecting cookie set from stdin" % optStr)
64         
65    except Exception, e:
66        raise optparse.OptionValueError(\
67                    "option %s: Reading cookie from file \"%s\": %s" % \
68                    (optStr, value, str(e)))
69                   
70
71#_____________________________________________________________________________
72def setClntPriKeyPwd(option, optStr, value, parser):
73    """Parser Callback function for reading client private key password"""
74
75    try:
76        parser.values.clntPriKeyPwd = open(value).read().strip()
77       
78    except IOError, (errNo, errMsg):
79        raise optparse.OptionValueError(\
80                    "Reading password from file \"%s\": %s" % (value, errMsg))
81                           
82    except Exception, e:
83        raise optparse.OptionValueError(\
84                    "Reading password from file \"%s\": %s" % (value, str(e)))
85       
86
87#_____________________________________________________________________________
88def setAAcert(option, optStr, value, parser):
89    """Parser callback function for reading Attribute Authority Public key"""
90   
91    try:
92        parser.values.aaCert = open(value).read().strip()
93       
94    except IOError, (errNo, errMsg):
95        raise optparse.OptionValueError(\
96                "Reading Attribute Authority Public key file \"%s\": %s" % \
97                (value, errMsg))
98                           
99    except Exception, e:
100        raise optparse.OptionValueError(\
101                "Reading Attribute Authority Public key file \"%s\": %s" % \
102                (value, str(e)))
103               
104                     
105#_____________________________________________________________________________
106def main():
107
108    usage = os.path.basename(sys.argv[0]) + " [--add-user=<username> ...]|"+\
109            "[--connect=<username> ...]|[--req-attr ...]|" + \
110            "[--connect=<username> ... --req-attr ...]"
111           
112    parser = optparse.OptionParser(usage=usage)
113    parser.add_option("-n", 
114                      "--add-user", 
115                      dest="newUserName",
116                      help="add a new user, see also: -p and -s options")
117
118    parser.add_option("-c", 
119                      "--connect",
120                      dest="userName",
121                      help="""login in to a Session Manager with username.""")
122   
123    parser.add_option("-r", 
124                      "--req-attr", 
125                      dest="attAuthorityURI", 
126                      help=\
127"""Get a Session Manager to request authorisation from an Attribute Authority
128with the given address.""")
129   
130    parser.add_option("-a", 
131                      "--att-authority-pubkey-file",
132                      action="callback",
133                      callback=setAAcert,
134                      dest="aaCert",
135                      type="string", 
136                      help=\
137"""File Path of Public key of Attribute Authority used by the Session Manager
138to encrypt requests to it.  WARNING: If this is not set, requests will be sent
139in clear text.""")
140
141    parser.add_option("-x",
142                      "--clnt-pubkey-file",
143                      dest="clntCertFilePath",
144                      help=\
145"""X.509 Certificate of client.  This is used by the Session Manager to
146encrypt responses.  WARNING: If this is not set, the response will be sent
147back in clear text""")
148
149    parser.add_option("-k",
150                      "--clnt-prikey-file",
151                      dest="clntPriKeyFilePath",
152                      help=\
153"""Private key file of client.  This is used by the client to decrypt
154responses.  This must be set if -x/--clnt-pubkey-file is set.""")
155
156    parser.add_option("-w",
157                      "--clnt-prikey-pwd-file",
158                      dest="clntPriKeyPwd",
159                      action="callback",
160                      callback=setClntPriKeyPwd,
161                      type="string",
162                      help=\
163"""Pass a file containing the password for the client private key.  If not
164set, it is prompted for from tty.""")
165
166    parser.add_option("-y",
167                      "--session-mgr-pubkey-file",
168                      dest="smCertFilePath",
169                      help=\
170"""X.509 Certificate of Session Manager.  This is used to encrypt the request
171to the Session Manager.  WARNING: if this is not set, the request will be sent
172in clear text""")
173
174    parser.add_option("-s",
175                      "--session-mgr-uri",
176                      dest="sessMgrURI",
177                      help="Address of Session Manager to connect to")
178
179    parser.add_option("-d",
180                      "--soap-debug",
181                      dest="soapDebug",
182                      action="callback",
183                      callback=setSoapDebug,
184                      help="Print SOAP message output")
185
186    parser.add_option("-p",
187                      "--pass-phrase-from-stdin",
188                      action="store_true",
189                      dest="bPassPhraseFromStdin",
190                      default=False,
191                      help="""\
192Take user's pass-phrase from stdin.  If this flag is omitted, pass-phrase is
193prompted for from tty""")
194
195    parser.add_option("-i",
196                      "--cookie-file",
197                      action="callback",
198                      callback=setSessCookie,
199                      type="string",
200                      dest="sessCookie",
201                      help=\
202"""Session cookie for --req-attr/-r call.  This is returned from a previous
203connect call (-c USERNAME/--connect=USERNAME).  Note that connect and request
204authoirsation calls can be combined.  In this case, this arg is not needed as
205the cookie is passed directly from the connect call output to the
206authorisation request e.g. ... -c username -r -s "http://..." -a
207"http://...""")
208
209    parser.add_option("-e",
210                      "--cookie-from-stdin",
211                      action="callback",
212                      callback=setSessCookieFromStdin,
213                      dest="sessCookie",
214                      help="Read session cookie from stdin.")
215
216    parser.add_option("-m",
217                      "--map-from-trusted-hosts",
218                      action="store_true",
219                      dest="mapFromTrustedHosts",
220                      default=False,
221                      help=\
222"""For use with --req-attr/-r flag.  Set to allow the Session Manager to
223automatically use Attribute Certificates from the user's wallet or, if no
224suitable ones are found, to contact other trusted hosts in order to get
225Attribute Certificates for mapping""")
226
227    parser.add_option("-q",
228                      "--req-role",
229                      dest="reqRole",
230                      help="""\
231For use with --req-attr/-r flag.  Making certifcate mapping more efficient
232by specifying to the Session Manager what role is needed for attribute
233certificates from trusted hosts in order to get a mapped Attribute Certificate
234back from the Attribute Authority""")
235
236    parser.add_option("-l",
237                      "--rtn-ext-att-cert-list",
238                      action="store_true",
239                      dest="rtnExtAttCertList",
240                      default=False,
241                      help=\
242"""For use with --req-attr/-r flag.  Determines behaviour in the case where
243authorisation is denied by an Attribute Authority.  If set, a list of
244candidate Attribute Certificates from trusted hosts will be returned.  Any one
245of these could be re-input in a subsequent authorisation request by setting
246the --ext-att-cert-list-file option.  The certificates can be used to obtain a
247mapped Attribute Certificate from the import target Attribute Authority""")
248
249    parser.add_option("-f",
250                      "--ext-att-cert-list-file",
251                      dest="extAttCertListFile",
252                      help=\
253"""For use with --req-attr/-r flag.  A file of concatenated Attribute
254Certificates.  These are certificates from other import hosts trusted by the
255Attribute Authority.  The Session Manager tries each in turn until the
256Attribute Authority accepts one and uses it to create and return a mapped
257Attribute Certificate""")
258   
259    parser.add_option("-t",
260                      "--ext-trusted-hosts-file",
261                      dest="extTrustedHostsFile",
262                      help=\
263"""For use with --req-attr/-r flag.  Pass a file containing a comma
264separarated list of hosts that are trusted by the Attribute Authority.  The
265Session Manager will contact these hosts in turn, stopping when one of them
266grants it an Attribute Certificate that it can present to the target Attribute
267Authority in order to get a mapped Attribute Certificate in return.""")
268
269    (options, args) = parser.parse_args()
270
271    if not options.sessMgrURI:       
272        sys.stderr.write("Error, No Session Manager WSDL URI set.\n\n")
273        parser.print_help()
274        return(1)
275       
276    passPhrase = None
277   
278    # For connect/addUser a pass-phrase is needed
279    if options.newUserName or options.userName:
280       
281        if options.bPassPhraseFromStdin:
282            # Read from standard input
283            passPhrase = sys.stdin.read().strip()           
284        else:
285            # Obtain from prompt
286            try:
287                passPhrase = getpass.getpass(prompt="Login pass-phrase: ") 
288            except KeyboardInterrupt:
289                return(1)
290
291    if options.clntPriKeyPwd is None and options.clntPriKeyFilePath:
292        # Obtain from prompt
293        try:
294            options.clntPriKeyPwd = getpass.getpass(\
295                                    prompt="Client private key pass-phrase: ") 
296        except KeyboardInterrupt:
297            return(1)
298
299                 
300    extAttCertList = None
301               
302    if options.extAttCertListFile:
303        try:
304            # Open and read file removing any <?xml ... ?> headers
305            sExtAttCertListFile = open(options.extAttCertListFile).read()
306            sAttCertTmp = re.sub("\s*<\?xml.*\?>\s*", "", sExtAttCertListFile)
307           
308            # Convert into a list
309            extAttCertList = ['<attributeCertificate>' + ac for ac in \
310                            sAttCertTmp.split('<attributeCertificate>')[1:]]
311        except Exception, e:
312            sys.stderr.write(\
313                "Error parsing file \%s\" for option \"%s\": %s" % \
314                (arg, "--ext-att-cert-list-file\"/\"-f", str(e)))
315
316       
317    extTrustedHostList = None
318
319    if options.extTrustedHostsFile:
320        try:
321            extTrustedHostList = \
322                re.split("\s*,\s*", open(options.extTrustedHostsFile).read())
323           
324        except Exception, e:
325            sys.stderr.write(\
326                "Error parsing file \%s\" for option \"%s\": %s" % \
327                (arg, "--ext-trusted-host-file\"/\"-t", str(e)))
328
329
330    # Initialise session client
331    try:
332        sessClnt = SessionManagerClient(smWSDL=options.sessMgrURI,
333                             smCertFilePath=options.smCertFilePath,
334                             clntCertFilePath=options.clntCertFilePath,
335                             clntPriKeyFilePath=options.clntPriKeyFilePath,
336                             tracefile=options.soapDebug)
337    except Exception, e:
338        sys.stderr.write("Initialising client: %s\n" % str(e))
339        return(1)
340   
341    methodCall = False   
342    try:
343        if options.newUserName:
344            methodCall = True
345           
346            sessClnt.addUser(userName=options.newUserName, 
347                             pPhrase=passPhrase,
348                             clntPriKeyPwd=options.clntPriKeyPwd)
349            return(0)
350                           
351        if options.userName:
352            methodCall = True
353           
354            sSessCookie = sessClnt.connect(userName=options.userName, 
355                                       pPhrase=passPhrase,
356                                       clntPriKeyPwd=options.clntPriKeyPwd)           
357            print sSessCookie
358            # Don't exit here - req-autho may have been set too
359           
360        if options.attAuthorityURI:
361            methodCall = True
362
363            if options.userName:
364                # Connect was set also - parse cookie in order to session ID
365                # and WSDL address
366                options.sessCookie = SimpleCookie(sSessCookie)
367               
368            authResp = sessClnt.reqAuthorisation(\
369                            sessCookie=options.sessCookie,
370                            aaWSDL=options.attAuthorityURI,
371                            aaCert=options.aaCert,
372                            mapFromTrustedHosts=options.mapFromTrustedHosts,
373                            reqRole=options.reqRole,
374                            rtnExtAttCertList=options.rtnExtAttCertList,
375                            extAttCertList=extAttCertList,
376                            extTrustedHostList=extTrustedHostList,
377                            clntPriKeyPwd=options.clntPriKeyPwd)
378            print authResp
379       
380        if not methodCall:   
381            sys.stderr.write("Set a flag to specify the web-service call " + \
382                             "e.g. --connect=USERNAME\n\n")
383            parser.print_help()
384            return(1)
385           
386    except Exception, e:
387        sys.stderr.write(str(e) + os.linesep)
388     
389    return(0)
Note: See TracBrowser for help on using the repository browser.