Skip to content
Snippets Groups Projects
Verified Commit edb39aea authored by Daniel Göbel's avatar Daniel Göbel
Browse files

Merge branch 'development' into feature/10-AAI-login

parents 6b6c1204 2fb7dd19
No related branches found
No related tags found
No related merge requests found
...@@ -203,6 +203,8 @@ async def delete_bucket( ...@@ -203,6 +203,8 @@ async def delete_bucket(
async def get_bucket_objects( async def get_bucket_objects(
bucket: BucketDB = Depends(get_current_bucket), bucket: BucketDB = Depends(get_current_bucket),
s3: S3ServiceResource = Depends(get_s3_resource), s3: S3ServiceResource = Depends(get_s3_resource),
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> list[S3ObjectMetaInformation]: ) -> list[S3ObjectMetaInformation]:
""" """
Get the metadata of the objects in the bucket. Get the metadata of the objects in the bucket.
...@@ -219,6 +221,12 @@ async def get_bucket_objects( ...@@ -219,6 +221,12 @@ async def get_bucket_objects(
objs : list[app.schemas.bucket.S3ObjectMetaInformation] objs : list[app.schemas.bucket.S3ObjectMetaInformation]
Meta information about all objects in the bucket. Meta information about all objects in the bucket.
""" """
permission = await CRUDBucketPermission.get(db, bucket.name, current_user.uid)
if permission is not None and permission.file_prefix is not None:
return [
S3ObjectMetaInformation.from_native_s3_object(obj)
for obj in s3.Bucket(bucket.name).objects.filter(Prefix=permission.file_prefix).all()
]
return [S3ObjectMetaInformation.from_native_s3_object(obj) for obj in s3.Bucket(bucket.name).objects.all()] return [S3ObjectMetaInformation.from_native_s3_object(obj) for obj in s3.Bucket(bucket.name).objects.all()]
...@@ -247,6 +255,8 @@ async def get_bucket_object( ...@@ -247,6 +255,8 @@ async def get_bucket_object(
}, },
}, },
), ),
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> S3ObjectMetaInformation: ) -> S3ObjectMetaInformation:
""" """
Get the metadata of a specific object in a bucket. Get the metadata of a specific object in a bucket.
...@@ -265,8 +275,11 @@ async def get_bucket_object( ...@@ -265,8 +275,11 @@ async def get_bucket_object(
objs : app.schemas.bucket.S3ObjectMetaInformation objs : app.schemas.bucket.S3ObjectMetaInformation
Meta information about the specific object in the bucket. Meta information about the specific object in the bucket.
""" """
permission = await CRUDBucketPermission.get(db, bucket.name, current_user.uid)
try: try:
obj = s3.ObjectSummary(bucket_name=bucket.name, key=object_path) if permission is None or permission.file_prefix is None or object_path.startswith(permission.file_prefix):
return S3ObjectMetaInformation.from_native_s3_object(obj) obj = s3.ObjectSummary(bucket_name=bucket.name, key=object_path)
return S3ObjectMetaInformation.from_native_s3_object(obj)
raise HTTPException(status.HTTP_403_FORBIDDEN, detail="No rights for this object.")
except ClientError: except ClientError:
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Object not found") raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Object not found")
import pytest import pytest
from fastapi import status from fastapi import status
from httpx import AsyncClient from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.config import settings from app.core.config import settings
from app.models.bucket import Bucket from app.models.bucket import Bucket
from app.models.bucket_permission import BucketPermission, PermissionEnum
from app.models.user import User
from app.tests.mocks.mock_s3_resource import MockS3ServiceResource from app.tests.mocks.mock_s3_resource import MockS3ServiceResource
from app.tests.utils.user import get_authorization_headers
from app.tests.utils.utils import random_lower_string from app.tests.utils.utils import random_lower_string
...@@ -13,6 +17,92 @@ class _TestS3ObjectsRoutes: ...@@ -13,6 +17,92 @@ class _TestS3ObjectsRoutes:
class TestS3ObjectsRoutesGet(_TestS3ObjectsRoutes): class TestS3ObjectsRoutesGet(_TestS3ObjectsRoutes):
@pytest.mark.asyncio
async def test_get_objects_with_right_for_specific_prefix(
self,
db: AsyncSession,
client: AsyncClient,
random_bucket: Bucket,
random_second_user: User,
mock_s3_service: MockS3ServiceResource,
) -> None:
"""
Test for getting the list of S3 objects in a bucket while only having rights for a specific prefix.
Parameters
----------
db : sqlalchemy.ext.asyncio.AsyncSession.
Async database session to perform query on. pytest fixture.
client : httpx.AsyncClient
HTTP Client to perform the request on. pytest fixture.
random_bucket : app.models.bucket.Bucket
Random bucket for testing. pytest fixture.
random_second_user : app.models.user.User
Random second user for testing. pytest fixture.
mock_s3_service : app.tests.mocks.mock_s3_resource.MockS3ServiceResource
Mock S3 Service to manipulate objects. pytest fixture.
"""
user_token_headers = await get_authorization_headers(client, random_second_user.uid)
mock_s3_service.create_object_in_bucket(bucket_name=random_bucket.name, key=random_lower_string())
obj = mock_s3_service.create_object_in_bucket(
bucket_name=random_bucket.name, key="pseudo/folder/" + random_lower_string()
)
permission = BucketPermission(
bucket_name=random_bucket.name,
user_id=random_second_user.uid,
permissions=PermissionEnum.READ,
file_prefix="pseudo/folder/",
)
db.add(permission)
await db.commit()
response = await client.get(f"{self.base_path}{random_bucket.name}/objects", headers=user_token_headers)
assert response.status_code == status.HTTP_200_OK
response_obj_list = response.json()
assert len(response_obj_list) == 1
assert response_obj_list[0]["key"] == obj.key
@pytest.mark.asyncio
async def test_get_object_without_right_for_specific_prefix(
self,
db: AsyncSession,
client: AsyncClient,
random_bucket: Bucket,
random_second_user: User,
mock_s3_service: MockS3ServiceResource,
) -> None:
"""
Test for getting a specific S3 object in a bucket while not having rights for the prefix.
Parameters
----------
db : sqlalchemy.ext.asyncio.AsyncSession.
Async database session to perform query on. pytest fixture.
client : httpx.AsyncClient
HTTP Client to perform the request on. pytest fixture.
random_bucket : app.models.bucket.Bucket
Random bucket for testing. pytest fixture.
random_second_user : app.models.user.User
Random second user for testing. pytest fixture.
mock_s3_service : app.tests.mocks.mock_s3_resource.MockS3ServiceResource
Mock S3 Service to manipulate objects. pytest fixture.
"""
user_token_headers = await get_authorization_headers(client, random_second_user.uid)
obj = mock_s3_service.create_object_in_bucket(
bucket_name=random_bucket.name, key="another/folder/" + random_lower_string()
)
permission = BucketPermission(
bucket_name=random_bucket.name,
user_id=random_second_user.uid,
permissions=PermissionEnum.READ,
file_prefix="pseudo/folder/",
)
db.add(permission)
await db.commit()
response = await client.get(
f"{self.base_path}{random_bucket.name}/objects/{obj.key}", headers=user_token_headers
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_get_all_s3_object_from_bucket( async def test_get_all_s3_object_from_bucket(
self, self,
......
...@@ -112,14 +112,16 @@ class MockS3Bucket: ...@@ -112,14 +112,16 @@ class MockS3Bucket:
--------- ---------
all() -> list[app.tests.mocks.mock_s3_resource.MockS3ObjectSummary] all() -> list[app.tests.mocks.mock_s3_resource.MockS3ObjectSummary]
Get the saved list. Get the saved list.
filter(Prefix: str) -> app.tests.mocks.mock_s3_resource.MockS3Bucket.MockS3ObjectList
Filter the object in the list by the prefix all their keys should have.
add(obj: app.tests.mocks.mock_s3_resource.MockS3ObjectSummary) -> None add(obj: app.tests.mocks.mock_s3_resource.MockS3ObjectSummary) -> None
Add a MockS3ObjectSummary to the list. Add a MockS3ObjectSummary to the list.
delete(key: str) -> None delete(key: str) -> None
Delete a MockS3ObjectSummary from the list Delete a MockS3ObjectSummary from the list
""" """
def __init__(self) -> None: def __init__(self, obj_list: list[MockS3ObjectSummary] | None = None) -> None:
self._objs: list[MockS3ObjectSummary] = [] self._objs: list[MockS3ObjectSummary] = [] if obj_list is None else obj_list
def all(self) -> list[MockS3ObjectSummary]: def all(self) -> list[MockS3ObjectSummary]:
""" """
...@@ -154,6 +156,22 @@ class MockS3Bucket: ...@@ -154,6 +156,22 @@ class MockS3Bucket:
""" """
self._objs = [obj for obj in self._objs if obj.key != key] self._objs = [obj for obj in self._objs if obj.key != key]
def filter(self, Prefix: str) -> "MockS3Bucket.MockS3ObjectList":
"""
Filter the object in the list by the prefix all their keys should have.
Parameters
----------
Prefix : str
The prefix that all keys should have.
Returns
-------
obj_list : app.tests.mocks.mock_s3_resource.MockS3Bucket.MockS3ObjectList
The filtered list.
"""
return MockS3Bucket.MockS3ObjectList(obj_list=list(filter(lambda x: x.key.startswith(Prefix), self._objs)))
def __init__(self, name: str, parent_service: "MockS3ServiceResource"): def __init__(self, name: str, parent_service: "MockS3ServiceResource"):
""" """
Initialize a MockS3Bucket. Initialize a MockS3Bucket.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment