diff --git a/server/lomas_server/admin_database/admin_database.py b/server/lomas_server/admin_database/admin_database.py index e3822ad1..0c983fe2 100644 --- a/server/lomas_server/admin_database/admin_database.py +++ b/server/lomas_server/admin_database/admin_database.py @@ -1,7 +1,7 @@ import argparse -import functools import time from abc import ABC, abstractmethod +from functools import wraps from typing import Callable, Dict, List from constants import MODEL_INPUT_TO_LIB @@ -28,7 +28,7 @@ def user_must_exist(func: Callable) -> Callable: # type: ignore before calling func. """ - @functools.wraps(func) + @wraps(func) def wrapper_decorator( self, *args: argparse.Namespace, **kwargs: Dict[str, str] ) -> None: @@ -60,14 +60,14 @@ def dataset_must_exist(func: Callable) -> Callable: # type: ignore before calling the wrapped function. """ - @functools.wraps(func) + @wraps(func) def wrapper_decorator( self, *args: argparse.Namespace, **kwargs: Dict[str, str] ) -> None: dataset_name = args[0] if not self.does_dataset_exist(dataset_name): raise InvalidQueryException( - f"Dataset {dataset_name} does not exists. " + f"Dataset {dataset_name} does not exist. " + "Please, verify the client object initialisation.", ) return func(self, *args, **kwargs) @@ -96,7 +96,7 @@ def user_must_have_access_to_dataset( to the dataset before calling the wrapped function. """ - @functools.wraps(func) + @wraps(func) def wrapper_decorator( self, *args: argparse.Namespace, **kwargs: Dict[str, str] ) -> None: diff --git a/server/lomas_server/admin_database/mongodb_database.py b/server/lomas_server/admin_database/mongodb_database.py index 34634867..0f8509f3 100644 --- a/server/lomas_server/admin_database/mongodb_database.py +++ b/server/lomas_server/admin_database/mongodb_database.py @@ -11,6 +11,7 @@ user_must_exist, user_must_have_access_to_dataset, ) +from utils.error_handler import InvalidQueryException class AdminMongoDatabase(AdminDatabase): @@ -134,6 +135,11 @@ def has_user_access_to_dataset( Returns: bool: True if the user has access, False otherwise. """ + if not self.does_dataset_exist(dataset_name): + raise InvalidQueryException( + f"Dataset {dataset_name} does not exist. " + + "Please, verify the client object initialisation.", + ) doc_count = self.db.users.count_documents( { "user_name": f"{user_name}", diff --git a/server/lomas_server/admin_database/yaml_database.py b/server/lomas_server/admin_database/yaml_database.py index a2cf84da..94cc12e6 100644 --- a/server/lomas_server/admin_database/yaml_database.py +++ b/server/lomas_server/admin_database/yaml_database.py @@ -9,7 +9,7 @@ user_must_exist, user_must_have_access_to_dataset, ) -from utils.error_handler import InternalServerException +from utils.error_handler import InternalServerException, InvalidQueryException class AdminYamlDatabase(AdminDatabase): @@ -142,6 +142,11 @@ def has_user_access_to_dataset( Returns: bool: True if the user has access, False otherwise. """ + if not self.does_dataset_exist(dataset_name): + raise InvalidQueryException( + f"Dataset {dataset_name} does not exist. " + + "Please, verify the client object initialisation.", + ) for user in self.database["users"]: if user["user_name"] == user_name: for dataset in user["datasets_list"]: diff --git a/server/lomas_server/routes_admin.py b/server/lomas_server/routes_admin.py index aa6a859c..345bdf0e 100644 --- a/server/lomas_server/routes_admin.py +++ b/server/lomas_server/routes_admin.py @@ -2,7 +2,11 @@ from fastapi.responses import JSONResponse, RedirectResponse, StreamingResponse from dp_queries.dummy_dataset import make_dummy_dataset -from utils.error_handler import KNOWN_EXCEPTIONS, InternalServerException +from utils.error_handler import ( + KNOWN_EXCEPTIONS, + InternalServerException, + UnauthorizedAccessException, +) from utils.example_inputs import ( example_get_admin_db_data, example_get_dummy_dataset, @@ -25,17 +29,19 @@ async def root(): # Get server state @router.get("/state", tags=["ADMIN_USER"]) async def get_state( + request: Request, user_name: str = Header(None), ) -> JSONResponse: """Returns the current state dict of this server instance. Args: + request (Request): Raw request object user_name (str, optional): The user name. Defaults to Header(None). Returns: JSONResponse: The state of the server instance. """ - from app import app # pylint: disable=C0415 + app = request.app return JSONResponse( content={ @@ -50,15 +56,16 @@ async def get_state( dependencies=[Depends(server_live)], tags=["ADMIN_USER"], ) -async def get_memory_usage() -> JSONResponse: +async def get_memory_usage(request: Request) -> JSONResponse: """Return the dataset store object memory usage Args: + request (Request): Raw request object user_name (str, optional): The user name. Defaults to Header(None). Returns: JSONResponse: with DatasetStore object memory usage """ - from app import app # pylint: disable=C0415 + app = request.app return JSONResponse( content={ @@ -74,8 +81,9 @@ async def get_memory_usage() -> JSONResponse: tags=["USER_METADATA"], ) def get_dataset_metadata( - _request: Request, + request: Request, query_json: GetDbData = Body(example_get_admin_db_data), + user_name: str = Header(None), ) -> JSONResponse: """ Retrieves metadata for a given dataset. @@ -95,11 +103,19 @@ def get_dataset_metadata( JSONResponse: The metadata dictionary for the specified dataset_name. """ - from app import app # pylint: disable=C0415 + app = request.app + + dataset_name = query_json.dataset_name + if not app.state.admin_database.has_user_access_to_dataset( + user_name, dataset_name + ): + raise UnauthorizedAccessException( + f"{user_name} does not have access to {dataset_name}.", + ) try: ds_metadata = app.state.admin_database.get_dataset_metadata( - query_json.dataset_name + dataset_name ) except KNOWN_EXCEPTIONS as e: @@ -117,8 +133,9 @@ def get_dataset_metadata( tags=["USER_DUMMY"], ) def get_dummy_dataset( - _request: Request, + request: Request, query_json: GetDummyDataset = Body(example_get_dummy_dataset), + user_name: str = Header(None), ) -> StreamingResponse: """ Generates and returns a dummy dataset. @@ -141,7 +158,15 @@ def get_dummy_dataset( Returns: StreamingResponse: a pd.DataFrame representing the dummy dataset. """ - from app import app # pylint: disable=C0415 + app = request.app + + dataset_name = query_json.dataset_name + if not app.state.admin_database.has_user_access_to_dataset( + user_name, dataset_name + ): + raise UnauthorizedAccessException( + f"{user_name} does not have access to {dataset_name}.", + ) try: ds_metadata = app.state.admin_database.get_dataset_metadata( @@ -166,7 +191,7 @@ def get_dummy_dataset( tags=["USER_BUDGET"], ) def get_initial_budget( - _request: Request, + request: Request, query_json: GetDbData = Body(example_get_admin_db_data), user_name: str = Header(None), ) -> JSONResponse: @@ -195,7 +220,7 @@ def get_initial_budget( - initial_epsilon (float): initial epsilon budget. - initial_delta (float): initial delta budget. """ - from app import app # pylint: disable=C0415 + app = request.app try: ( @@ -224,7 +249,7 @@ def get_initial_budget( tags=["USER_BUDGET"], ) def get_total_spent_budget( - _request: Request, + request: Request, query_json: GetDbData = Body(example_get_admin_db_data), user_name: str = Header(None), ) -> JSONResponse: @@ -253,7 +278,7 @@ def get_total_spent_budget( - total_spent_epsilon (float): total spent epsilon budget. - total_spent_delta (float): total spent delta budget. """ - from app import app # pylint: disable=C0415 + app = request.app try: ( @@ -282,7 +307,7 @@ def get_total_spent_budget( tags=["USER_BUDGET"], ) def get_remaining_budget( - _request: Request, + request: Request, query_json: GetDbData = Body(example_get_admin_db_data), user_name: str = Header(None), ) -> JSONResponse: @@ -311,7 +336,7 @@ def get_remaining_budget( - remaining_epsilon (float): remaining epsilon budget. - remaining_delta (float): remaining delta budget. """ - from app import app # pylint: disable=C0415 + app = request.app try: rem_epsilon, rem_delta = app.state.admin_database.get_remaining_budget( @@ -337,7 +362,7 @@ def get_remaining_budget( tags=["USER_BUDGET"], ) def get_user_previous_queries( - _request: Request, + request: Request, query_json: GetDbData = Body(example_get_admin_db_data), user_name: str = Header(None), ) -> JSONResponse: @@ -367,7 +392,7 @@ def get_user_previous_queries( - previous_queries (list[dict]): a list of dictionaries containing the previous queries. """ - from app import app # pylint: disable=C0415 + app = request.app try: previous_queries = app.state.admin_database.get_user_previous_queries( diff --git a/server/lomas_server/routes_dp.py b/server/lomas_server/routes_dp.py index 8687845b..68e59b2a 100644 --- a/server/lomas_server/routes_dp.py +++ b/server/lomas_server/routes_dp.py @@ -4,7 +4,11 @@ from constants import DPLibraries from dp_queries.dp_libraries.utils import querier_factory from dp_queries.dummy_dataset import get_dummy_dataset_for_query -from utils.error_handler import KNOWN_EXCEPTIONS, InternalServerException +from utils.error_handler import ( + KNOWN_EXCEPTIONS, + InternalServerException, + UnauthorizedAccessException, +) from utils.example_inputs import ( example_diffprivlib, example_dummy_diffprivlib, @@ -34,7 +38,7 @@ tags=["USER_QUERY"], ) def smartnoise_sql_handler( - _request: Request, + request: Request, query_json: SNSQLInp = Body(example_smartnoise_sql), user_name: str = Header(None), ) -> JSONResponse: @@ -80,7 +84,7 @@ def smartnoise_sql_handler( - spent_delta (float): The amount of delta budget spent for the query. """ - from app import app # pylint: disable=C0415 + app = request.app try: response = app.state.query_handler.handle_query( @@ -101,8 +105,9 @@ def smartnoise_sql_handler( tags=["USER_DUMMY"], ) def dummy_smartnoise_sql_handler( - _request: Request, + request: Request, query_json: DummySNSQLInp = Body(example_dummy_smartnoise_sql), + user_name: str = Header(None), ) -> JSONResponse: """ Handles queries on dummy datasets for the SmartNoiseSQL library. @@ -142,7 +147,15 @@ def dummy_smartnoise_sql_handler( - query_response (pd.DataFrame): a DataFrame containing the query response. """ - from app import app # pylint: disable=C0415 + app = request.app + + dataset_name = query_json.dataset_name + if not app.state.admin_database.has_user_access_to_dataset( + user_name, dataset_name + ): + raise UnauthorizedAccessException( + f"{user_name} does not have access to {dataset_name}.", + ) ds_private_dataset = get_dummy_dataset_for_query( app.state.admin_database, query_json @@ -168,8 +181,9 @@ def dummy_smartnoise_sql_handler( tags=["USER_QUERY"], ) def estimate_smartnoise_cost( - _request: Request, + request: Request, query_json: SNSQLInpCost = Body(example_smartnoise_sql_cost), + user_name: str = Header(None), ) -> JSONResponse: """ Estimates the privacy loss budget cost of a SmartNoiseSQL query. @@ -200,7 +214,15 @@ def estimate_smartnoise_cost( - epsilon_cost (float): The estimated epsilon cost. - delta_cost (float): The estimated delta cost. """ - from app import app # pylint: disable=C0415 + app = request.app + + dataset_name = query_json.dataset_name + if not app.state.admin_database.has_user_access_to_dataset( + user_name, dataset_name + ): + raise UnauthorizedAccessException( + f"{user_name} does not have access to {dataset_name}.", + ) try: response = app.state.query_handler.estimate_cost( @@ -219,7 +241,7 @@ def estimate_smartnoise_cost( "/opendp_query", dependencies=[Depends(server_live)], tags=["USER_QUERY"] ) def opendp_query_handler( - _request: Request, + request: Request, query_json: OpenDPInp = Body(example_opendp), user_name: str = Header(None), ) -> JSONResponse: @@ -261,7 +283,7 @@ def opendp_query_handler( - spent_delta (float): The amount of delta budget spent for the query. """ - from app import app # pylint: disable=C0415 + app = request.app try: response = app.state.query_handler.handle_query( @@ -281,8 +303,9 @@ def opendp_query_handler( tags=["USER_DUMMY"], ) def dummy_opendp_query_handler( - _request: Request, + request: Request, query_json: DummyOpenDPInp = Body(example_dummy_opendp), + user_name: str = Header(None), ) -> JSONResponse: """ Handles queries on dummy datasets for the OpenDP library. @@ -319,7 +342,15 @@ def dummy_opendp_query_handler( - query_response (pd.DataFrame): a DataFrame containing the query response. """ - from app import app # pylint: disable=C0415 + app = request.app + + dataset_name = query_json.dataset_name + if not app.state.admin_database.has_user_access_to_dataset( + user_name, dataset_name + ): + raise UnauthorizedAccessException( + f"{user_name} does not have access to {dataset_name}.", + ) ds_private_dataset = get_dummy_dataset_for_query( app.state.admin_database, query_json @@ -347,8 +378,9 @@ def dummy_opendp_query_handler( tags=["USER_QUERY"], ) def estimate_opendp_cost( - _request: Request, + request: Request, query_json: OpenDPInp = Body(example_opendp), + user_name: str = Header(None), ) -> JSONResponse: """ Estimates the privacy loss budget cost of an OpenDP query. @@ -373,7 +405,15 @@ def estimate_opendp_cost( - epsilon_cost (float): The estimated epsilon cost. - delta_cost (float): The estimated delta cost. """ - from app import app # pylint: disable=C0415 + app = request.app + + dataset_name = query_json.dataset_name + if not app.state.admin_database.has_user_access_to_dataset( + user_name, dataset_name + ): + raise UnauthorizedAccessException( + f"{user_name} does not have access to {dataset_name}.", + ) try: response = app.state.query_handler.estimate_cost( @@ -394,6 +434,7 @@ def estimate_opendp_cost( tags=["USER_QUERY"], ) def diffprivlib_query_handler( + request: Request, query_json: DiffPrivLibInp = Body(example_diffprivlib), user_name: str = Header(None), ): @@ -434,7 +475,7 @@ def diffprivlib_query_handler( - spent_delta (float): The amount of delta budget spent for the query. """ - from app import app # pylint: disable=C0415 + app = request.app try: response = app.state.query_handler.handle_query( @@ -454,7 +495,9 @@ def diffprivlib_query_handler( tags=["USER_DUMMY"], ) def dummy_diffprivlib_query_handler( + request: Request, query_json: DummyDiffPrivLibInp = Body(example_dummy_diffprivlib), + user_name: str = Header(None), ): """ Handles queries on dummy datasets for the DiffPrivLib library. @@ -486,7 +529,15 @@ def dummy_diffprivlib_query_handler( - query_response (pd.DataFrame): a DataFrame containing the query response. """ - from app import app # pylint: disable=C0415 + app = request.app + + dataset_name = query_json.dataset_name + if not app.state.admin_database.has_user_access_to_dataset( + user_name, dataset_name + ): + raise UnauthorizedAccessException( + f"{user_name} does not have access to {dataset_name}.", + ) ds_private_dataset = get_dummy_dataset_for_query( app.state.admin_database, query_json @@ -512,7 +563,9 @@ def dummy_diffprivlib_query_handler( tags=["USER_QUERY"], ) def estimate_diffprivlib_cost( + request: Request, query_json: DiffPrivLibInp = Body(example_diffprivlib), + user_name: str = Header(None), ): """ Estimates the privacy loss budget cost of an DiffPrivLib query. @@ -542,7 +595,15 @@ def estimate_diffprivlib_cost( - epsilon_cost (float): The estimated epsilon cost. - delta_cost (float): The estimated delta cost. """ - from app import app # pylint: disable=C0415 + app = request.app + + dataset_name = query_json.dataset_name + if not app.state.admin_database.has_user_access_to_dataset( + user_name, dataset_name + ): + raise UnauthorizedAccessException( + f"{user_name} does not have access to {dataset_name}.", + ) try: response = app.state.query_handler.estimate_cost( diff --git a/server/lomas_server/tests/test_api.py b/server/lomas_server/tests/test_api.py index f603c690..fec7db85 100644 --- a/server/lomas_server/tests/test_api.py +++ b/server/lomas_server/tests/test_api.py @@ -209,7 +209,20 @@ def test_get_dataset_metadata(self) -> None: assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json() == { "InvalidQueryException": f"Dataset {fake_dataset} does not " - + "exists. Please, verify the client object initialisation." + + "exist. Please, verify the client object initialisation." + } + + # Expect to fail: user does have access to dataset + other_dataset = "IRIS" + response = client.post( + "/get_dataset_metadata", + json={"dataset_name": other_dataset}, + headers=self.headers, + ) + assert response.status_code == status.HTTP_403_FORBIDDEN + assert response.json() == { + "UnauthorizedAccessException": "" + + f"{self.user_name} does not have access to {other_dataset}." } def test_get_dummy_dataset(self) -> None: @@ -217,7 +230,9 @@ def test_get_dummy_dataset(self) -> None: with TestClient(app) as client: # Expect to work response = client.post( - "/get_dummy_dataset", json=example_get_dummy_dataset + "/get_dummy_dataset", + json=example_get_dummy_dataset, + headers=self.headers, ) assert response.status_code == status.HTTP_200_OK @@ -244,7 +259,7 @@ def test_get_dummy_dataset(self) -> None: assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json() == { "InvalidQueryException": f"Dataset {fake_dataset} does not " - + "exists. Please, verify the client object initialisation." + + "exist. Please, verify the client object initialisation." } # Expect to fail: missing argument dummy_nb_rows @@ -257,6 +272,38 @@ def test_get_dummy_dataset(self) -> None: ) assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY + # Expect to fail: user does have access to dataset + other_dataset = "IRIS" + response = client.post( + "/get_dummy_dataset", + json={ + "dataset_name": other_dataset, + "dummy_nb_rows": DUMMY_NB_ROWS, + "dummy_seed": 0, + }, + headers=self.headers, + ) + assert response.status_code == status.HTTP_403_FORBIDDEN + assert response.json() == { + "UnauthorizedAccessException": "" + + f"{self.user_name} does not have access to {other_dataset}." + } + + # Expect to fail: user does not exist + fake_user = "fake_user" + new_headers = self.headers + new_headers["user-name"] = fake_user + response = client.post( + "/get_dummy_dataset", + json=example_get_dummy_dataset, + headers=new_headers, + ) + assert response.status_code == status.HTTP_403_FORBIDDEN + assert response.json() == { + "UnauthorizedAccessException": f"User {fake_user} does not " + + "exist. Please, verify the client object initialisation." + } + def test_smartnoise_query(self) -> None: """Test smartnoise-sql query""" with TestClient(app, headers=self.headers) as client: @@ -356,7 +403,7 @@ def test_smartnoise_query(self) -> None: assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json() == { "InvalidQueryException": "" - + "Dataset I_do_not_exist does not exists. " + + "Dataset I_do_not_exist does not exist. " + "Please, verify the client object initialisation." } @@ -402,7 +449,9 @@ def test_dummy_smartnoise_query(self) -> None: with TestClient(app) as client: # Expect to work response = client.post( - "/dummy_smartnoise_query", json=example_dummy_smartnoise_sql + "/dummy_smartnoise_query", + json=example_dummy_smartnoise_sql, + headers=self.headers, ) assert response.status_code == status.HTTP_200_OK @@ -411,12 +460,38 @@ def test_dummy_smartnoise_query(self) -> None: assert response_dict["query_response"]["data"][0][0] > 0 assert response_dict["query_response"]["data"][0][0] < 200 + # Should fail: no header + response = client.post( + "/dummy_smartnoise_query", json=example_dummy_smartnoise_sql + ) + assert response.status_code == status.HTTP_403_FORBIDDEN + assert response.json() == { + "UnauthorizedAccessException": "User None does not exist." + + " Please, verify the client object initialisation." + } + + # Should fail: user does not have access to dataset + body = dict(example_dummy_smartnoise_sql) + body["dataset_name"] = "IRIS" + response = client.post( + "/dummy_smartnoise_query", + json=body, + headers=self.headers, + ) + assert response.status_code == status.HTTP_403_FORBIDDEN + assert response.json() == { + "UnauthorizedAccessException": "" + + f"{self.user_name} does not have access to IRIS." + } + def test_smartnoise_cost(self) -> None: """test_smartnoise_cost""" with TestClient(app) as client: # Expect to work response = client.post( - "/estimate_smartnoise_cost", json=example_smartnoise_sql_cost + "/estimate_smartnoise_cost", + json=example_smartnoise_sql_cost, + headers=self.headers, ) assert response.status_code == status.HTTP_200_OK @@ -424,6 +499,20 @@ def test_smartnoise_cost(self) -> None: assert response_dict["epsilon_cost"] == SMARTNOISE_QUERY_EPSILON assert response_dict["delta_cost"] > SMARTNOISE_QUERY_DELTA + # Should fail: user does not have access to dataset + body = dict(example_smartnoise_sql_cost) + body["dataset_name"] = "IRIS" + response = client.post( + "/estimate_smartnoise_cost", + json=body, + headers=self.headers, + ) + assert response.status_code == status.HTTP_403_FORBIDDEN + assert response.json() == { + "UnauthorizedAccessException": "" + + f"{self.user_name} does not have access to IRIS." + } + def test_opendp_query(self) -> None: # pylint: disable=R0915 """test_opendp_query""" enable_logging() @@ -573,18 +662,36 @@ def test_dummy_opendp_query(self) -> None: with TestClient(app) as client: # Expect to work response = client.post( - "/dummy_opendp_query", json=example_dummy_opendp + "/dummy_opendp_query", + json=example_dummy_opendp, + headers=self.headers, ) assert response.status_code == status.HTTP_200_OK response_dict = json.loads(response.content.decode("utf8")) assert response_dict["query_response"] > 0 + # Should fail: user does not have access to dataset + body = dict(example_dummy_opendp) + body["dataset_name"] = "IRIS" + response = client.post( + "/dummy_opendp_query", + json=body, + headers=self.headers, + ) + assert response.status_code == status.HTTP_403_FORBIDDEN + assert response.json() == { + "UnauthorizedAccessException": "" + + f"{self.user_name} does not have access to IRIS." + } + def test_opendp_cost(self) -> None: """test_opendp_cost""" with TestClient(app) as client: # Expect to work response = client.post( - "/estimate_opendp_cost", json=example_opendp + "/estimate_opendp_cost", + json=example_opendp, + headers=self.headers, ) assert response.status_code == status.HTTP_200_OK @@ -592,6 +699,20 @@ def test_opendp_cost(self) -> None: assert response_dict["epsilon_cost"] > 0.1 assert response_dict["delta_cost"] == 0 + # Should fail: user does not have access to dataset + body = dict(example_opendp) + body["dataset_name"] = "IRIS" + response = client.post( + "/estimate_opendp_cost", + json=body, + headers=self.headers, + ) + assert response.status_code == status.HTTP_403_FORBIDDEN + assert response.json() == { + "UnauthorizedAccessException": "" + + f"{self.user_name} does not have access to IRIS." + } + def test_get_initial_budget(self) -> None: """test_get_initial_budget""" with TestClient(app, headers=self.headers) as client: diff --git a/server/lomas_server/tests/test_api_diffprivlib.py b/server/lomas_server/tests/test_api_diffprivlib.py index 079a4890..94db1846 100644 --- a/server/lomas_server/tests/test_api_diffprivlib.py +++ b/server/lomas_server/tests/test_api_diffprivlib.py @@ -324,7 +324,9 @@ def test_dummy_diffprivlib_query(self) -> None: with TestClient(app) as client: # Expect to work response = client.post( - "/dummy_diffprivlib_query", json=example_dummy_diffprivlib + "/dummy_diffprivlib_query", + json=example_dummy_diffprivlib, + headers=self.headers, ) assert response.status_code == status.HTTP_200_OK @@ -332,15 +334,45 @@ def test_dummy_diffprivlib_query(self) -> None: assert response_dict["query_response"]["score"] > 0 assert response_dict["query_response"]["model"] + # Expect to fail: user does have access to dataset + body = dict(example_dummy_diffprivlib) + body["dataset_name"] = "IRIS" + response = client.post( + "/dummy_diffprivlib_query", + json=body, + headers=self.headers, + ) + assert response.status_code == status.HTTP_403_FORBIDDEN + assert response.json() == { + "UnauthorizedAccessException": "" + + f"{self.user_name} does not have access to IRIS." + } + def test_diffprivlib_cost(self) -> None: """test_diffprivlib_cost""" with TestClient(app) as client: # Expect to work response = client.post( - "/estimate_diffprivlib_cost", json=example_diffprivlib + "/estimate_diffprivlib_cost", + json=example_diffprivlib, + headers=self.headers, ) assert response.status_code == status.HTTP_200_OK response_dict = json.loads(response.content.decode("utf8")) assert response_dict["epsilon_cost"] == 1.5 assert response_dict["delta_cost"] == 0 + + # Expect to fail: user does have access to dataset + body = dict(example_diffprivlib) + body["dataset_name"] = "IRIS" + response = client.post( + "/estimate_diffprivlib_cost", + json=body, + headers=self.headers, + ) + assert response.status_code == status.HTTP_403_FORBIDDEN + assert response.json() == { + "UnauthorizedAccessException": "" + + f"{self.user_name} does not have access to IRIS." + } diff --git a/server/requirements.txt b/server/requirements.txt index 626d87f5..963b18c0 100644 --- a/server/requirements.txt +++ b/server/requirements.txt @@ -11,4 +11,4 @@ pyaml==23.9.5 pymongo==4.6.3 scikit-learn==1.4.0 smartnoise-sql==1.0.3 -uvicorn==0.29.0 +uvicorn==0.29.0 \ No newline at end of file