source: TI12-security/trunk/python/ndg.security.common/ndg/security/common/ca/__init__.py @ 2145

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

python/ndg.security.server/ndg/security/server/ca/server-config.tac: added file copied
from Session Manager equivalent

python/ndg.security.server/ndg/security/server/ca/SimpleCA.py:

  • added ability to generate a certificate request using M2Crypto
  • added properties for running web service over SSL + PKI settings
  • properties file path can be set vai the NDGSEC_CA_PROPFILEPATH environment variable

python/ndg.security.server/ndg/security/server/ca/start-container.sh: script to run
service with twistd.

python/ndg.security.server/ndg/security/server/ca/Makefile: calls to wsdl2dispatch to
generate server side stubs.

python/ndg.security.server/ndg/security/server/SessionMgr/server-config.tac: fixed typo

  • ref to Attribute Authority instead of Session Manager.

python/ndg.security.server/ndg/security/server/MyProxy.py: simplified use of OpenSSLConfig
class.

python/conf/sessionMgrProperties.xml: removed duplicate lines.

python/conf/simpleCAProperties.xml: re-added - for some reason not previously stored in
repository.

python/ndg.security.test/ndg/security/test/ca/server.sh: adapted from Session Manager
version.

python/ndg.security.test/ndg/security/test/ca/caClientTest.cfg: added settings for
issueCert unit test to configure certificate request.

python/ndg.security.test/ndg/security/test/ca/caClientTest.py: setting up
test1IssueCert unit test.

python/ndg.security.test/ndg/security/test/ca/simpleCAProperties.xml: added settings for
SSL and PKI.

python/ndgSetup.sh: set up GRID_SECURITY_DIR environment variable

python/ndg.security.common/ndg/security/common/ca/init.py: Certificate Authority
web service client - updated settings for OpenSSLConfig object and issueCert method.

python/ndg.security.common/ndg/security/common/ca/CertReq.py: old code from alpha version
of NDG-Security.

python/ndg.security.common/ndg/security/common/ca/Makefile: generates client and server
side stubs for Certificate Authority web service.

python/ndg.security.common/ndg/security/common/wsSecurity.py: updated header

python/ndg.security.common/ndg/security/common/openssl.py:

  • fixed regular expression for 'req_distinguished_name' pattern match
  • parameters are parsed in call to read() rather than in getReqDN method.
  • reqDN is now a property.
Line 
1#!/usr/bin/env python
2"""NDG Security Certificate Authority client - client interface classes to the
3Certificate Authority. 
4
5NERC Data Grid Project
6
7@author P J Kershaw 17/11/06
8
9@copyright (C) 2006 CCLRC & NERC
10
11@license This software may be distributed under the terms of the Q Public
12License, version 1.0 or later.
13"""
14reposID = '$Id:$'
15
16__all__ = [
17    'CertificateAuthority_services',
18    'CertificateAuthority_services_types',
19    ]
20
21# Handling for public key retrieval
22import tempfile
23from M2Crypto import X509, RSA, EVP, m2
24
25from CertificateAuthority_services import CertificateAuthorityServiceLocator
26from ndg.security.common.wsSecurity import SignatureHandler
27from ndg.security.common.openssl import OpenSSLConfig
28
29
30#_____________________________________________________________________________
31class CertificateAuthorityClientError(Exception):
32    """Exception handling for CertificateAuthorityClient class"""
33
34
35#_____________________________________________________________________________
36class CertificateAuthorityClient(object):
37    """Client interface to Certificate Authority web service
38   
39    @ctype _certReqDNparamName: tuple
40    @cvar _certReqDNparamName: names of parameters needed to generate a
41    certificate request e.g. CN, OU etc."""
42
43    _certReqDNparamName = ('O', 'OU')
44   
45    #_________________________________________________________________________
46    def __init__(self, 
47                 uri=None, 
48                 tracefile=None,
49                 openSSLConfigFilePath=None, 
50                 **signatureHandlerKw):
51        """
52        @type uri: string
53        @keyword uri: URI for Attribute Authority WS.  Setting it will also
54        initialise the Service Proxy
55                                         
56        @keyword tracefile: set to file object such as sys.stderr to give
57        extra WS debug information
58       
59        @type **signatureHandlerKw: dict
60        @param **signatureHandlerKw: keywords for SignatureHandler class"""
61
62        self.__srv = None
63        self.__uri = None
64       
65
66        # Set-up parameter names for certificate request
67        self.__openSSLConfig = OpenSSLConfig(filePath=openSSLConfigFilePath)
68
69       
70        if uri:
71            self.__setURI(uri)
72
73        # WS-Security Signature handler
74        self.__signatureHandler = SignatureHandler(**signatureHandlerKw)
75           
76        self.__tracefile = tracefile
77
78         
79        # Instantiate Attribute Authority WS proxy
80        if self.__uri:
81            self.initService()
82       
83
84    #_________________________________________________________________________
85    def __setURI(self, uri):
86       
87        if not isinstance(uri, basestring):
88            raise CertificateAuthorityClientError, \
89                        "Attribute Authority WSDL URI must be a valid string"
90       
91        self.__uri = uri
92       
93    uri = property(fset=__setURI, doc="Set Attribute Authority WSDL URI")
94
95
96    #_________________________________________________________________________
97    def __getOpenSSLConfig(self):
98        "Get OpenSSLConfig object property method"
99        return self.__openSSLConfig
100   
101    openSSLConfig = property(fget=__getOpenSSLConfig,
102                             doc="OpenSSLConfig object")
103
104
105    #_________________________________________________________________________
106    def __getSignatureHandler(self):
107        "Get SignatureHandler object property method"
108        return self.__signatureHandler
109   
110    signatureHandler = property(fget=__getSignatureHandler,
111                                doc="SignatureHandler object")
112
113
114    #_________________________________________________________________________
115    def __setSrvCertFilePath(self, srvCertFilePath):
116       
117        if not isinstance(srvCertFilePath, basestring):
118            raise CertificateAuthorityClientError, \
119                "Attribute Authority public key URI must be a valid string"
120       
121        self.__srvCertFilePath = srvCertFilePath
122       
123    srvCertFilePath = property(fset=__setSrvCertFilePath,
124                              doc="Set Attribute Authority public key URI")
125
126 
127    #_________________________________________________________________________
128    def __setClntCertFilePath(self, clntCertFilePath):
129       
130        if not isinstance(clntCertFilePath, basestring):
131            raise CertificateAuthorityClientError, \
132                "Client public key file path must be a valid string"
133       
134        self.__clntCertFilePath = clntCertFilePath
135       
136        try:
137            self.__clntCert = open(self.__clntCertFilePath).read()
138           
139        except IOError, (errNo, errMsg):
140            raise CertificateAuthorityClientError, \
141                    "Reading certificate file \"%s\": %s" % \
142                    (self.__clntCertFilePath, errMsg)
143                               
144        except Exception, e:
145            raise CertificateAuthorityClientError, \
146                                    "Reading certificate file \"%s\": %s" % \
147                                    (self.__clntCertFilePath, str(e))
148       
149    clntCertFilePath = property(fset=__setClntCertFilePath,
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 CertificateAuthorityClientError(\
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 __setClntPriKeyPwd(self, clntPriKeyPwd):
168       
169        if not isinstance(clntPriKeyPwd, basestring):
170            raise SessionMgrClientError, \
171                        "Client private key password must be a valid string"
172       
173        self.__clntPriKeyPwd = clntPriKeyPwd
174       
175    clntPriKeyPwd = property(fset=__setClntPriKeyPwd,
176                         doc="Password protecting client private key file")
177
178       
179    #_________________________________________________________________________
180    def initService(self, uri=None):
181        """Set the WS proxy for the Attribute Authority
182       
183        @type uri: string
184        @param uri: URI for service to invoke"""
185       
186        if uri:
187            self.__setURI(uri)
188
189        # WS-Security Signature handler object is passed to binding
190        try:
191            locator = CertificateAuthorityServiceLocator()
192            self.__srv = locator.getCertificateAuthority(self.__uri, 
193                                         sig_handler=self.__signatureHandler,
194                                         tracefile=self.__tracefile)
195        except HTTPResponse, e:
196            raise CertificateAuthorityClientError, \
197                "Error initialising WSDL Service for \"%s\": %s %s" % \
198                (self.__uri, e.status, e.reason)
199           
200        except Exception, e:
201            raise CertificateAuthorityClientError, \
202                "Initialising WSDL Service for \"%s\": %s" % \
203                 (self.__uri, str(e))
204                 
205                 
206    #_________________________________________________________________________       
207    def _createCertReq(self, CN, nBitsForKey=1024, messageDigest="md5"):
208        """
209        Create a certificate request.
210       
211        @param CN: Common Name for certificate - effectively the same as the
212        username for the MyProxy credential
213        @param nBitsForKey: number of bits for private key generation -
214        default is 1024
215        @param messageDigest: message disgest type - default is MD5
216        @return tuple of certificate request PEM text and private key PEM text
217        """
218       
219        # Check all required certifcate request DN parameters are set               
220        # Create certificate request
221        req = X509.Request()
222   
223        # Generate keys
224        key = RSA.gen_key(nBitsForKey, m2.RSA_F4)
225   
226        # Create public key object
227        pubKey = EVP.PKey()
228        pubKey.assign_rsa(key)
229       
230        # Add the public key to the request
231        req.set_version(0)
232        req.set_pubkey(pubKey)
233       
234        defaultReqDN = self.__openSSLConfig.reqDN       
235           
236        # Set DN
237        x509Name = X509.X509_Name()
238        x509Name.CN = CN
239        x509Name.OU = defaultReqDN.get('0.organizationalUnitName') or \
240                        defaultReqDN['0U']
241        x509Name.O = defaultReqDN.get('0.organizationName') or \
242                        defaultReqDN['0']
243                       
244        req.set_subject_name(x509Name)
245       
246        req.sign(pubKey, messageDigest)
247       
248        return req, key
249   
250                                   
251    #_________________________________________________________________________
252    def issueCert(self, 
253                  certReq=None, 
254                  CN=None, 
255                  openSSLConfigFilePath=None,
256                  **createCertReqKw):
257        """Send a certificate request to the CA for signing
258       
259        signCert([certReq=cr]|[CN=cn, openSSLConfigFilePath=p, **kw])
260       
261        @type certReq: M2Crypto.X509.Request
262        @keyword certReq: X.509 certificate request.  If omitted,
263        _createCertReq method is called to create a new public and private
264        key and a certificate request
265       
266        @type CN: string
267        @keyword CN: common name component of Distinguished Name for new
268        cert.  This keyword is ignored if certReq keyword is set.
269       
270        @type openSSLConfigFilePath: string
271        @keyword openSSLConfigFilePath: file path for OpenSSL configuration
272        file from which to get settings for Distinguished Name for new
273        certificate.  This keyword is ignored if certReq keyword is set.
274       
275        @type **createCertReqKw: dict
276        @param **createCertReqKw: keywords to call to _createCertReq - only
277        applies if certReq is not set.
278       
279        @rtype: tuple
280        @return: signed certificate and private key.  Private key will be
281        None if certReq keyword was passed in
282        """
283
284        priKey = None
285        if not certReq:
286            # Create the certificate request
287            certReq, priKey = self._createCertReq(CN, **createCertReqKw)
288       
289        try:   
290            cert = self.__srv.issueCert(certReq.as_pem())
291
292        except Exception, e:
293            raise CertificateAuthorityClientError, \
294                                            "Signing Certificate: " + str(e)     
295        return cert, priKey
296
297                                   
298    #_________________________________________________________________________
299    def revokeCert(self, x509Cert):
300        """Request that the CA revoke the given certificate
301       
302        @type x509Cert: string
303        @param x509Cert: X.509 certificate to be revoked"""
304           
305        try:   
306            self.__srv.revokeCert(x509Cert)
307
308        except Exception, e:
309            raise CertificateAuthorityClientError, \
310                                            "Revoking certificate: " + str(e)
311   
312
313    #_________________________________________________________________________
314    def getCRL(self):
315        """Request Certificate Revocation List (CRL) for the CA
316       
317        @rtype string
318        @return PEM encoded CRL"""
319
320        try: 
321            crl = self.__srv.getCRL() 
322           
323        except Exception, e:
324            raise CertificateAuthorityClientError, "Requesting CRL: " + str(e)
325
326        return crl
Note: See TracBrowser for help on using the repository browser.