From ec9d640207a0ed2c31b6c7f464fa700573969714 Mon Sep 17 00:00:00 2001 From: Giuseppe De Marco Date: Fri, 19 Jul 2019 17:35:03 +0200 Subject: [PATCH 1/3] prettify XML string output by registering default namespace prefixes as @spaceone already proposed here: https://github.com/IdentityPython/pysaml2/pull/326 --- src/saml2/__init__.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/saml2/__init__.py b/src/saml2/__init__.py index 292513da5..d2a24cfe6 100644 --- a/src/saml2/__init__.py +++ b/src/saml2/__init__.py @@ -46,10 +46,28 @@ root_logger = logging.getLogger(__name__) root_logger.level = logging.NOTSET + NAMESPACE = 'urn:oasis:names:tc:SAML:2.0:assertion' # TEMPLATE = '{urn:oasis:names:tc:SAML:2.0:assertion}%s' # XSI_NAMESPACE = 'http://www.w3.org/2001/XMLSchema-instance' +# spaceone's https://github.com/IdentityPython/pysaml2/pull/326 +SAMLP_NAMESPACE = 'urn:oasis:names:tc:SAML:2.0:protocol' +XSI_NAMESPACE = 'http://www.w3.org/2001/XMLSchema-instance' +XS_NAMESPACE = 'http://www.w3.org/2001/XMLSchema' +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: + } + + NAMEID_FORMAT_EMAILADDRESS = ( "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress") @@ -687,7 +705,7 @@ def to_string_force_namespace(self, nspair): return ElementTree.tostring(elem, encoding="UTF-8") - def to_string(self, nspair=None): + def to_string(self, nspair=DEFAULT_NS_PREFIXES): """Converts the Saml object to a string containing XML. :param nspair: A dictionary of prefixes and uris to use when From 8b1bb93592797ba751fb1dc673b84aef33ed99a6 Mon Sep 17 00:00:00 2001 From: Giuseppe De Marco Date: Sun, 21 Jul 2019 00:25:43 +0200 Subject: [PATCH 2/3] unit test passes - ElementTree namespaces initialized globally in saml2.__init__ - code cleanup - SamlBase.register_prefix is now a staticmethod --- src/saml2/__init__.py | 39 +++++++++++++++++++++------------------ tests/test_02_saml.py | 4 ++-- tests/test_12_s_utils.py | 18 +++++++++--------- tests/test_42_enc.py | 2 +- tests/test_51_client.py | 8 ++++---- tests/test_88_nsprefix.py | 12 +++++++----- 6 files changed, 44 insertions(+), 39 deletions(-) diff --git a/src/saml2/__init__.py b/src/saml2/__init__.py index d2a24cfe6..169129ca7 100644 --- a/src/saml2/__init__.py +++ b/src/saml2/__init__.py @@ -49,24 +49,26 @@ NAMESPACE = 'urn:oasis:names:tc:SAML:2.0:assertion' # TEMPLATE = '{urn:oasis:names:tc:SAML:2.0:assertion}%s' -# XSI_NAMESPACE = 'http://www.w3.org/2001/XMLSchema-instance' - -# spaceone's https://github.com/IdentityPython/pysaml2/pull/326 SAMLP_NAMESPACE = 'urn:oasis:names:tc:SAML:2.0:protocol' XSI_NAMESPACE = 'http://www.w3.org/2001/XMLSchema-instance' XS_NAMESPACE = 'http://www.w3.org/2001/XMLSchema' -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: - } - +DS_NAMESPACE = 'http://www.w3.org/2000/09/xmldsig#' +XENC_NAMESPACE = "http://www.w3.org/2001/04/xmlenc#" +ALG_NAMESPACE = "urn:oasis:names:tc:SAML:metadata:algsupport" +MDATTR_NAMESPACE = "urn:oasis:names:tc:SAML:metadata:attribute" + +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, + 'alg': ALG_NAMESPACE, + 'mdattr': MDATTR_NAMESPACE} NAMEID_FORMAT_EMAILADDRESS = ( "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress") @@ -570,7 +572,8 @@ def _to_element_tree(self): self._add_members_to_element_tree(new_tree) return new_tree - def register_prefix(self, nspair): + @staticmethod + def register_prefix(nspair): """ Register with ElementTree a set of namespaces @@ -698,14 +701,11 @@ def fixup(name): del elem.attrib[key] def to_string_force_namespace(self, nspair): - elem = self._to_element_tree() - self.set_prefixes(elem, 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 @@ -1056,3 +1056,6 @@ def is_required_attribute(cls, attr): :return: True if required """ return cls.c_attributes[attr][REQUIRED] + +# this register preferred prefix namespaces +SamlBase.register_prefix(OASIS_DEFAULT_NS_PREFIXES) 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..83efe53a6 100644 --- a/tests/test_88_nsprefix.py +++ b/tests/test_88_nsprefix.py @@ -10,13 +10,15 @@ def test_nsprefix(): status_message = samlp.StatusMessage() status_message.text = "OK" - + + 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 +44,4 @@ def test_nsprefix2(): assert "saml2:Issuer" in txt if __name__ == "__main__": - test_nsprefix2() \ No newline at end of file + test_nsprefix2() From d009c0394845d9d8137104b89909921beb8b5a79 Mon Sep 17 00:00:00 2001 From: Giuseppe De Marco Date: Fri, 29 Jan 2021 21:14:47 +0100 Subject: [PATCH 3/3] added idpdisc ns prefix --- src/saml2/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/saml2/__init__.py b/src/saml2/__init__.py index 1471ac182..46c97e263 100644 --- a/src/saml2/__init__.py +++ b/src/saml2/__init__.py @@ -54,6 +54,7 @@ XENC_NAMESPACE = "http://www.w3.org/2001/04/xmlenc#" ALG_NAMESPACE = "urn:oasis:names:tc:SAML:metadata:algsupport" MDATTR_NAMESPACE = "urn:oasis:names:tc:SAML:metadata:attribute" +IDPDISC = "urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" OASIS_DEFAULT_NS_PREFIXES = {'saml': NAMESPACE, 'samlp': SAMLP_NAMESPACE, @@ -64,7 +65,9 @@ 'md': MD_NAMESPACE, 'xenc': XENC_NAMESPACE, 'alg': ALG_NAMESPACE, - 'mdattr': MDATTR_NAMESPACE} + 'mdattr': MDATTR_NAMESPACE, + 'idpdisc': IDPDISC +} NAMEID_FORMAT_EMAILADDRESS = ( "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")