From f76444fbf8690c1d876a80a680ce6564c49ceae4 Mon Sep 17 00:00:00 2001 From: JimMoen Date: Mon, 8 Jul 2024 15:35:20 +0800 Subject: [PATCH] fix: create authn jwt with bad public key --- apps/emqx_auth_jwt/src/emqx_authn_jwt.erl | 69 ++++++++++++++++------- changes/fix-13432.en.md | 1 + 2 files changed, 49 insertions(+), 21 deletions(-) create mode 100644 changes/fix-13432.en.md diff --git a/apps/emqx_auth_jwt/src/emqx_authn_jwt.erl b/apps/emqx_auth_jwt/src/emqx_authn_jwt.erl index 33e7ee645..18c954ab5 100644 --- a/apps/emqx_auth_jwt/src/emqx_authn_jwt.erl +++ b/apps/emqx_auth_jwt/src/emqx_authn_jwt.erl @@ -18,6 +18,7 @@ -include_lib("emqx_auth/include/emqx_authn.hrl"). -include_lib("emqx/include/logger.hrl"). +-include_lib("jose/include/jose_jwk.hrl"). -export([ create/2, @@ -38,7 +39,7 @@ create(_AuthenticatorID, Config) -> create(Config). create(#{verify_claims := VerifyClaims} = Config) -> - create2(Config#{verify_claims => handle_verify_claims(VerifyClaims)}). + do_create(Config#{verify_claims => handle_verify_claims(VerifyClaims)}). update( #{use_jwks := false} = Config, @@ -83,6 +84,7 @@ authenticate( } ) -> JWT = maps:get(From, Credential), + %% XXX: Only supports single public key JWKs = [JWK], VerifyClaims = replace_placeholder(VerifyClaims0, Credential), verify(JWT, JWKs, VerifyClaims, AclClaimName, DisconnectAfterExpire); @@ -119,7 +121,7 @@ destroy(_) -> %% Internal functions %%-------------------------------------------------------------------- -create2(#{ +do_create(#{ use_jwks := false, algorithm := 'hmac-based', secret := Secret0, @@ -142,24 +144,35 @@ create2(#{ from => From }} end; -create2(#{ - use_jwks := false, - algorithm := 'public-key', - public_key := PublicKey, - verify_claims := VerifyClaims, - disconnect_after_expire := DisconnectAfterExpire, - acl_claim_name := AclClaimName, - from := From -}) -> - JWK = create_jwk_from_public_key(PublicKey), - {ok, #{ - jwk => JWK, - verify_claims => VerifyClaims, - disconnect_after_expire => DisconnectAfterExpire, - acl_claim_name => AclClaimName, - from => From - }}; -create2( +do_create( + #{ + use_jwks := false, + algorithm := 'public-key', + public_key := PublicKey, + verify_claims := VerifyClaims, + disconnect_after_expire := DisconnectAfterExpire, + acl_claim_name := AclClaimName, + from := From + } = Config +) -> + case + create_jwk_from_public_key( + maps:get(enable, Config, false), + PublicKey + ) + of + {ok, JWK} -> + {ok, #{ + jwk => JWK, + verify_claims => VerifyClaims, + disconnect_after_expire => DisconnectAfterExpire, + acl_claim_name => AclClaimName, + from => From + }}; + {error, _Reason} = Err -> + Err + end; +do_create( #{ use_jwks := true, verify_claims := VerifyClaims, @@ -183,9 +196,23 @@ create2( from => From }}. -create_jwk_from_public_key(PublicKey) when +create_jwk_from_public_key(true, PublicKey) when is_binary(PublicKey); is_list(PublicKey) -> + try do_create_jwk_from_public_key(PublicKey) of + %% XXX: Only supports single public key + #jose_jwk{} = Res -> + {ok, Res}; + _ -> + {error, invalid_public_key} + catch + _:_ -> + {error, invalid_public_key} + end; +create_jwk_from_public_key(false, _PublicKey) -> + {ok, []}. + +do_create_jwk_from_public_key(PublicKey) -> case filelib:is_file(PublicKey) of true -> jose_jwk:from_pem_file(PublicKey); diff --git a/changes/fix-13432.en.md b/changes/fix-13432.en.md new file mode 100644 index 000000000..d1f56f052 --- /dev/null +++ b/changes/fix-13432.en.md @@ -0,0 +1 @@ +Fixed the issue where JWT authentication was silently bypassed when an invalid public key (or invalid public key file path) was used.