source: TI12-security/trunk/python/Tests/MyProxyClient/myProxyClient.py @ 1544

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/Tests/MyProxyClient/myProxyClient.py@1544
Revision 1544, 10.8 KB checked in by pjkersha, 14 years ago (diff)

Tests/MyProxyClient?/myProxyClient.py: pyOpenSSL MyProxy? client adapted from original by
Tom Uram <turam@…>

Tests/MyProxyClient?/m2CryptoMyPxClnt.py: M2Crypto equivalent of the above. Logon works, store still to do.

  • Property svn:executable set to *
Line 
1#!/bin/env python
2#
3# myproxy client
4#
5# Tom Uram <turam@mcs.anl.gov>
6# 2005/08/04
7#
8
9
10import os
11import socket
12from OpenSSL import crypto, SSL
13import re
14
15class GetException(Exception): pass
16class RetrieveProxyException(Exception): pass
17class StoreCredException(Exception): pass
18
19
20debug = 0
21def debuglevel(level):
22    global debug
23    return debug >= level
24
25
26def create_cert_req(keyType = crypto.TYPE_RSA,
27                    bits = 1024,
28                    messageDigest = "md5"):
29    """
30    Create certificate request.
31   
32    Returns: certificate request PEM text, private key PEM text
33    """
34                   
35    # Create certificate request
36    req = crypto.X509Req()
37
38    # Generate private key
39    pkey = crypto.PKey()
40    pkey.generate_key(keyType, bits)
41
42    req.set_pubkey(pkey)
43    req.sign(pkey, messageDigest)
44   
45    return (crypto.dump_certificate_request(crypto.FILETYPE_ASN1,req),
46           crypto.dump_privatekey(crypto.FILETYPE_PEM,pkey))
47   
48def deserialize_response(msg):
49    """
50    Deserialize a MyProxy server response
51   
52    Returns: integer response, errortext (if any)
53    """
54   
55    lines = msg.split('\n')
56   
57    # get response value
58    responselines = filter( lambda x: x.startswith('RESPONSE'), lines)
59    responseline = responselines[0]
60    response = int(responseline.split('=')[1])
61   
62    # get error text
63    errortext = ""
64    errorlines = filter( lambda x: x.startswith('ERROR'), lines)
65    for e in errorlines:
66        etext = e.split('=')[1]
67        errortext += etext
68   
69    return response,errortext
70 
71               
72def deserialize_certs(inp_dat):
73   
74    pem_certs = []
75   
76    dat = inp_dat
77   
78    import base64
79    while dat:
80
81        # find start of cert, get length       
82        ind = dat.find('\x30\x82')
83        if ind < 0:
84            break
85           
86        len = 256*ord(dat[ind+2]) + ord(dat[ind+3])
87
88        # extract der-format cert, and convert to pem
89        c = dat[ind:ind+len+4]
90        x509 = crypto.load_certificate(crypto.FILETYPE_ASN1,c)
91        pem_cert = crypto.dump_certificate(crypto.FILETYPE_PEM,x509)
92        pem_certs.append(pem_cert)
93
94        # trim cert from data
95        dat = dat[ind + len + 4:]
96   
97
98    return pem_certs
99
100
101CMD_GET="""VERSION=MYPROXYv2
102COMMAND=0
103USERNAME=%s
104PASSPHRASE=%s
105LIFETIME=%d\0"""
106
107CMD_STORE="""VERSION=MYPROXYv2
108COMMAND=5
109USERNAME=%s
110PASSPHRASE=
111LIFETIME=%d\0"""
112
113
114def myProxyStore(hostname, 
115                 username, 
116                 certFile,
117                 keyFile,
118                 lifetime=43200,
119                 port=7512):
120    """
121    Function to store credentials in a MyProxy server
122   
123    Exceptions:  GetException, StoreCredException
124    """
125    import pdb; pdb.set_trace()
126    context = SSL.Context(SSL.SSLv3_METHOD)
127   
128    # disable for compatibility with myproxy server (er, globus)
129    # globus doesn't handle this case, apparently, and instead
130    # chokes in proxy delegation code
131    context.set_options(0x00000800L)
132   
133    # connect to myproxy server
134    if debuglevel(1):   
135        print "debug: connect to myproxy server"
136       
137    conn = SSL.Connection(context, socket.socket())
138    conn.connect((hostname, port))
139   
140    # send globus compatibility stuff
141    if debuglevel(1):   
142        print "debug: send globus compat byte"
143    conn.write('0')
144
145    # send store command
146    if debuglevel(1): 
147        print "debug: send store command"
148       
149    cmd_store = CMD_STORE % (username, lifetime)
150    conn.write(cmd_store)
151
152    # process server response
153    if debuglevel(1):   
154        print "debug: get server response for store command request"
155       
156    dat = conn.recv(8192)
157    if debuglevel(1):   
158        print dat
159       
160    response, errortext = deserialize_response(dat)
161    if response:
162        raise GetException, errortext
163    else:
164        if debuglevel(1):   
165            print "debug: server response ok"
166   
167    # Send certificate and private key
168    pat = re.compile(\
169         '-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----', 
170         re.S)
171   
172    certTxt = pat.findall(open(certFile).read())[0]
173    keyTxt = open(keyFile).read()
174   
175    conn.send("%s\n%s" % (certTxt, keyTxt))
176
177
178    # process server response
179    if debuglevel(1):   
180        print "debug: get server response for store command completed"
181    resp = conn.recv(8192)
182    response, errortext = deserialize_response(resp)
183    if response:
184        raise RetrieveProxyException, errortext
185    else:
186        if debuglevel(1):
187            print "debug: server response ok"
188   
189   
190def myProxyLogon(hostname,
191                 username,
192                 passphrase,
193                 outfile,
194                 lifetime=43200,
195                 port=7512):
196    """
197    Function to retrieve a proxy credential from a MyProxy server
198   
199    Exceptions:  GetException, RetrieveProxyException
200    """
201   
202    context = SSL.Context(SSL.SSLv3_METHOD)
203   
204    # disable for compatibility with myproxy server (er, globus)
205    # globus doesn't handle this case, apparently, and instead
206    # chokes in proxy delegation code
207    context.set_options(0x00000800L)
208   
209    # connect to myproxy server
210    if debuglevel(1):   print "debug: connect to myproxy server"
211    conn = SSL.Connection(context,socket.socket())
212    conn.connect((hostname,port))
213   
214    # send globus compatibility stuff
215    if debuglevel(1):   print "debug: send globus compat byte"
216    conn.write('0')
217
218    # send get command
219    if debuglevel(1):   print "debug: send get command"
220    cmd_get = CMD_GET % (username,passphrase,lifetime)
221    conn.write(cmd_get)
222
223    # process server response
224    if debuglevel(1):   print "debug: get server response"
225    dat = conn.recv(8192)
226    if debuglevel(1):   print dat
227    response,errortext = deserialize_response(dat)
228    if response:
229        raise GetException(errortext)
230    else:
231        if debuglevel(1):   print "debug: server response ok"
232   
233    # generate and send certificate request
234    # - The client will generate a public/private key pair and send a
235    #   NULL-terminated PKCS#10 certificate request to the server.
236    if debuglevel(1):   print "debug: send cert request"
237    certreq,privatekey = create_cert_req()
238    conn.send(certreq)
239
240    # process certificates
241    # - 1 byte , number of certs
242    dat = conn.recv(1)
243    numcerts = ord(dat[0])
244   
245    # - n certs
246    if debuglevel(1):   print "debug: receive certs"
247    dat = conn.recv(8192)
248    if debuglevel(2):
249        print "debug: dumping cert data to myproxy.dump"
250        f = file('myproxy.dump','w')
251        f.write(dat)
252        f.close()
253
254    # process server response
255    if debuglevel(1):   print "debug: get server response"
256    resp = conn.recv(8192)
257    response,errortext = deserialize_response(resp)
258    if response:
259        raise RetrieveProxyException(errortext)
260    else:
261        if debuglevel(1):   print "debug: server response ok"
262
263    # deserialize certs from received cert data
264    pem_certs = deserialize_certs(dat)
265    if len(pem_certs) != numcerts:
266        print "Warning: %d certs expected, %d received" % (numcerts,len(pem_certs))
267
268    # write certs and private key to file
269    # - proxy cert
270    # - private key
271    # - rest of cert chain
272    if debuglevel(1):   print "debug: write proxy and certs to",outfile
273    f = file(outfile,'w')
274    f.write(pem_certs[0])
275    f.write(privatekey)
276    for c in pem_certs[1:]:
277        f.write(c)
278    f.close()
279   
280       
281if __name__ == '__main__':
282    import sys
283    import optparse
284    import getpass
285   
286    parser = optparse.OptionParser()
287    parser.add_option("-g", 
288                      "--get-delegation", 
289                      dest="getDelegation", 
290                      default=False,
291                      action="store_true",
292                      help="Get delegation / logon")
293   
294    parser.add_option("-c", "--store-cert", dest="certFile", default=None,
295                       help="Certificate to be stored")
296   
297    parser.add_option("-k", "--store-key", dest="keyFile", default=None,
298                       help="Private key to be stored")
299
300    parser.add_option("-s", "--pshost", dest="host", 
301                       help="The hostname of the MyProxy server to contact")
302    parser.add_option("-p", "--psport", dest="port", default=7512,
303                       help="The port of the MyProxy server to contact")
304    parser.add_option("-l", "--username", dest="username", 
305                       help="The username with which the credential is stored on the MyProxy server")
306    parser.add_option("-o", "--out", dest="outfile", 
307                       help="The username with which the credential is stored on the MyProxy server")
308    parser.add_option("-t", "--proxy-lifetime", dest="lifetime", default=43200,
309                       help="The username with which the credential is stored on the MyProxy server")
310    parser.add_option("-d", "--debug", dest="debug", default=0,
311                       help="Debug mode: 1=print debug info ; 2=print as in (1), and dump data to myproxy.dump")
312
313    (options,args) = parser.parse_args()
314   
315    debug = options.debug
316   
317    # process options
318    host = options.host
319    if not host:
320        print "Error: MyProxy host not specified"
321        sys.exit(1)
322    port = int(options.port)
323   
324    username = options.username
325    if not username:
326        if sys.platform == 'win32':
327            username = os.environ["USERNAME"]
328        else:
329            import pwd
330            username = pwd.getpwuid(os.geteuid())[0]
331    lifetime = int(options.lifetime)
332
333
334    if options.getDelegation:
335               
336        outfile = options.outfile
337        if not outfile:
338            if sys.platform == 'win32':
339                outfile = 'proxy'
340            elif sys.platform in ['linux2','darwin']:
341                outfile = '/tmp/x509up_u%s' % (os.getuid())
342   
343        # Get MyProxy password
344        passphrase = getpass.getpass()
345           
346        # Retrieve proxy cert
347        import pdb;pdb.set_trace()
348        try:
349            ret = myProxyLogon(host,
350                               username,
351                               passphrase,
352                               outfile,
353                               lifetime=lifetime,
354                               port=port)
355            print "A proxy has been received for user %s in %s." % \
356                (username, outfile)
357           
358        except Exception,e:
359            if debuglevel(1):
360                import traceback
361                traceback.print_exc()
362            else:
363                print "Error:", e
364    else:
365        try:
366            myProxyStore(host, 
367                         username, 
368                         options.certFile,
369                         options.keyFile,
370                         lifetime=lifetime,
371                         port=port)
372           
373        except Exception,e:
374            if debuglevel(1):
375                import traceback
376                traceback.print_exc()
377            else:
378                print "Error:", e
379           
Note: See TracBrowser for help on using the repository browser.