from datetime import datetime, timedelta, timezone import uuid import jwt import pytest from atlas_um.tokens.bearer_tokens import DNABearerToken, M2MBearerToken from tests.atlas_um.factories import ClaimValueFactory class TestDNABearerToken: JWT_TOKEN_KID = str(uuid.uuid4()) @pytest.fixture def app_config(self): def inner(app): app.config["JWT_TOKEN_KID"] = self.JWT_TOKEN_KID return inner @pytest.fixture def decoder(self, app): key = app.config["DNA_IDENTITY_PUBLIC_KEY"] def inner(token): return jwt.decode(token, key, algorithms="RS256") return inner @pytest.fixture def now(self): return datetime.now(timezone.utc) def test_default_ttl(self, dna_account, pgdb_session): token = DNABearerToken(dna_account) assert token.ttl == token.DEFAULT_TIME_TO_LIVE def test_ttl(self, dna_account, pgdb_session, faker): ttl = faker.pyint() token = DNABearerToken(dna_account, ttl=ttl) assert token.ttl == ttl def test_sub_from_dna_account(self, dna_account, now, pgdb_session): token = DNABearerToken(dna_account) assert token.claimset_at(now)["sub"] == dna_account.sub assert token.claimset_at(now)["email"] == dna_account.email assert token.claimset_at(now)["name"] == dna_account.name def test_kid(self, dna_account, now, pgdb_session): encoded = DNABearerToken(dna_account).encode() assert jwt.get_unverified_header(encoded)["kid"] == self.JWT_TOKEN_KID def test_iat_is_now(self, dna_account, now, pgdb_session): token = DNABearerToken(dna_account) assert token.claimset_at(now)["iat"] == int(now.timestamp()) def test_exp_is_in_5_min(self, dna_account, now, pgdb_session): token = DNABearerToken(dna_account) exp_time = now + timedelta(minutes=5) assert token.claimset_at(now)["exp"] == int(exp_time.timestamp()) def test_nbf_is_now(self, dna_account, now, pgdb_session): token = DNABearerToken(dna_account) assert token.claimset_at(now)["nbf"] == int(now.timestamp()) def test_encoding_roundtrip_preserves_claims( self, decoder, dna_account, now, pgdb_session ): token = DNABearerToken(dna_account) assert token.claimset_at(now) == decoder(token.encode_at(now)) def test_claims_no_resoure_group( self, app, dna_account, now, pgdb_session ): test_claim = ClaimValueFactory.build() dna_account.claim_values = [test_claim] pgdb_session.add(dna_account) pgdb_session.commit() token = DNABearerToken(dna_account) claimset = token.claimset_at(now) assert claimset["sub"] == dna_account.sub assert claimset["email"] == dna_account.email assert claimset["name"] == dna_account.name assert test_claim.claim_name.url in claimset def test_claims_with_resource_group( self, app, dna_account, now, pgdb_session ): test_claim1 = ClaimValueFactory.build() test_claim2 = ClaimValueFactory.build() dna_account.claim_values = [test_claim1, test_claim2] pgdb_session.add(dna_account) pgdb_session.commit() token = DNABearerToken( dna_account, test_claim1.claim_name.resource_group ) claimset = token.claimset_at(now) assert claimset["sub"] == dna_account.sub assert claimset["email"] == dna_account.email assert claimset["name"] == dna_account.name assert test_claim1.claim_name.url in claimset assert test_claim2.claim_name.url not in claimset class TestMMBearerToken: JWT_TOKEN_KID = str(uuid.uuid4()) @pytest.fixture def app_config(self): def inner(app): app.config["JWT_TOKEN_KID"] = self.JWT_TOKEN_KID return inner @pytest.fixture def decoder(self, app): key = app.config["DNA_IDENTITY_PUBLIC_KEY"] def inner(token, audience=None): return jwt.decode( token, key, algorithms="RS256", audience=audience ) return inner @pytest.fixture def now(self): return datetime.now(timezone.utc) def test_default_ttl(self, application, pgdb_session): application.ttl = 0 token = M2MBearerToken(application) assert token.ttl == token.DEFAULT_TIME_TO_LIVE def test_application_ttl(self, application, pgdb_session, faker): token = M2MBearerToken(application) assert token.ttl == application.ttl def test_ttl(self, application, pgdb_session, faker): ttl = faker.pyint() token = M2MBearerToken(application, ttl=ttl) assert token.ttl == ttl def test_sub_from_dna_account(self, application, now, pgdb_session): token = M2MBearerToken(application) assert token.claimset_at(now)["sub"] == application.client_id assert token.claimset_at(now)["name"] == application.name def test_kid(self, application, now, pgdb_session): encoded = M2MBearerToken(application).encode() assert jwt.get_unverified_header(encoded)["kid"] == self.JWT_TOKEN_KID def test_iat_is_now(self, application, now, pgdb_session): token = M2MBearerToken(application) assert token.claimset_at(now)["iat"] == int(now.timestamp()) def test_nbf_is_now(self, application, now, pgdb_session): token = M2MBearerToken(application) assert token.claimset_at(now)["nbf"] == int(now.timestamp()) def test_encoding_roundtrip_preserves_claims( self, decoder, application, now, pgdb_session ): token = M2MBearerToken(application) assert token.claimset_at(now) == decoder( token.encode_at(now), audience=application.token_audience ) def test_claims(self, app, application, now, pgdb_session): token = M2MBearerToken(application) claimset = token.claimset_at(now) assert claimset["sub"] == application.client_id assert claimset["name"] == application.name assert claimset["aud"] == application.token_audience assert claimset["scope"] == application.scope