Skip to content

Commit

Permalink
Refs #254. Allowed participants to query assets for a session they cr…
Browse files Browse the repository at this point in the history
…eated.
  • Loading branch information
SBriere committed Jul 9, 2024
1 parent 9ea0332 commit bb30acf
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def query_device(self, filters: dict):
filter_by(id_participant=self.participant.id_participant).all()
return result

def get_accessible_assets(self, id_asset: int = None, uuid_asset: str = None):
def get_accessible_assets(self, id_asset: int = None, uuid_asset: str = None, session_id: int = None):
from opentera.db.models.TeraAsset import TeraAsset

# A participant can only have access to assets that are directly assigned to them (where id_participant is set
Expand All @@ -42,6 +42,8 @@ def get_accessible_assets(self, id_asset: int = None, uuid_asset: str = None):
query = query.filter(TeraAsset.id_asset == id_asset)
elif uuid_asset:
query = query.filter(TeraAsset.asset_uuid == uuid_asset)
elif session_id:
query = query.filter(TeraAsset.id_session == session_id)

return query.all()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from flask import session, request
from flask_restx import Resource, inputs
from flask_babel import gettext
from modules.LoginModule.LoginModule import participant_multi_auth, current_participant
from modules.DatabaseModule.DBManager import DBManager
from modules.FlaskModule.FlaskModule import device_api_ns as api
Expand All @@ -12,6 +13,7 @@
get_parser = api.parser()
get_parser.add_argument('asset_uuid', type=str, help='Asset UUID to query', default=None)
get_parser.add_argument('id_asset', type=int, help='Asset ID to query', default=None)
get_parser.add_argument('id_session', type=int, help='Session ID to query assets for', default=None)
get_parser.add_argument('with_urls', type=inputs.boolean, help='Also include assets infos and download-upload url')
get_parser.add_argument('with_only_token', type=inputs.boolean, help='Only includes the access token. '
'Will ignore with_urls if specified.')
Expand All @@ -29,11 +31,22 @@ def __init__(self, _api, *args, **kwargs):
403: 'Participant doesn\'t have access to the specified asset'},
params={'token': 'Secret token'})
@api.expect(get_parser)
@participant_multi_auth.login_required(role='full')
@participant_multi_auth.login_required(role='limited')
def get(self):
args = get_parser.parse_args()
participant_access = DBManager.participantAccess(current_participant)
assets = participant_access.get_accessible_assets(id_asset=args['id_asset'], uuid_asset=args['asset_uuid'])

if not current_participant.fullAccess:
# Not full access = can only query by id_asset or id_session
if not args['id_session'] and not args['id_asset'] and not args['asset_uuid']:
return gettext('Forbidden'), 403

if args['id_session']:
if args['id_session'] not in participant_access.get_accessible_sessions_ids():
return gettext('No access to session'), 403

assets = participant_access.get_accessible_assets(id_asset=args['id_asset'], uuid_asset=args['asset_uuid'],
session_id=args['id_session'])

# Create response
servername = self.module.config.server_config['hostname']
Expand All @@ -45,27 +58,27 @@ def get(self):
if 'X_EXTERNALPORT' in request.headers:
port = request.headers['X_EXTERNALPORT']
services_infos = []
if (args['with_urls'] or args['with_only_token']) and assets:
if (args['with_urls'] or args['with_only_token']) and assets and current_participant.fullAccess:
services_infos = {service.service_uuid: service.service_clientendpoint
for service in participant_access.get_accessible_services()}

assets_json = []
for asset in assets:
if args['with_only_token']:
if args['with_only_token'] and current_participant.fullAccess:
asset_json = {'asset_uuid': asset.asset_uuid}
else:
asset_json = asset.to_json()

# Access token
if args['with_urls'] or args['with_only_token']:
if (args['with_urls'] or args['with_only_token']) and current_participant.fullAccess:
# Access token
token_key = self.module.redisGet(RedisVars.RedisVar_ServiceTokenAPIKey)
access_token = TeraAsset.get_access_token(asset_uuids=asset.asset_uuid,
token_key=token_key,
requester_uuid=current_participant.participant_uuid,
expiration=1800)
asset_json['access_token'] = access_token
if args['with_urls']:
if args['with_urls'] and current_participant.fullAccess:
# We have previously verified that the service is available to the user
if asset.asset_service_uuid in services_infos:
asset_json['asset_infos_url'] = 'https://' + servername + ':' + str(port) \
Expand Down
2 changes: 2 additions & 0 deletions teraserver/python/opentera/db/models/TeraSession.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ def create_defaults(test=False):
base_session.session_users = [base_session.session_creator_user, session_user2, session_user3]
if i == 3:
base_session.session_devices = [session_device]
if i == 1:
base_session.id_creator_participant = session_part.id_participant
base_session.session_uuid = str(uuid.uuid4())
TeraSession.db().session.add(base_session)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from typing import List
from BaseParticipantAPITest import BaseParticipantAPITest
from opentera.db.models.TeraAsset import TeraAsset
from opentera.db.models.TeraParticipant import TeraParticipant
from opentera.db.models.TeraSession import TeraSession


class ParticipantQueryAssetsTest(BaseParticipantAPITest):
Expand Down Expand Up @@ -35,11 +38,19 @@ def test_query_invalid_token_auth(self):

def test_static_token(self):
with self._flask_app.app_context():
params = {'id_asset': 1, 'with_urls': True}
params = {'with_urls': True}
response = self._get_with_participant_token_auth(self.test_client,
token=self.participant_static_token, params=params)
self.assertEqual(403, response.status_code)

def test_static_token_forbidden_id(self):
with self._flask_app.app_context():
params = {'id_asset': 10, 'with_urls': True}
response = self._get_with_participant_token_auth(self.test_client,
token=self.participant_static_token, params=params)
self.assertEqual(200, response.status_code)
self.assertEqual(0, len(response.json))

def test_query_assets_get_id(self):
with self._flask_app.app_context():
params = {'id_asset': 1, 'with_urls': True}
Expand Down Expand Up @@ -106,6 +117,78 @@ def test_query_assets_all_token_only(self):
self.assertTrue(data_item.__contains__("asset_uuid"))
self.assertTrue(data_item.__contains__("access_token"))

def test_get_endpoint_with_token_auth_with_forbidden_id_session(self):
with self._flask_app.app_context():
participants: List[TeraParticipant] = TeraParticipant.query.all()

for participant in participants:
for session in TeraSession.query.all():
params = {
'id_session': session.id_session,
'with_urls': True
}

if participant.participant_token:
if session.id_creator_participant != participant.id_participant:
response = self._get_with_participant_token_auth(self.test_client,
token=participant.participant_token,
params=params)
self.assertEqual(403, response.status_code)

def test_get_endpoint_with_token_auth_with_session_id(self):
with self._flask_app.app_context():
participants: List[TeraParticipant] = TeraParticipant.query.all()

for participant in participants:
for session in TeraSession.query.all():
params = {
'id_session': session.id_session,
'with_urls': True
}

if participant.participant_token:
if session.id_creator_participant == participant.id_participant:
response = self._get_with_participant_token_auth(self.test_client,
token=participant.participant_token,
params=params)
self.assertEqual(200, response.status_code)

assets_ids = [asset.id_asset for asset in
TeraAsset.get_assets_for_session(session.id_session)
if asset.id_participant == participant.id_participant]
for asset_json in response.json:
self.assertTrue(asset_json['id_asset'] in assets_ids)
self._checkJson(asset_json, minimal=True) # Participant with token = never return url
assets_ids.remove(asset_json['id_asset'])
self.assertFalse(assets_ids)

def test_get_endpoint_with_login_with_session_id(self):
with self._flask_app.app_context():
participants: List[TeraParticipant] = TeraParticipant.query.all()

for participant in participants:
for session in TeraSession.query.all():
params = {
'id_session': session.id_session,
'with_urls': True
}

if participant.participant_login_enabled:
if session.id_creator_participant == participant.id_participant:
response = self._get_with_participant_http_auth(self.test_client,
username=participant.participant_username,
password='opentera', params=params)
self.assertEqual(200, response.status_code)

assets_ids = [asset.id_asset for asset in
TeraAsset.get_assets_for_session(session.id_session)
if asset.id_participant == participant.id_participant]
for asset_json in response.json:
self.assertTrue(asset_json['id_asset'] in assets_ids)
self._checkJson(asset_json, minimal=False) # Full infos
assets_ids.remove(asset_json['id_asset'])
self.assertFalse(assets_ids)

def _checkJson(self, json_data, minimal=False):
self.assertGreater(len(json_data), 0)
self.assertTrue(json_data.__contains__('id_asset'))
Expand All @@ -123,3 +206,7 @@ def _checkJson(self, json_data, minimal=False):
self.assertTrue(json_data.__contains__('asset_infos_url'))
self.assertTrue(json_data.__contains__('asset_url'))
self.assertTrue(json_data.__contains__('access_token'))
else:
self.assertFalse(json_data.__contains__('asset_infos_url'))
self.assertFalse(json_data.__contains__('asset_url'))
self.assertFalse(json_data.__contains__('access_token'))

0 comments on commit bb30acf

Please sign in to comment.