From d1bfaeb17a786735827b8252b91deafde29dabd8 Mon Sep 17 00:00:00 2001 From: Galyna Zholtkevych Date: Fri, 21 Jul 2023 15:34:36 +0300 Subject: [PATCH] Issue #364: Some urls come with 403 response (#366) * Issue #364: Some urls come with 403 response python3-saml urllib dependency responds with 403 status to urls with default Python user-agent --- src/onelogin/saml2/idp_metadata_parser.py | 12 ++++++++---- .../saml2_tests/idp_metadata_parser_test.py | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/onelogin/saml2/idp_metadata_parser.py b/src/onelogin/saml2/idp_metadata_parser.py index dc802ae5..29ba08be 100644 --- a/src/onelogin/saml2/idp_metadata_parser.py +++ b/src/onelogin/saml2/idp_metadata_parser.py @@ -27,7 +27,7 @@ class OneLogin_Saml2_IdPMetadataParser(object): """ @classmethod - def get_metadata(cls, url, validate_cert=True, timeout=None): + def get_metadata(cls, url, validate_cert=True, timeout=None, headers=None): """ Gets the metadata XML from the provided URL :param url: Url where the XML of the Identity Provider Metadata is published. @@ -38,19 +38,23 @@ def get_metadata(cls, url, validate_cert=True, timeout=None): :param timeout: Timeout in seconds to wait for metadata response :type timeout: int + :param headers: Extra headers to send in the request + :type headers: dict :returns: metadata XML :rtype: string """ valid = False + request = urllib2.Request(url, headers=headers or {}) + if validate_cert: - response = urllib2.urlopen(url, timeout=timeout) + 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(url, context=ctx, timeout=timeout) + response = urllib2.urlopen(request, context=ctx, timeout=timeout) xml = response.read() if xml: @@ -87,7 +91,7 @@ def parse_remote(cls, url, validate_cert=True, entity_id=None, timeout=None, **k :returns: settings dict with extracted data :rtype: dict """ - idp_metadata = cls.get_metadata(url, validate_cert, timeout) + idp_metadata = cls.get_metadata(url, validate_cert, timeout, headers=kwargs.pop('headers', None)) return cls.parse(idp_metadata, entity_id=entity_id, **kwargs) @classmethod 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 93c08dab..3d027ed1 100644 --- a/tests/src/OneLogin/saml2_tests/idp_metadata_parser_test.py +++ b/tests/src/OneLogin/saml2_tests/idp_metadata_parser_test.py @@ -54,6 +54,12 @@ def testGetMetadata(self): except URLError: pass + def testGetMetadataWithHeaders(self): + data = OneLogin_Saml2_IdPMetadataParser.get_metadata('https://samltest.id/saml/providers', + headers={'User-Agent': 'Mozilla/5.0'}) + self.assertIsNotNone(data) + self.assertIn(b'entityID=', data) + def testParseRemote(self): """ Tests the parse_remote method of the OneLogin_Saml2_IdPMetadataParser @@ -86,6 +92,15 @@ def testParseRemote(self): expected_settings = json.loads(expected_settings_json) self.assertEqual(expected_settings, data) + def testParseRemoteWithHeaders(self): + """ + Tests the parse_remote method passing headers of the OneLogin_Saml2_IdPMetadataParser + """ + data = OneLogin_Saml2_IdPMetadataParser.parse_remote('https://samltest.id/saml/providers') + self.assertEqual(data['idp']['entityId'], 'https://samltest.id/saml/idp') + self.assertIsNotNone(data['idp']['singleSignOnService']['url']) + self.assertIsNotNone(data['idp']['x509certMulti']) + def testParse(self): """ Tests the parse method of the OneLogin_Saml2_IdPMetadataParser