Changeset 6567 for TI12-security/trunk/NDGSecurity
- Timestamp:
- 12/02/10 15:04:42 (11 years ago)
- Location:
- TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/__init__.py
r6566 r6567 12 12 log = logging.getLogger(__name__) 13 13 14 import re15 14 from os import path 16 from datetime import datetime, timedelta17 from uuid import uuid418 15 from ConfigParser import ConfigParser 19 16 20 from M2Crypto.m2urllib2 import HTTPSHandler21 22 17 from saml.common import SAMLObject 23 from saml.utils import SAMLDateTime 24 from saml.saml2.core import (Attribute, AttributeQuery, StatusCode, Response, 25 Issuer, Subject, SAMLVersion, NameID) 26 from saml.xml.etree import AttributeQueryElementTree, ResponseElementTree 27 28 from ndg.security.common.saml_utils.esg import EsgSamlNamespaces 29 from ndg.security.common.utils import TypedList, str2Bool 18 30 19 from ndg.security.common.utils.configfileparsers import ( 31 20 CaseSensitiveConfigParser) … … 37 26 UrlLib2SOAPRequest) 38 27 39 # Prevent whole module breaking if this is not available - it's only needed for40 # AttributeQuerySslSOAPBinding41 try:42 from ndg.security.common.utils.m2crypto import SSLContextProxy43 _sslContextProxySupport = True44 45 except ImportError:46 _sslContextProxySupport = False47 48 28 49 29 class SOAPBindingError(Exception): … … 72 52 requestEnvelopeClass=SOAPEnvelope, 73 53 responseEnvelopeClass=SOAPEnvelope, 74 serialise= AttributeQueryElementTree.toXML,75 deserialise= ResponseElementTree.fromXML,54 serialise=None, 55 deserialise=None, 76 56 handlers=(HTTPSHandler,)): 77 '''Create SAML SOAP Client - Nb. serialisation functions assume78 AttributeQuery/Response'''57 '''Create SAML SOAP Client - Nb. serialisation functions must be set 58 before send()ing the request''' 79 59 self.__client = None 80 self.serialise = serialise 81 self.deserialise = deserialise 60 self.__serialise = None 61 self.__deserialise = None 62 63 if serialise is not None: 64 self.serialise = serialise 65 66 if deserialise is not None: 67 self.deserialise = deserialise 82 68 83 69 self.client = UrlLib2SOAPClient() … … 125 111 def _setRequestEnvelopeClass(self, value): 126 112 if not issubclass(value, SOAPEnvelopeBase): 127 raise TypeError('Expecting %r for "requestEnvelopeClass"; got %r' %113 raise TypeError('Expecting %r for "requestEnvelopeClass"; got %r' % 128 114 (SOAPEnvelopeBase, value)) 129 115 … … 139 125 def _setClient(self, value): 140 126 if not isinstance(value, UrlLib2SOAPClient): 141 raise TypeError('Expecting %r for "client"; got %r' %127 raise TypeError('Expecting %r for "client"; got %r' % 142 128 (UrlLib2SOAPClient, type(value))) 143 129 self.__client = value … … 157 143 defaults to ndg.security.common.soap.client.UrlLib2SOAPRequest 158 144 ''' 145 if self.serialise is None: 146 raise AttributeError('No "serialise" method set to serialise the ' 147 'request') 148 149 if self.deserialise is None: 150 raise AttributeError('No "deserialise" method set to deserialise ' 151 'the response') 152 159 153 if not isinstance(samlObj, SAMLObject): 160 154 raise TypeError('Expecting %r for input attribute query; got %r' … … 193 187 @type cfg: basestring /ConfigParser derived type 194 188 @param cfg: configuration file path or ConfigParser type object 195 @rtype: ndg.security.common. credentialWallet.AttributeQuery189 @rtype: ndg.security.common.saml_utils.binding.soap.SOAPBinding 196 190 @return: new instance of this class 197 191 ''' … … 233 227 234 228 def __getstate__(self): 235 '''E nable pickling for use with beaker.session'''229 '''Explicit implementation needed with __slots__''' 236 230 _dict = {} 237 231 for attrName in SOAPBinding.__slots__: … … 246 240 247 241 def __setstate__(self, attrDict): 248 ''' Specificimplementation needed with __slots__'''242 '''Explicit implementation needed with __slots__''' 249 243 for attr, val in attrDict.items(): 250 244 setattr(self, attr, val) 251 252 253 class SubjectQueryResponseError(SOAPBindingInvalidResponse):254 """SAML Response error from Subject Query"""255 def __init__(self, *arg, **kw):256 SOAPBindingInvalidResponse.__init__(self, *arg, **kw)257 self.__response = None258 259 def _getResponse(self):260 '''Gets the response corresponding to this error261 262 @return the response263 '''264 return self.__response265 266 def _setResponse(self, value):267 '''Sets the response corresponding to this error.268 269 @param value: the response270 '''271 if not isinstance(value, Response):272 raise TypeError('"response" must be a %r, got %r' % (Response,273 type(value)))274 self.__response = value275 276 response = property(fget=_getResponse, fset=_setResponse,277 doc="SAML Response associated with this exception") -
TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/attributequery.py
r6566 r6567 12 12 log = logging.getLogger(__name__) 13 13 14 from M2Crypto.m2urllib2 import HTTPSHandler 15 16 from saml.saml2.core import Attribute, AttributeQuery 17 18 from ndg.security.common.utils import TypedList 14 19 from ndg.security.common.sam_utils.binding.soap.subjectquery import ( 15 SubjectQuery ,20 SubjectQuerySOAPBinding, 16 21 SubjectQueryResponseError) 22 23 # Prevent whole module breaking if this is not available - it's only needed for 24 # AttributeQuerySslSOAPBinding 25 try: 26 from ndg.security.common.utils.m2crypto import SSLContextProxy 27 _sslContextProxySupport = True 28 29 except ImportError: 30 _sslContextProxySupport = False 17 31 18 32 … … 21 35 22 36 23 class AttributeQuerySOAPBinding(S OAPBinding):37 class AttributeQuerySOAPBinding(SubjectQuery): 24 38 """SAML Attribute Query SOAP Binding 25 26 Nb. Assumes X.509 subject type for query issuer27 39 """ 28 SUBJECT_ID_OPTNAME = 'subjectID'29 ISSUER_NAME_OPTNAME = 'issuerName'30 CLOCK_SKEW_OPTNAME = 'clockSkewTolerance'31 32 CONFIG_FILE_OPTNAMES = (33 SUBJECT_ID_OPTNAME,34 ISSUER_NAME_OPTNAME,35 CLOCK_SKEW_OPTNAME36 )37 38 40 QUERY_ATTRIBUTES_ATTRNAME = 'queryAttributes' 39 41 LEN_QUERY_ATTRIBUTES_ATTRNAME = len(QUERY_ATTRIBUTES_ATTRNAME) … … 41 43 42 44 __PRIVATE_ATTR_PREFIX = "__" 43 __slots__ = tuple([__PRIVATE_ATTR_PREFIX + i 44 for i in \ 45 CONFIG_FILE_OPTNAMES + (QUERY_ATTRIBUTES_ATTRNAME,)]) 46 del i 45 __slots__ = (__PRIVATE_ATTR_PREFIX + QUERY_ATTRIBUTES_ATTRNAME,) 46 47 47 48 48 def __init__(self, **kw): 49 49 '''Create SOAP Client for SAML Attribute Query''' 50 self.__issuerName = None51 50 self.__queryAttributes = TypedList(Attribute) 52 self.__clockSkewTolerance = timedelta(seconds=0.)53 51 54 52 super(AttributeQuerySOAPBinding, self).__init__(**kw) 55 56 @classmethod57 def fromConfig(cls, cfg, **kw):58 '''Alternative constructor makes object from config file settings59 @type cfg: basestring /ConfigParser derived type60 @param cfg: configuration file path or ConfigParser type object61 @rtype: ndg.security.common.credentialWallet.AttributeQuery62 @return: new instance of this class63 '''64 obj = cls()65 obj.parseConfig(cfg, **kw)66 67 return obj68 69 def parseConfig(self, cfg, prefix='', section='DEFAULT'):70 '''Read config file settings71 @type cfg: basestring /ConfigParser derived type72 @param cfg: configuration file path or ConfigParser type object73 @type prefix: basestring74 @param prefix: prefix for option names e.g. "attributeQuery."75 @type section: baestring76 @param section: configuration file section from which to extract77 parameters.78 '''79 if isinstance(cfg, basestring):80 cfgFilePath = path.expandvars(cfg)81 _cfg = CaseSensitiveConfigParser()82 _cfg.read(cfgFilePath)83 84 elif isinstance(cfg, ConfigParser):85 _cfg = cfg86 else:87 raise AttributeError('Expecting basestring or ConfigParser type '88 'for "cfg" attribute; got %r type' % type(cfg))89 90 prefixLen = len(prefix)91 for optName, val in _cfg.items(section):92 if prefix:93 # Filter attributes based on prefix94 if optName.startswith(prefix):95 setattr(self, optName[prefixLen:], val)96 else:97 # No prefix set - attempt to set all attributes98 setattr(self, optName, val)99 53 100 54 def __setattr__(self, name, value): … … 124 78 else: 125 79 raise 126 127 def _getSubjectID(self):128 return self.__subjectID129 130 def _setSubjectID(self, value):131 if not isinstance(value, basestring):132 raise TypeError('Expecting string type for "subjectID"; got %r '133 'instead' % type(value))134 self.__subjectID = value135 136 subjectID = property(_getSubjectID, _setSubjectID,137 doc="ID to be sent as query subject")138 80 139 81 def _getQueryAttributes(self): 140 """Returns a *COPY* of the attributes to avoid overwriting the141 member variable content142 """143 82 return self.__queryAttributes 144 83 … … 155 94 "Attribute Authority") 156 95 157 def _getIssuerName(self):158 return self.__issuerName159 160 def _setIssuerName(self, value):161 if not isinstance(value, basestring):162 raise TypeError('Expecting string type for "issuerName"; '163 'got %r instead' % type(value))164 165 self.__issuerName = value166 167 issuerName = property(_getIssuerName, _setIssuerName,168 doc="Distinguished Name of issuer of SAML Attribute "169 "Query to Attribute Authority")170 171 def _getClockSkewTolerance(self):172 return self.__clockSkewTolerance173 174 def _setClockSkewTolerance(self, value):175 if isinstance(value, (float, int, long)):176 self.__clockSkewTolerance = timedelta(seconds=value)177 178 elif isinstance(value, basestring):179 self.__clockSkewTolerance = timedelta(seconds=float(value))180 else:181 raise TypeError('Expecting float, int, long or string type for '182 '"clockSkewTolerance"; got %r' % type(value))183 184 clockSkewTolerance = property(fget=_getClockSkewTolerance,185 fset=_setClockSkewTolerance,186 doc="Allow a clock skew in seconds for SAML Attribute"187 " Query issueInstant parameter check")188 189 96 def _createQuery(self): 190 97 """ Create a SAML attribute query""" 191 attributeQuery = AttributeQuery() 192 attributeQuery.version = SAMLVersion(SAMLVersion.VERSION_20) 193 attributeQuery.id = str(uuid4()) 194 attributeQuery.issueInstant = datetime.utcnow() 195 196 if self.issuerName is None: 197 raise AttributeError('No issuer DN has been set for SAML Attribute ' 198 'Query') 199 200 attributeQuery.issuer = Issuer() 201 attributeQuery.issuer.format = Issuer.X509_SUBJECT 202 attributeQuery.issuer.value = self.issuerName 203 204 attributeQuery.subject = Subject() 205 attributeQuery.subject.nameID = NameID() 206 attributeQuery.subject.nameID.format = EsgSamlNamespaces.NAMEID_FORMAT 207 attributeQuery.subject.nameID.value = self.subjectID 208 98 attributeQuery = super(AttributeQuerySOAPBinding, self)._createQuery( 99 AttributeQuerySOAPBinding) 209 100 # Add list of attributes to query 210 101 for attribute in self.queryAttributes: 211 102 attributeQuery.attributes.append(attribute) 212 103 213 return attributeQuery 214 215 def send(self, **kw): 216 '''Make an attribute query to a remote SAML service 217 218 @type uri: basestring 219 @param uri: uri of service. May be omitted if set from request.url 220 @type request: ndg.security.common.soap.UrlLib2SOAPRequest 221 @param request: SOAP request object to which query will be attached 222 defaults to ndg.security.common.soap.client.UrlLib2SOAPRequest 223 ''' 224 attributeQuery = self._createQuery() 225 226 response = super(AttributeQuerySOAPBinding, self).send(attributeQuery, 227 **kw) 228 229 # Perform validation 230 if response.status.statusCode.value != StatusCode.SUCCESS_URI: 231 msg = ('Return status code flagged an error. The message is: %r' % 232 response.status.statusMessage.value) 233 samlRespError = AttributeQueryResponseError(msg) 234 samlRespError.response = response 235 raise samlRespError 236 237 # Check Query ID matches the query ID the service received 238 if response.inResponseTo != attributeQuery.id: 239 msg = ('Response in-response-to ID %r, doesn\'t match the original ' 240 'query ID, %r' % (response.inResponseTo, attributeQuery.id)) 241 242 samlRespError = AttributeQueryResponseError(msg) 243 samlRespError.response = response 244 raise samlRespError 245 246 utcNow = datetime.utcnow() + self.clockSkewTolerance 247 if response.issueInstant > utcNow: 248 msg = ('SAML Attribute Response issueInstant [%s] is after ' 249 'the current clock time [%s]' % 250 (attributeQuery.issueInstant, SAMLDateTime.toString(utcNow))) 251 252 samlRespError = AttributeQueryResponseError(msg) 253 samlRespError.response = response 254 raise samlRespError 255 256 for assertion in response.assertions: 257 if assertion.conditions is not None: 258 if utcNow < assertion.conditions.notBefore: 259 msg = ('The current clock time [%s] is before the SAML ' 260 'Attribute Response assertion conditions not before ' 261 'time [%s]' % 262 (SAMLDateTime.toString(utcNow), 263 assertion.conditions.notBefore)) 264 265 samlRespError = AttributeQueryResponseError(msg) 266 samlRespError.response = response 267 raise samlRespError 268 269 if utcNow >= assertion.conditions.notOnOrAfter: 270 msg = ('The current clock time [%s] is on or after the ' 271 'SAML Attribute Response assertion conditions not ' 272 'on or after time [%s]' % 273 (SAMLDateTime.toString(utcNow), 274 response.assertion.conditions.notOnOrAfter)) 275 276 samlRespError = AttributeQueryResponseError(msg) 277 samlRespError.response = response 278 raise samlRespError 279 280 return response 104 return attributeQuery 281 105 282 106 -
TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/authzdecisionquery.py
r6566 r6567 12 12 import logging 13 13 log = logging.getLogger(__name__) 14 15 from M2Crypto.m2urllib2 import HTTPSHandler 16 17 from saml.saml2.core import AuthzDecisionQuery 18 19 from ndg.security.common.sam_utils.binding.soap.subjectquery import ( 20 SubjectQuerySOAPBinding, 21 SubjectQueryResponseError) 22 23 # Prevent whole module breaking if this is not available - it's only needed for 24 # AuthzDecisionQuerySslSOAPBinding 25 try: 26 from ndg.security.common.utils.m2crypto import SSLContextProxy 27 _sslContextProxySupport = True 28 29 except ImportError: 30 _sslContextProxySupport = False 31 32 33 class AuthzDecisionQueryResponseError(SubjectQueryResponseError): 34 """SAML Response error from Attribute Query""" 35 36 37 class AuthzDecisionQuerySOAPBinding(SubjectQuerySOAPBinding): 38 """SAML Attribute Query SOAP Binding 39 40 Nb. Assumes X.509 subject type for query issuer 41 """ 42 __slots__ = () 43 44 def __init__(self, **kw): 45 '''Create SOAP Client for SAML Authorization Decision Query''' 46 super(AuthzDecisionQuerySOAPBinding, self).__init__(**kw) 47 48 49 def _createQuery(self): 50 """Specialisation to force creation of AuthzDecisionQuery type instead 51 of SubjectQuery 52 """ 53 return super(AuthzDecisionQuerySOAPBinding, self)._createQuery( 54 AuthzDecisionQuery) 55 56 57 class AuthzDecisionQuerySslSOAPBinding(AuthzDecisionQuerySOAPBinding): 58 """Specialisation of AuthzDecisionQuerySOAPbinding taking in the setting of 59 SSL parameters for mutual authentication 60 """ 61 SSL_CONTEXT_PROXY_SUPPORT = _sslContextProxySupport 62 __slots__ = ('__sslCtxProxy',) 63 64 def __init__(self, **kw): 65 if not AuthzDecisionQuerySslSOAPBinding.SSL_CONTEXT_PROXY_SUPPORT: 66 raise ImportError("ndg.security.common.utils.m2crypto import " 67 "failed - missing M2Crypto package?") 68 69 # Miss out default HTTPSHandler and set in send() instead 70 if 'handlers' in kw: 71 raise TypeError("__init__() got an unexpected keyword argument " 72 "'handlers'") 73 74 super(AuthzDecisionQuerySslSOAPBinding, self).__init__(handlers=(), 75 **kw) 76 self.__sslCtxProxy = SSLContextProxy() 77 78 def send(self, **kw): 79 """Override base class implementation to pass explicit SSL Context 80 """ 81 httpsHandler = HTTPSHandler(ssl_context=self.sslCtxProxy.createCtx()) 82 self.client.openerDirector.add_handler(httpsHandler) 83 return super(AuthzDecisionQuerySslSOAPBinding, self).send(**kw) 84 85 @property 86 def sslCtxProxy(self): 87 """SSL Context Proxy object used for setting up an SSL Context for 88 queries 89 """ 90 return self.__sslCtxProxy 91 92 def __setattr__(self, name, value): 93 """Enable setting of SSLContextProxy attributes as if they were 94 attributes of this class. This is intended as a convenience for 95 making settings parameters read from a config file 96 """ 97 try: 98 super(AuthzDecisionQuerySslSOAPBinding, self).__setattr__(name, 99 value) 100 101 except AttributeError: 102 # Coerce into setting SSL Context Proxy attributes 103 try: 104 setattr(self.sslCtxProxy, name, value) 105 except: 106 raise -
TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/subjectquery.py
r6566 r6567 1 """SAML 2.0 bindings module implements SOAP binding for subject query 2 3 NERC DataGrid Project 4 """ 5 __author__ = "P J Kershaw" 6 __date__ = "12/02/10" 7 __copyright__ = "(C) 2010 Science and Technology Facilities Council" 8 __license__ = "BSD - see LICENSE file in top-level directory" 9 __contact__ = "Philip.Kershaw@stfc.ac.uk" 10 __revision__ = '$Id: $' 11 import logging 12 log = logging.getLogger(__name__) 13 14 from datetime import datetime, timedelta 15 16 from saml.common import SAMLObject 17 from saml.utils import SAMLDateTime 18 from saml.saml2.core import (Attribute, AttributeQuery, StatusCode, Response, 19 Issuer, Subject, SAMLVersion, NameID) 20 21 from ndg.security.common.saml_utils.binding.soap import (SOAPBinding, 22 SOAPBindingInvalidResponse) 23 24 25 class SubjectQueryResponseError(SOAPBindingInvalidResponse): 26 """SAML Response error from Subject Query""" 27 def __init__(self, *arg, **kw): 28 SOAPBindingInvalidResponse.__init__(self, *arg, **kw) 29 self.__response = None 30 31 def _getResponse(self): 32 '''Gets the response corresponding to this error 33 34 @return the response 35 ''' 36 return self.__response 37 38 def _setResponse(self, value): 39 '''Sets the response corresponding to this error. 40 41 @param value: the response 42 ''' 43 if not isinstance(value, Response): 44 raise TypeError('"response" must be a %r, got %r' % (Response, 45 type(value))) 46 self.__response = value 47 48 response = property(fget=_getResponse, fset=_setResponse, 49 doc="SAML Response associated with this exception") 1 50 2 51 3 52 class SubjectQuerySOAPBinding(SOAPBinding): 4 53 """SAML Subject Query SOAP Binding 5 6 Nb. Assumes X.509 subject type for query issuer7 54 """ 8 55 SUBJECT_ID_OPTNAME = 'subjectID' … … 26 73 '''Create SOAP Client for SAML Attribute Query''' 27 74 self.__issuerName = None 75 self.__issuerFormat = Issuer.X509_SUBJECT 76 self.__nameIdFormat = NameID.UNSPECIFIED 28 77 self.__clockSkewTolerance = timedelta(seconds=0.) 29 78 self.__verifyTimeConditions = True 30 79 31 80 super(SubjectQuerySOAPBinding, self).__init__(**kw) 81 82 def _getNameIdFormat(self): 83 return self.__nameIdFormat 84 85 def _setNameIdFormat(self, value): 86 self.__nameIdFormat = value 87 88 nameIdFormat = property(_getNameIdFormat, _setNameIdFormat, 89 doc="Subject Name ID format") 90 91 def _getIssuerFormat(self): 92 return self.__issuerFormat 93 94 def _setIssuerFormat(self, value): 95 if not isinstance(value, basestring): 96 raise TypeError('Expecting string type for "issuerFormat"; got %r ' 97 'instead' % type(value)) 98 self.__issuerFormat = value 99 100 issuerFormat = property(_getIssuerFormat, _setIssuerFormat, 101 doc="Issuer format") 32 102 33 103 def _getVerifyTimeConditions(self): … … 119 189 120 190 query.issuer = Issuer() 121 query.issuer.format = Issuer.X509_SUBJECT191 query.issuer.format = self.issuerFormat 122 192 query.issuer.value = self.issuerName 123 193 124 194 query.subject = Subject() 125 195 query.subject.nameID = NameID() 126 query.subject.nameID.format = EsgSamlNamespaces.NAMEID_FORMAT196 query.subject.nameID.format = self.nameIdFormat 127 197 query.subject.nameID.value = self.subjectID 128 198
Note: See TracChangeset
for help on using the changeset viewer.