Changeset 7314
- Timestamp:
- 11/08/10 16:39:41 (10 years ago)
- Location:
- TI12-security/trunk/NDGSecurity/python
- Files:
-
- 5 added
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/utils/__init__.py
r7076 r7314 9 9 __contact__ = "Philip.Kershaw@stfc.ac.uk" 10 10 __revision__ = '$Id$' 11 import UserDict 11 12 12 13 # Interpret a string as a boolean 13 14 str2Bool = lambda str: str.lower() in ("yes", "true", "t", "1") 15 14 16 15 17 class UniqList(list): … … 104 106 105 107 dict.update(self, d, **kw) 108 109 110 class VettedDict(UserDict.DictMixin): 111 """Enforce custom checking on keys and items before addition to a 112 dictionary 113 """ 114 115 def __init__(self, *args): 116 """Initialise setting the allowed type or types for keys and items 117 118 @param args: two arguments: the first is a callable which filters for 119 permissable keys in this dict, the second sets the type or list of 120 types permissable for items in this dict 121 @type args: tuple 122 """ 123 if len(args) != 2: 124 raise TypeError('__init__() takes 2 arguments, KeyFilter and ' 125 'valueFilter (%d given)' % len(args)) 126 127 # Validation of inputs 128 for arg, argName in zip(args, ('KeyFilter', 'valueFilter')): 129 if not callable(arg): 130 raise TypeError('Expecting callable for %r input; got %r' % 131 (argName, type(arg))) 132 133 self.__KeyFilter, self.__valueFilter = args 134 135 self.__map = {} 136 137 def _verifyKeyValPair(self, key, val): 138 """Check given key value pair and return False if they should be 139 filtered out. Filter functions may also raise an exception if they 140 wish to abort completely 141 142 @param key: dict key to check 143 @type key: basestring 144 @param val: value to check 145 @type val: any 146 """ 147 if not self.__KeyFilter(key): 148 return False 149 150 elif not self.__valueFilter(val): 151 return False 152 153 else: 154 return True 155 156 def __setitem__(self, key, val): 157 """Enforce type checking when setting new items 158 159 @param key: key for item to set 160 @type key: any 161 @param val: value to set for this key 162 @type val: any 163 """ 164 if self._verifyKeyValPair(key, val): 165 self.__map[key] = val 166 167 def __getitem__(self, key): 168 """Provide implementation for getting items 169 @param key: key for item to retrieve 170 @type key: any 171 @return: value for input key 172 @rtype: any 173 """ 174 if key not in self.__map: 175 raise KeyError('%r key not found in dict' % key) 176 177 return self.__map[key] 178 179 def get(self, key, *arg): 180 """Provide implementation of get item with default 181 182 @param key: key for item to retrieve 183 @type key: any 184 @param arg: use to set a default argument 185 @type arg: tuple 186 """ 187 if key in self.__map: 188 return self.__map[key] 189 190 elif len(arg) > 1: 191 # Default value set 192 return arg[1] 193 else: 194 return None 195 196 def __repr__(self): 197 return repr(self.__map) 198 199 def keys(self): 200 return self.__map.keys() 201 202 def items(self): 203 return self.__map.items() 204 205 def values(self): 206 return self.__map.values() 207 208 def __contains__(self, val): 209 return self.__map.__contains__(val) -
TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/xacml/pip/saml_pip.py
r7310 r7314 13 13 14 14 from os import path 15 from ConfigParser import SafeConfigParser 15 from ConfigParser import SafeConfigParser, ConfigParser 16 16 17 17 from ndg.xacml.core.context.pipinterface import PIPInterface … … 20 20 from ndg.saml.saml2.core import (AttributeQuery as SamlAttributeQuery, 21 21 Attribute as SamlAttribute) 22 from ndg.saml.utils import TypedList as SamlTypedList22 from ndg.saml.utils import TypedList 23 23 from ndg.saml.saml2.binding.soap.client.attributequery import \ 24 24 AttributeQuerySslSOAPBinding 25 25 26 from ndg.security.common. X509 import X509Cert26 from ndg.security.common.utils import VettedDict 27 27 28 28 29 29 class PIP(PIPInterface): 30 30 '''Policy Information Point enables XACML PDP to query for additional user 31 attr biutes. The PDP does this indirectly via the Context Handler31 attributes. The PDP does this indirectly via the Context Handler 32 32 ''' 33 33 # Subject attributes makes no sense for external configuration - these … … 45 45 ATTRIBUTE_QUERY_ATTRNAME_OFFSET = LEN_ATTRIBUTE_QUERY_ATTRNAME + 1 46 46 47 __slots__ = ('__mappingFilePath',) 47 DEFAULT_OPT_PREFIX = 'saml_pip.' 48 49 __slots__ = ( 50 '__subjectAttributeId', 51 '__mappingFilePath', 52 '__attribute2AttributeAuthorityMap', 53 '__attributeQueryBinding' 54 ) 48 55 49 56 def __init__(self): 50 57 '''Initialise settings for connection to an Attribute Authority''' 51 self.__ attributeQueryBinding = AttributeQuerySslSOAPBinding()58 self.__subjectAttributeId = None 52 59 self.__mappingFilePath = None 53 60 61 # Force mapping dict to have string type keys and items 62 _typeCheckers = (lambda val: isinstance(val, basestring),)*2 63 self.__attribute2AttributeAuthorityMap = VettedDict(*_typeCheckers) 64 65 self.__attributeQueryBinding = AttributeQuerySslSOAPBinding() 66 67 def _get_subjectAttributeId(self): 68 return self.__subjectAttributeId 69 70 def _set_subjectAttributeId(self, value): 71 if not isinstance(value, basestring): 72 raise TypeError('Expecting string type for "subjectAttributeId"; ' 73 'got %r' % type(value)) 74 self.__subjectAttributeId = value 75 76 subjectAttributeId = property(_get_subjectAttributeId, 77 _set_subjectAttributeId, 78 doc="The attribute ID of the subject value " 79 "to extract from the XACML request " 80 "context and pass in the SAML attribute " 81 "query") 82 54 83 def _getMappingFilePath(self): 55 84 return self.__mappingFilePath … … 59 88 raise TypeError('Expecting string type for "mappingFilePath"; got ' 60 89 '%r' % type(value)) 61 self.__mappingFilePath = value90 self.__mappingFilePath = path.expandvars(value) 62 91 63 92 mappingFilePath = property(_getMappingFilePath, 64 93 _setMappingFilePath, 65 doc="Mapping File maps attribute IDs to the " 66 "Attribute Authorities from which they may " 67 "be queried for") 68 94 doc="Mapping File maps Attribute ID -> " 95 "Attribute Authority mapping file. The PIP, on receipt of a query from the " 96 "XACML context handler, checks the attribute(s) being queried for and looks up " 97 "this mapping to determine which attribute authority to query to find out if " 98 "the subject has the attribute in their entitlement.") 99 100 attribute2AttributeAuthorityMap = property( 101 fget=lambda self: self.__attribute2AttributeAuthorityMap, 102 doc="Mapping from attribute Id to attribute authority " 103 "endpoint") 104 105 @property 106 def attributeQueryBinding(self): 107 """SAML SOAP Attribute Query client binding object""" 108 return self.__attributeQueryBinding 109 69 110 @classmethod 70 111 def fromConfig(cls, cfg, **kw): … … 96 137 setattr(self, optName, val) 97 138 98 def parseConfig(self, cfg, prefix= '', section='DEFAULT'):139 def parseConfig(self, cfg, prefix=DEFAULT_OPT_PREFIX, section='DEFAULT'): 99 140 '''Read config settings from a file, config parser object or dict 100 141 … … 103 144 @type prefix: basestring 104 145 @param prefix: prefix for option names e.g. "attributeQuery." 105 @type section: ba estring146 @type section: basetring 106 147 @param section: configuration file section from which to extract 107 148 parameters. … … 109 150 if isinstance(cfg, basestring): 110 151 cfgFilePath = path.expandvars(cfg) 111 _cfg = SafeConfigParser() 152 153 # Add a 'here' helper option for setting dir paths in the config 154 # file 155 hereDir = path.abspath(path.dirname(cfgFilePath)) 156 _cfg = SafeConfigParser(defaults={'here': hereDir}) 157 158 # Make option name reading case sensitive 159 _cfg.optionxform = str 112 160 _cfg.read(cfgFilePath) 113 161 items = _cfg.items(section) … … 129 177 # Filter attributes based on prefix 130 178 if optName.startswith(prefix): 131 se lf.__setAttr(optName[prefixLen:], val)179 setattr(self, optName[prefixLen:], val) 132 180 else: 133 181 # No prefix set - attempt to set all attributes 134 se lf.__setAttr(optName, val)182 setattr(self, optName, val) 135 183 136 # def __setattr__(self, name, value): 137 # """Enable setting of AttributeQuerySslSOAPBinding attributes from 138 # names starting with attributeQuery.* / attributeQuery_*. Addition for 139 # setting these values from ini file 140 # """ 141 # 142 # # Coerce into setting AttributeQuerySslSOAPBinding attributes - 143 # # names must start with 'attributeQuery\W' e.g. 144 # # attributeQuery.clockSkew or attributeQuery_issuerDN 145 # if name.startswith(self.__class__.ATTRIBUTE_QUERY_ATTRNAME): 146 # queryAttrName = name[ 147 # self.__class__.ATTRIBUTE_QUERY_ATTRNAME_OFFSET:] 148 # 149 # # Skip subject and attribute Id related parameters to prevent 150 # # settings from static configuration. These are set from the 151 # # incoming XACML context 152 # if min([queryAttrName.startswith(i) for i in 153 # self.__class__.DISALLOWED_ATTRIBUTE_QUERY_OPTNAMES]): 154 # super(PIP, self).__setattr__(name, value) 155 # 156 # setattr(self.__attributeQueryBinding, queryAttrName, value) 157 # else: 158 # super(PIP, self).__setattr__(name, value) 159 184 def __setattr__(self, name, value): 185 """Enable setting of AttributeQuerySslSOAPBinding attributes from 186 names starting with attributeQuery.* / attributeQuery_*. Addition for 187 setting these values from ini file 188 """ 189 190 # Coerce into setting AttributeQuerySslSOAPBinding attributes - 191 # names must start with 'attributeQuery\W' e.g. 192 # attributeQuery.clockSkewTolerance or attributeQuery_issuerDN 193 if name.startswith(self.__class__.ATTRIBUTE_QUERY_ATTRNAME): 194 queryAttrName = name[ 195 self.__class__.ATTRIBUTE_QUERY_ATTRNAME_OFFSET:] 196 197 # Skip subject related parameters to prevent settings from static 198 # configuration. These are set at runtime 199 if min([queryAttrName.startswith(i) 200 for i in self.__class__.DISALLOWED_ATTRIBUTE_QUERY_OPTNAMES 201 ]): 202 super(PIP, self).__setattr__(name, value) 203 204 setattr(self.__attributeQueryBinding, queryAttrName, value) 205 else: 206 super(PIP, self).__setattr__(name, value) 160 207 161 208 def readMappingFile(self): … … 163 210 """ 164 211 mappingFile = open(self.mappingFilePath) 165 self.__attribute2AttributeAuthorityMap = dict()166 for line in mappingFile.readline():167 if notline.startswith('#'):168 attributeId, attributeAuthorityURI = line.split()212 for line in mappingFile.readlines(): 213 _line = path.expandvars(line).strip() 214 if _line and not _line.startswith('#'): 215 attributeId, attributeAuthorityURI = _line.split() 169 216 self.__attribute2AttributeAuthorityMap[attributeId 170 217 ] = attributeAuthorityURI … … 182 229 (Request, type(context))) 183 230 184 # TODO: Check for cached attributes for this subject (i.e. user) 185 231 # TODO: Check for cached attributes for this subject (i.e. user) 186 232 # If none found send a query to the attribute authority 187 188 # TODO: Look-up the attribute authority corresponding to the query 189 190 # attributeAuthorityURI = self.__attribute2AttributeAuthorityMap.get( 191 # attributeName) 192 attributeAuthorityURI = 'https://localhost:7443/AttributeAuthority' 193 233 234 # Look up mapping from request attribute ID to Attribute Authority to 235 # query 236 attributeAuthorityURI = self.__attribute2AttributeAuthorityMap.get( 237 attributeDesignator.attributeId, 238 None) 239 if attributeAuthorityURI is None: 240 log.debug("No matching attribute authority endpoint found in " 241 "mapping file %r for input attribute ID %r", 242 self.mappingFilePath, 243 attributeDesignator.attributeId) 244 245 return [] 246 194 247 # Get subject from the request context 195 # TODO: parameterise data type setting196 248 subjectId = None 197 249 for subject in context.subjects: 198 250 for attribute in subject.attributes: 199 if attribute. dataType == 'urn:esg:openid':251 if attribute.attributeId == self.subjectAttributeId: 200 252 if len(attribute.attributeValues) != 1: 201 253 raise Exception("Expecting a single attribute value " … … 210 262 else: 211 263 # Keep a reference to the matching Subject instance 212 _subject = subject264 xacmlCtxSubject = subject 213 265 214 266 # Get the id of the attribute to be queried for and add it to the SAML … … 218 270 samlAttribute.name = attributeDesignator.attributeId 219 271 samlAttribute.nameFormat = attributeFormat 220 attributeQueryBinding.query.attributes.append(samlAttribute) 221 222 223 attributeQueryBinding.subjectID = subjectId 224 response = attributeQueryBinding.send(uri=attributeAuthorityURI) 272 self.attributeQueryBinding.query.attributes.append(samlAttribute) 273 274 # Dispatch query 275 try: 276 self.attributeQueryBinding.subjectID = subjectId 277 self.attributeQueryBinding.subjectIdFormat = self.subjectAttributeId 278 response = self.attributeQueryBinding.send( 279 uri=attributeAuthorityURI) 280 finally: 281 # !Ensure relevant query attributes are reset ready for any 282 # subsequent query! 283 self.attributeQueryBinding.subjectID = '' 284 self.attributeQueryBinding.subjectIdFormat = '' 285 self.attributeQueryBinding.query.attributes = TypedList( 286 SamlAttribute) 225 287 226 288 # Unpack SAML assertion attribute values corresponding to the name … … 234 296 235 297 # Update the XACML request context subject with the new attributes 236 _subject.attributes.append(attributeValues)298 xacmlCtxSubject.attributes.append(attributeValues) 237 299 238 300 # Return the attributes to the caller to comply with the interface
Note: See TracChangeset
for help on using the changeset viewer.