def _initResponse(self): """Create a SAML Response object with basic settings if any have been provided at initialisation of this class - see initialise :return: SAML response object :rtype: ndg.saml.saml2.core.Response """ samlResponse = Response() utcNow = datetime.utcnow() samlResponse.issueInstant = utcNow samlResponse.id = str(uuid4()) samlResponse.issuer = Issuer() if self.issuerName is not None: samlResponse.issuer.value = self.issuerName if self.issuerFormat is not None: # TODO: Check SAML 2.0 spec says issuer format must be omitted?? samlResponse.issuer.format = self.issuerFormat # Initialise to success status but reset on error samlResponse.status = Status() samlResponse.status.statusCode = StatusCode() samlResponse.status.statusMessage = StatusMessage() samlResponse.status.statusCode.value = StatusCode.SUCCESS_URI samlResponse.status.statusMessage = StatusMessage() return samlResponse
def create_authz_decision_query_response(cls): """Helper method for Authz Decision Response""" response = Response() now = datetime.utcnow() response.issueInstant = now # Make up a request ID that this response is responding to response.inResponseTo = str(uuid4()) response.id = str(uuid4()) response.version = SAMLVersion(SAMLVersion.VERSION_20) response.issuer = Issuer() response.issuer.format = Issuer.X509_SUBJECT response.issuer.value = cls.ISSUER_DN response.status = Status() response.status.statusCode = StatusCode() response.status.statusCode.value = StatusCode.SUCCESS_URI response.status.statusMessage = StatusMessage() response.status.statusMessage.value = "Response created successfully" assertion = Assertion() assertion.version = SAMLVersion(SAMLVersion.VERSION_20) assertion.id = str(uuid4()) assertion.issueInstant = now authzDecisionStatement = AuthzDecisionStatement() authzDecisionStatement.decision = DecisionType.PERMIT authzDecisionStatement.resource = cls.RESOURCE_URI authzDecisionStatement.actions.append(Action()) authzDecisionStatement.actions[-1].namespace = Action.GHPP_NS_URI authzDecisionStatement.actions[-1].value = Action.HTTP_GET_ACTION assertion.authzDecisionStatements.append(authzDecisionStatement) # Add a conditions statement for a validity of 8 hours assertion.conditions = Conditions() assertion.conditions.notBefore = now assertion.conditions.notOnOrAfter = now + timedelta(seconds=60*60*8) assertion.subject = Subject() assertion.subject.nameID = NameID() assertion.subject.nameID.format = cls.NAMEID_FORMAT assertion.subject.nameID.value = cls.NAMEID_VALUE assertion.issuer = Issuer() assertion.issuer.format = Issuer.X509_SUBJECT assertion.issuer.value = cls.ISSUER_DN response.assertions.append(assertion) return response
def _createAttributeQueryResponse(self): response = Response() response.issueInstant = datetime.utcnow() # Make up a request ID that this response is responding to response.inResponseTo = str(uuid4()) response.id = str(uuid4()) response.version = SAMLVersion(SAMLVersion.VERSION_20) response.issuer = Issuer() response.issuer.format = Issuer.X509_SUBJECT response.issuer.value = \ SAMLTestCase.ISSUER_DN response.status = Status() response.status.statusCode = StatusCode() response.status.statusCode.value = StatusCode.SUCCESS_URI response.status.statusMessage = StatusMessage() response.status.statusMessage.value = "Response created successfully" assertion = self._createAttributeAssertionHelper() # Add a conditions statement for a validity of 8 hours assertion.conditions = Conditions() assertion.conditions.notBefore = datetime.utcnow() assertion.conditions.notOnOrAfter = (assertion.conditions.notBefore + timedelta(seconds=60*60*8)) assertion.subject = Subject() assertion.subject.nameID = NameID() assertion.subject.nameID.format = SAMLTestCase.NAMEID_FORMAT assertion.subject.nameID.value = SAMLTestCase.NAMEID_VALUE assertion.issuer = Issuer() assertion.issuer.format = Issuer.X509_SUBJECT assertion.issuer.value = SAMLTestCase.ISSUER_DN response.assertions.append(assertion) return response
def test05SamlAttributeQuery(self): if self.skipTests: return # Prepare a client query 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=ESG/OU=NCAR/CN=Gateway' attributeQuery.subject = Subject() attributeQuery.subject.nameID = NameID() attributeQuery.subject.nameID.format = ESGFSamlNamespaces.NAMEID_FORMAT attributeQuery.subject.nameID.value = \ SQLAlchemyAttributeInterfaceTestCase.OPENID_URI emailAddressAttribute = Attribute() emailAddressAttribute.name = ESGFSamlNamespaces.EMAILADDRESS_ATTRNAME emailAddressAttribute.nameFormat = "InvalidFormat" emailAddressAttribute.friendlyName = "EmailAddress" attributeQuery.attributes.append(emailAddressAttribute) authzAttribute = Attribute() authzAttribute.name = \ SQLAlchemyAttributeInterfaceTestCase.ATTRIBUTE_NAMES[0] authzAttribute.nameFormat = XSStringAttributeValue.DEFAULT_FORMAT authzAttribute.friendlyName = "authz" attributeQuery.attributes.append(authzAttribute) # Add the response - the interface will populate with an assertion as # appropriate samlResponse = Response() samlResponse.issueInstant = datetime.utcnow() samlResponse.id = str(uuid4()) samlResponse.issuer = Issuer() # Initialise to success status but reset on error samlResponse.status = Status() samlResponse.status.statusCode = StatusCode() samlResponse.status.statusMessage = StatusMessage() samlResponse.status.statusCode.value = StatusCode.SUCCESS_URI # Nb. SAML 2.0 spec says issuer format must be omitted samlResponse.issuer.value = "CEDA" samlResponse.inResponseTo = attributeQuery.id # Set up the interface object # Define queries for SAML attribute names samlAttribute2SqlQuery = { ESGFSamlNamespaces.FIRSTNAME_ATTRNAME: SQLAlchemyAttributeInterfaceTestCase.SAML_FIRSTNAME_SQLQUERY, ESGFSamlNamespaces.LASTNAME_ATTRNAME: SQLAlchemyAttributeInterfaceTestCase.SAML_LASTNAME_SQLQUERY, ESGFSamlNamespaces.EMAILADDRESS_ATTRNAME: SQLAlchemyAttributeInterfaceTestCase.SAML_EMAILADDRESS_SQLQUERY, SQLAlchemyAttributeInterfaceTestCase.ATTRIBUTE_NAMES[0]: SQLAlchemyAttributeInterfaceTestCase.SAML_ATTRIBUTES_SQLQUERY } attributeInterface = SQLAlchemyAttributeInterface( samlAttribute2SqlQuery=samlAttribute2SqlQuery) attributeInterface.connectionString = \ SQLAlchemyAttributeInterfaceTestCase.DB_CONNECTION_STR attributeInterface.samlValidRequestorDNs = ( '/O=STFC/OU=CEDA/CN=AuthorisationService', '/O=ESG/OU=NCAR/CN=Gateway') attributeInterface.setProperties(samlAssertionLifetime=28800.) attributeInterface.samlSubjectSqlQuery = ( SQLAlchemyAttributeInterfaceTestCase.SAML_SUBJECT_SQLQUERY) # Make the query try: attributeInterface.getAttributes(attributeQuery, samlResponse) except InvalidAttributeFormat: print("PASSED: caught InvalidAttributeFormat exception") else: self.fail("Expecting InvalidAttributeFormat exception")
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 test05SamlAttributeQuery(self): if self.skipTests: return # Prepare a client query 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=ESG/OU=NCAR/CN=Gateway' attributeQuery.subject = Subject() attributeQuery.subject.nameID = NameID() attributeQuery.subject.nameID.format = ESGFSamlNamespaces.NAMEID_FORMAT attributeQuery.subject.nameID.value = TestUserDatabase.OPENID_URI emailAddressAttribute = Attribute() emailAddressAttribute.name = ESGFSamlNamespaces.EMAILADDRESS_ATTRNAME emailAddressAttribute.nameFormat = "InvalidFormat" emailAddressAttribute.friendlyName = "EmailAddress" attributeQuery.attributes.append(emailAddressAttribute) authzAttribute = Attribute() authzAttribute.name = TestUserDatabase.ATTRIBUTE_NAMES[0] authzAttribute.nameFormat = XSStringAttributeValue.DEFAULT_FORMAT authzAttribute.friendlyName = "authz" attributeQuery.attributes.append(authzAttribute) # Add the response - the interface will populate with an assertion as # appropriate samlResponse = Response() samlResponse.issueInstant = datetime.utcnow() samlResponse.id = str(uuid4()) samlResponse.issuer = Issuer() # Initialise to success status but reset on error samlResponse.status = Status() samlResponse.status.statusCode = StatusCode() samlResponse.status.statusMessage = StatusMessage() samlResponse.status.statusCode.value = StatusCode.SUCCESS_URI # Nb. SAML 2.0 spec says issuer format must be omitted samlResponse.issuer.value = "CEDA" samlResponse.inResponseTo = attributeQuery.id # Set up the interface object # Define queries for SAML attribute names samlAttribute2SqlQuery = { ESGFSamlNamespaces.FIRSTNAME_ATTRNAME: self.__class__.SAML_FIRSTNAME_SQLQUERY, ESGFSamlNamespaces.LASTNAME_ATTRNAME: self.__class__.SAML_LASTNAME_SQLQUERY, ESGFSamlNamespaces.EMAILADDRESS_ATTRNAME: self.__class__.SAML_EMAILADDRESS_SQLQUERY, TestUserDatabase.ATTRIBUTE_NAMES[0]: self.__class__.SAML_ATTRIBUTES_SQLQUERY } attributeInterface = SQLAlchemyAttributeInterface( samlAttribute2SqlQuery=samlAttribute2SqlQuery) attributeInterface.connectionString = TestUserDatabase.DB_CONNECTION_STR attributeInterface.samlValidRequestorDNs = ( '/O=STFC/OU=CEDA/CN=AuthorisationService', '/O=ESG/OU=NCAR/CN=Gateway') attributeInterface.setProperties(samlAssertionLifetime=28800.) attributeInterface.samlSubjectSqlQuery = ( SQLAlchemyAttributeInterfaceTestCase.SAML_SUBJECT_SQLQUERY) # Make the query attributeInterface.getAttributes(attributeQuery, samlResponse)
def test04SamlAttributeQuery(self): if self.skipTests: return # Prepare a client query 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=ESG/OU=NCAR/CN=Gateway' attributeQuery.subject = Subject() attributeQuery.subject.nameID = NameID() attributeQuery.subject.nameID.format = ESGFSamlNamespaces.NAMEID_FORMAT attributeQuery.subject.nameID.value = \ TestUserDatabase.OPENID_URI fnAttribute = Attribute() fnAttribute.name = ESGFSamlNamespaces.FIRSTNAME_ATTRNAME fnAttribute.nameFormat = XSStringAttributeValue.DEFAULT_FORMAT fnAttribute.friendlyName = "FirstName" attributeQuery.attributes.append(fnAttribute) lnAttribute = Attribute() lnAttribute.name = ESGFSamlNamespaces.LASTNAME_ATTRNAME lnAttribute.nameFormat = XSStringAttributeValue.DEFAULT_FORMAT lnAttribute.friendlyName = "LastName" attributeQuery.attributes.append(lnAttribute) emailAddressAttribute = Attribute() emailAddressAttribute.name = ESGFSamlNamespaces.EMAILADDRESS_ATTRNAME emailAddressAttribute.nameFormat = XSStringAttributeValue.DEFAULT_FORMAT emailAddressAttribute.friendlyName = "EmailAddress" attributeQuery.attributes.append(emailAddressAttribute) authzAttribute = Attribute() authzAttribute.name = \ TestUserDatabase.ATTRIBUTE_NAMES[0] authzAttribute.nameFormat = XSStringAttributeValue.DEFAULT_FORMAT authzAttribute.friendlyName = "authz" attributeQuery.attributes.append(authzAttribute) # Add the response - the interface will populate with an assertion as # appropriate samlResponse = Response() samlResponse.issueInstant = datetime.utcnow() samlResponse.id = str(uuid4()) samlResponse.issuer = Issuer() # Initialise to success status but reset on error samlResponse.status = Status() samlResponse.status.statusCode = StatusCode() samlResponse.status.statusMessage = StatusMessage() samlResponse.status.statusCode.value = StatusCode.SUCCESS_URI # Nb. SAML 2.0 spec says issuer format must be omitted samlResponse.issuer.value = "CEDA" samlResponse.inResponseTo = attributeQuery.id # Set up the interface object # Define queries for SAML attribute names samlAttribute2SqlQuery = { ESGFSamlNamespaces.FIRSTNAME_ATTRNAME: self.__class__.SAML_FIRSTNAME_SQLQUERY, ESGFSamlNamespaces.LASTNAME_ATTRNAME: self.__class__.SAML_LASTNAME_SQLQUERY, ESGFSamlNamespaces.EMAILADDRESS_ATTRNAME: self.__class__.SAML_EMAILADDRESS_SQLQUERY, TestUserDatabase.ATTRIBUTE_NAMES[0]: self.__class__.SAML_ATTRIBUTES_SQLQUERY, } attributeInterface = SQLAlchemyAttributeInterface( samlAttribute2SqlQuery=samlAttribute2SqlQuery) attributeInterface.connectionString = TestUserDatabase.DB_CONNECTION_STR attributeInterface.samlValidRequestorDNs = ( '/O=STFC/OU=CEDA/CN=AuthorisationService', '/O=ESG/OU=NCAR/CN=Gateway') attributeInterface.setProperties(samlAssertionLifetime=28800.) attributeInterface.samlSubjectSqlQuery = ( SQLAlchemyAttributeInterfaceTestCase.SAML_SUBJECT_SQLQUERY) # Make the query attributeInterface.getAttributes(attributeQuery, samlResponse) self.assert_( samlResponse.status.statusCode.value == StatusCode.SUCCESS_URI) self.assert_(samlResponse.inResponseTo == attributeQuery.id) self.assert_(samlResponse.assertions[0].subject.nameID.value == \ attributeQuery.subject.nameID.value) self.assert_( samlResponse.assertions[0].attributeStatements[0].attributes[1 ].attributeValues[0].value == 'Kershaw') self.assert_( len(samlResponse.assertions[0].attributeStatements[0].attributes[3 ].attributeValues) == TestUserDatabase.N_ATTRIBUTE_VALUES)