From 783ed009f1be91231daf3c76b9164f574fa7def1 Mon Sep 17 00:00:00 2001 From: aldbr Date: Fri, 19 Sep 2025 18:39:49 +0800 Subject: [PATCH 1/2] fix: token revoke endpoint parameters --- diracx-cli/src/diracx/cli/auth.py | 2 +- diracx-core/src/diracx/core/models.py | 7 +++ .../src/diracx/logic/auth/management.py | 21 ++++++- .../src/diracx/routers/auth/management.py | 38 ++++++++----- diracx-routers/tests/auth/test_standard.py | 56 ++++++++++++++++--- 5 files changed, 100 insertions(+), 24 deletions(-) diff --git a/diracx-cli/src/diracx/cli/auth.py b/diracx-cli/src/diracx/cli/auth.py index 91a8d9bad..956c003f4 100644 --- a/diracx-cli/src/diracx/cli/auth.py +++ b/diracx-cli/src/diracx/cli/auth.py @@ -129,7 +129,7 @@ async def logout(): # Revoke refresh token try: await api.auth.revoke_refresh_token_by_refresh_token( - client_id=api.client_id, refresh_token=credentials.refresh_token + client_id=api.client_id, token=credentials.refresh_token ) except Exception as e: print(f"Error revoking the refresh token {e!r}") diff --git a/diracx-core/src/diracx/core/models.py b/diracx-core/src/diracx/core/models.py index a98f87ab3..c71ef7392 100644 --- a/diracx-core/src/diracx/core/models.py +++ b/diracx-core/src/diracx/core/models.py @@ -247,6 +247,13 @@ class SandboxUploadResponse(BaseModel): fields: dict[str, str] = {} +class TokenTypeHint(StrEnum): + """Token type hints for RFC7009 revocation endpoint.""" + + access_token = "access_token" # noqa: S105 + refresh_token = "refresh_token" # noqa: S105 + + class GrantType(StrEnum): """Grant types for OAuth2.""" diff --git a/diracx-logic/src/diracx/logic/auth/management.py b/diracx-logic/src/diracx/logic/auth/management.py index 5d3cf52ff..5a02bd27f 100644 --- a/diracx-logic/src/diracx/logic/auth/management.py +++ b/diracx-logic/src/diracx/logic/auth/management.py @@ -4,6 +4,8 @@ from uuid_utils import UUID +from diracx.core.exceptions import InvalidCredentialsError +from diracx.core.models import TokenTypeHint from diracx.core.settings import AuthSettings from diracx.db.sql import AuthDB from diracx.logic.auth.utils import verify_dirac_refresh_token @@ -35,9 +37,22 @@ async def revoke_refresh_token_by_jti( async def revoke_refresh_token_by_refresh_token( - auth_db: AuthDB, subject: str | None, refresh_token: str, settings: AuthSettings + auth_db: AuthDB, + subject: str | None, + token: str, + token_type_hint: str | None, + client_id: str, + settings: AuthSettings, ) -> str: - """Revoke a refresh token. If a subject is provided, then the refresh token must be owned by that subject.""" - jti, _, _ = await verify_dirac_refresh_token(refresh_token, settings) + """Revoke a refresh token following RFC7009.""" + # Test the token type hint + if token_type_hint and token_type_hint == TokenTypeHint.access_token: + raise ValueError("unsupported_token_type") + + # Test the client_id + if settings.dirac_client_id != client_id: + raise InvalidCredentialsError("Unrecognised client_id") + # Decode and verify the refresh token + jti, _, _ = await verify_dirac_refresh_token(token, settings) return await revoke_refresh_token_by_jti(auth_db=auth_db, subject=subject, jti=jti) diff --git a/diracx-routers/src/diracx/routers/auth/management.py b/diracx-routers/src/diracx/routers/auth/management.py index 1f8775b4f..a008fb616 100644 --- a/diracx-routers/src/diracx/routers/auth/management.py +++ b/diracx-routers/src/diracx/routers/auth/management.py @@ -9,12 +9,12 @@ import logging from typing import Annotated, Any -from fastapi import Depends, HTTPException, status +from fastapi import Depends, Form, HTTPException, status from joserfc.errors import DecodeError from typing_extensions import TypedDict from uuid_utils import UUID -from diracx.core.exceptions import TokenNotFoundError +from diracx.core.exceptions import InvalidCredentialsError, TokenNotFoundError from diracx.core.properties import PROXY_MANAGEMENT, SecurityProperty from diracx.logic.auth.management import ( get_refresh_tokens as get_refresh_tokens_bl, @@ -66,22 +66,34 @@ async def get_refresh_tokens( async def revoke_refresh_token_by_refresh_token( auth_db: AuthDB, settings: AuthSettings, - refresh_token: str, - client_id: str, + token: Annotated[str, Form(description="The refresh token to revoke")], + token_type_hint: Annotated[ + str | None, + Form(description="Hint for the type of token being revoked"), + ] = None, + client_id: Annotated[ + str, + Form(description="The client ID of the application requesting the revocation"), + ] = "myDIRACClientID", ) -> str: - """Revoke a refresh token.""" - # Test the client_id - if settings.dirac_client_id != client_id: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, detail="Unrecognised client_id" - ) - + """Revoke a refresh token. Closely follows RFC 7009 (or try to, at least).""" try: await revoke_refresh_token_by_refresh_token_bl( - auth_db, None, refresh_token, settings + auth_db, None, token, token_type_hint, client_id, settings ) - except DecodeError: + except (DecodeError, KeyError): logger.warning("Someone tried to revoke its token but failed.") + except ValueError as e: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=str(e), + ) from e + except InvalidCredentialsError as e: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=str(e), + headers={"WWW-Authenticate": "Bearer"}, + ) from e return "Refresh token revoked" diff --git a/diracx-routers/tests/auth/test_standard.py b/diracx-routers/tests/auth/test_standard.py index 8ca5c3e2f..5865cc052 100644 --- a/diracx-routers/tests/auth/test_standard.py +++ b/diracx-routers/tests/auth/test_standard.py @@ -1124,8 +1124,8 @@ async def test_revoke_refresh_token_classic(test_client, auth_httpx_mock: HTTPXM # Normal user tries to delete a random and non-existing RT: should respond with a 200 r = test_client.post( "/api/auth/revoke", - params={ - "refresh_token": "does-not-exist", + data={ + "token": "does-not-exist", "client_id": DIRAC_CLIENT_ID, }, ) @@ -1134,8 +1134,8 @@ async def test_revoke_refresh_token_classic(test_client, auth_httpx_mock: HTTPXM # Normal user tries to delete his/her RT: should work r = test_client.post( "/api/auth/revoke", - params={ - "refresh_token": normal_user_refresh_token, + data={ + "token": normal_user_refresh_token, "client_id": DIRAC_CLIENT_ID, }, ) @@ -1152,14 +1152,56 @@ async def test_revoke_refresh_token_classic(test_client, auth_httpx_mock: HTTPXM # Normal user tries to delete a valid RT using the wrong client id r = test_client.post( "/api/auth/revoke", - params={ - "refresh_token": normal_user_refresh_token, + data={ + "token": normal_user_refresh_token, "client_id": "a_wrong_dirac_client_id", }, ) - assert r.status_code == 403 + assert r.status_code == 401 assert r.json()["detail"] == "Unrecognised client_id" + # Normal user tries to delete a valid access token: should not work but respond with a 200 + r = test_client.post( + "/api/auth/revoke", + data={ + "token": normal_user_access_token, + "client_id": DIRAC_CLIENT_ID, + }, + ) + assert r.status_code == 200 + + # Get all refresh tokens, expect no refresh token + r = test_client.get( + "/api/auth/refresh-tokens", + headers={"Authorization": f"Bearer {normal_user_access_token}"}, + ) + + assert r.json() == [] + + # Normal user tries to delete a valid access token by specifying the token_type_hint: should not work + r = test_client.post( + "/api/auth/revoke", + data={ + "token": normal_user_access_token, + "client_id": DIRAC_CLIENT_ID, + "token_type_hint": "access_token", + }, + ) + assert r.status_code == 400 + assert r.json()["detail"] == "unsupported_token_type" + + # Normal user tries to delete a valid access token by specifying an invalid token_type_hint: + # Should not work but respond with a 200 + r = test_client.post( + "/api/auth/revoke", + data={ + "token": normal_user_access_token, + "client_id": DIRAC_CLIENT_ID, + "token_type_hint": "invalid_token_type", + }, + ) + assert r.status_code == 200 + def _get_tokens( test_client, group: str = "lhcb_user", property: SecurityProperty = NORMAL_USER From 6bb41e048e9d73cfc735269f6439bce250298ef8 Mon Sep 17 00:00:00 2001 From: aldbr Date: Tue, 23 Sep 2025 10:16:05 +0800 Subject: [PATCH 2/2] fix: adapt clients --- .../_generated/aio/operations/_operations.py | 55 +------------- .../client/_generated/models/__init__.py | 2 + .../client/_generated/models/_models.py | 40 ++++++++++ .../_generated/operations/_operations.py | 75 +------------------ .../src/diracx/client/patches/auth/aio.py | 30 +++++++- .../src/diracx/client/patches/auth/common.py | 45 +++++++++-- .../src/diracx/client/patches/auth/sync.py | 33 +++++++- .../_generated/aio/operations/_operations.py | 55 +------------- .../client/_generated/models/__init__.py | 2 + .../client/_generated/models/_models.py | 40 ++++++++++ .../_generated/operations/_operations.py | 75 +------------------ 11 files changed, 181 insertions(+), 271 deletions(-) diff --git a/diracx-client/src/diracx/client/_generated/aio/operations/_operations.py b/diracx-client/src/diracx/client/_generated/aio/operations/_operations.py index a87316174..06f7a655f 100644 --- a/diracx-client/src/diracx/client/_generated/aio/operations/_operations.py +++ b/diracx-client/src/diracx/client/_generated/aio/operations/_operations.py @@ -35,7 +35,6 @@ build_auth_initiate_authorization_flow_request, build_auth_initiate_device_flow_request, build_auth_revoke_refresh_token_by_jti_request, - build_auth_revoke_refresh_token_by_refresh_token_request, build_auth_userinfo_request, build_config_serve_config_request, build_jobs_add_heartbeat_request, @@ -293,6 +292,7 @@ def __init__(self, *args, **kwargs) -> None: raise_if_not_implemented( self.__class__, [ + "revoke_refresh_token_by_refresh_token", "get_oidc_token", ], ) @@ -583,59 +583,6 @@ async def get_refresh_tokens(self, **kwargs: Any) -> List[Any]: return deserialized # type: ignore - @distributed_trace_async - async def revoke_refresh_token_by_refresh_token(self, *, refresh_token: str, client_id: str, **kwargs: Any) -> str: - """Revoke Refresh Token By Refresh Token. - - Revoke a refresh token. - - :keyword refresh_token: Required. - :paramtype refresh_token: str - :keyword client_id: Required. - :paramtype client_id: str - :return: str - :rtype: str - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[str] = kwargs.pop("cls", None) - - _request = build_auth_revoke_refresh_token_by_refresh_token_request( - refresh_token=refresh_token, - client_id=client_id, - headers=_headers, - params=_params, - ) - _request.url = self._client.format_url(_request.url) - - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - deserialized = self._deserialize("str", pipeline_response.http_response) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - @distributed_trace_async async def revoke_refresh_token_by_jti(self, jti: str, **kwargs: Any) -> str: """Revoke Refresh Token By Jti. diff --git a/diracx-client/src/diracx/client/_generated/models/__init__.py b/diracx-client/src/diracx/client/_generated/models/__init__.py index 06de02aab..c11a4fa77 100644 --- a/diracx-client/src/diracx/client/_generated/models/__init__.py +++ b/diracx-client/src/diracx/client/_generated/models/__init__.py @@ -14,6 +14,7 @@ from ._models import ( # type: ignore BodyAuthGetOidcToken, BodyAuthGetOidcTokenGrantType, + BodyAuthRevokeRefreshTokenByRefreshToken, BodyJobsRescheduleJobs, BodyJobsUnassignBulkJobsSandboxes, GroupInfo, @@ -65,6 +66,7 @@ __all__ = [ "BodyAuthGetOidcToken", "BodyAuthGetOidcTokenGrantType", + "BodyAuthRevokeRefreshTokenByRefreshToken", "BodyJobsRescheduleJobs", "BodyJobsUnassignBulkJobsSandboxes", "GroupInfo", diff --git a/diracx-client/src/diracx/client/_generated/models/_models.py b/diracx-client/src/diracx/client/_generated/models/_models.py index 964841dc3..5ecd5ad7b 100644 --- a/diracx-client/src/diracx/client/_generated/models/_models.py +++ b/diracx-client/src/diracx/client/_generated/models/_models.py @@ -94,6 +94,46 @@ class BodyAuthGetOidcTokenGrantType(_serialization.Model): """OAuth2 Grant type.""" +class BodyAuthRevokeRefreshTokenByRefreshToken(_serialization.Model): + """Body_auth_revoke_refresh_token_by_refresh_token. + + All required parameters must be populated in order to send to server. + + :ivar token: The refresh token to revoke. Required. + :vartype token: str + :ivar token_type_hint: Hint for the type of token being revoked. + :vartype token_type_hint: str + :ivar client_id: The client ID of the application requesting the revocation. + :vartype client_id: str + """ + + _validation = { + "token": {"required": True}, + } + + _attribute_map = { + "token": {"key": "token", "type": "str"}, + "token_type_hint": {"key": "token_type_hint", "type": "str"}, + "client_id": {"key": "client_id", "type": "str"}, + } + + def __init__( + self, *, token: str, token_type_hint: Optional[str] = None, client_id: str = "myDIRACClientID", **kwargs: Any + ) -> None: + """ + :keyword token: The refresh token to revoke. Required. + :paramtype token: str + :keyword token_type_hint: Hint for the type of token being revoked. + :paramtype token_type_hint: str + :keyword client_id: The client ID of the application requesting the revocation. + :paramtype client_id: str + """ + super().__init__(**kwargs) + self.token = token + self.token_type_hint = token_type_hint + self.client_id = client_id + + class BodyJobsRescheduleJobs(_serialization.Model): """Body_jobs_reschedule_jobs. diff --git a/diracx-client/src/diracx/client/_generated/operations/_operations.py b/diracx-client/src/diracx/client/_generated/operations/_operations.py index b8800ca84..14739c4fc 100644 --- a/diracx-client/src/diracx/client/_generated/operations/_operations.py +++ b/diracx-client/src/diracx/client/_generated/operations/_operations.py @@ -175,27 +175,6 @@ def build_auth_get_refresh_tokens_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -def build_auth_revoke_refresh_token_by_refresh_token_request( # pylint: disable=name-too-long - *, refresh_token: str, client_id: str, **kwargs: Any -) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - accept = _headers.pop("Accept", "application/json") - - # Construct URL - _url = "/api/auth/revoke" - - # Construct parameters - _params["refresh_token"] = _SERIALIZER.query("refresh_token", refresh_token, "str") - _params["client_id"] = _SERIALIZER.query("client_id", client_id, "str") - - # Construct headers - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - - return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) - - def build_auth_revoke_refresh_token_by_jti_request( # pylint: disable=name-too-long jti: str, **kwargs: Any ) -> HttpRequest: @@ -816,6 +795,7 @@ def __init__(self, *args, **kwargs) -> None: raise_if_not_implemented( self.__class__, [ + "revoke_refresh_token_by_refresh_token", "get_oidc_token", ], ) @@ -1104,59 +1084,6 @@ def get_refresh_tokens(self, **kwargs: Any) -> List[Any]: return deserialized # type: ignore - @distributed_trace - def revoke_refresh_token_by_refresh_token(self, *, refresh_token: str, client_id: str, **kwargs: Any) -> str: - """Revoke Refresh Token By Refresh Token. - - Revoke a refresh token. - - :keyword refresh_token: Required. - :paramtype refresh_token: str - :keyword client_id: Required. - :paramtype client_id: str - :return: str - :rtype: str - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[str] = kwargs.pop("cls", None) - - _request = build_auth_revoke_refresh_token_by_refresh_token_request( - refresh_token=refresh_token, - client_id=client_id, - headers=_headers, - params=_params, - ) - _request.url = self._client.format_url(_request.url) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - deserialized = self._deserialize("str", pipeline_response.http_response) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - @distributed_trace def revoke_refresh_token_by_jti(self, jti: str, **kwargs: Any) -> str: """Revoke Refresh Token By Jti. diff --git a/diracx-client/src/diracx/client/patches/auth/aio.py b/diracx-client/src/diracx/client/patches/auth/aio.py index e58950078..51016f677 100644 --- a/diracx-client/src/diracx/client/patches/auth/aio.py +++ b/diracx-client/src/diracx/client/patches/auth/aio.py @@ -6,6 +6,7 @@ """ from __future__ import annotations +from ast import Dict __all__ = [ "AuthOperations", @@ -19,7 +20,7 @@ _models, AuthOperations as _AuthOperations, ) -from .common import prepare_request, handle_response +from .common import handle_revoke_response, prepare_oidc_request, handle_oidc_response, prepare_revoke_request class AuthOperations(_AuthOperations): @@ -27,7 +28,7 @@ class AuthOperations(_AuthOperations): async def get_oidc_token( self, device_code: str, client_id: str, **kwargs ) -> TokenResponse | _models.DeviceFlowErrorResponse: - request = prepare_request( + request = prepare_oidc_request( device_code=device_code, client_id=client_id, format_url=self._client.format_url, @@ -39,7 +40,30 @@ async def get_oidc_token( ) ) - response = handle_response(pipeline_response, self._deserialize) + response = handle_oidc_response(pipeline_response, self._deserialize) if isinstance(response, _models.DeviceFlowErrorResponse): return response return TokenResponse.model_validate(response.as_dict()) + + @distributed_trace_async + async def revoke_refresh_token_by_refresh_token( + self, + *, + token: str, + client_id: str, + token_type_hint: str = "refresh_token", + **kwargs, + ) -> str: + request = prepare_revoke_request( + token=token, + client_id=client_id, + token_type_hint=token_type_hint, + format_url=self._client.format_url, + ) + + pipeline_response: PipelineResponse = ( + await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + ) + return handle_revoke_response(pipeline_response, self._deserialize) diff --git a/diracx-client/src/diracx/client/patches/auth/common.py b/diracx-client/src/diracx/client/patches/auth/common.py index 321489afb..7da915319 100644 --- a/diracx-client/src/diracx/client/patches/auth/common.py +++ b/diracx-client/src/diracx/client/patches/auth/common.py @@ -3,8 +3,8 @@ from __future__ import annotations __all__ = [ - "prepare_request", - "handle_response", + "prepare_oidc_request", + "handle_oidc_response", ] from typing import Any @@ -18,20 +18,24 @@ from ..._generated.operations._operations import _SERIALIZER -def build_token_request(**kwargs: Any) -> HttpRequest: +def build_request(**kwargs: Any) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) accept = _headers.pop("Accept", "application/json") - _url = "/api/auth/token" + _url = kwargs.pop("url") _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) + _method = kwargs.pop("method") + return HttpRequest(method=_method, url=_url, headers=_headers, **kwargs) -def prepare_request(device_code, client_id, format_url) -> HttpRequest: - request = build_token_request( + +def prepare_oidc_request(device_code, client_id, format_url) -> HttpRequest: + request = build_request( + method="POST", + url="/api/auth/token", data={ "grant_type": "urn:ietf:params:oauth:grant-type:device_code", "device_code": device_code, @@ -42,7 +46,21 @@ def prepare_request(device_code, client_id, format_url) -> HttpRequest: return request -def handle_response( +def prepare_revoke_request(token, client_id, token_type_hint, format_url) -> HttpRequest: + request = build_request( + method="POST", + url="/api/auth/revoke", + data={ + "token": token, + "client_id": client_id, + "token_type_hint": token_type_hint, + } + ) + request.url = format_url(request.url) + return request + + +def handle_oidc_response( pipeline_response: PipelineResponse, deserialize ) -> TokenResponse | DeviceFlowErrorResponse: response = pipeline_response.http_response @@ -54,3 +72,14 @@ def handle_response( else: map_error(status_code=response.status_code, response=response, error_map={}) raise HttpResponseError(response=response) + + +def handle_revoke_response( + pipeline_response: PipelineResponse, deserialize +) -> str: + response = pipeline_response.http_response + + if response.status_code != 200: + map_error(status_code=response.status_code, response=response, error_map={}) + raise HttpResponseError(response=response) + return deserialize("str", pipeline_response) diff --git a/diracx-client/src/diracx/client/patches/auth/sync.py b/diracx-client/src/diracx/client/patches/auth/sync.py index 20a3da1b4..1efa26d17 100644 --- a/diracx-client/src/diracx/client/patches/auth/sync.py +++ b/diracx-client/src/diracx/client/patches/auth/sync.py @@ -18,15 +18,15 @@ _models, AuthOperations as _AuthOperations, ) -from .common import prepare_request, handle_response +from .common import handle_revoke_response, prepare_oidc_request, handle_oidc_response, prepare_revoke_request class AuthOperations(_AuthOperations): @distributed_trace - async def get_oidc_token( + def get_oidc_token( self, device_code: str, client_id: str, **kwargs ) -> _models.TokenResponse | _models.DeviceFlowErrorResponse: - request = prepare_request( + request = prepare_oidc_request( device_code=device_code, client_id=client_id, format_url=self._client.format_url, @@ -38,4 +38,29 @@ async def get_oidc_token( ) ) - return handle_response(pipeline_response, self._deserialize) + return handle_oidc_response(pipeline_response, self._deserialize) + + + @distributed_trace + def revoke_refresh_token_by_refresh_token( + self, + *, + token: str, + client_id: str, + token_type_hint: str = "refresh_token", + **kwargs, + ) -> str: + request = prepare_revoke_request( + token=token, + client_id=client_id, + token_type_hint=token_type_hint, + format_url=self._client.format_url, + ) + + pipeline_response: PipelineResponse = ( + self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + ) + + return handle_revoke_response(pipeline_response, self._deserialize) diff --git a/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/aio/operations/_operations.py b/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/aio/operations/_operations.py index 8927a2921..c9a77f263 100644 --- a/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/aio/operations/_operations.py +++ b/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/aio/operations/_operations.py @@ -35,7 +35,6 @@ build_auth_initiate_authorization_flow_request, build_auth_initiate_device_flow_request, build_auth_revoke_refresh_token_by_jti_request, - build_auth_revoke_refresh_token_by_refresh_token_request, build_auth_userinfo_request, build_config_serve_config_request, build_jobs_add_heartbeat_request, @@ -296,6 +295,7 @@ def __init__(self, *args, **kwargs) -> None: raise_if_not_implemented( self.__class__, [ + "revoke_refresh_token_by_refresh_token", "get_oidc_token", ], ) @@ -586,59 +586,6 @@ async def get_refresh_tokens(self, **kwargs: Any) -> List[Any]: return deserialized # type: ignore - @distributed_trace_async - async def revoke_refresh_token_by_refresh_token(self, *, refresh_token: str, client_id: str, **kwargs: Any) -> str: - """Revoke Refresh Token By Refresh Token. - - Revoke a refresh token. - - :keyword refresh_token: Required. - :paramtype refresh_token: str - :keyword client_id: Required. - :paramtype client_id: str - :return: str - :rtype: str - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[str] = kwargs.pop("cls", None) - - _request = build_auth_revoke_refresh_token_by_refresh_token_request( - refresh_token=refresh_token, - client_id=client_id, - headers=_headers, - params=_params, - ) - _request.url = self._client.format_url(_request.url) - - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - deserialized = self._deserialize("str", pipeline_response.http_response) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - @distributed_trace_async async def revoke_refresh_token_by_jti(self, jti: str, **kwargs: Any) -> str: """Revoke Refresh Token By Jti. diff --git a/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/models/__init__.py b/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/models/__init__.py index d8e29cfeb..e2da4791a2 100644 --- a/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/models/__init__.py +++ b/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/models/__init__.py @@ -14,6 +14,7 @@ from ._models import ( # type: ignore BodyAuthGetOidcToken, BodyAuthGetOidcTokenGrantType, + BodyAuthRevokeRefreshTokenByRefreshToken, BodyJobsRescheduleJobs, BodyJobsUnassignBulkJobsSandboxes, ExtendedMetadata, @@ -65,6 +66,7 @@ __all__ = [ "BodyAuthGetOidcToken", "BodyAuthGetOidcTokenGrantType", + "BodyAuthRevokeRefreshTokenByRefreshToken", "BodyJobsRescheduleJobs", "BodyJobsUnassignBulkJobsSandboxes", "ExtendedMetadata", diff --git a/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/models/_models.py b/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/models/_models.py index 657e1417d..f37c11868 100644 --- a/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/models/_models.py +++ b/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/models/_models.py @@ -94,6 +94,46 @@ class BodyAuthGetOidcTokenGrantType(_serialization.Model): """OAuth2 Grant type.""" +class BodyAuthRevokeRefreshTokenByRefreshToken(_serialization.Model): + """Body_auth_revoke_refresh_token_by_refresh_token. + + All required parameters must be populated in order to send to server. + + :ivar token: The refresh token to revoke. Required. + :vartype token: str + :ivar token_type_hint: Hint for the type of token being revoked. + :vartype token_type_hint: str + :ivar client_id: The client ID of the application requesting the revocation. + :vartype client_id: str + """ + + _validation = { + "token": {"required": True}, + } + + _attribute_map = { + "token": {"key": "token", "type": "str"}, + "token_type_hint": {"key": "token_type_hint", "type": "str"}, + "client_id": {"key": "client_id", "type": "str"}, + } + + def __init__( + self, *, token: str, token_type_hint: Optional[str] = None, client_id: str = "myDIRACClientID", **kwargs: Any + ) -> None: + """ + :keyword token: The refresh token to revoke. Required. + :paramtype token: str + :keyword token_type_hint: Hint for the type of token being revoked. + :paramtype token_type_hint: str + :keyword client_id: The client ID of the application requesting the revocation. + :paramtype client_id: str + """ + super().__init__(**kwargs) + self.token = token + self.token_type_hint = token_type_hint + self.client_id = client_id + + class BodyJobsRescheduleJobs(_serialization.Model): """Body_jobs_reschedule_jobs. diff --git a/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/operations/_operations.py b/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/operations/_operations.py index fa5e665ce..1bac3a4cd 100644 --- a/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/operations/_operations.py +++ b/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/operations/_operations.py @@ -175,27 +175,6 @@ def build_auth_get_refresh_tokens_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -def build_auth_revoke_refresh_token_by_refresh_token_request( # pylint: disable=name-too-long - *, refresh_token: str, client_id: str, **kwargs: Any -) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - accept = _headers.pop("Accept", "application/json") - - # Construct URL - _url = "/api/auth/revoke" - - # Construct parameters - _params["refresh_token"] = _SERIALIZER.query("refresh_token", refresh_token, "str") - _params["client_id"] = _SERIALIZER.query("client_id", client_id, "str") - - # Construct headers - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - - return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) - - def build_auth_revoke_refresh_token_by_jti_request( # pylint: disable=name-too-long jti: str, **kwargs: Any ) -> HttpRequest: @@ -865,6 +844,7 @@ def __init__(self, *args, **kwargs) -> None: raise_if_not_implemented( self.__class__, [ + "revoke_refresh_token_by_refresh_token", "get_oidc_token", ], ) @@ -1153,59 +1133,6 @@ def get_refresh_tokens(self, **kwargs: Any) -> List[Any]: return deserialized # type: ignore - @distributed_trace - def revoke_refresh_token_by_refresh_token(self, *, refresh_token: str, client_id: str, **kwargs: Any) -> str: - """Revoke Refresh Token By Refresh Token. - - Revoke a refresh token. - - :keyword refresh_token: Required. - :paramtype refresh_token: str - :keyword client_id: Required. - :paramtype client_id: str - :return: str - :rtype: str - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[str] = kwargs.pop("cls", None) - - _request = build_auth_revoke_refresh_token_by_refresh_token_request( - refresh_token=refresh_token, - client_id=client_id, - headers=_headers, - params=_params, - ) - _request.url = self._client.format_url(_request.url) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - deserialized = self._deserialize("str", pipeline_response.http_response) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - @distributed_trace def revoke_refresh_token_by_jti(self, jti: str, **kwargs: Any) -> str: """Revoke Refresh Token By Jti.