def _makeRequestForQuery(self, query): """Wraps an XACMLAuthzDecisionQuery in a SOAP request. """ elem = XACMLAuthzDecisionQueryElementTree.toXML(query) soapRequest = SOAPEnvelope() soapRequest.create() soapRequest.body.elem.append(elem) request = soapRequest.serialize() return request
def test01SendRequest(self): requestEnvelope = SOAPEnvelope() requestEnvelope.create() request = requestEnvelope.serialize() response = self.app.post('/my-soap-endpoint', params=request, status=200) print((response.headers)) print((response.status)) print((response.body))
def _do_test(self, resourceContentsStr, expected_status, expected_decision): """Constructs, sends and evaluates the response from a SAML SOAP request using the XACML-SAML profile, with specified resource contents. """ # Load the AuthorisationServiceMiddleware and # SOAPQueryInterfaceMiddleware so that the authorisation service can be # called. self.__class__.INI_FILEPATH = os.path.join(self.__class__.THIS_DIR, self.__class__.INI_FILE) wsgiapp = loadapp('config:'+self.__class__.INI_FILEPATH) self.app = paste.fixture.TestApp(wsgiapp) # Construct a SOAP request. (header, request) = self._makeRequest(resourceContentsStr, issuer=self.ISSUER_DN) # Send the SOAP request to the authorisation service. httpResponse = self.app.post(self.AUTHZ_SERVICE_URI, params=request, headers=header, status=200) log.debug("Response status=%d", httpResponse.status) # Parse the SOAP response. envelope = SOAPEnvelope() respFile = StringIO(httpResponse.body) envelope.parse(respFile) # Extract the SAML response. samlAuthzResponse = ResponseElementTree.fromXML(envelope.body.elem[0]) # serialisedResponse = pickle.dumps(samlAuthzResponse) # response2 = pickle.loads(serialisedResponse) assertions = samlAuthzResponse.assertions (assertion, error_status, error_message) = XacmlSamlPepFilter._evaluate_assertions(assertions, self.SUBJECT_ID, self.RESOURCE_URI, self.AUTHZ_SERVICE_URI) if expected_status is None: self.assertTrue(error_status is None, ("Unexpected error %d: %s" % (0 if error_status is None else error_status, error_message))) self.assertEqual( assertion.statements[0].xacmlContextResponse.results[0 ].decision.value, expected_decision) else: self.assertEqual(error_status, expected_status)
def _makeRequest(self, attributeQuery=None, **kw): """Convenience method to construct queries for tests""" if attributeQuery is None: attributeQuery = self._createAttributeQuery(**kw) elem = AttributeQueryElementTree.toXML(attributeQuery) soapRequest = SOAPEnvelope() soapRequest.create() soapRequest.body.elem.append(elem) request = soapRequest.serialize() return request
def __call__(self, environ, start_response): requestFile = environ['wsgi.input'] print(("Server received request from client:\n\n%s" % requestFile.read())) soapResponse = SOAPEnvelope() soapResponse.create() response = soapResponse.serialize() start_response("200 OK", [('Content-length', str(len(response))), ('Content-type', 'text/xml')]) return [response]
def _parseResponse(self, responseStr): """Helper to parse a response from a string""" soapResponse = SOAPEnvelope() responseStream = StringIO() responseStream.write(responseStr) responseStream.seek(0) soapResponse.parse(responseStream) print("Parsed response ...") print(soapResponse.serialize()) response = ResponseElementTree.fromXML(soapResponse.body.elem[0]) return response
def _getSAMLResponse(self, responseBody): """Deserialise response string into ElementTree element""" soapResponse = SOAPEnvelope() responseStream = StringIO() responseStream.write(responseBody.decode()) responseStream.seek(0) soapResponse.parse(responseStream) print("Parsed response ...") print((soapResponse.serialize())) response = ResponseElementTree.fromXML(soapResponse.body.elem[0]) return response
def test01Envelope(self): envelope = SOAPEnvelope() envelope.create() soap = envelope.serialize().decode() self.assertTrue(len(soap) > 0) self.assertTrue("Envelope" in soap) self.assertTrue("Body" in soap) self.assertTrue("Header" in soap) print((envelope.prettyPrint())) stream = StringIO() stream.write(soap) stream.seek(0) envelope2 = SOAPEnvelope() envelope2.parse(stream) soap2 = envelope2.serialize().decode() self.assertTrue(soap2 == soap)
def test06CreateSOAPFaultResponse(self): # Create full SOAP Response containing a SOAP Fault envelope = SOAPEnvelope() envelope.body.fault = self._createSOAPFault() envelope.create() soap = envelope.serialize() self.assert_(len(soap) > 0) self.assert_("Envelope" in soap) self.assert_("Body" in soap) self.assert_("Header" in soap) self.assert_("Fault" in soap) print(envelope.prettyPrint()) stream = StringIO() stream.write(soap) stream.seek(0) envelope2 = SOAPEnvelope() envelope2.parse(stream) soap2 = envelope2.serialize() self.assert_(soap2 == soap)
def __call__(self, environ, start_response): soapRequestStream = environ['wsgi.input'] soapRequest = SOAPEnvelope() soapRequest.parse(soapRequestStream) attributeQueryElem = soapRequest.body.elem[0] attributeQuery = AttributeQueryElementTree.fromXML(attributeQueryElem) print("Received request from client:\n") print soapRequest.prettyPrint() samlResponse = Response() samlResponse.issueInstant = datetime.utcnow() samlResponse.id = str(uuid4()) samlResponse.issuer = Issuer() # SAML 2.0 spec says format must be omitted #samlResponse.issuer.format = Issuer.X509_SUBJECT samlResponse.issuer.value = \ "/O=NDG/OU=BADC/CN=attributeauthority.badc.rl.ac.uk" samlResponse.inResponseTo = attributeQuery.id assertion = Assertion() assertion.version = SAMLVersion(SAMLVersion.VERSION_20) assertion.id = str(uuid4()) assertion.issueInstant = samlResponse.issueInstant assertion.conditions = Conditions() assertion.conditions.notBefore = assertion.issueInstant assertion.conditions.notOnOrAfter = assertion.conditions.notBefore + \ timedelta(seconds=60*60*8) assertion.subject = Subject() assertion.subject.nameID = NameID() assertion.subject.nameID.format = attributeQuery.subject.nameID.format assertion.subject.nameID.value = attributeQuery.subject.nameID.value assertion.attributeStatements.append(AttributeStatement()) for attribute in attributeQuery.attributes: if attribute.name == SamlSoapBindingApp.FIRSTNAME_ATTRNAME: # special case handling for 'FirstName' attribute fnAttribute = Attribute() fnAttribute.name = attribute.name fnAttribute.nameFormat = attribute.nameFormat fnAttribute.friendlyName = attribute.friendlyName firstName = XSStringAttributeValue() firstName.value = self.firstName fnAttribute.attributeValues.append(firstName) assertion.attributeStatements[0].attributes.append(fnAttribute) elif attribute.name == SamlSoapBindingApp.LASTNAME_ATTRNAME: lnAttribute = Attribute() lnAttribute.name = attribute.name lnAttribute.nameFormat = attribute.nameFormat lnAttribute.friendlyName = attribute.friendlyName lastName = XSStringAttributeValue() lastName.value = self.lastName lnAttribute.attributeValues.append(lastName) assertion.attributeStatements[0].attributes.append(lnAttribute) elif attribute.name == SamlSoapBindingApp.EMAILADDRESS_ATTRNAME: emailAddressAttribute = Attribute() emailAddressAttribute.name = attribute.name emailAddressAttribute.nameFormat = attribute.nameFormat emailAddressAttribute.friendlyName = attribute.friendlyName emailAddress = XSStringAttributeValue() emailAddress.value = self.emailAddress emailAddressAttribute.attributeValues.append(emailAddress) assertion.attributeStatements[0].attributes.append( emailAddressAttribute) samlResponse.assertions.append(assertion) samlResponse.status = Status() samlResponse.status.statusCode = StatusCode() samlResponse.status.statusCode.value = StatusCode.SUCCESS_URI # Convert to ElementTree representation to enable attachment to SOAP # response body samlResponseElem = ResponseElementTree.toXML(samlResponse) xml = ElementTree.tostring(samlResponseElem) log.debug('Sending response to query:\n%s', xml) # Create SOAP response and attach the SAML Response payload soapResponse = SOAPEnvelope() soapResponse.create() soapResponse.body.elem.append(samlResponseElem) response = soapResponse.serialize() start_response("200 OK", [('Content-length', str(len(response))), ('Content-type', 'text/xml')]) return [response]
def test01AttributeQuery(self): attributeQuery = AttributeQuery() attributeQuery.version = SAMLVersion(SAMLVersion.VERSION_20) attributeQuery.id = str(uuid4()) attributeQuery.issueInstant = datetime.utcnow() attributeQuery.issuer = Issuer() attributeQuery.issuer.format = Issuer.X509_SUBJECT attributeQuery.issuer.value = \ "/O=NDG/OU=BADC/CN=attributeauthority.badc.rl.ac.uk" attributeQuery.subject = Subject() attributeQuery.subject.nameID = NameID() attributeQuery.subject.nameID.format = SamlSoapBindingApp.NAMEID_FORMAT attributeQuery.subject.nameID.value = \ "https://openid.localhost/philip.kershaw" # special case handling for 'FirstName' attribute fnAttribute = Attribute() fnAttribute.name = SamlSoapBindingApp.FIRSTNAME_ATTRNAME fnAttribute.nameFormat = "http://www.w3.org/2001/XMLSchema#string" fnAttribute.friendlyName = "FirstName" attributeQuery.attributes.append(fnAttribute) # special case handling for 'LastName' attribute lnAttribute = Attribute() lnAttribute.name = SamlSoapBindingApp.LASTNAME_ATTRNAME lnAttribute.nameFormat = "http://www.w3.org/2001/XMLSchema#string" lnAttribute.friendlyName = "LastName" attributeQuery.attributes.append(lnAttribute) # special case handling for 'LastName' attribute emailAddressAttribute = Attribute() emailAddressAttribute.name = SamlSoapBindingApp.EMAILADDRESS_ATTRNAME emailAddressAttribute.nameFormat = XMLConstants.XSD_NS+"#"+\ XSStringAttributeValue.TYPE_LOCAL_NAME emailAddressAttribute.friendlyName = "emailAddress" attributeQuery.attributes.append(emailAddressAttribute) elem = AttributeQueryElementTree.toXML(attributeQuery) soapRequest = SOAPEnvelope() soapRequest.create() soapRequest.body.elem.append(elem) request = soapRequest.serialize() header = { 'soapAction': "http://www.oasis-open.org/committees/security", 'Content-length': str(len(request)), 'Content-type': 'text/xml' } response = self.app.post('/attributeauthority', params=request, headers=header, status=200) print("Response status=%d" % response.status) soapResponse = SOAPEnvelope() responseStream = StringIO() responseStream.write(response.body) responseStream.seek(0) soapResponse.parse(responseStream) print("Parsed response ...") print(soapResponse.serialize()) # print(prettyPrint(soapResponse.elem)) response = ResponseElementTree.fromXML(soapResponse.body.elem[0]) self.assert_(response.status.statusCode.value==StatusCode.SUCCESS_URI) self.assert_(response.inResponseTo == attributeQuery.id) self.assert_(response.assertions[0].subject.nameID.value == \ attributeQuery.subject.nameID.value)
def __call__(self, environ, start_response): """Check for and parse a SOAP SAML Attribute Query and return a SAML Response :type environ: dict :param environ: WSGI environment variables dictionary :type start_response: function :param start_response: standard WSGI start response function """ # Ignore non-matching path if environ['PATH_INFO'] not in (self.mountPath, self.mountPath + '/'): return self._app(environ, start_response) # Ignore non-POST requests if environ.get('REQUEST_METHOD') != 'POST': return self._app(environ, start_response) soapRequestStream = environ.get('wsgi.input') if soapRequestStream is None: raise SOAPQueryInterfaceMiddlewareError('No "wsgi.input" in ' 'environ') # TODO: allow for chunked data contentLength = environ.get('CONTENT_LENGTH') if contentLength is None: raise SOAPQueryInterfaceMiddlewareError('No "CONTENT_LENGTH" in ' 'environ') contentLength = int(contentLength) if contentLength <= 0: raise SOAPQueryInterfaceMiddlewareError('"CONTENT_LENGTH" in ' 'environ is %d' % contentLength) soapRequestTxt = soapRequestStream.read(contentLength) # Parse into a SOAP envelope object soapRequest = SOAPEnvelope() soapRequest.parse(StringIO(soapRequestTxt)) log.debug("SOAPQueryInterfaceMiddleware.__call__: received SAML " "SOAP Query: %s", soapRequestTxt) queryElem = soapRequest.body.elem[0] # Create a response with basic attributes if provided in the # initialisation config samlResponse = self._initResponse() try: queryType = QName.getLocalPart(queryElem.tag) if queryType == XACMLAuthzDecisionQuery.DEFAULT_ELEMENT_LOCAL_NAME: # Set up additional ElementTree parsing for XACML profile. etree_xacml_profile.setElementTreeMap() samlQuery = self.deserialiseXacmlProfile(queryElem) else: samlQuery = self.deserialise(queryElem) except UnknownAttrProfile, e: log.exception("%r raised parsing incoming query: %s" % (type(e), traceback.format_exc())) samlResponse.status.statusCode.value = \ StatusCode.UNKNOWN_ATTR_PROFILE_URI
(queryInterface, self.queryInterfaceKeyName)) # Basic validation self._validateQuery(samlQuery, samlResponse) samlResponse.inResponseTo = samlQuery.id # Call query interface queryInterface(samlQuery, samlResponse) # Convert to ElementTree representation to enable attachment to SOAP # response body samlResponseElem = self.serialise(samlResponse) # Create SOAP response and attach the SAML Response payload soapResponse = SOAPEnvelope() soapResponse.create() soapResponse.body.elem.append(samlResponseElem) response = soapResponse.serialize() log.debug("SOAPQueryInterfaceMiddleware.__call__: sending response " "...\n\n%s", response) start_response("200 OK", [('Content-length', str(len(response))), ('Content-type', 'text/xml')]) return [response] def _validateQuery(self, query, response): """Checking incoming query issue instant and version