2013-07-23 22:08:07 +00:00
|
|
|
-module(http_security).
|
|
|
|
|
|
|
|
-behavior(riak_test).
|
|
|
|
-export([confirm/0]).
|
|
|
|
|
2013-12-10 23:34:00 +00:00
|
|
|
-export([map_object_value/3, reduce_set_union/2, mapred_modfun_input/3]).
|
|
|
|
|
2013-07-23 22:08:07 +00:00
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
|
2013-12-09 22:03:43 +00:00
|
|
|
-define(assertDenied(Op), ?assertMatch({error, {forbidden, _}}, Op)).
|
|
|
|
|
2013-07-23 22:08:07 +00:00
|
|
|
confirm() ->
|
2013-09-16 20:21:49 +00:00
|
|
|
application:start(crypto),
|
|
|
|
application:start(asn1),
|
|
|
|
application:start(public_key),
|
|
|
|
application:start(ssl),
|
|
|
|
application:start(ibrowse),
|
|
|
|
io:format("turning on tracing"),
|
|
|
|
ibrowse:trace_on(),
|
|
|
|
|
2013-07-23 22:08:07 +00:00
|
|
|
lager:info("Deploy some nodes"),
|
|
|
|
PrivDir = rt:priv_dir(),
|
|
|
|
Conf = [
|
|
|
|
{riak_core, [
|
2013-10-24 04:16:05 +00:00
|
|
|
{default_bucket_props, [{allow_mult, true}]},
|
2013-07-23 22:08:07 +00:00
|
|
|
{ssl, [
|
|
|
|
{certfile, filename:join([PrivDir,
|
|
|
|
"certs/selfsigned/site3-cert.pem"])},
|
|
|
|
{keyfile, filename:join([PrivDir,
|
|
|
|
"certs/selfsigned/site3-key.pem"])}
|
2013-10-24 04:16:05 +00:00
|
|
|
]}
|
2013-12-13 20:48:27 +00:00
|
|
|
]},
|
|
|
|
{riak_search, [
|
|
|
|
{enabled, true}
|
2013-07-23 22:08:07 +00:00
|
|
|
]}
|
|
|
|
],
|
|
|
|
Nodes = rt:build_cluster(4, Conf),
|
|
|
|
Node = hd(Nodes),
|
2013-10-24 04:16:05 +00:00
|
|
|
%% enable security on the cluster
|
|
|
|
ok = rpc:call(Node, riak_core_console, security_enable, [[]]),
|
2013-09-16 20:21:49 +00:00
|
|
|
enable_ssl(Node),
|
|
|
|
%[enable_ssl(N) || N <- Nodes],
|
2013-07-23 22:08:07 +00:00
|
|
|
{ok, [{"127.0.0.1", Port0}]} = rpc:call(Node, application, get_env,
|
2013-09-20 19:52:57 +00:00
|
|
|
[riak_api, http]),
|
2013-07-23 22:08:07 +00:00
|
|
|
{ok, [{"127.0.0.1", Port}]} = rpc:call(Node, application, get_env,
|
2013-09-20 19:52:57 +00:00
|
|
|
[riak_api, https]),
|
2013-07-23 22:08:07 +00:00
|
|
|
|
2013-09-16 20:21:49 +00:00
|
|
|
MD = riak_test_runner:metadata(),
|
|
|
|
_HaveIndexes = case proplists:get_value(backend, MD) of
|
|
|
|
undefined -> false; %% default is da 'cask
|
|
|
|
bitcask -> false;
|
|
|
|
_ -> true
|
|
|
|
end,
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Checking non-SSL results in error"),
|
2013-07-23 22:08:07 +00:00
|
|
|
%% connections over regular HTTP get told to go elsewhere
|
|
|
|
C0 = rhc:create("127.0.0.1", Port0, "riak", []),
|
|
|
|
?assertMatch({error, {ok, "426", _, _}}, rhc:ping(C0)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Checking SSL demands authentication"),
|
2013-07-23 22:08:07 +00:00
|
|
|
C1 = rhc:create("127.0.0.1", Port, "riak", [{is_ssl, true}]),
|
|
|
|
?assertMatch({error, {ok, "401", _, _}}, rhc:ping(C1)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Checking that unknown user demands reauth"),
|
2013-07-23 22:08:07 +00:00
|
|
|
C2 = rhc:create("127.0.0.1", Port, "riak", [{is_ssl, true}, {credentials,
|
|
|
|
"user",
|
|
|
|
"pass"}]),
|
|
|
|
?assertMatch({error, {ok, "401", _, _}}, rhc:ping(C2)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Creating user"),
|
2013-07-23 22:08:07 +00:00
|
|
|
%% grant the user credentials
|
|
|
|
ok = rpc:call(Node, riak_core_console, add_user, [["user", "password=password"]]),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Setting trust mode on user"),
|
2013-07-23 22:08:07 +00:00
|
|
|
%% trust anyone on localhost
|
|
|
|
ok = rpc:call(Node, riak_core_console, add_source, [["user",
|
|
|
|
"127.0.0.1/32",
|
|
|
|
"trust"]]),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Checking that credentials are ignored in trust mode"),
|
2013-07-23 22:08:07 +00:00
|
|
|
%% invalid credentials should be ignored in trust mode
|
|
|
|
C3 = rhc:create("127.0.0.1", Port, "riak", [{is_ssl, true}, {credentials,
|
|
|
|
"user",
|
|
|
|
"pass"}]),
|
|
|
|
?assertEqual(ok, rhc:ping(C3)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Setting password mode on user"),
|
2013-07-23 22:08:07 +00:00
|
|
|
%% require password on localhost
|
|
|
|
ok = rpc:call(Node, riak_core_console, add_source, [["user",
|
|
|
|
"127.0.0.1/32",
|
|
|
|
"password"]]),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Checking that incorrect password demands reauth"),
|
2013-07-23 22:08:07 +00:00
|
|
|
%% invalid credentials should be rejected in password mode
|
|
|
|
C4 = rhc:create("127.0.0.1", Port, "riak", [{is_ssl, true}, {credentials,
|
|
|
|
"user",
|
|
|
|
"pass"}]),
|
|
|
|
?assertMatch({error, {ok, "401", _, _}}, rhc:ping(C4)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Checking that correct password is successful"),
|
2013-07-23 22:08:07 +00:00
|
|
|
%% valid credentials should be accepted in password mode
|
|
|
|
C5 = rhc:create("127.0.0.1", Port, "riak", [{is_ssl, true}, {credentials,
|
|
|
|
"user",
|
|
|
|
"password"}]),
|
2013-07-24 16:42:27 +00:00
|
|
|
|
2013-07-23 22:08:07 +00:00
|
|
|
?assertEqual(ok, rhc:ping(C5)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("verifying the peer certificate rejects mismatch with server cert"),
|
2013-07-24 16:42:27 +00:00
|
|
|
%% verifying the peer certificate reject mismatch with server cert
|
|
|
|
C6 = rhc:create("127.0.0.1", Port, "riak", [{is_ssl, true},
|
|
|
|
{credentials, "user", "password"},
|
|
|
|
{ssl_options, [
|
|
|
|
{cacertfile, filename:join([PrivDir,
|
|
|
|
"certs/cacert.org/ca/root.crt"])},
|
|
|
|
{verify, verify_peer},
|
|
|
|
{reuse_sessions, false}
|
|
|
|
]}
|
|
|
|
]),
|
|
|
|
|
2013-10-21 18:41:27 +00:00
|
|
|
?assertMatch({error,{conn_failed,{error,_}}}, rhc:ping(C6)),
|
2013-07-24 16:42:27 +00:00
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("verifying the peer certificate should work if the cert is valid"),
|
2013-07-24 16:42:27 +00:00
|
|
|
%% verifying the peer certificate should work if the cert is valid
|
|
|
|
C7 = rhc:create("127.0.0.1", Port, "riak", [{is_ssl, true},
|
|
|
|
{credentials, "user", "password"},
|
|
|
|
{ssl_options, [
|
|
|
|
{cacertfile, filename:join([PrivDir,
|
|
|
|
"certs/selfsigned/ca/rootcert.pem"])},
|
|
|
|
{verify, verify_peer},
|
|
|
|
{reuse_sessions, false}
|
|
|
|
]}
|
|
|
|
]),
|
|
|
|
|
|
|
|
?assertEqual(ok, rhc:ping(C7)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("verifying that user cannot get/put without grants"),
|
2013-07-24 16:42:27 +00:00
|
|
|
?assertMatch({error, {ok, "403", _, _}}, rhc:get(C7, <<"hello">>,
|
|
|
|
<<"world">>)),
|
|
|
|
|
|
|
|
Object = riakc_obj:new(<<"hello">>, <<"world">>, <<"howareyou">>,
|
|
|
|
<<"text/plain">>),
|
|
|
|
|
|
|
|
?assertMatch({error, {ok, "403", _, _}}, rhc:put(C7, Object)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Granting riak_kv.get, checking get works but put doesn't"),
|
2013-07-24 16:42:27 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, grant, [["riak_kv.get", "ON",
|
2013-09-16 20:21:49 +00:00
|
|
|
"default", "hello", "TO", "user"]]),
|
2013-07-24 16:42:27 +00:00
|
|
|
|
|
|
|
%% key is not present
|
|
|
|
?assertMatch({error, notfound}, rhc:get(C7, <<"hello">>,
|
|
|
|
<<"world">>)),
|
|
|
|
|
|
|
|
?assertMatch({error, {ok, "403", _, _}}, rhc:put(C7, Object)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Granting riak_kv.put, checking put works and roundtrips with get"),
|
2013-07-24 16:42:27 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, grant, [["riak_kv.put", "ON",
|
2013-09-16 20:21:49 +00:00
|
|
|
"default", "hello", "TO", "user"]]),
|
2013-07-24 16:42:27 +00:00
|
|
|
|
|
|
|
%% NOW we can put
|
2013-09-16 20:21:49 +00:00
|
|
|
?assertEqual(ok, rhc:put(C7, Object)),
|
2013-07-24 16:42:27 +00:00
|
|
|
|
|
|
|
{ok, O} = rhc:get(C7, <<"hello">>, <<"world">>),
|
|
|
|
?assertEqual(<<"hello">>, riakc_obj:bucket(O)),
|
|
|
|
?assertEqual(<<"world">>, riakc_obj:key(O)),
|
|
|
|
?assertEqual(<<"howareyou">>, riakc_obj:get_value(O)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Checking that delete is disallowed"),
|
2013-09-16 20:21:49 +00:00
|
|
|
%% delete
|
|
|
|
?assertMatch({error, {ok, "403", _, _}}, rhc:delete(C7, <<"hello">>,
|
|
|
|
<<"world">>)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Granting riak_kv.delete, checking that delete succeeds"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, grant, [["riak_kv.delete", "ON",
|
|
|
|
"default", "hello", "TO", "user"]]),
|
|
|
|
?assertEqual(ok, rhc:delete(C7, <<"hello">>,
|
|
|
|
<<"world">>)),
|
|
|
|
|
|
|
|
%% key is deleted
|
|
|
|
?assertMatch({error, notfound}, rhc:get(C7, <<"hello">>,
|
|
|
|
<<"world">>)),
|
|
|
|
|
2013-10-26 18:59:01 +00:00
|
|
|
%% write it back for list_buckets later
|
|
|
|
?assertEqual(ok, rhc:put(C7, Object)),
|
|
|
|
|
2013-07-24 16:42:27 +00:00
|
|
|
%% slam the door in the user's face
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Revoking get/put/delete, checking that get/put/delete are disallowed"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, revoke,
|
|
|
|
[["riak_kv.put,riak_kv.get,riak_kv.delete", "ON",
|
|
|
|
"default", "hello", "FROM", "user"]]),
|
2013-07-24 16:42:27 +00:00
|
|
|
|
|
|
|
?assertMatch({error, {ok, "403", _, _}}, rhc:get(C7, <<"hello">>,
|
|
|
|
<<"world">>)),
|
|
|
|
|
|
|
|
?assertMatch({error, {ok, "403", _, _}}, rhc:put(C7, Object)),
|
|
|
|
|
2013-09-16 20:21:49 +00:00
|
|
|
%% list buckets
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Checking that list buckets is disallowed"),
|
2013-09-16 20:21:49 +00:00
|
|
|
?assertMatch({error, {"403", _}}, rhc:list_buckets(C7)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Granting riak_kv.list_buckets, checking that list_buckets succeeds"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, grant, [["riak_kv.list_buckets", "ON",
|
|
|
|
"default", "TO", "user"]]),
|
|
|
|
?assertMatch({ok, [<<"hello">>]}, rhc:list_buckets(C7)),
|
|
|
|
|
|
|
|
%% list keys
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Checking that list keys is disallowed"),
|
2013-09-16 20:21:49 +00:00
|
|
|
?assertMatch({error, {"403", _}}, rhc:list_keys(C7, <<"hello">>)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Granting riak_kv.list_keys, checking that list_keys succeeds"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, grant, [["riak_kv.list_keys", "ON",
|
|
|
|
"default", "TO", "user"]]),
|
|
|
|
|
|
|
|
?assertMatch({ok, [<<"world">>]}, rhc:list_keys(C7, <<"hello">>)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Revoking list_keys"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, revoke, [["riak_kv.list_keys", "ON",
|
|
|
|
"default", "FROM", "user"]]),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Checking that get_bucket is disallowed"),
|
2013-09-16 20:21:49 +00:00
|
|
|
?assertMatch({error, {ok, "403", _, _}}, rhc:get_bucket(C7, <<"hello">>)),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Granting riak_core.get_bucket, checking that get_bucket succeeds"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, grant, [["riak_core.get_bucket", "ON",
|
|
|
|
"default", "hello", "TO", "user"]]),
|
|
|
|
|
|
|
|
?assertEqual(3, proplists:get_value(n_val, element(2, rhc:get_bucket(C7,
|
|
|
|
<<"hello">>)))),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Checking that set_bucket is disallowed"),
|
2013-09-16 20:21:49 +00:00
|
|
|
?assertMatch({error, {ok, "403", _, _}}, rhc:set_bucket(C7, <<"hello">>,
|
|
|
|
[{n_val, 5}])),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Granting set_bucket, checking that set_bucket succeeds"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, grant, [["riak_core.set_bucket", "ON",
|
|
|
|
"default", "hello", "TO", "user"]]),
|
|
|
|
|
|
|
|
?assertEqual(ok, rhc:set_bucket(C7, <<"hello">>,
|
|
|
|
[{n_val, 5}])),
|
|
|
|
|
|
|
|
?assertEqual(5, proplists:get_value(n_val, element(2, rhc:get_bucket(C7,
|
|
|
|
<<"hello">>)))),
|
|
|
|
|
|
|
|
%% counters
|
|
|
|
|
|
|
|
%% grant get/put again
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Granting get/put for counters, checking value and increment"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, grant, [["riak_kv.get,riak_kv.put", "ON",
|
|
|
|
"default", "hello", "TO", "user"]]),
|
|
|
|
|
|
|
|
|
|
|
|
?assertMatch({error, {ok, "404", _, _}}, rhc:counter_val(C7, <<"hello">>,
|
|
|
|
<<"numberofpies">>)),
|
|
|
|
|
|
|
|
ok = rhc:counter_incr(C7, <<"hello">>,
|
|
|
|
<<"numberofpies">>, 5),
|
|
|
|
|
|
|
|
?assertEqual({ok, 5}, rhc:counter_val(C7, <<"hello">>,
|
|
|
|
<<"numberofpies">>)),
|
|
|
|
|
|
|
|
%% revoke get
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Revoking get, checking that value fails but increment succeeds"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, revoke,
|
|
|
|
[["riak_kv.get", "ON", "default", "hello", "FROM", "user"]]),
|
|
|
|
|
|
|
|
?assertMatch({error, {ok, "403", _, _}}, rhc:counter_val(C7, <<"hello">>,
|
|
|
|
<<"numberofpies">>)),
|
|
|
|
ok = rhc:counter_incr(C7, <<"hello">>,
|
|
|
|
<<"numberofpies">>, 5),
|
|
|
|
|
|
|
|
%% revoke put
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Revoking put, checking that increment fails"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, revoke,
|
|
|
|
[["riak_kv.put", "ON", "default", "hello", "FROM", "user"]]),
|
|
|
|
|
|
|
|
?assertMatch({error, {ok, "403", _, _}}, rhc:counter_incr(C7, <<"hello">>,
|
|
|
|
<<"numberofpies">>, 5)),
|
|
|
|
|
|
|
|
%% mapred tests
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Checking that full-bucket mapred is disallowed"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, grant, [["riak_kv.put", "ON",
|
|
|
|
"default", "MR", "TO", "user"]]),
|
|
|
|
|
|
|
|
|
|
|
|
ok = rhc:put(C7, riakc_obj:new(<<"MR">>, <<"lobster_roll">>, <<"16">>,
|
|
|
|
<<"text/plain">>)),
|
|
|
|
|
|
|
|
ok = rhc:put(C7, riakc_obj:new(<<"MR">>, <<"pickle_plate">>, <<"9">>,
|
|
|
|
<<"text/plain">>)),
|
|
|
|
|
|
|
|
ok = rhc:put(C7, riakc_obj:new(<<"MR">>, <<"pimms_cup">>, <<"8">>,
|
|
|
|
<<"text/plain">>)),
|
|
|
|
|
|
|
|
?assertMatch({error, {"403", _}},
|
|
|
|
rhc:mapred_bucket(C7, <<"MR">>, [{map, {jsfun,
|
|
|
|
<<"Riak.mapValuesJson">>}, undefined, false},
|
|
|
|
{reduce, {jsfun,
|
|
|
|
<<"Riak.reduceSum">>}, undefined,
|
|
|
|
true}])),
|
2013-10-01 14:59:15 +00:00
|
|
|
|
|
|
|
lager:info("Granting list-keys, asserting full-bucket mapred is still disallowed"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, grant, [["riak_kv.list_keys", "ON",
|
|
|
|
"default", "MR", "TO", "user"]]),
|
|
|
|
|
|
|
|
?assertMatch({error, {"403", _}},
|
|
|
|
rhc:mapred_bucket(C7, <<"MR">>, [{map, {jsfun,
|
|
|
|
<<"Riak.mapValuesJson">>}, undefined, false},
|
|
|
|
{reduce, {jsfun,
|
|
|
|
<<"Riak.reduceSum">>}, undefined,
|
|
|
|
true}])),
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Granting mapreduce, checking that job succeeds"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, grant, [["riak_kv.mapreduce", "ON",
|
|
|
|
"default", "MR", "TO", "user"]]),
|
|
|
|
|
|
|
|
?assertEqual({ok, [{1, [33]}]},
|
|
|
|
rhc:mapred_bucket(C7, <<"MR">>, [{map, {jsfun,
|
|
|
|
<<"Riak.mapValuesJson">>}, undefined, false},
|
|
|
|
{reduce, {jsfun,
|
|
|
|
<<"Riak.reduceSum">>}, undefined,
|
|
|
|
true}])),
|
|
|
|
|
2013-12-10 23:34:00 +00:00
|
|
|
%% load this module on all the nodes
|
|
|
|
ok = rt:load_modules_on_nodes([?MODULE], Nodes),
|
|
|
|
|
|
|
|
lager:info("checking erlang mapreduce works"),
|
|
|
|
?assertMatch({ok, [{1, _}]},
|
|
|
|
rhc:mapred_bucket(C7, <<"MR">>, [{map, {modfun,
|
|
|
|
riak_kv_mapreduce,
|
|
|
|
map_object_value}, undefined, false},
|
|
|
|
{reduce, {modfun,
|
|
|
|
riak_kv_mapreduce,
|
|
|
|
reduce_set_union}, undefined,
|
|
|
|
true}])),
|
|
|
|
|
|
|
|
lager:info("checking that insecure input modfun fails"),
|
|
|
|
?assertMatch({error, _},
|
|
|
|
rhc:mapred_bucket(C7, {modfun, ?MODULE, mapred_modfun_input,
|
|
|
|
[]}, [{map, {modfun,
|
|
|
|
riak_kv_mapreduce,
|
|
|
|
map_object_value}, undefined, false},
|
|
|
|
{reduce, {modfun,
|
|
|
|
riak_kv_mapreduce,
|
|
|
|
reduce_set_union}, undefined,
|
|
|
|
true}])),
|
|
|
|
|
|
|
|
lager:info("checking that insecure query modfuns fail"),
|
|
|
|
?assertMatch({error, _},
|
|
|
|
rhc:mapred_bucket(C7, <<"MR">>, [{map, {modfun,
|
|
|
|
?MODULE,
|
|
|
|
map_object_value}, undefined, false},
|
|
|
|
{reduce, {modfun,
|
|
|
|
?MODULE,
|
|
|
|
reduce_set_union}, undefined,
|
|
|
|
true}])),
|
|
|
|
|
|
|
|
lager:info("whitelisting module path"),
|
|
|
|
ok = rpc:call(Node, application, set_env, [riak_kv, add_paths,
|
|
|
|
[filename:dirname(code:which(?MODULE))]]),
|
|
|
|
|
|
|
|
lager:info("checking that insecure input modfun fails when whitelisted but"
|
|
|
|
" lacking permissions"),
|
|
|
|
?assertMatch({error, {"403", _}},
|
|
|
|
rhc:mapred_bucket(C7, {modfun, ?MODULE, mapred_modfun_input,
|
|
|
|
[]}, [{map, {modfun,
|
|
|
|
riak_kv_mapreduce,
|
|
|
|
map_object_value}, undefined, false},
|
|
|
|
{reduce, {modfun,
|
|
|
|
riak_kv_mapreduce,
|
|
|
|
reduce_set_union}, undefined,
|
|
|
|
true}])),
|
|
|
|
|
|
|
|
ok = rpc:call(Node, riak_core_console, grant, [["riak_kv.mapreduce", "ON",
|
|
|
|
"ANY", "TO", "user"]]),
|
|
|
|
|
|
|
|
lager:info("checking that insecure input modfun works when whitelisted and"
|
|
|
|
" has permissions"),
|
|
|
|
?assertMatch({ok, _},
|
|
|
|
rhc:mapred_bucket(C7, {modfun, ?MODULE, mapred_modfun_input,
|
|
|
|
[]}, [{map, {modfun,
|
|
|
|
riak_kv_mapreduce,
|
|
|
|
map_object_value}, undefined, false},
|
|
|
|
{reduce, {modfun,
|
|
|
|
riak_kv_mapreduce,
|
|
|
|
reduce_set_union}, undefined,
|
|
|
|
true}])),
|
|
|
|
|
|
|
|
ok = rpc:call(Node, riak_core_console, revoke, [["riak_kv.mapreduce", "ON",
|
|
|
|
"ANY", "FROM", "user"]]),
|
|
|
|
|
|
|
|
lager:info("checking that insecure query modfuns works when whitelisted"),
|
|
|
|
?assertMatch({ok, _},
|
|
|
|
rhc:mapred_bucket(C7, <<"MR">>, [{map, {modfun,
|
|
|
|
?MODULE,
|
|
|
|
map_object_value}, undefined, false},
|
|
|
|
{reduce, {modfun,
|
|
|
|
?MODULE,
|
|
|
|
reduce_set_union}, undefined,
|
|
|
|
true}])),
|
|
|
|
|
|
|
|
|
2013-10-01 14:59:15 +00:00
|
|
|
lager:info("Revoking list-keys, checking that full-bucket mapred fails"),
|
2013-09-16 20:21:49 +00:00
|
|
|
ok = rpc:call(Node, riak_core_console, revoke, [["riak_kv.list_keys", "ON",
|
|
|
|
"default", "MR", "FROM", "user"]]),
|
|
|
|
|
|
|
|
?assertMatch({error, {"403", _}},
|
|
|
|
rhc:mapred_bucket(C7, <<"MR">>, [{map, {jsfun,
|
|
|
|
<<"Riak.mapValuesJson">>}, undefined, false},
|
|
|
|
{reduce, {jsfun,
|
|
|
|
<<"Riak.reduceSum">>}, undefined,
|
|
|
|
true}])),
|
2013-12-09 22:03:43 +00:00
|
|
|
|
|
|
|
crdt_tests(Nodes, C7),
|
2013-12-13 20:48:27 +00:00
|
|
|
|
|
|
|
URL = lists:flatten(io_lib:format("https://127.0.0.1:~b", [Port])),
|
|
|
|
|
|
|
|
lager:info("checking link walking fails because it is deprecated"),
|
|
|
|
|
|
|
|
?assertMatch({ok, "403", _, <<"Link walking is deprecated", _/binary>>},
|
|
|
|
ibrowse:send_req(URL ++ "/riak/hb/first/_,_,_", [], get,
|
|
|
|
[], [{response_format, binary}, {is_ssl, true},
|
|
|
|
{ssl_options, [
|
|
|
|
{cacertfile, filename:join([PrivDir,
|
|
|
|
"certs/selfsigned/ca/rootcert.pem"])},
|
|
|
|
{verify, verify_peer},
|
|
|
|
{reuse_sessions, false}]}])),
|
|
|
|
|
2013-12-26 23:05:54 +00:00
|
|
|
lager:info("checking search 1.0 403s because search won't allow"
|
|
|
|
"connections with security enabled"),
|
2013-12-13 20:48:27 +00:00
|
|
|
|
2013-12-26 23:05:54 +00:00
|
|
|
?assertMatch({ok, "403", _, <<"Riak Search 1.0 is deprecated", _/binary>>},
|
2013-12-13 20:48:27 +00:00
|
|
|
ibrowse:send_req(URL ++ "/solr/index/select?q=foo:bar&wt=json", [], get,
|
|
|
|
[], [{response_format, binary}, {is_ssl, true},
|
|
|
|
{ssl_options, [
|
|
|
|
{cacertfile, filename:join([PrivDir,
|
|
|
|
"certs/selfsigned/ca/rootcert.pem"])},
|
|
|
|
{verify, verify_peer},
|
|
|
|
{reuse_sessions, false}]}])),
|
2013-07-23 22:08:07 +00:00
|
|
|
ok.
|
|
|
|
|
|
|
|
enable_ssl(Node) ->
|
2013-09-20 19:52:57 +00:00
|
|
|
[{http, {_IP, Port}}|_] = rt:connection_info(Node),
|
|
|
|
rt:update_app_config(Node, [{riak_api, [{https, [{"127.0.0.1",
|
2013-07-23 22:08:07 +00:00
|
|
|
Port+1000}]}]}]),
|
|
|
|
rt:wait_until_pingable(Node),
|
|
|
|
rt:wait_for_service(Node, riak_kv).
|
|
|
|
|
2013-12-10 23:34:00 +00:00
|
|
|
map_object_value(RiakObject, A, B) ->
|
|
|
|
riak_kv_mapreduce:map_object_value(RiakObject, A, B).
|
|
|
|
|
|
|
|
reduce_set_union(List, A) ->
|
|
|
|
riak_kv_mapreduce:reduce_set_union(List, A).
|
2013-07-23 22:08:07 +00:00
|
|
|
|
2013-12-10 23:34:00 +00:00
|
|
|
mapred_modfun_input(Pipe, _Args, _Timeout) ->
|
|
|
|
riak_pipe:queue_work(Pipe, {{<<"MR">>, <<"lobster_roll">>}, {struct, []}}),
|
|
|
|
riak_pipe:eoi(Pipe).
|
2013-07-23 22:08:07 +00:00
|
|
|
|
2013-12-09 22:03:43 +00:00
|
|
|
crdt_tests([Node|_]=Nodes, RHC) ->
|
|
|
|
lager:info("Creating bucket types for CRDTs"),
|
|
|
|
Types = [{<<"counters">>, counter, riakc_counter:to_op(riakc_counter:increment(5, riakc_counter:new()))},
|
|
|
|
{<<"sets">>, set, riakc_set:to_op(riakc_set:add_element(<<"foo">>, riakc_set:new()))},
|
|
|
|
{<<"maps">>, map, riakc_map:to_op(riakc_map:add({<<"bar">>, counter}, riakc_map:new()))}],
|
|
|
|
[ begin
|
|
|
|
rt:create_and_activate_bucket_type(Node, BType, [{allow_mult, true}, {datatype, DType}]),
|
|
|
|
rt:wait_until_bucket_type_status(BType, active, Nodes)
|
|
|
|
end || {BType, DType, _Op} <- Types ],
|
|
|
|
|
|
|
|
lager:info("Checking that CRDT fetch is denied"),
|
|
|
|
|
|
|
|
[ ?assertDenied(rhc:fetch_type(RHC, {BType, <<"bucket">>}, <<"key">>))
|
|
|
|
|| {BType, _, _} <- Types],
|
|
|
|
|
|
|
|
lager:info("Granting CRDT riak_kv.get, checking that fetches succeed"),
|
|
|
|
|
|
|
|
[ grant(Node, ["riak_kv.get", "ON", binary_to_list(Type), "TO", "user"]) || {Type, _, _} <- Types ],
|
|
|
|
|
|
|
|
[ ?assertEqual({error, {notfound, DType}},
|
|
|
|
(rhc:fetch_type(RHC, {BType, <<"bucket">>}, <<"key">>))) ||
|
|
|
|
{BType, DType, _, _} <- Types],
|
|
|
|
|
|
|
|
lager:info("Checking that CRDT update is denied"),
|
|
|
|
|
|
|
|
[ ?assertDenied(rhc:update_type(RHC, {BType, <<"bucket">>}, <<"key">>, Op))
|
|
|
|
|| {BType, _, Op} <- Types],
|
|
|
|
|
|
|
|
|
|
|
|
lager:info("Granting CRDT riak_kv.put, checking that updates succeed"),
|
|
|
|
|
|
|
|
[ grant(Node, ["riak_kv.put", "ON", binary_to_list(Type), "TO", "user"]) || {Type, _, _} <- Types ],
|
|
|
|
|
|
|
|
[?assertEqual(ok, (rhc:update_type(RHC, {BType, <<"bucket">>}, <<"key">>, Op)))
|
|
|
|
|| {BType, _, Op} <- Types],
|
|
|
|
|
|
|
|
ok.
|
|
|
|
|
|
|
|
grant(Node, Args) ->
|
|
|
|
ok = rpc:call(Node, riak_core_console, grant, [Args]).
|