From a5a90e8cb854e518d98c54c3eb3a7d1da6ea53c3 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 2 Apr 2024 11:57:02 +0200 Subject: [PATCH] :bug: Ensure the configure requests CA bundle is used Replaced IDP metadata fetching via urllib with requests. Projects making use of requests/self-certifi set up the CA bundle to wire up additional trusted root CAs, which are picked up by requests, so this should also work properly. Upstream issue: SAML-Toolkits/python3-saml#403 Open Forms issue: open-formulieren/open-forms#4079 --- src/onelogin/saml2/idp_metadata_parser.py | 23 ++++++------------- .../saml2_tests/idp_metadata_parser_test.py | 15 ++++-------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/onelogin/saml2/idp_metadata_parser.py b/src/onelogin/saml2/idp_metadata_parser.py index 0789827a..5e4b6fad 100644 --- a/src/onelogin/saml2/idp_metadata_parser.py +++ b/src/onelogin/saml2/idp_metadata_parser.py @@ -7,12 +7,7 @@ from copy import deepcopy -try: - import urllib.request as urllib2 -except ImportError: - import urllib2 - -import ssl +import requests from onelogin.saml2.constants import OneLogin_Saml2_Constants from onelogin.saml2.xml_utils import OneLogin_Saml2_XML @@ -46,16 +41,12 @@ def get_metadata(cls, url, validate_cert=True, timeout=None, headers=None): """ valid = False - request = urllib2.Request(url, headers=headers or {}) - - if validate_cert: - response = urllib2.urlopen(request, timeout=timeout) - else: - ctx = ssl.create_default_context() - ctx.check_hostname = False - ctx.verify_mode = ssl.CERT_NONE - response = urllib2.urlopen(request, context=ctx, timeout=timeout) - xml = response.read() + # MAYKIN: use requests to retrieve the metadata, so the CA bundle configured for + # requests can be used and self-signed/private root certificates still continue + # to work. + response = requests.get(url, headers=headers, verify=validate_cert, timeout=timeout) + response.raise_for_status() + xml = response.content if xml: try: diff --git a/tests/src/OneLogin/saml2_tests/idp_metadata_parser_test.py b/tests/src/OneLogin/saml2_tests/idp_metadata_parser_test.py index 23ab0c57..00d1d15d 100644 --- a/tests/src/OneLogin/saml2_tests/idp_metadata_parser_test.py +++ b/tests/src/OneLogin/saml2_tests/idp_metadata_parser_test.py @@ -1,15 +1,10 @@ # -*- coding: utf-8 -*- - -try: - from urllib.error import URLError -except ImportError: - from urllib2 import URLError - from copy import deepcopy import json from os.path import dirname, join, exists from lxml.etree import XMLSyntaxError +from requests import RequestException import unittest from onelogin.saml2.idp_metadata_parser import OneLogin_Saml2_IdPMetadataParser @@ -51,7 +46,7 @@ def testGetMetadata(self): try: data = OneLogin_Saml2_IdPMetadataParser.get_metadata('https://idp.testshib.org/idp/shibboleth') self.assertTrue(data is not None and data is not {}) - except URLError: + except RequestException: pass def testGetMetadataWithHeaders(self): @@ -69,7 +64,7 @@ def testParseRemote(self): try: data = OneLogin_Saml2_IdPMetadataParser.parse_remote('https://idp.testshib.org/idp/shibboleth') - except URLError: + except RequestException: xml = self.file_contents(join(self.data_path, 'metadata', 'testshib-providers.xml')) data = OneLogin_Saml2_IdPMetadataParser.parse(xml) @@ -172,7 +167,7 @@ def test_parse_testshib_required_binding_sso_redirect(self): try: xmldoc = OneLogin_Saml2_IdPMetadataParser.get_metadata( 'https://idp.testshib.org/idp/shibboleth') - except URLError: + except RequestException: xmldoc = self.file_contents(join(self.data_path, 'metadata', 'testshib-providers.xml')) # Parse, require SSO REDIRECT binding, implicitly. @@ -215,7 +210,7 @@ def test_parse_testshib_required_binding_sso_post(self): try: xmldoc = OneLogin_Saml2_IdPMetadataParser.get_metadata( 'https://idp.testshib.org/idp/shibboleth') - except URLError: + except RequestException: xmldoc = self.file_contents(join(self.data_path, 'metadata', 'testshib-providers.xml')) # Parse, require POST binding.