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 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 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]