Add first pass of a riak_control authentication test.

* Verify 'none' authentication method works on previous and legacy
  releases.
* Verify 'userlist' authentication, and forced SSL requirement of the
  previous and legacy releases.
* Verify force_ssl option on current as best as we can, giving the open
  R16B02 SSL ECC bug.
This commit is contained in:
Christopher Meiklejohn 2013-10-09 14:18:24 -04:00
parent 00e6cba241
commit 5f7c8d31df
2 changed files with 253 additions and 1 deletions

View File

@ -60,6 +60,7 @@
get_version/0,
heal/1,
http_url/1,
https_url/1,
httpc/1,
httpc_read/3,
httpc_write/4,
@ -213,7 +214,12 @@ rpc_get_env(Node, [{App,Var}|Others]) ->
connection_info(Node) when is_atom(Node) ->
{ok, [{PB_IP, PB_Port}]} = get_pb_conn_info(Node),
{ok, [{HTTP_IP, HTTP_Port}]} = get_http_conn_info(Node),
[{http, {HTTP_IP, HTTP_Port}}, {pb, {PB_IP, PB_Port}}];
case get_https_conn_info(Node) of
undefined ->
[{http, {HTTP_IP, HTTP_Port}}, {pb, {PB_IP, PB_Port}}];
{ok, [{HTTPS_IP, HTTPS_Port}]} ->
[{http, {HTTP_IP, HTTP_Port}}, {https, {HTTPS_IP, HTTPS_Port}}, {pb, {PB_IP, PB_Port}}]
end;
connection_info(Nodes) when is_list(Nodes) ->
[ {Node, connection_info(Node)} || Node <- Nodes].
@ -242,6 +248,16 @@ get_http_conn_info(Node) ->
undefined
end.
-spec get_https_conn_info(node()) -> [{inet:ip_address(), pos_integer()}].
get_https_conn_info(Node) ->
case rpc_get_env(Node, [{riak_api, https},
{riak_core, https}]) of
{ok, [{IP, Port}|_]} ->
{ok, [{IP, Port}]};
_ ->
undefined
end.
%% @doc Deploy a set of freshly installed Riak nodes, returning a list of the
%% nodes deployed.
%% @todo Re-add -spec after adding multi-version support
@ -978,6 +994,14 @@ pbc_really_deleted(Pid, Bucket, Keys) ->
end,
[] == lists:filter(StillThere, Keys).
%% @doc Returns HTTPS URL information for a list of Nodes
https_url(Nodes) when is_list(Nodes) ->
[begin
{Host, Port} = orddict:fetch(https, Connections),
lists:flatten(io_lib:format("https://~s:~b", [Host, Port]))
end || {_Node, Connections} <- connection_info(Nodes)];
https_url(Node) ->
hd(https_url([Node])).
%% @doc Returns HTTP URL information for a list of Nodes
http_url(Nodes) when is_list(Nodes) ->

View File

@ -0,0 +1,228 @@
%% -------------------------------------------------------------------
%%
%% Copyright (c) 2013 Basho Technologies, Inc.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------
%%
%% @doc Verify authentication works for riak_control.
-module(riak_control_authentication).
-behaviour(riak_test).
-export([confirm/0]).
-include_lib("eunit/include/eunit.hrl").
-define(RC_AUTH_NONE_CONFIG,
[{riak_control, [{enabled, true},
{auth, none}]}]).
-define(RC_AUTH_NONE_CONFIG_FORCE_SSL,
[{riak_api, [{https, [{"127.0.0.1", 8069}]}]},
{riak_core,
[{https, [{"127.0.0.1", 8069}]},
{ssl,
[{certfile, "./etc/cert.pem"},
{keyfile, "./etc/key.pem"}
]}]},
{riak_control, [{enabled, true},
{auth, none},
{force_ssl, true}]}]).
-define(RC_AUTH_USERLIST_CONFIG,
[{riak_api, [{https, [{"127.0.0.1", 8069}]}]},
{riak_core,
[{https, [{"127.0.0.1", 8069}]},
{ssl,
[{certfile, "./etc/cert.pem"},
{keyfile, "./etc/key.pem"}
]}]},
{riak_control, [{enabled, true},
{auth, userlist},
{userlist, [{"user", "pass"}]}]}]).
-define(RC_AUTH_USERLIST_CONFIG_FORCE_SSL,
[{riak_api, [{https, [{"127.0.0.1", 8069}]}]},
{riak_core,
[{https, [{"127.0.0.1", 8069}]},
{ssl,
[{certfile, "./etc/cert.pem"},
{keyfile, "./etc/key.pem"}
]}]},
{riak_control, [{enabled, true},
{force_ssl, true},
{auth, userlist},
{userlist, [{"user", "pass"}]}]}]).
-define(RC_AUTH_USERLIST_CONFIG_NO_FORCE_SSL,
[{riak_api, [{https, [{"127.0.0.1", 8069}]}]},
{riak_core,
[{https, [{"127.0.0.1", 8069}]},
{ssl,
[{certfile, "./etc/cert.pem"},
{keyfile, "./etc/key.pem"}
]}]},
{riak_control, [{enabled, true},
{force_ssl, false},
{auth, userlist},
{userlist, [{"user", "pass"}]}]}]).
%% @doc Confirm all authentication methods work for the three supported
%% releases.
confirm() ->
%% Verify authentication method 'none'.
verify_authentication(legacy, ?RC_AUTH_NONE_CONFIG),
verify_authentication(previous, ?RC_AUTH_NONE_CONFIG),
%% Verify authentication method 'userlist'.
verify_authentication(legacy, ?RC_AUTH_USERLIST_CONFIG),
verify_authentication(previous, ?RC_AUTH_USERLIST_CONFIG),
%% Verify authentication none, and then with forced SSL.
verify_authentication(current, ?RC_AUTH_NONE_CONFIG),
verify_authentication(current, ?RC_AUTH_NONE_CONFIG_FORCE_SSL),
%% Verify authentication userlist, without SSL and then with SSL.
verify_authentication(current, ?RC_AUTH_USERLIST_CONFIG_FORCE_SSL),
verify_authentication(current, ?RC_AUTH_USERLIST_CONFIG_NO_FORCE_SSL).
%% @doc Verify the disabled authentication method works.
verify_authentication(Vsn, ?RC_AUTH_NONE_CONFIG) ->
lager:info("Verifying auth 'none', ~p.", [Vsn]),
Nodes = build_singleton_cluster(Vsn, ?RC_AUTH_NONE_CONFIG),
Node = lists:nth(1, Nodes),
restart(Node),
%% Assert that we can load the main page.
lager:info("Verifying Control loads."),
Command = io_lib:format("curl -sL -w %{http_code} ~s~p -o /dev/null",
[rt:http_url(Node), "/admin"]),
?assertEqual("200", os:cmd(Command)),
pass;
%% @doc Verify the disabled authentication method works with force SSL.
verify_authentication(current, ?RC_AUTH_NONE_CONFIG_FORCE_SSL) ->
lager:info("Verifying auth 'none', 'force_ssl' 'true', current."),
Nodes = build_singleton_cluster(current,
?RC_AUTH_NONE_CONFIG_FORCE_SSL),
Node = lists:nth(1, Nodes),
restart(Node),
%% Assert that we get redirected if we hit the HTTP port.
lager:info("Verifying redirect to SSL."),
RedirectCommand = io_lib:format("curl -sL -w %{http_code} ~s~p -o /dev/null",
[rt:http_url(Node), "/admin"]),
?assertEqual("303", os:cmd(RedirectCommand)),
%% TODO: Temporarily disabled because of OTP R16B02 SSL bug.
%% Assert that we can access resource over the SSL port.
% lager:info("Verifying Control loads over SSL."),
% AccessCommand = io_lib:format("curl --insecure -sL -w %{http_code} ~s~p",
% [rt:https_url(Node), "/admin"]),
% ?assertEqual("200", os:cmd(AccessCommand)),
pass;
%% @doc Verify the userlist authentication method works.
verify_authentication(Vsn, ?RC_AUTH_USERLIST_CONFIG) ->
lager:info("Verifying auth 'userlist', ~p.", [Vsn]),
Nodes = build_singleton_cluster(Vsn, ?RC_AUTH_USERLIST_CONFIG),
Node = lists:nth(1, Nodes),
restart(Node),
%% Assert that we get redirected if we hit the HTTP port.
lager:info("Verifying redirect to SSL."),
RedirectCommand = io_lib:format("curl -sL -w %{http_code} ~s~p -o /dev/null",
[rt:http_url(Node), "/admin"]),
?assertEqual("303", os:cmd(RedirectCommand)),
%% Assert that we can access resource over the SSL port.
lager:info("Verifying Control loads over SSL."),
AccessCommand = io_lib:format("curl --insecure -sL -w %{http_code} ~s~p -o /dev/null",
[rt:https_url(Node), "/admin"]),
?assertEqual("401", os:cmd(AccessCommand)),
%% Assert that we can access resource over the SSL port.
lager:info("Verifying Control loads with credentials."),
AuthCommand = io_lib:format("curl -u user:pass --insecure -sL -w %{http_code} ~s~p -o /dev/null",
[rt:https_url(Node), "/admin"]),
?assertEqual("200", os:cmd(AuthCommand)),
pass;
%% @doc Verify the userlist authentication method works.
verify_authentication(current, ?RC_AUTH_USERLIST_CONFIG_FORCE_SSL) ->
lager:info("Verifying auth 'userlist', 'force_ssl' 'true', current."),
Nodes = build_singleton_cluster(current, ?RC_AUTH_USERLIST_CONFIG_FORCE_SSL),
Node = lists:nth(1, Nodes),
restart(Node),
%% Assert that we get redirected if we hit the HTTP port.
lager:info("Verifying redirect to SSL."),
RedirectCommand = io_lib:format("curl -sL -w %{http_code} ~s~p -o /dev/null",
[rt:http_url(Node), "/admin"]),
?assertEqual("303", os:cmd(RedirectCommand)),
%% TODO: Temporarily disabled because of OTP R16B02 SSL bug.
%% Assert that we can access resource over the SSL port.
% lager:info("Verifying Control loads over SSL."),
% AccessCommand = io_lib:format("curl --insecure -sL -w %{http_code} ~s~p -o /dev/null",
% [rt:https_url(Node), "/admin"]),
% ?assertEqual("401", os:cmd(AccessCommand)),
%% TODO: Temporarily disabled because of OTP R16B02 SSL bug.
%% Assert that we can access resource over the SSL port.
% lager:info("Verifying Control loads with credentials."),
% AuthCommand = io_lib:format("curl -u user:pass --insecure -sL -w %{http_code} ~s~p -o /dev/null",
% [rt:https_url(Node), "/admin"]),
% ?assertEqual("200", os:cmd(AuthCommand)),
pass;
%% @doc Verify the userlist authentication method works.
verify_authentication(current, ?RC_AUTH_USERLIST_CONFIG_NO_FORCE_SSL) ->
lager:info("Verifying auth 'userlist', 'force_ssl' 'false', current."),
Nodes = build_singleton_cluster(current, ?RC_AUTH_USERLIST_CONFIG_NO_FORCE_SSL),
Node = lists:nth(1, Nodes),
restart(Node),
%% Assert that we can access resource over the SSL port.
lager:info("Verifying Control loads over SSL."),
AccessCommand = io_lib:format("curl --insecure -sL -w %{http_code} ~s~p -o /dev/null",
[rt:http_url(Node), "/admin"]),
?assertEqual("401", os:cmd(AccessCommand)),
%% Assert that we can access resource over the SSL port.
lager:info("Verifying Control loads with credentials."),
AuthCommand = io_lib:format("curl -u user:pass --insecure -sL -w %{http_code} ~s~p -o /dev/null",
[rt:http_url(Node), "/admin"]),
?assertEqual("200", os:cmd(AuthCommand)),
pass.
%% @doc Build a one node cluster.
build_singleton_cluster(Vsn, Config) ->
Nodes = rt:build_cluster([{Vsn, Config}]),
lager:info("Build ~p, nodes: ~p.", [Vsn, Nodes]),
Nodes.
%% @doc Restart node.
%% Since many of the Riak Control configuration options change how
%% the supervisor starts, we need to restart to ensure settings
%% take effect.
restart(Node) ->
rt:stop_and_wait(Node),
rt:start_and_wait(Node),
rt:wait_for_service(Node, riak_kv).