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

Add BDD tests for Token Feature to RSTUF API #369

Merged
merged 2 commits into from
Aug 17, 2023
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
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ myst-parser = "*"
pre-commit = "*"
bandit = "*"
httpx = "*"
pytest-bdd = "*"

[requires]
python_version = "3.10"
187 changes: 113 additions & 74 deletions Pipfile.lock

Large diffs are not rendered by default.

26 changes: 15 additions & 11 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ coverage==7.3.0
cryptography==41.0.3
distlib==0.3.7
docutils==0.18.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
exceptiongroup==1.1.2; python_version < '3.11'
exceptiongroup==1.1.3; python_version < '3.11'
filelock==3.12.2; python_version >= '3.7'
flake8==6.1.0
gitdb==4.0.10; python_version >= '3.7'
Expand All @@ -34,6 +34,7 @@ jinja2==3.1.2; python_version >= '3.7'
jsonschema==4.19.0; python_version >= '3.8'
jsonschema-specifications==2023.7.1; python_version >= '3.8'
m2r==0.3.1
mako==1.2.4; python_version >= '3.7'
markdown-it-py==3.0.0; python_version >= '3.8'
markupsafe==2.1.3; python_version >= '3.7'
mccabe==0.7.0; python_version >= '3.6'
Expand All @@ -44,6 +45,8 @@ mypy-extensions==1.0.0; python_version >= '3.5'
myst-parser==2.0.0
nodeenv==1.8.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'
packaging==23.1; python_version >= '3.7'
parse==1.19.1
parse-type==0.6.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
pathspec==0.11.2; python_version >= '3.7'
pbr==5.11.1; python_version >= '2.6'
platformdirs==3.10.0; python_version >= '3.7'
Expand All @@ -56,31 +59,33 @@ pyflakes==3.1.0; python_version >= '3.8'
pygments==2.16.1; python_version >= '3.7'
pyproject-api==1.5.3; python_version >= '3.7'
pytest==7.4.0
pytest-bdd==6.1.1
pyyaml==6.0.1; python_version >= '3.6'
referencing==0.30.2; python_version >= '3.8'
requests==2.31.0; python_version >= '3.7'
rich==13.5.2; python_full_version >= '3.7.0'
rpds-py==0.9.2; python_version >= '3.8'
setuptools==68.0.0; python_version >= '3.7'
setuptools==68.1.0; python_version >= '3.8'
six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
smmap==5.0.0; python_version >= '3.6'
sniffio==1.3.0; python_version >= '3.7'
snowballstemmer==2.2.0
sphinx==6.2.1
sphinx-rtd-theme==1.2.2
sphinxcontrib-applehelp==1.0.6
sphinxcontrib-devhelp==1.0.4
sphinxcontrib-htmlhelp==2.0.3
sphinxcontrib-applehelp==1.0.7
sphinxcontrib-devhelp==1.0.5
sphinxcontrib-htmlhelp==2.0.4
sphinxcontrib-httpdomain==1.8.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
sphinxcontrib-jquery==4.1; python_version >= '2.7'
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-openapi==0.7.0
sphinxcontrib-plantuml==0.25
sphinxcontrib-qthelp==1.0.5
sphinxcontrib-serializinghtml==1.1.7
sphinxcontrib-qthelp==1.0.6
sphinxcontrib-serializinghtml==1.1.8
stevedore==5.1.0; python_version >= '3.8'
tomli==2.0.1; python_version < '3.11'
tox==4.8.0
tox==4.9.0
typing-extensions==4.7.1; python_version >= '3.7'
urllib3==2.0.4; python_version >= '3.7'
virtualenv==20.24.3; python_version >= '3.7'
voluptuous==0.13.1
Expand All @@ -104,11 +109,10 @@ pydantic==1.10.12; python_version >= '3.7'
python-dateutil==2.8.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
python-jose==3.3.0
python-multipart==0.0.6
redis==4.6.0
redis==5.0.0
rsa==4.9; python_version >= '3.6' and python_version < '4'
sqlalchemy==2.0.19
sqlalchemy==2.0.20
starlette==0.27.0; python_version >= '3.7'
typing-extensions==4.7.1; python_version >= '3.7'
tzdata==2023.3; python_version >= '2'
uvicorn==0.23.2
vine==5.0.0; python_version >= '3.6'
Expand Down
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ click-repl==0.3.0; python_version >= '3.6'
configobj==5.0.8
dynaconf==3.2.1
ecdsa==0.18.0; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'
exceptiongroup==1.1.2; python_version < '3.11'
exceptiongroup==1.1.3; python_version < '3.11'
fastapi==0.99.1
greenlet==2.0.2; platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))
h11==0.14.0; python_version >= '3.7'
Expand All @@ -24,11 +24,11 @@ pydantic==1.10.12; python_version >= '3.7'
python-dateutil==2.8.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
python-jose==3.3.0
python-multipart==0.0.6
redis==4.6.0
redis==5.0.0
rsa==4.9; python_version >= '3.6' and python_version < '4'
six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
sniffio==1.3.0; python_version >= '3.7'
sqlalchemy==2.0.19
sqlalchemy==2.0.20
starlette==0.27.0; python_version >= '3.7'
typing-extensions==4.7.1; python_version >= '3.7'
tzdata==2023.3; python_version >= '2'
Expand Down
69 changes: 69 additions & 0 deletions tests/bdd/features/tokens/generate.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
Feature: Generate HTTP token for Repository Service for TUF (RSTUF)
As an admin,
Admin has deployed and bootstrapped RSTUF


Scenario Outline: Admin uses HTTP API to generate a token
Given the admin has the admin password
And the admin gets an 'access_token' by logging in to '/api/v1/token' with a 'write:token' scope
And the admin adds Authorization Bearer 'access_token' in the 'headers'
And the admin adds JSON payload with scopes: <scopes> and expires: <expires>
When the admin sends a POST request to '/api/v1/token/new'
Then the admin should get status code '200'
And the admin should get 'access_token' with a new token

Examples:
| scopes | expires |
| ['write:targets'] | 1 |
| ['write:targets', 'read:settings'] | 240 |
| ['read:bootstrap'] | 1 |
| ['read:bootstrap','write:targets'] | 24 |
| ['read:settings'] | 3 |
| ['read:token'] | 5 |
| ['write:targets', 'read:settings', 'read:tasks'] | 380 |


Scenario Outline: Admin cannot generate Token using HTTP API with an invalid expires
Given the admin has the admin password
And the admin gets an 'access_token' by logging in to '/api/v1/token' with a 'write:token' scope
And the admin adds Authorization Bearer 'access_token' in the 'headers'
And the admin adds JSON payload with scopes: <scopes> and expires: <expires>
When the admin sends a POST request to '/api/v1/token/new' with invalid 'expires' in 'payload'
Then the admin should get status code '422'

Examples:
| scopes | expires |
| ['read:bootstrap','write:targets'] | 0 |
| ['read:bootstrap','write:targets'] | -5 |
| ['read:bootstrap'] | None |


Scenario Outline: Admin cannot generate Token using HTTP API for certain scopes
MVrachev marked this conversation as resolved.
Show resolved Hide resolved
Given the admin has the admin password
And the admin gets an 'access_token' by logging in to '/api/v1/token' with a 'write:token' scope
And the admin adds Authorization Bearer 'access_token' in the 'headers'
And the admin adds JSON payload with scopes: <scopes> and expires: <expires>
When the admin sends a POST request to '/api/v1/token/new' with not allowed 'scopes' in 'payload'
Then the admin should get status code '422'
MVrachev marked this conversation as resolved.
Show resolved Hide resolved

Examples:
| scopes | expires |
| ['write:token'] | 24 |
| ['read:bootstrap','write:token'] | 24 |
| ['write:bootstrap'] | 24 |
| ['write:bootstrap', 'read:settings'] | 24 |
| [] | 24 |
| [''] | 24 |

Scenario Outline: Admin is Unauthorized to generate using HTTP API with an invalid token
Given the admin adds Authorization Bearer <token> in the 'headers'
And the admin adds JSON payload with scopes: <scopes> and expires: <expires>
When the admin sends a POST request to '/api/v1/token/new' with invalid 'access_token' in the headers
Then the admin should get status code '401'
And the admin should get 'Failed to validate token' in the body

Examples:
| token | scopes | expires |
| invalid | ['write:targets'] | 1 |
| eyJhbiJIUzI | ['read:bootstrap'] | 1 |
| '' | ['read:bootstrap'] | 1 |
MVrachev marked this conversation as resolved.
Show resolved Hide resolved
52 changes: 52 additions & 0 deletions tests/bdd/features/tokens/login.feature
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an invalid expire in payload scenario for the login as we do for the generate in

When the admin sends a POST request to '/api/v1/token/new' with invalid 'expires' in 'payload'

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't check that in our code as well.
We relly that

expires = datetime.fromtimestamp(token.get("exp"))
will fail.

@kairoaraujo do you think we want to test that as FT test and/or add a check for expires?

Copy link
Collaborator

@KAUTH KAUTH Aug 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't check that in our code as well.

I believe there's validation done in the model here, which is defined for the endpoint here.

If that is indeed the case we can just add this in the improvements task.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
Feature: Login to Repository Service for TUF (RSTUF) and receive an access token
As an admin,
Admin has deployed and bootstrapped RSTUF

Scenario Outline: Login using RSTUF API
Given the API requester prepares 'data' with <username>, <password>, <scope>, <expires>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: instead of 'data' we could use 'token_data' as it is named in the resource or otherwise 'payload' or 'request_body' (swagger notation)

When the API requester sends a 'POST' method to '/api/v1/token' with 'data'
Then the API requester should get status code '200'
And the API requester should get 'access_token' in response body

Examples:
| username | password | scope | expires |
| admin | secret | read:bootstrap | None |
| admin | secret | read:bootstrap write:bootstrap | None |
| admin | secret | read:bootstrap read:settings | None |
| admin | secret | read:token | 240 |


Scenario Outline: Login using RSTUF API gets Unauthorized
Given the API requester prepares 'data' with <username>, <password>, <scope>, <expires>
When the API requester sends a 'POST' method to '/api/v1/token' with invalid username/password in 'data'
Then the API requester should get status code '401'
And the API requester should get 'detail: Unauthorized' in the response body

Examples:
| username | password | scope | expires |
| admin | invalidpass | write:bootstrap | 1 |
| admin | password-test | write:bootstrap | 1 |
| admin | test-assword | write:bootstrap | 1 |
| admin | admin | write:bootstrap | 1 |
| admin | '' | write:bootstrap | 1 |
| admin | None | write:bootstrap | 1 |
| admin | admin | write:bootstrap | 1 |
| root | secret | write:bootstrap | 1 |
| root | 123456 | write:bootstrap | 1 |
| '' | secret | write:bootstrap | 1 |
| None | 123456 | write:bootstrap | 1 |

Scenario Outline: Login using RSTUF API gets forbidden for invalid scopes
Given the API requester prepares 'data' with <username>, <password>, <scope>, <expires>
When the API requester sends a 'POST' method to '/api/v1/token' with invalid scopes in 'data'
Then the API requester should get status code '403'
And the API requester should get 'scope invalid' in the response body

Examples:
| username | password | scope | expires |
| admin | secret | invalid | 1 |
| admin | secret | root | 1 |
| admin | secret | all:all | 1 |
| admin | secret | read-write:token | 1 |
| admin | secret | '' | 1 |
| admin | secret | None | 1 |
MVrachev marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 3 additions & 0 deletions tests/bdd/tokens/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-FileCopyrightText: 2022-2023 VMware Inc
#
# SPDX-License-Identifier: MIT
Loading