def use_jti_claim(jti_claim: str, expires_at: datetime) -> None: """ Use a jti claim :param jti_claim: jti claim to mark as used. :param expires_at: the datetime at which the jti claim expires. :raises ValueError: when jti_claim is None. :raises TypeError: when jti_claim is not a valid uuid4. :raises JtiTokenUsed: when jti_claim has already been used. """ if jti_claim is None: raise ValueError if not is_valid_uuid(jti_claim): logger.info("jti claim is invalid", jti_claim=jti_claim) raise TypeError try: # Make claim expire a little later than exp to avoid race conditions with out of sync clocks. expires_at += timedelta(seconds=60) jti = UsedJtiClaim(jti_claim, expires_at) current_app.eq["ephemeral_storage"].put( jti, overwrite=False) # type: ignore except ItemAlreadyExistsError as e: logger.error("jti claim has already been used", jti_claim=jti_claim) raise JtiTokenUsed(jti_claim) from e
def test_duplicate_put_jti_fails(self): used_at = datetime.now(tz=timezone.utc) expires_at = used_at + timedelta(seconds=60) jti = UsedJtiClaim(str(uuid.uuid4()), expires_at) self.redis.put(jti, overwrite=False) with self.assertRaises(ItemAlreadyExistsError): self.redis.put(jti, overwrite=False)
def test_put_jti_stores_empty_value(self): used_at = datetime.now(tz=timezone.utc) expires_at = used_at + timedelta(seconds=60) jti = UsedJtiClaim(str(uuid.uuid4()), expires_at) self.redis.put(jti, overwrite=False) stored_data = self.mock_client.get(jti.jti_claim) self.assertEqual(b"", stored_data)
def test_delete_handles_connection_error_once(self): # Given used_at = datetime.now(tz=timezone.utc) expires_at = used_at + timedelta(seconds=60) jti = UsedJtiClaim(str(uuid.uuid4()), expires_at) self.redis.client.delete = mock.Mock( side_effect=[RedisConnectionError, RedisConnectionError]) # When with self.assertRaises(RedisConnectionError): self.redis.delete(jti) # Then assert self.redis.client.delete.call_count == 2
def test_put_handles_connection_error_once(self): # Given used_at = datetime.now() expires_at = used_at + timedelta(seconds=60) jti = UsedJtiClaim(str(uuid.uuid4()), expires_at) self.redis.client.set = mock.Mock( side_effect=[RedisConnectionError, RedisConnectionError]) # When with self.assertRaises(RedisConnectionError): self.redis.put(jti, overwrite=False) # Then assert self.redis.client.set.call_count == 2
def test_used_jti_claim(): model = UsedJtiClaim("claimid", NOW) assert create_model(model).__dict__ == model.__dict__
def test_used_jti_claim(self): self._test_model(UsedJtiClaim("claimid", NOW))