source: cred_printer/cred_printer/util.py

Last change on this file was 02dcba5, checked in by Ted Faber <faber@…>, 13 years ago

Add credential printer

  • Property mode set to 100644
File size: 4.0 KB
Line 
1#!/usr/local/bin/python
2
3import sys
4from M2Crypto import SSL
5
6# Turn off the matching of hostname to certificate ID
7SSL.Connection.clientPostConnectionCheck = None
8
9class ssl_context(SSL.Context):
10    """
11    Simple wrapper around an M2Crypto.SSL.Context to initialize it for use with
12    self-signed certs.
13    """
14    def __init__(self, my_cert, trusted_certs=None, password=None):
15        """
16        construct a cred_ssl_context
17
18        @param my_cert: PEM file with my certificate in it
19        @param trusted_certs: PEM file with trusted certs in it (optional)
20        """
21        SSL.Context.__init__(self)
22
23        # load_cert takes a callback to get a password, not a password, so if
24        # the caller provided a password, this creates a nonce callback using a
25        # lambda form.
26        if password != None and not callable(password):
27            # This is cute.  password = lambda *args: password produces a
28            # function object that returns itself rather than one that returns
29            # the object itself.  This is because password is an object
30            # reference and after the assignment it's a lambda.  So we assign
31            # to a temp.
32            pwd = str(password)
33            password =lambda *args: pwd
34
35        # The calls to str below (and above) are because the underlying SSL
36        # stuff is intolerant of unicode.
37        if password != None:
38            self.load_cert(str(my_cert), callback=password)
39        else:
40            self.load_cert(str(my_cert))
41
42        # If no trusted certificates are specified, allow unknown CAs.
43        if trusted_certs: 
44            self.load_verify_locations(trusted_certs)
45            self.set_verify(SSL.verify_peer, 10)
46        else:
47            callb = getattr(SSL.cb, "ssl_verify_callback")
48            self.set_allow_unknown_ca(True)
49            self.set_verify(SSL.verify_peer, 10, 
50                    callback=SSL.cb.ssl_verify_callback_allow_unknown_ca)
51
52# Python 2.7 broke the MCrypto 2.1 SSL_Transport.  If this is an older python,
53# use SSL_Transport unchanged, otherwise use a tweaked version.  Export them as
54# SSLTransport.
55if sys.version_info == 2 and sys.version_info < 7:
56    from M2Crypto.m2xmlrpclib import SSL_Transport
57    class SSLTransport(SSL_Transport): pass
58else:
59    # Most of this is directly from M2Crypto
60    import base64, string, sys
61
62    from xmlrpclib import *
63    import M2Crypto
64    import M2Crypto.SSL, M2Crypto.httpslib, M2Crypto.m2urllib
65
66    __version__ = M2Crypto.version
67
68    class SSLTransport(Transport):
69
70        user_agent = "M2Crypto_XMLRPC/%s - %s" % (__version__, 
71                Transport.user_agent)
72
73        def __init__(self, ssl_context=None, *args, **kw):
74            if getattr(Transport, '__init__', None) is not None:
75                Transport.__init__(self, *args, **kw)
76            if ssl_context is None:
77                self.ssl_ctx=M2Crypto.SSL.Context('sslv23')
78            else:
79                self.ssl_ctx=ssl_context
80
81        def request(self, host, handler, request_body, verbose=0):
82            # Handle username and password.
83            user_passwd, host_port = M2Crypto.m2urllib.splituser(host)
84            _host, _port = M2Crypto.m2urllib.splitport(host_port)
85
86            # This is a difference, was an (obsolete) HTTPS object, but
87            # HTTPSConnection is more supported and clear --tvf
88            h = M2Crypto.httpslib.HTTPSConnection(_host, int(_port), 
89                    ssl_context=self.ssl_ctx)
90            if verbose:
91                h.set_debuglevel(1)
92
93            # What follows is as in xmlrpclib.Transport. (Except the authz bit.)
94            h.putrequest("POST", handler)
95
96            # required by HTTP/1.1
97            h.putheader("Host", _host)
98
99            # required by XML-RPC
100            h.putheader("User-Agent", self.user_agent)
101            h.putheader("Content-Type", "text/xml")
102            h.putheader("Content-Length", str(len(request_body)))
103
104            # Authorisation.
105            if user_passwd is not None:
106                auth=string.strip(base64.encodestring(user_passwd))
107                h.putheader('Authorization', 'Basic %s' % auth)
108
109            h.endheaders()
110
111            if request_body:
112                h.send(request_body)
113
114            # These are the modifications -- tvf
115
116            resp = h.getresponse()
117            errcode = resp.status
118            errmsg = resp.reason
119
120            # end mods -- tvf
121
122            if errcode != 200:
123                raise ProtocolError(
124                    host + handler,
125                    errcode, errmsg,
126                    headers
127                    )
128
129            self.verbose = verbose
130            return self.parse_response(resp)
131
Note: See TracBrowser for help on using the repository browser.