Esempio n. 1
0
def gen_token(json_header: str, json_payload: str) -> str:
  cc_mac = _cc_mac()
  unsigned_token = (
      _jwt_format.encode_header(json_header) + b'.' +
      _jwt_format.encode_payload(json_payload))
  return _jwt_format.create_signed_compact(unsigned_token,
                                           cc_mac.compute_mac(unsigned_token))
Esempio n. 2
0
def generate_token(header: Text, payload: Text) -> Text:
    """Generates tokens with valid MACs."""
    unsigned_compact = (_jwt_format.encode_header(header) + b'.' +
                        _jwt_format.encode_payload(payload))
    mac_value = MAC.compute_mac(unsigned_compact)
    return (unsigned_compact + b'.' +
            _jwt_format.encode_signature(mac_value)).decode('utf8')
Esempio n. 3
0
 def test_decodeencode_header_rs256(self):
     # Example from https://tools.ietf.org/html/rfc7515#appendix-A.2
     encoded_header = b'eyJhbGciOiJSUzI1NiJ9'
     json_header = _jwt_format.decode_header(encoded_header)
     self.assertEqual(json_header['alg'], 'RS256')
     self.assertEqual(
         _jwt_format.decode_header(_jwt_format.encode_header(json_header)),
         json_header)
Esempio n. 4
0
 def test_decodeencode_header_hs256(self):
     # Example from https://tools.ietf.org/html/rfc7515#appendix-A.1
     encoded_header = b'eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9'
     json_header = _jwt_format.decode_header(encoded_header)
     self.assertEqual(json_header['alg'], 'HS256')
     self.assertEqual(json_header['typ'], 'JWT')
     self.assertEqual(
         _jwt_format.decode_header(_jwt_format.encode_header(json_header)),
         json_header)
Esempio n. 5
0
def create_signed_token(json_header: Text, json_payload: Text) -> Text:
    key_data = _fixed_key_data()
    cc_key_manager = tink_bindings.MacKeyManager.from_cc_registry(
        'type.googleapis.com/google.crypto.tink.JwtHmacKey')
    cc_mac = cc_key_manager.primitive(key_data.SerializeToString())
    unsigned_token = (_jwt_format.encode_header(json_header) + b'.' +
                      _jwt_format.encode_payload(json_payload))
    return _jwt_format.create_signed_compact(
        unsigned_token, cc_mac.compute_mac(unsigned_token))
Esempio n. 6
0
 def test_encode_decode_header(self):
     encoded_header = _jwt_format.encode_header('{ "alg": "RS256"} ')
     json_header = _jwt_format.decode_header(encoded_header)
     self.assertEqual(json_header, '{ "alg": "RS256"} ')
Esempio n. 7
0
 def test_encode_header_with_invalid_utf16_character(self):
     with self.assertRaises(_jwt_error.JwtInvalidError):
         _jwt_format.encode_header('{"alg": "RS256", "a":"\uD834"}')
Esempio n. 8
0
 def test_encode_header_with_utf16_surrogate(self):
     self.assertEqual(
         _jwt_format.encode_header('{"alg": "RS256", "a":"\U0001d11e"}'),
         b'eyJhbGciOiAiUlMyNTYiLCAiYSI6IvCdhJ4ifQ')
Esempio n. 9
0
 def test_validate_header_with_unknown_algorithm_fails(self):
     header = _jwt_format.encode_header({})
     with self.assertRaises(_jwt_error.JwtInvalidError):
         _jwt_format.validate_header(header, 'HS123')
Esempio n. 10
0
 def test_verify_empty_header_fails(self):
     header = _jwt_format.encode_header({})
     with self.assertRaises(_jwt_error.JwtInvalidError):
         _jwt_format.validate_header(header, 'ES256')
Esempio n. 11
0
 def test_validate_header_with_bad_typ_fails(self):
     header = _jwt_format.encode_header({'alg': 'HS256', 'typ': 'IWT'})
     with self.assertRaises(_jwt_error.JwtInvalidError):
         _jwt_format.validate_header(header, 'HS256')
Esempio n. 12
0
 def test_validate_header_with_lowercase_typ_success(self):
     header = _jwt_format.encode_header({'alg': 'HS256', 'typ': 'jwt'})
     _jwt_format.validate_header(header, 'HS256')
def gen_compact(json_header: str, json_payload: str, raw_sign) -> str:
    unsigned_compact = (_jwt_format.encode_header(json_header) + b'.' +
                        _jwt_format.encode_payload(json_payload))
    signature = raw_sign.sign(unsigned_compact)
    return _jwt_format.create_signed_compact(unsigned_compact, signature)
    def test_weird_tokens_with_valid_signatures(self):
        handle = tink.new_keyset_handle(jwt.raw_jwt_es256_template())
        sign = handle.primitive(jwt.JwtPublicKeySign)
        # Get the internal PublicKeySign primitive to create valid signatures.
        wrapped = cast(_jwt_signature_wrappers._WrappedJwtPublicKeySign, sign)
        raw_sign = cast(
            _jwt_signature_key_manager._JwtPublicKeySign,
            wrapped._primitive_set.primary().primitive)._public_key_sign

        verify = handle.public_keyset_handle().primitive(
            jwt.JwtPublicKeyVerify)
        validator = jwt.new_validator(expected_issuer='issuer',
                                      allow_missing_expiration=True)

        # Normal token.
        valid = gen_compact('{"alg":"ES256"}', '{"iss":"issuer"}', raw_sign)
        verified_jwt = verify.verify_and_decode(valid, validator)
        self.assertEqual(verified_jwt.issuer(), 'issuer')

        # Token with unknown header is valid.
        unknown_header = gen_compact(
            '{"alg":"ES256","unknown_header":"abc"} \n ', '{"iss":"issuer" }',
            raw_sign)
        verified_jwt = verify.verify_and_decode(unknown_header, validator)
        self.assertEqual(verified_jwt.issuer(), 'issuer')

        # Token with unknown kid is valid, since primitives with output prefix type
        # RAW ignore kid headers.
        unknown_header = gen_compact('{"alg":"ES256","kid":"unknown"} \n ',
                                     '{"iss":"issuer" }', raw_sign)
        verified_jwt = verify.verify_and_decode(unknown_header, validator)
        self.assertEqual(verified_jwt.issuer(), 'issuer')

        # Token with invalid alg header
        alg_invalid = gen_compact('{"alg":"ES384"}', '{"iss":"issuer"}',
                                  raw_sign)
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(alg_invalid, validator)

        # Token with empty header
        empty_header = gen_compact('{}', '{"iss":"issuer"}', raw_sign)
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(empty_header, validator)

        # Token header is not valid JSON
        header_invalid = gen_compact('{"alg":"ES256"', '{"iss":"issuer"}',
                                     raw_sign)
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(header_invalid, validator)

        # Token payload is not valid JSON
        payload_invalid = gen_compact('{"alg":"ES256"}', '{"iss":"issuer"',
                                      raw_sign)
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(payload_invalid, validator)

        # Token with whitespace in header JSON string is valid.
        whitespace_in_header = gen_compact(' {"alg":   \n  "ES256"} \n ',
                                           '{"iss":"issuer" }', raw_sign)
        verified_jwt = verify.verify_and_decode(whitespace_in_header,
                                                validator)
        self.assertEqual(verified_jwt.issuer(), 'issuer')

        # Token with whitespace in payload JSON string is valid.
        whitespace_in_payload = gen_compact('{"alg":"ES256"}',
                                            ' {"iss": \n"issuer" } \n',
                                            raw_sign)
        verified_jwt = verify.verify_and_decode(whitespace_in_payload,
                                                validator)
        self.assertEqual(verified_jwt.issuer(), 'issuer')

        # Token with whitespace in base64-encoded header is invalid.
        with_whitespace = (_jwt_format.encode_header('{"alg":"ES256"}') +
                           b' .' +
                           _jwt_format.encode_payload('{"iss":"issuer"}'))
        token_with_whitespace = _jwt_format.create_signed_compact(
            with_whitespace, raw_sign.sign(with_whitespace))
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(token_with_whitespace, validator)

        # Token with invalid character is invalid.
        with_invalid_char = (_jwt_format.encode_header('{"alg":"ES256"}') +
                             b'.?' +
                             _jwt_format.encode_payload('{"iss":"issuer"}'))
        token_with_invalid_char = _jwt_format.create_signed_compact(
            with_invalid_char, raw_sign.sign(with_invalid_char))
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(token_with_invalid_char, validator)

        # Token with additional '.' is invalid.
        with_dot = (_jwt_format.encode_header('{"alg":"ES256"}') + b'.' +
                    _jwt_format.encode_payload('{"iss":"issuer"}') + b'.')
        token_with_dot = _jwt_format.create_signed_compact(
            with_dot, raw_sign.sign(with_dot))
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(token_with_dot, validator)

        # num_recursions has been chosen such that parsing of this token fails
        # in all languages. We want to make sure that the algorithm does not
        # hang or crash in this case, but only returns a parsing error.
        num_recursions = 10000
        rec_payload = ('{"a":' * num_recursions) + '""' + ('}' *
                                                           num_recursions)
        rec_token = gen_compact('{"alg":"ES256"}', rec_payload, raw_sign)
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(
                rec_token,
                validator=jwt.new_validator(allow_missing_expiration=True))

        # test wrong types
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(cast(str, None), validator)
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(cast(str, 123), validator)
        with self.assertRaises(tink.TinkError):
            valid_bytes = valid.encode('utf8')
            verify.verify_and_decode(cast(str, valid_bytes), validator)
Esempio n. 15
0
  def test_weird_tokens_with_valid_macs(self):
    jwt_hmac = create_fixed_jwt_hmac()
    validator = jwt.new_validator(
        expected_issuer='joe', allow_missing_expiration=True)
    cc_mac = _cc_mac()

    # Normal token.
    valid_token = gen_token('{"alg":"HS256"}', '{"iss":"joe"}')
    verified = jwt_hmac.verify_mac_and_decode_with_kid(
        valid_token, validator, kid=None)
    self.assertEqual(verified.issuer(), 'joe')

    # Token with unknown header is valid.
    token_with_unknown_header = gen_token(
        '{"unknown_header":"123","alg":"HS256"}', '{"iss":"joe"}')
    verified2 = jwt_hmac.verify_mac_and_decode_with_kid(
        token_with_unknown_header, validator, kid=None)
    self.assertEqual(verified2.issuer(), 'joe')

    # Token with unknown kid is valid, since primitives with output prefix type
    # RAW ignore kid headers.
    token_with_unknown_kid = gen_token('{"kid":"unknown","alg":"HS256"}',
                                       '{"iss":"joe"}')
    verified2 = jwt_hmac.verify_mac_and_decode_with_kid(
        token_with_unknown_kid, validator, kid=None)
    self.assertEqual(verified2.issuer(), 'joe')

    # Token with invalid alg header
    alg_invalid = gen_token('{"alg":"HS384"}', '{"iss":"joe"}')
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(alg_invalid, validator, kid=None)

    # Token with empty header
    empty_header = gen_token('{}', '{"iss":"joe"}')
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(empty_header, validator, kid=None)

    # Token header is not valid JSON
    header_invalid = gen_token('{"alg":"HS256"', '{"iss":"joe"}')
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          header_invalid, validator, kid=None)

    # Token payload is not valid JSON
    payload_invalid = gen_token('{"alg":"HS256"}', '{"iss":"joe"')
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          payload_invalid, validator, kid=None)

    # Token with whitespace in header JSON string is valid.
    whitespace_in_header = gen_token(' {"alg":   \n  "HS256"} \n ',
                                     '{"iss":"joe" }')
    verified_jwt = jwt_hmac.verify_mac_and_decode_with_kid(
        whitespace_in_header, validator, kid=None)
    self.assertEqual(verified_jwt.issuer(), 'joe')

    # Token with whitespace in payload JSON string is valid.
    whitespace_in_payload = gen_token('{"alg":"HS256"}',
                                      ' {"iss": \n"joe" } \n')
    verified_jwt = jwt_hmac.verify_mac_and_decode_with_kid(
        whitespace_in_payload, validator, kid=None)
    self.assertEqual(verified_jwt.issuer(), 'joe')

    # Token with whitespace in base64-encoded header is invalid.
    with_whitespace_in_encoding = (
        _jwt_format.encode_header('{"alg":"HS256"}') + b' .' +
        _jwt_format.encode_payload('{"iss":"joe"}'))
    token_with_whitespace_in_encoding = _jwt_format.create_signed_compact(
        with_whitespace_in_encoding,
        cc_mac.compute_mac(with_whitespace_in_encoding))
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          token_with_whitespace_in_encoding, validator, kid=None)

    # Token with invalid character is invalid.
    with_invalid_char = (
        _jwt_format.encode_header('{"alg":"HS256"}') + b'.?' +
        _jwt_format.encode_payload('{"iss":"joe"}'))
    token_with_invalid_char = _jwt_format.create_signed_compact(
        with_invalid_char, cc_mac.compute_mac(with_invalid_char))
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          token_with_invalid_char, validator, kid=None)

    # Token with additional '.' is invalid.
    with_dot = (
        _jwt_format.encode_header('{"alg":"HS256"}') + b'.' +
        _jwt_format.encode_payload('{"iss":"joe"}') + b'.')
    token_with_dot = _jwt_format.create_signed_compact(
        with_dot, cc_mac.compute_mac(with_dot))
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          token_with_dot, validator, kid=None)

    # num_recursions has been chosen such that parsing of this token fails
    # in all languages. We want to make sure that the algorithm does not
    # hang or crash in this case, but only returns a parsing error.
    num_recursions = 10000
    rec_payload = ('{"a":' * num_recursions) + '""' + ('}' * num_recursions)
    rec_token = gen_token('{"alg":"HS256"}', rec_payload)
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          rec_token,
          validator=jwt.new_validator(allow_missing_expiration=True),
          kid=None)

    # test wrong types
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          cast(str, None), validator, kid=None)
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          cast(str, 123), validator, kid=None)
    with self.assertRaises(tink.TinkError):
      valid_token_bytes = valid_token.encode('utf8')
      jwt_hmac.verify_mac_and_decode_with_kid(
          cast(str, valid_token_bytes), validator, kid=None)