source: TI12-security/trunk/python/ndg.security.common/ndg/security/common/wssecurity/signaturehandler/__init__.py @ 5433

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.common/ndg/security/common/wssecurity/signaturehandler/__init__.py@5433
Revision 5433, 30.3 KB checked in by pjkersha, 12 years ago (diff)

Fixes for OAI editor security integration.

Line 
1""" Base class for the WS-Security digital signature handlers - to allow
2sharing of common code
3
4NERC DataGrid Project
5"""
6__author__ = "C Byrom"
7__date__ = "18/08/08"
8__copyright__ = ""
9__license__ = "BSD - see LICENSE file in top-level directory"
10__contact__ = "Philip.Kershaw@stfc.ac.uk"
11__revision__ = '$Id: $'
12
13import re
14
15# Digest and signature/verify
16from sha import sha
17from M2Crypto import X509, BIO, RSA
18import base64
19
20import os
21
22import ZSI
23from ZSI.wstools.Namespaces import ENCRYPTION, WSU
24from ZSI.wstools.Namespaces import OASIS as _OASIS
25from ConfigParser import RawConfigParser
26
27# Enable settings from a config file
28from ndg.security.common.wssecurity import WSSecurityConfig, WSSecurityError
29
30from ndg.security.common.X509 import X509Cert, X509CertParse, X509CertRead, \
31X509Stack, X509StackParseFromDER
32
33from datetime import datetime, timedelta
34import logging
35log = logging.getLogger(__name__)
36
37
38class _WSU(WSU):
39    '''Try different utility namespace for use with WebSphere'''
40    #UTILITY = "http://schemas.xmlsoap.org/ws/2003/06/utility"
41    UTILITY = ("http://docs.oasis-open.org/wss/2004/01/"
42               "oasis-200401-wss-wssecurity-utility-1.0.xsd")
43
44class OASIS(_OASIS):
45    # wss4j 1.5.3
46    WSSE11 = ("http://docs.oasis-open.org/wss/"
47              "oasis-wss-wssecurity-secext-1.1.xsd")
48    # wss4j 1.5.1
49#    WSSE11 = ("http://docs.oasis-open.org/wss/2005/xx/"
50#              "oasis-2005xx-wss-wssecurity-secext-1.1.xsd")
51
52
53class InvalidCertChain(WSSecurityError):   
54    """Raised from SignatureHandler.verify if the certificate submitted to
55    verify a signature is not from a known CA"""
56   
57class VerifyError(WSSecurityError):
58    """Raised from SignatureHandler.verify if an error occurs in the signature
59    verification"""
60 
61class TimestampError(WSSecurityError):
62    """Raised from SignatureHandler._verifyTimestamp if there is a problem with
63    the created or expiry times in an input message Timestamp"""
64
65class MessageExpired(TimestampError):
66    """Raised from SignatureHandler._verifyTimestamp if the timestamp of
67    the message being processed is before the current time.  Can be caught in
68    order to set a wsu:MessageExpired fault code"""
69   
70class InvalidSignature(WSSecurityError):
71    """Raised from verify method for an invalid signature"""
72
73class SignatureError(WSSecurityError):
74    """Flag if an error occurs during signature generation"""
75
76class NoSignatureFound(WSSecurityError):
77    """Raise from SignatureHandler.verify if inbound message is not signed"""
78
79
80class BaseSignatureHandler(object):
81    """Class to handle signature and verification of signature with
82    WS-Security
83   
84    @cvar binSecTokValType: supported ValueTypes for BinarySecurityToken
85    element in WSSE header
86    @type binSecTokValType: dict
87   
88    @ivar addTimestamp: set to true to add a timestamp to outbound messages
89    @type addTimestamp: bool
90
91    @ivar applySignatureConfirmation: for servers - set this flag to enable the
92    signature value of a request to be recorded and included with a
93    SignatureConfirmation element in the response.
94    @type applySignatureConfirmation: bool
95   
96    @param b64EncSignatureValue: base 64 encoded signature value for the last
97    message verified
98    @type b64EncSignatureValue: string/None"""
99
100    _binSecTokEncType = ("http://docs.oasis-open.org/wss/2004/01/"
101                         "oasis-200401-wss-soap-message-security-1.0#"
102                         "Base64Binary")
103   
104    binSecTokValType = {
105        "X509PKIPathv1": OASIS.X509TOKEN.X509PKIPathv1,
106        "X509":          OASIS.X509TOKEN.X509,
107        "X509v3":        OASIS.X509TOKEN.X509+"v3"
108    }
109
110
111    def __init__(self, cfg=None, cfgFileSection='DEFAULT', cfgFilePrefix='',
112                 cfgClass=WSSecurityConfig, **kw):
113        '''
114        @keyword reqBinSecTokValType: set the ValueType for the
115        BinarySecurityToken added to the WSSE header for a signed message.  See
116        __setReqBinSecTokValType method and binSecTokValType class variable
117        for options.  binSecTokValType determines whether signingCert or
118        signingCertChain attributes will be used.       
119        @type binSecTokValType: string
120       
121        @keyword verifyingCert: X.509 certificate used by verify method to
122        verify a message.  This argument can be omitted if the message to
123        be verified contains the X.509 certificate in the
124        BinarySecurityToken element.  In this case, the cert read from the
125        message will be assigned to the verifyingCert attribute.
126        @type verifyingCert: M2Crypto.X509.X509 /
127        ndg.security.common.X509.X509Cert
128       
129        @keyword verifyingCertFilePath: alternative input to the above, pass
130        the file path to the certificate stored in a file
131        @type verifyingCertFilePath: string
132       
133        @keyword signingCert: certificate associated with private key used to
134        sign a message.  The sign method will add this to the
135        BinarySecurityToken element of the WSSE header.  binSecTokValType
136        attribute must be set to 'X509' or 'X509v3' ValueTyep.  As an
137        alternative, use signingCertChain - see below...
138        @type signingCert: M2Crypto.X509.X509 /
139        ndg.security.common.X509.X509Cert
140       
141        @keyword signingCertFilePath: alternative input to the above, pass
142        the file path to the certificate stored in a file
143        @type signingCertFilePath: string
144       
145        @keyword signingCertChain: pass a list of certificates constituting a
146        chain of trust from the certificate used to verifying the signature
147        backward to the CA cert.  The CA cert need not be included.  To use
148        this option, reqBinSecTokValType must be set to the 'X509PKIPathv1'
149        ValueType
150        @type signingCertChain: list or tuple
151       
152        @keyword signingPriKey: private key used to be sign method to sign
153        message
154        @type signingPriKey: M2Crypto.RSA.
155       
156        @keyword signingPriKeyFilePath: equivalent to the above but pass
157        private key from PEM file
158        @type signingPriKeyFilePath: string
159       
160        @keyword signingPriKeyPwd: password protecting private key.  Set /
161        default to None if there is no password.
162        @type signingPriKeyPwd: string or None
163       
164        @keyword caCertDirPath: establish trust for signature verification.
165        This is a directory containing CA certificates.  These are used to
166        verify the certificate used to verify the message signature.
167        @type caCertDirPath: string
168       
169        @keyword caCertFilePathList: same as above except pass in a list of
170        file paths instead of a single directory name.
171        @type caCertFilePathList: list or tuple
172       
173        @keyword addTimestamp: set to true to add a timestamp to outbound
174        messages
175        @type addTimestamp: bool
176       
177        @keyword applySignatureConfirmation: for servers - set this flag to
178        enable the signature value of a request to be recorded and included
179        with a SignatureConfirmation element in the response.
180        @type : bool
181       
182        @param refC14nInclNS: list of namespaces to include in reference
183        Canonicalization.
184        @type refC14nInclNS: list
185       
186        @param signedInfoC14nInclNS: list of namespaces to include in
187        Signed Info Canonicalization.
188        @type signedInfoC14nInclNS: list
189        '''
190        log.debug("BaseSignatureHandler.__init__ ...")
191
192        # WSSecurityConfig is the default class for reading config params but
193        # alternative derivative class may be passed in instead.
194        if not issubclass(cfgClass, WSSecurityConfig):
195            raise TypeError("%s is not a sub-class of WSSecurityConfig" % 
196                            cfgClass)
197       
198        # Read parameters from config file if set
199        if isinstance(cfg, basestring):
200            log.debug("BaseSignatureHandler.__init__: config file path input "
201                      "...")
202            self.cfg = cfgClass()
203            self.cfg.read(cfg)
204            self.cfg.parse(section=cfgFileSection, prefix=cfgFilePrefix)
205
206        elif isinstance(cfg, RawConfigParser):
207            log.debug("BaseSignatureHandler.__init__: config object input ...")
208            self.cfg = cfgClass(cfg=cfg)
209            self.cfg.parse(section=cfgFileSection, prefix=cfgFilePrefix)
210           
211        elif isinstance(cfg, WSSecurityConfig):
212            log.debug("BaseSignatureHandler.__init__:  WSSSecurityConfig "
213                      "object input ...")
214            self.cfg = cfg
215        else:
216            self.cfg = cfgClass()
217               
218        # Also update config from keywords set
219        log.debug("BaseSignatureHandler.__init__: updating config from "
220                  "keywords...")
221       
222        # Filter keywords if a prefix is set removing any that don't start with
223        # the prefix given
224        self.cfg.update(kw, prefix=cfgFilePrefix)
225       
226        # set default value type, if none specified in config file
227        if not self.cfg['reqBinSecTokValType']:
228            self.cfg['reqBinSecTokValType'] = "X509v3"
229           
230        self.reqBinSecTokValType = self.cfg['reqBinSecTokValType']
231
232        # Set keywords for canonicalization of SignedInfo and reference
233        # elements
234        self.refC14nKw = {'inclusive_namespaces': self.cfg['refC14nInclNS']}
235
236        self.signedInfoC14nKw = {'inclusive_namespaces': 
237                                 self.cfg['signedInfoC14nInclNS']}
238
239        self.verifyingCert = self.cfg['verifyingCert']
240        self.verifyingCertFilePath = self.cfg['verifyingCertFilePath']
241       
242        self.signingCert = self.cfg['signingCert']
243        self.signingCertFilePath = self.cfg['signingCertFilePath']
244
245        self.signingCertChain = self.cfg['signingCertChain']
246             
247        # MUST be set before _setSigningPriKeyFilePath / _setSigningPriKey
248        # are called
249        self.signingPriKeyPwd = self.cfg['signingPriKeyPwd']
250       
251        if self.cfg.get('signingPriKey'):
252            # Don't allow None for private key setting
253            self.signingPriKey = self.cfg['signingPriKey']
254           
255        self.signingPriKeyFilePath = self.cfg['signingPriKeyFilePath']
256       
257        # CA certificate(s) for verification of X.509 certificate used with
258        # signature.
259        if self.cfg.get('caCertDirPath'):
260            self.caCertDirPath = self.cfg['caCertDirPath']
261           
262        elif self.cfg.get('caCertFilePathList'):
263            self.caCertFilePathList = self.cfg['caCertFilePathList']
264       
265        # Configure signature generation to add/omit a timestamp
266        self.addTimestamp = self.cfg['addTimestamp']
267       
268        # Configure timestamp checking in Signature verification handler
269        self.timestampMustBeSet = self.cfg['timestampMustBeSet']
270        self.createdElemMustBeSet = self.cfg['createdElemMustBeSet']
271        self.expiresElemMustBeSet = self.cfg['expiresElemMustBeSet']
272       
273        # set default value, if none specified in config file
274        if not self.cfg['applySignatureConfirmation']:
275            self.cfg['applySignatureConfirmation'] = False
276
277        self.applySignatureConfirmation=self.cfg['applySignatureConfirmation']
278        self.b64EncSignatureValue = None
279       
280        log.debug("WSSE Config = %s" % self.cfg)
281
282               
283    def _setReqBinSecTokValType(self, value):
284        """Set ValueType attribute for BinarySecurityToken used in a request
285         
286        @type value: string
287        @param value: name space for BinarySecurityToken ValueType check
288        'binSecTokValType' class variable for supported types.  Input can be
289        shortened to binSecTokValType keyword if desired.
290        """
291        log.debug("Setting reqBinSecTokValType - to %s" %value)
292        if value in self.__class__.binSecTokValType:
293            self._reqBinSecTokValType = self.__class__.binSecTokValType[value]
294 
295        elif value in self.__class__.binSecTokValType.values():
296            self._reqBinSecTokValType = value
297        else:
298            raise WSSecurityError('Request BinarySecurityToken ValueType '
299                                  '"%s" not recognised' % value)
300           
301    def _getReqBinSecTokValType(self):
302        """
303        Get ValueType attribute for BinarySecurityToken used in a request
304        """
305        log.debug("Getting reqBinSecTokValType value")
306        if hasattr(self, '_reqBinSecTokValType'):
307            return self._reqBinSecTokValType
308        else:
309            return ""
310       
311    reqBinSecTokValType = property(fset=_setReqBinSecTokValType,
312                                   fget=_getReqBinSecTokValType,
313         doc="ValueType attribute for BinarySecurityToken used in request")
314       
315
316    def __checkC14nKw(self, kw):
317        """Check keywords for canonicalization in signing process - generic
318        method for setting keywords for reference element and SignedInfo
319        element C14N
320       
321        @type kw: dict
322        @param kw: keyword used with ZSI.wstools.Utility.Canonicalization"""
323       
324        # Check for dict/None - Set to None in order to use inclusive
325        # canonicalization
326        if kw is not None and not isinstance(kw, dict):
327            # Otherwise keywords must be a dictionary
328            raise AttributeError("Expecting dictionary type for reference "
329                                 "C14N keywords")
330               
331        elif kw.get('inclusive_namespaces') and \
332             not isinstance(kw['inclusive_namespaces'], (list, tuple)):
333            raise AttributeError('Expecting list or tuple of prefix names for '
334                                 '"%s" keyword' % 'inclusive_namespaces')
335       
336               
337    def _setRefC14nKw(self, kw):
338        """Set keywords for canonicalization of reference elements in the
339        signing process"""
340        self.__checkC14nKw(kw)                   
341        self._refC14nKw = kw
342       
343    def _getRefC14nKw(self):
344        if hasattr(self, '_refC14nKw'):
345            return self._refC14nKw
346        else:
347            return {}
348       
349    refC14nKw = property(fset=_setRefC14nKw,
350                         fget=_getRefC14nKw,
351                         doc="Keywords for C14N of reference elements")
352       
353               
354    def _setSignedInfoC14nKw(self, kw):
355        """Set keywords for canonicalization of SignedInfo element in the
356        signing process"""
357        self.__checkC14nKw(kw)                   
358        self._signedInfoC14nKw = kw
359       
360    def _getSignedInfoC14nKw(self):
361        if hasattr(self, '_signedInfoC14nKw'):
362            return self._signedInfoC14nKw
363        else:
364            return {}
365       
366    signedInfoC14nKw = property(fset=_setSignedInfoC14nKw,
367                                fget=_getSignedInfoC14nKw,
368                                doc="Keywords for C14N of SignedInfo element")
369
370
371    def _refC14nIsExcl(self):
372        '''
373        @rtype: bool
374        @return: true if Exclusive C14N is set as algorithm to apply to
375        reference elements
376        '''
377        # TODO: alter logic here if inclusive C14N is re-instated.
378        return True
379               
380    refC14nIsExcl = property(fget=_refC14nIsExcl,
381    doc="Return True/False C14N for reference elements set to exclusive type")
382
383     
384    def _signedInfoC14nIsExcl(self):
385        '''
386        @rtype: bool
387        @return: true if Exclusive C14N is set as algorithm to apply to
388        the signed info elements of the XML Digital Signature
389        '''
390        # TODO: alter logic here if inclusive C14N is re-instated.
391        return True
392       
393    signedInfoC14nIsExcl = property(fget=_signedInfoC14nIsExcl,
394                                    doc="Return True/False C14N for "
395                                    "SignedInfo element set to exclusive type")
396   
397   
398    def _setCert(self, cert):
399        """filter and convert input cert to signing verifying cert set
400        property methods.  For signingCert, set to None if it is not to be
401        included in the SOAP header.  For verifyingCert, set to None if this
402        cert can be expected to be retrieved from the SOAP header of the
403        message to be verified
404       
405        @type: ndg.security.common.X509.X509Cert / M2Crypto.X509.X509 /
406        PEM encoded string or None
407        @param cert: X.509 certificate. 
408       
409        @rtype ndg.security.common.X509.X509Cert
410        @return X.509 certificate object"""
411       
412        if not cert or isinstance(cert, X509Cert):
413            # ndg.security.common.X509.X509Cert type / None
414            x509Cert = cert
415           
416        elif isinstance(cert, X509.X509):
417            # M2Crypto.X509.X509 type
418            x509Cert = X509Cert(m2CryptoX509=cert)
419           
420        elif isinstance(cert, basestring):
421            # Nb. Assume PEM encoded string!
422            x509Cert = X509CertParse(cert)
423       
424        else:
425            raise AttributeError("X.509 Cert. must be type: ndg.security."
426                                 "common.X509.X509Cert, M2Crypto.X509.X509 or "
427                                 "a base64 encoded string")
428       
429        # Check for expired certificate
430        if x509Cert:   
431            x509Cert.isValidTime(raiseExcep=True)
432           
433        return x509Cert
434
435   
436    def _getVerifyingCert(self):
437        '''Return X.509 cert object corresponding to cert used to verify the
438        signature in the last call to verify
439       
440         * Cert will correspond to one used in the LATEST call to verify, on
441         the next call it will be replaced
442         * if verify hasn't been called, the cert will be None
443       
444        @rtype: M2Crypto.X509.X509
445        @return: certificate object
446        '''
447        return self._verifyingCert
448
449
450    def _setVerifyingCert(self, verifyingCert):
451        "Set property method for X.509 cert. used to verify a signature"
452        self._verifyingCert = self._setCert(verifyingCert)
453       
454        # Reset file path as it may no longer apply
455        self._verifyingCertFilePath = None
456       
457    verifyingCert = property(fset=_setVerifyingCert,
458                             fget=_getVerifyingCert,
459                             doc="Set X.509 Cert. for verifying signature")
460
461
462    def _setVerifyingCertFilePath(self, verifyingCertFilePath):
463        "Set method for Service X.509 cert. file path property"
464        if verifyingCertFilePath:
465            if isinstance(verifyingCertFilePath, basestring):
466                self._verifyingCert = X509CertRead(verifyingCertFilePath)
467            else:
468                raise AttributeError, "X.509 Cert file path is not a valid string"
469       
470        self._verifyingCertFilePath = verifyingCertFilePath
471       
472    verifyingCertFilePath = property(fset=_setVerifyingCertFilePath,
473                    doc="file path of X.509 Cert. for verifying signature")
474
475   
476    def _getSigningCert(self):
477        '''Return X.509 certificate object corresponding to certificate used
478        with signature
479       
480        @rtype: M2Crypto.X509.X509
481        @return: certificate object
482        '''
483        return self._signingCert
484
485
486    def _setSigningCert(self, signingCert):
487        "Set property method for X.509 cert. to be included with signature"
488        self._signingCert = self._setCert(signingCert)
489   
490        # Reset file path as it may no longer apply
491        self._signingCertFilePath = None
492       
493    signingCert = property(fget=_getSigningCert,
494                           fset=_setSigningCert,
495                           doc="X.509 Certificate to include signature")
496
497 
498    def _setSigningCertFilePath(self, signingCertFilePath):
499        "Set signature X.509 certificate property method"
500       
501        if isinstance(signingCertFilePath, basestring):
502            self._signingCert = X509CertRead(signingCertFilePath)
503           
504        elif signingCertFilePath is not None:
505            raise AttributeError("Signature X.509 certificate file path must "
506                                 "be a valid string")
507       
508        self._signingCertFilePath = signingCertFilePath
509       
510       
511    signingCertFilePath = property(fset=_setSigningCertFilePath,
512                   doc="File path X.509 cert. to include with signed message")
513
514   
515    def _setSigningCertChain(self, signingCertChain):
516        '''Signature set-up with "X509PKIPathv1" BinarySecurityToken
517        ValueType.  Use an X.509 Stack to store certificates that make up a
518        chain of trust to certificate used to verify a signature
519       
520        @type signingCertChain: list or tuple of M2Crypto.X509.X509Cert or
521        ndg.security.common.X509.X509Cert types.
522        @param signingCertChain: list of certificate objects making up the
523        chain of trust.  The last certificate is the one associated with the
524        private key used to sign the message.'''
525       
526        if not isinstance(signingCertChain, (list, tuple)):
527            log.warning('Expecting a list or tuple for "signingCertChain" - '
528                        'ignoring value set, "%s"' % signingCertChain)
529            self._signingCertChain = None
530            return
531       
532        self._signingCertChain = X509Stack()
533           
534        for cert in signingCertChain:
535            self._signingCertChain.push(cert)
536           
537    def _getSigningCertChain(self):
538        return self._signingCertChain
539   
540    signingCertChain = property(fset=_setSigningCertChain,
541                                fget=_getSigningCertChain,
542                                doc="Cert.s in chain of trust to cert. used "
543                                    "to verify msg.")
544
545 
546    def _setSigningPriKeyPwd(self, signingPriKeyPwd):
547        "Set method for private key file password used to sign message"
548        if signingPriKeyPwd is not None and \
549           not isinstance(signingPriKeyPwd, basestring):
550            raise AttributeError("Signing private key password must be None "
551                                 "or a valid string")
552       
553        self._signingPriKeyPwd = signingPriKeyPwd
554
555    def _getSigningPriKeyPwd(self):
556        if hasattr(self, '_signingPriKeyPwd'):
557            return self._signingPriKeyPwd
558        else:
559            return ""
560       
561    signingPriKeyPwd = property(fset=_setSigningPriKeyPwd,
562                                fget=_getSigningPriKeyPwd,
563                                doc="Password protecting private key file "
564                                    "used to sign message")
565
566 
567    def _setSigningPriKey(self, signingPriKey):
568        """Set method for client private key
569       
570        Nb. if input is a string, signingPriKeyPwd will need to be set if
571        the key is password protected.
572       
573        @type signingPriKey: M2Crypto.RSA.RSA / string
574        @param signingPriKey: private key used to sign message"""
575       
576        if isinstance(signingPriKey, basestring):
577            pwdCallback = lambda *ar, **kw: self._signingPriKeyPwd
578            self._signingPriKey = RSA.load_key_string(signingPriKey,
579                                                       callback=pwdCallback)
580
581        elif isinstance(signingPriKey, RSA.RSA):
582            self._signingPriKey = signingPriKey
583                   
584        else:
585            raise AttributeError("Signing private key must be a valid "
586                                  "M2Crypto.RSA.RSA type or a string")
587               
588    def _getSigningPriKey(self):
589        return self._signingPriKey
590
591    signingPriKey = property(fset=_setSigningPriKey,
592                             fget=_getSigningPriKey,
593                             doc="Private key used to sign outbound message")
594
595 
596    def _setSigningPriKeyFilePath(self, signingPriKeyFilePath):
597        """Set method for client private key file path
598       
599        signingPriKeyPwd MUST be set prior to a call to this method"""
600        if isinstance(signingPriKeyFilePath, basestring):                           
601            try:
602                # Read Private key to sign with   
603                priKeyFile = BIO.File(open(signingPriKeyFilePath)) 
604                pwdCallback = lambda *ar, **kw: self._signingPriKeyPwd                                           
605                self._signingPriKey = RSA.load_key_bio(priKeyFile, 
606                                                        callback=pwdCallback)           
607            except Exception, e:
608                raise AttributeError("Setting private key for signature: %s"%e)
609       
610        elif signingPriKeyFilePath is not None:
611            raise AttributeError("Private key file path must be a valid "
612                                 "string or None")
613       
614        self.__signingPriKeyFilePath = signingPriKeyFilePath
615       
616    signingPriKeyFilePath = property(fset=_setSigningPriKeyFilePath,
617                      doc="File path for private key used to sign message")
618
619    def __caCertIsSet(self):
620        '''Check for CA certificate set (X.509 Stack has been created)'''
621        return hasattr(self, '_caX509Stack')
622   
623    caCertIsSet = property(fget=__caCertIsSet,
624           doc='Check for CA certificate set (X.509 Stack has been created)')
625   
626    def __appendCAX509Stack(self, caCertList):
627        '''Store CA certificates in an X.509 Stack
628       
629        @param caCertList: list or tuple
630        @type caCertList: M2Crypto.X509.X509 certificate objects'''
631       
632        if not hasattr(self, '_caX509Stack'):
633            self._caX509Stack = X509Stack()
634           
635        for cert in caCertList:
636            self._caX509Stack.push(cert)
637
638
639    def __setCAX509StackFromDir(self, caCertDir):
640        '''Read CA certificates from directory and add them to the X.509
641        stack
642       
643        @param caCertDir: string
644        @type caCertDir: directory from which to read CA certificate files'''
645       
646        # Mimic OpenSSL -CApath option which expects directory of CA files
647        # of form <Hash cert subject name>.0
648        reg = re.compile('\d+\.0')
649        try:
650            caCertList = [X509CertRead(caFile) \
651                          for caFile in os.listdir(caCertDir) \
652                          if reg.match(caFile)]
653        except Exception, e:
654            raise WSSecurityError('Loading CA certificate "%s" from CA '
655                                  'directory: %s' % (caFile, str(e)))
656                   
657        # Add to stack
658        self.__appendCAX509Stack(caCertList)
659       
660    caCertDirPath = property(fset=__setCAX509StackFromDir,
661                             doc="Dir. containing CA cert.s used for "
662                                "verification")
663
664
665    def __setCAX509StackFromCertFileList(self, caCertFilePathList):
666        '''Read CA certificates from file and add them to the X.509
667        stack
668       
669        @type caCertFilePathList: list or tuple
670        @param caCertFilePathList: list of file paths for CA certificates to
671        be used to verify certificate used to sign message'''
672       
673        if not isinstance(caCertFilePathList, (list, tuple)):
674            raise WSSecurityError('Expecting a list or tuple for '
675                                  '"caCertFilePathList"')
676
677        # Mimic OpenSSL -CApath option which expects directory of CA files
678        # of form <Hash cert subject name>.0
679        try:
680            caCertList=[X509CertRead(caFile) for caFile in caCertFilePathList]
681        except Exception, e:
682            raise WSSecurityError('Loading CA certificate "%s" from file '
683                                  'list: %s' % (caFile, str(e)))
684                   
685        # Add to stack
686        self.__appendCAX509Stack(caCertList)
687       
688    caCertFilePathList = property(fset=__setCAX509StackFromCertFileList,
689                      doc="List of CA cert. files used for verification")
690               
691
692    def _setBool(self, val):
693        """Convert input string, float or int to bool type
694       
695        @type val: int, float or basestring
696        @param val: input value to be converted
697        @rtype: bool
698        @return: input value converted to bool type
699        """
700       
701        if isinstance(val, bool):
702            return val
703       
704        elif isinstance(val, basestring):
705            val = val.lower()
706            if val not in ("true", "false"):
707                raise ValueError("String conversion failed for input: %r"%val)
708           
709            return val == "true"
710           
711        elif isinstance(val, (int, float)): 
712            return bool(val)
713        else:
714            raise TypeError("Invalid type for bool conversion: %r" % 
715                            val.__class__)
716       
717    def _get_timestampMustBeSet(self):
718        return getattr(self, "_timestampMustBeSet", False)
719
720    def _set_timestampMustBeSet(self, val):
721        self._timestampMustBeSet = self._setBool(val)
722       
723    timestampMustBeSet = property(fset=_set_timestampMustBeSet,
724                                  fget=_get_timestampMustBeSet,
725                                  doc="Set to True to raise an exception if a "
726                                      "message to be verified doesn't have a "
727                                      "timestamp element.  Set to False to "
728                                      "log a warning message and continue "
729                                      "processing")
730   
731    def _get_createdElemMustBeSet(self):
732        return getattr(self, "_createdElemMustBeSet", False)
733
734    def _set_createdElemMustBeSet(self, val):
735        self._createdElemMustBeSet = self._setBool(val)
736       
737    createdElemMustBeSet = property(fset=_set_createdElemMustBeSet,
738                                    fget=_get_createdElemMustBeSet,
739                                    doc="Set to True to raise an exception if "
740                                        "a message to be verified doesn't "
741                                        "have <wsu:Created/> element with its "
742                                        "timestamp element.  Set to False to "
743                                        "log a warning message and continue "
744                                        "processing")
745   
746    def _get_expiresElemMustBeSet(self):
747        return getattr(self, "_expiresElemMustBeSet", False)
748
749    def _set_expiresElemMustBeSet(self, val):
750        self._expiresElemMustBeSet = self._setBool(val)
751       
752    expiresElemMustBeSet = property(fset=_set_expiresElemMustBeSet,
753                                    fget=_get_expiresElemMustBeSet,
754                                    doc="Set to True to raise an exception if "
755                                        "a message to be verified doesn't "
756                                        "have <wsu:Expires/> element with its "
757                                        "timestamp element.  Set to False to "
758                                        "log a warning message and continue "
759                                        "processing")                                 
760
761                             
Note: See TracBrowser for help on using the repository browser.