diff --git a/src/saml2/__init__.py b/src/saml2/__init__.py index d2a24cfe6..eb70d1878 100644 --- a/src/saml2/__init__.py +++ b/src/saml2/__init__.py @@ -17,6 +17,7 @@ provides methods and functions to convert SAML classes to and from strings. """ +import copy import logging import six @@ -58,14 +59,28 @@ DS_NAMESPACE = 'http://www.w3.org/2000/09/xmldsig#' MD_NAMESPACE = "urn:oasis:names:tc:SAML:2.0:metadata" MDUI_NAMESPACE = "urn:oasis:names:tc:SAML:metadata:ui" -DEFAULT_NS_PREFIXES = {'saml': NAMESPACE, 'samlp': SAMLP_NAMESPACE, - 'ds': DS_NAMESPACE, 'xsi': XSI_NAMESPACE, - 'xs': XS_NAMESPACE, - 'mdui': MDUI_NAMESPACE, - 'md': MD_NAMESPACE, - # 'alg': TODO: algsupport.DIGEST_METHODS|SIGNING_METHODS shoulb be moved before mapping them here - # TODO: - } +XENC_NAMESPACE = "http://www.w3.org/2001/04/xmlenc#" + +# this should be configurable by users +OASIS_DEFAULT_NS_PREFIXES = {'saml': NAMESPACE, 'samlp': SAMLP_NAMESPACE, + 'ds': DS_NAMESPACE, 'xsi': XSI_NAMESPACE, + 'xs': XS_NAMESPACE, + 'mdui': MDUI_NAMESPACE, + 'md': MD_NAMESPACE, + 'xenc': XENC_NAMESPACE, + # mdattr: + } + + +# make DEFAULT_NS_PREFIXES as default without register ns in every entities +for prefix, uri in OASIS_DEFAULT_NS_PREFIXES.items(): + try: + ElementTree.register_namespace(prefix, uri) + except AttributeError: + # Backwards compatibility with ET < 1.3 + ElementTree._namespace_map[uri] = prefix + except ValueError: + pass NAMEID_FORMAT_EMAILADDRESS = ( @@ -90,6 +105,13 @@ BINDING_HTTP_ARTIFACT = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact' BINDING_URI = 'urn:oasis:names:tc:SAML:2.0:bindings:URI' +def replace_ns_prefixes(value, ns): + """function to adapt ns to user's customs + """ + if not SWAPPED_NS_PREFIXES: + return value + return value.replace(DEFAULT_SWAPPED_NS_PREFIXES[ns], + SWAPPED_NS_PREFIXES[ns]) def class_name(instance): return "%s:%s" % (instance.c_namespace, instance.c_tag) @@ -705,19 +727,19 @@ def to_string_force_namespace(self, nspair): return ElementTree.tostring(elem, encoding="UTF-8") - def to_string(self, nspair=DEFAULT_NS_PREFIXES): + def to_string(self, nspair=None): """Converts the Saml object to a string containing XML. :param nspair: A dictionary of prefixes and uris to use when constructing the text representation. :return: String representation of the object """ - if not nspair and self.c_ns_prefix: + if self.c_ns_prefix: nspair = self.c_ns_prefix if nspair: self.register_prefix(nspair) - + return ElementTree.tostring(self._to_element_tree(), encoding="UTF-8") def __str__(self): diff --git a/tests/test_02_saml.py b/tests/test_02_saml.py index fe5bbb707..fb8209f72 100644 --- a/tests/test_02_saml.py +++ b/tests/test_02_saml.py @@ -226,11 +226,11 @@ def test_to_string_nspair(self): foo = saml2.make_vals("lions", AttributeValue, part=True) txt = foo.to_string().decode('utf-8') nsstr = foo.to_string({"saml": saml.NAMESPACE}).decode('utf-8') - assert nsstr != txt + assert nsstr == txt # this must be the same print(txt) print(nsstr) assert "saml:AttributeValue" in nsstr - assert "saml:AttributeValue" not in txt + assert "saml:AttributeValue" in txt # this must be contained def test_set_text_empty(self): av = AttributeValue() diff --git a/tests/test_12_s_utils.py b/tests/test_12_s_utils.py index cd1be8e90..ea89a6e51 100644 --- a/tests/test_12_s_utils.py +++ b/tests/test_12_s_utils.py @@ -20,25 +20,25 @@ XML_HEADER = '\n' SUCCESS_STATUS_NO_HEADER = ( - '') + 'Value="urn:oasis:names:tc:SAML:2.0:status:Success" />') SUCCESS_STATUS = '%s%s' % (XML_HEADER, SUCCESS_STATUS_NO_HEADER) ERROR_STATUS_NO_HEADER = ( - 'Error resolving ' - 'principal') + '/>Error resolving ' + 'principal') ERROR_STATUS_NO_HEADER_EMPTY = ( - '') + '/>') ERROR_STATUS = '%s%s' % (XML_HEADER, ERROR_STATUS_NO_HEADER) ERROR_STATUS_EMPTY = '%s%s' % (XML_HEADER, ERROR_STATUS_NO_HEADER_EMPTY) diff --git a/tests/test_42_enc.py b/tests/test_42_enc.py index c29eca1e2..100075046 100644 --- a/tests/test_42_enc.py +++ b/tests/test_42_enc.py @@ -9,7 +9,7 @@ __author__ = 'roland' -TMPL_NO_HEADER = """my-rsa-key""" +TMPL_NO_HEADER = """my-rsa-key""" TMPL = "\n%s" % TMPL_NO_HEADER IDENTITY = {"eduPersonAffiliation": ["staff", "member"], diff --git a/tests/test_51_client.py b/tests/test_51_client.py index a063dcb43..2c8e264e2 100644 --- a/tests/test_51_client.py +++ b/tests/test_51_client.py @@ -1476,7 +1476,7 @@ def test_do_logout_post(self): _dic = unpack_form(info["data"]) res = self.server.parse_logout_request(_dic["SAMLRequest"], BINDING_HTTP_POST) - assert b'_foo' in res.xmlstr + assert b'_foo' in res.xmlstr def test_do_logout_session_expired(self): # information about the user from an IdP @@ -1506,7 +1506,7 @@ def test_do_logout_session_expired(self): _dic = unpack_form(info["data"]) res = self.server.parse_logout_request(_dic["SAMLRequest"], BINDING_HTTP_POST) - assert b'_foo' in res.xmlstr + assert b'_foo' in res.xmlstr def test_signature_wants(self): @@ -3053,7 +3053,7 @@ def test_do_logout_post(self): _dic = unpack_form(info["data"]) res = self.server.parse_logout_request(_dic["SAMLRequest"], BINDING_HTTP_POST) - assert b'_foo' in res.xmlstr + assert b'_foo' in res.xmlstr def test_do_logout_session_expired(self): # information about the user from an IdP @@ -3083,7 +3083,7 @@ def test_do_logout_session_expired(self): _dic = unpack_form(info["data"]) res = self.server.parse_logout_request(_dic["SAMLRequest"], BINDING_HTTP_POST) - assert b'_foo' in res.xmlstr + assert b'_foo' in res.xmlstr # Below can only be done with dummy Server IDP = "urn:mace:example.com:saml:roland:idp" diff --git a/tests/test_88_nsprefix.py b/tests/test_88_nsprefix.py index 4f652a54f..3979a7316 100644 --- a/tests/test_88_nsprefix.py +++ b/tests/test_88_nsprefix.py @@ -11,12 +11,18 @@ def test_nsprefix(): status_message = samlp.StatusMessage() status_message.text = "OK" + # not possibile: ns0 -> raise ValueError("Prefix format reserved for internal use") + #status_message.register_prefix(nspair={"ns0": saml.NAMESPACE, + #"ns0": samlp.NAMESPACE}) + + status_message.register_prefix(nspair={"samla": saml.NAMESPACE, + "samla": samlp.NAMESPACE}) txt = "%s" % status_message - assert "ns0:StatusMessage" in txt + assert "samla:StatusMessage" in txt - status_message.register_prefix({"saml2": saml.NAMESPACE, - "saml2p": samlp.NAMESPACE}) + status_message.register_prefix(nspair={"saml2p": samlp.NAMESPACE, + "saml2": saml.NAMESPACE}) txt = "%s" % status_message @@ -42,4 +48,4 @@ def test_nsprefix2(): assert "saml2:Issuer" in txt if __name__ == "__main__": - test_nsprefix2() \ No newline at end of file + test_nsprefix2()