chore(authn): test JWT authn with HTTPS key server
This commit is contained in:
parent
f230c20521
commit
2b3d3ebb0a
|
@ -114,8 +114,8 @@ certfile(_) -> undefined.
|
|||
keyfile(type) -> string();
|
||||
keyfile(_) -> undefined.
|
||||
|
||||
verify(type) -> boolean();
|
||||
verify(default) -> false;
|
||||
verify(type) -> hoconsc:enum([verify_peer, verify_none]);
|
||||
verify(default) -> verify_none;
|
||||
verify(_) -> undefined.
|
||||
|
||||
server_name_indication(type) -> string();
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
-include_lib("eunit/include/eunit.hrl").
|
||||
-include_lib("snabbkaffe/include/snabbkaffe.hrl").
|
||||
|
||||
-include("emqx_authn.hrl").
|
||||
|
||||
-define(AUTHN_ID, <<"mechanism:jwt">>).
|
||||
|
||||
-define(JWKS_PORT, 33333).
|
||||
|
@ -156,7 +154,7 @@ t_jwt_authenticator_public_key(_) ->
|
|||
ok.
|
||||
|
||||
t_jwks_renewal(_Config) ->
|
||||
{ok, _} = emqx_authn_http_test_server:start_link(?JWKS_PORT, ?JWKS_PATH),
|
||||
{ok, _} = emqx_authn_http_test_server:start_link(?JWKS_PORT, ?JWKS_PATH, server_ssl_opts()),
|
||||
ok = emqx_authn_http_test_server:set_handler(fun jwks_handler/2),
|
||||
|
||||
PrivateKey = test_rsa_key(private),
|
||||
|
@ -164,45 +162,63 @@ t_jwks_renewal(_Config) ->
|
|||
JWS = generate_jws('public-key', Payload, PrivateKey),
|
||||
Credential = #{username => <<"myuser">>,
|
||||
password => JWS},
|
||||
|
||||
BadConfig0 = #{mechanism => jwt,
|
||||
algorithm => 'public-key',
|
||||
ssl => #{enable => false},
|
||||
verify_claims => [],
|
||||
|
||||
BadConfig = #{mechanism => jwt,
|
||||
algorithm => 'public-key',
|
||||
ssl => #{enable => false},
|
||||
verify_claims => [],
|
||||
|
||||
use_jwks => true,
|
||||
endpoint => "http://127.0.0.1:" ++ integer_to_list(?JWKS_PORT + 1) ++ ?JWKS_PATH,
|
||||
refresh_interval => 1000
|
||||
},
|
||||
use_jwks => true,
|
||||
endpoint => "https://127.0.0.1:" ++ integer_to_list(?JWKS_PORT + 1) ++ ?JWKS_PATH,
|
||||
refresh_interval => 1000
|
||||
},
|
||||
|
||||
ok = snabbkaffe:start_trace(),
|
||||
|
||||
{{ok, State0}, _} = ?wait_async_action(
|
||||
emqx_authn_jwt:create(?AUTHN_ID, BadConfig),
|
||||
emqx_authn_jwt:create(?AUTHN_ID, BadConfig0),
|
||||
#{?snk_kind := jwks_endpoint_response},
|
||||
1000),
|
||||
10000),
|
||||
|
||||
ok = snabbkaffe:stop(),
|
||||
|
||||
?assertEqual(ignore, emqx_authn_jwt:authenticate(Credential, State0)),
|
||||
?assertEqual(ignore, emqx_authn_jwt:authenticate(Credential#{password => <<"badpassword">>}, State0)),
|
||||
|
||||
GoodConfig = BadConfig#{endpoint =>
|
||||
"http://127.0.0.1:" ++ integer_to_list(?JWKS_PORT) ++ ?JWKS_PATH},
|
||||
ClientSSLOpts = client_ssl_opts(),
|
||||
BadClientSSLOpts = ClientSSLOpts#{server_name_indication => "authn-https-unknown-host"},
|
||||
|
||||
BadConfig1 = BadConfig0#{endpoint =>
|
||||
"https://127.0.0.1:" ++ integer_to_list(?JWKS_PORT) ++ ?JWKS_PATH,
|
||||
ssl => BadClientSSLOpts},
|
||||
|
||||
ok = snabbkaffe:start_trace(),
|
||||
|
||||
{{ok, State1}, _} = ?wait_async_action(
|
||||
emqx_authn_jwt:update(GoodConfig, State0),
|
||||
emqx_authn_jwt:create(?AUTHN_ID, BadConfig1),
|
||||
#{?snk_kind := jwks_endpoint_response},
|
||||
1000),
|
||||
10000),
|
||||
|
||||
ok = snabbkaffe:stop(),
|
||||
|
||||
?assertEqual({ok, #{is_superuser => false}}, emqx_authn_jwt:authenticate(Credential, State1)),
|
||||
?assertEqual(ignore, emqx_authn_jwt:authenticate(Credential#{password => <<"badpassword">>}, State1)),
|
||||
?assertEqual(ignore, emqx_authn_jwt:authenticate(Credential, State1)),
|
||||
?assertEqual(ignore, emqx_authn_jwt:authenticate(Credential#{password => <<"badpassword">>}, State0)),
|
||||
|
||||
?assertEqual(ok, emqx_authn_jwt:destroy(State1)),
|
||||
GoodConfig = BadConfig1#{ssl => ClientSSLOpts},
|
||||
|
||||
ok = snabbkaffe:start_trace(),
|
||||
|
||||
{{ok, State2}, _} = ?wait_async_action(
|
||||
emqx_authn_jwt:update(GoodConfig, State1),
|
||||
#{?snk_kind := jwks_endpoint_response},
|
||||
10000),
|
||||
|
||||
ok = snabbkaffe:stop(),
|
||||
|
||||
?assertEqual({ok, #{is_superuser => false}}, emqx_authn_jwt:authenticate(Credential, State2)),
|
||||
?assertEqual(ignore, emqx_authn_jwt:authenticate(Credential#{password => <<"badpassword">>}, State2)),
|
||||
|
||||
?assertEqual(ok, emqx_authn_jwt:destroy(State2)),
|
||||
ok = emqx_authn_http_test_server:stop().
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
|
@ -220,12 +236,17 @@ jwks_handler(Req0, State) ->
|
|||
{ok, Req, State}.
|
||||
|
||||
test_rsa_key(public) ->
|
||||
Dir = code:lib_dir(emqx_authn, test),
|
||||
list_to_binary(filename:join([Dir, "data/public_key.pem"]));
|
||||
data_file("public_key.pem");
|
||||
|
||||
test_rsa_key(private) ->
|
||||
data_file("private_key.pem").
|
||||
|
||||
data_file(Name) ->
|
||||
Dir = code:lib_dir(emqx_authn, test),
|
||||
list_to_binary(filename:join([Dir, "data/private_key.pem"])).
|
||||
list_to_binary(filename:join([Dir, "data", Name])).
|
||||
|
||||
cert_file(Name) ->
|
||||
data_file(filename:join(["certs", Name])).
|
||||
|
||||
generate_jws('hmac-based', Payload, Secret) ->
|
||||
JWK = jose_jwk:from_oct(Secret),
|
||||
|
@ -243,3 +264,19 @@ generate_jws('public-key', Payload, PrivateKey) ->
|
|||
Signed = jose_jwt:sign(JWK, Header, Payload),
|
||||
{_, JWS} = jose_jws:compact(Signed),
|
||||
JWS.
|
||||
|
||||
client_ssl_opts() ->
|
||||
#{keyfile => cert_file("authn-https-client.key"),
|
||||
certfile => cert_file("authn-https-client.crt"),
|
||||
cacertfile => cert_file("authn-https-ca.crt"),
|
||||
enable => true,
|
||||
verify => verify_peer,
|
||||
server_name_indication => "authn-https"
|
||||
}.
|
||||
|
||||
server_ssl_opts() ->
|
||||
[{keyfile, cert_file("authn-https-server.key")},
|
||||
{certfile, cert_file("authn-https-server.crt")},
|
||||
{cacertfile, cert_file("authn-https-ca.crt")},
|
||||
{verify, verify_none}
|
||||
].
|
||||
|
|
Loading…
Reference in New Issue