Skip to content

Commit

Permalink
Add tests for create endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
petterhj committed Sep 3, 2021
1 parent 25374db commit 7d8d27b
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 55 deletions.
5 changes: 0 additions & 5 deletions clients/__init__.py
@@ -1,5 +0,0 @@
from clients.teams import TeamsClient

__all__ = [
"TeamsClient",
]
31 changes: 14 additions & 17 deletions clients/teams.py
Expand Up @@ -3,21 +3,18 @@
import requests


class TeamsClient:
@staticmethod
def has_member(access_token: str, team_id: str, user_id: str):
r = requests.get(
url=f"{os.environ['TEAMS_API_URL']}/teams/{team_id}/members/{user_id}",
headers={"Authorization": f"Bearer {access_token}"},
)
r.raise_for_status()
return r.status_code == 200
def has_member(access_token: str, team_id: str, user_id: str):
r = requests.get(
url=f"{os.environ['TEAMS_API_URL']}/teams/{team_id}/members/{user_id}",
headers={"Authorization": f"Bearer {access_token}"},
)
return r.status_code == 200

@staticmethod
def has_role(access_token: str, team_id: str, role: str):
r = requests.get(
url=f"{os.environ['TEAMS_API_URL']}/teams/{team_id}/roles",
headers={"Authorization": f"Bearer {access_token}"},
)
r.raise_for_status()
return role in r.json()

def has_role(access_token: str, team_id: str, role: str):
r = requests.get(
url=f"{os.environ['TEAMS_API_URL']}/teams/{team_id}/roles",
headers={"Authorization": f"Bearer {access_token}"},
)
r.raise_for_status()
return role in r.json()
1 change: 1 addition & 0 deletions models/models.py
Expand Up @@ -10,6 +10,7 @@ class MaskinportenClientIn(BaseModel):

class MaskinportenClientOut(BaseModel):
client_id: str
team_id: str
name: str
description: str
scopes: list[str]
Expand Down
20 changes: 5 additions & 15 deletions resources/authorizer.py
Expand Up @@ -5,7 +5,7 @@
from keycloak.keycloak_openid import KeycloakOpenID
from requests.exceptions import HTTPError

from clients import TeamsClient
from clients import teams
from models import MaskinportenClientIn
from resources.errors import ErrorResponse

Expand Down Expand Up @@ -56,18 +56,8 @@ def is_team_member(
auth: Auth = Depends(),
):
"""Pass through without exception if user is a team member."""
try:
if not TeamsClient.has_member(
auth.bearer_token, body.team_id, auth.principal_id
):
raise ErrorResponse(status.HTTP_403_FORBIDDEN, "Forbidden")
except HTTPError as e:
if e.response.status_code == 404:
raise ErrorResponse(
status.HTTP_400_BAD_REQUEST,
"User is not a member of specified team",
)
raise ErrorResponse(status.HTTP_500_INTERNAL_SERVER_ERROR, "Server error")
if not teams.has_member(auth.bearer_token, body.team_id, auth.principal_id):
raise ErrorResponse(status.HTTP_403_FORBIDDEN, "Forbidden")


def has_team_role(role: str):
Expand All @@ -77,10 +67,10 @@ def _verify_team_role(
):
"""Pass through without exception if specified team is assigned `role`."""
try:
if not TeamsClient.has_role(auth.bearer_token, body.team_id, role):
if not teams.has_role(auth.bearer_token, body.team_id, role):
raise ErrorResponse(
status.HTTP_403_FORBIDDEN,
f"Team is not assigned role {role}",
f"Team is not assigned required role {role}",
)
except HTTPError as e:
if e.response.status_code == 404:
Expand Down
1 change: 1 addition & 0 deletions resources/maskinporten_clients.py
Expand Up @@ -40,6 +40,7 @@ def create_client(
# TODO: Create pubreg-client resource using `okdata-permission-api`
return MaskinportenClientOut(
client_id="some-client-id",
team_id=body.team_id,
name=body.name,
description=body.description,
scopes=body.scopes,
Expand Down
30 changes: 29 additions & 1 deletion test/conftest.py
@@ -1,11 +1,39 @@
import pytest

import responses
from fastapi.testclient import TestClient
from keycloak import KeycloakOpenID

from app import app


team_id = "abc-123-def-456"
valid_access_token = "valid-access-token"
valid_access_token_not_member = "valid-access-token-not-member"
team_member_user = "janedoe"
not_team_member_user = "homersimpson"
origo_team_role = "origo-team"


@pytest.fixture
def mock_client():
app.debug = True
return TestClient(app)


@pytest.fixture
def mocked_responses():
with responses.RequestsMock() as rsps:
yield rsps


@pytest.fixture
def mock_keycloak(monkeypatch):
def introspect(self, token):
if token == valid_access_token:
return {"active": True, "username": team_member_user}
elif token == valid_access_token_not_member:
return {"active": True, "username": not_team_member_user}
else:
return {"active": False}

monkeypatch.setattr(KeycloakOpenID, "introspect", introspect)
123 changes: 107 additions & 16 deletions test/resources/test_maskinporten_clients.py
@@ -1,20 +1,109 @@
class TestMaskinportenClients:
# TODO
# def test_create_client(self, mock_client):
# body = {
# "name": "some-client",
# "description": "Very cool client",
# "scopes": ["some-scope"],
# }

# assert mock_client.post("/clients", json=body).json() == {
# "team_id": "abc-123",
# "client_id": "some-client-id",
# "name": "some-client",
# "description": "Very cool client",
# "scopes": ["some-scope"],
# }
import os

import responses


from test.conftest import (
valid_access_token,
valid_access_token_not_member,
team_id,
origo_team_role,
team_member_user,
not_team_member_user,
)


teams_api_list_roles_url = os.environ["TEAMS_API_URL"] + "/teams/{}/roles"
teams_api_verify_member_url = os.environ["TEAMS_API_URL"] + "/teams/{}/members/{}"
create_client_body_in = {
"team_id": team_id,
"name": "some-client",
"description": "Very cool client",
"scopes": ["some-scope"],
}


class TestMaskinportenCreateClient:
def test_create_client_forbidden(self, mock_client, mock_keycloak):
create_client_response = mock_client.post(
"/clients",
json=create_client_body_in,
headers={"Authorization": "Bearer invalid-access-token"},
)
assert create_client_response.status_code == 401
assert create_client_response.json()["message"] == "Invalid access token"

def test_create_client_missing_role(
self, mock_client, mock_keycloak, mocked_responses
):
mocked_responses.add(
responses.GET,
teams_api_list_roles_url.format(team_id),
json=["some-role"],
)

create_client_response = mock_client.post(
"/clients",
json=create_client_body_in,
headers={"Authorization": f"Bearer {valid_access_token}"},
)

assert create_client_response.status_code == 403
assert (
create_client_response.json()["message"]
== "Team is not assigned required role origo-team"
)

def test_create_client_not_team_member(
self, mock_client, mock_keycloak, mocked_responses
):
mocked_responses.add(
responses.GET,
teams_api_list_roles_url.format(team_id),
json=[origo_team_role, "some-other-role"],
)
mocked_responses.add(
responses.GET,
teams_api_verify_member_url.format(team_id, not_team_member_user),
status=404,
)

create_client_response = mock_client.post(
"/clients",
json=create_client_body_in,
headers={"Authorization": f"Bearer {valid_access_token_not_member}"},
)

assert create_client_response.status_code == 403
assert create_client_response.json()["message"] == "Forbidden"

def test_create_client_success(self, mock_client, mock_keycloak, mocked_responses):
mocked_responses.add(
responses.GET,
teams_api_list_roles_url.format(team_id),
json=[origo_team_role],
)
mocked_responses.add(
responses.GET, teams_api_verify_member_url.format(team_id, team_member_user)
)

create_client_response = mock_client.post(
"/clients",
json=create_client_body_in,
headers={"Authorization": f"Bearer {valid_access_token}"},
)

assert create_client_response.status_code == 201
assert create_client_response.json() == {
"client_id": "some-client-id",
"team_id": team_id,
"name": "some-client",
"description": "Very cool client",
"scopes": ["some-scope"],
}


class TestMaskinportenCreateClientKey:
def test_create_client_key(self, mock_client):
client_id = "some-client-id"

Expand All @@ -23,6 +112,8 @@ def test_create_client_key(self, mock_client):
"key": "some-key",
}


class TestMaskinportenListClientKey:
def test_list_client_keys(self, mock_client):
client_id = "some-client-id"

Expand Down
8 changes: 7 additions & 1 deletion tox.ini
Expand Up @@ -4,13 +4,19 @@ envlist = py39, flake8, black
[testenv]
deps =
pytest
responses
-r requirements.txt
commands =
pytest -s {posargs}
setenv =
AWS_ACCESS_KEY_ID = mock
AWS_SECRET_ACCESS_KEY = mock
SERVICE_NAME=lambda-boilerplate
SERVICE_NAME=mock-maskinporten-api
TEAMS_API_URL=http://api.teams.mock
KEYCLOAK_SERVER = http://keycloak.mock
KEYCLOAK_REALM = mock-realm
CLIENT_ID = mock-maskinporten-api
CLIENT_SECRET = abc123

[testenv:flake8]
skip_install = true
Expand Down

0 comments on commit 7d8d27b

Please sign in to comment.