Skip to content

Commit

Permalink
Adapted tokens to be handled externally to allow parallelism
Browse files Browse the repository at this point in the history
  • Loading branch information
Rasmus Oscar Welander committed Aug 29, 2024
1 parent afe7044 commit 50ac90b
Show file tree
Hide file tree
Showing 13 changed files with 167 additions and 145 deletions.
File renamed without changes.
25 changes: 13 additions & 12 deletions src/app.py → cs3client/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@
Authors: Rasmus Welander, Diogo Castro, Giuseppe Lo Presti.
Emails: [email protected], [email protected], [email protected]
Last updated: 19/08/2024
Last updated: 28/08/2024
"""

import logging
from auth import Auth
from cs3resource import Resource
import cs3.app.registry.v1beta1.registry_api_pb2 as cs3arreg
import cs3.app.registry.v1beta1.resources_pb2 as cs3arres
import cs3.gateway.v1beta1.gateway_api_pb2 as cs3gw
import cs3.app.provider.v1beta1.resources_pb2 as cs3apr
from cs3.gateway.v1beta1.gateway_api_pb2_grpc import GatewayAPIStub
from statuscodehandler import StatusCodeHandler
from config import Config

from cs3client.cs3resource import Resource
from cs3client.statuscodehandler import StatusCodeHandler
from cs3client.config import Config


class App:
Expand All @@ -28,7 +28,6 @@ def __init__(
config: Config,
log: logging.Logger,
gateway: GatewayAPIStub,
auth: Auth,
status_code_handler: StatusCodeHandler,
) -> None:
"""
Expand All @@ -37,20 +36,21 @@ def __init__(
:param config: Config object containing the configuration parameters.
:param log: Logger instance for logging.
:param gateway: GatewayAPIStub instance for interacting with CS3 Gateway.
:param auth: An instance of the auth class.
:param status_code_handler: An instance of the StatusCodeHandler class.
"""
self._status_code_handler: StatusCodeHandler = status_code_handler
self._gateway: GatewayAPIStub = gateway
self._log: logging.Logger = log
self._config: Config = config
self._auth: Auth = auth

def open_in_app(self, resource: Resource, view_mode: str = None, app: str = None) -> cs3apr.OpenInAppURL:
def open_in_app(
self, auth_token: tuple, resource: Resource, view_mode: str = None, app: str = None
) -> cs3apr.OpenInAppURL:
"""
Open a file in an app, given the resource, view mode (VIEW_MODE_VIEW_ONLY, VIEW_MODE_READ_ONLY,
VIEW_MODE_READ_WRITE, VIEW_MODE_PREVIEW), and app name.
:param auth_token: tuple in the form ('x-access-token', <token> (see auth.get_token/auth.check_token)
:param resource: Resource object containing the resource information.
:param view_mode: View mode of the app.
:param app: App name.
Expand All @@ -63,21 +63,22 @@ def open_in_app(self, resource: Resource, view_mode: str = None, app: str = None
if view_mode:
view_mode_type = cs3gw.OpenInAppRequest.ViewMode.Value(view_mode)
req = cs3gw.OpenInAppRequest(ref=resource.ref, view_mode=view_mode_type, app=app)
res = self._gateway.OpenInApp(request=req, metadata=[self._auth.get_token()])
res = self._gateway.OpenInApp(request=req, metadata=[auth_token])
self._status_code_handler.handle_errors(res.status, "open in app", f"{resource.get_file_ref_str()}")
self._log.debug(f'msg="Invoked OpenInApp" {resource.get_file_ref_str()} trace="{res.status.trace}"')
return res.OpenInAppURL

def list_app_providers(self) -> list[cs3arres.ProviderInfo]:
def list_app_providers(self, auth_token: dict) -> list[cs3arres.ProviderInfo]:
"""
list_app_providers lists all the app providers.
:param auth_token: tuple in the form ('x-access-token', <token> (see auth.get_token/auth.check_token)
:return: List of app providers.
:raises: AuthenticationException (Operation not permitted)
:raises: UnknownException (Unknown error)
"""
req = cs3arreg.ListAppProvidersRequest()
res = self._gateway.ListAppProviders(request=req, metadata=[self._auth.get_token()])
res = self._gateway.ListAppProviders(request=req, metadata=[auth_token])
self._status_code_handler.handle_errors(res.status, "list app providers")
self._log.debug(f'msg="Invoked ListAppProviders" res_count="{len(res.providers)}" trace="{res.status.trace}"')
return res.providers
45 changes: 17 additions & 28 deletions src/auth.py → cs3client/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Authors: Rasmus Welander, Diogo Castro, Giuseppe Lo Presti.
Emails: [email protected], [email protected], [email protected]
Last updated: 19/08/2024
Last updated: 28/08/2024
"""

import grpc
Expand All @@ -15,8 +15,8 @@
from cs3.gateway.v1beta1.gateway_api_pb2_grpc import GatewayAPIStub
from cs3.rpc.v1beta1.code_pb2 import CODE_OK

from exceptions.exceptions import AuthenticationException, SecretNotSetException
from config import Config
from cs3client.exceptions.exceptions import AuthenticationException, SecretNotSetException
from cs3client.config import Config


class Auth:
Expand All @@ -40,16 +40,6 @@ def __init__(self, config: Config, log: logging.Logger, gateway: GatewayAPIStub)
self._client_secret: str | None = None
self._token: str | None = None

def set_token(self, token: str) -> None:
"""
Should be used if the user wishes to set the reva token directly, instead of letting the client
exchange credentials for the token. NOTE that token OR the client secret has to be set when
instantiating the client object.
:param token: The reva token.
"""
self._token = token

def set_client_secret(self, token: str) -> None:
"""
Sets the client secret, exists so that the user can change the client secret (e.g. token, password) at runtime,
Expand All @@ -71,16 +61,13 @@ def get_token(self) -> tuple[str, str]:
:raises: SecretNotSetException (neither token or client secret was set)
"""

if not Auth._check_token(self._token):
# Check that client secret or token is set
if not self._client_secret and not self._token:
self._log.error("Attempted to authenticate, neither client secret or token was set.")
raise SecretNotSetException("The client secret (e.g. token, passowrd) is not set")
elif not self._client_secret and self._token:
# Case where ONLY a token is provided but it has expired
self._log.error("The provided token have expired")
raise AuthenticationException("The credentials have expired")
# Create an authentication request
try:
Auth.check_token(self._token)
except ValueError:
self._log.error("Attempted to authenticate, neither client secret or token was set.")
raise SecretNotSetException("The client secret (e.g. token, passowrd) is not set")
except AuthenticationException:
# Token has expired, obtain another one.
req = AuthenticateRequest(
type=self._config.auth_login_type,
client_id=self._config.auth_client_id,
Expand Down Expand Up @@ -116,20 +103,22 @@ def list_auth_providers(self) -> list[str]:
return res.types

@classmethod
def _check_token(cls, token: str) -> bool:
def check_token(cls, token: str) -> str:
"""
Checks if the given token is set and valid.
:param token: JWT token as a string.
:return: True if the token is valid, False otherwise.
:return tuple: A tuple containing the header key and the token.
:raises: ValueError (Token missing)
:raises: AuthenticationException (Token is expired)
"""
if not token:
return False
raise ValueError("A token is required")
# Decode the token without verifying the signature
decoded_token = jwt.decode(jwt=token, algorithms=["HS256"], options={"verify_signature": False})
now = datetime.datetime.now().timestamp()
token_expiration = decoded_token.get("exp")
if token_expiration and now > token_expiration:
return False
raise AuthenticationException("Token has expired")

return True
return ("x-access-token", token)
25 changes: 13 additions & 12 deletions src/checkpoint.py → cs3client/checkpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
Authors: Rasmus Welander, Diogo Castro, Giuseppe Lo Presti.
Emails: [email protected], [email protected], [email protected]
Last updated: 19/08/2024
Last updated: 28/08/2024
"""

from typing import Generator
import logging
from auth import Auth
import cs3.storage.provider.v1beta1.resources_pb2 as cs3spr
import cs3.storage.provider.v1beta1.provider_api_pb2 as cs3spp
from cs3.gateway.v1beta1.gateway_api_pb2_grpc import GatewayAPIStub
from config import Config
from statuscodehandler import StatusCodeHandler
from cs3resource import Resource

from cs3client.config import Config
from cs3client.statuscodehandler import StatusCodeHandler
from cs3client.cs3resource import Resource


class Checkpoint:
Expand All @@ -27,7 +27,6 @@ def __init__(
config: Config,
log: logging.Logger,
gateway: GatewayAPIStub,
auth: Auth,
status_code_handler: StatusCodeHandler,
) -> None:
"""
Expand All @@ -36,21 +35,20 @@ def __init__(
:param config: Config object containing the configuration parameters.
:param log: Logger instance for logging.
:param gateway: GatewayAPIStub instance for interacting with CS3 Gateway.
:param auth: An instance of the auth class.
:param status_code_handler: An instance of the StatusCodeHandler class.
"""
self._gateway: GatewayAPIStub = gateway
self._log: logging.Logger = log
self._config: Config = config
self._auth: Auth = auth
self._status_code_handler: StatusCodeHandler = status_code_handler

def list_file_versions(
self, resource: Resource, page_token: str = "", page_size: int = 0
self, auth_token: tuple, resource: Resource, page_token: str = "", page_size: int = 0
) -> Generator[cs3spr.FileVersion, any, any]:
"""
List all versions of a file.
:param auth_token: tuple in the form ('x-access-token', <token> (see auth.get_token/auth.check_token)
:param resource: Resource object containing the resource information.
:param page_token: Token for pagination.
:param page_size: Number of file versions to return.
Expand All @@ -61,15 +59,18 @@ def list_file_versions(
:raises: UnknownException (Unknown error)
"""
req = cs3spp.ListFileVersionsRequest(ref=resource.ref, page_token=page_token, page_size=page_size)
res = self._gateway.ListFileVersions(request=req, metadata=[self._auth.get_token()])
res = self._gateway.ListFileVersions(request=req, metadata=[auth_token])
self._status_code_handler.handle_errors(res.status, "list file versions", f"{resource.get_file_ref_str()}")
self._log.debug(f'msg="list file versions" {resource.get_file_ref_str()} trace="{res.status.trace}"')
return res.versions

def restore_file_version(self, resource: Resource, version_key: str, lock_id: str = None) -> None:
def restore_file_version(
self, auth_token: tuple, resource: Resource, version_key: str, lock_id: str = None
) -> None:
"""
Restore a file to a previous version.
:param auth_token: tuple in the form ('x-access-token', <token> (see auth.get_token/auth.check_token)
:param resource: Resource object containing the resource information.
:param version_key: Key of the version to restore.
:param lock_id: Lock ID of the file (OPTIONAL).
Expand All @@ -79,7 +80,7 @@ def restore_file_version(self, resource: Resource, version_key: str, lock_id: st
:raises: UnknownException (Unknown error)
"""
req = cs3spp.RestoreFileVersionRequest(ref=resource.ref, key=version_key, lock_id=lock_id)
res = self._gateway.RestoreFileVersion(request=req, metadata=[self._auth.get_token()])
res = self._gateway.RestoreFileVersion(request=req, metadata=[auth_token])
self._status_code_handler.handle_errors(res.status, "restore file version", f"{resource.get_file_ref_str()}")
self._log.debug(f'msg="restore file version" {resource.get_file_ref_str()} trace="{res.status.trace}"')
return
File renamed without changes.
30 changes: 15 additions & 15 deletions src/cs3client.py → cs3client/cs3client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@
Authors: Rasmus Welander, Diogo Castro, Giuseppe Lo Presti.
Emails: [email protected], [email protected], [email protected]
Last updated: 19/08/2024
Last updated: 28/08/2024
"""

import grpc
import logging
import cs3.gateway.v1beta1.gateway_api_pb2_grpc as cs3gw_grpc

from configparser import ConfigParser
from auth import Auth
from file import File
from user import User
from share import Share
from statuscodehandler import StatusCodeHandler
from app import App
from checkpoint import Checkpoint
from config import Config

from cs3client.auth import Auth
from cs3client.file import File
from cs3client.user import User
from cs3client.share import Share
from cs3client.statuscodehandler import StatusCodeHandler
from cs3client.app import App
from cs3client.checkpoint import Checkpoint
from cs3client.config import Config


class CS3Client:
Expand Down Expand Up @@ -47,13 +47,13 @@ def __init__(self, config: ConfigParser, config_category: str, log: logging.Logg
self._gateway: cs3gw_grpc.GatewayAPIStub = cs3gw_grpc.GatewayAPIStub(self.channel)
self._status_code_handler: StatusCodeHandler = StatusCodeHandler(self._log, self._config)
self.auth: Auth = Auth(self._config, self._log, self._gateway)
self.file: File = File(self._config, self._log, self._gateway, self.auth, self._status_code_handler)
self.user: User = User(self._config, self._log, self._gateway, self.auth, self._status_code_handler)
self.app: App = App(self._config, self._log, self._gateway, self.auth, self._status_code_handler)
self.file: File = File(self._config, self._log, self._gateway, self._status_code_handler)
self.user: User = User(self._config, self._log, self._gateway, self._status_code_handler)
self.app: App = App(self._config, self._log, self._gateway, self._status_code_handler)
self.checkpoint: Checkpoint = Checkpoint(
self._config, self._log, self._gateway, self.auth, self._status_code_handler
self._config, self._log, self._gateway, self._status_code_handler
)
self.share = Share(self._config, self._log, self._gateway, self.auth, self._status_code_handler)
self.share = Share(self._config, self._log, self._gateway, self._status_code_handler)

def _create_channel(self) -> grpc.Channel:
"""
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 50ac90b

Please sign in to comment.