From a1dc5e7555dad40fb73614f180e15a65b7da28d7 Mon Sep 17 00:00:00 2001 From: Matthias Dellweg Date: Thu, 3 Oct 2024 22:09:42 +0200 Subject: [PATCH] Fix oauth2 with custom ca bundle fixes #1096 --- CHANGES/1096.bugfix | 1 + pulp-glue/pulp_glue/common/authentication.py | 49 +++++++++++--------- pulp-glue/tests/test_authentication.py | 4 +- pulpcore/cli/common/generic.py | 4 ++ 4 files changed, 35 insertions(+), 23 deletions(-) create mode 100644 CHANGES/1096.bugfix diff --git a/CHANGES/1096.bugfix b/CHANGES/1096.bugfix new file mode 100644 index 00000000..eaf12949 --- /dev/null +++ b/CHANGES/1096.bugfix @@ -0,0 +1 @@ +Fixed OAuth2 not using the provided CA bundle. diff --git a/pulp-glue/pulp_glue/common/authentication.py b/pulp-glue/pulp_glue/common/authentication.py index 32f8c1d1..c48aa84f 100644 --- a/pulp-glue/pulp_glue/common/authentication.py +++ b/pulp-glue/pulp_glue/common/authentication.py @@ -16,28 +16,30 @@ def __init__( client_secret: str, token_url: str, scopes: t.Optional[t.List[str]] = None, + verify: t.Optional[t.Union[str, bool]] = None, ): - self.token_auth = requests.auth.HTTPBasicAuth(client_id, client_secret) - self.token_url = token_url - self.scopes = scopes + self._token_server_auth = requests.auth.HTTPBasicAuth(client_id, client_secret) + self._token_url = token_url + self._scopes = scopes + self._verify = verify - self.access_token: t.Optional[str] = None - self.expire_at: t.Optional[datetime] = None + self._access_token: t.Optional[str] = None + self._expire_at: t.Optional[datetime] = None def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: - if self.expire_at is None or self.expire_at < datetime.now(): - self.retrieve_token() + if self._expire_at is None or self._expire_at < datetime.now(): + self._retrieve_token() - assert self.access_token is not None + assert self._access_token is not None - request.headers["Authorization"] = f"Bearer {self.access_token}" + request.headers["Authorization"] = f"Bearer {self._access_token}" # Call to untyped function "register_hook" in typed context - request.register_hook("response", self.handle401) # type: ignore[no-untyped-call] + request.register_hook("response", self._handle401) # type: ignore[no-untyped-call] return request - def handle401( + def _handle401( self, response: requests.Response, **kwargs: t.Any, @@ -48,9 +50,9 @@ def handle401( # If we get this far, probably the token is not valid anymore. # Try to reach for a new token once. - self.retrieve_token() + self._retrieve_token() - assert self.access_token is not None + assert self._access_token is not None # Consume content and release the original connection # to allow our new request to reuse the same one. @@ -58,12 +60,12 @@ def handle401( response.close() prepared_new_request = response.request.copy() - prepared_new_request.headers["Authorization"] = f"Bearer {self.access_token}" + prepared_new_request.headers["Authorization"] = f"Bearer {self._access_token}" # Avoid to enter into an infinity loop. # Call to untyped function "deregister_hook" in typed context prepared_new_request.deregister_hook( # type: ignore[no-untyped-call] - "response", self.handle401 + "response", self._handle401 ) # "Response" has no attribute "connection" @@ -73,18 +75,23 @@ def handle401( return new_response - def retrieve_token(self) -> None: + def _retrieve_token(self) -> None: data = { "grant_type": "client_credentials", } - if self.scopes: - data["scope"] = " ".join(self.scopes) + if self._scopes: + data["scope"] = " ".join(self._scopes) - response: requests.Response = requests.post(self.token_url, data=data, auth=self.token_auth) + response: requests.Response = requests.post( + self._token_url, + data=data, + auth=self._token_server_auth, + verify=self._verify, + ) response.raise_for_status() token = response.json() - self.expire_at = datetime.now() + timedelta(seconds=token["expires_in"]) - self.access_token = token["access_token"] + self._expire_at = datetime.now() + timedelta(seconds=token["expires_in"]) + self._access_token = token["access_token"] diff --git a/pulp-glue/tests/test_authentication.py b/pulp-glue/tests/test_authentication.py index 56c271fb..dc3df073 100644 --- a/pulp-glue/tests/test_authentication.py +++ b/pulp-glue/tests/test_authentication.py @@ -22,8 +22,8 @@ def _requests_post_mocked(url: str, data: t.Dict[str, t.Any], **kwargs: t.Any): monkeypatch.setattr("requests.post", _requests_post_mocked) - OAuth2ClientCredentialsAuth(token_url="", client_id="", client_secret="").retrieve_token() + OAuth2ClientCredentialsAuth(token_url="", client_id="", client_secret="")._retrieve_token() OAuth2ClientCredentialsAuth( token_url="", client_id="", client_secret="", scopes=[] - ).retrieve_token() + )._retrieve_token() diff --git a/pulpcore/cli/common/generic.py b/pulpcore/cli/common/generic.py index 6cb5bf81..08a09714 100644 --- a/pulpcore/cli/common/generic.py +++ b/pulpcore/cli/common/generic.py @@ -268,6 +268,8 @@ def oauth2_client_credentials_auth( token_url=flow["tokenUrl"], # Try to request all possible scopes. scopes=flow["scopes"], + # This is desparately looking for a better design. + verify=self.pulp_ctx.api._session.verify, ) else: self._memoized[key] = OAuth2ClientCredentialsAuth( @@ -276,6 +278,8 @@ def oauth2_client_credentials_auth( token_url=flow["tokenUrl"], # Try to request all possible scopes. scopes=flow["scopes"], + # This is desparately looking for a better design. + verify=self.pulp_ctx.api._session.verify, ) return self._memoized[key]