-
Notifications
You must be signed in to change notification settings - Fork 3.4k
[Core] Fix MSAL to respect REQUESTS_CA_BUNDLE for proxy certificates #32208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,3 +45,32 @@ def change_ssl_cert_verification_track2(): | |
| logger.debug("Using CA bundle file at '%s'.", ca_bundle_file) | ||
| client_kwargs['connection_verify'] = ca_bundle_file | ||
| return client_kwargs | ||
|
|
||
|
|
||
| def get_msal_http_client(): | ||
| """ | ||
| Create an HTTP client (requests.Session) for MSAL that respects certificate verification settings. | ||
|
|
||
| This ensures MSAL applications use the same certificate verification settings as the rest of Azure CLI, | ||
| including custom CA bundles specified via REQUESTS_CA_BUNDLE environment variable. | ||
|
|
||
| Returns: | ||
| requests.Session: A configured Session object with appropriate certificate verification settings. | ||
| """ | ||
| import requests | ||
|
|
||
| session = requests.Session() | ||
|
|
||
| if should_disable_connection_verify(): | ||
| logger.warning("Connection verification disabled by environment variable %s", | ||
| DISABLE_VERIFY_VARIABLE_NAME) | ||
| os.environ[ADAL_PYTHON_SSL_NO_VERIFY] = '1' | ||
| session.verify = False | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is by design that |
||
| elif REQUESTS_CA_BUNDLE in os.environ: | ||
| ca_bundle_file = os.environ[REQUESTS_CA_BUNDLE] | ||
| if not os.path.isfile(ca_bundle_file): | ||
| raise CLIError('REQUESTS_CA_BUNDLE environment variable is specified with an invalid file path') | ||
| logger.debug("MSAL: Using CA bundle file at '%s'.", ca_bundle_file) | ||
| session.verify = ca_bundle_file | ||
|
|
||
| return session | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,8 @@ | |
| import os | ||
| import logging | ||
| import unittest | ||
| from unittest.mock import MagicMock | ||
| from unittest.mock import MagicMock, patch | ||
| import tempfile | ||
|
|
||
| import azure.cli.core._debug as _debug | ||
| import azure.cli.core.util as cli_util | ||
|
|
@@ -35,6 +36,52 @@ def test_verify_client_connection(self): | |
| clientMock = _debug.change_ssl_cert_verification(clientMock) | ||
| self.assertFalse(clientMock.config.connection.verify) | ||
|
|
||
| def test_get_msal_http_client_respects_ca_bundle(self): | ||
| """Test that get_msal_http_client() respects REQUESTS_CA_BUNDLE environment variable.""" | ||
| # Save original environment | ||
| original_ca_bundle = os.environ.get(_debug.REQUESTS_CA_BUNDLE) | ||
| original_disable_verify = os.environ.get(cli_util.DISABLE_VERIFY_VARIABLE_NAME) | ||
|
|
||
| try: | ||
| # Create a temporary file to act as a CA bundle | ||
| with tempfile.NamedTemporaryFile(delete=False, suffix='.pem') as tmp_file: | ||
| tmp_file.write(b'# Test CA Bundle') | ||
| tmp_file_path = tmp_file.name | ||
|
|
||
| # Test 1: With REQUESTS_CA_BUNDLE set | ||
| os.environ[_debug.REQUESTS_CA_BUNDLE] = tmp_file_path | ||
| if cli_util.DISABLE_VERIFY_VARIABLE_NAME in os.environ: | ||
| del os.environ[cli_util.DISABLE_VERIFY_VARIABLE_NAME] | ||
|
|
||
| session = _debug.get_msal_http_client() | ||
| self.assertEqual(session.verify, tmp_file_path) | ||
|
|
||
| # Test 2: With connection verification disabled | ||
| del os.environ[_debug.REQUESTS_CA_BUNDLE] | ||
| os.environ[cli_util.DISABLE_VERIFY_VARIABLE_NAME] = "1" | ||
|
|
||
| session = _debug.get_msal_http_client() | ||
| self.assertFalse(session.verify) | ||
|
|
||
| # Test 3: With neither set (default behavior) | ||
| del os.environ[cli_util.DISABLE_VERIFY_VARIABLE_NAME] | ||
|
|
||
| session = _debug.get_msal_http_client() | ||
| self.assertTrue(session.verify) # Default is True | ||
|
|
||
| finally: | ||
| # Cleanup | ||
| os.unlink(tmp_file_path) | ||
| # Restore original environment | ||
| if original_ca_bundle: | ||
| os.environ[_debug.REQUESTS_CA_BUNDLE] = original_ca_bundle | ||
| elif _debug.REQUESTS_CA_BUNDLE in os.environ: | ||
| del os.environ[_debug.REQUESTS_CA_BUNDLE] | ||
|
Comment on lines
+76
to
+79
|
||
| if original_disable_verify: | ||
| os.environ[cli_util.DISABLE_VERIFY_VARIABLE_NAME] = original_disable_verify | ||
| elif cli_util.DISABLE_VERIFY_VARIABLE_NAME in os.environ: | ||
| del os.environ[cli_util.DISABLE_VERIFY_VARIABLE_NAME] | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting
os.environ[ADAL_PYTHON_SSL_NO_VERIFY] = '1'inside this function modifies global state as a side effect. This should be handled separately or documented clearly, as it affects the entire process and may have unintended consequences for other parts of the application.