def test_verify_success_without_validated_registered_claims(self): """ Test verifying a valid token without registered claims that are validated (exp, iss, nbf), using the correct key. Expected Result: An object representing the token is returned. """ easyjwt_creation = EasyJWT(self.key) easyjwt_creation.JWT_ID = self.JWT_ID easyjwt_creation.subject = self.subject token = easyjwt_creation.create() easyjwt_verification = EasyJWT.verify(token, self.key) self.assertIsNotNone(easyjwt_verification) self.assertEqual(easyjwt_creation._key, easyjwt_verification._key) self.assertEqual(easyjwt_creation.audience, easyjwt_verification.audience) self.assertEqual(easyjwt_creation.expiration_date, easyjwt_verification.expiration_date) self.assertEqual(easyjwt_creation.issued_at_date, easyjwt_verification.issued_at_date) self.assertEqual(easyjwt_creation.issuer, easyjwt_verification.issuer) self.assertEqual(easyjwt_creation.JWT_ID, easyjwt_verification.JWT_ID) self.assertEqual(easyjwt_creation.not_before_date, easyjwt_verification.not_before_date) self.assertEqual(easyjwt_creation.subject, easyjwt_verification.subject) self.assertEqual(easyjwt_creation._easyjwt_class, easyjwt_verification._easyjwt_class)
def test_algorithms_supported(self): """ Test that the algorithms in the enum are actually supported. Expected result: All algorithms specified in the enum can encode and decode the token. """ key = 'abcdefghijklmnopqrstuvwxyz' # noinspection PyTypeChecker for algorithm in list(Algorithm): # Set the algorithm on the class so it is used for decoding. EasyJWT.algorithm = algorithm easyjwt_creation = EasyJWT(key) # Encode the token with the current algorithm. token = easyjwt_creation.create() self.assertEqual(algorithm, easyjwt_creation.algorithm, msg=f'Algorithm {algorithm} not set on token') self.assertIsNotNone( token, msg=f'Failed to encode token with algorithm {algorithm}') # Decode the token with the current algorithm. easyjwt_verification = EasyJWT.verify(token, key) self.assertEqual(algorithm, easyjwt_verification.algorithm, msg=f'Algorithm {algorithm} not set on token') self.assertIsNotNone( easyjwt_verification, msg=f'Failed to decode token with algorithm {algorithm}')
def test_verify_success_lenient_verification(self): """ Test verifying a token without the `_easyjwt_class` claim with strict verification disabled. Expected Result: The token is successfully verified and an object representing the token is returned. """ EasyJWT.strict_verification = False easyjwt_creation = EasyJWT(self.key) easyjwt_creation.JWT_ID = self.JWT_ID easyjwt_creation.subject = self.subject token = easyjwt_creation.create() easyjwt_verification = EasyJWT.verify(token, self.key) self.assertIsNotNone(easyjwt_verification) self.assertEqual(easyjwt_creation._key, easyjwt_verification._key) self.assertEqual(easyjwt_creation.audience, easyjwt_verification.audience) self.assertEqual(easyjwt_creation.expiration_date, easyjwt_verification.expiration_date) self.assertEqual(easyjwt_creation.issued_at_date, easyjwt_verification.issued_at_date) self.assertEqual(easyjwt_creation.issuer, easyjwt_verification.issuer) self.assertEqual(easyjwt_creation.JWT_ID, easyjwt_verification.JWT_ID) self.assertEqual(easyjwt_creation.not_before_date, easyjwt_verification.not_before_date) self.assertEqual(easyjwt_creation.subject, easyjwt_verification.subject) self.assertNotIn('_easyjwt_class', vars(easyjwt_verification))
def test_create_success_lenient_verification(self): """ Test creating a token with strict verification disabled. Expected Result: A token is created successfully. The create token can be decoded. """ EasyJWT.strict_verification = False easyjwt = EasyJWT(self.key) easyjwt.expiration_date = self.expiration_date easyjwt.issuer = self.issuer easyjwt.JWT_ID = self.JWT_ID easyjwt.not_before_date = self.not_before_date easyjwt.subject = self.subject token = easyjwt.create() self.assertIsNotNone(token) self.assertIsNotNone(easyjwt.issued_at_date) claim_set = decode(token, self.key, algorithms=easyjwt._get_decode_algorithms()) self.assertIsNotNone(claim_set)
def test_str(self): """ Test converting the object to a string. Expected Result: The token is returned as if `create()` had been called. """ easyjwt = EasyJWT(self.key) # Note: If this assertion ever fails it might be because the issued-at date is set within `create()` and the # difference between the two calls is too large. self.assertEqual(easyjwt.create(), str(easyjwt))
def test_verify_failure_invalid_issued_at(self): """ Test verifying a token with an invalid issued-at date. Expected Result: An `InvalidIssuedAtError` is raised. """ easyjwt_creation = EasyJWT(self.key) # noinspection PyTypeChecker token = easyjwt_creation.create(issued_at='NaN') with self.assertRaises(InvalidIssuedAtError): easyjwt_verification = EasyJWT.verify(token, self.key) self.assertIsNone(easyjwt_verification)
def test_verify_failure_invalid_signature(self): """ Test verifying a token using an invalid key. Expected Result: An `InvalidSignatureError` error is raised. """ easyjwt_creation = EasyJWT(self.key) token = easyjwt_creation.create() key = 'invalid-' + self.key with self.assertRaises(InvalidSignatureError): easyjwt_verification = EasyJWT.verify(token, key) self.assertIsNone(easyjwt_verification)
def test_verify_failure_invalid_audience_no_audience_expected(self): """ Test verifying a token with an audience claim, but without expecting one when verifying the token. Expected Result: An `InvalidAudienceError` is raised. """ easyjwt_creation = EasyJWT(self.key) easyjwt_creation.audience = self.audience token = easyjwt_creation.create() with self.assertRaises(InvalidAudienceError): easyjwt_verification = EasyJWT.verify(token, self.key) self.assertIsNone(easyjwt_verification)
def test_verify_failure_not_yet_valid_token(self): """ Test verifying a token that is not yet valid. Expected Result: An `ImmatureTokenError` error is raised. """ easyjwt_creation = EasyJWT(self.key) easyjwt_creation.not_before_date = self.not_before_date + timedelta( minutes=15) token = easyjwt_creation.create() with self.assertRaises(ImmatureTokenError): easyjwt_verification = EasyJWT.verify(token, self.key) self.assertIsNone(easyjwt_verification)
def test_verify_failure_expired_token(self): """ Test verifying an expired token. Expected Result: An `ExpiredTokenError` error is raised. """ easyjwt_creation = EasyJWT(self.key) easyjwt_creation.expiration_date = self.expiration_date - timedelta( minutes=30) token = easyjwt_creation.create() with self.assertRaises(ExpiredTokenError): easyjwt_verification = EasyJWT.verify(token, self.key) self.assertIsNone(easyjwt_verification)
def test_verify_failure_missing_issuer(self): """ Test verifying a token without giving an issuer. Expected Result: An `InvalidIssuerError` is raised. """ easyjwt_creation = EasyJWT(self.key) token = easyjwt_creation.create() with self.assertRaises(InvalidClaimSetError) as exception_cm: easyjwt_verification = EasyJWT.verify(token, self.key, issuer=self.issuer) self.assertIsNone(easyjwt_verification) self.assertSetEqual({'issuer'}, exception_cm.exception.missing_claims)
def test_verify_failure_invalid_issuer(self): """ Test verifying a token with an invalid issuer. Expected Result: An `InvalidIssuerError` is raised. """ easyjwt_creation = EasyJWT(self.key) easyjwt_creation.issuer = self.issuer token = easyjwt_creation.create() invalid_issuer = 'Impersonating ' + self.issuer with self.assertRaises(InvalidIssuerError): easyjwt_verification = EasyJWT.verify(token, self.key, issuer=invalid_issuer) self.assertIsNone(easyjwt_verification)
def test_verify_failure_invalid_audience_wrong_type(self): """ Test verifying a token with an audience claim, but giving an audience of a wrong type. Expected Result: An `InvalidAudienceError` is raised. """ easyjwt_creation = EasyJWT(self.key) easyjwt_creation.audience = self.audience token = easyjwt_creation.create() with self.assertRaises(InvalidAudienceError): # noinspection PyTypeChecker easyjwt_verification = EasyJWT.verify(token, self.key, audience=42.1337) self.assertIsNone(easyjwt_verification)
def test_verify_failure_invalid_audience_no_audience_in_token(self): """ Test verifying a token without an audience claim, but expecting one. Expected Result: An `InvalidClaimSetError` is raised. """ easyjwt_creation = EasyJWT(self.key) token = easyjwt_creation.create() with self.assertRaises(InvalidClaimSetError) as exception_cm: easyjwt_verification = EasyJWT.verify(token, self.key, audience=self.audience) self.assertIsNone(easyjwt_verification) self.assertIn('audience', exception_cm.exception.missing_claims)
def test_create_failure_missing_required_claims(self): """ Test creating a token if required claims are empty. Expected Result: An `MissingRequiredClaimsError` error is raised. """ # Unset the claim for the EasyJWT class which is always required. easyjwt = EasyJWT(self.key) easyjwt._easyjwt_class = None self.assertTrue(easyjwt._is_claim('_easyjwt_class')) with self.assertRaises(MissingRequiredClaimsError) as exception_cm: token = easyjwt.create() self.assertIsNone(token) self.assertEqual('Required empty claims: {_easyjwt_class}', str(exception_cm.exception))
def test_verify_failure_verification_error(self): """ Test verifying a token with an expiration date claim that is not an integer. Expected Result: A `VerificationError` is raised. """ # Create the token with a string expiration date. easyjwt_creation = EasyJWT(self.key) easyjwt_creation.expiration_date = 'January 1, 2019 12:34.56' token = easyjwt_creation.create() # Try to verify the token. with self.assertRaises(VerificationError) as exception_cm: easyjwt_verification = EasyJWT.verify(token, self.key) self.assertIsNone(easyjwt_verification) self.assertEqual('Expiration Time claim (exp) must be an integer.', str(exception_cm.exception))
def test_create_failure_incompatible_key(self): """ Test creating a token using an incompatible key. Expected Result: An `IncompatibleKeyError` error is raised. """ # Ensure that the algorithm needs an HMAC key. Provide an asymmetric key instead. incompatible_key = '-----BEGIN PUBLIC KEY-----' self.assertIn(EasyJWT.algorithm, {Algorithm.HS256, Algorithm.HS384, Algorithm.HS512}) easyjwt = EasyJWT(incompatible_key) with self.assertRaises(IncompatibleKeyError) as exception_cm: token = easyjwt.create() self.assertIsNone(token) message = 'The specified key is an asymmetric key or x509 certificate and should not be used as an HMAC secret.' self.assertEqual(message, str(exception_cm.exception))
def test_verify_failure_invalid_claim_set(self): """ Test verifying a token with unsupported claims. Expected Result: An `InvalidClaimSetError` error is raised. """ easyjwt_creation = EasyJWT(self.key) # Add some claim to the object that is not part of the class. fake_claim = 'part_of_the_claim_set' easyjwt_creation.part_of_the_claim_set = True self.assertTrue(easyjwt_creation._is_claim(fake_claim)) token = easyjwt_creation.create() with self.assertRaises(InvalidClaimSetError) as exception_cm: easyjwt_verification = EasyJWT.verify(token, self.key) self.assertIsNone(easyjwt_verification) self.assertIn(fake_claim, str(exception_cm.exception))
def test_create_success_without_issued_at_date(self): """ Test creating a token without specifying an issued-at date. Expected Result: A token is created. The created token can be decoded. """ easyjwt = EasyJWT(self.key) easyjwt.expiration_date = self.expiration_date easyjwt.issuer = self.issuer easyjwt.JWT_ID = self.JWT_ID easyjwt.not_before_date = self.not_before_date easyjwt.subject = self.subject token = easyjwt.create() self.assertIsNotNone(token) self.assertIsNotNone(easyjwt.issued_at_date) claim_set = decode(token, self.key, algorithms=easyjwt._get_decode_algorithms()) self.assertIsNotNone(claim_set)
def test_verify_failure_unsupported_algorithm(self): """ Test verifying a token with an incompatible algorithm. Expected Result: An `UnsupportedAlgorithmError` is raised. """ # Save the default algorithm to restore it later. encoding_algorithm = EasyJWT.algorithm easyjwt_creation = EasyJWT(self.key) token = easyjwt_creation.create() # Change the algorithm for now so that the one used for creation is not supported. EasyJWT.algorithm = Algorithm.HS512 self.assertNotEqual(encoding_algorithm, EasyJWT.algorithm) # Try to verify the token. with self.assertRaises(UnsupportedAlgorithmError): easyjwt_verification = EasyJWT.verify(token, self.key) self.assertIsNone(easyjwt_verification) # Restore the default algorithm on the class to prevent side effect on other parts of the tests. EasyJWT.algorithm = encoding_algorithm