Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
want_authn_requests_signed = entity_descriptor_node.get('WantAuthnRequestsSigned', None)
name_id_format_nodes = OneLogin_Saml2_Utils.query(idp_descriptor_node, './md:NameIDFormat')
if len(name_id_format_nodes) > 0:
idp_name_id_format = OneLogin_Saml2_Utils.element_text(name_id_format_nodes[0])
sso_nodes = OneLogin_Saml2_Utils.query(
idp_descriptor_node,
"./md:SingleSignOnService[@Binding='%s']" % required_sso_binding
)
if len(sso_nodes) > 0:
idp_sso_url = sso_nodes[0].get('Location', None)
slo_nodes = OneLogin_Saml2_Utils.query(
idp_descriptor_node,
"./md:SingleLogoutService[@Binding='%s']" % required_slo_binding
)
if len(slo_nodes) > 0:
idp_slo_url = slo_nodes[0].get('Location', None)
signing_nodes = OneLogin_Saml2_Utils.query(idp_descriptor_node, "./md:KeyDescriptor[not(contains(@use, 'encryption'))]/ds:KeyInfo/ds:X509Data/ds:X509Certificate")
encryption_nodes = OneLogin_Saml2_Utils.query(idp_descriptor_node, "./md:KeyDescriptor[not(contains(@use, 'signing'))]/ds:KeyInfo/ds:X509Data/ds:X509Certificate")
if len(signing_nodes) > 0 or len(encryption_nodes) > 0:
certs = {}
if len(signing_nodes) > 0:
certs['signing'] = []
for cert_node in signing_nodes:
certs['signing'].append(''.join(OneLogin_Saml2_Utils.element_text(cert_node).split()))
if len(encryption_nodes) > 0:
def __query(self, query):
"""
Extracts a node from the DOMDocument (Logout Response Menssage)
:param query: Xpath Expresion
:type query: string
:return: The queried node
:rtype: DOMNodeList
"""
# Switch to lxml for querying
xml = self.document.toxml()
return OneLogin_Saml2_Utils.query(fromstring(xml, forbid_dtd=True), query)
"""
if len(signed_elements) > 2:
return False
response_tag = '{%s}Response' % OneLogin_Saml2_Constants.NS_SAMLP
assertion_tag = '{%s}Assertion' % OneLogin_Saml2_Constants.NS_SAML
if (response_tag in signed_elements and signed_elements.count(response_tag) > 1) or \
(assertion_tag in signed_elements and signed_elements.count(assertion_tag) > 1) or \
(response_tag not in signed_elements and assertion_tag not in signed_elements):
return False
# Check that the signed elements found here, are the ones that will be verified
# by OneLogin_Saml2_Utils.validate_sign
if response_tag in signed_elements:
expected_signature_nodes = OneLogin_Saml2_Utils.query(self.document, OneLogin_Saml2_Utils.RESPONSE_SIGNATURE_XPATH)
if len(expected_signature_nodes) != 1:
raise OneLogin_Saml2_ValidationError(
'Unexpected number of Response signatures found. SAML Response rejected.',
OneLogin_Saml2_ValidationError.WRONG_NUMBER_OF_SIGNATURES_IN_RESPONSE
)
if assertion_tag in signed_elements:
expected_signature_nodes = self.__query(OneLogin_Saml2_Utils.ASSERTION_SIGNATURE_XPATH)
if len(expected_signature_nodes) != 1:
raise OneLogin_Saml2_ValidationError(
'Unexpected number of Assertion signatures found. SAML Response rejected.',
OneLogin_Saml2_ValidationError.WRONG_NUMBER_OF_SIGNATURES_IN_ASSERTION
)
return True
def validate_num_assertions(self):
"""
Verifies that the document only contains a single Assertion (encrypted or not)
:returns: True if only 1 assertion encrypted or not
:rtype: bool
"""
encrypted_assertion_nodes = OneLogin_Saml2_Utils.query(self.document, '//saml:EncryptedAssertion')
assertion_nodes = OneLogin_Saml2_Utils.query(self.document, '//saml:Assertion')
valid = len(encrypted_assertion_nodes) + len(assertion_nodes) == 1
if (self.encrypted):
assertion_nodes = OneLogin_Saml2_Utils.query(self.decrypted_document, '//saml:Assertion')
valid = valid and len(assertion_nodes) == 1
return valid
def _parse_name_id_format(self, provider_node):
"""Parses a name ID format
NOTE: OneLogin's python-saml library used for implementing SAML authentication support only one name ID format.
If there are multiple name ID formats specified in the XML metadata, we select the first one.
:param provider_node: Parent IDPSSODescriptor/SPSSODescriptor node
:type provider_node: defusedxml.lxml.RestrictedElement
:return: Name ID format
:rtype: string
"""
name_id_format = NameIDFormat.UNSPECIFIED.value
name_id_format_nodes = OneLogin_Saml2_Utils.query(provider_node, './ md:NameIDFormat')
if len(name_id_format_nodes) > 0:
# OneLogin's python-saml supports only one name ID format so we select the first one
name_id_format = OneLogin_Saml2_Utils.element_text(name_id_format_nodes[0])
return name_id_format
def get_issuers(self):
"""
Gets the issuers (from message and from assertion)
:returns: The issuers
:rtype: list
"""
issuers = []
message_issuer_nodes = OneLogin_Saml2_Utils.query(self.document, '/samlp:Response/saml:Issuer')
if len(message_issuer_nodes) > 0:
if len(message_issuer_nodes) == 1:
issuers.append(OneLogin_Saml2_Utils.element_text(message_issuer_nodes[0]))
else:
raise OneLogin_Saml2_ValidationError(
'Issuer of the Response is multiple.',
OneLogin_Saml2_ValidationError.ISSUER_MULTIPLE_IN_RESPONSE
)
assertion_issuer_nodes = self.__query_assertion('/saml:Issuer')
if len(assertion_issuer_nodes) == 1:
issuers.append(OneLogin_Saml2_Utils.element_text(assertion_issuer_nodes[0]))
else:
raise OneLogin_Saml2_ValidationError(
'Issuer of the Assertion not found or multiple.',
OneLogin_Saml2_ValidationError.ISSUER_NOT_FOUND_IN_ASSERTION
"""
data = {}
dom = fromstring(idp_metadata, forbid_dtd=True)
entity_desc_path = '//md:EntityDescriptor'
if entity_id:
entity_desc_path += "[@entityID='%s']" % entity_id
entity_descriptor_nodes = OneLogin_Saml2_Utils.query(dom, entity_desc_path)
idp_entity_id = want_authn_requests_signed = idp_name_id_format = idp_sso_url = idp_slo_url = certs = None
if len(entity_descriptor_nodes) > 0:
entity_descriptor_node = entity_descriptor_nodes[0]
idp_descriptor_nodes = OneLogin_Saml2_Utils.query(entity_descriptor_node, './md:IDPSSODescriptor')
if len(idp_descriptor_nodes) > 0:
idp_descriptor_node = idp_descriptor_nodes[0]
idp_entity_id = entity_descriptor_node.get('entityID', None)
want_authn_requests_signed = entity_descriptor_node.get('WantAuthnRequestsSigned', None)
name_id_format_nodes = OneLogin_Saml2_Utils.query(idp_descriptor_node, './md:NameIDFormat')
if len(name_id_format_nodes) > 0:
idp_name_id_format = OneLogin_Saml2_Utils.element_text(name_id_format_nodes[0])
sso_nodes = OneLogin_Saml2_Utils.query(
idp_descriptor_node,
"./md:SingleSignOnService[@Binding='%s']" % required_sso_binding
)
:param entity_id: Specify the entity_id of the EntityDescriptor that you want to parse a XML
that contains multiple EntityDescriptor.
:type entity_id: string
:returns: settings dict with extracted data
:rtype: dict
"""
data = {}
dom = fromstring(idp_metadata, forbid_dtd=True)
entity_desc_path = '//md:EntityDescriptor'
if entity_id:
entity_desc_path += "[@entityID='%s']" % entity_id
entity_descriptor_nodes = OneLogin_Saml2_Utils.query(dom, entity_desc_path)
idp_entity_id = want_authn_requests_signed = idp_name_id_format = idp_sso_url = idp_slo_url = certs = None
if len(entity_descriptor_nodes) > 0:
entity_descriptor_node = entity_descriptor_nodes[0]
idp_descriptor_nodes = OneLogin_Saml2_Utils.query(entity_descriptor_node, './md:IDPSSODescriptor')
if len(idp_descriptor_nodes) > 0:
idp_descriptor_node = idp_descriptor_nodes[0]
idp_entity_id = entity_descriptor_node.get('entityID', None)
want_authn_requests_signed = entity_descriptor_node.get('WantAuthnRequestsSigned', None)
name_id_format_nodes = OneLogin_Saml2_Utils.query(idp_descriptor_node, './md:NameIDFormat')
if len(name_id_format_nodes) > 0:
idp_name_id_format = OneLogin_Saml2_Utils.element_text(name_id_format_nodes[0])
def validate_num_assertions(self):
"""
Verifies that the document only contains a single Assertion (encrypted or not)
:returns: True if only 1 assertion encrypted or not
:rtype: bool
"""
encrypted_assertion_nodes = OneLogin_Saml2_Utils.query(self.document, '//saml:EncryptedAssertion')
assertion_nodes = OneLogin_Saml2_Utils.query(self.document, '//saml:Assertion')
valid = len(encrypted_assertion_nodes) + len(assertion_nodes) == 1
if (self.encrypted):
assertion_nodes = OneLogin_Saml2_Utils.query(self.decrypted_document, '//saml:Assertion')
valid = valid and len(assertion_nodes) == 1
return valid