Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test that creation of work order tokens is secure (GSI-903) #25

Merged
merged 5 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ repos:
- id: no-commit-to-branch
args: [--branch, dev, --branch, int, --branch, main]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.1
rev: v0.5.4
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.1
rev: v1.11.0
hooks:
- id: mypy
args: [--no-warn-unused-ignores]
4 changes: 2 additions & 2 deletions .pyproject_generation/pyproject_custom.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[project]
name = "wps"
version = "2.0.3"
version = "2.0.4"
description = "Work Package Service"
dependencies = [
"ghga-event-schemas~=3.3.1",
"ghga-service-commons[api,auth,crypt]>=3.1.5",
"hexkit[akafka,mongodb]>=3.3.0",
"hexkit[akafka,mongodb]>=3.4.0",
"httpx>=0.27",
"typer>=0.12",
]
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,21 @@ We recommend using the provided Docker container.

A pre-build version is available at [docker hub](https://hub.docker.com/repository/docker/ghga/work-package-service):
```bash
docker pull ghga/work-package-service:2.0.3
docker pull ghga/work-package-service:2.0.4
```

Or you can build the container yourself from the [`./Dockerfile`](./Dockerfile):
```bash
# Execute in the repo's root dir:
docker build -t ghga/work-package-service:2.0.3 .
docker build -t ghga/work-package-service:2.0.4 .
```

For production-ready deployment, we recommend using Kubernetes, however,
for simple use cases, you could execute the service using docker
on a single server:
```bash
# The entrypoint is preconfigured:
docker run -p 8080:8080 ghga/work-package-service:2.0.3 --help
docker run -p 8080:8080 ghga/work-package-service:2.0.4 --help
```

If you prefer not to use containers, you may install the service from source:
Expand Down
734 changes: 300 additions & 434 deletions lock/requirements-dev.txt

Large diffs are not rendered by default.

476 changes: 169 additions & 307 deletions lock/requirements.txt

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ components:
info:
description: A service managing work packages for the GHGA CLI
title: Work Package Service
version: 2.0.3
version: 2.0.4
openapi: 3.1.0
paths:
/health:
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ classifiers = [
"Intended Audience :: Developers",
]
name = "wps"
version = "2.0.3"
version = "2.0.4"
description = "Work Package Service"
dependencies = [
"ghga-event-schemas~=3.3.1",
"ghga-service-commons[api,auth,crypt]>=3.1.5",
"hexkit[akafka,mongodb]>=3.3.0",
"hexkit[akafka,mongodb]>=3.4.0",
"httpx>=0.27",
"typer>=0.12",
]
Expand Down
1 change: 1 addition & 0 deletions src/wps/core/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ async def work_order_token(
- if check_valid is set and the work package has expired
- if a work_package_access_token is specified and it does not match
the token hash that is stored in the work package
- if the access permission has been revoked
"""
extra = { # only used for logging
"work_package_id": work_package_id,
Expand Down
1 change: 0 additions & 1 deletion tests/fixtures/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
"fixture_config",
"fixture_repository",
"fixture_client",
"fixture_consumer",
"headers_for_token",
"non_mocked_hosts",
"Consumer",
Expand Down
48 changes: 33 additions & 15 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ async def test_create_work_order_token(
mongodb_populated: MongoDbFixture,
):
"""Test that work order tokens can be properly created."""
# mock the access check for the test dataset
# mock the access check for the test dataset to grant access

httpx_mock.add_response(
method="GET",
Expand Down Expand Up @@ -186,29 +186,29 @@ async def test_create_work_order_token(
)
assert response.status_code == status.HTTP_201_CREATED

token = response.json()
assert isinstance(token, str)
wot = response.json()
assert isinstance(wot, str)

# decrypt the work order token

assert token and isinstance(token, str) and token.isascii()
token = decrypt(token)
assert wot and isinstance(wot, str) and wot.isascii()
wot = decrypt(wot)

# validate the work order token

assert isinstance(token, str)
assert len(token) > 80
assert token.count(".") == 2
token_chars = token.replace(".", "").replace("-", "").replace("_", "")
assert token_chars.isalnum()
assert token_chars.isascii()
token_dict = decode_and_validate_token(token, SIGNING_KEY_PAIR.public())
assert isinstance(wot, str)
assert len(wot) > 80
assert wot.count(".") == 2
wot_chars = wot.replace(".", "").replace("-", "").replace("_", "")
assert wot_chars.isalnum()
assert wot_chars.isascii()
wot_dict = decode_and_validate_token(wot, SIGNING_KEY_PAIR.public())

# check the content of the work order token

assert isinstance(token_dict, dict)
assert token_dict.pop("exp") - token_dict.pop("iat") == 30
assert token_dict == {
assert isinstance(wot_dict, dict)
assert wot_dict.pop("exp") - wot_dict.pop("iat") == 30
assert wot_dict == {
"type": "download",
"file_id": "file-id-3",
"user_id": "[email protected]",
Expand All @@ -217,6 +217,24 @@ async def test_create_work_order_token(
"email": "[email protected]",
}

# mock the access check for the test dataset to revoke access

httpx_mock.reset(assert_all_responses_were_requested=True)
Cito marked this conversation as resolved.
Show resolved Hide resolved
httpx_mock.add_response(
method="GET",
url="http://access/users/[email protected]/datasets/some-dataset-id",
text="false",
)

# try to fetch a work order token again

response = await client.post(
f"/work-packages/{work_package_id}/files/file-id-3/work-order-tokens",
headers=headers_for_token(token),
)
assert response.status_code == status.HTTP_403_FORBIDDEN
assert "Access has been revoked" in response.json()["detail"]


async def test_get_datasets_unauthenticated(client: AsyncTestClient):
"""Test that the list of accessible datasets cannot be fetched unauthenticated."""
Expand Down
19 changes: 19 additions & 0 deletions tests/test_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,25 @@ async def test_work_package_and_token_creation(
"email": package.email,
}

# revoke access and check that work order token cannot be created any more
async def check_download_access_patched(user_id: str, dataset_id: str) -> bool:
assert user_id == package.user_id
assert dataset_id == package.dataset_id
return False

access = repository._access
_check_download_access_original = access.check_download_access
try:
access.check_download_access = check_download_access_patched # type: ignore
with pytest.raises(repository.WorkPackageAccessError):
await repository.work_order_token(
work_package_id=work_package_id,
file_id="file-id-1",
work_package_access_token=wpat,
)
finally:
access.check_download_access = _check_download_access_original # type: ignore


async def test_checking_accessible_datasets(
repository: WorkPackageRepository,
Expand Down