%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2005-2013. All Rights Reserved. %% %% Licensed 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. %% %% %CopyrightEnd% %% %% -module(httpd_mod). -include("test_server.hrl"). %% General testcases bodies called from httpd_SUITE -export([alias/4, actions/4, security/5, auth/4, auth_api/6, auth_mnesia_api/4, htaccess/4, cgi/4, esi/4, get/4, head/4, all/4]). %% Help functions -export([event/4, ssl_password_cb/0]). %% Seconds before successful auths timeout. -define(AUTH_TIMEOUT,5). %%------------------------------------------------------------------------- %% Test cases starts here. %%------------------------------------------------------------------------- alias(Type, Port, Host, Node) -> %% This is very crude, but... Opts = [], ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /pics/icon.sheet.gif " "HTTP/1.0\r\n\r\n", [{statuscode, 200}, {header, "Content-Type","image/gif"}, {header, "Server"}, {header, "Date"}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET / HTTP/1.0\r\n\r\n", [{statuscode, 200}, {header, "Content-Type","text/html"}, {header, "Server"}, {header, "Date"}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /misc/ HTTP/1.0\r\n\r\n", [{statuscode, 200}, {header, "Content-Type","text/html"}, {header, "Server"}, {header, "Date"}, {version, "HTTP/1.0"}]), %% Check redirection if trailing slash is missing. ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /misc HTTP/1.0\r\n\r\n", [{statuscode, 301}, {header, "Location"}, {header, "Content-Type","text/html"}, {version, "HTTP/1.0"}]). %%------------------------------------------------------------------------- actions(Type, Port, Host, Node) -> ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "HEAD / HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]). %%------------------------------------------------------------------------- security(ServerRoot, Type, Port, Host, Node) -> global:register_name(mod_security_test, self()), % Receive events tsp("security -> " "sleep"), test_server:sleep(5000), OpenDir = filename:join([ServerRoot, "htdocs", "open"]), %% Test blocking / unblocking of users. %% /open, require user one Aladdin tsp("security -> " "blocking and unblocking of users - " "remove all existing users"), remove_users(Node, ServerRoot, Host, Port, "open"), tsp("security -> " "blocking and unblocking of users - " "auth request for nonex user 'one' - expect 401"), auth_request(Type, Host, Port, Node, "/open/", "one", "onePassword", [{statuscode, 401}]), tsp("security -> " "blocking and unblocking of users - " "await fail security event"), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "one"}, {password, "onePassword"}]}, Node, Port), tsp("security -> " "blocking and unblocking of users - " "auth request for nonex user 'two' - expect 401"), auth_request(Type,Host,Port,Node,"/open/", "two", "twoPassword", [{statuscode, 401}]), tsp("security -> " "blocking and unblocking of users - " "await fail security event"), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "two"}, {password, "twoPassword"}]}, Node, Port), tsp("security -> " "blocking and unblocking of users - " "auth request for nonex user 'Alladin' - expect 401"), auth_request(Type, Host, Port, Node,"/open/", "Aladdin", "AladdinPassword", [{statuscode, 401}]), tsp("security -> " "blocking and unblocking of users - " "await fail security event"), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "Aladdin"}, {password, "AladdinPassword"}]}, Node, Port), tsp("security -> " "blocking and unblocking of users - " "add user 'one'"), add_user(Node, ServerRoot, Port, "open", "one", "onePassword", []), tsp("security -> " "blocking and unblocking of users - " "add user 'two'"), add_user(Node, ServerRoot, Port, "open", "two", "twoPassword", []), tsp("security -> " "blocking and unblocking of users - " "auth request 1 for user 'one' with wrong password - expect 401"), auth_request(Type, Host, Port, Node,"/open/", "one", "WrongPassword", [{statuscode, 401}]), tsp("security -> " "blocking and unblocking of users - " "await fail security event"), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "one"}, {password, "WrongPassword"}]}, Node, Port), tsp("security -> " "blocking and unblocking of users - " "auth request 2 for user 'one' with wrong password - expect 401"), auth_request(Type, Host, Port, Node,"/open/", "one", "WrongPassword", [{statuscode, 401}]), tsp("security -> " "blocking and unblocking of users - " "await fail security event"), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "one"}, {password, "WrongPassword"}]}, Node, Port), tsp("security -> " "blocking and unblocking of users - " "await block security event (two failed attempts)"), receive_security_event({event, user_block, Port, OpenDir, [{user, "one"}]}, Node, Port), tsp("security -> " "blocking and unblocking of users - " "unregister - no more security events"), global:unregister_name(mod_security_test), % No more events. tsp("security -> " "blocking and unblocking of users - " "auth request for user 'one' with wrong password - expect 401"), auth_request(Type, Host, Port, Node,"/open/", "one", "WrongPassword", [{statuscode, 401}]), tsp("security -> " "blocking and unblocking of users - " "auth request for user 'one' with correct password - expect 403"), auth_request(Type, Host, Port, Node,"/open/", "one", "onePassword", [{statuscode, 403}]), %% User "one" should be blocked now.. tsp("security -> " "blocking and unblocking of users - " "list blocked users - 'one' should be the only one"), case list_blocked_users(Node, Port) of [{"one",_, Port, OpenDir,_}] -> ok; Blocked -> tsp(" *** unexpected blocked users ***" "~n Blocked: ~p", [Blocked]), exit({unexpected_blocked, Blocked}) end, tsp("security -> " "blocking and unblocking of users - " "list users blocked for dir '~p' - " "user 'one' should be the only one", [OpenDir]), [{"one",_, Port, OpenDir,_}] = list_blocked_users(Node, Port, OpenDir), tsp("security -> " "blocking and unblocking of users - " "unblock user 'one' for dir '~p'", [OpenDir]), true = unblock_user(Node, "one", Port, OpenDir), %% User "one" should not be blocked any more. tsp("security -> " "blocking and unblocking of users - " "ensure user 'one' is no longer blocked"), [] = list_blocked_users(Node, Port), tsp("security -> " "blocking and unblocking of users - " "auth request for user 'one' with correct password - expect 200"), auth_request(Type, Host, Port, Node,"/open/", "one", "onePassword", [{statuscode, 200}]), %% Test list_auth_users & auth_timeout tsp("security -> " "list-auth-users and auth-timeout - " "list auth users - expect user 'one'"), ["one"] = list_auth_users(Node, Port), tsp("security -> " "list-auth-users and auth-timeout - " "auth request for user 'two' with wrong password - expect 401"), auth_request(Type, Host, Port, Node,"/open/", "two", "onePassword", [{statuscode, 401}]), tsp("security -> " "list-auth-users and auth-timeout - " "list auth users - expect user 'one'"), ["one"] = list_auth_users(Node, Port), tsp("security -> " "list-auth-users and auth-timeout - " "list auth users for dir '~p' - expect user 'one'", [OpenDir]), ["one"] = list_auth_users(Node, Port, OpenDir), tsp("security -> " "list-auth-users and auth-timeout - " "auth request for user 'two' with correct password - expect 401"), auth_request(Type, Host, Port, Node,"/open/", "two", "twoPassword", [{statuscode, 401}]), tsp("security -> " "list-auth-users and auth-timeout - " "list auth users - expect user 'one'"), ["one"] = list_auth_users(Node, Port), tsp("security -> " "list-auth-users and auth-timeout - " "list auth users for dir '~p' - expect user 'one'", [OpenDir]), ["one"] = list_auth_users(Node, Port, OpenDir), %% Wait for successful auth to timeout. tsp("security -> " "list-auth-users and auth-timeout - " "wait for successful auth to timeout"), test_server:sleep(?AUTH_TIMEOUT*1001), tsp("security -> " "list-auth-users and auth-timeout - " "list auth users - expect none"), [] = list_auth_users(Node, Port), tsp("security -> " "list-auth-users and auth-timeout - " "list auth users for dir '~p'~n - expect none", [OpenDir]), [] = list_auth_users(Node, Port, OpenDir), %% "two" is blocked. tsp("security -> " "list-auth-users and auth-timeout - " "unblock user 'two' for dir '~p'", [OpenDir]), true = unblock_user(Node, "two", Port, OpenDir), %% Test explicit blocking. Block user 'two'. tsp("security -> " "explicit blocking - list blocked users - should be none"), [] = list_blocked_users(Node,Port,OpenDir), tsp("security -> " "explicit blocking - " "block user 'two' for dir '~p'", [OpenDir]), true = block_user(Node, "two", Port, OpenDir, 10), tsp("security -> " "explicit blocking - " "auth request for user 'two' with correct password - expect 401"), auth_request(Type, Host, Port, Node,"/open/", "two", "twoPassword", [{statuscode, 401}]), tsp("security -> " "done"). %%------------------------------------------------------------------------- auth(Type, Port, Host, Node) -> %% Authentication required! ok = httpd_test_lib:verify_request(Type,Host,Port,Node, "GET /open/ HTTP/1.0\r\n\r\n", [{statuscode, 401}, {version, "HTTP/1.0"}, {header, "WWW-Authenticate"}]), ok = httpd_test_lib:verify_request(Type,Host,Port,Node, "GET /secret/ HTTP/1.0\r\n\r\n", [{statuscode, 401}, {version, "HTTP/1.0"}, {header, "WWW-Authenticate"}]), ok = httpd_test_lib:verify_request(Type,Host,Port,Node, "GET /secret/top_secret/" " HTTP/1.0\r\n\r\n", [{statuscode, 401}, {version, "HTTP/1.0"}, {header, "WWW-Authenticate"}]), %% Authentication OK! ["one:OnePassword" user first in user list] auth_request(Type, Host, Port, Node, "/open/dummy.html", "one", "onePassword", [{statuscode, 200}]), %% Authentication OK and a directory listing is supplied! %% ["Aladdin:open sesame" user second in user list] auth_request(Type, Host, Port, Node, "/open/","Aladdin", "AladdinPassword", [{statuscode, 200}]), %% User correct but wrong password! ["one:one" user first in user list] auth_request(Type, Host, Port, Node, "/open/", "one", "one", [{statuscode, 401},{header, "WWW-Authenticate"}]), %% Make sure Authenticate header is received even the second time %% we try a incorrect password! Otherwise a browser client will hang! auth_request(Type, Host, Port, Node, "/open/", "one", "one", [{statuscode, 401},{header, "WWW-Authenticate"}]), %% Neither user or password correct! ["dummy:dummy"] auth_request(Type, Host, Port, Node, "/open/", "dummy", "dummy", [{statuscode, 401}]), %% Authentication OK! ["two:TwoPassword" user in first group] auth_request(Type, Host, Port, Node, "/secret/dummy.html", "two", "twoPassword", [{statuscode, 200}]), %% Authentication OK and a directory listing is supplied! %% ["three:ThreePassword" user in second group] auth_request(Type, Host, Port, Node,"/secret/", "three", "threePassword", [{statuscode, 200}]), %% User correct but wrong password! ["two:two" user in first group] auth_request(Type, Host, Port, Node, "/secret/", "two", "two", [{statuscode, 401}]), %% Neither user or password correct! ["dummy:dummy"] auth_request(Type, Host, Port, Node,"/secret/", "dummy", "dummy", [{statuscode, 401}]), %% Nested secret/top_secret OK! ["Aladdin:open sesame"] auth_request(Type, Host, Port, Node, "/secret/top_secret/", "Aladdin", "AladdinPassword", [{statuscode, 200}]), %% Authentication still required! ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /open/ " "HTTP/1.0\r\n\r\n", [{statuscode, 401}, {version, "HTTP/1.0"}, {header, "WWW-Authenticate"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /secret/ " "HTTP/1.0\r\n\r\n", [{statuscode, 401}, {version, "HTTP/1.0"}, {header, "WWW-Authenticate"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /secret/top_secret/ " "HTTP/1.0\r\n\r\n", [{statuscode, 401}, {version, "HTTP/1.0"}, {header, "WWW-Authenticate"}]). %%------------------------------------------------------------------------- %% What to test here: %% %% /open - plain, require user one Aladdin %% /secret - plain, require group group1 group2 %% /secret/top_secret - plain, require group group3 %% /dets_open - dets, require user one Aladdin %% /dets_secret - dets, require group group1 group2 %% /dets_secret/top_secret - dets, require group group3 %% /mnesia_open/ - mnesia, require user one Aladdin %% /mnesia_secret/ - mnesia, require group group1 group2 %% /mnesia_secret/top_secret/ - mnesia, require group group3 auth_api(ServerRoot, AuthStoreType, Type, Port, Host, Node) -> ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET / HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), auth_request(Type, Host, Port, Node, "/", "one", "WrongPassword", [{statuscode, 200}]), %% Make sure Authenticate header is received even the second time %% we try a incorrect password! Otherwise a browser client will hang! auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/", "dummy", "WrongPassword", [{statuscode, 401}, {header, "WWW-Authenticate"}]), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/", "dummy", "WrongPassword", [{statuscode, 401}, {header, "WWW-Authenticate"}]), %% Change the password to DummyPassword then try to add a user %% Get an error and set it to NoPassword ok = update_password(Node, ServerRoot, Host, Port, AuthStoreType ++ "open", "NoPassword", "DummyPassword"), {error,bad_password} = add_user(Node, ServerRoot, Port, AuthStoreType ++ "open", "one", "onePassword", []), ok = update_password(Node, ServerRoot, Host, Port, AuthStoreType ++"open", "DummyPassword", "NoPassword"), %% Test /*open, require user one Aladdin remove_users(Node, ServerRoot, Host, Port, AuthStoreType ++ "open"), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/", "one", "onePassword", [{statuscode, 401}]), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/", "two", "twoPassword", [{statuscode, 401}]), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/", "Aladdin", "onePassword", [{statuscode, 401}]), add_user(Node, ServerRoot, Port, AuthStoreType ++ "open", "one", "onePassword", []), add_user(Node, ServerRoot, Port, AuthStoreType ++ "open", "two", "twoPassword", []), add_user(Node, ServerRoot, Port, AuthStoreType ++ "open", "Aladdin", "AladdinPassword", []), {ok, [_|_]} = list_users(Node, ServerRoot, Host, Port, AuthStoreType++"open"), auth_request(Type, Host, Port, Node, "/" ++ AuthStoreType ++ "open/", "one", "WrongPassword", [{statuscode, 401}]), auth_request(Type, Host, Port, Node, "/" ++ AuthStoreType ++ "open/", "one", "onePassword", [{statuscode, 200}]), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/", "two", "twoPassword", [{statuscode, 401}]), auth_request(Type, Host, Port, Node, "/" ++ AuthStoreType ++ "open/", "Aladdin", "WrongPassword", [{statuscode, 401}]), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/", "Aladdin", "AladdinPassword", [{statuscode, 200}]), remove_users(Node, ServerRoot, Host, Port, AuthStoreType++"open"), {ok, []} = list_users(Node, ServerRoot, Host, Port, AuthStoreType++"open"), %% Phase 2 remove_users(Node, ServerRoot, Host, Port, AuthStoreType++"secret"), {ok, []} = list_users(Node, ServerRoot, Host, Port, AuthStoreType ++ "secret"), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/", "one", "onePassword", [{statuscode, 401}]), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/", "two", "twoPassword", [{statuscode, 401}]), auth_request(Type, Host, Port, Node, "/" ++ AuthStoreType ++ "secret/", "three", "threePassword", [{statuscode, 401}]), add_user(Node, ServerRoot, Port, AuthStoreType ++ "secret", "one", "onePassword", []), add_user(Node, ServerRoot, Port, AuthStoreType ++ "secret", "two", "twoPassword", []), add_user(Node, ServerRoot, Port, AuthStoreType++"secret", "Aladdin", "AladdinPassword",[]), add_group_member(Node, ServerRoot, Port, AuthStoreType ++ "secret", "one", "group1"), add_group_member(Node, ServerRoot, Port, AuthStoreType ++ "secret", "two", "group1"), add_group_member(Node, ServerRoot, Port, AuthStoreType ++ "secret", "Aladdin", "group2"), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/", "one", "onePassword", [{statuscode, 200}]), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/", "two", "twoPassword", [{statuscode, 200}]), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/", "Aladdin", "AladdinPassword", [{statuscode, 200}]), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/", "three", "threePassword", [{statuscode, 401}]), remove_users(Node, ServerRoot, Host, Port, AuthStoreType ++ "secret"), {ok, []} = list_users(Node, ServerRoot, Host, Port, AuthStoreType ++ "secret"), remove_groups(Node, ServerRoot, Host, Port, AuthStoreType ++ "secret"), Directory = filename:join([ServerRoot, "htdocs", AuthStoreType ++ "secret"]), {ok, []} = list_groups(Node, ServerRoot, Host, Port, Directory), %% Phase 3 remove_users(Node, ServerRoot, Host, Port, AuthStoreType ++ "secret/top_secret"), remove_groups(Node, ServerRoot, Host, Port, AuthStoreType ++ "secret/top_secret"), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/top_secret/", "three", "threePassword", [{statuscode, 401}]), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/top_secret/", "two", "twoPassword", [{statuscode, 401}]), add_user(Node, ServerRoot, Port, AuthStoreType ++ "secret/top_secret","three", "threePassword",[]), add_user(Node, ServerRoot, Port, AuthStoreType ++ "secret/top_secret", "two","twoPassword", []), add_group_member(Node, ServerRoot, Port, AuthStoreType ++ "secret/top_secret", "three", "group3"), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/top_secret/", "three", "threePassword", [{statuscode, 200}]), auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/top_secret/", "two", "twoPassword", [{statuscode, 401}]), add_group_member(Node, ServerRoot, Port, AuthStoreType ++ "secret/top_secret", "two", "group3"), auth_request(Type,Host,Port,Node,"/" ++ AuthStoreType ++ "secret/top_secret/", "two", "twoPassword", [{statuscode, 200}]), remove_users(Node, ServerRoot, Host, Port, AuthStoreType ++ "secret/top_secret"), {ok, []} = list_users(Node, ServerRoot, Host, Port, AuthStoreType ++ "secret/top_secret"), remove_groups(Node, ServerRoot, Host, Port, AuthStoreType ++ "secret/top_secret"), Directory2 = filename:join([ServerRoot, "htdocs", AuthStoreType ++ "secret/top_secret"]), {ok, []} = list_groups(Node, ServerRoot, Host, Port, Directory2), auth_request(Type, Host, Port, Node, "/" ++ AuthStoreType ++ "secret/top_secret/", "two", "twoPassword", [{statuscode, 401}]), auth_request(Type, Host, Port, Node, "/" ++ AuthStoreType ++ "secret/top_secret/","three", "threePassword", [{statuscode, 401}]). %%-------------------------------------------------------------------------- auth_mnesia_api(_Type, Port, _Host, _Node) -> %% Create three groups: %% group1 : one Aladdin %% group2 : two %% group3 : three mod_auth_mnesia:store_user("one", "onePassword", Port, "/mnesia_open", ""), mod_auth_mnesia:store_user("Aladdin", "AladdinPassword", Port, "/mnesia_open", ""), mod_auth_mnesia:store_user("two", "twoPassword", Port, "/mnesia_open", ""), mod_auth_mnesia:store_user("three", "threePassword", Port, "/mnesia_open", ""), Users = mod_auth_mnesia:list_users(Port, "/mnesia_open"), ok = check_lists_members(Users,["Aladdin","one","two","three"]), true = mod_auth_mnesia:store_group_member("group1", "one", Port, "/mnesia_open", ""), true = mod_auth_mnesia:store_group_member("group1","Aladdin", Port, "/mnesia_open", ""), true = mod_auth_mnesia:store_group_member("group2","two", Port, "/mnesia_open", ""), true = mod_auth_mnesia:store_group_member("group3","three", Port, "/mnesia_open", ""), %% Check that all three created groups exist. Groups = mod_auth_mnesia:list_groups(Port, "/mnesia_open"), ok = check_lists_members(Groups, ["group1","group2","group3"]), %% Check that the members of all groups are correct. Group1 = mod_auth_mnesia:list_group_members("group1", Port, "/mnesia_open"), ok = check_lists_members(Group1,["one","Aladdin"]), {ok,["two"]} = mod_auth_mnesia:list_group_members("group2", Port, "/mnesia_open"), {ok,["three"]} = mod_auth_mnesia:list_group_members("group3", Port, "/mnesia_open"), %% Delete user 'one' from group one and check that he was removed %% correctly. true = mod_auth_mnesia:remove_group_member("group1", "one", Port, "/mnesia_open", ""), {ok,["Aladdin"]} = mod_auth_mnesia:list_group_members("group1", Port, "/mnesia_open"), %% Remove group1 and check that the group was removed correctly. true = mod_auth_mnesia:remove_group("group1", Port, "/mnesia_open", ""), Groups_1 = mod_auth_mnesia:list_groups(Port, "/mnesia_open"), ok = check_lists_members(Groups_1,["group2","group3"]), %% Check that the other users still exist in their groups. Users_1 = mod_auth_mnesia:list_users(Port, "/mnesia_open"), ok = check_lists_members(Users_1,["Aladdin","one","two","three"]), {ok,["two"]} = mod_auth_mnesia:list_group_members("group2", Port, "/mnesia_open"), {ok,["three"]} = mod_auth_mnesia:list_group_members("group3", Port, "/mnesia_open"), %% Remove the remaining groups/users and check that all %% users/groups are removed. true = mod_auth_mnesia:remove_group("group2", Port, "/mnesia_open", ""), true = mod_auth_mnesia:remove_group("group3", Port, "/mnesia_open", ""), {ok, []} = mod_auth_mnesia:list_groups(Port, "/mnesia_open"), true = mod_auth_mnesia:remove_user("one", Port, "/mnesia_open", ""), true = mod_auth_mnesia:remove_user("Aladdin", Port, "/mnesia_open", ""), true = mod_auth_mnesia:remove_user("two", Port, "/mnesia_open", ""), true = mod_auth_mnesia:remove_user("three", Port, "/mnesia_open", ""), {ok, []} = mod_auth_mnesia:list_users(Port, "/mnesia_open"), ok. %%-------------------------------------------------------------------------- htaccess(Type, Port, Host, Node) -> %% Control that authentication required! %% Control that the pages that shall be %% authenticated really need authenticatin ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /ht/open/ HTTP/1.0\r\n\r\n", [{statuscode, 401}, {version, "HTTP/1.0"}, {header, "WWW-Authenticate"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /ht/secret/ HTTP/1.0\r\n\r\n", [{statuscode, 401}, {version, "HTTP/1.0"}, {header, "WWW-Authenticate"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /ht/secret/top_secret/ " "HTTP/1.0\r\n\r\n", [{statuscode, 401}, {version, "HTTP/1.0"}, {header, "WWW-Authenticate"}]), %% Make sure Authenticate header is received even the second time %% we try a incorrect password! Otherwise a browser client will hang! auth_request(Type, Host, Port, Node,"/ht/open/", "dummy", "WrongPassword", [{statuscode, 401}, {header, "WWW-Authenticate"}]), auth_request(Type, Host, Port, Node,"/ht/open/", "dummy", "WrongPassword", [{statuscode, 401}, {header, "WWW-Authenticate"}]), %% Control that not just the first user in the list is valid %% Control the first user %% Authennticating ["one:OnePassword" user first in user list] auth_request(Type, Host, Port, Node, "/ht/open/dummy.html", "one", "OnePassword", [{statuscode, 200}]), %% Control the second user %% Authentication OK and a directory listing is supplied! %% ["Aladdin:open sesame" user second in user list] auth_request(Type, Host, Port, Node, "/ht/open/","Aladdin", "AladdinPassword", [{statuscode, 200}]), %% Contro that bad passwords and userids get a good denial %% User correct but wrong password! ["one:one" user first in user list] auth_request(Type, Host, Port, Node, "/ht/open/", "one", "one", [{statuscode, 401}]), %% Neither user or password correct! ["dummy:dummy"] auth_request(Type, Host, Port, Node, "/ht/open/", "dummy", "dummy", [{statuscode, 401}]), %% Control that authetication still works, even if its a member in a group %% Authentication OK! ["two:TwoPassword" user in first group] auth_request(Type, Host, Port, Node, "/ht/secret/dummy.html", "two", "TwoPassword", [{statuscode, 200}]), %% Authentication OK and a directory listing is supplied! %% ["three:ThreePassword" user in second group] auth_request(Type, Host, Port, Node,"/ht/secret/", "three", "ThreePassword", [{statuscode, 200}]), %% Deny users with bad passwords even if the user is a group member %% User correct but wrong password! ["two:two" user in first group] auth_request(Type, Host, Port, Node, "/ht/secret/", "two", "two", [{statuscode, 401}]), %% Neither user or password correct! ["dummy:dummy"] auth_request(Type, Host, Port, Node,"/ht/secret/", "dummy", "dummy", [{statuscode, 401}]), %% control that we deny the users that are in subnet above the allowed auth_request(Type, Host, Port, Node,"/ht/blocknet/dummy.html", "four", "FourPassword", [{statuscode, 403}]), %% Control that we only applies the rules to the right methods ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "HEAD /ht/blocknet/dummy.html" " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), %% Control that the rerquire directive can be overrideen auth_request(Type, Host, Port, Node, "/ht/secret/top_secret/", "Aladdin", "AladdinPassword", [{statuscode, 401}]), %% Authentication still required! ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /ht/open/ " "HTTP/1.0\r\n\r\n", [{statuscode, 401}, {version, "HTTP/1.0"}, {header, "WWW-Authenticate"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /ht/secret/ HTTP/1.0\r\n\r\n", [{statuscode, 401}, {version, "HTTP/1.0"}, {header, "WWW-Authenticate"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /ht/secret/top_secret/ " "HTTP/1.0\r\n\r\n", [{statuscode, 401}, {version, "HTTP/1.0"}, {header, "WWW-Authenticate"}]). %%-------------------------------------------------------------------- cgi(Type, Port, Host, Node) -> {Script, Script2, Script3} = case test_server:os_type() of {win32, _} -> {"printenv.bat", "printenv.sh", "cgi_echo.exe"}; _ -> {"printenv.sh", "printenv.bat", "cgi_echo"} end, %% The length (> 100) is intentional %% tsp("cgi -> request 01 with length > 100"), ok = httpd_test_lib: verify_request(Type, Host, Port, Node, "POST /cgi-bin/" ++ Script3 ++ " HTTP/1.0\r\n" "Content-Length:100 \r\n\r\n " "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" " \r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}, {header, "content-type", "text/plain"}]), %% tsp("cgi -> request 02"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/"++ Script ++ " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), %% tsp("cgi -> request 03"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/not_there " "HTTP/1.0\r\n\r\n", [{statuscode, 404},{statuscode, 500}, {version, "HTTP/1.0"}]), %% tsp("cgi -> request 04"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/"++ Script ++ "?Nisse:kkk?sss/lll HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), %% tsp("cgi -> request 04"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "POST /cgi-bin/"++ Script ++ " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), %% tsp("cgi -> request 05"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /htbin/"++ Script ++ " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), %% tsp("cgi -> request 06"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /htbin/not_there " "HTTP/1.0\r\n\r\n", [{statuscode, 404},{statuscode, 500}, {version, "HTTP/1.0"}]), %% tsp("cgi -> request 07"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /htbin/"++ Script ++ "?Nisse:kkk?sss/lll HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), %% tsp("cgi -> request 08"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "POST /htbin/"++ Script ++ " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), %% tsp("cgi -> request 09"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "POST /htbin/"++ Script ++ " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), %% Execute an existing, but bad CGI script.. %% tsp("cgi -> request 10 - bad script"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "POST /htbin/"++ Script2 ++ " HTTP/1.0\r\n\r\n", [{statuscode, 404}, {version, "HTTP/1.0"}]), %% tsp("cgi -> request 11 - bad script"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "POST /cgi-bin/"++ Script2 ++ " HTTP/1.0\r\n\r\n", [{statuscode, 404}, {version, "HTTP/1.0"}]), %% tsp("cgi -> done"), %% Check "ScriptNoCache" directive (default: false) ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/" ++ Script ++ " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {no_header, "cache-control"}, {version, "HTTP/1.0"}]), ok. %%-------------------------------------------------------------------- esi(Type, Port, Host, Node) -> %% Check "ErlScriptAlias" and "EvalScriptAlias" directives ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /eval?httpd_example:print(\"Hi!\")" " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /eval?not_allowed:print(\"Hi!\")" " HTTP/1.0\r\n\r\n", [{statuscode, 403}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /eval?httpd_example:undef(\"Hi!\")" " HTTP/1.0\r\n\r\n", [{statuscode, 500}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/erl/httpd_example " "HTTP/1.0\r\n\r\n", [{statuscode, 400}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/erl/httpd_example:get " "HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/erl/httpd_example:" "get?input=4711" " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/erl/httpd_example:" "post HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/erl/not_allowed:post " "HTTP/1.0\r\n\r\n", [{statuscode, 403}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/erl/httpd_example:undef " "HTTP/1.0\r\n\r\n", [{statuscode, 404}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/erl/httpd_example/yahoo" " HTTP/1.0\r\n\r\n", [{statuscode, 302}, {version, "HTTP/1.0"}]), %% Check "ErlScriptNoCache" directive (default: false) ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/erl/httpd_example:get" " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {no_header, "cache-control"}, {version, "HTTP/1.0"}]), ok. %%-------------------------------------------------------------------- get(Type, Port, Host, Node) -> ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /index.html HTTP/1.0\r\n\r\n", [{statuscode, 200}, {header, "Content-Type", "text/html"}, {header, "Date"}, {header, "Server"}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /fsize.shtml HTTP/1.1\r\nHost:" ++ Host ++ "\r\n\r\n", [{statuscode, 200}, {header, "Content-Type", "text/html"}, {header, "Date"}, {header, "Server"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /fsize.shtml HTTP/1.0\r\n\r\n", [{statuscode, 200}, {header, "Content-Type"}, {header, "Server"}, {header, "Date"}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /secret/dummy.html " "HTTP/1.0\r\n\r\n", [{statuscode, 401}, {header, "WWW-Authenticate"}, {version, "HTTP/1.0"}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /index.html HTTP/1.0\r\n\r\n", [{statuscode, 200}, {header, "Server"}, {header, "Date"}, {header, "Content-Type", "text/html"}, {version, "HTTP/1.0"}]), ok. %%-------------------------------------------------------------------- head(Type, Port, Host, Node) -> ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "HEAD /index.html HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), ok. %%-------------------------------------------------------------------- all(Type, Port, Host, Node) -> actions(Type, Port, Host, Node), alias(Type, Port, Host, Node), auth(Type, Port, Host, Node), cgi(Type, Port, Host, Node), esi(Type, Port, Host, Node), get(Type, Port, Host, Node), head(Type, Port, Host, Node), ok. %%-------------------------------------------------------------------- %% Internal functions %%-------------------------------------------------------------------- auth_request(Type, Host, Port, Node, URI, User, Passwd, Expect) -> Req = ["GET ", URI, " HTTP/1.0\r\n", "Authorization: Basic ", base64:encode_to_string(User++":"++Passwd), "\r\n\r\n"], ok = httpd_test_lib:verify_request(Type, Host, Port, Node, lists:flatten(Req), [{version, "HTTP/1.0"} | Expect]). remove_users(Node, ServerRoot, Host, Port, Dir) -> %% List users, delete them, and make sure they are gone. case list_users(Node, ServerRoot, Host, Port, Dir) of {ok, Users} -> lists:foreach(fun(User) -> delete_user(Node, ServerRoot, Host, Port, Dir, User) end, Users), {ok, []} = list_users(Node, ServerRoot, Host, Port, Dir); _ -> ok end. add_user(Node, Root, Port, Dir, User, Password, UserData) -> Addr = undefined, Directory = filename:join([Root, "htdocs", Dir]), rpc:call(Node, mod_auth, add_user, [User, Password, UserData, Addr, Port, Directory]). delete_user(Node, Root, _Host, Port, Dir, User) -> Addr = undefined, Directory = filename:join([Root, "htdocs", Dir]), rpc:call(Node, mod_auth, delete_user, [User, Addr, Port, Directory]). list_users(Node, Root, _Host, Port, Dir) -> Addr = undefined, Directory = filename:join([Root, "htdocs", Dir]), rpc:call(Node, mod_auth, list_users, [Addr, Port, Directory]). receive_security_event(Event, Node, Port) -> tsp("receive_security_event -> await ~w event", [element(2, Event)]), receive Event -> tsp("receive_security_event -> " "received expected ~w event", [element(2, Event)]), ok; {'EXIT', _, _} -> receive_security_event(Event, Node, Port) after 5000 -> %% Flush the message queue, to see if we got something... Msgs = inets_test_lib:flush(), tsf({expected_event_not_received, Msgs}) end. %% receive_security_event(Event, Node, Port) -> %% io:format(user, "~w:receive_security_event -> entry with" %% "~n Event: ~p" %% "~n Node: ~p" %% "~n Port: ~p" %% "~n", [?MODULE, Event, Node, Port]), %% receive %% Event -> %% ok; %% {'EXIT', _, _} -> %% receive_security_event(Event, Node, Port); %% Other -> %% test_server:fail({unexpected_event, %% {expected, Event}, {received, Other}}) %% after 5000 -> %% test_server:fail(no_event_recived) %% end. list_blocked_users(Node,Port) -> Addr = undefined, % Assumed to be on the same host rpc:call(Node, mod_security, list_blocked_users, [Addr,Port]). list_blocked_users(Node,Port,Dir) -> Addr = undefined, % Assumed to be on the same host rpc:call(Node, mod_security, list_blocked_users, [Addr,Port,Dir]). block_user(Node,User,Port,Dir,Sec) -> Addr = undefined, % Assumed to be on the same host rpc:call(Node, mod_security, block_user, [User, Addr, Port, Dir, Sec]). unblock_user(Node,User,Port,Dir) -> Addr = undefined, % Assumed to be on the same host rpc:call(Node, mod_security, unblock_user, [User, Addr, Port, Dir]). list_auth_users(Node,Port) -> Addr = undefined, % Assumed to be on the same host rpc:call(Node, mod_security, list_auth_users, [Addr,Port]). list_auth_users(Node,Port,Dir) -> Addr = undefined, % Assumed to be on the same host rpc:call(Node, mod_security, list_auth_users, [Addr,Port,Dir]). update_password(Node, ServerRoot, _Address, Port, Dir, Old, New)-> Directory = filename:join([ServerRoot, "htdocs", Dir]), rpc:call(Node, mod_auth, update_password, [undefined, Port, Directory, Old, New, New]). remove_groups(Node, ServerRoot, Host, Port, Dir) -> Directory = filename:join([ServerRoot, "htdocs", Dir]), {ok, Groups} = list_groups(Node, ServerRoot, Host, Port, Directory), lists:foreach(fun(Group) -> delete_group(Node, Group, Port, Directory) end, Groups), {ok, []} = list_groups(Node, ServerRoot, Host, Port, Directory), ok. delete_group(Node, Group, Port, Dir) -> Addr = undefined, rpc:call(Node, mod_auth, delete_group, [Group, Addr, Port, Dir]). list_groups(Node, _, _, Port, Dir) -> Addr = undefined, rpc:call(Node, mod_auth, list_groups, [Addr, Port, Dir]). add_group_member(Node, ServerRoot, Port, Dir, User, Group) -> Addr = undefined, rpc:call(Node, mod_auth, add_group_member, [Group, User, Addr, Port, filename:join( [ServerRoot, "htdocs",Dir])]). event(What, Port, Dir, Data) -> Msg = {event, What, Port, Dir, Data}, case global:whereis_name(mod_security_test) of undefined -> ok; _Pid -> global:send(mod_security_test, Msg) end. ssl_password_cb() -> "dummy-ssl-password". check_lists_members({ok,L},L) -> ok; check_lists_members({ok,L1},L2) -> check_lists_members1(lists:sort(L1),lists:sort(L2)); check_lists_members(Error,_L) -> Error. check_lists_members1(L,L) -> ok; check_lists_members1(L1,L2) -> {error,{lists_not_equal,L1,L2}}. %% p(F) -> %% p(F, []). %% p(F, A) -> %% io:format(user, "~w:" ++ F ++ "~n", [?MODULE|A]). tsp(F) -> inets_test_lib:tsp(F). tsp(F, A) -> inets_test_lib:tsp(F, A). tsf(Reason) -> test_server:fail(Reason).