Changeset 4134
- Timestamp:
- 26/08/08 16:49:13 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
TI12-security/trunk/python/ndg.security.common/ndg/security/common/utils/ConfigFileParsers.py
r4131 r4134 13 13 14 14 from ConfigParser import SafeConfigParser 15 15 from ndg.security.common.wssecurity import WSSecurityConfig 16 16 # For parsing of properties file 17 17 try: # python 2.5 … … 24 24 log = logging.getLogger(__name__) 25 25 26 # lambda function to expand out any environment variables in properties read in 27 expandEnvVars = lambda x: isinstance(x, basestring) and os.path.expandvars(x).strip() or x 28 29 # since they are used across services, define the valid keys for the WS-Security section 30 # here for easy access 31 __wsSecurityValidKeys = { 32 'certFile': None, 33 'keyFile': None, 34 'keyPwd': None, 35 'clntCertFile': None, 36 'caCertFileList': [], 37 'wssRefInclNS': [], 38 'wssSignedInfoInclNS': [], 39 'reqBinSecTokValType': 'X509v3', 40 'applySignatureConfirmation': True, 41 'useSignatureHandler': True 42 } 26 43 27 44 class CaseSensitiveConfigParser(SafeConfigParser): … … 34 51 return optionstr 35 52 36 37 def readProperties(propFilePath, validKeys={}, sections=[]): 53 def readAndValidateProperties(propFilePath, validKeys={}): 38 54 """ 39 55 Determine the type of properties file and load the contents appropriately. 56 If a dict of valid keys is also specified, check the loaded properties against these. 40 57 @param propFilePath: file path to properties file - either in xml or ini format 41 58 @type propFilePath: string … … 43 60 - if values are encountered that are not in this list, an exception will be thrown 44 61 - if all info should be read, this keyword should be left to its default value 45 @type validKeys: dict 46 @keyword sections: a list of sections to include data from - if reading from an 'ini' type file 47 @type sections: list 62 - NB, this dict will also ensure list data is read in correctely 63 @type validKeys: dict 64 @raise ValueError: if a key is read in from the file that is not included in the 65 specified validKeys dict 66 """ 67 log.debug("Reading properties from %s" %propFilePath) 68 properties = {} 69 if propFilePath.lower().endswith('xml'): 70 log.debug("File has 'xml' suffix - treating as standard XML formatted properties file") 71 properties = readXMLPropertyFile(propFilePath, validKeys) 72 else: 73 properties = readINIPropertyFile(propFilePath, validKeys) 74 75 # if validKeys set, check that all loaded property values are featured in 76 # this list 77 if validKeys: 78 validateProperties(properties, validKeys) 79 80 # lastly set any default values from the validKeys dict for vals not read in 81 # from the property file 82 _setDefaultValues(properties, validKeys) 83 84 # lastly, expand out any environment variables set in the properties file 85 properties = _expandEnvironmentVariables(properties) 86 log.info('Properties loaded') 87 return properties 88 89 90 def readProperties(propFilePath, validKeys={}): 91 """ 92 Determine the type of properties file and load the contents appropriately. 93 @param propFilePath: file path to properties file - either in xml or ini format 94 @type propFilePath: string 95 """ 96 log.debug("Reading properties from %s" %propFilePath) 97 properties = {} 98 if propFilePath.lower().endswith('xml'): 99 log.debug("File has 'xml' suffix - treating as standard XML formatted properties file") 100 properties = readXMLPropertyFile(propFilePath, validKeys) 101 else: 102 properties = readINIPropertyFile(propFilePath, validKeys) 103 104 # lastly, expand out any environment variables set in the properties file 105 properties = _expandEnvironmentVariables(properties) 106 log.info('Properties loaded') 107 return properties 108 109 110 def readINIPropertyFile(propFilePath, validKeys): 111 """ 112 Read 'ini' type property file - i.e. a flat text file with key/value 113 data separated into sections 114 115 @param propFilePath: file path to properties file - either in xml or ini format 116 @type propFilePath: string 117 @param validKeys: a dictionary of valid values to be read from the file 118 - if values are encountered that are not in this list, an exception will be thrown 119 - if all info should be read, set this param to 'None' 120 @type validKeys: dict 48 121 @return: dict with the loaded properties in 49 122 @raise ValueError: if a key is read in from the file that is not included in the 50 123 specified validKeys dict 51 124 """ 52 log.debug("Reading properties from %s" %propFilePath) 53 properties = {} 54 if propFilePath.lower().endswith('xml'): 55 properties = readXMLPropertyFile(propFilePath, validKeys) 125 log.debug("File is not marked as XML - treating as flat, 'ini' format file") 126 127 if not os.path.isfile(propFilePath): 128 raise ValueError("Error parsing properties file \"%s\": No such file" %propFilePath) 129 130 cfg = CaseSensitiveConfigParser() 131 cfg.read(propFilePath) 132 properties = {} 133 134 # NB, add 'DEFAULT' section since this isn't returned by the 'sections()' 135 sections = cfg.sections() 136 sections.append('DEFAULT') 137 138 # parse data from the specified sections of the config file 139 for section in sections: 140 if section == 'DEFAULT': 141 properties.update(_parseConfig(cfg, validKeys, section=section)) 142 else: 143 keys = validKeys 144 if section == 'WS-Security': 145 keys = __wsSecurityValidKeys #WSSecurityConfig.defParam 146 properties[section] = _parseConfig(cfg, keys, section=section) 147 148 log.debug("Finished reading from INI properties file") 149 return properties 150 151 152 def _parseConfig(cfg, validKeys, section='DEFAULT'): 153 ''' 154 Extract parameters from cfg config object 155 @param cfg: config object 156 @type cfg: CaseSensitiveConfigParser 157 @param validKeys: a dictionary of valid values to be read from the file - used to check the 158 type of the input parameter to ensure (lists) are handled correctly 159 @type validKeys: dict 160 @keyword section: section of config file to parse from 161 @type section: string 162 @return: dict with the loaded properties in 163 ''' 164 log.debug("Parsing section: %s" %section) 165 keys = {} 166 properties = {} 167 if section == 'DEFAULT': 168 keys = cfg.defaults().keys() 56 169 else: 57 properties = readINIPropertyFile(propFilePath, validKeys, sections) 58 59 # if validKeys set, check that all loaded property values are featured in 60 # this list 61 if validKeys: 62 _checkForInvalidElements(properties, validKeys) 63 64 # lastly set any default values from the validKeys dict for vals not read in 65 # from the property file 66 _setDefaultValues(properties, validKeys) 67 68 # lastly, expand out any environment variables set in the properties file 69 properties = _expandEnvironmentVariables(properties) 70 log.info('Properties loaded') 71 return properties 170 keys = cfg.options(section) 171 # NB, we need to be careful here - since this will return the section keywords 172 # AND the 'DEFAULT' section entries - so use the difference between the two 173 keys = filter(lambda x:x not in cfg.defaults().keys(), keys) 174 175 for key in keys: 176 val = cfg.get(section, key) 177 if val: 178 179 # expand out any env vars 180 val = expandEnvVars(val) 181 182 # if the tag contains an integer, convert this appropriately 183 if val.isdigit(): 184 val = int(val) 185 186 # if the value is in the validKeys dict, ensure it is read in as the correct type 187 if key in validKeys: 188 if isinstance(validKeys[key], list): 189 # Treat as a list of space separated elements 190 val = val.split() 191 else: 192 # NB, the XML parser will return empty vals as None, so ensure consistency here 193 val = None 194 195 # check if key already exists; if so, append to list 196 if properties.has_key(key): 197 properties[key] = __listify(properties[key]).extend(val) 198 else: 199 properties[key] = val 200 201 log.debug("Finished parsing section") 202 return properties 203 204 205 def readXMLPropertyFile(propFilePath, validKeys, rootElem=None): 206 """ 207 Read property file - assuming the standard XML schema 208 209 @param propFilePath: file path to properties file - either in xml or ini format 210 @type propFilePath: string 211 @param validKeys: a dictionary of valid values to be read from the file - used to check the 212 type of the input parameter to ensure (lists) are handled correctly 213 @keyword rootElem: a particular element of an ElementTree can be passed in to 214 use as the root element; NB, if this is set, it will take precedence over any 215 propFilePath specified 216 @type rootElem: ElementTree.Element 217 @return: dict with the loaded properties in 218 """ 219 if rootElem is None: 220 try: 221 tree = ElementTree.parse(propFilePath) 222 223 except IOError, ioErr: 224 raise ValueError, "Error parsing properties file \"%s\": %s" % \ 225 (ioErr.filename, ioErr.strerror) 226 227 rootElem = tree.getroot() 228 if rootElem is None: 229 raise ValueError, \ 230 "Parsing properties file \"%s\": root element is not defined" % \ 231 propFilePath 232 233 properties = {} 234 # Copy properties from file into a dictionary 235 try: 236 for elem in rootElem: 237 key = elem.tag 238 val = elem.text 239 240 # expand out any env vars 241 val = expandEnvVars(val) 242 243 # if the tag contains an integer, convert this appropriately 244 if val and val.isdigit(): 245 val = int(val) 246 247 # check for lists - don't recurse into these else the key names 248 # will end up being wrong 249 if key in validKeys and isinstance(validKeys[key], list): 250 # handle lists of elements 251 if len(elem) == 0: 252 if elem.text is not None: 253 # Treat as a list of space separated elements 254 val = val.split() 255 else: 256 # Parse from a list of sub-elements 257 val = [expandEnvVars(subElem.text.strip()) for subElem in elem] 258 259 # otherwise check for subelements; if these exist, recurse and store properties 260 # in an inner dictionary 261 elif len(elem) > 0: 262 keys = validKeys 263 if key == 'WS-Security': 264 keys = __wsSecurityValidKeys #WSSecurityConfig.defParam 265 val = readXMLPropertyFile(propFilePath, keys, rootElem=elem) 266 267 # check if key already exists; if so, append to list 268 if properties.has_key(key): 269 properties[key] = __listify(properties[key]).extend(val) 270 else: 271 properties[key] = val 272 #print "XML: Key: %s, Val: %s" %(key, properties[key]) 273 274 except Exception, e: 275 raise ValueError, \ 276 "Error parsing tag \"%s\" in properties file \"%s\": %s" % \ 277 (elem.tag, propFilePath, e) 278 279 log.debug("Finished reading from XML properties file") 280 return properties 281 282 283 def __listify(val): 284 ''' 285 Checks if val is a list; if so return as is, if not return as list 286 @param val: object to turn into a list 287 @return: val as a list (if it is not already) 288 ''' 289 if isinstance(val, list): 290 return val 291 return [val] 292 293 294 def validateProperties(properties, validKeys): 295 ''' 296 Check the contents of the properties dict to ensure it doesn't contain 297 any keys not featured in the validKeys dict; if it does, throw an exception 298 @param properties: dictionary storing loaded properties 299 @type properties: dict 300 @param validKeys: a dictionary of valid values 301 @type validKeys: dict 302 @raise ValueError: if a key is read in from the file that is not included in the 303 specified validKeys dict 304 ''' 305 log.debug("Checking for invalid properties") 306 invalidKeys = [] 307 for key in properties: 308 # NB, this is a standard property used across most services - so check 309 # using the properties listed here 310 if key == 'WS-Security': 311 validateProperties(properties[key], __wsSecurityValidKeys) 312 else: 313 if key not in validKeys: 314 invalidKeys.append(key) 315 316 if invalidKeys != []: 317 errorMessage = "The following properties file " + \ 318 "elements are invalid: " + ', '.join(invalidKeys) 319 print errorMessage 320 log.error(errorMessage) 321 raise ValueError, errorMessage 72 322 73 323 … … 110 360 val = os.path.expandvars(val) 111 361 return val 112 113 114 def readINIPropertyFile(propFilePath, validKeys, sections=[]):115 """116 Read 'ini' type property file - i.e. a flat text file with key/value117 data separated into sections118 119 @param propFilePath: file path to properties file - either in xml or ini format120 @type propFilePath: string121 @param validKeys: a dictionary of valid values to be read from the file122 - if values are encountered that are not in this list, an exception will be thrown123 - if all info should be read, set this param to 'None'124 @type validKeys: dict125 @keyword sections: a list of sections to include data from126 @type sections: list127 @return: dict with the loaded properties in128 @raise ValueError: if a key is read in from the file that is not included in the129 specified validKeys dict130 """131 log.debug("File is not marked as XML - treating as flat, 'ini' format file")132 133 if not os.path.isfile(propFilePath):134 raise ValueError("Error parsing properties file \"%s\": No such file" %propFilePath)135 136 cfg = CaseSensitiveConfigParser()137 cfg.read(propFilePath)138 properties = {}139 140 # if no sections are set, use all sections - including the default one141 # - NB, this isn't returned by the 'sections()' method so needs to be added explicitly142 if not sections:143 sections = cfg.sections()144 sections.append('DEFAULT')145 146 # parse data from the specified sections of the config file147 if len(sections):148 for section in sections:149 properties = _parseConfig(cfg, properties, validKeys, section=section)150 151 log.debug("Finished reading from INI properties file")152 return properties153 154 155 def _checkForInvalidElements(properties, validKeys):156 '''157 Check the contents of the properties dict to ensure it doesn't contain158 any keys not featured in the validKeys dict; if it does, throw an exception159 @param properties: dictionary storing loaded properties160 @type properties: dict161 @param validKeys: a dictionary of valid values162 @type validKeys: dict163 @raise ValueError: if a key is read in from the file that is not included in the164 specified validKeys dict165 '''166 log.debug("Checking for invalid properties")167 invalidKeys = []168 for key in properties:169 if key not in validKeys:170 invalidKeys.append(key)171 172 if invalidKeys != []:173 errorMessage = "The following properties file " + \174 "elements are invalid: " + ', '.join(invalidKeys)175 log.error(errorMessage)176 raise ValueError, errorMessage177 362 178 363 … … 195 380 properties[key] = validKeys[key] 196 381 log.debug("Finished checking for unset keys") 197 198 199 def _parseConfig(cfg, properties, validKeys, section='DEFAULT'): 200 ''' 201 Extract parameters from cfg config object 202 @param cfg: config object 203 @type cfg: CaseSensitiveConfigParser 204 @param properties: dictionary to store properties in 205 @type properties: dict 206 @param validKeys: a dictionary of valid values to be read from the file 207 - if values are encountered that are not in this list, an exception will be thrown 208 - if all info should be read, set this param to 'None' 209 @type validKeys: dict 210 @keyword section: section of config file to parse from 211 @type section: string 212 @return: dict with the loaded properties in 213 ''' 214 log.debug("Parsing section: %s" %section) 215 keys = {} 216 if section == 'DEFAULT': 217 keys = cfg.defaults().keys() 218 else: 219 keys = cfg.options(section) 220 221 for key in keys: 222 val = cfg.get(section, key) 223 224 # NB, the XML parser will return empty vals as None, so ensure consistency here 225 if not val: 226 properties[key] = None 227 continue 228 229 # if the value is in the validKeys dict, ensure it is read in as the correct type 230 if key in validKeys: 231 if isinstance(validKeys[key], list): 232 # Treat as a list of space separated elements 233 properties[key] = val.split() 234 else: 235 properties[key] = val 236 else: 237 properties[key] = val 238 239 log.debug("Finished parsing section") 240 return properties 241 242 243 def readXMLPropertyFile(propFilePath, validKeys): 244 """ 245 Read property file - assuming the standard XML schema 246 247 @param propFilePath: file path to properties file - either in xml or ini format 248 @type propFilePath: string 249 @param validKeys: a dictionary of valid values to be read from the file 250 - if values are encountered that are not in this list, an exception will be thrown 251 - if all info should be read, set this param to 'None' 252 @type validKeys: dict 253 @return: dict with the loaded properties in 254 """ 255 log.debug("File has 'xml' suffix - treating as standard XML formatted properties file") 256 try: 257 tree = ElementTree.parse(propFilePath) 258 259 except IOError, ioErr: 260 raise ValueError, "Error parsing properties file \"%s\": %s" % \ 261 (ioErr.filename, ioErr.strerror) 262 263 rootElem = tree.getroot() 264 if rootElem is None: 265 raise ValueError, \ 266 "Parsing properties file \"%s\": root element is not defined" % \ 267 propFilePath 268 269 # Copy properties from file into a dictionary 270 properties = {} 271 try: 272 for elem in rootElem: 273 # if the value is in the validKeys dict, ensure it is read in as the correct type 274 if elem.tag in validKeys: 275 if isinstance(validKeys[elem.tag], list): 276 if len(elem) == 0: 277 if elem.text is not None: 278 # Treat as a list of space separated elements 279 properties[elem.tag] = elem.text.split() 280 else: 281 properties[elem.tag] = [] 282 else: 283 # Parse from a list of sub-elements 284 properties[elem.tag] = \ 285 [subElem.text.strip() for subElem in elem] 286 else: 287 properties[elem.tag] = elem.text 288 else: 289 properties[elem.tag] = elem.text 290 291 except Exception, e: 292 raise ValueError, \ 293 "Error parsing tag \"%s\" in properties file \"%s\": %s" % \ 294 (elem.tag, propFilePath, e) 295 296 log.debug("Finished reading from XML properties file") 297 return properties 382
Note: See TracChangeset
for help on using the changeset viewer.