|
|
@@ -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);
|