From 34f243ac695d25c3ff9d41b8b828bcdde71a8cb0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Sep 2025 12:32:46 +0000 Subject: [PATCH 1/4] Initial plan From 62b19189b7cb7869b66072c320a9106b905c31ed Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Sep 2025 12:36:06 +0000 Subject: [PATCH 2/4] Initial analysis: User trying to import from wrong package Co-authored-by: Subterrane <5290140+Subterrane@users.noreply.github.com> --- =2.0.2 | 0 =2.11.0 | 0 =2.5.3 | 0 =3.1.11 | 0 =67.7.1 | 36 ++++++++++++++++++++++++++++++++++++ 5 files changed, 36 insertions(+) create mode 100644 =2.0.2 create mode 100644 =2.11.0 create mode 100644 =2.5.3 create mode 100644 =3.1.11 create mode 100644 =67.7.1 diff --git a/=2.0.2 b/=2.0.2 new file mode 100644 index 00000000..e69de29b diff --git a/=2.11.0 b/=2.11.0 new file mode 100644 index 00000000..e69de29b diff --git a/=2.5.3 b/=2.5.3 new file mode 100644 index 00000000..e69de29b diff --git a/=3.1.11 b/=3.1.11 new file mode 100644 index 00000000..e69de29b diff --git a/=67.7.1 b/=67.7.1 new file mode 100644 index 00000000..6cff9e6e --- /dev/null +++ b/=67.7.1 @@ -0,0 +1,36 @@ +Defaulting to user installation because normal site-packages is not writeable +Collecting pydantic + Downloading pydantic-2.11.7-py3-none-any.whl.metadata + - 68.0 kB 216.0 MB/s 0:00:00 +Requirement already satisfied: urllib3 in /usr/lib/python3/dist-packages (2.0.7) +Requirement already satisfied: python-dateutil in /usr/lib/python3/dist-packages (2.8.2) +Collecting aenum + Downloading aenum-3.1.16-py3-none-any.whl.metadata + - 3.8 kB ? 0:00:00 +Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (68.1.2) +Collecting annotated-types>=0.6.0 (from pydantic) + Downloading annotated_types-0.7.0-py3-none-any.whl.metadata + - 15.0 kB 147.7 MB/s 0:00:00 +Collecting pydantic-core==2.33.2 (from pydantic) + Downloading pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata + - 6.8 kB ? 0:00:00 +Collecting typing-extensions>=4.12.2 (from pydantic) + Downloading typing_extensions-4.15.0-py3-none-any.whl.metadata + - 3.3 kB ? 0:00:00 +Collecting typing-inspection>=0.4.0 (from pydantic) + Downloading typing_inspection-0.4.1-py3-none-any.whl.metadata + - 2.6 kB ? 0:00:00 +Downloading pydantic-2.11.7-py3-none-any.whl + - 444.8 kB 17.5 MB/s 0:00:00 +Downloading pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - 2.0 MB 90.6 MB/s 0:00:00 +Downloading aenum-3.1.16-py3-none-any.whl + - 165.6 kB 166.1 MB/s 0:00:00 +Downloading annotated_types-0.7.0-py3-none-any.whl + - 13.6 kB 62.0 MB/s 0:00:00 +Downloading typing_extensions-4.15.0-py3-none-any.whl + - 44.6 kB 131.3 MB/s 0:00:00 +Downloading typing_inspection-0.4.1-py3-none-any.whl + - 14.6 kB 110.1 MB/s 0:00:00 +Installing collected packages: aenum, typing-extensions, annotated-types, typing-inspection, pydantic-core, pydantic +Successfully installed aenum-3.1.16 annotated-types-0.7.0 pydantic-2.11.7 pydantic-core-2.33.2 typing-extensions-4.15.0 typing-inspection-0.4.1 From cb9bd61fd544876e7a569290c659df61557fe661 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Sep 2025 12:40:48 +0000 Subject: [PATCH 3/4] Add SAML2 compatibility module with helpful error messages Co-authored-by: Subterrane <5290140+Subterrane@users.noreply.github.com> --- =2.0.2 | 0 =2.11.0 | 0 =2.5.3 | 0 =3.1.11 | 0 =67.7.1 | 36 ---------------- onelogin/saml2/__init__.py | 12 ++++++ onelogin/saml2/auth.py | 57 +++++++++++++++++++++++++ test/test_saml2_import_compatibility.py | 55 ++++++++++++++++++++++++ 8 files changed, 124 insertions(+), 36 deletions(-) delete mode 100644 =2.0.2 delete mode 100644 =2.11.0 delete mode 100644 =2.5.3 delete mode 100644 =3.1.11 delete mode 100644 =67.7.1 create mode 100644 onelogin/saml2/__init__.py create mode 100644 onelogin/saml2/auth.py create mode 100644 test/test_saml2_import_compatibility.py diff --git a/=2.0.2 b/=2.0.2 deleted file mode 100644 index e69de29b..00000000 diff --git a/=2.11.0 b/=2.11.0 deleted file mode 100644 index e69de29b..00000000 diff --git a/=2.5.3 b/=2.5.3 deleted file mode 100644 index e69de29b..00000000 diff --git a/=3.1.11 b/=3.1.11 deleted file mode 100644 index e69de29b..00000000 diff --git a/=67.7.1 b/=67.7.1 deleted file mode 100644 index 6cff9e6e..00000000 --- a/=67.7.1 +++ /dev/null @@ -1,36 +0,0 @@ -Defaulting to user installation because normal site-packages is not writeable -Collecting pydantic - Downloading pydantic-2.11.7-py3-none-any.whl.metadata - - 68.0 kB 216.0 MB/s 0:00:00 -Requirement already satisfied: urllib3 in /usr/lib/python3/dist-packages (2.0.7) -Requirement already satisfied: python-dateutil in /usr/lib/python3/dist-packages (2.8.2) -Collecting aenum - Downloading aenum-3.1.16-py3-none-any.whl.metadata - - 3.8 kB ? 0:00:00 -Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (68.1.2) -Collecting annotated-types>=0.6.0 (from pydantic) - Downloading annotated_types-0.7.0-py3-none-any.whl.metadata - - 15.0 kB 147.7 MB/s 0:00:00 -Collecting pydantic-core==2.33.2 (from pydantic) - Downloading pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata - - 6.8 kB ? 0:00:00 -Collecting typing-extensions>=4.12.2 (from pydantic) - Downloading typing_extensions-4.15.0-py3-none-any.whl.metadata - - 3.3 kB ? 0:00:00 -Collecting typing-inspection>=0.4.0 (from pydantic) - Downloading typing_inspection-0.4.1-py3-none-any.whl.metadata - - 2.6 kB ? 0:00:00 -Downloading pydantic-2.11.7-py3-none-any.whl - - 444.8 kB 17.5 MB/s 0:00:00 -Downloading pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - 2.0 MB 90.6 MB/s 0:00:00 -Downloading aenum-3.1.16-py3-none-any.whl - - 165.6 kB 166.1 MB/s 0:00:00 -Downloading annotated_types-0.7.0-py3-none-any.whl - - 13.6 kB 62.0 MB/s 0:00:00 -Downloading typing_extensions-4.15.0-py3-none-any.whl - - 44.6 kB 131.3 MB/s 0:00:00 -Downloading typing_inspection-0.4.1-py3-none-any.whl - - 14.6 kB 110.1 MB/s 0:00:00 -Installing collected packages: aenum, typing-extensions, annotated-types, typing-inspection, pydantic-core, pydantic -Successfully installed aenum-3.1.16 annotated-types-0.7.0 pydantic-2.11.7 pydantic-core-2.33.2 typing-extensions-4.15.0 typing-inspection-0.4.1 diff --git a/onelogin/saml2/__init__.py b/onelogin/saml2/__init__.py new file mode 100644 index 00000000..c611f114 --- /dev/null +++ b/onelogin/saml2/__init__.py @@ -0,0 +1,12 @@ +# coding: utf-8 + +""" +SAML2 Authentication Module + +This module provides compatibility for users expecting to import +OneLogin_Saml2_Auth from onelogin.saml2.auth. However, OneLogin_Saml2_Auth is +actually provided by the 'python3-saml' package, not this onelogin package. + +This onelogin package is for OneLogin API management, while python3-saml is +for SAML2 authentication integration. +""" diff --git a/onelogin/saml2/auth.py b/onelogin/saml2/auth.py new file mode 100644 index 00000000..ad41178c --- /dev/null +++ b/onelogin/saml2/auth.py @@ -0,0 +1,57 @@ +# coding: utf-8 + +""" +SAML2 Authentication Module + +OneLogin_Saml2_Auth is not part of this package. This package (onelogin) is +for OneLogin API management. For SAML2 authentication, you need the +'python3-saml' package. + +To fix this import error: + +1. Install the correct package: + pip install python3-saml + +2. Import from the correct module: + from onelogin.saml2.auth import OneLogin_Saml2_Auth + + OR use the newer syntax: + from onelogin.saml2.auth import Auth as OneLogin_Saml2_Auth + +For more information, see: https://github.com/onelogin/python3-saml +""" + + +class ImportError(Exception): + """Custom import error with helpful message""" + pass + + +def __getattr__(name): + """ + Intercept attempts to import OneLogin_Saml2_Auth and provide helpful + error message. + """ + if name == "OneLogin_Saml2_Auth": + raise ImportError( + "OneLogin_Saml2_Auth is not available in this package.\n\n" + "This package (onelogin) is for OneLogin API management.\n" + "For SAML2 authentication, you need the 'python3-saml' " + "package.\n\n" + "To fix this:\n" + "1. Install the correct package: pip install python3-saml\n" + "2. Import from: from onelogin.saml2.auth import " + "OneLogin_Saml2_Auth\n\n" + "Note: You may need to uninstall this 'onelogin' package if you " + "only need SAML2 auth:\n" + "pip uninstall onelogin\n\n" + "For more information: https://github.com/onelogin/python3-saml" + ) + + raise AttributeError( + f"module 'onelogin.saml2.auth' has no attribute '{name}'" + ) + + +# Make module attributes available for inspection +__all__ = [] diff --git a/test/test_saml2_import_compatibility.py b/test/test_saml2_import_compatibility.py new file mode 100644 index 00000000..7d228df7 --- /dev/null +++ b/test/test_saml2_import_compatibility.py @@ -0,0 +1,55 @@ +# coding: utf-8 + +""" +Test import behavior for SAML2 compatibility module +""" + +import pytest +from onelogin.saml2.auth import ImportError + + +class TestSaml2ImportCompatibility: + """Test the SAML2 import compatibility module""" + + def test_import_onelogin_saml2_auth_raises_helpful_error(self): + """Test that importing OneLogin_Saml2_Auth raises a helpful error message""" + + # Attempt to import OneLogin_Saml2_Auth + with pytest.raises(ImportError) as exc_info: + from onelogin.saml2.auth import OneLogin_Saml2_Auth + + # Verify the error message contains helpful guidance + error_message = str(exc_info.value) + assert "OneLogin_Saml2_Auth is not available in this package" in error_message + assert "python3-saml" in error_message + assert "pip install python3-saml" in error_message + assert "https://github.com/onelogin/python3-saml" in error_message + + def test_getattr_for_nonexistent_attribute_raises_attribute_error(self): + """Test that accessing non-existent attributes raises AttributeError""" + + import onelogin.saml2.auth + with pytest.raises(AttributeError) as exc_info: + getattr(onelogin.saml2.auth, 'NonExistentClass') + + error_message = str(exc_info.value) + assert "module 'onelogin.saml2.auth' has no attribute 'NonExistentClass'" in error_message + + def test_saml2_module_can_be_imported(self): + """Test that the saml2 module itself can be imported without error""" + + import onelogin.saml2 + # Should not raise any errors + + def test_saml2_auth_module_can_be_imported(self): + """Test that the saml2.auth module itself can be imported without error""" + + import onelogin.saml2.auth + # Should not raise any errors + + def test_saml2_auth_module_has_empty_all_list(self): + """Test that __all__ is defined and empty""" + + import onelogin.saml2.auth + assert hasattr(onelogin.saml2.auth, '__all__') + assert onelogin.saml2.auth.__all__ == [] \ No newline at end of file From 430278e26d0ea7dab455eb7064f5bc4bb736f7d8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Sep 2025 13:57:46 +0000 Subject: [PATCH 4/4] Improve SAML2 compatibility to handle namespace conflicts when python3-saml is installed Co-authored-by: Subterrane <5290140+Subterrane@users.noreply.github.com> --- onelogin/saml2/auth.py | 79 ++++++++++++++----------- test/test_saml2_import_compatibility.py | 50 ++++++++++++++-- 2 files changed, 91 insertions(+), 38 deletions(-) diff --git a/onelogin/saml2/auth.py b/onelogin/saml2/auth.py index ad41178c..2ce96077 100644 --- a/onelogin/saml2/auth.py +++ b/onelogin/saml2/auth.py @@ -3,50 +3,63 @@ """ SAML2 Authentication Module -OneLogin_Saml2_Auth is not part of this package. This package (onelogin) is -for OneLogin API management. For SAML2 authentication, you need the -'python3-saml' package. +This module provides compatibility for users expecting to import +OneLogin_Saml2_Auth from onelogin.saml2.auth. However, OneLogin_Saml2_Auth is +actually provided by the 'python3-saml' package, not this onelogin package. -To fix this import error: - -1. Install the correct package: - pip install python3-saml - -2. Import from the correct module: - from onelogin.saml2.auth import OneLogin_Saml2_Auth - - OR use the newer syntax: - from onelogin.saml2.auth import Auth as OneLogin_Saml2_Auth - -For more information, see: https://github.com/onelogin/python3-saml +This onelogin package is for OneLogin API management, while python3-saml is +for SAML2 authentication integration. """ +import os +import site + -class ImportError(Exception): - """Custom import error with helpful message""" - pass +def _check_python3_saml_installed(): + """Check if python3-saml is installed by looking for its onelogin.saml2.auth module""" + for site_dir in site.getsitepackages() + [site.getusersitepackages()]: + if site_dir and os.path.exists(site_dir): + potential_path = os.path.join(site_dir, 'onelogin', 'saml2', 'auth.py') + if os.path.exists(potential_path): + return True + return False def __getattr__(name): """ Intercept attempts to import OneLogin_Saml2_Auth and provide helpful - error message. + error message based on whether python3-saml is detected. """ if name == "OneLogin_Saml2_Auth": - raise ImportError( - "OneLogin_Saml2_Auth is not available in this package.\n\n" - "This package (onelogin) is for OneLogin API management.\n" - "For SAML2 authentication, you need the 'python3-saml' " - "package.\n\n" - "To fix this:\n" - "1. Install the correct package: pip install python3-saml\n" - "2. Import from: from onelogin.saml2.auth import " - "OneLogin_Saml2_Auth\n\n" - "Note: You may need to uninstall this 'onelogin' package if you " - "only need SAML2 auth:\n" - "pip uninstall onelogin\n\n" - "For more information: https://github.com/onelogin/python3-saml" - ) + python3_saml_installed = _check_python3_saml_installed() + + if python3_saml_installed: + # python3-saml is installed but there's a namespace conflict + raise ImportError( + "OneLogin_Saml2_Auth is not available due to a package namespace conflict.\n\n" + "You have both 'onelogin' (API management) and 'python3-saml' (SAML authentication) installed.\n" + "These packages both provide 'onelogin' modules, causing a conflict.\n\n" + "To fix this conflict:\n\n" + "OPTION 1 - If you only need SAML authentication:\n" + " 1. Uninstall this package: pip uninstall onelogin\n" + " 2. Then import will work: from onelogin.saml2.auth import OneLogin_Saml2_Auth\n\n" + "OPTION 2 - If you need both packages:\n" + " 1. Import directly from python3-saml's location in site-packages\n" + " 2. See: https://github.com/onelogin/python3-saml for documentation\n\n" + "OPTION 3 - Use virtual environments to separate the packages\n\n" + "To check your installations: pip list | grep -E '(onelogin|python3-saml)'" + ) + else: + # python3-saml is not installed + raise ImportError( + "OneLogin_Saml2_Auth is not available in this package.\n\n" + "This package (onelogin) is for OneLogin API management.\n" + "For SAML2 authentication, you need the 'python3-saml' package.\n\n" + "To fix this:\n" + "1. Install the correct package: pip install python3-saml\n" + "2. Import from: from onelogin.saml2.auth import OneLogin_Saml2_Auth\n\n" + "For more information: https://github.com/onelogin/python3-saml" + ) raise AttributeError( f"module 'onelogin.saml2.auth' has no attribute '{name}'" diff --git a/test/test_saml2_import_compatibility.py b/test/test_saml2_import_compatibility.py index 7d228df7..2b58ef8e 100644 --- a/test/test_saml2_import_compatibility.py +++ b/test/test_saml2_import_compatibility.py @@ -5,7 +5,8 @@ """ import pytest -from onelogin.saml2.auth import ImportError +import os +import site class TestSaml2ImportCompatibility: @@ -20,10 +21,21 @@ def test_import_onelogin_saml2_auth_raises_helpful_error(self): # Verify the error message contains helpful guidance error_message = str(exc_info.value) - assert "OneLogin_Saml2_Auth is not available in this package" in error_message + assert "OneLogin_Saml2_Auth is not available" in error_message assert "python3-saml" in error_message - assert "pip install python3-saml" in error_message - assert "https://github.com/onelogin/python3-saml" in error_message + + # The specific message depends on whether python3-saml is detected + python3_saml_installed = self._check_python3_saml_installed() + + if python3_saml_installed: + # Should show namespace conflict message + assert "namespace conflict" in error_message + assert "both 'onelogin'" in error_message + assert "pip uninstall onelogin" in error_message + else: + # Should show installation instruction message + assert "pip install python3-saml" in error_message + assert "https://github.com/onelogin/python3-saml" in error_message def test_getattr_for_nonexistent_attribute_raises_attribute_error(self): """Test that accessing non-existent attributes raises AttributeError""" @@ -52,4 +64,32 @@ def test_saml2_auth_module_has_empty_all_list(self): import onelogin.saml2.auth assert hasattr(onelogin.saml2.auth, '__all__') - assert onelogin.saml2.auth.__all__ == [] \ No newline at end of file + assert onelogin.saml2.auth.__all__ == [] + + def test_python3_saml_detection_function(self): + """Test that the python3-saml detection function works correctly""" + + import onelogin.saml2.auth + result = onelogin.saml2.auth._check_python3_saml_installed() + # Should return a boolean + assert isinstance(result, bool) + + # Test by checking if the expected path exists manually + expected_exists = False + for site_dir in site.getsitepackages() + [site.getusersitepackages()]: + if site_dir and os.path.exists(site_dir): + potential_path = os.path.join(site_dir, 'onelogin', 'saml2', 'auth.py') + if os.path.exists(potential_path): + expected_exists = True + break + + assert result == expected_exists + + def _check_python3_saml_installed(self): + """Helper method to check if python3-saml is installed""" + for site_dir in site.getsitepackages() + [site.getusersitepackages()]: + if site_dir and os.path.exists(site_dir): + potential_path = os.path.join(site_dir, 'onelogin', 'saml2', 'auth.py') + if os.path.exists(potential_path): + return True + return False \ No newline at end of file