Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Revert "Revert "WAZO-67 refresh token""
This reverts commit 711d8f9.
- Loading branch information
Showing
26 changed files
with
531 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,3 +12,4 @@ nosetests.xml | |
pep8.txt | ||
pylint.txt | ||
pycodestyle.txt | ||
unit-tests.xml |
38 changes: 38 additions & 0 deletions
38
alembic/versions/7b15f7bd52ba_add_the_refresh_token_table.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
"""add the refresh_token table | ||
Revision ID: 7b15f7bd52ba | ||
Revises: 7c7c2fc280ca | ||
""" | ||
|
||
from alembic import op | ||
import sqlalchemy as sa | ||
from sqlalchemy.schema import Column | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = '7b15f7bd52ba' | ||
down_revision = '7c7c2fc280ca' | ||
|
||
|
||
def upgrade(): | ||
op.create_table( | ||
'auth_refresh_token', | ||
Column( | ||
'uuid', sa.String(36), server_default=sa.text('uuid_generate_v4()'), primary_key=True, | ||
), | ||
Column('client_id', sa.Text), | ||
Column('user_uuid', sa.String(36), sa.ForeignKey('auth_user.uuid', ondelete='CASCADE')), | ||
Column('backend', sa.Text), | ||
Column('login', sa.Text), | ||
Column('user_agent', sa.Text), | ||
Column('remote_addr', sa.Text), | ||
) | ||
op.create_unique_constraint( | ||
'auth_refresh_token_client_id_user_uuid', | ||
'auth_refresh_token', | ||
['client_id', 'user_uuid'], | ||
) | ||
|
||
|
||
def downgrade(): | ||
op.drop_table('auth_refresh_token') |
23 changes: 23 additions & 0 deletions
23
alembic/versions/7c7c2fc280ca_add_the_user_agent_and_remote_addr_to_.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
"""add the user-agent and remote_addr to the token | ||
Revision ID: 7c7c2fc280ca | ||
Revises: 63acf2b9a7b9 | ||
""" | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = '7c7c2fc280ca' | ||
down_revision = '63acf2b9a7b9' | ||
|
||
from alembic import op | ||
import sqlalchemy as sa | ||
|
||
|
||
def upgrade(): | ||
op.add_column('auth_token', sa.Column('user_agent', sa.Text, server_default='', default='')) | ||
op.add_column('auth_token', sa.Column('remote_addr', sa.Text, server_default='', default='')) | ||
|
||
|
||
def downgrade(): | ||
op.drop_column('auth_token', 'remote_addr') | ||
op.drop_column('auth_token', 'user_agent') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# Copyright 2019 The Wazo Authors (see the AUTHORS file) | ||
# SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
from hamcrest import ( | ||
assert_that, | ||
calling, | ||
ends_with, | ||
equal_to, | ||
has_entries, | ||
has_key, | ||
has_properties, | ||
not_, | ||
) | ||
from xivo_test_helpers.hamcrest.raises import raises | ||
|
||
from .helpers.base import WazoAuthTestCase | ||
|
||
|
||
class TestTokens(WazoAuthTestCase): | ||
|
||
def test_that_a_token_has_a_remote_address_and_user_agent(self): | ||
ua = 'My Test Runner' | ||
|
||
post_result = self.client.token.new(expiration=1, user_agent=ua) | ||
assert_that(post_result, has_entries(user_agent=ua, remote_addr=ends_with('.1'))) | ||
# Docker host address are always X.X.X.1 | ||
|
||
get_result = self.client.token.get(post_result['token']) | ||
assert_that(get_result, has_entries(user_agent=ua, remote_addr=ends_with('.1'))) | ||
|
||
def test_refresh_token(self): | ||
client_id = 'my-test' | ||
|
||
result = self.client.token.new(expiration=1, access_type='offline', client_id=client_id) | ||
assert_that(result, has_entries(refresh_token=not_(None))) | ||
|
||
refresh_token = result['refresh_token'] | ||
|
||
result = self.client.token.new( | ||
expiration=1, | ||
refresh_token=refresh_token, | ||
client_id=client_id, | ||
) | ||
assert_that(result, not_(has_key('refresh_token'))) | ||
|
||
def test_that_only_one_refresh_token_exist_for_each_user_uuid_client_id(self): | ||
client_id = 'two-refresh-token' | ||
|
||
result_1 = self.client.token.new(expiration=1, access_type='offline', client_id=client_id) | ||
result_2 = self.client.token.new(expiration=1, access_type='offline', client_id=client_id) | ||
|
||
assert_that(result_1['refresh_token'], equal_to(result_2['refresh_token'])) | ||
|
||
def test_refresh_token_with_the_wrong_client_id(self): | ||
client_id = 'my-test' | ||
|
||
result = self.client.token.new(expiration=1, access_type='offline', client_id=client_id) | ||
assert_that(result, has_entries(refresh_token=not_(None))) | ||
|
||
refresh_token = result['refresh_token'] | ||
|
||
assert_that( | ||
calling(self.client.token.new).with_args( | ||
expiration=1, | ||
refresh_token=refresh_token, | ||
client_id='another-client-id', | ||
), | ||
raises(Exception).matching(has_properties(response=has_properties(status_code=401))) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Copyright 2019 The Wazo Authors (see the AUTHORS file) | ||
# SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
from sqlalchemy import and_, exc | ||
|
||
from wazo_auth import exceptions | ||
|
||
from .base import BaseDAO | ||
from ..models import RefreshToken | ||
|
||
|
||
class RefreshTokenDAO(BaseDAO): | ||
|
||
def create(self, body): | ||
refresh_token = RefreshToken(**body) | ||
with self.new_session() as s: | ||
s.add(refresh_token) | ||
try: | ||
s.flush() | ||
except exc.IntegrityError as e: | ||
if e.orig.pgcode == self._UNIQUE_CONSTRAINT_CODE: | ||
constraint = e.orig.diag.constraint_name | ||
if constraint == 'auth_refresh_token_client_id_user_uuid': | ||
s.rollback() | ||
return self._get_existing_refresh_token( | ||
body['client_id'], body['user_uuid'] | ||
) | ||
raise | ||
|
||
return refresh_token.uuid | ||
|
||
def get(self, refresh_token, client_id): | ||
filter_ = and_(RefreshToken.client_id == client_id, RefreshToken.uuid == refresh_token) | ||
with self.new_session() as s: | ||
query = s.query(RefreshToken).filter(filter_) | ||
for refresh_token in query.all(): | ||
return {'backend_name': refresh_token.backend, 'login': refresh_token.login} | ||
|
||
raise exceptions.UnknownRefreshToken(refresh_token, client_id) | ||
|
||
def _get_existing_refresh_token(self, client_id, user_uuid): | ||
filter_ = and_(RefreshToken.client_id == client_id, RefreshToken.user_uuid == user_uuid) | ||
with self.new_session() as s: | ||
query = s.query(RefreshToken).filter(filter_) | ||
for refresh_token in query.all(): | ||
return refresh_token.uuid |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.