Changeset 6378


Ignore:
Timestamp:
22/01/10 15:36:40 (9 years ago)
Author:
pjkersha
Message:

Refactoring base signature handler

Location:
TI12-security/trunk/WSSecurity
Files:
5 added
2 deleted
5 edited
2 copied

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/WSSecurity/ndg/wssecurity/common/wssecurity/__init__.py

    r6069 r6378  
    1 """NDG Security WS-Security package - contains signature handler and config 
     1"""NDG Security WS-Security package - contains exception types 
    22 
    33NERC DataGrid Project 
     
    2020from ZSI.wstools.Namespaces import OASIS 
    2121 
    22 from ndg.security.common.utils.configfileparsers import \ 
    23     CaseSensitiveConfigParser 
     22 
     23from ndg.security.common.wssecurity.utils import CaseSensitiveConfigParser 
     24 
    2425 
    2526class WSSecurityError(Exception): 
     
    2930        log.error(errorMessage) 
    3031        super(WSSecurityError, self).__init__(errorMessage) 
     32     
    3133         
    3234class WSSecurityConfigError(WSSecurityError): 
    3335    """Configuration error with WS-Security setting or settings""" 
    3436     
     37     
    3538class WSSecurityConfigOpNotPermitted(WSSecurityConfigError): 
    3639    "Raise for dict methods not allowed in WSSecurityConfig" 
    37      
    38 class WSSecurityConfig(dict): 
    39     """Parser for WS-Security configuration.  Extends dict to enable 
    40     convenient interface for access to params. 
    41     """ 
    42     propertyDefaults = dict( 
    43         reqBinSecTokValType=OASIS.X509TOKEN.X509, 
    44         verifyingCert=None, 
    45         verifyingCertFilePath=None, 
    46         signingCert=None, 
    47         signingCertFilePath=None,  
    48         signingCertChain=[], 
    49         signingPriKey=None, 
    50         signingPriKeyFilePath=None,  
    51         signingPriKeyPwd=None, 
    52         caCertDirPath=None, 
    53         caCertFilePathList=[], 
    54         addTimestamp=True, 
    55         timestampClockSkew=0., 
    56         timestampMustBeSet=False, 
    57         createdElemMustBeSet=True, 
    58         expiresElemMustBeSet=True, 
    59         applySignatureConfirmation=False, 
    60         refC14nInclNS=[], 
    61         signedInfoC14nInclNS=[]) 
    62      
    63     def __init__(self, cfg=SafeConfigParser()): 
    64         '''Initialise settings from an existing config file object or the 
    65         given path to config file 
    66          
    67         @type cfg: SafeConfigParser or string 
    68         @param cfg: config object instance or file path to config file to be 
    69         parsed''' 
    70          
    71         dict.__init__(self) 
    72          
    73         # Initialise parameters from ref in class var 
    74         self._param = WSSecurityConfig.propertyDefaults.copy() 
    75          
    76         if isinstance(cfg, basestring): 
    77             # Assume file path to be read 
    78             self.read(cfg) 
    79         else: 
    80             # Assume existing config type object 
    81             self._cfg = cfg 
    82          
    83  
    84     def read(self, filePath): 
    85         '''Read ConfigParser object 
    86          
    87         @type filePath: basestring 
    88         @param filePath: file to read config from''' 
    89          
    90         # Expand environment variables in file path 
    91         expandedFilePath = exVar(filePath) 
    92          
    93         # Add 'here' item to enable convenient path substitutions in the config 
    94         # file 
    95         defaultItems = dict(here=os.path.dirname(expandedFilePath)) 
    96         self._cfg = CaseSensitiveConfigParser(defaults=defaultItems) 
    97          
    98         readFilePaths = self._cfg.read(expandedFilePath) 
    99          
    100         # Check file was read in OK 
    101         if len(readFilePaths) == 0: 
    102             raise IOError('Missing config file: "%s"' % expandedFilePath) 
    103  
    104     def parse(self, **kw): 
    105         '''Extract items from config file and place in dict 
    106         @type **kw: dict 
    107         @param **kw: this enables WS-Security params to be set in a config file 
    108         with other sections e.g. params could be under the section 'wssecurity' 
    109         ''' 
    110         section = kw.pop('section', 'DEFAULT') 
    111          
    112         # Prefix for option names - optNames = name as they appear in the  
    113         # config file, self._param are the names used in the code. 
    114         prefix = kw.pop('prefix', None) 
    115  
    116         if prefix: 
    117             optNames = ["%s.%s" % (prefix, optName) for optName in self._param]  
    118         else: 
    119             optNames = self._param 
    120              
    121         for optName, paramName in zip(optNames, self._param): 
    122              
    123             # Parameters may be omitted and set later 
    124             if self._cfg.has_option(section, optName): 
    125                 if isinstance(WSSecurityConfig.propertyDefaults[paramName],  
    126                               list): 
    127                     try: 
    128                         self._param[paramName] = \ 
    129                             exVar(self._cfg.get(section, optName)).split() 
    130                     except AttributeError: 
    131                         raise WSSecurityConfigError('Setting "%s"' % paramName) 
    132                      
    133                 elif isinstance(WSSecurityConfig.propertyDefaults[paramName],  
    134                                 bool):            
    135                     self._param[paramName] = self._cfg.getboolean(section,  
    136                                                                   optName) 
    137                 else: 
    138                     # Default to None if setting is an empty string.  Settings 
    139                     # of '' causes problems for M2Crypto parsing 
    140                     self._param[paramName] = \ 
    141                         exVar(self._cfg.get(section, optName)) or None 
    142  
    143     def __len__(self): 
    144         return len(self._param) 
    145      
    146     def __iter__(self): 
    147         return self._param.__iter__() 
    148      
    149     def __repr__(self): 
    150         """Return file properties dictionary as representation""" 
    151         return repr(self._param) 
    152  
    153     def __delitem__(self, key): 
    154         "Session Manager keys cannot be removed"         
    155         raise KeyError('Keys cannot be deleted from ' + \ 
    156                         WSSecurityConfig.__name__) 
    157  
    158     def __getitem__(self, key): 
    159         WSSecurityConfig.__name__ + \ 
    160         """ behaves as data dictionary of WS-Security properties 
    161         """ 
    162         if key not in WSSecurityConfig.propertyDefaults: 
    163             raise KeyError("Invalid key '%s'" % key) 
    164          
    165         return self._param[key]   
    166      
    167     def __setitem__(self, key, item): 
    168         WSSecurityConfig.__name__ + \ 
    169         """ behaves as data dictionary of WS-Security properties""" 
    170         if key not in WSSecurityConfig.propertyDefaults: 
    171             raise KeyError("Parameter key '%s' is not recognised" % key) 
    172          
    173         self._param[key] = item 
    174  
    175     def copy(self): 
    176         wsSecurityConfig = WSSecurityConfig() 
    177         wsSecurityConfig._param = self._param.copy() 
    178         return wsSecurityConfig 
    179      
    180     def get(self, key, *arg): 
    181         return self._param.get(key, *arg) 
    182  
    183     def clear(self): 
    184         raise WSSecurityConfigOpNotPermitted("Data cannot be cleared from "+\ 
    185                                              WSSecurityConfig.__name__) 
    186     
    187     def keys(self): 
    188         return self._param.keys() 
    189  
    190     def items(self): 
    191         return self._param.items() 
    192  
    193     def values(self): 
    194         return self._param.values() 
    195  
    196     def has_key(self, key): 
    197         return self._param.has_key(key) 
    198  
    199     # 'in' operator 
    200     def __contains__(self, key): 
    201         return key in self._param 
    202      
    203     def update(self, seq, *arg, **kw): 
    204  
    205         # Prefix for option names - optNames = name as they appear in the  
    206         # config file, self._param are the names used in the code. 
    207         prefix = kw.pop('prefix', None) 
    208         if prefix: 
    209             pfxWithDot = prefix+'.' 
    210             seqFilt = dict([(k.replace(pfxWithDot, ''), v)  
    211                             for k, v in seq.items()  
    212                             if k.startswith(pfxWithDot)]) 
    213         else: 
    214             seqFilt = seq 
    215          
    216         badKeys = [] 
    217         for optName, optVal in seqFilt.items(): 
    218             if optName not in WSSecurityConfig.propertyDefaults: 
    219                 badKeys += [optName] 
    220                  
    221             elif isinstance(WSSecurityConfig.propertyDefaults[optName], list): 
    222                 if isinstance(optVal, basestring): 
    223                     # Parse into a list 
    224                     seqFilt[optName] = exVar(optVal).split() 
    225                 elif isinstance(optVal, list): 
    226                     seqFilt[optName] = exVar(optVal) 
    227                 else: 
    228                     raise WSSecurityConfigError("Expecting list type for " 
    229                                                 'option "%s"' % optName) 
    230             elif isinstance(WSSecurityConfig.propertyDefaults[optName], bool): 
    231                 if isinstance(optVal, basestring): 
    232                     # Parse into a boolean 
    233                     seqFilt[optName] = bool(optVal) 
    234                      
    235                 elif isinstance(optVal, bool): 
    236                     seqFilt[optName] = optVal 
    237                 else: 
    238                     raise WSSecurityConfigError("Expecting bool type for " 
    239                                                 'option "%s"' % optName) 
    240             else: 
    241                 # Default to None if setting is an empty string.  Settings 
    242                 # of '' causes problems for M2Crypto parsing 
    243                 if optVal is None: 
    244                     seqFilt[optName] = optVal 
    245                 else: 
    246                     seqFilt[optName] = exVar(optVal) or None 
    247                  
    248         if len(badKeys) > 0: 
    249             log.warning("Ignoring unrecognised parameter key(s) for update: " 
    250                         "%s" % ', '.join(badKeys)) 
    251  
    252         return self._param.update(seqFilt, *arg) 
    253      
    254     def fromkeys(self, seq): 
    255         badKeys=[i for i in seq if i not in WSSecurityConfig.propertyDefaults] 
    256         if badKeys: 
    257             raise KeyError("Parameter key(s) %s not recognised" %  
    258                            ','.join(badKeys)) 
    259         return self._param.fromkeys(seq) 
    260      
    261     def setdefault(self, key, *arg): 
    262         badKeys=[i for i in arg if i not in WSSecurityConfig.propertyDefaults] 
    263         if badKeys: 
    264             raise KeyError("Parameter keys '%s' not recognised" % badKeys) 
    265         return self._param.setdefault(key, *arg) 
    266  
    267     def pop(self, key, *arg): 
    268         raise WSSecurityConfigOpNotPermitted("Params should not be deleted") 
    269      
    270     def popitem(self): 
    271         raise WSSecurityConfigOpNotPermitted("Params should not be deleted") 
    272      
    273     def iteritems(self): 
    274         return self._param.iteritems() 
    275      
    276     def iterkeys(self): 
    277         return self._param.iterkeys() 
    278      
    279     def itervalues(self): 
    280         return self._param.itervalues() 
    281     
     40      
  • TI12-security/trunk/WSSecurity/ndg/wssecurity/common/wssecurity/signaturehandler/__init__.py

    r5441 r6378  
    44NERC DataGrid Project 
    55""" 
    6 __author__ = "C Byrom" 
     6__author__ = "Philip Kershaw and C Byrom" 
    77__date__ = "18/08/08" 
    8 __copyright__ = "" 
     8__copyright__ = "(C) 2009 Science and Technology Facilities Council" 
    99__license__ = "BSD - see LICENSE file in top-level directory" 
    1010__contact__ = "Philip.Kershaw@stfc.ac.uk" 
     
    2727# Enable settings from a config file 
    2828from ndg.security.common.wssecurity import WSSecurityConfig, WSSecurityError 
    29  
    30 from ndg.security.common.X509 import X509Cert, X509CertParse, X509CertRead, \ 
    31 X509Stack, X509StackParseFromDER 
     29from ndg.security.common.wssecurity.utils import ContextSensitiveConfigParser 
     30from ndg.security.common.wssecurity.pki import (X509Cert, X509CertParse,  
     31                                                X509CertRead, X509Stack,  
     32                                                X509StackParseFromDER) 
    3233 
    3334from datetime import datetime, timedelta 
     
    4142    UTILITY = ("http://docs.oasis-open.org/wss/2004/01/" 
    4243               "oasis-200401-wss-wssecurity-utility-1.0.xsd") 
     44 
    4345 
    4446class OASIS(_OASIS): 
     
    5557    verify a signature is not from a known CA""" 
    5658     
     59     
    5760class VerifyError(WSSecurityError): 
    5861    """Raised from SignatureHandler.verify if an error occurs in the signature 
    5962    verification""" 
    6063  
     64  
    6165class TimestampError(WSSecurityError): 
    6266    """Raised from SignatureHandler._verifyTimestamp if there is a problem with 
     
    6872    order to set a wsu:MessageExpired fault code""" 
    6973     
     74     
    7075class InvalidSignature(WSSecurityError): 
    7176    """Raised from verify method for an invalid signature""" 
     77 
    7278 
    7379class SignatureError(WSSecurityError): 
     
    107113        "X509v3":        OASIS.X509TOKEN.X509+"v3" 
    108114    } 
    109  
    110  
    111     def __init__(self, cfg=None, cfgFileSection='DEFAULT', cfgFilePrefix='', 
    112                  cfgClass=WSSecurityConfig, **kw): 
     115     
     116    CFG_PARSER_CLASS = CaseSensitiveConfigParser 
     117 
     118    PROPERTY_DEFAULTS = dict( 
     119        reqBinSecTokValType=(OASIS.X509TOKEN.X509,), 
     120        verifyingCert=(None,), 
     121        verifyingCertFilePath=(None, ''), 
     122        signingCert=(None,), 
     123        signingCertFilePath=(None, ''),  
     124        signingCertChain=[], 
     125        signingPriKey=(None,), 
     126        signingPriKeyFilePath=(None, ''),  
     127        signingPriKeyPwd=(None, ''), 
     128        caCertDirPath=(None, ''), 
     129        caCertFilePathList=([], ), 
     130        addTimestamp=(True,), 
     131        timestampClockSkew=(0., 0), 
     132        timestampMustBeSet=(False,), 
     133        createdElemMustBeSet=(True,), 
     134        expiresElemMustBeSet=(True,), 
     135        applySignatureConfirmation=(False,), 
     136        refC14nInclNS=([],), 
     137        signedInfoC14nInclNS=([],), 
     138        cfg=(None, CFG_PARSER_CLASS())) 
     139     
     140    TYPE_MAP = dict([(k, tuple([type(i) for i in v])) 
     141                     for k, v in PROPERTY_DEFAULTS.items()]) 
     142     
     143    # Special case to parse an option containing a comma separated list 
     144    LIST_PARAM_SEP_PAT = re.compile(',\s*') 
     145    _parseCfgGetList = lambda section, option: LIST_PARAM_SEP_PAT.split( 
     146                                        CFG_PARSER_CLASS.get(section, option)) 
     147    parseCfgGetList = classmethod(_parseCfgGetList) 
     148     
     149    CFG_PARSER_GET_FUNC_MAP = { 
     150        'basestring': CFG_PARSER_CLASS.get, 
     151        'bool': CFG_PARSER_CLASS.getboolean, 
     152        'float': CFG_PARSER_CLASS.getfloat, 
     153        'int': CFG_PARSER_CLASS.getint, 
     154        'list': parseCfgGetList 
     155    } 
     156     
     157    __slots__ = {}.update(TYPE_MAP) 
     158         
     159    def __init__(self, cfg=None): 
     160        '''Initialise settings from an existing config file object or the 
     161        given path to config file 
     162         
     163        @type cfg: SafeConfigParser or string 
     164        @param cfg: config object instance or file path to config file to be 
     165        parsed''' 
     166         
     167        # initialise attributes 
     168        for name, val in BaseSignatureHandler.PROPERTY_DEFAULTS: 
     169            setattr(self, name, val[0])   
     170             
     171        if cfg is not None: 
     172            self.cfg = cfg 
     173                   
     174    def __setattr__(self, name, val): 
     175        """Apply type checking on inputs""" 
     176        allowedType = BaseSignatureHandler.TYPE_MAP.get(name) 
     177        if allowedType: 
     178            if not isinstance(val, allowedType): 
     179                raise TypeError('Allowed type(s) for %r attribute are %r; ' 
     180                                'got %r' % (name, allowedType, type(val))) 
     181             
     182        super(BaseSignatureHandler).__setattr__(name, val) 
     183         
     184    def read(self, filePath): 
     185        '''Read ConfigParser object 
     186         
     187        @type filePath: basestring 
     188        @param filePath: file to read config from''' 
     189         
     190        # Expand environment variables in file path 
     191        expandedFilePath = os.path.expandvars(filePath) 
     192         
     193        # Add 'here' item to enable convenient path substitutions in the config 
     194        # file 
     195        defaultItems = dict(here=os.path.dirname(expandedFilePath)) 
     196        self.cfg.defaultitems().update(defaultItems) 
     197         
     198        readFilePaths = self._cfg.read(expandedFilePath) 
     199         
     200        # Check file was read in OK 
     201        if len(readFilePaths) == 0: 
     202            raise IOError('Missing config file: "%s"' % expandedFilePath) 
     203         
     204    def parse(self, section='DEFAULT', prefix=None, **kw): 
     205        '''Extract items from config file and place in dict 
     206        @type **kw: dict 
     207        @param **kw: this enables WS-Security params to be set in a config file 
     208        with other sections e.g. params could be under the section 'wssecurity' 
    113209        ''' 
    114         @param cfg: object from which to read config items - a file path, 
    115         config parser object or WSSecurityConfig object 
    116         @type cfg: basestring/RawConfigParser/WSSecurityConfig 
    117          
    118         @param cfgFileSection: section name in config file containing  
    119         parameters 
    120         @type cfgFileSection: basestring 
    121          
    122         @param cfgFilePrefix: prefix for parameter names in the config file. 
    123         This enables these parameters to be filtered from other unrelated 
    124         parameters in the same section 
    125         @type cfgFilePrefix: basestring 
    126          
    127         @param cfgClass: class used to parse the settings 
    128         @type cfgClass: WSSecurityConfig derived class type 
    129          
    130         @param kw: any config parameters as specified by WSSecurityConfig class 
    131         @type kw: dict 
    132         ''' 
    133         log.debug("BaseSignatureHandler.__init__ ...") 
    134  
    135         # WSSecurityConfig is the default class for reading config params but 
    136         # alternative derivative class may be passed in instead. 
    137         if not issubclass(cfgClass, WSSecurityConfig): 
    138             raise TypeError("%s is not a sub-class of WSSecurityConfig" %  
    139                             cfgClass) 
    140          
    141         # Read parameters from config file if set 
    142         if isinstance(cfg, basestring): 
    143             log.debug("BaseSignatureHandler.__init__: config file path input " 
    144                       "...") 
    145             self.cfg = cfgClass() 
    146             self.cfg.read(cfg) 
    147             self.cfg.parse(section=cfgFileSection, prefix=cfgFilePrefix) 
    148  
    149         elif isinstance(cfg, RawConfigParser): 
    150             log.debug("BaseSignatureHandler.__init__: config object input ...") 
    151             self.cfg = cfgClass(cfg=cfg) 
    152             self.cfg.parse(section=cfgFileSection, prefix=cfgFilePrefix) 
    153              
    154         elif isinstance(cfg, WSSecurityConfig): 
    155             log.debug("BaseSignatureHandler.__init__:  WSSSecurityConfig " 
    156                       "object input ...") 
    157             self.cfg = cfg 
     210        if prefix: 
     211            optNames = ["%s.%s" % (prefix, optName)  
     212                        for optName in BaseSignatureHandler.PROPERTY_DEFAULTS]  
    158213        else: 
    159             self.cfg = cfgClass() 
     214            optNames = BaseSignatureHandler.PROPERTY_DEFAULTS.keys() 
     215             
     216        nameTypeMap = zip(optNames, BaseSignatureHandler.TYPE_MAP)  
     217            
     218        for optName, expectedType in nameTypeMap: 
     219            # Parameters may be omitted and set later 
     220            if self.cfg.has_option(sectionName, optName): 
     221                getFunc = BaseSignatureHandler.CFG_PARSER_GET_FUNC_MAP.get( 
     222                                                                expectedType) 
     223                val = getFunc(self.cfg, section, optName) 
     224                setattr(self, name, val) 
     225 
     226    def update(self, prefix=None, **kw):    
     227        """Set attributes from a set of keywords or a dictionary""" 
     228        if prefix: 
     229            optNames = ["%s.%s" % (prefix, optName)  
     230                        for optName in BaseSignatureHandler.PROPERTY_DEFAULTS]  
     231        else: 
     232            optNames = BaseSignatureHandler.PROPERTY_DEFAULTS.keys() 
     233             
     234        nameTypeMap = zip(optNames, BaseSignatureHandler.TYPE_MAP)  
     235            
     236        for optName, expectedType in nameTypeMap: 
     237            # Parameters may be omitted and set later 
     238            if optName in kw: 
     239                setattr(self, optName, kw[optName]) 
    160240                 
    161         # Also update config from keywords set  
    162         log.debug("BaseSignatureHandler.__init__: updating config from " 
    163                   "keywords...") 
    164          
    165         # Filter keywords if a prefix is set removing any that don't start with 
    166         # the prefix given 
    167         self.cfg.update(kw, prefix=cfgFilePrefix) 
    168          
    169         # set default value type, if none specified in config file 
    170         if not self.cfg['reqBinSecTokValType']: 
    171             self.cfg['reqBinSecTokValType'] = "X509v3" 
    172              
    173         self.reqBinSecTokValType = self.cfg['reqBinSecTokValType'] 
    174  
    175         # Set keywords for canonicalization of SignedInfo and reference  
    176         # elements 
    177         self.refC14nKw = {'inclusive_namespaces': self.cfg['refC14nInclNS']} 
    178  
    179         self.signedInfoC14nKw = {'inclusive_namespaces':  
    180                                  self.cfg['signedInfoC14nInclNS']} 
    181  
    182         self.verifyingCert = self.cfg['verifyingCert'] 
    183         self.verifyingCertFilePath = self.cfg['verifyingCertFilePath'] 
    184          
    185         self.signingCert = self.cfg['signingCert'] 
    186         self.signingCertFilePath = self.cfg['signingCertFilePath'] 
    187  
    188         self.signingCertChain = self.cfg['signingCertChain'] 
    189               
    190         # MUST be set before _setSigningPriKeyFilePath / _setSigningPriKey 
    191         # are called 
    192         self.signingPriKeyPwd = self.cfg['signingPriKeyPwd'] 
    193          
    194         if self.cfg.get('signingPriKey'): 
    195             # Don't allow None for private key setting 
    196             self.signingPriKey = self.cfg['signingPriKey'] 
    197              
    198         self.signingPriKeyFilePath = self.cfg['signingPriKeyFilePath'] 
    199          
    200         # CA certificate(s) for verification of X.509 certificate used with 
    201         # signature. 
    202         if self.cfg.get('caCertDirPath'): 
    203             self.caCertDirPath = self.cfg['caCertDirPath'] 
    204              
    205         elif self.cfg.get('caCertFilePathList'): 
    206             self.caCertFilePathList = self.cfg['caCertFilePathList'] 
    207          
    208         # Configure signature generation to add/omit a timestamp 
    209         self.addTimestamp = self.cfg['addTimestamp'] 
    210          
    211         # Configure timestamp checking in Signature verification handler 
    212         self.timestampClockSkew = self.cfg['timestampClockSkew'] 
    213         self.timestampMustBeSet = self.cfg['timestampMustBeSet'] 
    214         self.createdElemMustBeSet = self.cfg['createdElemMustBeSet'] 
    215         self.expiresElemMustBeSet = self.cfg['expiresElemMustBeSet'] 
    216          
    217         # set default value, if none specified in config file 
    218         if not self.cfg['applySignatureConfirmation']: 
    219             self.cfg['applySignatureConfirmation'] = False 
    220  
    221         self.applySignatureConfirmation=self.cfg['applySignatureConfirmation'] 
    222         self.b64EncSignatureValue = None 
    223          
    224         log.debug("WSSE Config = %s" % self.cfg) 
    225  
    226                  
    227     def _setReqBinSecTokValType(self, value): 
    228         """Set ValueType attribute for BinarySecurityToken used in a request 
    229           
    230         @type value: string 
    231         @param value: name space for BinarySecurityToken ValueType check 
    232         'binSecTokValType' class variable for supported types.  Input can be  
    233         shortened to binSecTokValType keyword if desired. 
    234         """ 
    235         log.debug("Setting reqBinSecTokValType - to %s" %value) 
    236         if value in self.__class__.binSecTokValType: 
    237             self._reqBinSecTokValType = self.__class__.binSecTokValType[value] 
    238   
    239         elif value in self.__class__.binSecTokValType.values(): 
    240             self._reqBinSecTokValType = value 
    241         else: 
    242             raise WSSecurityError('Request BinarySecurityToken ValueType ' 
    243                                   '"%s" not recognised' % value) 
    244              
    245     def _getReqBinSecTokValType(self): 
    246         """ 
    247         Get ValueType attribute for BinarySecurityToken used in a request 
    248         """ 
    249         log.debug("Getting reqBinSecTokValType value") 
    250         if hasattr(self, '_reqBinSecTokValType'): 
    251             return self._reqBinSecTokValType 
    252         else: 
    253             return "" 
    254          
    255     reqBinSecTokValType = property(fset=_setReqBinSecTokValType, 
    256                                    fget=_getReqBinSecTokValType, 
    257          doc="ValueType attribute for BinarySecurityToken used in request") 
    258          
     241    @classmethod 
     242    def fromKeywords(cls, cfg=None, **kw): 
     243        """Instantiate from attribute values set in a list of keywords""" 
     244        handler = cls(cfg=cfg) 
     245        handler.update(**kw) 
     246        return handler 
     247     
     248    @classmethod 
     249    def fromConfigFile(cls, filePath, cfg=None, **kw): 
     250        """Instantiate from settings in configuration file""" 
     251        handler = cls(cfg=cfg) 
     252        handler.read(filePath) 
     253        handler.parse(**kw) 
     254        return handler        
    259255 
    260256    def __checkC14nKw(self, kw): 
     
    270266        if kw is not None and not isinstance(kw, dict): 
    271267            # Otherwise keywords must be a dictionary 
    272             raise AttributeError("Expecting dictionary type for reference " 
     268            raise TypeError("Expecting dictionary type for reference " 
    273269                                 "C14N keywords") 
    274270                 
    275271        elif kw.get('inclusive_namespaces') and \ 
    276272             not isinstance(kw['inclusive_namespaces'], (list, tuple)): 
    277             raise AttributeError('Expecting list or tuple of prefix names for ' 
     273            raise TypeError('Expecting list or tuple of prefix names for ' 
    278274                                 '"%s" keyword' % 'inclusive_namespaces') 
    279275         
    280                  
    281276    def _setRefC14nKw(self, kw): 
    282277        """Set keywords for canonicalization of reference elements in the  
     
    367362         
    368363        else: 
    369             raise AttributeError("X.509 Cert. must be type: ndg.security." 
     364            raise TypeError("X.509 Cert. must be type: ndg.security." 
    370365                                 "common.X509.X509Cert, M2Crypto.X509.X509 or " 
    371366                                 "a base64 encoded string") 
     
    410405                self._verifyingCert = X509CertRead(verifyingCertFilePath) 
    411406            else: 
    412                 raise AttributeError, "X.509 Cert file path is not a valid string" 
     407                raise TypeError, "X.509 Cert file path is not a valid string" 
    413408         
    414409        self._verifyingCertFilePath = verifyingCertFilePath 
     
    447442             
    448443        elif signingCertFilePath is not None: 
    449             raise AttributeError("Signature X.509 certificate file path must " 
     444            raise TypeError("Signature X.509 certificate file path must " 
    450445                                 "be a valid string") 
    451446         
     
    486481                                doc="Cert.s in chain of trust to cert. used " 
    487482                                    "to verify msg.") 
    488  
    489   
    490     def _setSigningPriKeyPwd(self, signingPriKeyPwd): 
    491         "Set method for private key file password used to sign message" 
    492         if signingPriKeyPwd is not None and \ 
    493            not isinstance(signingPriKeyPwd, basestring): 
    494             raise AttributeError("Signing private key password must be None " 
    495                                  "or a valid string") 
    496          
    497         self._signingPriKeyPwd = signingPriKeyPwd 
    498  
    499     def _getSigningPriKeyPwd(self): 
    500         if hasattr(self, '_signingPriKeyPwd'): 
    501             return self._signingPriKeyPwd 
    502         else: 
    503             return "" 
    504          
    505     signingPriKeyPwd = property(fset=_setSigningPriKeyPwd, 
    506                                 fget=_getSigningPriKeyPwd, 
    507                                 doc="Password protecting private key file " 
    508                                     "used to sign message") 
    509  
    510483  
    511484    def _setSigningPriKey(self, signingPriKey): 
     
    527500                    
    528501        else: 
    529             raise AttributeError("Signing private key must be a valid " 
    530                                   "M2Crypto.RSA.RSA type or a string") 
     502            raise TypeError("Signing private key must be a valid " 
     503                            "M2Crypto.RSA.RSA type or a string") 
    531504                 
    532505    def _getSigningPriKey(self): 
     
    550523                                                        callback=pwdCallback)            
    551524            except Exception, e: 
    552                 raise AttributeError("Setting private key for signature: %s"%e) 
     525                raise TypeError("Setting private key for signature: %s"%e) 
    553526         
    554527        elif signingPriKeyFilePath is not None: 
    555             raise AttributeError("Private key file path must be a valid " 
     528            raise TypeError("Private key file path must be a valid " 
    556529                                 "string or None") 
    557530         
     
    579552        for cert in caCertList: 
    580553            self._caX509Stack.push(cert) 
    581  
    582554 
    583555    def __setCAX509StackFromDir(self, caCertDir): 
     
    592564        reg = re.compile('\d+\.0') 
    593565        try: 
    594             caCertList = [X509CertRead(caFile) \ 
    595                           for caFile in os.listdir(caCertDir) \ 
     566            caCertList = [X509CertRead(caFile)  
     567                          for caFile in os.listdir(caCertDir)  
    596568                          if reg.match(caFile)] 
    597569        except Exception, e: 
     
    632604    caCertFilePathList = property(fset=__setCAX509StackFromCertFileList, 
    633605                      doc="List of CA cert. files used for verification")               
    634          
    635     def _get_timestampClockSkew(self): 
    636         return getattr(self, "_timestampClockSkew", 0.) 
    637  
    638     def _set_timestampClockSkew(self, val): 
    639         if isinstance(val, basestring): 
    640             self._timestampClockSkew = float(val) 
    641              
    642         elif isinstance(val, (float, int)): 
    643             self._timestampClockSkew = val 
    644              
    645         else: 
    646             raise TypeError("Expecting string, float or int type for " 
    647                             "timestampClockSkew attribute, got %r" %  
    648                             getattr(val, "__class__", val)) 
    649          
    650     timestampClockSkew = property(fset=_set_timestampClockSkew, 
    651                                   fget=_get_timestampClockSkew, 
    652                                   doc="adjust the current time calculated by " 
    653                                       "the number of seconds specified in " 
    654                                       "this parameter.  This enables " 
    655                                       "allowance to be made for clock skew " 
    656                                       "between a client and server system " 
    657                                       "clocks.") 
    658606     
    659607    def _setBool(self, val): 
     
    681629            raise TypeError("Invalid type for bool conversion: %r" %  
    682630                            val.__class__) 
    683          
    684     def _get_timestampMustBeSet(self): 
    685         return getattr(self, "_timestampMustBeSet", False) 
    686  
    687     def _set_timestampMustBeSet(self, val): 
    688         self._timestampMustBeSet = self._setBool(val) 
    689          
    690     timestampMustBeSet = property(fset=_set_timestampMustBeSet, 
    691                                   fget=_get_timestampMustBeSet, 
    692                                   doc="Set to True to raise an exception if a " 
    693                                       "message to be verified doesn't have a " 
    694                                       "timestamp element.  Set to False to " 
    695                                       "log a warning message and continue " 
    696                                       "processing") 
    697      
    698     def _get_createdElemMustBeSet(self): 
    699         return getattr(self, "_createdElemMustBeSet", False) 
    700  
    701     def _set_createdElemMustBeSet(self, val): 
    702         self._createdElemMustBeSet = self._setBool(val) 
    703          
    704     createdElemMustBeSet = property(fset=_set_createdElemMustBeSet, 
    705                                     fget=_get_createdElemMustBeSet, 
    706                                     doc="Set to True to raise an exception if " 
    707                                         "a message to be verified doesn't " 
    708                                         "have <wsu:Created/> element with its " 
    709                                         "timestamp element.  Set to False to " 
    710                                         "log a warning message and continue " 
    711                                         "processing") 
    712      
    713     def _get_expiresElemMustBeSet(self): 
    714         return getattr(self, "_expiresElemMustBeSet", False) 
    715  
    716     def _set_expiresElemMustBeSet(self, val): 
    717         self._expiresElemMustBeSet = self._setBool(val) 
    718          
    719     expiresElemMustBeSet = property(fset=_set_expiresElemMustBeSet, 
    720                                     fget=_get_expiresElemMustBeSet, 
    721                                     doc="Set to True to raise an exception if " 
    722                                         "a message to be verified doesn't " 
    723                                         "have <wsu:Expires/> element with its " 
    724                                         "timestamp element.  Set to False to " 
    725                                         "log a warning message and continue " 
    726                                         "processing")                                   
     631                                  
    727632 
    728633                               
  • TI12-security/trunk/WSSecurity/ndg/wssecurity/common/wssecurity/signaturehandler/foursuite.py

    r5771 r6378  
    3636 
    3737from ndg.security.common.wssecurity import WSSecurityError 
    38 from ndg.security.common.wssecurity.signaturehandler import _WSU, OASIS, \ 
    39     BaseSignatureHandler, NoSignatureFound, InvalidSignature, TimestampError, \ 
    40     MessageExpired, VerifyError, SignatureError 
    41  
    42 from ndg.security.common.X509 import X509Cert, X509CertParse, X509CertRead, \ 
    43     X509Stack, X509StackParseFromDER 
     38from ndg.security.common.wssecurity.signaturehandler import (_WSU, OASIS,  
     39    BaseSignatureHandler, NoSignatureFound, InvalidSignature, TimestampError,  
     40    MessageExpired, VerifyError, SignatureError) 
     41 
     42from ndg.security.common.wssecurity.pki import (X509Cert, X509CertParse,  
     43                                                X509CertRead, X509Stack,  
     44                                                X509StackParseFromDER) 
    4445 
    4546 
  • TI12-security/trunk/WSSecurity/ndg/wssecurity/common/wssecurity/utils.py

    r5060 r6378  
    1 """4Suite XML substitution for default DOM parsing and outputting for  
    2 ZSI based services. 
    3  
    4 This code is included for NDG Security code from pyGridWare package by  
    5 permission of the authors.  See copyright notice below. 
    6 """ 
    7 __author__ = "Joshua R. Boverhof, LBNL" 
    8 __date__ = "04/03/09" 
    9 __copyright__ = ( 
    10 "Copyright (c) 2004, The Regents of the University of California, through " 
    11 "Lawrence Berkeley National Laboratory (subject to receipt of any required " 
    12 "approvals from the U.S. Dept. of Energy).  All rights reserved." 
    13 ) 
    14  
    15 __license__ = "BSD - see LICENSE file in top-level directory" 
    16 __contact__ = "Philip.Kershaw@stfc.ac.uk" 
    17 __revision__ = '$Id: $' 
    18 from cStringIO import StringIO 
    19 from string import join, strip, split 
    20  
    21 from xml.dom import Node 
    22 from Ft.Xml.Domlette import NonvalidatingReaderBase, NonvalidatingReader, \ 
    23     CanonicalPrint 
    24 import Ft.Xml.Domlette 
    25 from Ft.Xml import XPath 
    26  
    27 from ZSI.wstools.c14n import Canonicalize 
    28 from ZSI.wstools.Namespaces import SCHEMA, SOAP, XMLNS, DSIG 
    29 from ZSI.wstools.Utility import DOMException, SplitQName 
    30 from ZSI.wstools.Utility import NamespaceError, MessageInterface, ElementProxy 
    31  
    32  
    33 class DomletteReader(NonvalidatingReaderBase): 
    34     '''Used with ZSI.parse.ParsedSoap 
     1class CaseSensitiveConfigParser(SafeConfigParser): 
    352    ''' 
    36     fromString = NonvalidatingReaderBase.parseString 
    37     fromStream = NonvalidatingReaderBase.parseStream 
    38  
    39     def __init__(self, *arg, **kw): 
    40         NonvalidatingReaderBase.__init__(self, *arg, **kw) 
    41         self._context = None 
    42         self.processorNss = None 
    43  
    44  
    45 class DomletteElementProxy(ElementProxy): 
    46     expression_dict = {} 
    47  
    48     def __init__(self, sw, message=None): 
    49         '''Initialize.  
    50            sw -- SoapWriter 
    51         ''' 
    52         ElementProxy.__init__(self, sw, message) 
    53         self._dom = DOM 
    54         self._context = None 
    55  
    56     def evaluate(self, expression, processorNss=None): 
    57         '''expression -- XPath statement or compiled expression. 
    58         ''' 
    59         if isinstance(expression, basestring): 
    60             if not self.expression_dict.has_key(expression): 
    61                 self.expression_dict[expression] =  XPath.Compile(expression) 
    62             expression = self.expression_dict[expression] 
    63  
    64         context = self._context 
    65         if context is None: 
    66             context = XPath.Context.Context(self.node, processorNss=processorNss or self.processorNss) 
    67         result = expression.evaluate(context) 
    68         if type(result) in (list,tuple): 
    69             #return map(lambda node: DomletteElementProxy(self.sw,node), result) 
    70             l = [] 
    71             for node in result: 
    72                 item = node 
    73                 if node.nodeType == Node.ELEMENT_NODE: 
    74                     item = DomletteElementProxy(self.sw,node) 
    75                 #elif node.nodeType == Node.TEXT_NODE: 
    76                 #   item = node.nodeValue 
    77                 # probably dont want to wrap other stuff... 
    78                 l.append(item) 
    79             result = l 
    80         else: 
    81             if node.nodeType == Node.ELEMENT_NODE: 
    82                 result = DomletteElementProxy(self.sw,result) 
    83  
    84         return result 
    85          
    86     def isContextInitialized(self, processorNss=None): 
    87         return self._context is not None 
    88     def setContext(self, processorNss=None): 
    89         self._context = XPath.Context.Context(self.node, processorNss=processorNss or self.processorNss) 
    90  
    91     ############################################# 
    92     # Methods for checking/setting the 
    93     # classes (namespaceURI,name) node.  
    94     ############################################# 
    95     def checkNode(self, namespaceURI=None, localName=None): 
    96         ''' 
    97             namespaceURI -- namespace of element 
    98             localName -- local name of element 
    99         ''' 
    100         namespaceURI = namespaceURI or self.namespaceURI 
    101         localName = localName or self.name 
    102         check = False 
    103         if localName and self.node: 
    104             check = self._dom.isElement(self.node, localName, namespaceURI) 
    105         if not check: 
    106             raise NamespaceError, 'unexpected node type %s, expecting %s' %(self.node, localName) 
    107  
    108     def setNode(self, node=None): 
    109         if node: 
    110             if isinstance(node, DomletteElementProxy): 
    111                 self.node = node._getNode() 
    112             else: 
    113                 self.node = node 
    114         elif self.node: 
    115             node = self._dom.getElement(self.node, self.name, self.namespaceURI, default=None) 
    116             if not node: 
    117                 raise NamespaceError, 'cant find element (%s,%s)' %(self.namespaceURI,self.name) 
    118             self.node = node 
    119         else: 
    120             #self.node = self._dom.create(self.node, self.name, self.namespaceURI, default=None) 
    121             self.createDocument(self.namespaceURI, localName=self.name, doctype=None) 
    122          
    123         self.checkNode() 
    124  
    125     ############################################# 
    126     # Wrapper Methods for direct DOM Element Node access 
    127     ############################################# 
    128     def _getNode(self): 
    129         return self.node 
    130  
    131     def _getElements(self): 
    132         return self._dom.getElements(self.node, name=None) 
    133  
    134     def _getOwnerDocument(self): 
    135         return self.node.ownerDocument or self.node 
    136  
    137     def _getUniquePrefix(self): 
    138         '''I guess we need to resolve all potential prefixes 
    139         because when the current node is attached it copies the  
    140         namespaces into the parent node. 
    141         ''' 
    142         while 1: 
    143             self._indx += 1 
    144             prefix = 'ns%d' %self._indx 
    145             try: 
    146                 self._dom.findNamespaceURI(prefix, self._getNode()) 
    147             except (AttributeError, DOMException), ex: 
    148                 break 
    149         return prefix 
    150  
    151     def _getPrefix(self, node, nsuri): 
    152         ''' 
    153         Keyword arguments: 
    154             node -- DOM Element Node 
    155             nsuri -- namespace of attribute value 
    156         ''' 
    157         try: 
    158             if node and (node.nodeType == node.ELEMENT_NODE) and \ 
    159                 (nsuri == self._dom.findDefaultNS(node)): 
    160                 return None 
    161         except DOMException, ex: 
    162             pass 
    163         if nsuri == XMLNS.XML: 
    164             return self._xml_prefix 
    165         if node.nodeType == Node.ELEMENT_NODE: 
    166             for attr in node.attributes.values(): 
    167                 if attr.namespaceURI == XMLNS.BASE \ 
    168                    and nsuri == attr.value: 
    169                         return attr.localName 
    170             else: 
    171                 if node.parentNode: 
    172                     return self._getPrefix(node.parentNode, nsuri) 
    173         raise NamespaceError, 'namespaceURI "%s" is not defined' %nsuri 
    174  
    175     def _appendChild(self, node): 
    176         ''' 
    177         Keyword arguments: 
    178             node -- DOM Element Node 
    179         ''' 
    180         if node is None: 
    181             raise TypeError, 'node is None' 
    182         self.node.appendChild(node) 
    183  
    184     def _insertBefore(self, newChild, refChild): 
    185         ''' 
    186         Keyword arguments: 
    187             child -- DOM Element Node to insert 
    188             refChild -- DOM Element Node  
    189         ''' 
    190         self.node.insertBefore(newChild, refChild) 
    191  
    192     def _setAttributeNS(self, namespaceURI, qualifiedName, value): 
    193         ''' 
    194         Keyword arguments: 
    195             namespaceURI -- namespace of attribute 
    196             qualifiedName -- qualified name of new attribute value 
    197             value -- value of attribute 
    198         ''' 
    199         self.node.setAttributeNS(namespaceURI, qualifiedName, value) 
    200  
    201     ############################################# 
    202     #General Methods 
    203     ############################################# 
    204     def isFault(self): 
    205         '''check to see if this is a soap:fault message. 
    206         ''' 
    207         return False 
    208  
    209     def getPrefix(self, namespaceURI): 
    210         try: 
    211             prefix = self._getPrefix(node=self.node, nsuri=namespaceURI) 
    212         except NamespaceError, ex: 
    213             prefix = self._getUniquePrefix()  
    214             self.setNamespaceAttribute(prefix, namespaceURI) 
    215         return prefix 
    216  
    217     def getDocument(self): 
    218         return self._getOwnerDocument() 
    219  
    220     def setDocument(self, document): 
    221         self.node = document 
    222  
    223     def importFromString(self, xmlString): 
    224         doc = self._dom.loadDocument(StringIO(xmlString)) 
    225         node = self._dom.getElement(doc, name=None) 
    226         clone = self.importNode(node) 
    227         self._appendChild(clone) 
    228  
    229     def importNode(self, node): 
    230         if isinstance(node, DomletteElementProxy): 
    231             node = node._getNode() 
    232         return self._dom.importNode(self._getOwnerDocument(), node, deep=1) 
    233  
    234     def loadFromString(self, data): 
    235         self.node = self._dom.loadDocument(StringIO(data)) 
    236  
    237 #    def canonicalize(self, algorithm=DSIG.C14N, unsuppressedPrefixes=[]): 
    238 #        if algorithm == DSIG.C14N_EXCL: 
    239 #            return Canonicalize(self.node, unsuppressedPrefixes=unsuppressedPrefixes) 
    240 #        else: 
    241 #            return Canonicalize(self.node) 
    242  
    243     def canonicalize(self, algorithm=DSIG.C14N, unsuppressedPrefixes=[]): 
    244         '''4Suite-XML based canonicalization''' 
    245         f = StringIO() 
    246         if algorithm == DSIG.C14N_EXCL: 
    247             CanonicalPrint(self.node, stream=f, exclusive=True, 
    248                            inclusivePrefixes=unsuppressedPrefixes) 
    249         else: 
    250             CanonicalPrint(self.node, stream=f) 
    251  
    252         c14n = f.getvalue() 
    253         return c14n 
    254  
    255     def toString(self): 
    256         s = StringIO() 
    257         FastPrint(self.node, output=s) 
    258         return s.getvalue() 
    259  
    260     def createDocument(self, namespaceURI, localName, doctype=None): 
    261         prefix = self._soap_env_prefix 
    262         if namespaceURI == self.reserved_ns[prefix]: 
    263             qualifiedName = '%s:%s' %(prefix,localName) 
    264         elif namespaceURI is localName is None: 
    265             self.node = self._dom.createDocument(None,None,None) 
    266             return 
    267         else: 
    268             raise KeyError, 'only support creation of document in %s' %self.reserved_ns[prefix] 
    269  
    270         qualifiedName = '%s:%s' %(prefix,localName) 
    271         document = self._dom.createDocument(nsuri=namespaceURI, qname=qualifiedName, doctype=doctype) 
    272         self.node = document.childNodes[0] 
    273  
    274         #set up reserved namespace attributes 
    275         for prefix,nsuri in self.reserved_ns.items(): 
    276             self._setAttributeNS(namespaceURI=self._xmlns_nsuri,  
    277                 qualifiedName='%s:%s' %(self._xmlns_prefix,prefix),  
    278                 value=nsuri) 
    279  
    280     ############################################# 
    281     #Methods for attributes 
    282     ############################################# 
    283     def hasAttribute(self, namespaceURI, localName): 
    284         return self._dom.hasAttr(self._getNode(), name=localName, nsuri=namespaceURI) 
    285  
    286     def setAttributeType(self, namespaceURI, localName): 
    287         '''set xsi:type 
    288         Keyword arguments: 
    289             namespaceURI -- namespace of attribute value 
    290             localName -- name of new attribute value 
    291  
    292         ''' 
    293         self.logger.debug('setAttributeType: (%s,%s)', namespaceURI, localName) 
    294         value = localName 
    295         if namespaceURI: 
    296             value = '%s:%s' %(self.getPrefix(namespaceURI),localName) 
    297         self._setAttributeNS(self._xsi_nsuri, '%s:type' %self._xsi_prefix, value) 
    298  
    299     def createAttributeNS(self, namespace, name, value): 
    300         document = self._getOwnerDocument() 
    301         attrNode = document.createAttributeNS(namespace, name, value) 
    302  
    303     def setAttributeNS(self, namespaceURI, localName, value): 
    304         ''' 
    305         Keyword arguments: 
    306             namespaceURI -- namespace of attribute to create, None is for 
    307                 attributes in no namespace. 
    308             localName -- local name of new attribute 
    309             value -- value of new attribute 
    310         '''  
    311         prefix = None 
    312         if namespaceURI: 
    313             try: 
    314                 prefix = self.getPrefix(namespaceURI) 
    315             except KeyError, ex: 
    316                 prefix = 'ns2' 
    317                 self.setNamespaceAttribute(prefix, namespaceURI) 
    318         qualifiedName = localName 
    319         if prefix: 
    320             qualifiedName = '%s:%s' %(prefix, localName) 
    321         self._setAttributeNS(namespaceURI, qualifiedName, value) 
    322  
    323     def setNamespaceAttribute(self, prefix, namespaceURI): 
    324         ''' 
    325         Keyword arguments: 
    326             prefix -- xmlns prefix 
    327             namespaceURI -- value of prefix 
    328         ''' 
    329         self._setAttributeNS(XMLNS.BASE, 'xmlns:%s' %prefix, namespaceURI) 
    330  
    331     ############################################# 
    332     #Methods for elements 
    333     ############################################# 
    334     def createElementNS(self, namespace, qname): 
    335         ''' 
    336         Keyword arguments: 
    337             namespace -- namespace of element to create 
    338             qname -- qualified name of new element 
    339         ''' 
    340         document = self._getOwnerDocument() 
    341         node = document.createElementNS(namespace, qname) 
    342         return DomletteElementProxy(self.sw, node) 
    343  
    344     def createAppendSetElement(self, namespaceURI, localName, prefix=None): 
    345         '''Create a new element (namespaceURI,name), append it 
    346            to current node, then set it to be the current node. 
    347         Keyword arguments: 
    348             namespaceURI -- namespace of element to create 
    349             localName -- local name of new element 
    350             prefix -- if namespaceURI is not defined, declare prefix.  defaults 
    351                 to 'ns1' if left unspecified. 
    352         ''' 
    353         node = self.createAppendElement(namespaceURI, localName, prefix=None) 
    354         node=node._getNode() 
    355         self._setNode(node._getNode()) 
    356  
    357     def createAppendElement(self, namespaceURI, localName, prefix=None): 
    358         '''Create a new element (namespaceURI,name), append it 
    359            to current node, and return the newly created node. 
    360         Keyword arguments: 
    361             namespaceURI -- namespace of element to create 
    362             localName -- local name of new element 
    363             prefix -- if namespaceURI is not defined, declare prefix.  defaults 
    364                 to 'ns1' if left unspecified. 
    365         ''' 
    366         declare = False 
    367         qualifiedName = localName 
    368         if namespaceURI: 
    369             try: 
    370                 prefix = self.getPrefix(namespaceURI) 
    371             except: 
    372                 declare = True 
    373                 prefix = prefix or self._getUniquePrefix() 
    374             if prefix:  
    375                 qualifiedName = '%s:%s' %(prefix, localName) 
    376         node = self.createElementNS(namespaceURI, qualifiedName) 
    377         if declare: 
    378             node._setAttributeNS(XMLNS.BASE, 'xmlns:%s' %prefix, namespaceURI) 
    379         self._appendChild(node=node._getNode()) 
    380         return node 
    381  
    382     def createInsertBefore(self, namespaceURI, localName, refChild): 
    383         qualifiedName = localName 
    384         prefix = self.getPrefix(namespaceURI) 
    385         if prefix:  
    386             qualifiedName = '%s:%s' %(prefix, localName) 
    387         node = self.createElementNS(namespaceURI, qualifiedName) 
    388         self._insertBefore(newChild=node._getNode(), refChild=refChild._getNode()) 
    389         return node 
    390  
    391     def getElement(self, namespaceURI, localName): 
    392         ''' 
    393         Keyword arguments: 
    394             namespaceURI -- namespace of element 
    395             localName -- local name of element 
    396         ''' 
    397         node = self._dom.getElement(self.node, localName, namespaceURI, default=None) 
    398         if node: 
    399             return DomletteElementProxy(self.sw, node) 
    400         return None 
    401  
    402     def getElements(self, namespaceURI=None, localName=None): 
    403         ''' 
    404          Keyword arguments: 
    405             namespaceURI -- namespace of element 
    406             localName -- local name of element 
    407         ''' 
    408         nodes = self._dom.getElements(self.node,localName, namespaceURI) 
    409         nodesList = [] 
    410         if nodes: 
    411             for node in nodes: 
    412                 nodesList.append(DomletteElementProxy(self.sw, node)) 
    413  
    414         return nodesList 
    415                                   
    416     def getAttributeValue(self, namespaceURI, localName): 
    417         ''' 
    418         Keyword arguments: 
    419             namespaceURI -- namespace of attribute 
    420             localName -- local name of attribute 
    421         ''' 
    422         if self.hasAttribute(namespaceURI, localName): 
    423             attr = self.node.getAttributeNodeNS(namespaceURI,localName) 
    424             return attr.value 
    425         return None 
    426  
    427     def getValue(self): 
    428         return self._dom.getElementText(self.node, preserve_ws=True)     
    429  
    430     ############################################# 
    431     #Methods for text nodes 
    432     ############################################# 
    433     def createAppendTextNode(self, pyobj): 
    434         node = self.createTextNode(pyobj) 
    435         self._appendChild(node=node._getNode()) 
    436         return node 
    437  
    438     def createTextNode(self, pyobj): 
    439         document = self._getOwnerDocument() 
    440         node = document.createTextNode(pyobj) 
    441         return DomletteElementProxy(self.sw, node) 
    442  
    443     ############################################# 
    444     #Methods for retrieving namespaceURI's 
    445     ############################################# 
    446     def findNamespaceURI(self, qualifiedName): 
    447         parts = SplitQName(qualifiedName) 
    448         element = self._getNode() 
    449         if len(parts) == 1: 
    450             return (self._dom.findTargetNS(element), value) 
    451         return self._dom.findNamespaceURI(parts[0], element) 
    452  
    453     def resolvePrefix(self, prefix): 
    454         element = self._getNode() 
    455         return self._dom.findNamespaceURI(prefix, element) 
    456  
    457     def getSOAPEnvURI(self): 
    458         return self._soap_env_nsuri 
    459  
    460     def isEmpty(self): 
    461         return not self.node 
    462  
    463  
    464 class DOM: 
    465     """The DOM singleton defines a number of XML related constants and 
    466        provides a number of utility methods for DOM related tasks. It 
    467        also provides some basic abstractions so that the rest of the 
    468        package need not care about actual DOM implementation in use.""" 
    469  
    470     # Namespace stuff related to the SOAP specification. 
    471  
    472     NS_SOAP_ENV_1_1 = 'http://schemas.xmlsoap.org/soap/envelope/' 
    473     NS_SOAP_ENC_1_1 = 'http://schemas.xmlsoap.org/soap/encoding/' 
    474  
    475     NS_SOAP_ENV_1_2 = 'http://www.w3.org/2001/06/soap-envelope' 
    476     NS_SOAP_ENC_1_2 = 'http://www.w3.org/2001/06/soap-encoding' 
    477  
    478     NS_SOAP_ENV_ALL = (NS_SOAP_ENV_1_1, NS_SOAP_ENV_1_2) 
    479     NS_SOAP_ENC_ALL = (NS_SOAP_ENC_1_1, NS_SOAP_ENC_1_2) 
    480  
    481     NS_SOAP_ENV = NS_SOAP_ENV_1_1 
    482     NS_SOAP_ENC = NS_SOAP_ENC_1_1 
    483  
    484     _soap_uri_mapping = { 
    485         NS_SOAP_ENV_1_1 : '1.1', 
    486         NS_SOAP_ENV_1_2 : '1.2', 
    487     } 
    488  
    489     SOAP_ACTOR_NEXT_1_1 = 'http://schemas.xmlsoap.org/soap/actor/next' 
    490     SOAP_ACTOR_NEXT_1_2 = 'http://www.w3.org/2001/06/soap-envelope/actor/next' 
    491     SOAP_ACTOR_NEXT_ALL = (SOAP_ACTOR_NEXT_1_1, SOAP_ACTOR_NEXT_1_2) 
    492      
    493     def SOAPUriToVersion(self, uri): 
    494         """Return the SOAP version related to an envelope uri.""" 
    495         value = self._soap_uri_mapping.get(uri) 
    496         if value is not None: 
    497             return value 
    498         raise ValueError( 
    499             'Unsupported SOAP envelope uri: %s' % uri 
    500             ) 
    501  
    502     def GetSOAPEnvUri(self, version): 
    503         """Return the appropriate SOAP envelope uri for a given 
    504            human-friendly SOAP version string (e.g. '1.1').""" 
    505         attrname = 'NS_SOAP_ENV_%s' % join(split(version, '.'), '_') 
    506         value = getattr(self, attrname, None) 
    507         if value is not None: 
    508             return value 
    509         raise ValueError( 
    510             'Unsupported SOAP version: %s' % version 
    511             ) 
    512  
    513     def GetSOAPEncUri(self, version): 
    514         """Return the appropriate SOAP encoding uri for a given 
    515            human-friendly SOAP version string (e.g. '1.1').""" 
    516         attrname = 'NS_SOAP_ENC_%s' % join(split(version, '.'), '_') 
    517         value = getattr(self, attrname, None) 
    518         if value is not None: 
    519             return value 
    520         raise ValueError( 
    521             'Unsupported SOAP version: %s' % version 
    522             ) 
    523  
    524     def GetSOAPActorNextUri(self, version): 
    525         """Return the right special next-actor uri for a given 
    526            human-friendly SOAP version string (e.g. '1.1').""" 
    527         attrname = 'SOAP_ACTOR_NEXT_%s' % join(split(version, '.'), '_') 
    528         value = getattr(self, attrname, None) 
    529         if value is not None: 
    530             return value 
    531         raise ValueError( 
    532             'Unsupported SOAP version: %s' % version 
    533             ) 
    534  
    535  
    536     # Namespace stuff related to XML Schema. 
    537  
    538     NS_XSD_99 = 'http://www.w3.org/1999/XMLSchema' 
    539     NS_XSI_99 = 'http://www.w3.org/1999/XMLSchema-instance'     
    540  
    541     NS_XSD_00 = 'http://www.w3.org/2000/10/XMLSchema' 
    542     NS_XSI_00 = 'http://www.w3.org/2000/10/XMLSchema-instance'     
    543  
    544     NS_XSD_01 = 'http://www.w3.org/2001/XMLSchema' 
    545     NS_XSI_01 = 'http://www.w3.org/2001/XMLSchema-instance' 
    546  
    547     NS_XSD_ALL = (NS_XSD_99, NS_XSD_00, NS_XSD_01) 
    548     NS_XSI_ALL = (NS_XSI_99, NS_XSI_00, NS_XSI_01) 
    549  
    550     NS_XSD = NS_XSD_01 
    551     NS_XSI = NS_XSI_01 
    552  
    553     _xsd_uri_mapping = { 
    554         NS_XSD_99 : NS_XSI_99, 
    555         NS_XSD_00 : NS_XSI_00, 
    556         NS_XSD_01 : NS_XSI_01, 
    557     } 
    558  
    559     for key, value in _xsd_uri_mapping.items(): 
    560         _xsd_uri_mapping[value] = key 
    561  
    562  
    563     def InstanceUriForSchemaUri(self, uri): 
    564         """Return the appropriate matching XML Schema instance uri for 
    565            the given XML Schema namespace uri.""" 
    566         return self._xsd_uri_mapping.get(uri) 
    567  
    568     def SchemaUriForInstanceUri(self, uri): 
    569         """Return the appropriate matching XML Schema namespace uri for 
    570            the given XML Schema instance namespace uri.""" 
    571         return self._xsd_uri_mapping.get(uri) 
    572  
    573  
    574     # Namespace stuff related to WSDL. 
    575  
    576     NS_WSDL_1_1 = 'http://schemas.xmlsoap.org/wsdl/' 
    577     NS_WSDL_ALL = (NS_WSDL_1_1,) 
    578     NS_WSDL = NS_WSDL_1_1 
    579  
    580     NS_SOAP_BINDING_1_1 = 'http://schemas.xmlsoap.org/wsdl/soap/' 
    581     NS_HTTP_BINDING_1_1 = 'http://schemas.xmlsoap.org/wsdl/http/' 
    582     NS_MIME_BINDING_1_1 = 'http://schemas.xmlsoap.org/wsdl/mime/' 
    583  
    584     NS_SOAP_BINDING_ALL = (NS_SOAP_BINDING_1_1,) 
    585     NS_HTTP_BINDING_ALL = (NS_HTTP_BINDING_1_1,) 
    586     NS_MIME_BINDING_ALL = (NS_MIME_BINDING_1_1,) 
    587  
    588     NS_SOAP_BINDING = NS_SOAP_BINDING_1_1 
    589     NS_HTTP_BINDING = NS_HTTP_BINDING_1_1 
    590     NS_MIME_BINDING = NS_MIME_BINDING_1_1 
    591  
    592     NS_SOAP_HTTP_1_1 = 'http://schemas.xmlsoap.org/soap/http' 
    593     NS_SOAP_HTTP_ALL = (NS_SOAP_HTTP_1_1,) 
    594     NS_SOAP_HTTP = NS_SOAP_HTTP_1_1 
    595      
    596  
    597     _wsdl_uri_mapping = { 
    598         NS_WSDL_1_1 : '1.1', 
    599     } 
    600      
    601     def WSDLUriToVersion(self, uri): 
    602         """Return the WSDL version related to a WSDL namespace uri.""" 
    603         value = self._wsdl_uri_mapping.get(uri) 
    604         if value is not None: 
    605             return value 
    606         raise ValueError( 
    607             'Unsupported SOAP envelope uri: %s' % uri 
    608             ) 
    609  
    610     def GetWSDLUri(self, version): 
    611         attr = 'NS_WSDL_%s' % join(split(version, '.'), '_') 
    612         value = getattr(self, attr, None) 
    613         if value is not None: 
    614             return value 
    615         raise ValueError( 
    616             'Unsupported WSDL version: %s' % version 
    617             ) 
    618  
    619     def GetWSDLSoapBindingUri(self, version): 
    620         attr = 'NS_SOAP_BINDING_%s' % join(split(version, '.'), '_') 
    621         value = getattr(self, attr, None) 
    622         if value is not None: 
    623             return value 
    624         raise ValueError( 
    625             'Unsupported WSDL version: %s' % version 
    626             ) 
    627  
    628     def GetWSDLHttpBindingUri(self, version): 
    629         attr = 'NS_HTTP_BINDING_%s' % join(split(version, '.'), '_') 
    630         value = getattr(self, attr, None) 
    631         if value is not None: 
    632             return value 
    633         raise ValueError( 
    634             'Unsupported WSDL version: %s' % version 
    635             ) 
    636  
    637     def GetWSDLMimeBindingUri(self, version): 
    638         attr = 'NS_MIME_BINDING_%s' % join(split(version, '.'), '_') 
    639         value = getattr(self, attr, None) 
    640         if value is not None: 
    641             return value 
    642         raise ValueError( 
    643             'Unsupported WSDL version: %s' % version 
    644             ) 
    645  
    646     def GetWSDLHttpTransportUri(self, version): 
    647         attr = 'NS_SOAP_HTTP_%s' % join(split(version, '.'), '_') 
    648         value = getattr(self, attr, None) 
    649         if value is not None: 
    650             return value 
    651         raise ValueError( 
    652             'Unsupported WSDL version: %s' % version 
    653             ) 
    654  
    655  
    656     # Other xml namespace constants. 
    657     NS_XMLNS     = 'http://www.w3.org/2000/xmlns/' 
    658  
    659  
    660  
    661     def isElement(self, node, name, nsuri=None): 
    662         """Return true if the given node is an element with the given 
    663            name and optional namespace uri.""" 
    664         if node.nodeType != node.ELEMENT_NODE: 
    665             return 0 
    666         return node.localName == name and \ 
    667                (nsuri is None or self.nsUriMatch(node.namespaceURI, nsuri)) 
    668  
    669     def getElement(self, node, name, nsuri=None, default=join): 
    670         """Return the first child of node with a matching name and 
    671            namespace uri, or the default if one is provided.""" 
    672         nsmatch = self.nsUriMatch 
    673         ELEMENT_NODE = node.ELEMENT_NODE 
    674         for child in node.childNodes: 
    675             if child.nodeType == ELEMENT_NODE: 
    676                 if ((child.localName == name or name is None) and 
    677                     (nsuri is None or nsmatch(child.namespaceURI, nsuri)) 
    678                     ): 
    679                     return child 
    680         if default is not join: 
    681             return default 
    682         raise KeyError, name 
    683  
    684     def getElementById(self, node, id, default=join): 
    685         """Return the first child of node matching an id reference.""" 
    686         attrget = self.getAttr 
    687         ELEMENT_NODE = node.ELEMENT_NODE 
    688         for child in node.childNodes: 
    689             if child.nodeType == ELEMENT_NODE: 
    690                 if attrget(child, 'id') == id: 
    691                     return child 
    692         if default is not join: 
    693             return default 
    694         raise KeyError, name 
    695  
    696     def getMappingById(self, document, depth=None, element=None, 
    697                        mapping=None, level=1): 
    698         """Create an id -> element mapping of those elements within a 
    699            document that define an id attribute. The depth of the search 
    700            may be controlled by using the (1-based) depth argument.""" 
    701         if document is not None: 
    702             element = document.documentElement 
    703             mapping = {} 
    704         attr = element._attrs.get('id', None) 
    705         if attr is not None: 
    706             mapping[attr.value] = element 
    707         if depth is None or depth > level: 
    708             level = level + 1 
    709             ELEMENT_NODE = element.ELEMENT_NODE 
    710             for child in element.childNodes: 
    711                 if child.nodeType == ELEMENT_NODE: 
    712                     self.getMappingById(None, depth, child, mapping, level) 
    713         return mapping         
    714  
    715     def getElements(self, node, name, nsuri=None): 
    716         """Return a sequence of the child elements of the given node that 
    717            match the given name and optional namespace uri.""" 
    718         nsmatch = self.nsUriMatch 
    719         result = [] 
    720         ELEMENT_NODE = node.ELEMENT_NODE 
    721         for child in node.childNodes: 
    722             if child.nodeType == ELEMENT_NODE: 
    723                 if ((child.localName == name or name is None) and ( 
    724                     (nsuri is None) or nsmatch(child.namespaceURI, nsuri))): 
    725                     result.append(child) 
    726         return result 
    727  
    728     def hasAttr(self, node, name, nsuri=None): 
    729         """Return true if element has attribute with the given name and 
    730            optional nsuri. If nsuri is not specified, returns true if an 
    731            attribute exists with the given name with any namespace.""" 
    732         return node.hasAttributeNS(nsuri, name) 
    733  
    734     def getAttr(self, node, name, nsuri=None, default=join): 
    735         """Return the value of the attribute named 'name' with the 
    736            optional nsuri, or the default if one is specified. If 
    737            nsuri is not specified, an attribute that matches the 
    738            given name will be returned regardless of namespace.""" 
    739         result = node.getAttributeNS(nsuri,name) 
    740         if result is not None and result != '': 
    741             return result 
    742         if default is not join: 
    743             return default 
    744         return '' 
    745  
    746     def getAttrs(self, node): 
    747         """Return a Collection of all attributes  
    748         """ 
    749         attrs = {} 
    750         for k,v in node._attrs.items(): 
    751             attrs[k] = v.value 
    752         return attrs 
    753  
    754     def getElementText(self, node, preserve_ws=None): 
    755         """Return the text value of an xml element node. Leading and trailing 
    756            whitespace is stripped from the value unless the preserve_ws flag 
    757            is passed with a true value.""" 
    758         result = [] 
    759         for child in node.childNodes: 
    760             nodetype = child.nodeType 
    761             if nodetype == child.TEXT_NODE or \ 
    762                nodetype == child.CDATA_SECTION_NODE: 
    763                 result.append(child.nodeValue) 
    764         value = join(result, '') 
    765         if preserve_ws is None: 
    766             value = strip(value) 
    767         return value 
    768  
    769     def findNamespaceURI(self, prefix, node): 
    770         """Find a namespace uri given a prefix and a context node.""" 
    771         attrkey = (self.NS_XMLNS, prefix) 
    772         DOCUMENT_NODE = node.DOCUMENT_NODE 
    773         ELEMENT_NODE = node.ELEMENT_NODE 
    774         while 1: 
    775             if node.nodeType != ELEMENT_NODE: 
    776                 node = node.parentNode 
    777                 continue 
    778             #result = node._attrsNS.get(attrkey, None) 
    779             #if result is not None: 
    780             #    return result.value 
    781             result = node.getAttributeNS(*attrkey) 
    782             if result != '': 
    783                 return result 
    784  
    785             if hasattr(node, '__imported__'): 
    786                 raise DOMException('Value for prefix %s not found.' % prefix) 
    787             node = node.parentNode 
    788             if node.nodeType == DOCUMENT_NODE: 
    789                 raise DOMException('Value for prefix %s not found.' % prefix) 
    790  
    791     def findDefaultNS(self, node): 
    792         """Return the current default namespace uri for the given node.""" 
    793         attrkey = (self.NS_XMLNS, 'xmlns') 
    794         DOCUMENT_NODE = node.DOCUMENT_NODE 
    795         ELEMENT_NODE = node.ELEMENT_NODE 
    796         while 1: 
    797             if node.nodeType != ELEMENT_NODE: 
    798                 node = node.parentNode 
    799                 continue 
    800             #result = node._attrsNS.get(attrkey, None) 
    801             #if result is not None: 
    802             #    return result.value 
    803             result = node.getAttributeNS(*attrkey) 
    804             if result != '': 
    805                 return result 
    806  
    807             if hasattr(node, '__imported__'): 
    808                 raise DOMException('Cannot determine default namespace.') 
    809             node = node.parentNode 
    810             if node.nodeType == DOCUMENT_NODE: 
    811                 raise DOMException('Cannot determine default namespace.') 
    812  
    813     def findTargetNS(self, node): 
    814         """Return the defined target namespace uri for the given node.""" 
    815         attrget = self.getAttr 
    816         attrkey = (self.NS_XMLNS, 'xmlns') 
    817         DOCUMENT_NODE = node.DOCUMENT_NODE 
    818         ELEMENT_NODE = node.ELEMENT_NODE 
    819         while 1: 
    820             if node.nodeType != ELEMENT_NODE: 
    821                 node = node.parentNode 
    822                 continue 
    823             result = attrget(node, 'targetNamespace', default=None) 
    824             if result is not None: 
    825                 return result 
    826             node = node.parentNode 
    827             if node.nodeType == DOCUMENT_NODE: 
    828                 raise DOMException('Cannot determine target namespace.') 
    829  
    830     def getTypeRef(self, element): 
    831         """Return (namespaceURI, name) for a type attribue of the given 
    832            element, or None if the element does not have a type attribute.""" 
    833         typeattr = self.getAttr(element, 'type', default=None) 
    834         if typeattr is None: 
    835             return None 
    836         parts = typeattr.split(':', 1) 
    837         if len(parts) == 2: 
    838             nsuri = self.findNamespaceURI(parts[0], element) 
    839         else: 
    840             nsuri = self.findDefaultNS(element) 
    841         return (nsuri, parts[1]) 
    842  
    843     def importNode(self, document, node, deep=0): 
    844         """Implements (well enough for our purposes) DOM node import.""" 
    845         nodetype = node.nodeType 
    846         if nodetype in (node.DOCUMENT_NODE, node.DOCUMENT_TYPE_NODE): 
    847             raise DOMException('Illegal node type for importNode') 
    848         if nodetype == node.ENTITY_REFERENCE_NODE: 
    849             deep = 0 
    850         clone = node.cloneNode(deep) 
    851         self._setOwnerDoc(document, clone) 
    852         clone.__imported__ = 1 
    853         return clone 
    854  
    855     def _setOwnerDoc(self, document, node): 
    856         node.ownerDocument = document 
    857         for child in node.childNodes: 
    858             self._setOwnerDoc(document, child) 
    859  
    860     def nsUriMatch(self, value, wanted, strict=0, tt=type(())): 
    861         """Return a true value if two namespace uri values match.""" 
    862         if value == wanted or (type(wanted) is tt) and value in wanted: 
    863             return 1 
    864         if not strict: 
    865             wanted = type(wanted) is tt and wanted or (wanted,) 
    866             value = value[-1:] != '/' and value or value[:-1] 
    867             for item in wanted: 
    868                 if item == value or item[:-1] == value: 
    869                     return 1 
    870         return 0 
    871  
    872     def createDocument(self, nsuri, qname, doctype=None): 
    873         """Create a new writable DOM document object.""" 
    874         #impl = xml.dom.minidom.getDOMImplementation() 
    875         impl = Ft.Xml.Domlette.implementation 
    876         return impl.createDocument(nsuri, qname, doctype) 
    877  
    878     def loadDocument(self, data): 
    879         """Load an xml file from a file-like object and return a DOM 
    880            document instance.""" 
    881         #return xml.dom.minidom.parse(data) 
    882         return NonvalidatingReader.parseStream(data) 
    883  
    884     def loadFromURL(self, url): 
    885         """Load an xml file from a URL and return a DOM document.""" 
    886         file = urlopen(url) 
    887         try:     result = self.loadDocument(file) 
    888         finally: file.close() 
    889         return result 
    890  
    891     def unlink(self, document): 
    892         """When you are finished with a DOM, you should clean it up.  
    893         This is necessary because some versions of Python do not support  
    894         garbage collection of objects that refer to each other in a cycle.  
    895         Until this restriction is removed from all versions of Python, it  
    896         is safest to write your code as if cycles would not be cleaned up.""" 
    897         #if hasattr(document, 'unlink'): 
    898         #    document.unlink() 
    899         return 
    900  
    901 DOM = DOM() 
    902  
    903  
    904 """ 
    905 Some code from c14n modified to not do sorting.   
    906 ~30% faster than c14n.Canonicalize 
    907 ~12% faster than Ft.Xml.Domlette.Print 
    908  
    909     --Ft.Xml.Domlette.Print(self.node, stream=s) 
    910     This function produces XML with a different canonical form 
    911     from the source. 
    912 """ 
    913 _attrs = lambda E: (E.attributes and E.attributes.values()) or [] 
    914 _children = lambda E: E.childNodes or [] 
    915 _IN_XML_NS = lambda n: n.namespaceURI == XMLNS.XML 
    916 _LesserElement, _Element, _GreaterElement = range(3) 
    917  
    918 def _utilized(n, node, other_attrs, unsuppressedPrefixes): 
    919     '''_utilized(n, node, other_attrs, unsuppressedPrefixes) -> boolean 
    920     Return true if that nodespace is utilized within the node''' 
    921  
    922     if n.startswith('xmlns:'): 
    923         n = n[6:] 
    924     elif n.startswith('xmlns'): 
    925         n = n[5:] 
    926     if n == node.prefix or n in unsuppressedPrefixes: return 1 
    927     for attr in other_attrs: 
    928         if n == attr.prefix: return 1 
    929     return 0 
    930  
    931 _in_subset = lambda subset, node: not subset or node in subset 
    932  
    933 class _implementation: 
    934     '''Implementation class for C14N. This accompanies a node during it's 
    935     processing and includes the parameters and processing state.''' 
    936  
    937     # Handler for each node type; populated during module instantiation. 
    938     handlers = {} 
    939  
    940     def __init__(self, node, write, **kw): 
    941         '''Create and run the implementation.''' 
    942  
    943         self.write = write 
    944         self.subset = kw.get('subset') 
    945         if self.subset: 
    946             self.comments = kw.get('comments', 1) 
    947         else: 
    948             self.comments = kw.get('comments', 0) 
    949         self.unsuppressedPrefixes = kw.get('unsuppressedPrefixes') 
    950         nsdict = kw.get('nsdict', { 'xml': XMLNS.XML, 'xmlns': XMLNS.BASE }) 
    951  
    952         # Processing state. 
    953         self.state = (nsdict, ['xml'], []) 
    954  
    955         #ATTRIBUTE_NODE 
    956         #CDATA_SECTION_NODE 
    957         #COMMENT_NODE 
    958         #DOCUMENT_FRAGMENT_NODE 
    959         #DOCUMENT_NODE 
    960         #DOCUMENT_TYPE_NODE 
    961         #ELEMENT_NODE 
    962         #ENTITY_NODE 
    963         #ENTITY_REFERENCE_NODE 
    964         #NOTATION_NODE 
    965         #PROCESSING_INSTRUCTION_NODE 
    966         #TEXT_NODE 
    967         #TREE_POSITION_SAME_NODE 
    968         if node.nodeType == Node.DOCUMENT_NODE: 
    969             self._do_document(node) 
    970         elif node.nodeType == Node.ELEMENT_NODE: 
    971             self.documentOrder = _Element        # At document element 
    972             if self.unsuppressedPrefixes is not None: 
    973                 self._do_element(node) 
    974             else: 
    975                 inherited = self._inherit_context(node) 
    976                 self._do_element(node, inherited) 
    977         elif node.nodeType == Node.DOCUMENT_TYPE_NODE: 
    978             pass 
    979         else: 
    980             raise TypeError, str(node) 
    981  
    982  
    983     def _inherit_context(self, node): 
    984         '''_inherit_context(self, node) -> list 
    985         Scan ancestors of attribute and namespace context.  Used only 
    986         for single element node canonicalization, not for subset 
    987         canonicalization.''' 
    988  
    989         # Collect the initial list of xml:foo attributes. 
    990         xmlattrs = filter(_IN_XML_NS, _attrs(node)) 
    991  
    992         # Walk up and get all xml:XXX attributes we inherit. 
    993         inherited, parent = [], node.parentNode 
    994         while parent and parent.nodeType == Node.ELEMENT_NODE: 
    995             for a in filter(_IN_XML_NS, _attrs(parent)): 
    996                 n = a.localName 
    997                 if n not in xmlattrs: 
    998                     xmlattrs.append(n) 
    999                     inherited.append(a) 
    1000             parent = parent.parentNode 
    1001         return inherited 
    1002  
    1003  
    1004     def _do_document(self, node): 
    1005         '''_do_document(self, node) -> None 
    1006         Process a document node. documentOrder holds whether the document 
    1007         element has been encountered such that PIs/comments can be written 
    1008         as specified.''' 
    1009  
    1010         self.documentOrder = _LesserElement 
    1011         for child in node.childNodes: 
    1012             if child.nodeType == Node.ELEMENT_NODE: 
    1013                 self.documentOrder = _Element        # At document element 
    1014                 self._do_element(child) 
    1015                 self.documentOrder = _GreaterElement # After document element 
    1016             elif child.nodeType == Node.PROCESSING_INSTRUCTION_NODE: 
    1017                 self._do_pi(child) 
    1018             elif child.nodeType == Node.COMMENT_NODE: 
    1019                 self._do_comment(child) 
    1020             elif child.nodeType == Node.DOCUMENT_TYPE_NODE: 
    1021                 pass 
    1022             else: 
    1023                 raise TypeError, str(child) 
    1024     handlers[Node.DOCUMENT_NODE] = _do_document 
    1025  
    1026  
    1027     def _do_text(self, node): 
    1028         '''_do_text(self, node) -> None 
    1029         Process a text or CDATA node.  Render various special characters 
    1030         as their C14N entity representations.''' 
    1031         if not _in_subset(self.subset, node): return 
    1032         s = node.data \ 
    1033                 .replace("&", "&amp;") \ 
    1034                 .replace("<", "&lt;") \ 
    1035                 .replace(">", "&gt;") \ 
    1036                 .replace("\015", "&#xD;") 
    1037         if s: self.write(s) 
    1038     handlers[Node.TEXT_NODE] = _do_text 
    1039     handlers[Node.CDATA_SECTION_NODE] = _do_text 
    1040  
    1041  
    1042     def _do_pi(self, node): 
    1043         '''_do_pi(self, node) -> None 
    1044         Process a PI node. Render a leading or trailing #xA if the 
    1045         document order of the PI is greater or lesser (respectively) 
    1046         than the document element. 
    1047         ''' 
    1048         if not _in_subset(self.subset, node): return 
    1049         W = self.write 
    1050         if self.documentOrder == _GreaterElement: W('\n') 
    1051         W('<?') 
    1052         W(node.nodeName) 
    1053         s = node.data 
    1054         if s: 
    1055             W(' ') 
    1056             W(s) 
    1057         W('?>') 
    1058         if self.documentOrder == _LesserElement: W('\n') 
    1059     handlers[Node.PROCESSING_INSTRUCTION_NODE] = _do_pi 
    1060  
    1061  
    1062     def _do_comment(self, node): 
    1063         '''_do_comment(self, node) -> None 
    1064         Process a comment node. Render a leading or trailing #xA if the 
    1065         document order of the comment is greater or lesser (respectively) 
    1066         than the document element. 
    1067         ''' 
    1068         if not _in_subset(self.subset, node): return 
    1069         if self.comments: 
    1070             W = self.write 
    1071             if self.documentOrder == _GreaterElement: W('\n') 
    1072             W('<!--') 
    1073             W(node.data) 
    1074             W('-->') 
    1075             if self.documentOrder == _LesserElement: W('\n') 
    1076     handlers[Node.COMMENT_NODE] = _do_comment 
    1077  
    1078  
    1079     def _do_attr(self, n, value): 
    1080         ''''_do_attr(self, node) -> None 
    1081         Process an attribute.''' 
    1082  
    1083         W = self.write 
    1084         W(' ') 
    1085         W(n) 
    1086         W('="') 
    1087         s = value \ 
    1088             .replace("&", "&amp;") \ 
    1089             .replace("<", "&lt;") \ 
    1090             .replace('"', '&quot;') \ 
    1091             .replace('\011', '&#x9') \ 
    1092             .replace('\012', '&#xA') \ 
    1093             .replace('\015', '&#xD') 
    1094         W(s) 
    1095         W('"') 
    1096  
    1097     def _do_element(self, node, initial_other_attrs = []): 
    1098         '''_do_element(self, node, initial_other_attrs = []) -> None 
    1099         Process an element (and its children).''' 
    1100  
    1101         # Get state (from the stack) make local copies. 
    1102         #       ns_parent -- NS declarations in parent 
    1103         #       ns_rendered -- NS nodes rendered by ancestors 
    1104         #       xml_attrs -- Attributes in XML namespace from parent 
    1105         #       ns_local -- NS declarations relevant to this element 
    1106         ns_parent, ns_rendered, xml_attrs = \ 
    1107                 self.state[0], self.state[1][:], self.state[2][:] 
    1108         ns_local = ns_parent.copy() 
    1109  
    1110         # Divide attributes into NS, XML, and others. 
    1111         other_attrs = initial_other_attrs[:] 
    1112         in_subset = _in_subset(self.subset, node) 
    1113         for a in _attrs(node): 
    1114             if a.namespaceURI == XMLNS.BASE: 
    1115                 n = a.nodeName 
    1116                 if n == "xmlns:": n = "xmlns"        # DOM bug workaround 
    1117                 ns_local[n] = a.nodeValue 
    1118             elif a.namespaceURI == XMLNS.XML: 
    1119                 if self.unsuppressedPrefixes is None or in_subset: 
    1120                     xml_attrs.append(a) 
    1121             else: 
    1122                 other_attrs.append(a) 
    1123  
    1124         # Render the node 
    1125         W, name = self.write, None 
    1126         if in_subset: 
    1127             name = node.nodeName 
    1128             W('<') 
    1129             W(name) 
    1130  
    1131             # Create list of NS attributes to render. 
    1132             ns_to_render = [] 
    1133             for n,v in ns_local.items(): 
    1134                 pval = ns_parent.get(n) 
    1135  
    1136                 # If default namespace is XMLNS.BASE or empty, skip 
    1137                 if n == "xmlns" \ 
    1138                 and v in [ XMLNS.BASE, '' ] and pval in [ XMLNS.BASE, '' ]: 
    1139                     continue 
    1140  
    1141                 # "omit namespace node with local name xml, which defines 
    1142                 # the xml prefix, if its string value is 
    1143                 # http://www.w3.org/XML/1998/namespace." 
    1144                 if n == "xmlns:xml" \ 
    1145                 and v in [ 'http://www.w3.org/XML/1998/namespace' ]: 
    1146                     continue 
    1147  
    1148                 # If different from parent, or parent didn't render 
    1149                 # and if not exclusive, or this prefix is needed or 
    1150                 # not suppressed 
    1151                 if (v != pval or n not in ns_rendered) \ 
    1152                   and (self.unsuppressedPrefixes is None or \ 
    1153                   _utilized(n, node, other_attrs, self.unsuppressedPrefixes)): 
    1154                     ns_to_render.append((n, v)) 
    1155  
    1156             # Sort and render the ns, marking what was rendered. 
    1157             #ns_to_render.sort(_sorter_ns) 
    1158             for n,v in ns_to_render: 
    1159                 self._do_attr(n, v) 
    1160                 ns_rendered.append(n) 
    1161  
    1162             # Add in the XML attributes (don't pass to children, since 
    1163             # we're rendering them), sort, and render. 
    1164             other_attrs.extend(xml_attrs) 
    1165             xml_attrs = [] 
    1166             #other_attrs.sort(_sorter) 
    1167             for a in other_attrs: 
    1168                 self._do_attr(a.nodeName, a.value) 
    1169             W('>') 
    1170  
    1171         # Push state, recurse, pop state. 
    1172         state, self.state = self.state, (ns_local, ns_rendered, xml_attrs) 
    1173         for c in _children(node): 
    1174             _implementation.handlers[c.nodeType](self, c) 
    1175         self.state = state 
    1176  
    1177         if name: W('</%s>' % name) 
    1178     handlers[Node.ELEMENT_NODE] = _do_element 
    1179  
    1180  
    1181 def FastPrint(node, output=None, **kw): 
    1182     """FastPrint(node, output=None, **kw) -> UTF-8 
    1183      
    1184     Output a DOM document/element node and all descendents. 
    1185     Return the text; if output is specified then output.write will 
    1186     be called to output the text and None will be returned 
    1187     Keyword parameters: 
    1188         comments: keep comments if non-zero (default is 0) 
    1189          
    1190     """ 
    1191     if output: 
    1192         _implementation(node, output.write, **kw) 
    1193     else: 
    1194         s = StringIO.StringIO() 
    1195         _implementation(node, s.write, **kw) 
    1196         return s.getvalue() 
    1197  
    1198  
    1199 if __name__ == '__main__': print _copyright 
     3    Subclass the SafeConfigParser - to preserve the original string case of the 
     4    cfg section names - NB, the RawConfigParser default is to lowercase these  
     5    by default 
     6    ''' 
     7    def optionxform(self, optionstr): 
     8        return optionstr 
  • TI12-security/trunk/WSSecurity/ndg/wssecurity/test/unit/wssecurity/foursuite/client/test_echoclient.py

    r6069 r6378  
    1616import os 
    1717import sys 
    18 import traceback 
     18import unittest 
    1919 
    20 from os.path import expandvars as xpdVars 
    2120from os.path import join, dirname, abspath 
    2221mkPath = lambda file: join(os.environ['NDGSEC_WSSECLNT_UNITTEST_DIR'], file) 
     
    2625from EchoService_services import EchoServiceLocator 
    2726 
    28 from ndg.security.test.unit import BaseTestCase 
    2927from ndg.security.common.wssecurity.signaturehandler.foursuite import \ 
    3028    SignatureHandler 
     
    3432    DomletteElementProxy 
    3533 
    36 class EchoClientTestCase(BaseTestCase): 
     34 
     35class EchoClientTestCase(unittest.TestCase): 
    3736     
    3837    def setUp(self): 
     
    5857         
    5958        # Signature handler object is passed to binding 
    60         sigHandler = SignatureHandler(cfg=configFilePath, 
    61                                       cfgFileSection='setUp') 
     59        sigHandler = SignatureHandler.fromConfigFile(configFilePath, 
     60                                                     section='setUp') 
    6261 
    6362        locator = EchoServiceLocator() 
Note: See TracChangeset for help on using the changeset viewer.