import pytest from flask import g from werkzeug.http import dump_cookie from atlas_um import consts from atlas_um.auth import AuthManager from atlas_um.auth.claims import Audience from atlas_um.auth.models import User, AnonymousUser from atlas_um.tokens.bearer_tokens import DNABearerToken from tests.atlas_um.factories import DNAAccountFactory from .helpers import FakeClaim class TestAuthManager: NAMESPACE = "test_product" @pytest.fixture def app_config(self): def inner(app): app.config["RELATED_CLAIMS_NAMESPACE"] = TestAuthManager.NAMESPACE return inner @pytest.fixture def fake_token(self, app, pgdb_session): return DNABearerToken(DNAAccountFactory.build()) def test_init_app(self, mocker): app = mocker.MagicMock() manager = AuthManager() manager.init_app(app) assert app.auth_manager == manager assert app.after_request.call_args_list == [ mocker.call(manager._load_user) ] def test_get_token_dev_token_enabled(self, app, faker): app.config["DEV_TOKEN_ENABLED"] = True fake_token = faker.pystr() with app.test_request_context( path=f"/?{consts.DEV_TOKEN_PARAM}={fake_token}" ): token = app.auth_manager._get_token() assert token == fake_token def test_get_token_dev_token_disabled(self, app, faker): app.config["DEV_TOKEN_ENABLED"] = False fake_token = faker.pystr() with app.test_request_context( path=f"/?{consts.DEV_TOKEN_PARAM}={fake_token}" ): token = app.auth_manager._get_token() assert token == "" def test_get_token_cookie(self, app, faker): fake_token = faker.pystr() header = dump_cookie( app.config.get("DNA_BEARER_TOKEN_COOKIE_NAME"), fake_token ) with app.test_request_context(environ_base={"HTTP_COOKIE": header}): token = app.auth_manager._get_token() assert token == fake_token def test_get_token_auth_header(self, app, faker): fake_token = faker.pystr() with app.test_request_context( environ_base={"HTTP_AUTHORIZATION": f"Bearer {fake_token}"} ): token = app.auth_manager._get_token() assert token == fake_token def test_get_validation_params_aud(self, app, mocker): test_claimset = { "aud": "test_aud", f"{self.NAMESPACE}/{FakeClaim.path}": { FakeClaim.value_field: FakeClaim.Values.test_value1.value }, "other_product/other_path": { "id": "other_id", "slug": "other_slug", }, } mocked_jwt_decode = mocker.patch("jwt.decode") mocked_jwt_decode.return_value = test_claimset assert app.auth_manager._get_validation_params(test_claimset) == { "audience": Audience.Values.list() } def test_get_validation_params_no_aud(self, app, mocker): test_claimset = { f"{self.NAMESPACE}/{FakeClaim.path}": { FakeClaim.value_field: FakeClaim.Values.test_value1.value }, "other_product/other_path": { "id": "other_id", "slug": "other_slug", }, } mocked_jwt_decode = mocker.patch("jwt.decode") mocked_jwt_decode.return_value = test_claimset assert app.auth_manager._get_validation_params(test_claimset) == {} def test_get_assigned_claims(self, app): test_claimset = { f"{self.NAMESPACE}/{FakeClaim.path}": { FakeClaim.value_field: FakeClaim.Values.test_value1.value }, "other_product/other_path": { "id": "other_id", "slug": "other_slug", }, } expected_claims = [FakeClaim(FakeClaim.Values.test_value1)] actual_claims = app.auth_manager._get_assigned_claims(test_claimset) assert actual_claims == expected_claims def test_update_request_context_with_user_empty(self, app, faker): with app.test_request_context(): app.auth_manager._update_request_context_with_user(None) g.user = AnonymousUser() def test_update_request_context_with_user_non_empty(self, app, faker): with app.test_request_context(): user = User(faker.pystr(), []) app.auth_manager._update_request_context_with_user(user) g.user = user def test_load_user_failure_no_token(self, app, mocker): with app.test_request_context(): mocked_anonymous = mocker.patch( "atlas_um.auth.models.AnonymousUser" ).return_value expected_response = mocker.MagicMock() mocked_update_request_context_with_user = mocker.patch( "atlas_um.auth.manager.AuthManager." "_update_request_context_with_user" ) actual_response = app.auth_manager._load_user(expected_response) assert expected_response == actual_response assert mocked_update_request_context_with_user.call_args_list == [ mocker.call(mocked_anonymous) ] def test_load_user_failure_invalid_token(self, app, mocker, fake_token): # real like token with not matching signature corrupted_token = fake_token.encode()[:-1] header = dump_cookie( app.config.get("DNA_BEARER_TOKEN_COOKIE_NAME"), corrupted_token ) mocked_anonymous = mocker.patch( "atlas_um.auth.models.AnonymousUser" ).return_value with app.test_request_context(environ_base={"HTTP_COOKIE": header}): expected_response = mocker.MagicMock() mocked_update_request_context_with_user = mocker.patch( "atlas_um.auth.manager.AuthManager." "_update_request_context_with_user" ) mocked_jwt_decode = mocker.patch("jwt.decode") actual_response = app.auth_manager._load_user(expected_response) assert mocked_jwt_decode.call_args_list == [ mocker.call( corrupted_token, options={"verify_signature": False} ), mocker.call( corrupted_token, app.config["DNA_IDENTITY_PUBLIC_KEY"], DNABearerToken.ENCODING_ALGORITHM, ), ] assert expected_response == actual_response assert mocked_update_request_context_with_user.call_args_list == [ mocker.call(mocked_anonymous) ] def test_load_user_success(self, app, mocker, fake_token): expected_user = User(fake_token.dna_account.sub, []) header = dump_cookie( app.config.get("DNA_BEARER_TOKEN_COOKIE_NAME"), fake_token.encode() ) with app.test_request_context(environ_base={"HTTP_COOKIE": header}): expected_response = mocker.MagicMock() mocked_update_request_context_with_user = mocker.patch( "atlas_um.auth.manager.AuthManager." "_update_request_context_with_user" ) actual_response = app.auth_manager._load_user(expected_response) assert expected_response == actual_response assert mocked_update_request_context_with_user.call_args_list == [ mocker.call(expected_user) ]