зеркало из https://github.com/microsoft/AzureTRE.git
Airlock manager can use user resources (#2649)
Co-authored-by: JaimieWi <92854957+JaimieWi@users.noreply.github.com>
This commit is contained in:
Родитель
9dc7b55810
Коммит
5067730259
|
@ -209,3 +209,4 @@ pytest_api_unit_failed
|
|||
validation.txt
|
||||
|
||||
/index.html
|
||||
.DS_Store
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = "0.4.40"
|
||||
__version__ = "0.4.41"
|
||||
|
|
|
@ -24,7 +24,10 @@ from models.schemas.resource_template import ResourceTemplateInformationInList
|
|||
from resources import strings
|
||||
from services.access_service import AuthConfigValidationError
|
||||
from services.authentication import get_current_admin_user, \
|
||||
get_access_service, get_current_workspace_owner_user, get_current_workspace_owner_or_researcher_user, get_current_tre_user_or_tre_admin, get_current_workspace_owner_or_researcher_user_or_tre_admin, get_current_workspace_owner_or_tre_admin
|
||||
get_access_service, get_current_workspace_owner_user, get_current_workspace_owner_or_researcher_user, get_current_tre_user_or_tre_admin, \
|
||||
get_current_workspace_owner_or_tre_admin, \
|
||||
get_current_workspace_owner_or_researcher_user_or_airlock_manager, \
|
||||
get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin
|
||||
from services.authentication import extract_auth_information
|
||||
from services.azure_resource_status import get_azure_resource_status
|
||||
from azure.cosmos.exceptions import CosmosAccessConditionFailedError
|
||||
|
@ -33,13 +36,13 @@ from .resource_helpers import get_identity_role_assignments, save_and_deploy_res
|
|||
from models.domain.request_action import RequestAction
|
||||
|
||||
workspaces_core_router = APIRouter(dependencies=[Depends(get_current_tre_user_or_tre_admin)])
|
||||
workspaces_shared_router = APIRouter(dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_tre_admin)])
|
||||
workspace_services_workspace_router = APIRouter(dependencies=[Depends(get_current_workspace_owner_or_researcher_user)])
|
||||
user_resources_workspace_router = APIRouter(dependencies=[Depends(get_current_workspace_owner_or_researcher_user)])
|
||||
workspaces_shared_router = APIRouter(dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin)])
|
||||
workspace_services_workspace_router = APIRouter(dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager)])
|
||||
user_resources_workspace_router = APIRouter(dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager)])
|
||||
|
||||
|
||||
def validate_user_is_workspace_owner_or_resource_owner(user, user_resource):
|
||||
if "WorkspaceOwner" in user.roles:
|
||||
def validate_user_has_valid_role_for_user_resource(user, user_resource):
|
||||
if "WorkspaceOwner" in user.roles or "AirlockManager" in user.roles:
|
||||
return
|
||||
|
||||
if "WorkspaceResearcher" in user.roles and user_resource.ownerId == user.id:
|
||||
|
@ -170,14 +173,21 @@ async def invoke_action_on_workspace(response: Response, action: str, user=Depen
|
|||
# workspace operations
|
||||
# This method only returns templates that the authenticated user is authorized to use
|
||||
@workspaces_shared_router.get("/workspace/{workspace_id}/workspace-service-templates", response_model=ResourceTemplateInformationInList, name=strings.API_GET_WORKSPACE_SERVICE_TEMPLATES_IN_WORKSPACE)
|
||||
async def get_workspace_service_templates(workspace=Depends(get_workspace_by_id_from_path), template_repo=Depends(get_repository(ResourceTemplateRepository)), user=Depends(get_current_workspace_owner_or_researcher_user_or_tre_admin)) -> ResourceTemplateInformationInList:
|
||||
async def get_workspace_service_templates(
|
||||
workspace=Depends(get_workspace_by_id_from_path),
|
||||
template_repo=Depends(get_repository(ResourceTemplateRepository)),
|
||||
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin)) -> ResourceTemplateInformationInList:
|
||||
template_infos = template_repo.get_templates_information(ResourceType.WorkspaceService, user.roles)
|
||||
return ResourceTemplateInformationInList(templates=template_infos)
|
||||
|
||||
|
||||
# This method only returns templates that the authenticated user is authorized to use
|
||||
@workspaces_shared_router.get("/workspace/{workspace_id}/workspace-service-templates/{service_template_name}/user-resource-templates", response_model=ResourceTemplateInformationInList, name=strings.API_GET_USER_RESOURCE_TEMPLATES_IN_WORKSPACE)
|
||||
async def get_user_resource_templates(service_template_name: str, workspace=Depends(get_workspace_by_id_from_path), template_repo=Depends(get_repository(ResourceTemplateRepository)), user=Depends(get_current_workspace_owner_or_researcher_user_or_tre_admin)) -> ResourceTemplateInformationInList:
|
||||
async def get_user_resource_templates(
|
||||
service_template_name: str,
|
||||
workspace=Depends(get_workspace_by_id_from_path),
|
||||
template_repo=Depends(get_repository(ResourceTemplateRepository)),
|
||||
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin)) -> ResourceTemplateInformationInList:
|
||||
template_infos = template_repo.get_templates_information(ResourceType.UserResource, user.roles, service_template_name)
|
||||
return ResourceTemplateInformationInList(templates=template_infos)
|
||||
|
||||
|
@ -193,13 +203,13 @@ async def retrieve_workspace_operation_by_workspace_id_and_operation_id(workspac
|
|||
|
||||
|
||||
# WORKSPACE SERVICES ROUTES
|
||||
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services", response_model=WorkspaceServicesInList, name=strings.API_GET_ALL_WORKSPACE_SERVICES, dependencies=[Depends(get_current_workspace_owner_or_researcher_user)])
|
||||
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services", response_model=WorkspaceServicesInList, name=strings.API_GET_ALL_WORKSPACE_SERVICES, dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager)])
|
||||
async def retrieve_users_active_workspace_services(workspace=Depends(get_workspace_by_id_from_path), workspace_services_repo=Depends(get_repository(WorkspaceServiceRepository))) -> WorkspaceServicesInList:
|
||||
workspace_services = workspace_services_repo.get_active_workspace_services_for_workspace(workspace.id)
|
||||
return WorkspaceServicesInList(workspaceServices=workspace_services)
|
||||
|
||||
|
||||
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}", response_model=WorkspaceServiceInResponse, name=strings.API_GET_WORKSPACE_SERVICE_BY_ID, dependencies=[Depends(get_current_workspace_owner_or_researcher_user), Depends(get_workspace_by_id_from_path)])
|
||||
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}", response_model=WorkspaceServiceInResponse, name=strings.API_GET_WORKSPACE_SERVICE_BY_ID, dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager), Depends(get_workspace_by_id_from_path)])
|
||||
async def retrieve_workspace_service_by_id(workspace_service=Depends(get_workspace_service_by_id_from_path)) -> WorkspaceServiceInResponse:
|
||||
return WorkspaceServiceInResponse(workspaceService=workspace_service)
|
||||
|
||||
|
@ -290,19 +300,23 @@ async def invoke_action_on_workspace_service(response: Response, action: str, us
|
|||
|
||||
|
||||
# workspace service operations
|
||||
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/operations", response_model=OperationInList, name=strings.API_GET_RESOURCE_OPERATIONS, dependencies=[Depends(get_current_workspace_owner_or_researcher_user), Depends(get_workspace_by_id_from_path)])
|
||||
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/operations", response_model=OperationInList, name=strings.API_GET_RESOURCE_OPERATIONS, dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager), Depends(get_workspace_by_id_from_path)])
|
||||
async def retrieve_workspace_service_operations_by_workspace_service_id(workspace_service=Depends(get_workspace_service_by_id_from_path), operations_repo=Depends(get_repository(OperationRepository))) -> OperationInList:
|
||||
return OperationInList(operations=operations_repo.get_operations_by_resource_id(resource_id=workspace_service.id))
|
||||
|
||||
|
||||
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/operations/{operation_id}", response_model=OperationInResponse, name=strings.API_GET_RESOURCE_OPERATION_BY_ID, dependencies=[Depends(get_current_workspace_owner_or_researcher_user), Depends(get_workspace_by_id_from_path)])
|
||||
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/operations/{operation_id}", response_model=OperationInResponse, name=strings.API_GET_RESOURCE_OPERATION_BY_ID, dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager), Depends(get_workspace_by_id_from_path)])
|
||||
async def retrieve_workspace_service_operation_by_workspace_service_id_and_operation_id(workspace_service=Depends(get_workspace_service_by_id_from_path), operation=Depends(get_operation_by_id_from_path)) -> OperationInList:
|
||||
return OperationInResponse(operation=operation)
|
||||
|
||||
|
||||
# USER RESOURCE ROUTES
|
||||
@user_resources_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources", response_model=UserResourcesInList, name=strings.API_GET_MY_USER_RESOURCES, dependencies=[Depends(get_workspace_by_id_from_path)])
|
||||
async def retrieve_user_resources_for_workspace_service(workspace_id: str, service_id: str, user=Depends(get_current_workspace_owner_or_researcher_user), user_resource_repo=Depends(get_repository(UserResourceRepository))) -> UserResourcesInList:
|
||||
async def retrieve_user_resources_for_workspace_service(
|
||||
workspace_id: str,
|
||||
service_id: str,
|
||||
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager),
|
||||
user_resource_repo=Depends(get_repository(UserResourceRepository))) -> UserResourcesInList:
|
||||
user_resources = user_resource_repo.get_user_resources_for_workspace_service(workspace_id, service_id)
|
||||
|
||||
# filter only to the user - for researchers
|
||||
|
@ -317,8 +331,10 @@ async def retrieve_user_resources_for_workspace_service(workspace_id: str, servi
|
|||
|
||||
|
||||
@user_resources_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}", response_model=UserResourceInResponse, name=strings.API_GET_USER_RESOURCE, dependencies=[Depends(get_workspace_by_id_from_path)])
|
||||
async def retrieve_user_resource_by_id(user_resource=Depends(get_user_resource_by_id_from_path), user=Depends(get_current_workspace_owner_or_researcher_user)) -> UserResourceInResponse:
|
||||
validate_user_is_workspace_owner_or_resource_owner(user, user_resource)
|
||||
async def retrieve_user_resource_by_id(
|
||||
user_resource=Depends(get_user_resource_by_id_from_path),
|
||||
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager)) -> UserResourceInResponse:
|
||||
validate_user_has_valid_role_for_user_resource(user, user_resource)
|
||||
|
||||
if 'azure_resource_id' in user_resource.properties:
|
||||
user_resource.azureStatus = get_azure_resource_status(user_resource.properties['azure_resource_id'])
|
||||
|
@ -333,7 +349,7 @@ async def create_user_resource(
|
|||
user_resource_repo=Depends(get_repository(UserResourceRepository)),
|
||||
resource_template_repo=Depends(get_repository(ResourceTemplateRepository)),
|
||||
operations_repo=Depends(get_repository(OperationRepository)),
|
||||
user=Depends(get_current_workspace_owner_or_researcher_user),
|
||||
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager),
|
||||
workspace=Depends(get_deployed_workspace_by_id_from_path),
|
||||
workspace_service=Depends(get_deployed_workspace_service_by_id_from_path)) -> OperationInResponse:
|
||||
|
||||
|
@ -359,8 +375,15 @@ async def create_user_resource(
|
|||
|
||||
|
||||
@user_resources_workspace_router.delete("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}", response_model=OperationInResponse, name=strings.API_DELETE_USER_RESOURCE)
|
||||
async def delete_user_resource(response: Response, user=Depends(get_current_workspace_owner_or_researcher_user), user_resource=Depends(get_user_resource_by_id_from_path), workspace_service=Depends(get_workspace_service_by_id_from_path), user_resource_repo=Depends(get_repository(UserResourceRepository)), operations_repo=Depends(get_repository(OperationRepository)), resource_template_repo=Depends(get_repository(ResourceTemplateRepository))) -> OperationInResponse:
|
||||
validate_user_is_workspace_owner_or_resource_owner(user, user_resource)
|
||||
async def delete_user_resource(
|
||||
response: Response,
|
||||
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager),
|
||||
user_resource=Depends(get_user_resource_by_id_from_path),
|
||||
workspace_service=Depends(get_workspace_service_by_id_from_path),
|
||||
user_resource_repo=Depends(get_repository(UserResourceRepository)),
|
||||
operations_repo=Depends(get_repository(OperationRepository)),
|
||||
resource_template_repo=Depends(get_repository(ResourceTemplateRepository))) -> OperationInResponse:
|
||||
validate_user_has_valid_role_for_user_resource(user, user_resource)
|
||||
|
||||
if user_resource.isEnabled:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=strings.USER_RESOURCE_NEEDS_TO_BE_DISABLED_BEFORE_DELETION)
|
||||
|
@ -382,8 +405,17 @@ async def delete_user_resource(response: Response, user=Depends(get_current_work
|
|||
|
||||
|
||||
@user_resources_workspace_router.patch("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}", status_code=status.HTTP_202_ACCEPTED, response_model=OperationInResponse, name=strings.API_UPDATE_USER_RESOURCE, dependencies=[Depends(get_workspace_by_id_from_path), Depends(get_workspace_service_by_id_from_path)])
|
||||
async def patch_user_resource(user_resource_patch: ResourcePatch, response: Response, user=Depends(get_current_workspace_owner_or_researcher_user), user_resource=Depends(get_user_resource_by_id_from_path), workspace_service=Depends(get_workspace_service_by_id_from_path), user_resource_repo=Depends(get_repository(UserResourceRepository)), resource_template_repo=Depends(get_repository(ResourceTemplateRepository)), operations_repo=Depends(get_repository(OperationRepository)), etag: str = Header(...)) -> OperationInResponse:
|
||||
validate_user_is_workspace_owner_or_resource_owner(user, user_resource)
|
||||
async def patch_user_resource(
|
||||
user_resource_patch: ResourcePatch,
|
||||
response: Response,
|
||||
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager),
|
||||
user_resource=Depends(get_user_resource_by_id_from_path),
|
||||
workspace_service=Depends(get_workspace_service_by_id_from_path),
|
||||
user_resource_repo=Depends(get_repository(UserResourceRepository)),
|
||||
resource_template_repo=Depends(get_repository(ResourceTemplateRepository)),
|
||||
operations_repo=Depends(get_repository(OperationRepository)),
|
||||
etag: str = Header(...)) -> OperationInResponse:
|
||||
validate_user_has_valid_role_for_user_resource(user, user_resource)
|
||||
|
||||
try:
|
||||
patched_user_resource, resource_template = user_resource_repo.patch_user_resource(user_resource, user_resource_patch, etag, resource_template_repo, workspace_service.templateName, user)
|
||||
|
@ -406,8 +438,16 @@ async def patch_user_resource(user_resource_patch: ResourcePatch, response: Resp
|
|||
|
||||
# user resource actions
|
||||
@user_resources_workspace_router.post("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}/invoke-action", status_code=status.HTTP_202_ACCEPTED, response_model=OperationInResponse, name=strings.API_INVOKE_ACTION_ON_USER_RESOURCE)
|
||||
async def invoke_action_on_user_resource(response: Response, action: str, user_resource=Depends(get_user_resource_by_id_from_path), workspace_service=Depends(get_workspace_service_by_id_from_path), resource_template_repo=Depends(get_repository(ResourceTemplateRepository)), user_resource_repo=Depends(get_repository(UserResourceRepository)), operations_repo=Depends(get_repository(OperationRepository)), user=Depends(get_current_workspace_owner_or_researcher_user)) -> OperationInResponse:
|
||||
validate_user_is_workspace_owner_or_resource_owner(user, user_resource)
|
||||
async def invoke_action_on_user_resource(
|
||||
response: Response,
|
||||
action: str,
|
||||
user_resource=Depends(get_user_resource_by_id_from_path),
|
||||
workspace_service=Depends(get_workspace_service_by_id_from_path),
|
||||
resource_template_repo=Depends(get_repository(ResourceTemplateRepository)),
|
||||
user_resource_repo=Depends(get_repository(UserResourceRepository)),
|
||||
operations_repo=Depends(get_repository(OperationRepository)),
|
||||
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager)) -> OperationInResponse:
|
||||
validate_user_has_valid_role_for_user_resource(user, user_resource)
|
||||
operation = await send_custom_action_message(
|
||||
resource=user_resource,
|
||||
resource_repo=user_resource_repo,
|
||||
|
@ -425,12 +465,18 @@ async def invoke_action_on_user_resource(response: Response, action: str, user_r
|
|||
|
||||
# user resource operations
|
||||
@user_resources_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}/operations", response_model=OperationInList, name=strings.API_GET_RESOURCE_OPERATIONS, dependencies=[Depends(get_workspace_by_id_from_path)])
|
||||
async def retrieve_user_resource_operations_by_user_resource_id(user_resource=Depends(get_user_resource_by_id_from_path), user=Depends(get_current_workspace_owner_or_researcher_user), operations_repo=Depends(get_repository(OperationRepository))) -> OperationInList:
|
||||
validate_user_is_workspace_owner_or_resource_owner(user, user_resource)
|
||||
async def retrieve_user_resource_operations_by_user_resource_id(
|
||||
user_resource=Depends(get_user_resource_by_id_from_path),
|
||||
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager),
|
||||
operations_repo=Depends(get_repository(OperationRepository))) -> OperationInList:
|
||||
validate_user_has_valid_role_for_user_resource(user, user_resource)
|
||||
return OperationInList(operations=operations_repo.get_operations_by_resource_id(resource_id=user_resource.id))
|
||||
|
||||
|
||||
@user_resources_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}/operations/{operation_id}", response_model=OperationInResponse, name=strings.API_GET_RESOURCE_OPERATION_BY_ID, dependencies=[Depends(get_workspace_by_id_from_path)])
|
||||
async def retrieve_user_resource_operations_by_user_resource_id_and_operation_id(user_resource=Depends(get_user_resource_by_id_from_path), user=Depends(get_current_workspace_owner_or_researcher_user), operation=Depends(get_operation_by_id_from_path)) -> OperationInList:
|
||||
validate_user_is_workspace_owner_or_resource_owner(user, user_resource)
|
||||
async def retrieve_user_resource_operations_by_user_resource_id_and_operation_id(
|
||||
user_resource=Depends(get_user_resource_by_id_from_path),
|
||||
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager),
|
||||
operation=Depends(get_operation_by_id_from_path)) -> OperationInList:
|
||||
validate_user_has_valid_role_for_user_resource(user, user_resource)
|
||||
return OperationInResponse(operation=operation)
|
||||
|
|
|
@ -48,4 +48,7 @@ get_current_workspace_owner_or_researcher_user_or_airlock_manager = AzureADAutho
|
|||
get_current_workspace_owner_or_researcher_user_or_tre_admin = AzureADAuthorization(require_one_of_roles=["TREAdmin", "WorkspaceOwner", "WorkspaceResearcher"])
|
||||
|
||||
|
||||
get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin = AzureADAuthorization(require_one_of_roles=["TREAdmin", "WorkspaceOwner", "WorkspaceResearcher", "AirlockManager"])
|
||||
|
||||
|
||||
get_current_workspace_owner_or_tre_admin = AzureADAuthorization(require_one_of_roles=["TREAdmin", "WorkspaceOwner"])
|
||||
|
|
|
@ -20,7 +20,11 @@ from models.domain.workspace import Workspace, WorkspaceRole
|
|||
from models.domain.workspace_service import WorkspaceService
|
||||
from models.schemas.resource_template import ResourceTemplateInformation
|
||||
from resources import strings
|
||||
from services.authentication import get_current_admin_user, get_current_tre_user_or_tre_admin, get_current_workspace_owner_user, get_current_workspace_owner_or_researcher_user, get_current_workspace_owner_or_researcher_user_or_tre_admin
|
||||
from services.authentication import get_current_admin_user, \
|
||||
get_current_tre_user_or_tre_admin, get_current_workspace_owner_user, \
|
||||
get_current_workspace_owner_or_researcher_user, \
|
||||
get_current_workspace_owner_or_researcher_user_or_airlock_manager, \
|
||||
get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin
|
||||
from azure.cosmos.exceptions import CosmosAccessConditionFailedError
|
||||
|
||||
|
||||
|
@ -215,7 +219,8 @@ class TestWorkspaceRoutesThatDontRequireAdminRights:
|
|||
def log_in_with_non_admin_user(self, app, non_admin_user):
|
||||
with patch('services.aad_authentication.AzureADAuthorization._get_user_from_token', return_value=non_admin_user()):
|
||||
app.dependency_overrides[get_current_tre_user_or_tre_admin] = non_admin_user
|
||||
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_tre_admin] = non_admin_user
|
||||
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_airlock_manager] = non_admin_user
|
||||
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin] = non_admin_user
|
||||
yield
|
||||
app.dependency_overrides = {}
|
||||
|
||||
|
@ -298,6 +303,7 @@ class TestWorkspaceRoutesThatRequireAdminRights:
|
|||
def _prepare(self, app, admin_user):
|
||||
with patch('services.aad_authentication.AzureADAuthorization._get_user_from_token', return_value=admin_user()):
|
||||
app.dependency_overrides[get_current_tre_user_or_tre_admin] = admin_user
|
||||
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_airlock_manager] = admin_user
|
||||
app.dependency_overrides[get_current_admin_user] = admin_user
|
||||
yield
|
||||
app.dependency_overrides = {}
|
||||
|
@ -503,6 +509,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerRights:
|
|||
def log_in_with_owner_user(self, app, owner_user):
|
||||
# The following ws services requires the WS app registration
|
||||
app.dependency_overrides[get_current_workspace_owner_user] = owner_user
|
||||
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_airlock_manager] = owner_user
|
||||
app.dependency_overrides[get_current_workspace_owner_or_researcher_user] = owner_user
|
||||
yield
|
||||
app.dependency_overrides = {}
|
||||
|
@ -661,7 +668,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerRights:
|
|||
# [PATCH] /workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}
|
||||
@ patch("api.routes.workspaces.send_resource_request_message", return_value=sample_resource_operation(resource_id=USER_RESOURCE_ID, operation_id=OPERATION_ID))
|
||||
@ patch("api.routes.workspaces.ResourceTemplateRepository.get_template_by_name_and_version", return_value=None)
|
||||
@ patch("api.routes.workspaces.validate_user_is_workspace_owner_or_resource_owner")
|
||||
@ patch("api.routes.workspaces.validate_user_has_valid_role_for_user_resource")
|
||||
@ patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id", return_value=sample_workspace_service())
|
||||
@ patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id", return_value=sample_workspace())
|
||||
@ patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id", return_value=sample_user_resource_object())
|
||||
|
@ -726,7 +733,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerOrResearcherRights:
|
|||
@pytest.fixture(autouse=True, scope='class')
|
||||
def log_in_with_researcher_user(self, app, researcher_user):
|
||||
# The following ws services requires the WS app registration
|
||||
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_tre_admin] = researcher_user
|
||||
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_airlock_manager] = researcher_user
|
||||
app.dependency_overrides[get_current_workspace_owner_or_researcher_user] = researcher_user
|
||||
yield
|
||||
app.dependency_overrides = {}
|
||||
|
@ -951,7 +958,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerOrResearcherRights:
|
|||
assert response.text == strings.WORKSPACE_SERVICE_IS_NOT_DEPLOYED
|
||||
|
||||
# [PATCH] /workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}
|
||||
@ patch("api.routes.workspaces.validate_user_is_workspace_owner_or_resource_owner")
|
||||
@ patch("api.routes.workspaces.validate_user_has_valid_role_for_user_resource")
|
||||
@ patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id", return_value=sample_user_resource_object())
|
||||
@ patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id", return_value=sample_workspace_service())
|
||||
@ patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id", return_value=sample_workspace())
|
||||
|
@ -998,7 +1005,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerOrResearcherRights:
|
|||
# [PATCH] /workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}
|
||||
@ patch("api.routes.workspaces.send_resource_request_message", return_value=sample_resource_operation(resource_id=USER_RESOURCE_ID, operation_id=OPERATION_ID))
|
||||
@ patch("api.routes.workspaces.ResourceTemplateRepository.get_template_by_name_and_version", return_value=None)
|
||||
@ patch("api.routes.workspaces.validate_user_is_workspace_owner_or_resource_owner")
|
||||
@ patch("api.routes.workspaces.validate_user_has_valid_role_for_user_resource")
|
||||
@ patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id", return_value=sample_workspace_service())
|
||||
@ patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id", return_value=sample_workspace())
|
||||
@ patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id", return_value=sample_user_resource_object())
|
||||
|
@ -1026,7 +1033,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerOrResearcherRights:
|
|||
@patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id")
|
||||
@patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id")
|
||||
@patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id")
|
||||
@patch("api.routes.workspaces.validate_user_is_workspace_owner_or_resource_owner")
|
||||
@patch("api.routes.workspaces.validate_user_has_valid_role_for_user_resource")
|
||||
async def test_delete_user_resource_raises_400_if_user_resource_is_enabled(self, _, get_user_resource_mock, ___, ____, resource_template_repo, app, client, basic_user_resource_template):
|
||||
user_resource = sample_user_resource_object()
|
||||
get_user_resource_mock.return_value = user_resource
|
||||
|
@ -1041,7 +1048,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerOrResearcherRights:
|
|||
@patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id")
|
||||
@patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id")
|
||||
@patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id", return_value=disabled_user_resource())
|
||||
@patch("api.routes.workspaces.validate_user_is_workspace_owner_or_resource_owner")
|
||||
@patch("api.routes.workspaces.validate_user_has_valid_role_for_user_resource")
|
||||
@patch("api.routes.workspaces.send_uninstall_message", return_value=sample_resource_operation(resource_id=USER_RESOURCE_ID, operation_id=OPERATION_ID))
|
||||
async def test_delete_user_resource_sends_uninstall_message(self, send_uninstall_mock, __, ___, ____, _____, resource_template_repo, app, client, basic_user_resource_template):
|
||||
resource_template_repo.return_value = basic_user_resource_template
|
||||
|
@ -1052,7 +1059,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerOrResearcherRights:
|
|||
@patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id")
|
||||
@patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id")
|
||||
@patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id")
|
||||
@patch("api.routes.workspaces.validate_user_is_workspace_owner_or_resource_owner")
|
||||
@patch("api.routes.workspaces.validate_user_has_valid_role_for_user_resource")
|
||||
@patch("api.routes.workspaces.send_uninstall_message", return_value=sample_resource_operation(resource_id=USER_RESOURCE_ID, operation_id=OPERATION_ID))
|
||||
async def test_delete_user_resource_returns_resource_id(self, __, ___, get_user_resource_mock, ____, _____, resource_template_repo, app, client, basic_user_resource_template):
|
||||
user_resource = disabled_user_resource()
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = "0.3.7"
|
||||
__version__ = "0.3.8"
|
||||
|
|
|
@ -67,9 +67,11 @@ public class AuthenticationProviderService {
|
|||
|
||||
List<String> rolesList = roles.asList(String.class);
|
||||
if (rolesList.stream().noneMatch(x -> x.equalsIgnoreCase("WorkspaceOwner")
|
||||
|| x.equalsIgnoreCase("WorkspaceResearcher"))) {
|
||||
|| x.equalsIgnoreCase("WorkspaceResearcher")
|
||||
|| x.equalsIgnoreCase("AirlockManager"))) {
|
||||
throw new GuacamoleInvalidCredentialsException(
|
||||
"User must have a workspace owner or workspace researcher role", CredentialsInfo.USERNAME_PASSWORD);
|
||||
"User must have a workspace owner or workspace researcher or Airlock Manager role",
|
||||
CredentialsInfo.USERNAME_PASSWORD);
|
||||
}
|
||||
} catch (final Exception ex) {
|
||||
LOGGER.error("Could not validate token", ex);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
name: tre-service-guacamole
|
||||
version: 0.4.5
|
||||
version: 0.4.6
|
||||
description: "An Azure TRE service for Guacamole"
|
||||
dockerfile: Dockerfile.tmpl
|
||||
registry: azuretre
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
"description": "Linux virtual machine.",
|
||||
"required": [
|
||||
],
|
||||
"authorizedRoles": [
|
||||
"WorkspaceOwner", "WorkspaceResearcher"
|
||||
],
|
||||
"properties": {
|
||||
"os_image": {
|
||||
"$id": "#/properties/os_image",
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
"description": "Windows virtual machine.",
|
||||
"required": [
|
||||
],
|
||||
"authorizedRoles": [
|
||||
"WorkspaceOwner", "WorkspaceResearcher"
|
||||
],
|
||||
"properties": {
|
||||
"os_image": {
|
||||
"$id": "#/properties/os_image",
|
||||
|
|
|
@ -74,7 +74,7 @@ export const ResourceContextMenu: React.FunctionComponent<ResourceContextMenuPro
|
|||
wsAuth = true;
|
||||
break;
|
||||
case ResourceType.UserResource:
|
||||
r = [WorkspaceRoleName.WorkspaceOwner, WorkspaceRoleName.WorkspaceResearcher];
|
||||
r = [WorkspaceRoleName.WorkspaceOwner, WorkspaceRoleName.WorkspaceResearcher, WorkspaceRoleName.AirlockManager];
|
||||
wsAuth = true;
|
||||
break;
|
||||
case ResourceType.Workspace:
|
||||
|
|
|
@ -112,7 +112,7 @@ export const WorkspaceServiceItem: React.FunctionComponent<WorkspaceServiceItemP
|
|||
<Stack.Item>
|
||||
<Stack horizontal horizontalAlign="space-between">
|
||||
<h1>Resources</h1>
|
||||
<SecuredByRole allowedRoles={[WorkspaceRoleName.WorkspaceOwner, WorkspaceRoleName.WorkspaceResearcher]} workspaceAuth={true} element={
|
||||
<SecuredByRole allowedRoles={[WorkspaceRoleName.WorkspaceOwner, WorkspaceRoleName.WorkspaceResearcher, WorkspaceRoleName.AirlockManager]} workspaceAuth={true} element={
|
||||
<PrimaryButton iconProps={{ iconName: 'Add' }} text="Create new"
|
||||
disabled={!workspaceService.isEnabled || latestUpdate.componentAction === ComponentAction.Lock || successStates.indexOf(workspaceService.deploymentStatus) === -1}
|
||||
title={(!workspaceService.isEnabled || latestUpdate.componentAction === ComponentAction.Lock || successStates.indexOf(workspaceService.deploymentStatus) === -1) ? 'Service must be enabled, successfully deployed, and not locked' : 'Create a User Resource'}
|
||||
|
|
|
@ -5,5 +5,6 @@ export enum RoleName {
|
|||
|
||||
export enum WorkspaceRoleName {
|
||||
WorkspaceOwner = "WorkspaceOwner",
|
||||
WorkspaceResearcher = "WorkspaceResearcher"
|
||||
WorkspaceResearcher = "WorkspaceResearcher",
|
||||
AirlockManager = "AirlockManager"
|
||||
}
|
Загрузка…
Ссылка в новой задаче