API - init OAuth server and oauth clients creation

This commit is contained in:
Sam
2022-05-27 13:28:26 +02:00
parent c13e9e0286
commit c6cd7ff67c
19 changed files with 700 additions and 1 deletions

View File

@ -10,6 +10,7 @@ os.environ['DATABASE_URL'] = os.environ['DATABASE_TEST_URL']
TEMP_FOLDER = '/tmp/FitTrackee'
os.environ['UPLOAD_FOLDER'] = TEMP_FOLDER
os.environ['APP_LOG'] = TEMP_FOLDER + '/fittrackee.log'
os.environ['AUTHLIB_INSECURE_TRANSPORT'] = '1'
pytest_plugins = [
'fittrackee.tests.fixtures.fixtures_app',

View File

@ -1,4 +1,5 @@
import json
from random import randint
from typing import Any, Dict, Optional, Tuple
from flask import Flask
@ -18,10 +19,18 @@ class RandomMixin:
) -> str:
return random_string(length, prefix, suffix)
@staticmethod
def random_domain() -> str:
return random_string(prefix='https://', suffix='com')
@staticmethod
def random_email() -> str:
return random_email()
@staticmethod
def random_int(min_val: int = 0, max_val: int = 999999) -> int:
return randint(min_val, max_val)
class ApiTestCaseMixin(RandomMixin):
@staticmethod

View File

View File

@ -0,0 +1,137 @@
from time import time
from typing import Dict
from unittest.mock import patch
from flask import Flask
from fittrackee.oauth2.client import create_oauth_client
from fittrackee.oauth2.models import OAuth2Client
from fittrackee.users.models import User
from ..utils import random_domain, random_string
TEST_METADATA = {
'client_name': random_string(),
'client_uri': random_string(),
'redirect_uris': [random_domain()],
'scope': 'read write',
}
class TestCreateOAuth2Client:
def test_it_creates_oauth_client(self, app: Flask, user_1: User) -> None:
oauth_client = create_oauth_client(TEST_METADATA, user_1)
assert isinstance(oauth_client, OAuth2Client)
def test_oauth_client_id_is_generated_with_gen_salt(
self, app: Flask, user_1: User
) -> None:
client_id = random_string()
with patch(
'fittrackee.oauth2.client.gen_salt', return_value=client_id
):
oauth_client = create_oauth_client(TEST_METADATA, user_1)
assert oauth_client.client_id == client_id
def test_oauth_client_client_id_issued_at_is_initialized(
self, app: Flask, user_1: User
) -> None:
client_id_issued_at = int(time())
with patch(
'fittrackee.oauth2.client.time', return_value=client_id_issued_at
):
oauth_client = create_oauth_client(TEST_METADATA, user_1)
assert oauth_client.client_id_issued_at == client_id_issued_at
def test_oauth_client_has_expected_name(
self, app: Flask, user_1: User
) -> None:
client_name = random_string()
client_metadata: Dict = {**TEST_METADATA, 'client_name': client_name}
oauth_client = create_oauth_client(client_metadata, user_1)
assert oauth_client.client_name == client_name
def test_oauth_client_has_expected_client_uri(
self, app: Flask, user_1: User
) -> None:
client_uri = random_domain()
client_metadata: Dict = {**TEST_METADATA, 'client_uri': client_uri}
oauth_client = create_oauth_client(client_metadata, user_1)
assert oauth_client.client_uri == client_uri
def test_oauth_client_has_expected_grant_types(
self, app: Flask, user_1: User
) -> None:
oauth_client = create_oauth_client(TEST_METADATA, user_1)
assert oauth_client.grant_types == ['authorization_code']
def test_oauth_client_has_expected_redirect_uris(
self, app: Flask, user_1: User
) -> None:
redirect_uris = [random_domain()]
client_metadata: Dict = {
**TEST_METADATA,
'redirect_uris': redirect_uris,
}
oauth_client = create_oauth_client(client_metadata, user_1)
assert oauth_client.redirect_uris == redirect_uris
def test_oauth_client_has_expected_response_types(
self, app: Flask, user_1: User
) -> None:
response_types = ['code']
client_metadata: Dict = {
**TEST_METADATA,
'response_types': response_types,
}
oauth_client = create_oauth_client(client_metadata, user_1)
assert oauth_client.response_types == ['code']
def test_oauth_client_has_expected_scope(
self, app: Flask, user_1: User
) -> None:
scope = 'profile'
client_metadata: Dict = {**TEST_METADATA, 'scope': scope}
oauth_client = create_oauth_client(client_metadata, user_1)
assert oauth_client.scope == scope
def test_oauth_client_has_expected_token_endpoint_auth_method(
self, app: Flask, user_1: User
) -> None:
oauth_client = create_oauth_client(TEST_METADATA, user_1)
assert oauth_client.token_endpoint_auth_method == 'client_secret_post'
def test_when_auth_method_is_not_none_oauth_client_secret_is_generated(
self, app: Flask, user_1: User
) -> None:
client_secret = random_string()
with patch(
'fittrackee.oauth2.client.gen_salt', return_value=client_secret
):
oauth_client = create_oauth_client(TEST_METADATA, user_1)
assert oauth_client.client_secret == client_secret
def test_it_creates_oauth_client_for_given_user(
self, app: Flask, user_1: User
) -> None:
oauth_client = create_oauth_client(TEST_METADATA, user_1)
assert oauth_client.user_id == user_1.id

View File

@ -0,0 +1,36 @@
from flask import Flask
from fittrackee.oauth2.models import OAuth2Client
from ..mixins import RandomMixin
class TestOAuthClientSerialize(RandomMixin):
def test_it_returns_oauth_client(self, app: Flask) -> None:
oauth_client = OAuth2Client(
id=self.random_int(),
client_id=self.random_string(),
client_id_issued_at=self.random_int(),
)
oauth_client.set_client_metadata(
{
'client_name': self.random_string(),
'redirect_uris': [self.random_string()],
'client_uri': self.random_domain(),
}
)
serialized_oauth_client = oauth_client.serialize()
assert serialized_oauth_client['client_id'] == oauth_client.client_id
assert (
serialized_oauth_client['client_secret']
== oauth_client.client_secret
)
assert serialized_oauth_client['id'] == oauth_client.id
assert serialized_oauth_client['name'] == oauth_client.client_name
assert (
serialized_oauth_client['redirect_uris']
== oauth_client.redirect_uris
)
assert serialized_oauth_client['website'] == oauth_client.client_uri

View File

@ -0,0 +1,163 @@
import json
from typing import List, Union
from unittest.mock import patch
import pytest
from flask import Flask
from fittrackee.oauth2.models import OAuth2Client
from fittrackee.users.models import User
from ..mixins import ApiTestCaseMixin
from ..utils import random_domain, random_string
TEST_METADATA = {
'client_name': random_string(),
'client_uri': random_domain(),
'redirect_uris': [random_domain()],
'scope': 'read write',
}
class TestOAuthClientCreation(ApiTestCaseMixin):
route = '/api/oauth/apps'
def test_it_returns_error_when_no_user_authenticated(
self, app: Flask, user_1: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email
)
response = client.post(
self.route,
data=json.dumps(TEST_METADATA),
content_type='application/json',
)
self.assert_401(response)
def test_it_returns_error_when_no_metadata_provided(
self, app: Flask, user_1: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email
)
response = client.post(
self.route,
data=json.dumps(dict()),
content_type='application/json',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
self.assert_400(
response, error_message='OAuth client metadata missing'
)
@pytest.mark.parametrize(
'missing_key',
[
'client_name',
'client_uri',
'redirect_uris',
'scope',
],
)
def test_it_returns_error_when_metadata_key_is_missing(
self, app: Flask, user_1: User, missing_key: str
) -> None:
metadata = TEST_METADATA.copy()
del metadata[missing_key]
client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email
)
response = client.post(
self.route,
data=json.dumps(metadata),
content_type='application/json',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
self.assert_400(
response,
error_message=f'OAuth client metadata missing keys: {missing_key}',
)
def test_it_creates_oauth_client(self, app: Flask, user_1: User) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email
)
response = client.post(
self.route,
data=json.dumps(TEST_METADATA),
content_type='application/json',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 201
oauth_client = OAuth2Client.query.first()
assert oauth_client is not None
def test_it_returns_serialized_oauth_client(
self, app: Flask, user_1: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email
)
client_id = self.random_string()
client_secret = self.random_string()
with patch(
'fittrackee.oauth2.client.gen_salt',
side_effect=[client_id, client_secret],
):
response = client.post(
self.route,
data=json.dumps(TEST_METADATA),
content_type='application/json',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert data['data']['client']['client_id'] == client_id
assert data['data']['client']['client_secret'] == client_secret
assert data['data']['client']['name'] == TEST_METADATA['client_name']
assert (
data['data']['client']['redirect_uris']
== TEST_METADATA['redirect_uris']
)
assert data['data']['client']['website'] == TEST_METADATA['client_uri']
@pytest.mark.parametrize(
'input_key,expected_value',
[
('grant_types', ['authorization_code']),
('response_types', ['code']),
('token_endpoint_auth_method', 'client_secret_post'),
],
)
def test_it_always_create_oauth_client_with_authorization_grant(
self,
app: Flask,
user_1: User,
input_key: str,
expected_value: Union[List, str],
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email
)
client.post(
self.route,
data=json.dumps(
{**TEST_METADATA, input_key: self.random_string()}
),
content_type='application/json',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
oauth_client = OAuth2Client.query.first()
assert getattr(oauth_client, input_key) == expected_value

View File

@ -24,6 +24,10 @@ def random_string(
)
def random_domain() -> str:
return random_string(prefix='https://', suffix='.com')
def random_email() -> str:
return random_string(suffix='@example.com')