summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Thode <prometheanfire@gentoo.org>2017-01-10 21:00:40 -0600
committerMatthew Thode <prometheanfire@gentoo.org>2017-01-10 21:01:03 -0600
commit908a711df2180e3cbcdf8ec873bbe7bf809135db (patch)
treeca3af1f8ee7e107d3ceea34f4891e929e9ad96ae
parentdev-libs/icu-layoutex: amd64 stable (diff)
downloadgentoo-908a711df2180e3cbcdf8ec873bbe7bf809135db.tar.gz
gentoo-908a711df2180e3cbcdf8ec873bbe7bf809135db.tar.bz2
gentoo-908a711df2180e3cbcdf8ec873bbe7bf809135db.zip
dev-python/pysaml2: fix xxe in pysaml2
Package-Manager: portage-2.3.0
-rw-r--r--dev-python/pysaml2/files/xxe-4.0.2.patch305
-rw-r--r--dev-python/pysaml2/pysaml2-4.0.2-r1.ebuild37
2 files changed, 342 insertions, 0 deletions
diff --git a/dev-python/pysaml2/files/xxe-4.0.2.patch b/dev-python/pysaml2/files/xxe-4.0.2.patch
new file mode 100644
index 000000000000..8e1a2ef53cc0
--- /dev/null
+++ b/dev-python/pysaml2/files/xxe-4.0.2.patch
@@ -0,0 +1,305 @@
+diff -Naur pysaml2/setup.py pysaml2.new/setup.py
+--- pysaml2/setup.py 2015-12-06 00:46:33.000000000 -0600
++++ pysaml2.new/setup.py 2017-01-10 20:31:43.387413477 -0600
+@@ -17,6 +17,7 @@
+ 'pytz',
+ 'pyOpenSSL',
+ 'python-dateutil',
++ 'defusedxml',
+ 'six'
+ ]
+
+diff -Naur pysaml2/src/saml2/__init__.py pysaml2.new/src/saml2/__init__.py
+--- pysaml2/src/saml2/__init__.py 2016-01-07 05:53:57.000000000 -0600
++++ pysaml2.new/src/saml2/__init__.py 2017-01-10 20:34:04.171641116 -0600
+@@ -35,6 +35,7 @@
+ import cElementTree as ElementTree
+ except ImportError:
+ from elementtree import ElementTree
++import defusedxml.ElementTree
+
+ root_logger = logging.getLogger(__name__)
+ root_logger.level = logging.NOTSET
+@@ -86,7 +87,7 @@
+ """
+ if not isinstance(xml_string, six.binary_type):
+ xml_string = xml_string.encode('utf-8')
+- tree = ElementTree.fromstring(xml_string)
++ tree = defusedxml.ElementTree.fromstring(xml_string)
+ return create_class_from_element_tree(target_class, tree)
+
+
+@@ -268,7 +269,7 @@
+
+
+ def extension_element_from_string(xml_string):
+- element_tree = ElementTree.fromstring(xml_string)
++ element_tree = defusedxml.ElementTree.fromstring(xml_string)
+ return _extension_element_from_element_tree(element_tree)
+
+
+diff -Naur pysaml2/src/saml2/pack.py pysaml2.new/src/saml2/pack.py
+--- pysaml2/src/saml2/pack.py 2015-12-11 07:31:39.000000000 -0600
++++ pysaml2.new/src/saml2/pack.py 2017-01-10 20:35:35.382435020 -0600
+@@ -37,6 +37,7 @@
+ import cElementTree as ElementTree
+ except ImportError:
+ from elementtree import ElementTree
++import defusedxml.ElementTree
+
+ NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope/"
+ FORM_SPEC = """<form method="post" action="%s">
+@@ -235,7 +236,7 @@
+ :param text: The SOAP object as XML
+ :return: header parts and body as saml.samlbase instances
+ """
+- envelope = ElementTree.fromstring(text)
++ envelope = defusedxml.ElementTree.fromstring(text)
+ assert envelope.tag == '{%s}Envelope' % NAMESPACE
+
+ # print(len(envelope))
+diff -Naur pysaml2/src/saml2/soap.py pysaml2.new/src/saml2/soap.py
+--- pysaml2/src/saml2/soap.py 2015-05-18 02:54:05.000000000 -0500
++++ pysaml2.new/src/saml2/soap.py 2017-01-10 20:36:16.163808770 -0600
+@@ -19,6 +19,7 @@
+ except ImportError:
+ #noinspection PyUnresolvedReferences
+ from elementtree import ElementTree
++import defusedxml.ElementTree
+
+
+ logger = logging.getLogger(__name__)
+@@ -133,7 +134,7 @@
+ :param expected_tags: What the tag of the SAML thingy is expected to be.
+ :return: SAML thingy as a string
+ """
+- envelope = ElementTree.fromstring(text)
++ envelope = defusedxml.ElementTree.fromstring(text)
+
+ # Make sure it's a SOAP message
+ assert envelope.tag == '{%s}Envelope' % soapenv.NAMESPACE
+@@ -183,7 +184,7 @@
+ :return: The body and headers as class instances
+ """
+ try:
+- envelope = ElementTree.fromstring(text)
++ envelope = defusedxml.ElementTree.fromstring(text)
+ except Exception as exc:
+ raise XmlParseError("%s" % exc)
+
+@@ -209,7 +210,7 @@
+ :return: dictionary with two keys "body"/"header"
+ """
+ try:
+- envelope = ElementTree.fromstring(text)
++ envelope = defusedxml.ElementTree.fromstring(text)
+ except Exception as exc:
+ raise XmlParseError("%s" % exc)
+
+diff -Naur pysaml2/tests/test_03_saml2.py pysaml2.new/tests/test_03_saml2.py
+--- pysaml2/tests/test_03_saml2.py 2015-06-06 02:15:20.000000000 -0500
++++ pysaml2.new/tests/test_03_saml2.py 2017-01-10 20:38:32.541728380 -0600
+@@ -17,6 +17,7 @@
+ import cElementTree as ElementTree
+ except ImportError:
+ from elementtree import ElementTree
++from defusedxml.common import EntitiesForbidden
+
+ ITEMS = {
+ NameID: ["""<?xml version="1.0" encoding="utf-8"?>
+@@ -27,7 +28,7 @@
+ </NameID>
+ """, """<?xml version="1.0" encoding="utf-8"?>
+ <NameID xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
+- SPNameQualifier="https://foo.example.com/sp"
++ SPNameQualifier="https://foo.example.com/sp"
+ Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_1632879f09d08ea5ede2dc667cbed7e429ebc4335c</NameID>
+ """, """<?xml version="1.0" encoding="utf-8"?>
+ <NameID xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
+@@ -47,9 +48,9 @@
+ SubjectConfirmationData:
+ """<?xml version="1.0" encoding="utf-8"?>
+ <SubjectConfirmationData xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
+-InResponseTo="_1683146e27983964fbe7bf8f08961108d166a652e5"
+-NotOnOrAfter="2010-02-18T13:52:13.959Z"
+-NotBefore="2010-01-16T12:00:00Z"
++InResponseTo="_1683146e27983964fbe7bf8f08961108d166a652e5"
++NotOnOrAfter="2010-02-18T13:52:13.959Z"
++NotBefore="2010-01-16T12:00:00Z"
+ Recipient="http://192.168.0.10/saml/sp" />""",
+ SubjectConfirmation:
+ """<?xml version="1.0" encoding="utf-8"?>
+@@ -166,6 +167,19 @@
+ assert kl == None
+
+
++def test_create_class_from_xml_string_xxe():
++ xml = """<?xml version="1.0"?>
++ <!DOCTYPE lolz [
++ <!ENTITY lol "lol">
++ <!ELEMENT lolz (#PCDATA)>
++ <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
++ ]>
++ <lolz>&lol1;</lolz>
++ """
++ with raises(EntitiesForbidden) as err:
++ create_class_from_xml_string(NameID, xml)
++
++
+ def test_ee_1():
+ ee = saml2.extension_element_from_string(
+ """<?xml version='1.0' encoding='UTF-8'?><foo>bar</foo>""")
+@@ -193,7 +207,7 @@
+ def test_ee_3():
+ ee = saml2.extension_element_from_string(
+ """<?xml version='1.0' encoding='UTF-8'?>
+- <foo xmlns="urn:mace:example.com:saml:ns"
++ <foo xmlns="urn:mace:example.com:saml:ns"
+ id="xyz">bar</foo>""")
+ assert ee != None
+ print(ee.__dict__)
+@@ -454,6 +468,19 @@
+ assert nid.text.strip() == "http://federationX.org"
+
+
++def test_ee_xxe():
++ xml = """<?xml version="1.0"?>
++ <!DOCTYPE lolz [
++ <!ENTITY lol "lol">
++ <!ELEMENT lolz (#PCDATA)>
++ <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
++ ]>
++ <lolz>&lol1;</lolz>
++ """
++ with raises(EntitiesForbidden):
++ saml2.extension_element_from_string(xml)
++
++
+ def test_extension_element_loadd():
+ ava = {'attributes': {},
+ 'tag': 'ExternalEntityAttributeAuthority',
+diff -Naur pysaml2/tests/test_43_soap.py pysaml2.new/tests/test_43_soap.py
+--- pysaml2/tests/test_43_soap.py 2013-04-28 09:38:07.000000000 -0500
++++ pysaml2.new/tests/test_43_soap.py 2017-01-10 20:39:53.730364008 -0600
+@@ -12,16 +12,20 @@
+ import cElementTree as ElementTree
+ except ImportError:
+ from elementtree import ElementTree
++from defusedxml.common import EntitiesForbidden
++
++from pytest import raises
+
+ import saml2.samlp as samlp
+ from saml2.samlp import NAMESPACE as SAMLP_NAMESPACE
++from saml2 import soap
+
+ NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope/"
+
+ example = """<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
+ <Body>
+- <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
+- xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
++ <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
++ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ ID="_6c3a4f8b9c2d" Version="2.0" IssueInstant="2004-03-27T08:42:00Z">
+ <saml:Issuer>https://www.example.com/SAML</saml:Issuer>
+ <Status>
+@@ -55,7 +59,7 @@
+ envelope.tag = '{%s}Envelope' % NAMESPACE
+ body = ElementTree.Element('')
+ body.tag = '{%s}Body' % NAMESPACE
+- envelope.append(body)
++ envelope.append(body)
+ request = samlp.AuthnRequest()
+ request.become_child_element_of(body)
+
+@@ -66,3 +70,42 @@
+ assert len(body) == 1
+ saml_part = body[0]
+ assert saml_part.tag == '{%s}AuthnRequest' % SAMLP_NAMESPACE
++
++
++def test_parse_soap_enveloped_saml_thingy_xxe():
++ xml = """<?xml version="1.0"?>
++ <!DOCTYPE lolz [
++ <!ENTITY lol "lol">
++ <!ELEMENT lolz (#PCDATA)>
++ <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
++ ]>
++ <lolz>&lol1;</lolz>
++ """
++ with raises(EntitiesForbidden):
++ soap.parse_soap_enveloped_saml_thingy(xml, None)
++
++
++def test_class_instances_from_soap_enveloped_saml_thingies_xxe():
++ xml = """<?xml version="1.0"?>
++ <!DOCTYPE lolz [
++ <!ENTITY lol "lol">
++ <!ELEMENT lolz (#PCDATA)>
++ <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
++ ]>
++ <lolz>&lol1;</lolz>
++ """
++ with raises(soap.XmlParseError):
++ soap.class_instances_from_soap_enveloped_saml_thingies(xml, None)
++
++
++def test_open_soap_envelope_xxe():
++ xml = """<?xml version="1.0"?>
++ <!DOCTYPE lolz [
++ <!ENTITY lol "lol">
++ <!ELEMENT lolz (#PCDATA)>
++ <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
++ ]>
++ <lolz>&lol1;</lolz>
++ """
++ with raises(soap.XmlParseError):
++ soap.open_soap_envelope(xml)
+diff -Naur pysaml2/tests/test_51_client.py pysaml2.new/tests/test_51_client.py
+--- pysaml2/tests/test_51_client.py 2015-12-11 05:10:01.000000000 -0600
++++ pysaml2.new/tests/test_51_client.py 2017-01-10 20:42:12.819280442 -0600
+@@ -5,6 +5,7 @@
+ import uuid
+ import six
+ from six.moves.urllib.parse import parse_qs, urlencode, urlparse
++from pytest import raises
+ from saml2.cert import OpenSSLWrapper
+ from saml2.xmldsig import SIG_RSA_SHA256
+ from saml2 import BINDING_HTTP_POST
+@@ -21,6 +22,7 @@
+ from saml2.authn_context import INTERNETPROTOCOLPASSWORD
+ from saml2.client import Saml2Client
+ from saml2.config import SPConfig
++from saml2.pack import parse_soap_enveloped_saml
+ from saml2.response import LogoutResponse
+ from saml2.saml import NAMEID_FORMAT_PERSISTENT, EncryptedAssertion, Advice
+ from saml2.saml import NAMEID_FORMAT_TRANSIENT
+@@ -34,6 +36,8 @@
+ from saml2.s_utils import factory
+ from saml2.time_util import in_a_while, a_while_ago
+
++from defusedxml.common import EntitiesForbidden
++
+ from fakeIDP import FakeIDP
+ from fakeIDP import unpack_form
+ from pathutils import full_path
+@@ -1445,6 +1449,18 @@
+ 'http://www.example.com/login'
+ assert ac.authn_context_class_ref.text == INTERNETPROTOCOLPASSWORD
+
++def test_parse_soap_enveloped_saml_xxe():
++ xml = """<?xml version="1.0"?>
++ <!DOCTYPE lolz [
++ <!ENTITY lol "lol">
++ <!ELEMENT lolz (#PCDATA)>
++ <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
++ ]>
++ <lolz>&lol1;</lolz>
++ """
++ with raises(EntitiesForbidden):
++ parse_soap_enveloped_saml(xml, None)
++
+
+ # if __name__ == "__main__":
+ # tc = TestClient()
diff --git a/dev-python/pysaml2/pysaml2-4.0.2-r1.ebuild b/dev-python/pysaml2/pysaml2-4.0.2-r1.ebuild
new file mode 100644
index 000000000000..69aac4c21ed1
--- /dev/null
+++ b/dev-python/pysaml2/pysaml2-4.0.2-r1.ebuild
@@ -0,0 +1,37 @@
+# Copyright 1999-2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+EAPI=6
+PYTHON_COMPAT=( python2_7 python3_4 python3_5 )
+
+inherit distutils-r1
+
+DESCRIPTION="Python implementation of SAML Version 2 to be used in a WSGI environment"
+HOMEPAGE="https://github.com/rohe/pysaml2"
+SRC_URI="mirror://pypi/${PN:0:1}/${PN}/${P}.tar.gz"
+
+LICENSE="Apache-2.0"
+SLOT="0"
+KEYWORDS="~amd64 ~arm64 ~x86"
+IUSE=""
+
+PATCHES=( "${FILESDIR}/xxe-4.0.2.patch" )
+
+DEPEND="
+ dev-python/setuptools[${PYTHON_USEDEP}]
+"
+RDEPEND="
+ dev-python/decorator[${PYTHON_USEDEP}]
+ >=dev-python/requests-1.0.0[${PYTHON_USEDEP}]
+ dev-python/future[${PYTHON_USEDEP}]
+ dev-python/paste[${PYTHON_USEDEP}]
+ dev-python/zope-interface[${PYTHON_USEDEP}]
+ dev-python/repoze-who[${PYTHON_USEDEP}]
+ >=dev-python/pycrypto-2.5[${PYTHON_USEDEP}]
+ dev-python/pytz[${PYTHON_USEDEP}]
+ dev-python/pyopenssl[${PYTHON_USEDEP}]
+ dev-python/python-dateutil[${PYTHON_USEDEP}]
+ dev-python/six[${PYTHON_USEDEP}]
+ dev-python/defusedxml[${PYTHON_USEDEP}]
+"