def xsstringAttributeValueParser(self, attrVal): """Convert string attribute value retrieved from database query into the respective SAML Attribute Value type """ xsstringAttrVal = XSStringAttributeValue() xsstringAttrVal.value = attrVal return xsstringAttrVal
def createAttributes(self): """Create SAML Attributes for use in an Assertion or AttributeQuery""" attributes = [] if self.firstName is not None: # special case handling for 'FirstName' attribute fnAttribute = Attribute() fnAttribute.name = "urn:esg:first:name" fnAttribute.nameFormat = SAMLUtil.XSSTRING_NS fnAttribute.friendlyName = "FirstName" firstName = XSStringAttributeValue() firstName.value = self.firstName fnAttribute.attributeValues.append(firstName) attributes.append(fnAttribute) if self.lastName is not None: # special case handling for 'LastName' attribute lnAttribute = Attribute() lnAttribute.name = "urn:esg:last:name" lnAttribute.nameFormat = SAMLUtil.XSSTRING_NS lnAttribute.friendlyName = "LastName" lastName = XSStringAttributeValue() lastName.value = self.lastName lnAttribute.attributeValues.append(lastName) attributes.append(lnAttribute) if self.emailAddress is not None: # special case handling for 'LastName' attribute emailAddressAttribute = Attribute() emailAddressAttribute.name = "urn:esg:email:address" emailAddressAttribute.nameFormat = SAMLConstants.XSD_NS+"#"+\ XSStringAttributeValue.TYPE_LOCAL_NAME emailAddressAttribute.friendlyName = "emailAddress" emailAddress = XSStringAttributeValue() emailAddress.value = self.emailAddress emailAddressAttribute.attributeValues.append(emailAddress) attributes.append(emailAddressAttribute) for name, value in self.__miscAttrList: attribute = Attribute() attribute.name = name attribute.nameFormat = SAMLUtil.XSSTRING_NS stringAttributeValue = XSStringAttributeValue() stringAttributeValue.value = value attribute.attributeValues.append(stringAttributeValue) attributes.append(attribute) return attributes
def attributeQuery(query, response): """Attribute Query interface called by the next middleware in the stack the SAML SOAP Query interface middleware instance (ndg.saml.saml2.binding.soap.server.wsgi.queryinterface.SOAPQueryInterfaceMiddleware) """ response.issueInstant = datetime.utcnow() response.id = str(uuid4()) response.inResponseTo = query.id if query.issuer.value not in self.__class__.VALID_QUERY_ISSUERS: response.status.statusCode.value = \ StatusCode.REQUEST_DENIED_URI response.status.statusMessage.value = 'Invalid issuer' return response if query.subject.nameID.value not in self.__class__.VALID_SUBJECTS: response.status.statusCode.value = \ StatusCode.UNKNOWN_PRINCIPAL_URI response.status.statusMessage.value = 'Unknown user' return response assertion = Assertion() assertion.version = SAMLVersion(SAMLVersion.VERSION_20) assertion.id = str(uuid4()) assertion.issueInstant = response.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 = query.subject.nameID.format assertion.subject.nameID.value = query.subject.nameID.value assertion.attributeStatements.append(AttributeStatement()) for attribute in query.attributes: if attribute.name == self.__class__.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 == self.__class__.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 == self.__class__.EMAILADDRESS_ATTRNAME and query.issuer.value == self.__class__.VALID_QUERY_ISSUERS[0]): 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) else: response.status.statusCode.value = \ StatusCode.INVALID_ATTR_NAME_VALUE_URI return response response.assertions.append(assertion) response.status.statusCode.value = StatusCode.SUCCESS_URI return response
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]
class TestUserRoles(AttributeInterface): """Test User Roles class dynamic import for Attribute Authority""" ATTRIBUTE_NAMES = () ATTRIBUTE_VALUES = () SAML_ATTRIBUTE_NAMES = ATTRIBUTE_NAMES + ( ESGFSamlNamespaces.EMAILADDRESS_ATTRNAME, ESGFSamlNamespaces.FIRSTNAME_ATTRNAME, ESGFSamlNamespaces.LASTNAME_ATTRNAME, 'urn:esg:sitea:grouprole') SAML_ATTRIBUTE_VALUES = (ATTRIBUTE_VALUES, ('*****@*****.**', ), ('Philip', ), ('Kershaw', ), (('siteagroup', 'default'), )) SAML_ATTRIBUTE_FRIENDLY_NAMES = ('', ) * len(ATTRIBUTE_NAMES) + ( "EmailAddress", "FirstName", "LastName", "groupRole") SAML_ATTRIBUTE_FORMATS = ( SAMLConstants.XSD_NS+"#"+XSStringAttributeValue.TYPE_LOCAL_NAME,) * ( len(SAML_ATTRIBUTE_NAMES)-1) + \ (ESGFGroupRoleAttributeValue.TYPE_LOCAL_NAME, ) SAML_ATTRIBUTES = [] name, val, vals, format, friendlyName = (None, None, None, None, None) for name, vals, format, friendlyName in zip(SAML_ATTRIBUTE_NAMES, SAML_ATTRIBUTE_VALUES, SAML_ATTRIBUTE_FORMATS, SAML_ATTRIBUTE_FRIENDLY_NAMES): SAML_ATTRIBUTES.append(Attribute()) SAML_ATTRIBUTES[-1].name = name SAML_ATTRIBUTES[-1].nameFormat = format SAML_ATTRIBUTES[-1].friendlyName = friendlyName for val in vals: if isinstance(val, tuple): SAML_ATTRIBUTES[-1].attributeValues.append( ESGFGroupRoleAttributeValue()) SAML_ATTRIBUTES[-1].attributeValues[-1].value = val else: SAML_ATTRIBUTES[-1].attributeValues.append( XSStringAttributeValue()) SAML_ATTRIBUTES[-1].attributeValues[-1].value = val del name, val, vals, format, friendlyName # 8 hours validity for issued assertions SAML_ASSERTION_LIFETIME = 8 * 60 * 60 VALID_USER_IDS = ("https://openid.localhost/philip.kershaw", TestUserDatabase.OPENID_URI) VALID_REQUESTOR_IDS = BaseTestCase.VALID_REQUESTOR_IDS INSUFFICIENT_PRIVILEGES_REQUESTOR_ID = X500DN.from_string( "/O=Site B/CN=Authorisation Service") def __init__(self, propertiesFilePath=None): pass def getRoles(self, userId): return TestUserRoles.ATTRIBUTE_VALUES def getAttributes(self, attributeQuery, response): '''Test Attribute Authority SAML Attribute Query interface''' userId = attributeQuery.subject.nameID.value requestedAttributeNames = [ attribute.name for attribute in attributeQuery.attributes ] if attributeQuery.issuer.format != Issuer.X509_SUBJECT: raise InvalidRequestorId( 'Requestor issuer format "%s" is invalid' % attributeQuery.issuerFormat.value) requestorId = X500DN.fromString(attributeQuery.issuer.value) if userId not in TestUserRoles.VALID_USER_IDS: raise UserIdNotKnown('Subject Id "%s" is not known to this ' 'authority' % userId) if requestorId not in TestUserRoles.VALID_REQUESTOR_IDS: raise InvalidRequestorId('Requestor identity "%s" is invalid' % requestorId) unknownAttrNames = [ attrName for attrName in requestedAttributeNames if attrName not in TestUserRoles.SAML_ATTRIBUTE_NAMES ] if len(unknownAttrNames) > 0: raise AttributeNotKnownError("Unknown attributes requested: %r" % unknownAttrNames) if requestorId == TestUserRoles.INSUFFICIENT_PRIVILEGES_REQUESTOR_ID: raise AttributeReleaseDenied("Attribute release denied for the " 'requestor "%s"' % requestorId) # Create a new assertion to hold the attributes to be returned assertion = Assertion() assertion.version = SAMLVersion(SAMLVersion.VERSION_20) assertion.id = str(uuid4()) assertion.issueInstant = response.issueInstant assertion.issuer = Issuer() assertion.issuer.value = response.issuer.value assertion.issuer.format = Issuer.X509_SUBJECT assertion.conditions = Conditions() assertion.conditions.notBefore = assertion.issueInstant assertion.conditions.notOnOrAfter = assertion.conditions.notBefore + \ timedelta(seconds=TestUserRoles.SAML_ASSERTION_LIFETIME) assertion.subject = Subject() assertion.subject.nameID = NameID() assertion.subject.nameID.format = attributeQuery.subject.nameID.format assertion.subject.nameID.value = attributeQuery.subject.nameID.value attributeStatement = AttributeStatement() # Add test set of attributes for name in requestedAttributeNames: attributeFound = False for attribute in TestUserRoles.SAML_ATTRIBUTES: if attribute.name == name: attributeFound = True break if attributeFound: attributeStatement.attributes.append(attribute) else: raise AttributeNotKnownError( "Unknown attribute requested: %s" % name) assertion.attributeStatements.append(attributeStatement) response.assertions.append(assertion)