From e405fd82ab6d7995158790da2961d983497b54b0 Mon Sep 17 00:00:00 2001 From: box-sdk-build Date: Fri, 26 Apr 2024 02:40:25 -0700 Subject: [PATCH] fix: Fix deserialization logic (box/box-codegen#474) --- .codegen.json | 2 +- box_sdk_gen/box/developer_token_auth.py | 98 +------------------------ box_sdk_gen/box/token_storage.py | 10 +-- box_sdk_gen/networking/auth.py | 17 ----- docs/authentication.md | 12 ++- test/auth.py | 44 ----------- 6 files changed, 13 insertions(+), 170 deletions(-) diff --git a/.codegen.json b/.codegen.json index a5bd42e..4e55a1e 100644 --- a/.codegen.json +++ b/.codegen.json @@ -1 +1 @@ -{ "engineHash": "baea184", "specHash": "1698c95", "version": "0.6.4" } +{ "engineHash": "f0bd1ce", "specHash": "1698c95", "version": "0.6.4" } diff --git a/box_sdk_gen/box/developer_token_auth.py b/box_sdk_gen/box/developer_token_auth.py index d5b8ebb..a6be9ac 100644 --- a/box_sdk_gen/box/developer_token_auth.py +++ b/box_sdk_gen/box/developer_token_auth.py @@ -1,11 +1,5 @@ from typing import Optional -from typing import List - -from box_sdk_gen.schemas import PostOAuth2TokenGrantTypeField - -from box_sdk_gen.schemas import PostOAuth2TokenSubjectTokenTypeField - from box_sdk_gen.schemas import AccessToken from box_sdk_gen.networking.auth import Authentication @@ -14,37 +8,11 @@ from box_sdk_gen.box.errors import BoxSDKError -from box_sdk_gen.box.token_storage import TokenStorage - -from box_sdk_gen.box.token_storage import InMemoryTokenStorage - -from box_sdk_gen.managers.authorization import AuthorizationManager - -from box_sdk_gen.schemas import PostOAuth2Token - -from box_sdk_gen.schemas import PostOAuth2Revoke - - -class DeveloperTokenConfig: - def __init__( - self, *, client_id: Optional[str] = None, client_secret: Optional[str] = None - ): - self.client_id = client_id - self.client_secret = client_secret - class BoxDeveloperTokenAuth(Authentication): - def __init__(self, token: str, *, config: DeveloperTokenConfig = None, **kwargs): - """ - :param config: Configuration object of DeveloperTokenAuth., defaults to None - :type config: DeveloperTokenConfig, optional - """ + def __init__(self, token: str, **kwargs): super().__init__(**kwargs) self.token = token - self.config = config - self.token_storage = InMemoryTokenStorage( - token=AccessToken(access_token=self.token) - ) def retrieve_token( self, *, network_session: Optional[NetworkSession] = None @@ -54,10 +22,7 @@ def retrieve_token( :param network_session: An object to keep network session state, defaults to None :type network_session: Optional[NetworkSession], optional """ - token: Optional[AccessToken] = self.token_storage.get() - if token == None: - raise BoxSDKError(message='No access token is available.') - return token + return AccessToken(access_token=self.token) def refresh_token( self, *, network_session: Optional[NetworkSession] = None @@ -76,62 +41,3 @@ def retrieve_authorization_header( ) -> str: token: AccessToken = self.retrieve_token(network_session=network_session) return ''.join(['Bearer ', token.access_token]) - - def revoke_token(self, *, network_session: Optional[NetworkSession] = None) -> None: - """ - Revoke an active Access Token, effectively logging a user out that has been previously authenticated. - :param network_session: An object to keep network session state, defaults to None - :type network_session: Optional[NetworkSession], optional - """ - token: Optional[AccessToken] = self.token_storage.get() - if token == None: - return None - auth_manager: AuthorizationManager = AuthorizationManager( - network_session=( - network_session if not network_session == None else NetworkSession() - ) - ) - auth_manager.revoke_access_token( - client_id=self.config.client_id, - client_secret=self.config.client_secret, - token=token.access_token, - ) - self.token_storage.clear() - return None - - def downscope_token( - self, - scopes: List[str], - *, - resource: Optional[str] = None, - shared_link: Optional[str] = None, - network_session: Optional[NetworkSession] = None - ) -> AccessToken: - """ - Downscope access token to the provided scopes. Returning a new access token with the provided scopes, with the original access token unchanged. - :param scopes: The scope(s) to apply to the resulting token. - :type scopes: List[str] - :param resource: The file or folder to get a downscoped token for. If None and shared_link None, the resulting token will not be scoped down to just a single item. The resource should be a full URL to an item, e.g. https://api.box.com/2.0/files/123456., defaults to None - :type resource: Optional[str], optional - :param shared_link: The shared link to get a downscoped token for. If None and item None, the resulting token will not be scoped down to just a single item., defaults to None - :type shared_link: Optional[str], optional - :param network_session: An object to keep network session state, defaults to None - :type network_session: Optional[NetworkSession], optional - """ - token: Optional[AccessToken] = self.token_storage.get() - if token == None or token.access_token == None: - raise BoxSDKError(message='No access token is available.') - auth_manager: AuthorizationManager = AuthorizationManager( - network_session=( - network_session if not network_session == None else NetworkSession() - ) - ) - downscoped_token: AccessToken = auth_manager.request_access_token( - PostOAuth2TokenGrantTypeField.URN_IETF_PARAMS_OAUTH_GRANT_TYPE_TOKEN_EXCHANGE.value, - subject_token=token.access_token, - subject_token_type=PostOAuth2TokenSubjectTokenTypeField.URN_IETF_PARAMS_OAUTH_TOKEN_TYPE_ACCESS_TOKEN.value, - resource=resource, - scope=' '.join(scopes), - box_shared_link=shared_link, - ) - return downscoped_token diff --git a/box_sdk_gen/box/token_storage.py b/box_sdk_gen/box/token_storage.py index 7a964b5..27ccdc5 100644 --- a/box_sdk_gen/box/token_storage.py +++ b/box_sdk_gen/box/token_storage.py @@ -20,17 +20,17 @@ def clear(self) -> None: class InMemoryTokenStorage(TokenStorage): - def __init__(self, token: Optional[AccessToken] = None): - self._token = token + def __init__(self): + self.token: Optional[AccessToken] = None def store(self, token: AccessToken) -> None: - self._token = token + self.token = token def get(self) -> Optional[AccessToken]: - return self._token + return self.token def clear(self) -> None: - self._token = None + self.token = None class FileTokenStorage(TokenStorage): diff --git a/box_sdk_gen/networking/auth.py b/box_sdk_gen/networking/auth.py index f976406..c5be20c 100644 --- a/box_sdk_gen/networking/auth.py +++ b/box_sdk_gen/networking/auth.py @@ -2,8 +2,6 @@ from abc import abstractmethod -from typing import List - from box_sdk_gen.schemas import AccessToken from box_sdk_gen.networking.network import NetworkSession @@ -30,18 +28,3 @@ def retrieve_authorization_header( self, *, network_session: Optional[NetworkSession] = None ) -> str: pass - - @abstractmethod - def revoke_token(self, *, network_session: Optional[NetworkSession] = None) -> None: - pass - - @abstractmethod - def downscope_token( - self, - scopes: List[str], - *, - resource: Optional[str] = None, - shared_link: Optional[str] = None, - network_session: Optional[NetworkSession] = None - ) -> AccessToken: - pass diff --git a/docs/authentication.md b/docs/authentication.md index 0d7b6ee..6d2007f 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -315,11 +315,9 @@ if __name__ == '__main__': # Revoke token Access tokens for a client can be revoked when needed. This call invalidates old token. -For BoxCCGAuth and BoxJWTAuth you can still reuse the `auth` object to retrieve a new token. -If you make any new call after revoking the token, a new token will be automatically retrieved. -For BoxOAuth it would be necessary to manually go through the authentication process again. -For BoxDeveloperTokenAuth, it is necessary to provide a DeveloperTokenConfig during initialization, -containing the client ID and client secret. +For CCGAuth and JWTAuth you can still reuse the `auth` object to retrieve a new token. If you make any new call after revoking the token, +a new token will be automatically retrieved. +For OAuth it would be necessary to manually go through the authentication process again. To revoke current client's tokens in the storage use the following code: @@ -344,7 +342,7 @@ If you want to learn more about available scopes please go [here](https://develo For example to get a new token with only `item_preview` scope, restricted to a single file, suitable for the [Content Preview UI Element](https://developer.box.com/en/guides/embed/ui-elements/preview/) you can use the following code. -You can also initialize `BoxDeveloperTokenAuth` with the retrieved access token and use it to create a new Client. +You can also initialize `DeveloperTokenAuth` with the retrieved access token and use it to create a new Client. @@ -356,7 +354,7 @@ downscoped_token: AccessToken = auth.downscope_token( scopes=['item_preview'], resource=resource, ) -downscoped_auth = BoxDeveloperTokenAuth(token=downscoped_token.access_token) +downscoped_auth = BoxDeveloperTokenAuth(downscoped_token.access_token) client = BoxClient(auth=downscoped_auth) ``` diff --git a/test/auth.py b/test/auth.py index 4c40a7e..d29c737 100644 --- a/test/auth.py +++ b/test/auth.py @@ -40,8 +40,6 @@ from box_sdk_gen.box.developer_token_auth import BoxDeveloperTokenAuth -from box_sdk_gen.box.developer_token_auth import DeveloperTokenConfig - from box_sdk_gen.box.oauth import BoxOAuth from box_sdk_gen.box.oauth import OAuthConfig @@ -202,48 +200,6 @@ def get_access_token() -> AccessToken: return auth_user.retrieve_token() -def test_developer_token_auth_revoke(): - developer_token_config: DeveloperTokenConfig = DeveloperTokenConfig( - client_id=get_env_var('CLIENT_ID'), client_secret=get_env_var('CLIENT_SECRET') - ) - token: AccessToken = get_access_token() - auth: BoxDeveloperTokenAuth = BoxDeveloperTokenAuth( - token=token.access_token, config=developer_token_config - ) - auth.retrieve_token() - token_from_storage_before_revoke: Optional[AccessToken] = auth.token_storage.get() - auth.revoke_token() - token_from_storage_after_revoke: Optional[AccessToken] = auth.token_storage.get() - assert not token_from_storage_before_revoke == None - assert token_from_storage_after_revoke == None - - -def test_developer_token_auth_downscope(): - developer_token_config: DeveloperTokenConfig = DeveloperTokenConfig( - client_id=get_env_var('CLIENT_ID'), client_secret=get_env_var('CLIENT_SECRET') - ) - token: AccessToken = get_access_token() - auth: BoxDeveloperTokenAuth = BoxDeveloperTokenAuth( - token=token.access_token, config=developer_token_config - ) - parent_client: BoxClient = BoxClient(auth=auth) - folder: FolderFull = parent_client.folders.create_folder( - get_uuid(), CreateFolderParent(id='0') - ) - resource_path: str = ''.join(['https://api.box.com/2.0/folders/', folder.id]) - downscoped_token: AccessToken = auth.downscope_token( - ['item_rename', 'item_preview'], resource=resource_path - ) - assert not downscoped_token.access_token == None - downscoped_client: BoxClient = BoxClient( - auth=BoxDeveloperTokenAuth(token=downscoped_token.access_token) - ) - downscoped_client.folders.update_folder_by_id(folder.id, name=get_uuid()) - with pytest.raises(Exception): - downscoped_client.folders.delete_folder_by_id(folder.id) - parent_client.folders.delete_folder_by_id(folder.id) - - def test_developer_token_auth(): user_id: str = get_env_var('USER_ID') token: AccessToken = get_access_token()