def test_only_tink_output_prefix_type_encodes_a_kid_header(self): handle = tink.new_keyset_handle(jwt.raw_jwt_hs256_template()) jwt_mac = handle.primitive(jwt.JwtMac) tink_handle = _change_output_prefix_to_tink(handle) tink_jwt_mac = tink_handle.primitive(jwt.JwtMac) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) token = jwt_mac.compute_mac_and_encode(raw_jwt) token_with_kid = tink_jwt_mac.compute_mac_and_encode(raw_jwt) _, header, _, _ = _jwt_format.split_signed_compact(token) self.assertNotIn('kid', _json_util.json_loads(header)) _, header_with_kid, _, _ = _jwt_format.split_signed_compact( token_with_kid) self.assertIn('kid', _json_util.json_loads(header_with_kid)) validator = jwt.new_validator(expected_issuer='issuer', allow_missing_expiration=True) jwt_mac.verify_mac_and_decode(token, validator) tink_jwt_mac.verify_mac_and_decode(token_with_kid, validator) # With output prefix type RAW, a kid header is ignored jwt_mac.verify_mac_and_decode(token_with_kid, validator) # With output prefix type TINK, a kid header is required. with self.assertRaises(tink.TinkError): tink_jwt_mac.verify_mac_and_decode(token, validator) other_handle = _change_key_id(tink_handle) other_jwt_mac = other_handle.primitive(jwt.JwtMac) # A token with a wrong kid is rejected, even if the signature is ok. with self.assertRaises(tink.TinkError): other_jwt_mac.verify_mac_and_decode(token_with_kid, validator)
def test_raw_key_with_custom_kid_header(self, template): # normal key with output prefix RAW handle = tink.new_keyset_handle(template) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) validator = jwt.new_validator( expected_issuer='issuer', allow_missing_expiration=True) sign = handle.primitive(jwt.JwtPublicKeySign) token = sign.sign_and_encode(raw_jwt) verify = handle.public_keyset_handle().primitive(jwt.JwtPublicKeyVerify) verify.verify_and_decode(token, validator) _, json_header, _, _ = _jwt_format.split_signed_compact(token) self.assertNotIn('kid', _json_util.json_loads(json_header)) # key with a custom_kid set custom_kid_handle = _set_custom_kid(handle, custom_kid=LONG_CUSTOM_KID) custom_kid_sign = custom_kid_handle.primitive(jwt.JwtPublicKeySign) token_with_kid = custom_kid_sign.sign_and_encode(raw_jwt) custom_kid_verify = custom_kid_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) custom_kid_verify.verify_and_decode(token_with_kid, validator) _, header_with_kid, _, _ = _jwt_format.split_signed_compact(token_with_kid) self.assertEqual(_json_util.json_loads(header_with_kid)['kid'], LONG_CUSTOM_KID) # The primitive with a custom_kid set accepts tokens without kid header. custom_kid_verify.verify_and_decode(token, validator) # The primitive without a custom_kid set ignores the kid header. verify.verify_and_decode(token_with_kid, validator) # key with a different custom_kid set other_handle = _set_custom_kid(handle, custom_kid='other kid') other_verify = other_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) # Fails because the kid value do not match. with self.assertRaises(tink.TinkError): other_verify.verify_and_decode(token_with_kid, validator) tink_handle = _change_output_prefix_to_tink(custom_kid_handle) tink_sign = tink_handle.primitive(jwt.JwtPublicKeySign) tink_verify = tink_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) # Having custom_kid set with output prefix TINK is not allowed. with self.assertRaises(tink.TinkError): tink_sign.sign_and_encode(raw_jwt) with self.assertRaises(tink.TinkError): tink_verify.verify_and_decode(token, validator) with self.assertRaises(tink.TinkError): tink_verify.verify_and_decode(token_with_kid, validator)
def test_signed_compact_create_split_with_kid(self): raw_jwt = _raw_jwt.raw_jwt_from_json(None, '{"iss":"joe"}') signature = _jwt_format.decode_signature( b'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk') unsigned_compact = _jwt_format.create_unsigned_compact( 'RS256', 'AZxkm2U', raw_jwt) signed_compact = _jwt_format.create_signed_compact( unsigned_compact, signature) un_comp, hdr, pay, sig = _jwt_format.split_signed_compact( signed_compact) self.assertEqual( unsigned_compact, b'eyJraWQiOiJBWnhrbTJVIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJqb2UifQ') self.assertEqual( signed_compact, 'eyJraWQiOiJBWnhrbTJVIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJqb2UifQ' '.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk') self.assertEqual(un_comp, unsigned_compact) self.assertEqual(sig, signature) self.assertEqual(hdr, '{"kid":"AZxkm2U","alg":"RS256"}') header = _json_util.json_loads(hdr) _jwt_format.validate_header(header, 'RS256') self.assertEqual(pay, '{"iss":"joe"}') self.assertIsNone(_jwt_format.get_type_header(header))
def test_split_signed_compact_success(self): un_comp, hdr, pay, sig = _jwt_format.split_signed_compact( 'e30.e30.YWJj') self.assertEqual(un_comp, b'e30.e30') self.assertEqual(sig, b'abc') self.assertEqual(hdr, '{}') self.assertEqual(pay, '{}')
def test_ps256_key_with_a_custom_kid_header(self): keyset_handle = tink.new_keyset_handle( jwt.raw_jwt_ps256_2048_f4_template()) # Add a custom kid to the key in keyset_handle value = keyset_handle._keyset.key[0].key_data.value pss_key = jwt_rsa_ssa_pss_pb2.JwtRsaSsaPssPrivateKey.FromString(value) pss_key.public_key.custom_kid.value = 'my kid' keyset_handle._keyset.key[ 0].key_data.value = pss_key.SerializeToString() sign = keyset_handle.primitive(jwt.JwtPublicKeySign) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) signed_compact = sign.sign_and_encode(raw_jwt) _, json_header, _, _ = _jwt_format.split_signed_compact(signed_compact) header = _jwt_format.json_loads(json_header) self.assertEqual(header['kid'], 'my kid') # Now, change the output prefix type to TINK. This should fail. keyset_handle._keyset.key[0].output_prefix_type = tink_pb2.TINK with self.assertRaises(tink.TinkError): tink_sign = keyset_handle.primitive(jwt.JwtPublicKeySign) tink_sign.sign_and_encode(raw_jwt)
def test_raw_output_prefix_type_encodes_a_custom_kid_header(self): # normal HMAC jwt_mac with output prefix RAW handle = tink.new_keyset_handle(jwt.raw_jwt_hs256_template()) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) validator = jwt.new_validator(expected_issuer='issuer', allow_missing_expiration=True) jwt_mac = handle.primitive(jwt.JwtMac) token = jwt_mac.compute_mac_and_encode(raw_jwt) jwt_mac.verify_mac_and_decode(token, validator) _, json_header, _, _ = _jwt_format.split_signed_compact(token) self.assertNotIn('kid', _json_util.json_loads(json_header)) # HMAC jwt_mac with a custom_kid set custom_kid_handle = _set_custom_kid(handle, custom_kid='my kid') custom_kid_jwt_mac = custom_kid_handle.primitive(jwt.JwtMac) token_with_kid = custom_kid_jwt_mac.compute_mac_and_encode(raw_jwt) custom_kid_jwt_mac.verify_mac_and_decode(token_with_kid, validator) _, header_with_kid, _, _ = _jwt_format.split_signed_compact( token_with_kid) self.assertEqual( _json_util.json_loads(header_with_kid)['kid'], 'my kid') # Even when custom_kid is set, its not required to be set in the header. custom_kid_jwt_mac.verify_mac_and_decode(token, validator) # An additional kid header is ignored. jwt_mac.verify_mac_and_decode(token_with_kid, validator) other_handle = _set_custom_kid(handle, custom_kid='other kid') other_jwt_mac = other_handle.primitive(jwt.JwtMac) with self.assertRaises(tink.TinkError): # The custom_kid does not match the kid header. other_jwt_mac.verify_mac_and_decode(token_with_kid, validator) tink_handle = _change_output_prefix_to_tink(custom_kid_handle) tink_jwt_mac = tink_handle.primitive(jwt.JwtMac) # having custom_kid set with output prefix TINK is not allowed with self.assertRaises(tink.TinkError): tink_jwt_mac.compute_mac_and_encode(raw_jwt) with self.assertRaises(tink.TinkError): tink_jwt_mac.verify_mac_and_decode(token, validator) with self.assertRaises(tink.TinkError): tink_jwt_mac.verify_mac_and_decode(token_with_kid, validator)
def test_tink_output_prefix_type_encodes_a_kid_header(self): keyset_handle = tink.new_keyset_handle(jwt_es256_tink_template()) sign = keyset_handle.primitive(jwt.JwtPublicKeySign) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) signed_compact = sign.sign_and_encode(raw_jwt) _, json_header, _, _ = _jwt_format.split_signed_compact(signed_compact) header = _jwt_format.json_loads(json_header) self.assertIn('kid', header)
def verify_mac_and_decode( self, compact: Text, validator: _jwt_validator.JwtValidator) -> _verified_jwt.VerifiedJwt: """Verifies, validates and decodes a MACed compact JWT token.""" parts = _jwt_format.split_signed_compact(compact) unsigned_compact, json_header, json_payload, mac = parts self._verify_mac(mac, unsigned_compact) _jwt_format.validate_header(json_header, self._algorithm) raw_jwt = _raw_jwt.RawJwt.from_json_payload(json_payload) _jwt_validator.validate(validator, raw_jwt) return _verified_jwt.VerifiedJwt._create(raw_jwt) # pylint: disable=protected-access
def test_only_tink_output_prefix_type_encodes_a_kid_header(self): handle = tink.new_keyset_handle(jwt.raw_jwt_es256_template()) sign = handle.primitive(jwt.JwtPublicKeySign) verify = handle.public_keyset_handle().primitive(jwt.JwtPublicKeyVerify) tink_handle = _change_output_prefix_to_tink(handle) tink_sign = tink_handle.primitive(jwt.JwtPublicKeySign) tink_verify = tink_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) token = sign.sign_and_encode(raw_jwt) token_with_kid = tink_sign.sign_and_encode(raw_jwt) _, header, _, _ = _jwt_format.split_signed_compact(token) self.assertNotIn('kid', _json_util.json_loads(header)) _, header_with_kid, _, _ = _jwt_format.split_signed_compact(token_with_kid) self.assertIn('kid', _json_util.json_loads(header_with_kid)) validator = jwt.new_validator( expected_issuer='issuer', allow_missing_expiration=True) verify.verify_and_decode(token, validator) tink_verify.verify_and_decode(token_with_kid, validator) other_handle = _change_key_id(tink_handle) other_verify = other_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) verify.verify_and_decode(token_with_kid, validator) # For output prefix type TINK, the kid header is required. with self.assertRaises(tink.TinkError): tink_verify.verify_and_decode(token, validator) # This should fail because value of the kid header is wrong. with self.assertRaises(tink.TinkError): other_verify.verify_and_decode(token_with_kid, validator)
def verify_mac_and_decode_with_kid( self, compact: str, validator: _jwt_validator.JwtValidator, kid: Optional[str]) -> _verified_jwt.VerifiedJwt: """Verifies, validates and decodes a MACed compact JWT token.""" parts = _jwt_format.split_signed_compact(compact) unsigned_compact, json_header, json_payload, mac = parts self._verify_mac(mac, unsigned_compact) header = _json_util.json_loads(json_header) _jwt_format.validate_header(header=header, algorithm=self._algorithm, tink_kid=kid, custom_kid=self._custom_kid) raw_jwt = _raw_jwt.raw_jwt_from_json( _jwt_format.get_type_header(header), json_payload) _jwt_validator.validate(validator, raw_jwt) return _verified_jwt.VerifiedJwt._create(raw_jwt) # pylint: disable=protected-access
def test_signed_compact_create_split(self): payload = '{"iss":"joe"}' signature = _jwt_format.decode_signature( b'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk') unsigned_compact = _jwt_format.create_unsigned_compact( 'RS256', payload) signed_compact = _jwt_format.create_signed_compact( unsigned_compact, signature) un_comp, hdr, pay, sig = _jwt_format.split_signed_compact( signed_compact) self.assertEqual(unsigned_compact, b'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UifQ') self.assertEqual( signed_compact, 'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UifQ.' 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk') self.assertEqual(un_comp, unsigned_compact) self.assertEqual(sig, signature) self.assertEqual(hdr, '{"alg":"RS256"}') _jwt_format.validate_header(hdr, 'RS256') self.assertEqual(pay, payload)
def test_signed_compact_create_split(self): payload = '{"iss":"joe"}' signature = _jwt_format.decode_signature( b'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk') unsigned_compact = _jwt_format.create_unsigned_compact( 'RS256', 'JWT', None, payload) signed_compact = _jwt_format.create_signed_compact(unsigned_compact, signature) un_comp, hdr, pay, sig = _jwt_format.split_signed_compact(signed_compact) self.assertEqual( unsigned_compact, b'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJqb2UifQ') self.assertEqual( signed_compact, 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.' 'eyJpc3MiOiJqb2UifQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk') self.assertEqual(un_comp, unsigned_compact) self.assertEqual(sig, signature) self.assertEqual(hdr, '{"alg":"RS256","typ":"JWT"}') header = _jwt_format.json_loads(hdr) _jwt_format.validate_header(header, 'RS256') self.assertEqual(pay, payload) self.assertEqual(_jwt_format.get_type_header(header), 'JWT')
def test_raw_output_prefix_type_encodes_a_custom_kid_header(self): keyset_handle = tink.new_keyset_handle(jwt.raw_jwt_hs256_template()) # Add a custom kid to the key in keyset_handle value = keyset_handle._keyset.key[0].key_data.value hmac_key = jwt_hmac_pb2.JwtHmacKey.FromString(value) hmac_key.custom_kid.value = 'my kid' keyset_handle._keyset.key[ 0].key_data.value = hmac_key.SerializeToString() jwt_mac = keyset_handle.primitive(jwt.JwtMac) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) signed_compact = jwt_mac.compute_mac_and_encode(raw_jwt) _, json_header, _, _ = _jwt_format.split_signed_compact(signed_compact) header = _jwt_format.json_loads(json_header) self.assertEqual(header['kid'], 'my kid') # Now, change the output prefix type to TINK. This should fail. keyset_handle._keyset.key[0].output_prefix_type = tink_pb2.TINK with self.assertRaises(tink.TinkError): tink_jwt_mac = keyset_handle.primitive(jwt.JwtMac) tink_jwt_mac.compute_mac_and_encode(raw_jwt)
def test_split_signed_compact_with_invalid_utf8_in_header(self): encoded_header = _jwt_format.base64_encode( b'{"alg":"RS256", "bad":"\xc2"}') token = (encoded_header + b'.e30.YWJj').decode('utf8') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact(token)
def test_split_signed_compact_with_bad_characters_fails(self): with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('{e30.e30.YWJj') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact(' e30.e30.YWJj') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('e30. e30.YWJj') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('e30.e30.YWJj ') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('e30.e30.\nYWJj') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('e30.\re30.YWJj') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('e30$.e30.YWJj') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('e30.$e30.YWJj') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('e30.e30.YWJj$') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('e30.e30.YWJj\ud83c')
def test_split_signed_compact_with_bad_format_fails(self): with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('e30.e30.YWJj.abc') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('e30.e30.YWJj.') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('.e30.e30.YWJj') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('.e30.e30.') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('e30') with self.assertRaises(_jwt_error.JwtInvalidError): _jwt_format.split_signed_compact('')
def test_split_empty_signed_compact(self): un_comp, hdr, pay, sig = _jwt_format.split_signed_compact('..') self.assertEqual(un_comp, b'.') self.assertEmpty(sig) self.assertEmpty(hdr) self.assertEmpty(pay)