diff options
Diffstat (limited to 'lib/inets')
-rw-r--r-- | lib/inets/src/http_server/httpd_example.erl | 4 | ||||
-rw-r--r-- | lib/inets/test/httpd_1_1.erl | 89 | ||||
-rw-r--r-- | lib/inets/test/httpd_SUITE.erl | 1451 | ||||
-rw-r--r-- | lib/inets/test/httpd_test_lib.erl | 119 | ||||
-rw-r--r-- | lib/inets/test/old_httpd_SUITE.erl | 140 |
5 files changed, 1325 insertions, 478 deletions
diff --git a/lib/inets/src/http_server/httpd_example.erl b/lib/inets/src/http_server/httpd_example.erl index 16a080f8e2..6fc07f033c 100644 --- a/lib/inets/src/http_server/httpd_example.erl +++ b/lib/inets/src/http_server/httpd_example.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -66,7 +66,7 @@ get_bin(_Env,_Input) -> <INPUT TYPE=\"text\" NAME=\"input2\"> <INPUT TYPE=\"submit\"><BR> </FORM>" ++ "\n"), - footer()]. + list_to_binary(footer())]. post(_Env,[]) -> [header(), diff --git a/lib/inets/test/httpd_1_1.erl b/lib/inets/test/httpd_1_1.erl index 0d8fe07033..6a5fc4a18f 100644 --- a/lib/inets/test/httpd_1_1.erl +++ b/lib/inets/test/httpd_1_1.erl @@ -152,13 +152,13 @@ if_test(Type, Port, Host, Node, DocRoot)-> calendar:datetime_to_gregorian_seconds(FileInfo#file_info.mtime), Mod = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( - CreatedSec-1)), + CreatedSec-1)), %% Test that we get the data when the file is modified ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET / HTTP/1.1\r\nHost:" ++ Host ++ - "\r\nIf-Modified-Since:" ++ - Mod ++ "\r\n\r\n", + "\r\nIf-Modified-Since:" ++ + Mod ++ "\r\n\r\n", [{statuscode, 200}]), Mod1 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( CreatedSec+100)), @@ -168,64 +168,63 @@ if_test(Type, Port, Host, Node, DocRoot)-> ++ Mod1 ++"\r\n\r\n", [{statuscode, 304}]), - + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET / HTTP/1.1\r\nHost:" ++ Host ++ - "\r\nIf-Modified-Since:" ++ - "AAA[...]AAAA" ++ "\r\n\r\n", + "\r\nIf-Modified-Since:" ++ + "AAA[...]AAAA" ++ "\r\n\r\n", [{statuscode, 400}]), - - - Mod2 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( + + Mod2 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( CreatedSec+1)), - %% Control that the If-Unmodified-Header lmits the response - ok = httpd_test_lib:verify_request(Type,Host,Port,Node, - "GET / HTTP/1.1\r\nHost:" - ++ Host ++ - "\r\nIf-Unmodified-Since:" ++ Mod2 - ++ "\r\n\r\n", - [{statuscode, 200}]), - Mod3 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( + %% Control that the If-Unmodified-Header lmits the response + ok = httpd_test_lib:verify_request(Type,Host,Port,Node, + "GET / HTTP/1.1\r\nHost:" + ++ Host ++ + "\r\nIf-Unmodified-Since:" ++ Mod2 + ++ "\r\n\r\n", + [{statuscode, 200}]), + Mod3 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime( CreatedSec-1)), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" - ++ Host ++ - "\r\nIf-Unmodified-Since:"++ Mod3 + "GET / HTTP/1.1\r\nHost:" + ++ Host ++ + "\r\nIf-Unmodified-Since:"++ Mod3 ++"\r\n\r\n", - [{statuscode, 412}]), + [{statuscode, 412}]), - %% Control that we get the body when the etag match + %% Control that we get the body when the etag match ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" ++ Host - ++"\r\n"++ - "If-Match:"++ - httpd_util:create_etag(FileInfo)++ - "\r\n\r\n", - [{statuscode, 200}]), - ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" ++ - Host ++ "\r\n"++ - "If-Match:NotEtag\r\n\r\n", - [{statuscode, 412}]), + "GET / HTTP/1.1\r\nHost:" ++ Host + ++"\r\n"++ + "If-Match:"++ + httpd_util:create_etag(FileInfo)++ + "\r\n\r\n", + [{statuscode, 200}]), + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + "GET / HTTP/1.1\r\nHost:" ++ + Host ++ "\r\n"++ + "If-Match:NotEtag\r\n\r\n", + [{statuscode, 412}]), - %% Control the response when the if-none-match header is there - ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - "GET / HTTP/1.1\r\nHost:" - ++ Host ++"\r\n"++ - "If-None-Match:NoTaag," ++ - httpd_util:create_etag(FileInfo) ++ - "\r\n\r\n", - [{statuscode, 304}]), + %% Control the response when the if-none-match header is there + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + "GET / HTTP/1.1\r\nHost:" + ++ Host ++"\r\n"++ + "If-None-Match:NoTaag," ++ + httpd_util:create_etag(FileInfo) ++ + "\r\n\r\n", + [{statuscode, 304}]), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET / HTTP/1.1\r\nHost:" - ++ Host ++ "\r\n"++ - "If-None-Match:NotEtag," - "NeihterEtag\r\n\r\n", + ++ Host ++ "\r\n"++ + "If-None-Match:NotEtag," + "NeihterEtag\r\n\r\n", [{statuscode,200}]), ok. - + trace(Type, Port, Host, Node)-> ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "TRACE / HTTP/1.1\r\n" ++ diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index 18f66c98f9..3eb8a0818f 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -34,6 +34,11 @@ -record(httpd_user, {user_name, password, user_data}). -record(httpd_group, {group_name, userlist}). +-define(MAX_HEADER_SIZE, 256). +%% Minutes before failed auths timeout. +-define(FAIL_EXPIRE_TIME,1). +%% Seconds before successful auths timeout. +-define(AUTH_TIMEOUT,5). %%-------------------------------------------------------------------- %% Common Test interface functions ----------------------------------- @@ -43,22 +48,59 @@ suite() -> all() -> [ - {group, http}, + {group, http_basic}, + {group, https_basic}, {group, http_limit}, - {group, https} + {group, https_limit}, + {group, http_basic_auth}, + {group, https_basic_auth}, + {group, http_auth_api}, + {group, https_auth_api}, + {group, http_auth_api_dets}, + {group, https_auth_api_dets}, + {group, http_auth_api_mnesia}, + {group, https_auth_api_mnesia}, + {group, http_htaccess}, + {group, https_htaccess}, + {group, http_security}, + {group, https_security} ]. groups() -> [ - {http, [], all_groups()}, - {https, [], all_groups()}, - {http_limit, [], [max_clients_1_1, max_clients_1_0, max_clients_0_9]}, - {http_1_1, [], [host, chunked, expect, cgi, trace, range] ++ http_head() ++ http_get()}, - {http_1_0, [], [host, cgi, trace] ++ http_head() ++ http_get()}, - {http_0_9, [], http_head() ++ http_get()} + {http_basic, [], basic_groups()}, + {https_basic, [], basic_groups()}, + {http_limit, [], [{group, limit}]}, + {https_limit, [], [{group, limit}]}, + {http_basic_auth, [], [{group, basic_auth}]}, + {https_basic_auth, [], [{group, basic_auth}]}, + {http_auth_api, [], [{group, auth_api}]}, + {https_auth_api, [], [{group, auth_api}]}, + {http_auth_api_dets, [], [{group, auth_api_dets}]}, + {https_auth_api_dets, [], [{group, auth_api_dets}]}, + {http_auth_api_mnesia, [], [{group, auth_api_mnesia}]}, + {https_auth_api_mnesia, [], [{group, auth_api_mnesia}]}, + {http_htaccess, [], [{group, htaccess}]}, + {https_htaccess, [], [{group, htaccess}]}, + {http_security, [], [{group, security}]}, + {https_security, [], [{group, security}]}, + {limit, [], [max_clients_1_1, max_clients_1_0, max_clients_0_9]}, + {basic_auth, [], [basic_auth_1_1, basic_auth_1_0, basic_auth_0_9]}, + {auth_api, [], [auth_api_1_1, auth_api_1_0, auth_api_0_9 + ]}, + {auth_api_dets, [], [auth_api_1_1, auth_api_1_0, auth_api_0_9 + ]}, + {auth_api_mnesia, [], [auth_api_1_1, auth_api_1_0, auth_api_0_9 + ]}, + {htaccess, [], [htaccess_1_1, htaccess_1_0, htaccess_0_9]}, + {security, [], [security_1_1, security_1_0]}, %% Skip 0.9 as causes timing issus in test code + {http_1_1, [], [host, chunked, expect, cgi, cgi_chunked_encoding_test, + trace, range, if_modified_since] ++ http_head() ++ http_get() ++ load()}, + {http_1_0, [], [host, cgi, trace] ++ http_head() ++ http_get() ++ load()}, + {http_0_9, [], http_head() ++ http_get() ++ load()} ]. -all_groups ()-> +basic_groups ()-> [{group, http_1_1}, {group, http_1_0}, {group, http_0_9} @@ -67,15 +109,27 @@ all_groups ()-> http_head() -> [head]. http_get() -> - [alias, get, - basic_auth, - esi, ssi]. + [alias, + get, + %%actions, Add configuration so that this test mod_action + esi, + ssi, + content_length, + bad_hex, + missing_CR, + max_header, + ipv6 + ]. +load() -> + [light, medium + %%,heavy + ]. + init_per_suite(Config) -> PrivDir = ?config(priv_dir, Config), DataDir = ?config(data_dir, Config), inets_test_lib:stop_apps([inets]), - inets_test_lib:start_apps([inets]), ServerRoot = filename:join(PrivDir, "server_root"), inets_test_lib:del_dirs(ServerRoot), DocRoot = filename:join(ServerRoot, "htdocs"), @@ -83,44 +137,31 @@ init_per_suite(Config) -> [{server_root, ServerRoot}, {doc_root, DocRoot}, {node, node()}, - {host, inets_test_lib:hostname()} | Config]. + {host, inets_test_lib:hostname()}, + {address, getaddr()} | Config]. end_per_suite(_Config) -> ok. %%-------------------------------------------------------------------- -init_per_group(https = Group, Config0) -> - PrivDir = ?config(priv_dir, Config0), - CaKey = {_Trusted,_} = - erl_make_certs:make_cert([{key, dsa}, - {subject, - [{name, "Public Key"}, - {?'id-at-name', - {printableString, "public_key"}}, - {?'id-at-pseudonym', - {printableString, "pubkey"}}, - {city, "Stockholm"}, - {country, "SE"}, - {org, "erlang"}, - {org_unit, "testing dep"} - ]} - ]), - ok = erl_make_certs:write_pem(PrivDir, "public_key_cacert", CaKey), - - CertK1 = {_Cert1, _} = erl_make_certs:make_cert([{issuer, CaKey}]), - CertK2 = {_Cert2,_} = erl_make_certs:make_cert([{issuer, CertK1}, - {digest, md5}, - {extensions, false}]), - ok = erl_make_certs:write_pem(PrivDir, "public_key_cert", CertK2), - - case start_apps(Group) of - ok -> - init_httpd(Group, [{type, ssl} | Config0]); - _ -> - {skip, "Could not start https apps"} - end; - -init_per_group(Group, Config0) when Group == http; Group == http_limit -> +init_per_group(Group, Config0) when Group == https_basic; + Group == https_limit; + Group == https_basic_auth; + Group == https_auth_api; + Group == https_auth_api_dets; + Group == https_auth_api_mnesia; + Group == https_security + -> + init_ssl(Group, Config0); +init_per_group(Group, Config0) when Group == http_basic; + Group == http_limit; + Group == http_basic_auth; + Group == http_auth_api; + Group == http_auth_api_dets; + Group == http_auth_api_mnesia; + Group == http_security + -> + ok = start_apps(Group), init_httpd(Group, [{type, ip_comm} | Config0]); init_per_group(http_1_1, Config) -> [{http_version, "HTTP/1.1"} | Config]; @@ -128,20 +169,55 @@ init_per_group(http_1_0, Config) -> [{http_version, "HTTP/1.0"} | Config]; init_per_group(http_0_9, Config) -> [{http_version, "HTTP/0.9"} | Config]; +init_per_group(http_htaccess = Group, Config) -> + Path = ?config(doc_root, Config), + catch remove_htaccess(Path), + create_htaccess_data(Path, ?config(address, Config)), + ok = start_apps(Group), + init_httpd(Group, [{type, ip_comm} | Config]); +init_per_group(https_htaccess = Group, Config) -> + Path = ?config(doc_root, Config), + catch remove_htaccess(Path), + create_htaccess_data(Path, ?config(address, Config)), + init_ssl(Group, Config); +init_per_group(auth_api, Config) -> + [{auth_prefix, ""} | Config]; +init_per_group(auth_api_dets, Config) -> + [{auth_prefix, "dets_"} | Config]; +init_per_group(auth_api_mnesia, Config) -> + start_mnesia(?config(node, Config)), + [{auth_prefix, "mnesia_"} | Config]; init_per_group(_, Config) -> Config. -end_per_group(http, _Config) -> - ok; -end_per_group(https, _Config) -> - ssl:stop(); + +end_per_group(Group, _Config) when Group == http_basic; + Group == http_limit; + Group == http_basic_auth; + Group == http_auth_api; + Group == http_auth_api_dets; + Group == http_auth_api_mnesia; + Group == http_htaccess; + Group == http_security + -> + inets:stop(); +end_per_group(Group, _Config) when Group == https_basic; + Group == https_limit; + Group == https_basic_auth; + Group == https_auth_api; + Group == http_auth_api_dets; + Group == http_auth_api_mnesia; + Group == https_htaccess; + Group == http_security + -> + ssl:stop(), + inets:stop(); + +end_per_group(auth_api_mnesia, _) -> + cleanup_mnesia(); + end_per_group(_, _) -> ok. -init_httpd(Group, Config0) -> - Config1 = proplists:delete(port, Config0), - Config = proplists:delete(server_pid, Config1), - {Pid, Port} = server_start(Group, server_config(Group, Config)), - [{server_pid, Pid}, {port, Port} | Config]. %%-------------------------------------------------------------------- init_per_testcase(Case, Config) when Case == host; Case == trace -> Prop = ?config(tc_group_properties, Config), @@ -158,15 +234,10 @@ init_per_testcase(range, Config) -> DocRoot = ?config(doc_root, Config), create_range_data(DocRoot), Config; + init_per_testcase(_, Config) -> Config. -%% init_per_testcase(basic_auth = Case, Config) -> -%% start_mnesia(?config(node, Config)), -%% common_init_per_test_case(Case, Config); - -%% end_per_testcase(basic_auth, Config) -> -%% cleanup_mnesia(); end_per_testcase(_Case, _Config) -> ok. @@ -204,6 +275,15 @@ get(Config) when is_list(Config) -> {header, "Server"}, {version, Version}]). +basic_auth_1_1(Config) when is_list(Config) -> + basic_auth([{http_version, "HTTP/1.1"} | Config]). + +basic_auth_1_0(Config) when is_list(Config) -> + basic_auth([{http_version, "HTTP/1.0"} | Config]). + +basic_auth_0_9(Config) when is_list(Config) -> + basic_auth([{http_version, "HTTP/0.9"} | Config]). + basic_auth() -> [{doc, "Test Basic authentication with WWW-Authenticate header"}]. @@ -235,7 +315,203 @@ basic_auth(Config) -> Config, [{statuscode, 200}]), %% Authentication still required! basic_auth_requiered(Config). - + +auth_api_1_1(Config) when is_list(Config) -> + auth_api([{http_version, "HTTP/1.1"} | Config]). + +auth_api_1_0(Config) when is_list(Config) -> + auth_api([{http_version, "HTTP/1.0"} | Config]). + +auth_api_0_9(Config) when is_list(Config) -> + auth_api([{http_version, "HTTP/0.9"} | Config]). + +auth_api() -> + [{doc, "Test mod_auth API"}]. + +auth_api(Config) when is_list(Config) -> + Prefix = ?config(auth_prefix, Config), + do_auth_api(Prefix, Config). + +do_auth_api(AuthPrefix, Config) -> + Version = ?config(http_version, Config), + Host = ?config(host, Config), + Port = ?config(port, Config), + Node = ?config(node, Config), + ServerRoot = ?config(server_root, Config), + ok = http_status("GET / ", Config, + [{statuscode, 200}]), + ok = auth_status(auth_request("/", "one", "WrongPassword", Version, Host), Config, + [{statuscode, 200}]), + + %% Make sure Authenticate header is received even the second time + %% we try a incorrect password! Otherwise a browser client will hang! + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/", + "dummy", "WrongPassword", Version, Host), Config, + [{statuscode, 401}, + {header, "WWW-Authenticate"}]), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/", "dummy", "WrongPassword", + Version, Host), Config, [{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, AuthPrefix, + "open", "NoPassword", "DummyPassword"), + {error,bad_password} = + add_user(Node, ServerRoot, Port, AuthPrefix, "open", "one", + "onePassword", []), + ok = update_password(Node, ServerRoot, Host, Port, AuthPrefix, "open", + "DummyPassword", "NoPassword"), + + %% Test /*open, require user one Aladdin + remove_users(Node, ServerRoot, Host, Port, AuthPrefix, "open"), + + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/", + "one", "onePassword", Version, Host), Config, + [{statuscode, 401}]), + + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/", + "two", "twoPassword", Version, Host), Config, + [{statuscode, 401}]), + + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/", + "Aladdin", "onePassword", Version, Host), + Config, [{statuscode, 401}]), + + true = add_user(Node, ServerRoot, Port, AuthPrefix, "open", "one", + "onePassword", []), + true = add_user(Node, ServerRoot, Port, AuthPrefix, "open", "two", + "twoPassword", []), + true = add_user(Node, ServerRoot, Port, AuthPrefix, "open", "Aladdin", + "AladdinPassword", []), + {ok, [_|_]} = list_users(Node, ServerRoot, Host, Port, + AuthPrefix, "open"), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/", + "one", "WrongPassword", Version, Host), + Config, [{statuscode, 401}]), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/", + "one", "onePassword", Version, Host), + Config, [{statuscode, 200}]), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/", + "two", "twoPassword", Version, Host), + Config,[{statuscode, 401}]), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/", + "Aladdin", "WrongPassword", Version, Host), + Config,[{statuscode, 401}]), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/", + "Aladdin", "AladdinPassword", Version, Host), + Config, [{statuscode, 200}]), + + remove_users(Node, ServerRoot, Host, Port, AuthPrefix, "open"), + {ok, []} = list_users(Node, ServerRoot, Host, Port, + AuthPrefix, "open"), + + %% Phase 2 + remove_users(Node, ServerRoot, Host, Port, AuthPrefix, "secret"), + {ok, []} = list_users(Node, ServerRoot, Host, Port, AuthPrefix, + "secret"), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/", + "one", "onePassword", Version, Host), + Config, [{statuscode, 401}]), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/", + "two", "twoPassword", Version, Host), + Config, [{statuscode, 401}]), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/", + "three", "threePassword", Version, Host), + Config, [{statuscode, 401}]), + add_user(Node, ServerRoot, Port, AuthPrefix, "secret", "one", + "onePassword", + []), + add_user(Node, ServerRoot, Port, AuthPrefix, "secret", + "two", "twoPassword", []), + add_user(Node, ServerRoot, Port, AuthPrefix, "secret", "Aladdin", + "AladdinPassword",[]), + add_group_member(Node, ServerRoot, Port, AuthPrefix, "secret", + "one", "group1"), + add_group_member(Node, ServerRoot, Port, AuthPrefix, "secret", + "two", "group1"), + add_group_member(Node, ServerRoot, Port, AuthPrefix, + "secret", "Aladdin", "group2"), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/", + "one", "onePassword", Version, Host), + Config, [{statuscode, 200}]), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/", + "two", "twoPassword", Version, Host), + Config,[{statuscode, 200}]), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/", + "Aladdin", "AladdinPassword", Version, Host), + Config, [{statuscode, 200}]), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/", + "three", "threePassword", Version, Host), + Config, [{statuscode, 401}]), + remove_users(Node, ServerRoot, Host, Port, AuthPrefix, "secret"), + {ok, []} = list_users(Node, ServerRoot, Host, Port, + AuthPrefix, "secret"), + remove_groups(Node, ServerRoot, Host, Port, AuthPrefix, "secret"), + + {ok, []} = list_groups(Node, ServerRoot, Host, Port, AuthPrefix, "secret"), + + %% Phase 3 + remove_users(Node, ServerRoot, Host, Port, AuthPrefix, "secret/top_secret"), + remove_groups(Node, ServerRoot, Host, Port, AuthPrefix, "secret/top_secret"), + + ok = auth_status(auth_request("/" ++ AuthPrefix ++ + "secret/top_secret/", + "three", "threePassword", Version, Host), + Config, [{statuscode, 401}]), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ + "secret/top_secret/", "two", "twoPassword", Version, Host), + Config, [{statuscode, 401}]), + add_user(Node, ServerRoot, Port, AuthPrefix, + "secret/top_secret","three", + "threePassword",[]), + add_user(Node, ServerRoot, Port, AuthPrefix, "secret/top_secret", + "two","twoPassword", []), + add_group_member(Node, ServerRoot, Port, AuthPrefix, "secret/top_secret", "three", "group3"), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ + "secret/top_secret/", "three", "threePassword", + Version, Host), + Config, [{statuscode, 200}]), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ + "secret/top_secret/", "two", "twoPassword", Version, Host), + Config, [{statuscode, 401}]), + add_group_member(Node, ServerRoot, Port, AuthPrefix, "secret/top_secret", "two", "group3"), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ + "secret/top_secret/", + "two", "twoPassword", Version, Host), + Config, [{statuscode, 200}]), + remove_users(Node, ServerRoot, Host, Port, AuthPrefix, "secret/top_secret"), + {ok, []} = list_users(Node, ServerRoot, Host, Port, + AuthPrefix, "secret/top_secret"), + remove_groups(Node, ServerRoot, Host, Port, AuthPrefix, "secret/top_secret"), + {ok, []} = list_groups(Node, ServerRoot, Host, Port, AuthPrefix, "secret/top_secret"), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ + "secret/top_secret/", "two", "twoPassword", Version, Host), + Config, [{statuscode, 401}]), + ok = auth_status(auth_request("/" ++ AuthPrefix ++ + "secret/top_secret/","three", "threePassword", Version, Host), + Config, [{statuscde, 401}]). +%%------------------------------------------------------------------------- +ipv6() -> + [{require, ipv6_hosts}, + {doc,"Test ipv6."}]. +ipv6(Config) when is_list(Config) -> + {ok, Hostname0} = inet:gethostname(), + case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of + true -> + Version = ?config(http_version, Config), + Host = ?config(host, Config), + URI = http_request("GET /", Version, Host), + httpd_test_lib:verify_request(?config(type, Config), Host, + ?config(port, Config), [inet6], + ?config(code, Config), + URI, + [{statuscode, 200}, {version, Version}]); + false -> + {skip, "Host does not support IPv6"} + end. + +%%------------------------------------------------------------------------- ssi() -> [{doc, "HTTP GET server side include test"}]. ssi(Config) when is_list(Config) -> @@ -251,6 +527,131 @@ ssi(Config) when is_list(Config) -> {header, "Date"}, {header, "Server"}, {version, Version}]). +%%------------------------------------------------------------------------- +htaccess_1_1(Config) when is_list(Config) -> + htaccess([{http_version, "HTTP/1.1"} | Config]). + +htaccess_1_0(Config) when is_list(Config) -> + htaccess([{http_version, "HTTP/1.0"} | Config]). + +htaccess_0_9(Config) when is_list(Config) -> + htaccess([{http_version, "HTTP/0.9"} | Config]). + +htaccess() -> + [{doc, "Test mod_auth API"}]. + +htaccess(Config) when is_list(Config) -> + Version = ?config(http_version, Config), + Host = ?config(host, Config), + Type = ?config(type, Config), + Port = ?config(port, Config), + Node = ?config(node, Config), + %% 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, + http_request("GET /ht/open/ ", Version, Host), + [{statuscode, 401}, + {version, Version}, + {header, "WWW-Authenticate"}]), + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + http_request("GET /ht/secret/ ", Version, Host), + [{statuscode, 401}, + {version, Version}, + {header, "WWW-Authenticate"}]), + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + http_request("GET /ht/secret/top_secret/ ", + Version, Host), + [{statuscode, 401}, + {version, Version}, + {header, "WWW-Authenticate"}]), + + %% Make sure Authenticate header is received even the second time + %% we try a incorrect password! Otherwise a browser client will hang! + ok = auth_status(auth_request("/ht/open/", + "dummy", "WrongPassword", Version, Host), Config, + [{statuscode, 401}, + {header, "WWW-Authenticate"}]), + ok = auth_status(auth_request("/ht/open/", + "dummy", "WrongPassword", Version, Host), Config, + [{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] + ok = auth_status(auth_request("/ht/open/dummy.html", "one", "OnePassword", + Version, Host), Config, + [{statuscode, 200}]), + + %% Control the second user + %% Authentication OK and a directory listing is supplied! + %% ["Aladdin:open sesame" user second in user list] + ok = auth_status(auth_request("/ht/open/","Aladdin", + "AladdinPassword", Version, Host), Config, + [{statuscode, 200}]), + + %% Contro that bad passwords and userids get a good denial + %% User correct but wrong password! ["one:one" user first in user list] + ok = auth_status(auth_request("/ht/open/", "one", "one", Version, Host), Config, + [{statuscode, 401}]), + %% Neither user or password correct! ["dummy:dummy"] + ok = auth_status(auth_request("/ht/open/", "dummy", "dummy", Version, Host), Config, + [{statuscode, 401}]), + + %% Control that authetication still works, even if its a member in a group + %% Authentication OK! ["two:TwoPassword" user in first group] + ok = auth_status(auth_request("/ht/secret/dummy.html", "two", + "TwoPassword", Version, Host), Config, + [{statuscode, 200}]), + + %% Authentication OK and a directory listing is supplied! + %% ["three:ThreePassword" user in second group] + ok = auth_status(auth_request("/ht/secret/", "three", + "ThreePassword", Version, Host), Config, + [{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] + ok = auth_status(auth_request("/ht/secret/", "two", "two", Version, Host), Config, + [{statuscode, 401}]), + %% Neither user or password correct! ["dummy:dummy"] + ok = auth_status(auth_request("/ht/secret/", "dummy", "dummy", Version, Host), Config, + [{statuscode, 401}]), + + %% control that we deny the users that are in subnet above the allowed + ok = auth_status(auth_request("/ht/blocknet/dummy.html", "four", + "FourPassword", Version, Host), Config, + [{statuscode, 403}]), + %% Control that we only applies the rules to the right methods + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + http_request("HEAD /ht/blocknet/dummy.html ", Version, Host), + [{statuscode, head_status(Version)}, + {version, Version}]), + + %% Control that the rerquire directive can be overrideen + ok = auth_status(auth_request("/ht/secret/top_secret/ ", "Aladdin", "AladdinPassword", + Version, Host), Config, + [{statuscode, 401}]), + + %% Authentication still required! + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + http_request("GET /ht/open/ ", Version, Host), + [{statuscode, 401}, + {version, Version}, + {header, "WWW-Authenticate"}]), + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + http_request("GET /ht/secret/ ", Version, Host), + [{statuscode, 401}, + {version, Version}, + {header, "WWW-Authenticate"}]), + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + http_request("GET /ht/secret/top_secret/ ", Version, Host), + [{statuscode, 401}, + {version, Version}, + {header, "WWW-Authenticate"}]). + +%%------------------------------------------------------------------------- host() -> [{doc, "Test host header"}]. @@ -258,21 +659,21 @@ host(Config) when is_list(Config) -> Cb = ?config(version_cb, Config), Cb:host(?config(type, Config), ?config(port, Config), ?config(host, Config), ?config(node, Config)). - +%%------------------------------------------------------------------------- chunked() -> [{doc, "Check that the server accepts chunked requests."}]. chunked(Config) when is_list(Config) -> httpd_1_1:chunked(?config(type, Config), ?config(port, Config), ?config(host, Config), ?config(node, Config)). - +%%------------------------------------------------------------------------- expect() -> ["Check that the server handles request with the expect header " "field appropiate"]. expect(Config) when is_list(Config) -> httpd_1_1:expect(?config(type, Config), ?config(port, Config), ?config(host, Config), ?config(node, Config)). - +%%------------------------------------------------------------------------- max_clients_1_1() -> [{doc, "Test max clients limit"}]. @@ -290,7 +691,7 @@ max_clients_0_9() -> max_clients_0_9(Config) when is_list(Config) -> do_max_clients([{http_version, "HTTP/0.9"} | Config]). - +%%------------------------------------------------------------------------- esi() -> [{doc, "Test mod_esi"}]. @@ -320,7 +721,7 @@ esi(Config) when is_list(Config) -> ok = http_status("GET /cgi-bin/erl/httpd_example:get ", Config, [{statuscode, 200}, {no_header, "cache-control"}]). - +%%------------------------------------------------------------------------- cgi() -> [{doc, "Test mod_cgi"}]. @@ -395,7 +796,27 @@ cgi(Config) when is_list(Config) -> ok = http_status("GET /cgi-bin/" ++ Script ++ " ", Config, [{statuscode, 200}, {no_header, "cache-control"}]). - +%%------------------------------------------------------------------------- +cgi_chunked_encoding_test() -> + [{doc, "Test chunked encoding together with mod_cgi "}]. +cgi_chunked_encoding_test(Config) when is_list(Config) -> + Host = ?config(host, Config), + Script = + case test_server:os_type() of + {win32, _} -> + "/cgi-bin/printenv.bat"; + _ -> + "/cgi-bin/printenv.sh" + end, + Requests = + ["GET " ++ Script ++ " HTTP/1.1\r\nHost:"++ Host ++"\r\n\r\n", + "GET /cgi-bin/erl/httpd_example/newformat HTTP/1.1\r\nHost:" + ++ Host ++"\r\n\r\n"], + httpd_1_1:mod_cgi_chunked_encoding_test(?config(type, Config), ?config(port, Config), + Host, + ?config(node, Config), + Requests). +%%------------------------------------------------------------------------- alias() -> [{doc, "Test mod_alias"}]. @@ -423,13 +844,14 @@ alias(Config) when is_list(Config) -> [{statuscode, 301}, {header, "Location"}, {header, "Content-Type","text/html"}]). -%% action() -> -%% [{doc, "Test mod_actions"}]. +%%------------------------------------------------------------------------- +actions() -> + [{doc, "Test mod_actions"}]. -%% action(Config) when is_list(Config) -> -%% ok = http_status("HEAD /", Config, -%% [{statuscode, 200}]). - +actions(Config) when is_list(Config) -> + ok = http_status("GET /", Config, [{statuscode, 200}]). + +%%------------------------------------------------------------------------- range() -> [{doc, "Test Range header"}]. @@ -437,6 +859,7 @@ range(Config) when is_list(Config) -> httpd_1_1:range(?config(type, Config), ?config(port, Config), ?config(host, Config), ?config(node, Config)). +%%------------------------------------------------------------------------- if_modified_since() -> [{doc, "Test If-Modified-Since header"}]. @@ -444,6 +867,7 @@ if_modified_since(Config) when is_list(Config) -> httpd_1_1:if_test(?config(type, Config), ?config(port, Config), ?config(host, Config), ?config(node, Config), ?config(doc_root, Config)). +%%------------------------------------------------------------------------- trace() -> [{doc, "Test TRACE method"}]. @@ -452,158 +876,214 @@ trace(Config) when is_list(Config) -> Cb:trace(?config(type, Config), ?config(port, Config), ?config(host, Config), ?config(node, Config)). -%% auth_api() -> -%% [{doc, "Test mod_auth API"}]. - -%% auth_api(Config) when is_list(Config) -> -%% Version = ?config(http_version, Config), -%% Host = ?config(host, Config), -%% ok = http_status("GET / ", Config, -%% [{statuscode, 200}]), -%% ok = auth_status(auth_request("/", "one", "WrongPassword", Version, Host), Config, -%% [{statuscode, 200}]), - -%% %% Make sure Authenticate header is received even the second time -%% %% we try a incorrect password! Otherwise a browser client will hang! -%% ok = auth_status(auth_request("/" ++ AuthStoreType ++ "open/", -%% "dummy", "WrongPassword", Host), Config, -%% [{statuscode, 401}, -%% {header, "WWW-Authenticate"}]), -%% ok = auth_status(auth_request("/" ++ AuthStoreType ++ "open/", "dummy", "WrongPassword", -%% Host), Config, [{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"), +%%------------------------------------------------------------------------- +light() -> + ["Test light load"]. +light(Config) when is_list(Config) -> + httpd_load:load_test(?config(type, Config), ?config(port, Config), ?config(host, Config), + ?config(node, Config), 10). +%%------------------------------------------------------------------------- +medium() -> + ["Test medium load"]. +medium(Config) when is_list(Config) -> + httpd_load:load_test(?config(type, Config), ?config(port, Config), ?config(host, Config), + ?config(node, Config), 100). +%%------------------------------------------------------------------------- +heavy() -> + ["Test heavy load"]. +heavy(Config) when is_list(Config) -> + httpd_load:load_test(?config(type, Config), ?config(port, Config), ?config(host, Config), + ?config(node, Config), + 1000). +%%------------------------------------------------------------------------- +content_length() -> + ["Tests that content-length is correct OTP-5775"]. +content_length(Config) -> + Version = ?config(http_version, Config), + Host = ?config(host, Config), + ok = httpd_test_lib:verify_request(?config(type, Config), Host, + ?config(port, Config), ?config(node, Config), + http_request("GET /cgi-bin/erl/httpd_example:get_bin ", + Version, Host), + [{statuscode, 200}, + {content_length, 274}, + {version, Version}]). +%%------------------------------------------------------------------------- +bad_hex() -> + ["Tests that a URI with a bad hexadecimal code is handled OTP-6003"]. +bad_hex(Config) -> + Version = ?config(http_version, Config), + Host = ?config(host, Config), + ok = httpd_test_lib:verify_request(?config(type, Config), Host, + ?config(port, Config), ?config(node, Config), + http_request("GET http://www.erlang.org/%skalle ", + Version, Host), + [{statuscode, 400}, + {version, Version}]). +%%------------------------------------------------------------------------- +missing_CR() -> + ["Tests missing CR in delimiter OTP-7304"]. +missing_CR(Config) -> + Version = ?config(http_version, Config), + Host = ?config(host, Config), + ok = httpd_test_lib:verify_request(?config(type, Config), Host, + ?config(port, Config), ?config(node, Config), + http_request_missing_CR("GET /index.html ", Version, Host), + [{statuscode, 200}, + {version, Version}]). + +%%------------------------------------------------------------------------- +max_header() -> + ["Denial Of Service (DOS) attack, prevented by max_header"]. +max_header(Config) when is_list(Config) -> + Version = ?config(http_version, Config), + Host = ?config(host, Config), + case Version of + "HTTP/0.9" -> + {skip, no_implemented}; + _ -> + dos_hostname(?config(type, Config), ?config(port, Config), Host, + ?config(node, Config), Version, ?MAX_HEADER_SIZE) + end. -%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/", -%% "one", "onePassword", [{statuscode, 401}]), +%%------------------------------------------------------------------------- +security_1_1(Config) when is_list(Config) -> + security([{http_version, "HTTP/1.1"} | Config]). + +security_1_0(Config) when is_list(Config) -> + security([{http_version, "HTTP/1.0"} | Config]). + +security() -> + ["Test mod_security"]. +security(Config) -> + Version = ?config(http_version, Config), + Host = ?config(host, Config), + Port = ?config(port, Config), + Node = ?config(node, Config), + ServerRoot = ?config(server_root, Config), + + global:register_name(mod_security_test, self()), % Receive events + + test_server: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"), + + ok = auth_status(auth_request("/open/", + "one", "onePassword", Version, Host), Config, + [{statuscode, 401}]), + + receive_security_event({event, auth_fail, Port, OpenDir, + [{user, "one"}, {password, "onePassword"}]}, + Node, Port), -%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/", -%% "two", "twoPassword", [{statuscode, 401}]), + ok = auth_status(auth_request("/open/", + "two", "twoPassword", Version, Host), Config, + [{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", []), + receive_security_event({event, auth_fail, Port, OpenDir, + [{user, "two"}, {password, "twoPassword"}]}, + Node, Port), + + ok = auth_status(auth_request("/open/", + "Aladdin", "AladdinPassword", Version, Host), + Config, [{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", []), + + ok = auth_status(auth_request("/open/", "one", "WrongPassword", Version, Host), Config, + [{statuscode, 401}]), + + receive_security_event({event, auth_fail, Port, OpenDir, + [{user, "one"}, {password, "WrongPassword"}]}, + Node, Port), + + ok = auth_status(auth_request("/open/", "one", "WrongPassword", Version, Host), Config, + [{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. + + ok = auth_status(auth_request("/open/", "one", "WrongPassword", Version, Host), Config, + [{statuscode, 401}]), + + %% User "one" should be blocked now.. + case list_blocked_users(Node, Port) of + [{"one",_, Port, OpenDir,_}] -> + ok; + Blocked -> + ct:fail({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), + + ok = auth_status(auth_request("/open/", "one", "onePassword", Version, Host), Config, + [{statuscode, 200}]), + + %% Test list_auth_users & auth_timeout + + ["one"] = list_auth_users(Node, Port), + + ok = auth_status(auth_request("/open/", "two", "onePassword", Version, Host), Config, + [{statuscode, 401}]), + + ["one"] = list_auth_users(Node, Port), + -%% {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}]), + ["one"] = list_auth_users(Node, Port, OpenDir), + -%% 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}]). + ok = auth_status(auth_request("/open/", "two", "twoPassword", Version, Host), Config, + [{statuscode, 401}]), + + ["one"] = list_auth_users(Node, Port), + + + ["one"] = list_auth_users(Node, Port, OpenDir), + + %% Wait for successful auth to timeout. + test_server: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), + + ok = auth_status(auth_request("/open/", "two", "twoPassword", Version, Host), Config, + [{statuscode, 401}]), + + true = unblock_user(Node, "two", Port, OpenDir). + %%-------------------------------------------------------------------- @@ -611,26 +1091,34 @@ trace(Config) when is_list(Config) -> %%-------------------------------------------------------------------- do_max_clients(Config) -> Version = ?config(http_version, Config), - Host = ?config(host, Config), - Type = ?config(type, Config), - start_blocker(Config), - ok = httpd_test_lib:verify_request(?config(type, Config), Host, - ?config(port, Config), + Host = ?config(host, Config), + Port = ?config(port, Config), + Type = ?config(type, Config), + + Request = http_request("GET /index.html ", Version, Host), + BlockRequest = http_request("GET /eval?httpd_example:delay(2000) ", Version, Host), + {ok, Socket} = inets_test_lib:connect_bin(Type, Host, Port, transport_opts(Type, Config)), + inets_test_lib:send(Type, Socket, BlockRequest), + ct:sleep(100), + ok = httpd_test_lib:verify_request(Type, Host, + Port, transport_opts(Type, Config), ?config(node, Config), - http_request("GET /index.html ", Version, Host), + Request, [{statuscode, 503}, {version, Version}]), receive - after 2000 -> - ok = httpd_test_lib:verify_request(?config(type, Config), Host, - ?config(port, Config), - transport_opts(Type, Config), - ?config(node, Config), - http_request("GET /index.html ", Version, Host), - [{statuscode, 200}, - {version, Version}]) - end. + {_, Socket, _Msg} -> + ok + end, + inets_test_lib:close(Type, Socket), + ok = httpd_test_lib:verify_request(Type, Host, + Port, + transport_opts(Type, Config), + ?config(node, Config), + Request, + [{statuscode, 200}, + {version, Version}]). setup_server_dirs(ServerRoot, DocRoot, DataDir) -> CgiDir = filename:join(ServerRoot, "cgi-bin"), @@ -670,10 +1158,24 @@ setup_server_dirs(ServerRoot, DocRoot, DataDir) -> ok = file:write_file_info(EnvCGI, FileInfo1#file_info{mode = 8#00755}). -start_apps(https) -> - inets_test_lib:start_apps([asn1, crypto, public_key, ssl]); -start_apps(_) -> - ok. +start_apps(Group) when Group == https_basic; + Group == https_limit; + Group == https_basic_auth; + Group == https_auth_api; + Group == https_auth_api_dets; + Group == https_auth_api_mnesia; + Group == http_htaccess; + Group == http_security -> + inets_test_lib:start_apps([inets, asn1, crypto, public_key, ssl]); +start_apps(Group) when Group == http_basic; + Group == http_limit; + Group == http_basic_auth; + Group == http_auth_api; + Group == http_auth_api_dets; + Group == http_auth_api_mnesia; + Group == https_htaccess; + Group == https_security -> + inets_test_lib:start_apps([inets]). server_start(_, HttpdConfig) -> {ok, Pid} = inets:start(httpd, HttpdConfig), @@ -681,6 +1183,80 @@ server_start(_, HttpdConfig) -> {value, {_, _, Info}} = lists:keysearch(Pid, 2, Serv), {Pid, proplists:get_value(port, Info)}. +init_ssl(Group, Config) -> + PrivDir = ?config(priv_dir, Config), + CaKey = {_Trusted,_} = + erl_make_certs:make_cert([{key, dsa}, + {subject, + [{name, "Public Key"}, + {?'id-at-name', + {printableString, "public_key"}}, + {?'id-at-pseudonym', + {printableString, "pubkey"}}, + {city, "Stockholm"}, + {country, "SE"}, + {org, "erlang"}, + {org_unit, "testing dep"} + ]} + ]), + ok = erl_make_certs:write_pem(PrivDir, "public_key_cacert", CaKey), + + CertK1 = {_Cert1, _} = erl_make_certs:make_cert([{issuer, CaKey}]), + CertK2 = {_Cert2,_} = erl_make_certs:make_cert([{issuer, CertK1}, + {digest, md5}, + {extensions, false}]), + ok = erl_make_certs:write_pem(PrivDir, "public_key_cert", CertK2), + + case start_apps(Group) of + ok -> + init_httpd(Group, [{type, ssl} | Config]); + _ -> + {skip, "Could not start https apps"} + end. + +server_config(http_basic, Config) -> + basic_conf() ++ server_config(http, Config); +server_config(https_basic, Config) -> + basic_conf() ++ server_config(https, Config); +server_config(http_limit, Config) -> + [{max_clients, 1}] ++ server_config(http, Config); +server_config(https_limit, Config) -> + [{max_clients, 1}] ++ server_config(https, Config); +server_config(http_basic_auth, Config) -> + ServerRoot = ?config(server_root, Config), + auth_conf(ServerRoot) ++ server_config(http, Config); +server_config(https_basic_auth, Config) -> + ServerRoot = ?config(server_root, Config), + auth_conf(ServerRoot) ++ server_config(https, Config); +server_config(http_auth_api, Config) -> + ServerRoot = ?config(server_root, Config), + auth_api_conf(ServerRoot, plain) ++ server_config(http, Config); +server_config(https_auth_api, Config) -> + ServerRoot = ?config(server_root, Config), + auth_api_conf(ServerRoot, plain) ++ server_config(https, Config); +server_config(http_auth_api_dets, Config) -> + ServerRoot = ?config(server_root, Config), + auth_api_conf(ServerRoot, dets) ++ server_config(http, Config); +server_config(https_auth_api_dets, Config) -> + ServerRoot = ?config(server_root, Config), + auth_api_conf(ServerRoot, dets) ++ server_config(https, Config); +server_config(http_auth_api_mnesia, Config) -> + ServerRoot = ?config(server_root, Config), + auth_api_conf(ServerRoot, mnesia) ++ server_config(http, Config); +server_config(https_auth_api_mnesia, Config) -> + ServerRoot = ?config(server_root, Config), + auth_api_conf(ServerRoot, mnesia) ++ server_config(https, Config); +server_config(http_htaccess, Config) -> + auth_access_conf() ++ server_config(http, Config); +server_config(https_htaccess, Config) -> + auth_access_conf() ++ server_config(https, Config); +server_config(http_security, Config) -> + ServerRoot = ?config(server_root, Config), + tl(auth_conf(ServerRoot)) ++ security_conf(ServerRoot) ++ server_config(http, Config); +server_config(https_security, Config) -> + ServerRoot = ?config(server_root, Config), + tl(auth_conf(ServerRoot)) ++ security_conf(ServerRoot) ++ server_config(https, Config); + server_config(http, Config) -> ServerRoot = ?config(server_root, Config), [{port, 0}, @@ -691,6 +1267,7 @@ server_config(http, Config) -> {ipfamily, inet}, {max_header_size, 256}, {max_header_action, close}, + {directory_index, ["index.html", "welcome.html"]}, {mime_types, [{"html","text/html"},{"htm","text/html"}, {"shtml","text/html"}, {"gif", "image/gif"}]}, {alias, {"/icons/", filename:join(ServerRoot,"icons") ++ "/"}}, @@ -699,19 +1276,7 @@ server_config(http, Config) -> {script_alias, {"/htbin/", filename:join(ServerRoot, "cgi-bin") ++ "/"}}, {erl_script_alias, {"/cgi-bin/erl", [httpd_example, io]}}, {eval_script_alias, {"/eval", [httpd_example, io]}} - ] ++ auth_conf(ServerRoot) ++ mod_conf(); - -server_config(http_limit, Config) -> - [{max_clients, 1}] ++ server_config(http, Config); - -%% server_config(range, Config) -> -%% range_conf() ++ server_config(http, Config); - -%% server_config(if_modified_since, Config) -> -%% if_modified_since_conf() ++ server_config(http, Config); - -%% server_config(trace, Config) -> -%% trace_conf() ++ server_config(http, Config); + ]; server_config(https, Config) -> PrivDir = ?config(priv_dir, Config), @@ -724,6 +1289,12 @@ server_config(https, Config) -> filename:join(PrivDir, "public_key_cert_key.pem")} ]}}] ++ server_config(http, Config). +init_httpd(Group, Config0) -> + Config1 = proplists:delete(port, Config0), + Config = proplists:delete(server_pid, Config1), + {Pid, Port} = server_start(Group, server_config(Group, Config)), + [{server_pid, Pid}, {port, Port} | Config]. + http_request(Request, "HTTP/1.1" = Version, Host, {Headers, Body}) -> Request ++ Version ++ "\r\nhost:" ++ Host ++ "\r\n" ++ Headers ++ "\r\n" ++ Body; http_request(Request, Version, _, {Headers, Body}) -> @@ -745,19 +1316,33 @@ auth_request(Path, User, Passwd, Version, _Host) -> base64:encode_to_string(User++":"++Passwd) ++ "\r\n\r\n". +http_request_missing_CR(Request, "HTTP/1.1" = Version, Host) -> + Request ++ Version ++ "\r\nhost:" ++ Host ++ "\r\n\r\n\n"; +http_request_missing_CR(Request, Version, _) -> + Request ++ Version ++ "\r\n\n". + head_status("HTTP/0.9") -> 501; %% Not implemented in HTTP/0.9 head_status(_) -> 200. +basic_conf() -> + [{modules, [mod_alias, mod_range, mod_responsecontrol, + mod_trace, mod_esi, mod_cgi, mod_dir, mod_get, mod_head]}]. + +auth_access_conf() -> + [{modules, [mod_alias, mod_htaccess, mod_dir, mod_get, mod_head]}, + {access_files, [".htaccess"]}]. + auth_conf(Root) -> - [{directory, {filename:join(Root, "htdocs/open"), + [{modules, [mod_alias, mod_auth, mod_dir, mod_get, mod_head]}, + {directory, {filename:join(Root, "htdocs/open"), [{auth_type, plain}, {auth_name, "Open Area"}, {auth_user_file, filename:join(Root, "auth/passwd")}, {auth_group_file, filename:join(Root, "auth/group")}, {require_user, ["one", "Aladdin"]}]}}, - {directory, {filename:join(Root, "htdocs/secret"), + {directory, {filename:join(Root, "htdocs/secret"), [{auth_type, plain}, {auth_name, "Secret Area"}, {auth_user_file, filename:join(Root, "auth/passwd")}, @@ -768,24 +1353,103 @@ auth_conf(Root) -> {auth_name, "Top Secret Area"}, {auth_user_file, filename:join(Root, "auth/passwd")}, {auth_group_file, filename:join(Root, "auth/group")}, - {require_group, ["group3"]}]}}, + {require_group, ["group3"]}]}}]. + +auth_api_conf(Root, plain) -> + [{modules, [mod_alias, mod_auth, mod_dir, mod_get, mod_head]}, {directory, {filename:join(Root, "htdocs/open"), - [{auth_type, mnesia}, + [{auth_type, plain}, {auth_name, "Open Area"}, {auth_user_file, filename:join(Root, "auth/passwd")}, {auth_group_file, filename:join(Root, "auth/group")}, {require_user, ["one", "Aladdin"]}]}}, {directory, {filename:join(Root, "htdocs/secret"), - [{auth_type, mnesia}, + [{auth_type, plain}, {auth_name, "Secret Area"}, {auth_user_file, filename:join(Root, "auth/passwd")}, {auth_group_file, filename:join(Root, "auth/group")}, - {require_group, ["group1", "group2"]}]}} - ]. + {require_group, ["group1", "group2"]}]}}, + {directory, {filename:join(Root, "htdocs/secret/top_secret"), + [{auth_type, plain}, + {auth_name, "Top Secret Area"}, + {auth_user_file, filename:join(Root, "auth/passwd")}, + {auth_group_file, filename:join(Root, "auth/group")}, + {require_group, ["group3"]}]}}]; -mod_conf() -> - [{modules, [mod_alias, mod_auth, mod_responsecontrol, mod_esi, mod_actions, mod_cgi, mod_trace, mod_include, - mod_dir, mod_range, mod_get, mod_head, mod_log, mod_disk_log]}]. +auth_api_conf(Root, dets) -> + [ + {modules, [mod_alias, mod_auth, mod_dir, mod_get, mod_head]}, + {directory, {filename:join(Root, "htdocs/dets_open"), + [{auth_type, dets}, + {auth_name, "Dets Open Area"}, + {auth_user_file, filename:join(Root, "passwd")}, + {auth_group_file, filename:join(Root, "group")}, + {require_user, ["one", "Aladdin"]}]}}, + {directory, {filename:join(Root, "htdocs/dets_secret"), + [{auth_type, dets}, + {auth_name, "Dests Secret Area"}, + {auth_user_file, filename:join(Root, "passwd")}, + {auth_group_file, filename:join(Root, "group")}, + {require_group, ["group1", "group2"]}]}}, + {directory, {filename:join(Root, "htdocs/dets_secret/top_secret"), + [{auth_type, dets}, + {auth_name, "Dets Top Secret Area"}, + {auth_user_file, filename:join(Root, "passwd")}, + {auth_group_file, filename:join(Root, "group")}, + {require_group, ["group3"]}]}} + ]; + +auth_api_conf(Root, mnesia) -> + [{modules, [mod_alias, mod_auth, mod_dir, mod_get, mod_head]}, + {directory, {filename:join(Root, "htdocs/mnesia_open"), + [{auth_type, mnesia}, + {auth_name, "Mnesia Open Area"}, + {require_user, ["one", "Aladdin"]}]}}, + {directory, {filename:join(Root, "htdocs/mnesia_secret"), + [{auth_type, mnesia}, + {auth_name, "Mnesia Secret Area"}, + {require_group, ["group1", "group2"]}]}}, + {directory, {filename:join(Root, "htdocs/mnesia_secret/top_secret"), + [{auth_type, mnesia}, + {auth_name, "Mnesia Top Secret Area"}, + {require_group, ["group3"]}]}}]. + +security_conf(Root) -> + SecFile = filename:join(Root, "security_data"), + Open = filename:join(Root, "htdocs/open"), + Secret = filename:join(Root, "htdocs/secret"), + TopSecret = filename:join(Root, "htdocs/secret/top_secret"), + + [{modules, [mod_alias, mod_auth, mod_security, mod_dir, mod_get, mod_head]}, + {security_directory, {Open, + [{auth_name, "Open Area"}, + {auth_user_file, filename:join(Root, "auth/passwd")}, + {auth_group_file, filename:join(Root, "auth/group")}, + {require_user, ["one", "Aladdin"]} | + mod_security_conf(SecFile, Open)]}}, + {security_directory, {Secret, + [{auth_name, "Secret Area"}, + {auth_user_file, filename:join(Root, "auth/passwd")}, + {auth_group_file, filename:join(Root, "auth/group")}, + {require_group, ["group1", "group2"]} | + mod_security_conf(SecFile, Secret)]}}, + {security_directory, {TopSecret, + [{auth_name, "Top Secret Area"}, + {auth_user_file, filename:join(Root, "auth/passwd")}, + {auth_group_file, filename:join(Root, "auth/group")}, + {require_group, ["group3"]} | + mod_security_conf(SecFile, TopSecret)]}}]. + +mod_security_conf(SecFile, Dir) -> + [{data_file, SecFile}, + {max_retries, 3}, + {fail_expire_time, ?FAIL_EXPIRE_TIME}, + {block_time, 1}, + {auth_timeout, ?AUTH_TIMEOUT}, + {callback_module, ?MODULE}, + {path, Dir} %% This is should not be needed, but is atm, awful design! + ]. + http_status(Request, Config, Expected) -> Version = ?config(http_version, Config), @@ -867,36 +1531,14 @@ cleanup_mnesia() -> mnesia:delete_schema([node()]), ok. -start_blocker(Config) -> - spawn(httpd_SUITE, init_blocker, [self(), Config]), - receive - blocker_start -> - ok - end. - -init_blocker(From, Config) -> - From ! blocker_start, - block(Config). - -block(Config) -> - Version = ?config(http_version, Config), - Host = ?config(host, Config), - Type = ?config(type, Config), - httpd_test_lib:verify_request(?config(type, Config), Host, - ?config(port, Config), - transport_opts(Type, Config), - ?config(node, Config), - http_request("GET /eval?httpd_example:delay(1000) ", - Version, Host), - [{statuscode, 200}, - {version, Version}]). - transport_opts(ssl, Config) -> PrivDir = ?config(priv_dir, Config), [{cacertfile, filename:join(PrivDir, "public_key_cacert.pem")}]; transport_opts(_, _) -> []. + +%%% mod_range create_range_data(Path) -> PathAndFileName=filename:join([Path,"range.txt"]), case file:read_file(PathAndFileName) of @@ -909,3 +1551,238 @@ create_range_data(Path) -> _ -> ok end. + +%%% mod_htaccess +create_htaccess_data(Path, IpAddress)-> + create_htaccess_dirs(Path), + + create_html_file(filename:join([Path,"ht/open/dummy.html"])), + create_html_file(filename:join([Path,"ht/blocknet/dummy.html"])), + create_html_file(filename:join([Path,"ht/secret/dummy.html"])), + create_html_file(filename:join([Path,"ht/secret/top_secret/dummy.html"])), + + create_htaccess_file(filename:join([Path,"ht/open/.htaccess"]), + Path, "user one Aladdin"), + create_htaccess_file(filename:join([Path,"ht/secret/.htaccess"]), + Path, "group group1 group2"), + create_htaccess_file(filename:join([Path, + "ht/secret/top_secret/.htaccess"]), + Path, "user four"), + create_htaccess_file(filename:join([Path,"ht/blocknet/.htaccess"]), + Path, nouser, IpAddress), + + create_user_group_file(filename:join([Path,"ht","users.file"]), + "one:OnePassword\ntwo:TwoPassword\nthree:" + "ThreePassword\nfour:FourPassword\nAladdin:" + "AladdinPassword"), + create_user_group_file(filename:join([Path,"ht","groups.file"]), + "group1: two one\ngroup2: two three"). + +create_html_file(PathAndFileName)-> + file:write_file(PathAndFileName,list_to_binary( + "<html><head><title>test</title></head> + <body>testar</body></html>")). + +create_htaccess_file(PathAndFileName, BaseDir, RequireData)-> + file:write_file(PathAndFileName, + list_to_binary( + "AuthUserFile "++ BaseDir ++ + "/ht/users.file\nAuthGroupFile "++ BaseDir + ++ "/ht/groups.file\nAuthName Test\nAuthType" + " Basic\n<Limit>\nrequire " ++ RequireData ++ + "\n</Limit>")). + +create_htaccess_file(PathAndFileName, BaseDir, nouser, IpAddress)-> + file:write_file(PathAndFileName,list_to_binary( + "AuthUserFile "++ BaseDir ++ + "/ht/users.file\nAuthGroupFile " ++ + BaseDir ++ "/ht/groups.file\nAuthName" + " Test\nAuthType" + " Basic\n<Limit GET>\n\tallow from " ++ + format_ip(IpAddress, + string:rchr(IpAddress,$.)) ++ + "\n</Limit>")). + +create_user_group_file(PathAndFileName, Data)-> + file:write_file(PathAndFileName, list_to_binary(Data)). + +create_htaccess_dirs(Path)-> + ok = file:make_dir(filename:join([Path,"ht"])), + ok = file:make_dir(filename:join([Path,"ht/open"])), + ok = file:make_dir(filename:join([Path,"ht/blocknet"])), + ok = file:make_dir(filename:join([Path,"ht/secret"])), + ok = file:make_dir(filename:join([Path,"ht/secret/top_secret"])). + +remove_htaccess_dirs(Path)-> + file:del_dir(filename:join([Path,"ht/secret/top_secret"])), + file:del_dir(filename:join([Path,"ht/secret"])), + file:del_dir(filename:join([Path,"ht/blocknet"])), + file:del_dir(filename:join([Path,"ht/open"])), + file:del_dir(filename:join([Path,"ht"])). + +format_ip(IpAddress,Pos)when Pos > 0-> + case lists:nth(Pos,IpAddress) of + $.-> + case lists:nth(Pos-2,IpAddress) of + $.-> + format_ip(IpAddress,Pos-3); + _-> + lists:sublist(IpAddress,Pos-2) ++ "." + end; + _ -> + format_ip(IpAddress,Pos-1) + end; + +format_ip(IpAddress, _Pos)-> + "1" ++ IpAddress. + +remove_htaccess(Path)-> + file:delete(filename:join([Path,"ht/open/dummy.html"])), + file:delete(filename:join([Path,"ht/secret/dummy.html"])), + file:delete(filename:join([Path,"ht/secret/top_secret/dummy.html"])), + file:delete(filename:join([Path,"ht/blocknet/dummy.html"])), + file:delete(filename:join([Path,"ht/blocknet/.htaccess"])), + file:delete(filename:join([Path,"ht/open/.htaccess"])), + file:delete(filename:join([Path,"ht/secret/.htaccess"])), + file:delete(filename:join([Path,"ht/secret/top_secret/.htaccess"])), + file:delete(filename:join([Path,"ht","users.file"])), + file:delete(filename:join([Path,"ht","groups.file"])), + remove_htaccess_dirs(Path). + +dos_hostname(Type, Port, Host, Node, Version, Max) -> + TooLongHeader = lists:append(lists:duplicate(Max + 1, "a")), + + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + dos_hostname_request("", Version), + [{statuscode, 200}, + {version, Version}]), + + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + dos_hostname_request("dummy-host.ericsson.se", Version), + [{statuscode, 200}, + {version, Version}]), + + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + dos_hostname_request(TooLongHeader, Version), + [{statuscode, dos_code(Version)}, + {version, Version}]). +dos_hostname_request(Host, Version) -> + dos_http_request("GET / ", Version, Host). + +dos_http_request(Request, "HTTP/1.1" = Version, Host) -> + http_request(Request, Version, Host); +dos_http_request(Request, Version, Host) -> + Request ++ Version ++ "\r\nhost:" ++ Host ++ "\r\n\r\n". + +dos_code("HTTP/1.0") -> + 403; %% 413 not defined in HTTP/1.0 +dos_code(_) -> + 413. + +update_password(Node, ServerRoot, _Address, Port, AuthPrefix, Dir, Old, New)-> + Directory = filename:join([ServerRoot, "htdocs", AuthPrefix ++ Dir]), + rpc:call(Node, mod_auth, update_password, + [undefined, Port, Directory, Old, New, New]). + +add_user(Node, Root, Port, AuthPrefix, Dir, User, Password, UserData) -> + Addr = undefined, + Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]), + rpc:call(Node, mod_auth, add_user, + [User, Password, UserData, Addr, Port, Directory]). + + +delete_user(Node, Root, _Host, Port, AuthPrefix, Dir, User) -> + Addr = undefined, + Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]), + rpc:call(Node, mod_auth, delete_user, [User, Addr, Port, Directory]). +remove_users(Node, ServerRoot, Host, Port, AuthPrefix, Dir) -> + %% List users, delete them, and make sure they are gone. + case list_users(Node, ServerRoot, Host, Port, AuthPrefix, Dir) of + {ok, Users} -> + lists:foreach(fun(User) -> + delete_user(Node, ServerRoot, Host, + Port, AuthPrefix, Dir, User) + end, + Users), + {ok, []} = list_users(Node, ServerRoot, Host, Port, AuthPrefix, Dir); + _ -> + ok + end. + +list_users(Node, Root, _Host, Port, AuthPrefix, Dir) -> + Addr = undefined, + Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]), + rpc:call(Node, mod_auth, list_users, [Addr, Port, Directory]). + +remove_groups(Node, ServerRoot, Host, Port, AuthPrefix, Dir) -> + {ok, Groups} = list_groups(Node, ServerRoot, Host, Port, AuthPrefix, Dir), + lists:foreach(fun(Group) -> + delete_group(Node, Group, Port, ServerRoot, AuthPrefix, Dir) + end, + Groups), + {ok, []} = list_groups(Node, ServerRoot, Host, Port, AuthPrefix, Dir). + +delete_group(Node, Group, Port, Root, AuthPrefix, Dir) -> + Addr = undefined, + Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]), + rpc:call(Node, mod_auth, delete_group, [Group, Addr, Port, Directory]). + +list_groups(Node, Root, _, Port, AuthPrefix, Dir) -> + Addr = undefined, + Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]), + rpc:call(Node, mod_auth, list_groups, [Addr, Port, Directory]). + +add_group_member(Node, Root, Port, AuthPrefix, Dir, User, Group) -> + Addr = undefined, + Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]), + rpc:call(Node, mod_auth, add_group_member, [Group, User, Addr, Port, + Directory]). +getaddr() -> + {ok,HostName} = inet:gethostname(), + {ok,{A1,A2,A3,A4}} = inet:getaddr(HostName,inet), + lists:flatten(io_lib:format("~p.~p.~p.~p",[A1,A2,A3,A4])). + +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... + inets_test_lib:flush() + 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]). + +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. + diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index 6406eeae79..ed466fd727 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -92,16 +92,6 @@ verify_request(SocketType, Host, Port, Node, RequestStr, Options, TimeOut) verify_request(SocketType, Host, Port, [], Node, RequestStr, Options, TimeOut). verify_request(SocketType, Host, Port, TranspOpts0, Node, RequestStr, Options, TimeOut) -> - tsp("verify_request -> entry with" - "~n SocketType: ~p" - "~n Host: ~p" - "~n Port: ~p" - "~n TranspOpts: ~p" - "~n Node: ~p" - "~n Options: ~p" - "~n TimeOut: ~p", - [SocketType, Host, Port, TranspOpts0, Node, Options, TimeOut]), - %% For now, until we modernize the httpd tests TranspOpts = case lists:member(inet6, TranspOpts0) of @@ -113,10 +103,7 @@ verify_request(SocketType, Host, Port, TranspOpts0, Node, RequestStr, Options, T try inets_test_lib:connect_bin(SocketType, Host, Port, TranspOpts) of {ok, Socket} -> - tsp("verify_request -> connected - now send message"), SendRes = inets_test_lib:send(SocketType, Socket, RequestStr), - tsp("verify_request -> send result: " - "~n ~p", [SendRes]), State = case inets_regexp:match(RequestStr, "printenv") of nomatch -> #state{}; @@ -127,37 +114,24 @@ verify_request(SocketType, Host, Port, TranspOpts0, Node, RequestStr, Options, T case request(State#state{request = RequestStr, socket = Socket}, TimeOut) of {error, Reason} -> - tsp("verify_request -> request failed: " - "~n Reason: ~p", [Reason]), {error, Reason}; NewState -> - tsp("verify_request -> validate reply: " - "~n NewState: ~p", [NewState]), ValidateResult = validate(RequestStr, NewState, Options, Node, Port), - tsp("verify_request -> validation result: " - "~n ~p", [ValidateResult]), inets_test_lib:close(SocketType, Socket), ValidateResult end; ConnectError -> - tsp("verify_request -> connect error: " - "~n ~p" - "~n", [ConnectError]), - tsf({connect_error, ConnectError, - [SocketType, Host, Port, TranspOpts]}) + ct:fail({connect_error, ConnectError, + [SocketType, Host, Port, TranspOpts]}) catch T:E -> - tsp("verify_request -> connect failed: " - "~n E: ~p" - "~n T: ~p" - "~n", [E, T]), - tsf({connect_failure, - [{type, T}, - {error, E}, - {stacktrace, erlang:get_stacktrace()}, - {args, [SocketType, Host, Port, TranspOpts]}]}) + ct:fail({connect_failure, + [{type, T}, + {error, E}, + {stacktrace, erlang:get_stacktrace()}, + {args, [SocketType, Host, Port, TranspOpts]}]}) end. request(#state{mfa = {Module, Function, Args}, @@ -166,10 +140,6 @@ request(#state{mfa = {Module, Function, Args}, HeadRequest = lists:sublist(RequestStr, 1, 4), receive {tcp, Socket, Data} -> - io:format("~p ~w[~w]request -> received (tcp) data" - "~n Data: ~p" - "~n", [self(), ?MODULE, ?LINE, Data]), - print(tcp, Data, State), case Module:Function([Data | Args]) of {ok, Parsed} -> handle_http_msg(Parsed, State); @@ -179,22 +149,12 @@ request(#state{mfa = {Module, Function, Args}, request(State#state{mfa = NewMFA}, TimeOut) end; {tcp_closed, Socket} when Function =:= whole_body -> - io:format("~p ~w[~w]request -> " - "received (tcp) closed when whole_body" - "~n", [self(), ?MODULE, ?LINE]), - print(tcp, "closed", State), State#state{body = hd(Args)}; {tcp_closed, Socket} -> - io:format("~p ~w[~w]request -> received (tcp) closed" - "~n", [self(), ?MODULE, ?LINE]), exit({test_failed, connection_closed}); {tcp_error, Socket, Reason} -> - io:format("~p ~w[~w]request -> received (tcp) error" - "~n Reason: ~p" - "~n", [self(), ?MODULE, ?LINE, Reason]), ct:fail({tcp_error, Reason}); {ssl, Socket, Data} -> - print(ssl, Data, State), case Module:Function([Data | Args]) of {ok, Parsed} -> handle_http_msg(Parsed, State); @@ -204,28 +164,19 @@ request(#state{mfa = {Module, Function, Args}, request(State#state{mfa = NewMFA}, TimeOut) end; {ssl_closed, Socket} when Function =:= whole_body -> - print(ssl, "closed", State), State#state{body = hd(Args)}; {ssl_closed, Socket} -> exit({test_failed, connection_closed}); {ssl_error, Socket, Reason} -> ct:fail({ssl_error, Reason}) after TimeOut -> - io:format("~p ~w[~w]request -> timeout" - "~n", [self(), ?MODULE, ?LINE]), + ct:pal("~p ~w[~w]request -> timeout" + "~n", [self(), ?MODULE, ?LINE]), ct:fail(connection_timed_out) end. handle_http_msg({Version, StatusCode, ReasonPharse, Headers, Body}, State = #state{request = RequestStr}) -> - io:format("~p ~w[~w]handle_http_msg -> entry with" - "~n Version: ~p" - "~n StatusCode: ~p" - "~n ReasonPharse: ~p" - "~n Headers: ~p" - "~n Body: ~p" - "~n", [self(), ?MODULE, ?LINE, - Version, StatusCode, ReasonPharse, Headers, Body]), case is_expect(RequestStr) of true -> State#state{status_line = {Version, @@ -285,11 +236,6 @@ validate(RequestStr, #state{status_line = {Version, StatusCode, _}, headers = Headers, body = Body}, Options, N, P) -> - tsp("validate -> entry with" - "~n StatusCode: ~p" - "~n Headers: ~p" - "~n Body: ~p", [StatusCode, Headers, Body]), - check_version(Version, Options), case lists:keysearch(statuscode, 1, Options) of {value, _} -> @@ -311,20 +257,20 @@ check_version(Version, Options) -> {value, {version, Version}} -> ok; {value, {version, Ver}} -> - tsf({wrong_version, [{got, Version}, - {expected, Ver}]}); + ct:fail({wrong_version, [{got, Version}, + {expected, Ver}]}); _ -> - case Version of - "HTTP/1.1" -> - ok; + case Version of + "HTTP/1.1" -> + ok; _ -> - tsf({wrong_version, [{got, Version}, - {expected, "HTTP/1.1"}]}) - end + ct:fail({wrong_version, [{got, Version}, + {expected, "HTTP/1.1"}]}) + end end. check_status_code(StatusCode, [], Options) -> - tsf({wrong_status_code, [{got, StatusCode}, {expected, Options}]}); + ct:fail({wrong_status_code, [{got, StatusCode}, {expected, Options}]}); check_status_code(StatusCode, Current = [_ | Rest], Options) -> case lists:keysearch(statuscode, 1, Current) of {value, {statuscode, StatusCode}} -> @@ -332,7 +278,7 @@ check_status_code(StatusCode, Current = [_ | Rest], Options) -> {value, {statuscode, _OtherStatus}} -> check_status_code(StatusCode, Rest, Options); false -> - tsf({wrong_status_code, [{got, StatusCode}, {expected, Options}]}) + ct:fail({wrong_status_code, [{got, StatusCode}, {expected, Options}]}) end. do_validate(_, [], _, _) -> @@ -345,9 +291,9 @@ do_validate(Header, [{header, HeaderField}|Rest], N, P) -> {value, {LowerHeaderField, _Value}} -> ok; false -> - tsf({missing_header_field, LowerHeaderField, Header}); + ct:fail({missing_header_field, LowerHeaderField, Header}); _ -> - tsf({missing_header_field, LowerHeaderField, Header}) + ct:fail({missing_header_field, LowerHeaderField, Header}) end, do_validate(Header, Rest, N, P); do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) -> @@ -356,15 +302,15 @@ do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) -> {value, {LowerHeaderField, Value}} -> ok; false -> - tsf({wrong_header_field_value, LowerHeaderField, Header}); + ct:fail({wrong_header_field_value, LowerHeaderField, Header}); _ -> - tsf({wrong_header_field_value, LowerHeaderField, Header}) + ct:fail({wrong_header_field_value, LowerHeaderField, Header}) end, do_validate(Header, Rest, N, P); do_validate(Header,[{no_header, HeaderField}|Rest],N,P) -> case lists:keysearch(HeaderField,1,Header) of {value,_} -> - tsf({wrong_header_field_value, HeaderField, Header}); + ct:fail({wrong_header_field_value, HeaderField, Header}); _ -> ok end, @@ -382,14 +328,14 @@ is_expect(RequestStr) -> %% OTP-5775, content-length check_body("GET /cgi-bin/erl/httpd_example:get_bin HTTP/1.0\r\n\r\n", 200, "text/html", Length, _Body) when (Length =/= 274) -> - tsf(content_length_error); + ct:fail(content_length_error); check_body("GET /cgi-bin/cgi_echo HTTP/1.0\r\n\r\n", 200, "text/plain", _, Body) -> case size(Body) of 100 -> ok; _ -> - tsf(content_length_error) + ct:fail(content_length_error) end; check_body(RequestStr, 200, "text/html", _, Body) -> @@ -404,16 +350,3 @@ check_body(RequestStr, 200, "text/html", _, Body) -> check_body(_, _, _, _,_) -> ok. -print(Proto, Data, #state{print = true}) -> - ct:pal("Received ~p: ~p~n", [Proto, Data]); -print(_, _, #state{print = false}) -> - ok. - - -tsp(F) -> - inets_test_lib:tsp(F). -tsp(F, A) -> - inets_test_lib:tsp(F, A). - -tsf(Reason) -> - inets_test_lib:tsf(Reason). diff --git a/lib/inets/test/old_httpd_SUITE.erl b/lib/inets/test/old_httpd_SUITE.erl index de9aa4562e..3e1a1a3845 100644 --- a/lib/inets/test/old_httpd_SUITE.erl +++ b/lib/inets/test/old_httpd_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2013. All Rights Reserved. +%% Copyright Ericsson AB 2005-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -155,65 +155,103 @@ all() -> [ {group, ip}, {group, ssl}, - {group, http_1_1_ip}, - {group, http_1_0_ip}, - {group, http_0_9_ip}, - {group, ipv6}, + %%{group, http_1_1_ip}, + %%{group, http_1_0_ip}, + %%{group, http_0_9_ip}, + %%{group, ipv6}, {group, tickets} ]. groups() -> [ {ip, [], - [ip_mod_alias, ip_mod_actions, ip_mod_security, - ip_mod_auth, ip_mod_auth_api, ip_mod_auth_mnesia_api, - ip_mod_htaccess, ip_mod_cgi, ip_mod_esi, ip_mod_get, - ip_mod_head, ip_mod_all, ip_load_light, ip_load_medium, - ip_load_heavy, ip_dos_hostname, ip_time_test, - ip_restart_no_block, ip_restart_disturbing_block, - ip_restart_non_disturbing_block, - ip_block_disturbing_idle, ip_block_non_disturbing_idle, - ip_block_503, ip_block_disturbing_active, - ip_block_non_disturbing_active, - ip_block_disturbing_active_timeout_not_released, - ip_block_disturbing_active_timeout_released, - ip_block_non_disturbing_active_timeout_not_released, - ip_block_non_disturbing_active_timeout_released, - ip_block_disturbing_blocker_dies, - ip_block_non_disturbing_blocker_dies]}, + [ + %%ip_mod_alias, + ip_mod_actions, + %%ip_mod_security, + %% ip_mod_auth, + %% ip_mod_auth_api, + ip_mod_auth_mnesia_api, + %%ip_mod_htaccess, + %%ip_mod_cgi, + %%ip_mod_esi, + %%ip_mod_get, + %%ip_mod_head, + %%ip_mod_all, + %% ip_load_light, + %% ip_load_medium, + %% ip_load_heavy, + %%ip_dos_hostname, + ip_time_test + %% Replaced by load_config + %% ip_restart_no_block, + %% ip_restart_disturbing_block, + %% ip_restart_non_disturbing_block, + %% ip_block_disturbing_idle, + %% ip_block_non_disturbing_idle, + %% ip_block_503, + %% ip_block_disturbing_active, + %% ip_block_non_disturbing_active, + %% ip_block_disturbing_active_timeout_not_released, + %% ip_block_disturbing_active_timeout_released, + %% ip_block_non_disturbing_active_timeout_not_released, + %% ip_block_non_disturbing_active_timeout_released, + %% ip_block_disturbing_blocker_dies, + %% ip_block_non_disturbing_blocker_dies + ]}, {ssl, [], [{group, essl}]}, {essl, [], - [essl_mod_alias, essl_mod_actions, essl_mod_security, - essl_mod_auth, essl_mod_auth_api, - essl_mod_auth_mnesia_api, essl_mod_htaccess, - essl_mod_cgi, essl_mod_esi, essl_mod_get, essl_mod_head, - essl_mod_all, essl_load_light, essl_load_medium, - essl_load_heavy, essl_dos_hostname, essl_time_test, - essl_restart_no_block, essl_restart_disturbing_block, - essl_restart_non_disturbing_block, - essl_block_disturbing_idle, - essl_block_non_disturbing_idle, essl_block_503, - essl_block_disturbing_active, - essl_block_non_disturbing_active, - essl_block_disturbing_active_timeout_not_released, - essl_block_disturbing_active_timeout_released, - essl_block_non_disturbing_active_timeout_not_released, - essl_block_non_disturbing_active_timeout_released, - essl_block_disturbing_blocker_dies, - essl_block_non_disturbing_blocker_dies]}, - {http_1_1_ip, [], - [ip_host, ip_chunked, ip_expect, ip_range, ip_if_test, - ip_http_trace, ip_http1_1_head, - ip_mod_cgi_chunked_encoding_test]}, - {http_1_0_ip, [], - [ip_head_1_0, ip_get_1_0, ip_post_1_0]}, - {http_0_9_ip, [], [ip_get_0_9]}, - {ipv6, [], [ipv6_hostname_ipcomm, ipv6_address_ipcomm, - ipv6_hostname_essl, ipv6_address_essl]}, + [ + %%essl_mod_alias, + essl_mod_actions, + %% essl_mod_security, + %% essl_mod_auth, + %% essl_mod_auth_api, + essl_mod_auth_mnesia_api, + %%essl_mod_htaccess, + %%essl_mod_cgi, + %%essl_mod_esi, + %%essl_mod_get, + %%essl_mod_head, + %% essl_mod_all, + %% essl_load_light, + %% essl_load_medium, + %% essl_load_heavy, + %%essl_dos_hostname, + essl_time_test + %% Replaced by load_config + %% essl_restart_no_block, + %% essl_restart_disturbing_block, + %% essl_restart_non_disturbing_block, + %% essl_block_disturbing_idle, + %% essl_block_non_disturbing_idle, essl_block_503, + %% essl_block_disturbing_active, + %% essl_block_non_disturbing_active, + %% essl_block_disturbing_active_timeout_not_released, + %% essl_block_disturbing_active_timeout_released, + %% essl_block_non_disturbing_active_timeout_not_released, + %% essl_block_non_disturbing_active_timeout_released, + %% essl_block_disturbing_blocker_dies, + %% essl_block_non_disturbing_blocker_dies + ]}, + %% {http_1_1_ip, [], + %% [ + %% %%ip_host, ip_chunked, ip_expect, + %% %%ip_range, + %% %%ip_if_test + %% %%ip_http_trace, ip_http1_1_head, + %% %%ip_mod_cgi_chunked_encoding_test + %% ]}, + %%{http_1_0_ip, [], + %%[ip_head_1_0, ip_get_1_0, ip_post_1_0]}, + %%{http_0_9_ip, [], [ip_get_0_9]}, + %% {ipv6, [], [ipv6_hostname_ipcomm, ipv6_address_ipcomm, + %% ipv6_hostname_essl, ipv6_address_essl]}, {tickets, [], - [ticket_5775, ticket_5865, ticket_5913, ticket_6003, - ticket_7304]}]. - + [%%ticket_5775, ticket_5865, + ticket_5913%%, ticket_6003, + %%ticket_7304 + ]}]. init_per_group(ipv6 = _GroupName, Config) -> case inets_test_lib:has_ipv6_support() of |