Преглед на файлове

test(authn): add test cases for jwt authn

zhouzb преди 4 години
родител
ревизия
ecd3c9f85c
променени са 2 файла, в които са добавени 134 реда и са изтрити 132 реда
  1. 1 1
      apps/emqx_authn/src/simple_authn/emqx_authn_jwt.erl
  2. 133 131
      apps/emqx_authn/test/emqx_authn_jwt_SUITE.erl

+ 1 - 1
apps/emqx_authn/src/simple_authn/emqx_authn_jwt.erl

@@ -238,7 +238,7 @@ may_decode_secret(true, Secret) ->
     try base64:decode(Secret)
     catch
         error : _ ->
-            {error, {invalid_parameter, Secret}}
+            {error, {invalid_parameter, secret}}
     end.
 
 replace_placeholder(L, Variables) ->

+ 133 - 131
apps/emqx_authn/test/emqx_authn_jwt_SUITE.erl

@@ -19,140 +19,142 @@
 -compile(export_all).
 -compile(nowarn_export_all).
 
-% -include_lib("common_test/include/ct.hrl").
-% -include_lib("eunit/include/eunit.hrl").
+-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
 
-% -include("emqx_authn.hrl").
+-include("emqx_authn.hrl").
 
-% -define(AUTH, emqx_authn).
+-define(AUTHN_ID, <<"mechanism:jwt">>).
 
 all() ->
     emqx_common_test_helpers:all(?MODULE).
 
-% init_per_suite(Config) ->
-%     emqx_common_test_helpers:start_apps([emqx_authn]),
-%     Config.
-
-% end_per_suite(_) ->
-%     emqx_common_test_helpers:stop_apps([emqx_authn]),
-%     ok.
-
-% t_jwt_authenticator(_) ->
-%     AuthenticatorName = <<"myauthenticator">>,
-%     Config = #{name => AuthenticatorName,
-%                mechanism => jwt,
-%                use_jwks => false,
-%                algorithm => 'hmac-based',
-%                secret => <<"abcdef">>,
-%                secret_base64_encoded => false,
-%                verify_claims => []},
-%     {ok, #{name := AuthenticatorName, id := ID}} = ?AUTH:create_authenticator(?CHAIN, Config),
-
-%     Payload = #{<<"username">> => <<"myuser">>},
-%     JWS = generate_jws('hmac-based', Payload, <<"abcdef">>),
-%     ClientInfo = #{username => <<"myuser">>,
-% 			       password => JWS},
-%     ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
-
-%     Payload1 = #{<<"username">> => <<"myuser">>, <<"is_superuser">> => true},
-%     JWS1 = generate_jws('hmac-based', Payload1, <<"abcdef">>),
-%     ClientInfo1 = #{username => <<"myuser">>,
-% 			        password => JWS1},
-%     ?assertEqual({stop, {ok, #{is_superuser => true}}}, ?AUTH:authenticate(ClientInfo1, ignored)),
-
-%     BadJWS = generate_jws('hmac-based', Payload, <<"bad_secret">>),
-%     ClientInfo2 = ClientInfo#{password => BadJWS},
-%     ?assertEqual({stop, {error, not_authorized}}, ?AUTH:authenticate(ClientInfo2, ignored)),
-
-%     %% secret_base64_encoded
-%     Config2 = Config#{secret => base64:encode(<<"abcdef">>),
-%                       secret_base64_encoded => true},
-%     ?assertMatch({ok, _}, ?AUTH:update_authenticator(?CHAIN, ID, Config2)),
-%     ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
-
-%     Config3 = Config#{verify_claims => [{<<"username">>, <<"${mqtt-username}">>}]},
-%     ?assertMatch({ok, _}, ?AUTH:update_authenticator(?CHAIN, ID, Config3)),
-%     ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
-%     ?assertEqual({stop, {error, bad_username_or_password}}, ?AUTH:authenticate(ClientInfo#{username => <<"otheruser">>}, ok)),
-
-%     %% Expiration
-%     Payload3 = #{ <<"username">> => <<"myuser">>
-%                 , <<"exp">> => erlang:system_time(second) - 60},
-%     JWS3 = generate_jws('hmac-based', Payload3, <<"abcdef">>),
-%     ClientInfo3 = ClientInfo#{password => JWS3},
-%     ?assertEqual({stop, {error, bad_username_or_password}}, ?AUTH:authenticate(ClientInfo3, ignored)),
-
-%     Payload4 = #{ <<"username">> => <<"myuser">>
-%                 , <<"exp">> => erlang:system_time(second) + 60},
-%     JWS4 = generate_jws('hmac-based', Payload4, <<"abcdef">>),
-%     ClientInfo4 = ClientInfo#{password => JWS4},
-%     ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo4, ignored)),
-
-%     %% Issued At
-%     Payload5 = #{ <<"username">> => <<"myuser">>
-%                 , <<"iat">> => erlang:system_time(second) - 60},
-%     JWS5 = generate_jws('hmac-based', Payload5, <<"abcdef">>),
-%     ClientInfo5 = ClientInfo#{password => JWS5},
-%     ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo5, ignored)),
-
-%     Payload6 = #{ <<"username">> => <<"myuser">>
-%                 , <<"iat">> => erlang:system_time(second) + 60},
-%     JWS6 = generate_jws('hmac-based', Payload6, <<"abcdef">>),
-%     ClientInfo6 = ClientInfo#{password => JWS6},
-%     ?assertEqual({stop, {error, bad_username_or_password}}, ?AUTH:authenticate(ClientInfo6, ignored)),
-
-%     %% Not Before
-%     Payload7 = #{ <<"username">> => <<"myuser">>
-%                 , <<"nbf">> => erlang:system_time(second) - 60},
-%     JWS7 = generate_jws('hmac-based', Payload7, <<"abcdef">>),
-%     ClientInfo7 = ClientInfo#{password => JWS7},
-%     ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo7, ignored)),
-
-%     Payload8 = #{ <<"username">> => <<"myuser">>
-%                 , <<"nbf">> => erlang:system_time(second) + 60},
-%     JWS8 = generate_jws('hmac-based', Payload8, <<"abcdef">>),
-%     ClientInfo8 = ClientInfo#{password => JWS8},
-%     ?assertEqual({stop, {error, bad_username_or_password}}, ?AUTH:authenticate(ClientInfo8, ignored)),
-
-%     ?assertEqual(ok, ?AUTH:delete_authenticator(?CHAIN, ID)),
-%     ok.
-
-% t_jwt_authenticator2(_) ->
-%     Dir = code:lib_dir(emqx_authn, test),
-%     PublicKey = list_to_binary(filename:join([Dir, "data/public_key.pem"])),
-%     PrivateKey = list_to_binary(filename:join([Dir, "data/private_key.pem"])),
-%     AuthenticatorName = <<"myauthenticator">>,
-%     Config = #{name => AuthenticatorName,
-%                mechanism => jwt,
-%                use_jwks => false,
-%                algorithm => 'public-key',
-%                certificate => PublicKey,
-%                verify_claims => []},
-%     {ok, #{name := AuthenticatorName, id := ID}} = ?AUTH:create_authenticator(?CHAIN, Config),
-
-%     Payload = #{<<"username">> => <<"myuser">>},
-%     JWS = generate_jws('public-key', Payload, PrivateKey),
-%     ClientInfo = #{username => <<"myuser">>,
-% 			       password => JWS},
-%     ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
-%     ?assertEqual({stop, {error, not_authorized}}, ?AUTH:authenticate(ClientInfo#{password => <<"badpassword">>}, ignored)),
-
-%     ?assertEqual(ok, ?AUTH:delete_authenticator(?CHAIN, ID)),
-%     ok.
-
-% generate_jws('hmac-based', Payload, Secret) ->
-%     JWK = jose_jwk:from_oct(Secret),
-%     Header = #{ <<"alg">> => <<"HS256">>
-%               , <<"typ">> => <<"JWT">>
-%               },
-%     Signed = jose_jwt:sign(JWK, Header, Payload),
-%     {_, JWS} = jose_jws:compact(Signed),
-%     JWS;
-% generate_jws('public-key', Payload, PrivateKey) ->
-%     JWK = jose_jwk:from_pem_file(PrivateKey),
-%     Header = #{ <<"alg">> => <<"RS256">>
-%               , <<"typ">> => <<"JWT">>
-%               },
-%     Signed = jose_jwt:sign(JWK, Header, Payload),
-%     {_, JWS} = jose_jws:compact(Signed),
-%     JWS.
+init_per_suite(Config) ->
+    emqx_common_test_helpers:start_apps([emqx_authn]),
+    Config.
+
+end_per_suite(_) ->
+    emqx_common_test_helpers:stop_apps([emqx_authn]),
+    ok.
+
+t_jwt_authenticator(_) ->
+    Secret = <<"abcdef">>,
+    Config = #{mechanism => jwt,
+               use_jwks => false,
+               algorithm => 'hmac-based',
+               secret => Secret,
+               secret_base64_encoded => false,
+               verify_claims => []},
+    {ok, State} = emqx_authn_jwt:create(?AUTHN_ID, Config),
+
+    Payload = #{<<"username">> => <<"myuser">>},
+    JWS = generate_jws('hmac-based', Payload, Secret),
+    Credential = #{username => <<"myuser">>,
+			       password => JWS},
+    ?assertEqual({ok, #{is_superuser => false}}, emqx_authn_jwt:authenticate(Credential, State)),
+
+    Payload1 = #{<<"username">> => <<"myuser">>, <<"is_superuser">> => true},
+    JWS1 = generate_jws('hmac-based', Payload1, Secret),
+    Credential1 = #{username => <<"myuser">>,
+			        password => JWS1},
+    ?assertEqual({ok, #{is_superuser => true}}, emqx_authn_jwt:authenticate(Credential1, State)),
+
+    BadJWS = generate_jws('hmac-based', Payload, <<"bad_secret">>),
+    Credential2 = Credential#{password => BadJWS},
+    ?assertEqual(ignore, emqx_authn_jwt:authenticate(Credential2, State)),
+
+    %% secret_base64_encoded
+    Config2 = Config#{secret => base64:encode(Secret),
+                      secret_base64_encoded => true},
+    {ok, State2} = emqx_authn_jwt:update(Config2, State),
+    ?assertEqual({ok, #{is_superuser => false}}, emqx_authn_jwt:authenticate(Credential, State2)),
+
+    %% invalid secret
+    BadConfig = Config#{secret => <<"emqxsecret">>,
+                        secret_base64_encoded => true},
+    {error, {invalid_parameter, secret}} = emqx_authn_jwt:create(?AUTHN_ID, BadConfig),
+
+    Config3 = Config#{verify_claims => [{<<"username">>, <<"${username}">>}]},
+    {ok, State3} = emqx_authn_jwt:update(Config3, State2),
+    ?assertEqual({ok, #{is_superuser => false}}, emqx_authn_jwt:authenticate(Credential, State3)),
+    ?assertEqual({error, bad_username_or_password}, emqx_authn_jwt:authenticate(Credential#{username => <<"otheruser">>}, State3)),
+
+    %% Expiration
+    Payload3 = #{ <<"username">> => <<"myuser">>
+                , <<"exp">> => erlang:system_time(second) - 60},
+    JWS3 = generate_jws('hmac-based', Payload3, Secret),
+    Credential3 = Credential#{password => JWS3},
+    ?assertEqual({error, bad_username_or_password}, emqx_authn_jwt:authenticate(Credential3, State3)),
+
+    Payload4 = #{ <<"username">> => <<"myuser">>
+                , <<"exp">> => erlang:system_time(second) + 60},
+    JWS4 = generate_jws('hmac-based', Payload4, Secret),
+    Credential4 = Credential#{password => JWS4},
+    ?assertEqual({ok, #{is_superuser => false}}, emqx_authn_jwt:authenticate(Credential4, State3)),
+
+    %% Issued At
+    Payload5 = #{ <<"username">> => <<"myuser">>
+                , <<"iat">> => erlang:system_time(second) - 60},
+    JWS5 = generate_jws('hmac-based', Payload5, Secret),
+    Credential5 = Credential#{password => JWS5},
+    ?assertEqual({ok, #{is_superuser => false}}, emqx_authn_jwt:authenticate(Credential5, State3)),
+
+    Payload6 = #{ <<"username">> => <<"myuser">>
+                , <<"iat">> => erlang:system_time(second) + 60},
+    JWS6 = generate_jws('hmac-based', Payload6, Secret),
+    Credential6 = Credential#{password => JWS6},
+    ?assertEqual({error, bad_username_or_password}, emqx_authn_jwt:authenticate(Credential6, State3)),
+
+    %% Not Before
+    Payload7 = #{ <<"username">> => <<"myuser">>
+                , <<"nbf">> => erlang:system_time(second) - 60},
+    JWS7 = generate_jws('hmac-based', Payload7, Secret),
+    Credential7 = Credential6#{password => JWS7},
+    ?assertEqual({ok, #{is_superuser => false}}, emqx_authn_jwt:authenticate(Credential7, State3)),
+
+    Payload8 = #{ <<"username">> => <<"myuser">>
+                , <<"nbf">> => erlang:system_time(second) + 60},
+    JWS8 = generate_jws('hmac-based', Payload8, Secret),
+    Credential8 = Credential#{password => JWS8},
+    ?assertEqual({error, bad_username_or_password}, emqx_authn_jwt:authenticate(Credential8, State3)),
+
+    ?assertEqual(ok, emqx_authn_jwt:destroy(State3)),
+    ok.
+
+t_jwt_authenticator2(_) ->
+    Dir = code:lib_dir(emqx_authn, test),
+    PublicKey = list_to_binary(filename:join([Dir, "data/public_key.pem"])),
+    PrivateKey = list_to_binary(filename:join([Dir, "data/private_key.pem"])),
+    Config = #{mechanism => jwt,
+               use_jwks => false,
+               algorithm => 'public-key',
+               certificate => PublicKey,
+               verify_claims => []},
+    {ok, State} = emqx_authn_jwt:create(?AUTHN_ID, Config),
+
+    Payload = #{<<"username">> => <<"myuser">>},
+    JWS = generate_jws('public-key', Payload, PrivateKey),
+    Credential = #{username => <<"myuser">>,
+			       password => JWS},
+    ?assertEqual({ok, #{is_superuser => false}}, emqx_authn_jwt:authenticate(Credential, State)),
+    ?assertEqual(ignore, emqx_authn_jwt:authenticate(Credential#{password => <<"badpassword">>}, State)),
+
+    ?assertEqual(ok, emqx_authn_jwt:destroy(State)),
+    ok.
+
+generate_jws('hmac-based', Payload, Secret) ->
+    JWK = jose_jwk:from_oct(Secret),
+    Header = #{ <<"alg">> => <<"HS256">>
+              , <<"typ">> => <<"JWT">>
+              },
+    Signed = jose_jwt:sign(JWK, Header, Payload),
+    {_, JWS} = jose_jws:compact(Signed),
+    JWS;
+generate_jws('public-key', Payload, PrivateKey) ->
+    JWK = jose_jwk:from_pem_file(PrivateKey),
+    Header = #{ <<"alg">> => <<"RS256">>
+              , <<"typ">> => <<"JWT">>
+              },
+    Signed = jose_jwt:sign(JWK, Header, Payload),
+    {_, JWS} = jose_jws:compact(Signed),
+    JWS.