API - add route to get access token
This commit is contained in:
parent
249c975810
commit
64b813a44b
@ -65,3 +65,8 @@ def authorize(auth_user: User) -> Response:
|
|||||||
return authorization_server.create_authorization_response(
|
return authorization_server.create_authorization_response(
|
||||||
grant_user=auth_user
|
grant_user=auth_user
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@oauth_blueprint.route('/oauth/token', methods=['POST'])
|
||||||
|
def issue_token() -> Response:
|
||||||
|
return authorization_server.create_token_response()
|
||||||
|
@ -22,3 +22,19 @@ def assert_errored_response(
|
|||||||
if match is not None:
|
if match is not None:
|
||||||
assert re.match(match, data['message'])
|
assert re.match(match, data['message'])
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def assert_oauth_errored_response(
|
||||||
|
response: TestResponse,
|
||||||
|
status_code: int,
|
||||||
|
error: str,
|
||||||
|
error_description: Optional[str] = None,
|
||||||
|
) -> Dict:
|
||||||
|
assert response.content_type == 'application/json'
|
||||||
|
assert response.status_code == status_code
|
||||||
|
|
||||||
|
data = json.loads(response.data.decode())
|
||||||
|
assert error in data['error']
|
||||||
|
if error_description is not None:
|
||||||
|
assert error_description in data['error_description']
|
||||||
|
return data
|
||||||
|
@ -6,7 +6,10 @@ from flask import Flask
|
|||||||
from flask.testing import FlaskClient
|
from flask.testing import FlaskClient
|
||||||
from werkzeug.test import TestResponse
|
from werkzeug.test import TestResponse
|
||||||
|
|
||||||
from .custom_asserts import assert_errored_response
|
from .custom_asserts import (
|
||||||
|
assert_errored_response,
|
||||||
|
assert_oauth_errored_response,
|
||||||
|
)
|
||||||
from .utils import random_email, random_string
|
from .utils import random_email, random_string
|
||||||
|
|
||||||
|
|
||||||
@ -122,6 +125,28 @@ class ApiTestCaseMixin(RandomMixin):
|
|||||||
response, 500, error_message=error_message, status=status
|
response, 500, error_message=error_message, status=status
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def assert_unsupported_grant_type(response: TestResponse) -> Dict:
|
||||||
|
return assert_oauth_errored_response(
|
||||||
|
response, 400, error='unsupported_grant_type'
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def assert_invalid_client(response: TestResponse) -> Dict:
|
||||||
|
return assert_oauth_errored_response(
|
||||||
|
response,
|
||||||
|
400,
|
||||||
|
error='invalid_client',
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def assert_invalid_request(response: TestResponse) -> Dict:
|
||||||
|
return assert_oauth_errored_response(
|
||||||
|
response,
|
||||||
|
400,
|
||||||
|
error='invalid_request',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CallArgsMixin:
|
class CallArgsMixin:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -5,7 +5,9 @@ from urllib.parse import parse_qs
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
from flask.testing import FlaskClient
|
||||||
from urllib3.util import parse_url
|
from urllib3.util import parse_url
|
||||||
|
from werkzeug.test import TestResponse
|
||||||
|
|
||||||
from fittrackee import db
|
from fittrackee import db
|
||||||
from fittrackee.oauth2.client import create_oauth_client
|
from fittrackee.oauth2.client import create_oauth_client
|
||||||
@ -156,7 +158,7 @@ class TestOAuthClientCreation(OAuth2TestCase):
|
|||||||
('token_endpoint_auth_method', 'client_secret_post'),
|
('token_endpoint_auth_method', 'client_secret_post'),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_it_always_create_oauth_client_with_authorization_grant(
|
def test_it_always_creates_oauth_client_with_authorization_grant(
|
||||||
self,
|
self,
|
||||||
app: Flask,
|
app: Flask,
|
||||||
user_1: User,
|
user_1: User,
|
||||||
@ -258,3 +260,152 @@ class TestOAuthClientAuthorization(OAuth2TestCase):
|
|||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
parsed_url = parse_url(response.location)
|
parsed_url = parse_url(response.location)
|
||||||
assert parse_qs(parsed_url.query).get('code') is not None
|
assert parse_qs(parsed_url.query).get('code') is not None
|
||||||
|
|
||||||
|
|
||||||
|
class TestOAuthIssueToken(OAuth2TestCase):
|
||||||
|
route = '/api/oauth/token'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def assert_token_is_returned(response: TestResponse) -> None:
|
||||||
|
assert response.status_code == 200
|
||||||
|
data = json.loads(response.data.decode())
|
||||||
|
assert data.get('access_token') is not None
|
||||||
|
assert data.get('expires_in') is not None
|
||||||
|
assert data.get('token_type') == 'Bearer'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def authorize_client(
|
||||||
|
client: FlaskClient, oauth_client: OAuth2Client, auth_token: str
|
||||||
|
) -> Union[List[str], str]:
|
||||||
|
response = client.post(
|
||||||
|
'/api/oauth/authorize',
|
||||||
|
data={
|
||||||
|
'client_id': oauth_client.client_id,
|
||||||
|
'response_type': 'code',
|
||||||
|
},
|
||||||
|
headers=dict(
|
||||||
|
Authorization=f'Bearer {auth_token}',
|
||||||
|
content_type='multipart/form-data',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
parsed_url = parse_url(response.location)
|
||||||
|
code = parse_qs(parsed_url.query).get('code', '')
|
||||||
|
return code
|
||||||
|
|
||||||
|
def test_it_returns_error_when_form_is_empty(self, app: Flask) -> None:
|
||||||
|
client = app.test_client()
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
self.route,
|
||||||
|
data=dict(data='{}'),
|
||||||
|
headers=dict(content_type='multipart/form-data'),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assert_unsupported_grant_type(response)
|
||||||
|
|
||||||
|
def test_it_returns_error_when_client_id_is_invalid(
|
||||||
|
self, app: Flask, user_1: User
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
|
app, user_1.email
|
||||||
|
)
|
||||||
|
oauth_client = self.create_oauth_client(user_1)
|
||||||
|
code = self.authorize_client(client, oauth_client, auth_token)
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
self.route,
|
||||||
|
data={
|
||||||
|
'client_id': self.random_string(),
|
||||||
|
'client_secret': oauth_client.client_secret,
|
||||||
|
'grant_type': 'authorization_code',
|
||||||
|
'code': code,
|
||||||
|
},
|
||||||
|
headers=dict(content_type='multipart/form-data'),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assert_invalid_client(response)
|
||||||
|
|
||||||
|
def test_it_returns_error_when_client_secret_is_invalid(
|
||||||
|
self, app: Flask, user_1: User
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
|
app, user_1.email
|
||||||
|
)
|
||||||
|
oauth_client = self.create_oauth_client(user_1)
|
||||||
|
code = self.authorize_client(client, oauth_client, auth_token)
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
self.route,
|
||||||
|
data={
|
||||||
|
'client_id': oauth_client.client_id,
|
||||||
|
'client_secret': self.random_string(),
|
||||||
|
'grant_type': 'authorization_code',
|
||||||
|
'code': code,
|
||||||
|
},
|
||||||
|
headers=dict(content_type='multipart/form-data'),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assert_invalid_client(response)
|
||||||
|
|
||||||
|
def test_it_returns_error_when_client_not_authorized(
|
||||||
|
self, app: Flask, user_1: User
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
|
app, user_1.email
|
||||||
|
)
|
||||||
|
oauth_client = self.create_oauth_client(user_1)
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
self.route,
|
||||||
|
data={
|
||||||
|
'client_id': oauth_client.client_id,
|
||||||
|
'client_secret': oauth_client.client_secret,
|
||||||
|
'grant_type': 'authorization_code',
|
||||||
|
'code': self.random_string(),
|
||||||
|
},
|
||||||
|
headers=dict(content_type='multipart/form-data'),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assert_invalid_request(response)
|
||||||
|
|
||||||
|
def test_it_returns_error_when_code_is_invalid(
|
||||||
|
self, app: Flask, user_1: User
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
|
app, user_1.email
|
||||||
|
)
|
||||||
|
oauth_client = self.create_oauth_client(user_1)
|
||||||
|
self.authorize_client(client, oauth_client, auth_token)
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
self.route,
|
||||||
|
data={
|
||||||
|
'client_id': oauth_client.client_id,
|
||||||
|
'client_secret': oauth_client.client_secret,
|
||||||
|
'grant_type': 'authorization_code',
|
||||||
|
'code': self.random_string(),
|
||||||
|
},
|
||||||
|
headers=dict(content_type='multipart/form-data'),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assert_invalid_request(response)
|
||||||
|
|
||||||
|
def test_it_returns_access_token(self, app: Flask, user_1: User) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
|
app, user_1.email
|
||||||
|
)
|
||||||
|
oauth_client = self.create_oauth_client(user_1)
|
||||||
|
code = self.authorize_client(client, oauth_client, auth_token)
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
self.route,
|
||||||
|
data={
|
||||||
|
'client_id': oauth_client.client_id,
|
||||||
|
'client_secret': oauth_client.client_secret,
|
||||||
|
'grant_type': 'authorization_code',
|
||||||
|
'code': code,
|
||||||
|
},
|
||||||
|
headers=dict(content_type='multipart/form-data'),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assert_token_is_returned(response)
|
||||||
|
Loading…
Reference in New Issue
Block a user