%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2005-2018. 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_lib("common_test/include/ct.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 ct:sleep(5000), OpenDir = filename:join([ServerRoot, "htdocs", "open"]), %% Test blocking / unblocking of users. %% /open, require user one Aladdin remove_users(Node, ServerRoot, Host, Port, "open"), auth_request(Type, Host, Port, Node, "/open/", "one", "onePassword", [{statuscode, 401}]), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "one"}, {password, "onePassword"}]}, Node, Port), auth_request(Type,Host,Port,Node,"/open/", "two", "twoPassword", [{statuscode, 401}]), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "two"}, {password, "twoPassword"}]}, Node, Port), auth_request(Type, Host, Port, Node,"/open/", "Aladdin", "AladdinPassword", [{statuscode, 401}]), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "Aladdin"}, {password, "AladdinPassword"}]}, Node, Port), add_user(Node, ServerRoot, Port, "open", "one", "onePassword", []), add_user(Node, ServerRoot, Port, "open", "two", "twoPassword", []), auth_request(Type, Host, Port, Node,"/open/", "one", "WrongPassword", [{statuscode, 401}]), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "one"}, {password, "WrongPassword"}]}, Node, Port), auth_request(Type, Host, Port, Node,"/open/", "one", "WrongPassword", [{statuscode, 401}]), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "one"}, {password, "WrongPassword"}]}, Node, Port), receive_security_event({event, user_block, Port, OpenDir, [{user, "one"}]}, Node, Port), global:unregister_name(mod_security_test), % No more events. auth_request(Type, Host, Port, Node,"/open/", "one", "WrongPassword", [{statuscode, 401}]), auth_request(Type, Host, Port, Node,"/open/", "one", "onePassword", [{statuscode, 403}]), %% User "one" should be blocked now.. case list_blocked_users(Node, Port) of [{"one",_, Port, OpenDir,_}] -> ok; Blocked -> exit({unexpected_blocked, Blocked}) end, [{"one",_, Port, OpenDir,_}] = list_blocked_users(Node, Port, OpenDir), true = unblock_user(Node, "one", Port, OpenDir), %% User "one" should not be blocked any more. [] = list_blocked_users(Node, Port), auth_request(Type, Host, Port, Node,"/open/", "one", "onePassword", [{statuscode, 200}]), %% Test list_auth_users & auth_timeout ["one"] = list_auth_users(Node, Port), auth_request(Type, Host, Port, Node,"/open/", "two", "onePassword", [{statuscode, 401}]), ["one"] = list_auth_users(Node, Port), ["one"] = list_auth_users(Node, Port, OpenDir), auth_request(Type, Host, Port, Node,"/open/", "two", "twoPassword", [{statuscode, 401}]), ["one"] = list_auth_users(Node, Port), ["one"] = list_auth_users(Node, Port, OpenDir), %% Wait for successful auth to timeout. ct:sleep(?AUTH_TIMEOUT*1001), [] = list_auth_users(Node, Port), [] = list_auth_users(Node, Port, OpenDir), %% "two" is blocked. true = unblock_user(Node, "two", Port, OpenDir), %% Test explicit blocking. Block user 'two'. [] = list_blocked_users(Node,Port,OpenDir), true = block_user(Node, "two", Port, OpenDir, 10), auth_request(Type, Host, Port, Node,"/open/", "two", "twoPassword", [{statuscode, 401}]). %%------------------------------------------------------------------------- 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 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"}]), 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"}]), 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"}]), 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"}]), 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"}]), 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"}]), 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"}]), 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"}]), 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"}]), 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.. 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"}]), 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"}]), %% 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"}]). %%-------------------------------------------------------------------- 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 = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/erl/httpd_example:new_status_and_location" " HTTP/1.1\r\n\r\n", [{statuscode, 201}, {header, "Location"}, {version, "HTTP/1.1"}]), 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) -> receive 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(), ct:fail({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 -> %% ct:fail({unexpected_event, %% {expected, Event}, {received, Other}}) %% after 5000 -> %% ct: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}}.