Skip to content

Commit db5eb1f

Browse files
🐛 Ensure function execute permission check is performed only once in map endpoint (ITISFoundation#8499)
1 parent aadb582 commit db5eb1f

File tree

3 files changed

+48
-33
lines changed

3 files changed

+48
-33
lines changed

services/api-server/src/simcore_service_api_server/_service_function_jobs_task_client.py

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
TaskID,
2121
)
2222
from models_library.functions_errors import (
23-
FunctionExecuteAccessDeniedError,
24-
FunctionsExecuteApiAccessDeniedError,
2523
UnsupportedFunctionClassError,
2624
UnsupportedFunctionFunctionJobClassCombinationError,
2725
)
@@ -245,36 +243,7 @@ async def get_cached_function_job(
245243
function: RegisteredFunction,
246244
job_inputs: JobInputs,
247245
) -> RegisteredFunctionJob:
248-
"""
249-
N.B. this function checks access rights
250-
251-
raises FunctionsExecuteApiAccessDeniedError if user cannot execute functions
252-
raises FunctionJobCacheNotFoundError if no cached job is found
253-
254-
"""
255-
256-
user_api_access_rights = (
257-
await self._web_rpc_client.get_functions_user_api_access_rights(
258-
user_id=self.user_id, product_name=self.product_name
259-
)
260-
)
261-
if not user_api_access_rights.execute_functions:
262-
raise FunctionsExecuteApiAccessDeniedError(
263-
user_id=self.user_id,
264-
function_id=function.uid,
265-
)
266-
267-
user_permissions = await self._web_rpc_client.get_function_user_permissions(
268-
function_id=function.uid,
269-
user_id=self.user_id,
270-
product_name=self.product_name,
271-
)
272-
if not user_permissions.execute:
273-
raise FunctionExecuteAccessDeniedError(
274-
user_id=self.user_id,
275-
function_id=function.uid,
276-
)
277-
246+
"""Raises FunctionJobCacheNotFoundError if no cached job is found"""
278247
if cached_function_jobs := await self._web_rpc_client.find_cached_function_jobs(
279248
function_id=function.uid,
280249
inputs=job_inputs.values,

services/api-server/src/simcore_service_api_server/_service_functions.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55

66
from common_library.exclude import as_dict_exclude_none
77
from models_library.functions import FunctionClass, FunctionID, RegisteredFunction
8-
from models_library.functions_errors import UnsupportedFunctionClassError
8+
from models_library.functions_errors import (
9+
FunctionExecuteAccessDeniedError,
10+
FunctionsExecuteApiAccessDeniedError,
11+
UnsupportedFunctionClassError,
12+
)
913
from models_library.products import ProductName
1014
from models_library.rest_pagination import (
1115
MAXIMUM_NUMBER_OF_ITEMS_PER_PAGE,
@@ -76,3 +80,37 @@ async def get_function(self, function_id: FunctionID) -> RegisteredFunction:
7680
product_name=self.product_name,
7781
function_id=function_id,
7882
)
83+
84+
async def check_execute_function_permission(
85+
self,
86+
*,
87+
function: RegisteredFunction,
88+
) -> None:
89+
"""
90+
Check execute permissions for a user on a function
91+
92+
raises FunctionsExecuteApiAccessDeniedError if user cannot execute functions via the functions API
93+
raises FunctionExecuteAccessDeniedError if user cannot execute this functions
94+
"""
95+
96+
user_api_access_rights = (
97+
await self._web_rpc_client.get_functions_user_api_access_rights(
98+
user_id=self.user_id, product_name=self.product_name
99+
)
100+
)
101+
if not user_api_access_rights.execute_functions:
102+
raise FunctionsExecuteApiAccessDeniedError(
103+
user_id=self.user_id,
104+
function_id=function.uid,
105+
)
106+
107+
user_permissions = await self._web_rpc_client.get_function_user_permissions(
108+
function_id=function.uid,
109+
user_id=self.user_id,
110+
product_name=self.product_name,
111+
)
112+
if not user_permissions.execute:
113+
raise FunctionExecuteAccessDeniedError(
114+
user_id=self.user_id,
115+
function_id=function.uid,
116+
)

services/api-server/src/simcore_service_api_server/api/routes/functions_routes.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,10 @@ async def run_function(
343343
else None
344344
)
345345
pricing_spec = JobPricingSpecification.create_from_headers(request.headers)
346+
347+
await function_service.check_execute_function_permission(
348+
function=to_run_function,
349+
)
346350
job_links = await function_service.get_function_job_links(to_run_function, url_for)
347351

348352
return await function_job_task_client_service.create_function_job_creation_task(
@@ -418,6 +422,10 @@ async def map_function(
418422
else None
419423
)
420424
pricing_spec = JobPricingSpecification.create_from_headers(request.headers)
425+
426+
await function_service.check_execute_function_permission(
427+
function=to_run_function,
428+
)
421429
job_links = await function_service.get_function_job_links(to_run_function, url_for)
422430

423431
async def _run_single_function(function_inputs: FunctionInputs) -> FunctionJobID:

0 commit comments

Comments
 (0)