summaryrefslogtreecommitdiff
path: root/lib/inets
diff options
context:
space:
mode:
authorIngela Anderton Andin <ingela@erlang.org>2019-11-21 17:11:36 +0100
committerIngela Anderton Andin <ingela@erlang.org>2019-12-13 15:19:27 +0100
commit7d209cffbe26d184a24980944f1dec873a610332 (patch)
tree7b23564238c311a61908ef8b51632473f367d6d9 /lib/inets
parent758f472059f6e6e6d8d9112be0341b5263f00811 (diff)
downloaderlang-7d209cffbe26d184a24980944f1dec873a610332.tar.gz
inets: httpd - Remove legacy security model
This is not secure and should not be used. Also reduces maintainance burden.
Diffstat (limited to 'lib/inets')
-rw-r--r--lib/inets/doc/src/http_server.xml177
-rw-r--r--lib/inets/doc/src/httpd.xml14
-rw-r--r--lib/inets/src/http_server/Makefile1
-rw-r--r--lib/inets/src/http_server/mod_htaccess.erl1071
-rw-r--r--lib/inets/src/inets_app/inets.app.src1
-rw-r--r--lib/inets/test/httpd_SUITE.erl258
-rw-r--r--lib/inets/test/httpd_mod_SUITE.erl2
7 files changed, 7 insertions, 1517 deletions
diff --git a/lib/inets/doc/src/http_server.xml b/lib/inets/doc/src/http_server.xml
index 65b3dcde95..6a7be73a4e 100644
--- a/lib/inets/doc/src/http_server.xml
+++ b/lib/inets/doc/src/http_server.xml
@@ -171,162 +171,9 @@
</section>
<section>
- <title>Htaccess - User Configurable Authentication</title>
- <marker id="htaccess"></marker>
- <p>Web server users without server administrative privileges
- that need to manage authentication of web pages that are local
- to their user can use the per-directory runtime configurable
- user-authentication scheme <c>htaccess</c>.
- It works as follows:</p>
- <list type="bulleted">
- <item>Each directory in the path to the requested asset is
- searched for an access file (default is <c>.htaccess</c>), which
- restricts the web servers rights to respond to a request.
- If an access file is found, the rules in that file is applied to the
- request.</item>
- <item>The rules in an access file apply to files in the same
- directory and in subdirectories. If there exists more than one
- access file in the path to an asset, the rules in the
- access file nearest the requested asset is applied.</item>
- <item>To change the rules that restrict the use of
- an asset, the user only needs write access
- to the directory where the asset is.</item>
- <item>All access files in the path to a requested asset are read
- once per request. This means that the load on the server
- increases when <c>htaccess</c> is used.</item>
- <item>If a directory is limited both by authentication directives
- in the HTTP server configuration file and by the <c>htaccess</c>
- files, the user must be allowed to get access to the file by both
- methods for the request to succeed.</item>
- </list>
-
- <section>
- <title>Access Files Directives</title>
- <p>In every directory under <c>DocumentRoot</c> or under an
- <c>Alias</c> a user can place an access file. An access file
- is a plain text file that specifies the restrictions to
- consider before the web server answers to a
- request. If there are more than one access file in the path
- to the requested asset, the directives in the access file in
- the directory nearest the asset is used.</p>
- <taglist>
- <tag><em>"allow"</em></tag>
- <item>
- <p><em>Syntax:</em> <c>Allow</c> from subnet <c>subnet | from all</c></p>
- <p><em>Default:</em> <c>from all</c></p>
- <p>Same as directive <c>allow</c> for the server configuration file.</p>
- </item>
- <tag><em>"AllowOverRide"</em></tag>
- <item>
- <p><em>Syntax:</em> <c>AllowOverRide</c> <c>all | none | Directives</c></p>
- <p><em>Default:</em> <c>none</c></p>
- <p><c>AllowOverRide</c> specifies the parameters that
- access files in subdirectories are not allowed to alter the value
- for. If the parameter is set to <c>none</c>, no further
- access files is parsed.
- </p>
- <p>If only one access file exists, setting this parameter to
- <c>none</c> can ease the burden on the server as the server
- then stops looking for access files.</p>
- </item>
- <tag><em>"AuthGroupfile"</em></tag>
- <item>
- <p><em>Syntax:</em> <c>AuthGroupFile</c> Filename</p>
- <p><em>Default:</em> <c>none</c></p>
- <p><c>AuthGroupFile</c> indicates which file that contains the list
- of groups. The filename must contain the absolute path to the
- file. The format of the file is one group per row and
- every row contains the name of the group and the members
- of the group, separated by a space, for example:</p>
- <pre>
-GroupName: Member1 Member2 .... MemberN</pre>
- </item>
- <tag><em>"AuthName"</em></tag>
- <item>
- <p><em>Syntax:</em> <c>AuthName</c> auth-domain</p>
- <p><em>Default:</em> <c>none</c></p>
- <p>Same as directive <c>AuthName</c> for the server
- configuration file.</p>
- </item>
- <tag><em>"AuthType"</em></tag>
- <item>
- <p><em>Syntax:</em> <c>AuthType</c> <c>Basic</c></p>
- <p><em>Default:</em> <c>Basic</c></p>
- <p><c>AuthType</c> specifies which authentication scheme to
- be used. Only Basic Authenticating using UUEncoding of
- the password and user ID is implemented.</p>
- </item>
- <tag><em>"AuthUserFile"</em></tag>
- <item>
- <p><em>Syntax:</em> <c>AuthUserFile</c> Filename</p>
- <p><em>Default:</em><c>none</c></p>
- <p><c>AuthUserFile</c> indicates which file that contains the list
- of users. The filename must contain the absolute path to the
- file. The username and password are not encrypted so do not
- place the file with users in a directory that is accessible
- through the web server. The format of the file is one user per row.
- Every row contains <c>UserName</c> and <c>Password</c> separated
- by a colon, for example:</p>
- <pre>
-UserName:Password
-UserName:Password</pre>
- </item>
- <tag><em>"deny"</em></tag>
- <item>
- <p><em>Syntax:</em> <c>deny</c> from subnet <c>subnet | from all</c></p>
- <p><em>Context:</em> Limit</p>
- <p>Same as directive <c>deny</c> for the server configuration file.</p>
- </item>
- <tag><em>"Limit"</em></tag>
- <item>
- <p><em>Syntax:</em> <c><![CDATA[<Limit]]></c> RequestMethods<c>></c></p>
- <p><em>Default:</em> <c>none</c></p>
- <p><c><![CDATA[<Limit>]]></c> and <c>&lt;/Limit&gt;</c> are used to enclose
- a group of directives applying only to requests using
- the specified methods. If no request method is specified,
- all request methods are verified against the restrictions.</p>
- <p>Example:</p>
- <pre>
-&lt;Limit POST GET HEAD&gt;
- order allow deny
- require group group1
- allow from 123.145.244.5
-&lt;/Limit&gt;</pre>
- </item>
- <tag><em>"order"</em></tag>
- <item>
- <p><em>Syntax:</em> <c>order</c> <c>allow deny | deny allow</c></p>
- <p><em>Default:</em> <c>allow deny</c></p>
- <p><c>order</c> defines if the deny or allow control is to
- be performed first.</p>
- <p>If the order is set to <c>allow deny</c>, the users
- network address is first controlled to be in the allow subset.
- If the user network address is not in the allowed subset, the user
- is denied to get the asset. If the network address is in the
- allowed subset, a second control is performed. That is,
- the user network address is not in the subset of network
- addresses to be denied as specified by parameter <c>deny</c>.</p>
- <p>If the order is set to <c>deny allow</c>, only users from networks
- specified to be in the allowed subset succeeds to request
- assets in the limited area.</p>
- </item>
- <tag><em>"require"</em></tag>
- <item>
- <p><em>Syntax:</em> <c>require</c>
- <c>group group1 group2... | user user1 user2...</c></p>
- <p><em>Default:</em> <c>none</c></p>
- <p><em>Context:</em> Limit</p>
- <p>For more information, see directive <c>require</c> in
- <seealso marker="mod_auth">mod_auth(3)</seealso>.</p>
- </item>
- </taglist>
- </section>
- </section>
-
- <section>
- <title>Dynamic Web Pages</title>
- <marker id="dynamic_we_pages"></marker>
- <p><c>Inets</c> HTTP server provides two ways of creating dynamic web
+ <title>Dynamic Web Pages</title>
+ <marker id="dynamic_we_pages"></marker>
+ <p><c>Inets</c> HTTP server provides two ways of creating dynamic web
pages, each with its own advantages and disadvantages:</p>
<taglist>
<tag><em>CGI scripts</em></tag>
@@ -718,23 +565,7 @@ start() ->
<item><c>real_name</c> - from <seealso marker="mod_alias">mod_alias</seealso></item>
</list>
</section>
-
- <section>
- <title>mod_htaccess - User Configurable Access</title>
- <p>This module provides per-directory user configurable access
- control.</p>
- <p>Uses the following Erlang Web Server API interaction data:
- </p>
- <list type="bulleted">
- <item><c>real_name</c> - from <seealso marker="mod_alias">mod_alias</seealso></item>
- </list>
- <p>Exports the following Erlang Web Server API interaction data:
- </p>
- <taglist>
- <tag><c>{remote_user_name, User}</c></tag>
- <item>The username used for authentication.</item>
- </taglist>
- </section>
+
<section>
<title>mod_log - Logging Using Text Files.</title>
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index 987f0c3cf4..a7401f41dc 100644
--- a/lib/inets/doc/src/httpd.xml
+++ b/lib/inets/doc/src/httpd.xml
@@ -881,20 +881,6 @@ Transport: TLS
</taglist>
- <marker id="props_htaccess"></marker>
- <p><em>Htaccess Authentication Properties - Requires mod_htaccess</em></p>
- <taglist>
- <tag><marker id="prop_access_files"></marker>{access_files, [path()]}</tag>
- <item>
- <p>Specifies the filenames that are used for
- access files. When a request comes, every directory in the path
- to the requested asset are searched after files with the
- names specified by this parameter. If such a file is found, the
- file is parsed and the restrictions specified in it are
- applied to the request.</p>
- </item>
- </taglist>
-
<marker id="props_sec"></marker>
<p><em>Security Properties - Requires mod_security</em></p>
diff --git a/lib/inets/src/http_server/Makefile b/lib/inets/src/http_server/Makefile
index 509a64982d..da9549406f 100644
--- a/lib/inets/src/http_server/Makefile
+++ b/lib/inets/src/http_server/Makefile
@@ -80,7 +80,6 @@ MODULES = \
mod_esi \
mod_get \
mod_head \
- mod_htaccess \
mod_log \
mod_range \
mod_responsecontrol \
diff --git a/lib/inets/src/http_server/mod_htaccess.erl b/lib/inets/src/http_server/mod_htaccess.erl
deleted file mode 100644
index 7b742bba24..0000000000
--- a/lib/inets/src/http_server/mod_htaccess.erl
+++ /dev/null
@@ -1,1071 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. 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(mod_htaccess).
-
--export([do/1, load/2, store/2]).
-
--include("httpd.hrl").
--include("httpd_internal.hrl").
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Public methods that interface the eswapi %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%----------------------------------------------------------------------
-% Public method called by the webbserver to insert the data about
-% Names on accessfiles
-%----------------------------------------------------------------------
-load("AccessFileName" ++ FileNames, _Context)->
- CleanFileNames=string:strip(FileNames),
- {ok,[],{access_files,string:tokens(CleanFileNames," ")}}.
-
-store({access_files, Files} = Conf, _) when is_list(Files)->
- {ok, Conf};
-store({access_files, Value}, _) ->
- {error, {wrong_type, {access_files, Value}}}.
-
-%----------------------------------------------------------------------
-% Public method that the webbserver calls to control the page
-%----------------------------------------------------------------------
-do(Info)->
- case proplists:get_value(status, Info#mod.data) of
- {_Status_code, _PhraseArgs, _Reason}->
- {proceed,Info#mod.data};
- undefined ->
- control_path(Info)
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% The functions that start the control if there is a accessfile %%
-%% and if so controls if the dir is allowed or not %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%----------------------------------------------------------------------
-%Info = record mod as specified in httpd.hrl
-%returns either {proceed,Info#mod.data}
-%{proceed,[{status,403....}|Info#mod.data]}
-%{proceed,[{status,401....}|Info#mod.data]}
-%{proceed,[{status,500....}|Info#mod.data]}
-%----------------------------------------------------------------------
-control_path(Info) ->
- Path = mod_alias:path(Info#mod.data,
- Info#mod.config_db,
- Info#mod.request_uri),
- case isErlScriptOrNotAccessibleFile(Path,Info) of
- true->
- {proceed,Info#mod.data};
- false->
- case getHtAccessData(Path,Info)of
- {ok,public}->
- %%There was no restrictions on the page continue
- {proceed,Info#mod.data};
- {error, _Reason} ->
- %%Something got wrong continue or quit??????????????????/
- {proceed,Info#mod.data};
- {accessData,AccessData}->
- controlAllowedMethod(Info,AccessData)
- end
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% These methods controls that the method the client used in the %%
-%% request is one of the limited %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%----------------------------------------------------------------------
-%Control that if the accessmethod used is in the list of modes to challenge
-%
-%Info is the mod record as specified in httpd.hrl
-%AccessData is an ets table whit the data in the .htaccessfiles
-%----------------------------------------------------------------------
-controlAllowedMethod(Info,AccessData)->
- case allowedRequestMethod(Info,AccessData) of
- allow->
- %%The request didnt use one of the limited methods
- ets:delete(AccessData),
- {proceed,Info#mod.data};
- challenge->
- authenticateUser(Info,AccessData)
- end.
-
-%----------------------------------------------------------------------
-%Check the specified access method in the .htaccessfile
-%----------------------------------------------------------------------
-allowedRequestMethod(Info,AccessData)->
- case ets:lookup(AccessData,limit) of
- [{limit,all}]->
- challenge;
- [{limit,Methods}]->
- isLimitedRequestMethod(Info,Methods)
- end.
-
-
-%----------------------------------------------------------------------
-%Check the specified accessmethods in the .htaccesfile against the users
-%accessmethod
-%
-%Info is the record from the do call
-%Methods is a list of the methods specified in the .htaccessfile
-%----------------------------------------------------------------------
-isLimitedRequestMethod(Info,Methods)->
- case lists:member(Info#mod.method,Methods) of
- true->
- challenge;
- false ->
- allow
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% These methods controls that the user comes from an allowwed net %%
-%% and if so wheather its a valid user or a challenge shall be %%
-%% generated %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%----------------------------------------------------------------------
-%The first thing to control is that the user is from a network
-%that has access to the page
-%----------------------------------------------------------------------
-authenticateUser(Info,AccessData)->
- case controlNet(Info,AccessData) of
- allow->
- %the network is ok control that it is an allowed user
- authenticateUser2(Info,AccessData);
- deny->
- %The user isnt allowed to access the pages from that network
- ets:delete(AccessData),
- {proceed,[{status,{403,Info#mod.request_uri,
- "Restricted area not allowed from your network"}}|Info#mod.data]}
- end.
-
-
-%----------------------------------------------------------------------
-%The network the user comes from is allowed to view the resources
-%control whether the user needsto supply a password or not
-%----------------------------------------------------------------------
-authenticateUser2(Info,AccessData)->
- case ets:lookup(AccessData,require) of
- [{require,AllowedUsers}]->
- case ets:lookup(AccessData,auth_name) of
- [{auth_name,Realm}]->
- authenticateUser2(Info,AccessData,Realm,AllowedUsers);
- _NoAuthName->
- ets:delete(AccessData),
- {break,[{status,{500,none,
- ?NICE("mod_htaccess:AuthName directive "
- "not specified")}}]}
- end;
- [] ->
- %%No special user is required the network is ok so let
- %%the user in
- ets:delete(AccessData),
- {proceed,Info#mod.data}
- end.
-
-
-%----------------------------------------------------------------------
-%The user must send a userId and a password to get the resource
-%Control if its already in the http-request
-%if the file with users is bad send an 500 response
-%----------------------------------------------------------------------
-authenticateUser2(Info,AccessData,Realm,AllowedUsers)->
- case authenticateUser(Info,AccessData,AllowedUsers) of
- allow ->
- ets:delete(AccessData),
- {user,Name, _Pwd} = getAuthenticatingDataFromHeader(Info),
- {proceed, [{remote_user_name,Name}|Info#mod.data]};
- challenge->
- ets:delete(AccessData),
- ReasonPhrase = httpd_util:reason_phrase(401),
- Message = httpd_util:message(401,none,Info#mod.config_db),
- {proceed,
- [{response,
- {401,
- ["WWW-Authenticate: Basic realm=\"",Realm,
- "\"\r\n\r\n","<HTML>\n<HEAD>\n<TITLE>",
- ReasonPhrase,"</TITLE>\n",
- "</HEAD>\n<BODY>\n<H1>",ReasonPhrase,
- "</H1>\n",Message,"\n</BODY>\n</HTML>\n"]}}|
- Info#mod.data]};
- deny->
- ets:delete(AccessData),
- {break,[{status,{500,none,
- ?NICE("mod_htaccess:Bad path to user "
- "or group file")}}]}
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% Methods that validate the netwqork the user comes from %%
-%% according to the allowed networks %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%---------------------------------------------------------------------
-%Controls the users networkaddress agains the specifed networks to
-%allow or deny
-%
-%returns either allow or deny
-%----------------------------------------------------------------------
-controlNet(Info,AccessData)->
- UserNetwork=getUserNetworkAddress(Info),
- case getAllowDenyOrder(AccessData) of
- {_deny,[],_allow,[]}->
- allow;
- {deny,[],allow,AllowedNetworks}->
- controlIfAllowed(AllowedNetworks,UserNetwork,allow,deny);
- {allow,AllowedNetworks,deny,[]}->
- controlIfAllowed(AllowedNetworks,UserNetwork,allow,deny);
-
- {deny,DeniedNetworks,allow,[]}->
- controlIfAllowed(DeniedNetworks,UserNetwork,allow,deny);
- {allow,[],deny,DeniedNetworks}->
- controlIfAllowed(DeniedNetworks,UserNetwork,allow,deny);
-
- {deny,DeniedNetworks,allow,AllowedNetworks}->
- controlDenyAllow(DeniedNetworks,AllowedNetworks,UserNetwork);
- {allow,AllowedNetworks,deny,DeniedNetworks}->
- controlAllowDeny(AllowedNetworks,DeniedNetworks,UserNetwork)
- end.
-
-
-%----------------------------------------------------------------------
-%Returns the users IP-Number
-%----------------------------------------------------------------------
-getUserNetworkAddress(Info)->
- {_Socket,Address}=(Info#mod.init_data)#init_data.peername,
- Address.
-
-
-%----------------------------------------------------------------------
-%Control the users Ip-number against the ip-numbers in the .htaccessfile
-%----------------------------------------------------------------------
-controlIfAllowed(AllowedNetworks,UserNetwork,IfAllowed,IfDenied)->
- case AllowedNetworks of
- [{allow,all}]->
- IfAllowed;
- [{deny,all}]->
- IfDenied;
- [{deny,Networks}]->
- memberNetwork(Networks,UserNetwork,IfDenied,IfAllowed);
- [{allow,Networks}]->
- memberNetwork(Networks,UserNetwork,IfAllowed,IfDenied);
- _Error->
- IfDenied
- end.
-
-
-%---------------------------------------------------------------------%
-%The Denycontrol isn't neccessary to preform since the allow control %
-%override the deny control %
-%---------------------------------------------------------------------%
-controlDenyAllow(_DeniedNetworks, AllowedNetworks, UserNetwork)->
- case AllowedNetworks of
- [{allow, all}]->
- allow;
- [{allow, Networks}]->
- case memberNetwork(Networks, UserNetwork) of
- true->
- allow;
- false->
- deny
- end
- end.
-
-
-%----------------------------------------------------------------------%
-%Control that the user is in the allowed list if so control that the %
-%network is in the denied list
-%----------------------------------------------------------------------%
-controlAllowDeny(AllowedNetworks,DeniedNetworks,UserNetwork)->
- case controlIfAllowed(AllowedNetworks,UserNetwork,allow,deny) of
- allow->
- controlIfAllowed(DeniedNetworks,UserNetwork,deny,allow);
- deny ->
- deny
- end.
-
-%----------------------------------------------------------------------
-%Controls if the users Ipnumber is in the list of either denied or
-%allowed networks
-%----------------------------------------------------------------------
-memberNetwork(Networks,UserNetwork,IfTrue,IfFalse)->
- case memberNetwork(Networks,UserNetwork) of
- true->
- IfTrue;
- false->
- IfFalse
- end.
-
-
-%----------------------------------------------------------------------
-%regexp match the users ip-address against the networks in the list of
-%ipadresses or subnet addresses.
-memberNetwork(Networks,UserNetwork)->
- case lists:filter(fun(Net)->
- case re:run(UserNetwork,
- formatRegexp(Net), [{capture, first}]) of
- {match,[{0,_}]}->
- true;
- _NotSubNet ->
- false
- end
- end,Networks) of
- []->
- false;
- _MemberNetWork ->
- true
- end.
-
-
-%----------------------------------------------------------------------
-%Creates a regexp from an ip-number i.e "127.0.0-> "^127[.]0[.]0.*"
-%"127.0.0.-> "^127[.]0[.]0[.].*"
-%----------------------------------------------------------------------
-formatRegexp(Net)->
- [SubNet1|SubNets]=string:tokens(Net,"."),
- NetRegexp=lists:foldl(fun(SubNet,Newnet)->
- Newnet ++ "[.]" ++SubNet
- end,"^"++SubNet1,SubNets),
- case string:len(Net)-string:rchr(Net,$.) of
- 0->
- NetRegexp++"[.].*";
- _->
- NetRegexp++".*"
- end.
-
-%----------------------------------------------------------------------
-%If the user has specified if the allow or deny check shall be preformed
-%first get that order if no order is specified take
-%allow - deny since its harder that deny - allow
-%----------------------------------------------------------------------
-getAllowDenyOrder(AccessData)->
- case ets:lookup(AccessData,order) of
- [{order,{deny,allow}}]->
- {deny,ets:lookup(AccessData,deny),
- allow,ets:lookup(AccessData,allow)};
- _DefaultOrder->
- {allow,ets:lookup(AccessData,allow),
- deny,ets:lookup(AccessData,deny)}
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% The methods that validates the user %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%----------------------------------------------------------------------
-%Control if there is anyu autheticating data in threquest header
-%if so it controls it against the users in the list Allowed Users
-%----------------------------------------------------------------------
-authenticateUser(Info,AccessData,AllowedUsers)->
- case getAuthenticatingDataFromHeader(Info) of
- {user,User,PassWord}->
- authenticateUser(Info,AccessData,AllowedUsers,
- {user,User,PassWord});
- {error,nouser}->
- challenge;
- {error, _BadData}->
- challenge
- end.
-
-
-%----------------------------------------------------------------------
-%Returns the Autheticating data in the http-request
-%----------------------------------------------------------------------
-getAuthenticatingDataFromHeader(Info)->
- PrsedHeader=Info#mod.parsed_header,
- case proplists:get_value("authorization", PrsedHeader) of
- undefined->
- {error,nouser};
- [$B,$a,$s,$i,$c,$\ |EncodedString] = Credentials ->
- case (catch base64:decode_to_string(EncodedString)) of
- {'EXIT',{function_clause, _}} ->
- {error, Credentials};
- UnCodedString ->
- case httpd_util:split(UnCodedString,":",2) of
- {ok,[User,PassWord]}->
- {user,User,PassWord};
- Other ->
- {error, Other}
- end
- end;
- BadCredentials ->
- {error,BadCredentials}
- end.
-
-%----------------------------------------------------------------------
-%Returns a list of all members of the allowed groups
-%----------------------------------------------------------------------
-getGroupMembers(Groups,AllowedGroups)->
- Allowed=lists:foldl(fun({group,Name,Members},AllowedMembers)->
- case lists:member(Name,AllowedGroups) of
- true->
- AllowedMembers++Members;
- false ->
- AllowedMembers
- end
- end,[],Groups),
- {ok,Allowed}.
-
-authenticateUser(Info,AccessData,{{users,[]},{groups,Groups}},User)->
- authenticateUser(Info,AccessData,{groups,Groups},User);
-authenticateUser(Info,AccessData,{{users,Users},{groups,[]}},User)->
- authenticateUser(Info,AccessData,{users,Users},User);
-
-authenticateUser(Info,AccessData,{{users,Users},{groups,Groups}},User)->
- AllowUser=authenticateUser(Info,AccessData,{users,Users},User),
- AllowGroup=authenticateUser(Info,AccessData,{groups,Groups},User),
- case {AllowGroup,AllowUser} of
- {_,allow}->
- allow;
- {allow,_}->
- allow;
- {challenge,_}->
- challenge;
- {_,challenge}->
- challenge;
- {_deny,_deny}->
- deny
- end;
-
-
-%----------------------------------------------------------------------
-%Controls that the user is a member in one of the allowed group
-%----------------------------------------------------------------------
-authenticateUser(Info,AccessData,{groups,AllowedGroups},{user,User,PassWord})->
- case getUsers(AccessData,group_file) of
- {group_data,Groups}->
- {ok, Members } = getGroupMembers(Groups,AllowedGroups),
- authenticateUser(Info,AccessData,{users,Members},
- {user,User,PassWord});
- {error, _BadData}->
- deny
- end;
-
-
-%----------------------------------------------------------------------
-%Control that the user is one of the allowed users and that the passwd is ok
-%----------------------------------------------------------------------
-authenticateUser(_Info,AccessData,{users,AllowedUsers},{user,User,PassWord})->
- case lists:member(User,AllowedUsers) of
- true->
- %Get the usernames and passwords from the file
- case getUsers(AccessData,user_file) of
- {error, _BadData}->
- deny;
- {user_data,Users}->
- %Users is a list of the users in
- %the userfile [{user,User,Passwd}]
- checkPassWord(Users,{user,User,PassWord})
- end;
- false ->
- challenge
- end.
-
-
-%----------------------------------------------------------------------
-%Control that the user User={user,"UserName","PassWd"} is
-%member of the list of Users
-%----------------------------------------------------------------------
-checkPassWord(Users,User)->
- case lists:member(User,Users) of
- true->
- allow;
- false->
- challenge
- end.
-
-
-%----------------------------------------------------------------------
-%Get the users in the specified file
-%UserOrGroup is an atom that specify if its a group file or a user file
-%i.e. group_file or user_file
-%----------------------------------------------------------------------
-getUsers({file,FileName},UserOrGroup)->
- case file:open(FileName,[read]) of
- {ok,AccessFileHandle} ->
- getUsers({stream,AccessFileHandle},[],UserOrGroup);
- {error,Reason} ->
- {error,{Reason,FileName}}
- end;
-
-
-%----------------------------------------------------------------------
-%The method that starts the lokkong for user files
-%----------------------------------------------------------------------
-
-getUsers(AccessData,UserOrGroup)->
- case ets:lookup(AccessData,UserOrGroup) of
- [{UserOrGroup,File}]->
- getUsers({file,File},UserOrGroup);
- _ ->
- {error,noUsers}
- end.
-
-
-%----------------------------------------------------------------------
-%Reads data from the filehandle File to the list FileData and when its
-%reach the end it returns the list in a tuple {user_file|group_file,FileData}
-%----------------------------------------------------------------------
-getUsers({stream,File},FileData,UserOrGroup)->
- case io:get_line(File,[]) of
- eof when UserOrGroup =:= user_file ->
- {user_data,FileData};
- eof when UserOrGroup =:= group_file ->
- {group_data,FileData};
- Line ->
- getUsers({stream,File},
- formatUser(Line,FileData,UserOrGroup),UserOrGroup)
- end.
-
-
-%----------------------------------------------------------------------
-%If the line is a comment remove it
-%----------------------------------------------------------------------
-formatUser([$#|_UserDataComment],FileData,_UserOrgroup)->
- FileData;
-
-
-%----------------------------------------------------------------------
-%The user name in the file is Username:Passwd\n
-%Remove the newline sign and split the user name in
-%UserName and Password
-%----------------------------------------------------------------------
-formatUser(UserData,FileData,UserOrGroup)->
- case string:tokens(UserData," \r\n")of
- [User| _Whitespace] when UserOrGroup =:= user_file ->
- case string:tokens(User,":") of
- [Name,PassWord]->
- [{user,Name,PassWord}|FileData];
- _Error->
- FileData
- end;
- GroupData when UserOrGroup =:= group_file ->
- parseGroupData(GroupData,FileData);
- _Error ->
- FileData
- end.
-
-
-%----------------------------------------------------------------------
-%if everything is right GroupData is on the form
-% ["groupName:", "Member1", "Member2", "Member2"
-%----------------------------------------------------------------------
-parseGroupData([GroupName|GroupData],FileData)->
- [{group,formatGroupName(GroupName),GroupData}|FileData].
-
-
-%----------------------------------------------------------------------
-%the line in the file is GroupName: Member1 Member2 .....MemberN
-%Remove the : from the group name
-%----------------------------------------------------------------------
-formatGroupName(GroupName)->
- string:strip(GroupName,right,$:).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% Functions that parses the accessfiles %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%----------------------------------------------------------------------
-%Control that the asset is a real file and not a request for an virtual
-%asset
-%----------------------------------------------------------------------
-isErlScriptOrNotAccessibleFile(Path, _Info)->
- case file:read_file_info(Path) of
- {ok,_fileInfo}->
- false;
- {error,_Reason} ->
- true
- end.
-
-
-%----------------------------------------------------------------------
-%Path=PathToTheRequestedFile=String
-%Innfo=record#mod
-%----------------------------------------------------------------------
-getHtAccessData(Path,Info)->
- HtAccessFileNames=getHtAccessFileNames(Info),
- case getData(Path,Info,HtAccessFileNames) of
- {ok,public}->
- {ok,public};
- {accessData,AccessData}->
- {accessData,AccessData};
- {error,Reason} ->
- {error,Reason}
- end.
-
-
-%----------------------------------------------------------------------
-%returns the names of the accessfiles
-%----------------------------------------------------------------------
-getHtAccessFileNames(Info)->
- case httpd_util:lookup(Info#mod.config_db,access_files) of
- undefined->
- [".htaccess"];
- Files->
- Files
- end.
-%----------------------------------------------------------------------
-%HtAccessFileNames=["accessfileName1",..."AccessFileName2"]
-%----------------------------------------------------------------------
-getData(Path,Info,HtAccessFileNames)->
- SplittedPath = re:split(Path, "/", [{return, list}]),
- getData2(HtAccessFileNames,SplittedPath,Info).
-
-%----------------------------------------------------------------------
-%Add to together the data in the Splittedpath up to the path
-%that is the alias or the document root
-%Since we do not need to control after any accessfiles before here
-%----------------------------------------------------------------------
-getData2(HtAccessFileNames,SplittedPath,Info)->
- case getRootPath(SplittedPath,Info) of
- {error,Path}->
- {error,Path};
- {ok,StartPath,RestOfSplittedPath} ->
- getData2(HtAccessFileNames,StartPath,RestOfSplittedPath,Info)
- end.
-
-
-%----------------------------------------------------------------------
-%HtAccessFilenames is a list the names the accesssfiles can have
-%Path is the shortest match agains all alias and documentroot
-%rest of splitted path is a list of the parts of the path
-%Info is the mod recod from the server
-%----------------------------------------------------------------------
-getData2(HtAccessFileNames, StartPath, RestOfSplittedPath, _Info)->
- case getHtAccessFiles(HtAccessFileNames,StartPath,RestOfSplittedPath) of
- []->
- %No accessfile qiut its a public directory
- {ok,public};
- Files ->
- loadAccessFilesData(Files)
- end.
-
-
-%----------------------------------------------------------------------
-%Loads the data in the accessFiles specifiied by
-% AccessFiles=["/hoem/public/html/accefile",
-% "/home/public/html/priv/accessfile"]
-%----------------------------------------------------------------------
-loadAccessFilesData(AccessFiles)->
- loadAccessFilesData(AccessFiles,ets:new(accessData,[])).
-
-
-%----------------------------------------------------------------------
-%Returns the found data
-%----------------------------------------------------------------------
-contextToValues(AccessData)->
- case ets:lookup(AccessData,context) of
- [{context,Values}]->
- ets:delete(AccessData,context),
- insertContext(AccessData,Values),
- {accessData,AccessData};
- _Error->
- {error,errorInAccessFile}
- end.
-
-
-insertContext(_AccessData, [])->
- ok;
-
-insertContext(AccessData,[{allow,From}|Values])->
- insertDenyAllowContext(AccessData,{allow,From}),
- insertContext(AccessData,Values);
-
-insertContext(AccessData,[{deny,From}|Values])->
- insertDenyAllowContext(AccessData,{deny,From}),
- insertContext(AccessData,Values);
-
-insertContext(AccessData,[{require,{GrpOrUsr,Members}}|Values])->
- case ets:lookup(AccessData,require) of
- [] when GrpOrUsr =:= users ->
- ets:insert(AccessData,{require,{{users,Members},{groups,[]}}});
-
- [{require,{{users,Users},{groups,Groups}}}] when GrpOrUsr =:= users ->
- ets:insert(AccessData,{require,{{users,Users++Members},
- {groups,Groups}}});
- [] when GrpOrUsr =:= groups ->
- ets:insert(AccessData,{require,{{users,[]},{groups,Members}}});
-
- [{require,{{users,Users},{groups,Groups}}}] when GrpOrUsr =:= groups ->
- ets:insert(AccessData,{require,{{users,Users},
- {groups,Groups++Members}}})
- end,
- insertContext(AccessData,Values);
-
-
-
-%%limit and order directive need no transforming they areis just to insert
-insertContext(AccessData,[Elem|Values])->
- ets:insert(AccessData,Elem),
- insertContext(AccessData,Values).
-
-
-insertDenyAllowContext(AccessData,{AllowDeny,From})->
- case From of
- all ->
- ets:insert(AccessData,{AllowDeny,all});
- _AllowedSubnets ->
- case ets:lookup(AccessData,AllowDeny) of
- []->
- ets:insert(AccessData,{AllowDeny,From});
- [{AllowDeny,all}]->
- ok;
- [{AllowDeny,Networks}]->
- ets:insert(AccessData,{allow,Networks++From})
- end
- end.
-
-loadAccessFilesData([],AccessData)->
- %preform context to limits
- contextToValues(AccessData),
- {accessData,AccessData};
-
-%----------------------------------------------------------------------
-%Takes each file in the list and load the data to the ets table
-%AccessData
-%----------------------------------------------------------------------
-loadAccessFilesData([FileName|FileNames],AccessData)->
- case loadAccessFileData({file,FileName},AccessData) of
- overRide->
- loadAccessFilesData(FileNames,AccessData);
- noOverRide ->
- {accessData,AccessData};
- error->
- ets:delete(AccessData),
- {error,errorInAccessFile}
- end.
-
-%----------------------------------------------------------------------
-%opens the filehandle to the specified file
-%----------------------------------------------------------------------
-loadAccessFileData({file,FileName},AccessData)->
- case file:open(FileName,[read]) of
- {ok,AccessFileHandle}->
- loadAccessFileData({stream,AccessFileHandle},AccessData,[]);
- {error, _Reason} ->
- overRide
- end.
-
-%----------------------------------------------------------------------
-%%look att each line in the file and add them to the database
-%%When end of file is reached control i overrride is allowed
-%% if so return
-%----------------------------------------------------------------------
-loadAccessFileData({stream,File},AccessData,FileData)->
- case io:get_line(File,[]) of
- eof->
- insertData(AccessData,FileData),
- case ets:match_object(AccessData,{'_',error}) of
- []->
- %Case we got no error control that we can override a
- %at least some of the values
- case ets:match_object(AccessData,
- {allow_over_ride,none}) of
- []->
- overRide;
- _NoOverride->
- noOverRide
- end;
- _ ->
- error
- end;
- Line ->
- loadAccessFileData({stream,File},AccessData,
- insertLine(string:strip(Line,left),FileData))
- end.
-
-%----------------------------------------------------------------------
-%AccessData is a ets table where the previous found data is inserted
-%FileData is a list of the directives in the last parsed file
-%before insertion a control is done that the directive is allowed to
-%override
-%----------------------------------------------------------------------
-insertData(AccessData,{{context,Values},FileData})->
- insertData(AccessData,[{context,Values}|FileData]);
-
-insertData(AccessData,FileData)->
- case ets:lookup(AccessData,allow_over_ride) of
- [{allow_over_ride,all}]->
- lists:foreach(fun(Elem)->
- ets:insert(AccessData,Elem)
- end,FileData);
- []->
- lists:foreach(fun(Elem)->
- ets:insert(AccessData,Elem)
- end,FileData);
- [{allow_over_ride,Directives}] when is_list(Directives)->
- lists:foreach(fun({Key,Value}) ->
- case lists:member(Key,Directives) of
- true->
- ok;
- false ->
- ets:insert(AccessData,{Key,Value})
- end
- end,FileData);
- [{allow_over_ride,_}]->
- %Will never appear if the user
- %aint doing very strang econfig files
- ok
- end.
-%----------------------------------------------------------------------
-%Take a line in the accessfile and transform it into a tuple that
-%later can be inserted in to the ets:table
-%----------------------------------------------------------------------
-%%%Here is the alternatives that resides inside the limit context
-
-insertLine("order"++ Order, {{context, Values}, FileData})->
- {{context,[{order,getOrder(Order)}|Values]},FileData};
-%%Let the user place a tab in the beginning
-insertLine([$\t,$o,$r,$d,$e,$r|Order],{{context,Values},FileData})->
- {{context,[{order,getOrder(Order)}|Values]},FileData};
-
-insertLine("allow" ++ Allow, {{context, Values}, FileData})->
- {{context,[{allow,getAllowDenyData(Allow)}|Values]},FileData};
-insertLine([$\t,$a,$l,$l,$o,$w|Allow],{{context,Values},FileData})->
- {{context,[{allow,getAllowDenyData(Allow)}|Values]},FileData};
-
-insertLine("deny" ++ Deny, {{context,Values}, FileData})->
- {{context,[{deny,getAllowDenyData(Deny)}|Values]},FileData};
-insertLine([$\t, $d,$e,$n,$y|Deny],{{context,Values},FileData})->
- {{context,[{deny,getAllowDenyData(Deny)}|Values]},FileData};
-
-insertLine("require" ++ Require, {{context, Values}, FileData})->
- {{context,[{require,getRequireData(Require)}|Values]},FileData};
-insertLine([$\t,$r,$e,$q,$u,$i,$r,$e|Require],{{context,Values},FileData})->
- {{context,[{require,getRequireData(Require)}|Values]},FileData};
-
-insertLine("</Limit" ++ _EndLimit, {Context,FileData})->
- [Context | FileData];
-insertLine("<Limit" ++ Limit, FileData)->
- {{context,[{limit,getLimits(Limit)}]}, FileData};
-
-insertLine([$A,$u,$t,$h,$U,$s,$e,$r,$F,$i,$l,$e,$\ |AuthUserFile],FileData)->
- [{user_file,string:strip(AuthUserFile,right,$\n)}|FileData];
-
-insertLine([$A,$u,$t,$h,$G,$r,$o,$u,$p,$F,$i,$l,$e,$\ |AuthGroupFile],
- FileData)->
- [{group_file,string:strip(AuthGroupFile,right,$\n)}|FileData];
-
-insertLine("AllowOverRide" ++ AllowOverRide, FileData)->
- [{allow_over_ride,getAllowOverRideData(AllowOverRide)}
- | FileData];
-
-insertLine([$A,$u,$t,$h,$N,$a,$m,$e,$\ |AuthName],FileData)->
- [{auth_name,string:strip(AuthName,right,$\n)}|FileData];
-
-insertLine("AuthType" ++ AuthType,FileData)->
- [{auth_type,getAuthorizationType(AuthType)}|FileData];
-
-insertLine(_BadDirectiveOrComment,FileData)->
- FileData.
-
-%----------------------------------------------------------------------
-%transform the Data specified about override to a form that is ieasier
-%handled later
-%Override data="all"|"md5"|"Directive1 .... DirectioveN"
-%----------------------------------------------------------------------
-
-getAllowOverRideData(OverRideData)->
- case string:tokens(OverRideData," \r\n") of
- ["all" ++ _] ->
- all;
- ["none" ++ _]->
- none;
- Directives ->
- getOverRideDirectives(Directives)
- end.
-
-getOverRideDirectives(Directives)->
- lists:map(fun(Directive)->
- transformDirective(Directive)
- end,Directives).
-transformDirective("AuthUserFile" ++ _)->
- user_file;
-transformDirective("AuthGroupFile" ++ _) ->
- group_file;
-transformDirective("AuthName" ++ _)->
- auth_name;
-transformDirective("AuthType" ++ _)->
- auth_type;
-transformDirective(_UnAllowedOverRideDirective) ->
- unallowed.
-%----------------------------------------------------------------------
-%Replace the string that specify which method to use for authentication
-%and replace it with the atom for easier mathing
-%----------------------------------------------------------------------
-getAuthorizationType(AuthType)->
- [Arg | _Crap] = string:tokens(AuthType,"\n\r\ "),
- case Arg of
- "Basic"->
- basic;
- "MD5" ->
- md5;
- _What ->
- error
- end.
-%----------------------------------------------------------------------
-%Returns a list of the specified methods to limit or the atom all
-%----------------------------------------------------------------------
-getLimits(Limits)->
- case re:split(Limits,">", [{return, list}])of
- [_NoEndOnLimit]->
- error;
- [Methods | _Crap]->
- case re:split(Methods," ", [{return, list}]) of
- [[]]->
- all;
- SplittedMethods ->
- SplittedMethods
- end
- end.
-
-
-%----------------------------------------------------------------------
-% Transform the order to prefrom deny allow control to a tuple of atoms
-%----------------------------------------------------------------------
-getOrder(Order)->
- [First | _Rest]=lists:map(fun(Part)->
- list_to_atom(Part)
- end,string:tokens(Order," \n\r")),
- case First of
- deny->
- {deny,allow};
- allow->
- {allow,deny};
- _Error->
- error
- end.
-
-%----------------------------------------------------------------------
-% The string AllowDeny is "from all" or "from Subnet1 Subnet2...SubnetN"
-%----------------------------------------------------------------------
-getAllowDenyData(AllowDeny)->
- case string:tokens(AllowDeny," \n\r") of
- [_From|AllowDenyData] when length(AllowDenyData)>=1 ->
- case lists:nth(1,AllowDenyData) of
- "all" ->
- all;
- _Hosts->
- AllowDenyData
- end;
- _ ->
- error
- end.
-%----------------------------------------------------------------------
-% Fix the string that describes who is allowed to se the page
-%----------------------------------------------------------------------
-getRequireData(Require)->
- [UserOrGroup|UserData]=string:tokens(Require," \n\r"),
- case UserOrGroup of
- "user"->
- {users,UserData};
- "group" ->
- {groups,UserData};
- _Whatever ->
- error
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% Methods that collects the searchways to the accessfiles %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%----------------------------------------------------------------------
-% Get the whole path to the different accessfiles
-%----------------------------------------------------------------------
-getHtAccessFiles(HtAccessFileNames,Path,RestOfSplittedPath)->
- getHtAccessFiles(HtAccessFileNames,Path,RestOfSplittedPath,[]).
-
-getHtAccessFiles(HtAccessFileNames,Path,[[]],HtAccessFiles)->
- HtAccessFiles ++ accessFilesOfPath(HtAccessFileNames,Path++"/");
-
-getHtAccessFiles(_HtAccessFileNames, _Path, [], HtAccessFiles)->
- HtAccessFiles;
-getHtAccessFiles(HtAccessFileNames,Path,[NextDir|RestOfSplittedPath],
- AccessFiles)->
- getHtAccessFiles(HtAccessFileNames,Path++"/"++NextDir,RestOfSplittedPath,
- AccessFiles ++
- accessFilesOfPath(HtAccessFileNames,Path++"/")).
-
-
-%----------------------------------------------------------------------
-%Control if therer are any accessfies in the path
-%----------------------------------------------------------------------
-accessFilesOfPath(HtAccessFileNames,Path)->
- lists:foldl(fun(HtAccessFileName,Files)->
- case file:read_file_info(Path++HtAccessFileName) of
- {ok, _}->
- [Path++HtAccessFileName|Files];
- {error,_Error} ->
- Files
- end
- end,[],HtAccessFileNames).
-
-
-%----------------------------------------------------------------------
-%Sake the splitted path and joins it up to the documentroot or the alias
-%that match first
-%----------------------------------------------------------------------
-
-getRootPath(SplittedPath, Info)->
- DocRoot=httpd_util:lookup(Info#mod.config_db,document_root,"/"),
- PresumtiveRootPath=
- [DocRoot|lists:map(fun({_Alias,RealPath})->
- RealPath
- end,
- httpd_util:multi_lookup(Info#mod.config_db,alias))],
- getRootPath(PresumtiveRootPath,SplittedPath,Info).
-
-
-getRootPath(PresumtiveRootPath,[[],Splittedpath],Info)->
- getRootPath(PresumtiveRootPath,["/",Splittedpath],Info);
-
-
-getRootPath(PresumtiveRootPath,[Part,NextPart|SplittedPath],Info)->
- case lists:member(Part,PresumtiveRootPath)of
- true->
- {ok,Part,[NextPart|SplittedPath]};
- false ->
- getRootPath(PresumtiveRootPath,
- [Part++"/"++NextPart|SplittedPath],Info)
- end;
-
-getRootPath(PresumtiveRootPath, [Part], _Info)->
- case lists:member(Part,PresumtiveRootPath)of
- true->
- {ok,Part,[]};
- false ->
- {error,Part}
- end.
diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src
index 5523d08c90..e5310fd80e 100644
--- a/lib/inets/src/inets_app/inets.app.src
+++ b/lib/inets/src/inets_app/inets.app.src
@@ -89,7 +89,6 @@
mod_esi,
mod_get,
mod_head,
- mod_htaccess,
mod_log,
mod_range,
mod_responsecontrol,
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index 1289432f0d..8622ee3eb4 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -68,8 +68,6 @@ all() ->
{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},
{group, http_reload},
@@ -104,8 +102,6 @@ groups() ->
{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}]},
{http_logging, [], [{group, logging}]},
@@ -136,7 +132,6 @@ groups() ->
]},
{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
{logging, [], [disk_log_internal, disk_log_exists,
disk_log_bad_size, disk_log_bad_file]},
@@ -262,24 +257,6 @@ init_per_group(http_0_9, Config) ->
_ ->
[{http_version, "HTTP/0.9"} | Config]
end;
-init_per_group(http_htaccess = Group, Config) ->
- Path = proplists:get_value(doc_root, Config),
- catch remove_htaccess(Path),
- create_htaccess_data(Path, proplists:get_value(address, Config)),
- ok = start_apps(Group),
- init_httpd(Group, [{type, ip_comm} | Config]);
-init_per_group(https_htaccess = Group, Config) ->
- Path = proplists:get_value(doc_root, Config),
- catch remove_htaccess(Path),
- create_htaccess_data(Path, proplists:get_value(address, Config)),
- catch crypto:stop(),
- try crypto:start() of
- ok ->
- init_ssl(Group, Config)
- catch
- _:_ ->
- {skip, "Crypto did not start"}
- end;
init_per_group(auth_api, Config) ->
[{auth_prefix, ""} | Config];
init_per_group(auth_api_dets, Config) ->
@@ -306,7 +283,6 @@ end_per_group(Group, _Config) when Group == http_basic;
Group == http_auth_api;
Group == http_auth_api_dets;
Group == http_auth_api_mnesia;
- Group == http_htaccess;
Group == http_security;
Group == http_reload;
Group == http_post;
@@ -319,7 +295,6 @@ end_per_group(Group, _Config) when Group == https_basic;
Group == https_auth_api;
Group == https_auth_api_dets;
Group == https_auth_api_mnesia;
- Group == https_htaccess;
Group == https_security;
Group == https_reload
->
@@ -453,7 +428,8 @@ head(Config) when is_list(Config) ->
Version = proplists:get_value(http_version, Config),
Host = proplists:get_value(host, Config),
ok = httpd_test_lib:verify_request(proplists:get_value(type, Config), Host,
- proplists:get_value(port, Config), proplists:get_value(node, Config),
+ proplists:get_value(port, Config),
+ proplists:get_value(node, Config),
http_request("HEAD /index.html ", Version, Host),
[{statuscode, head_status(Version)},
{version, Version}]).
@@ -808,130 +784,6 @@ post_204(Config) ->
end.
%%-------------------------------------------------------------------------
-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 = proplists:get_value(http_version, Config),
- Host = proplists:get_value(host, Config),
- Type = proplists:get_value(type, Config),
- Port = proplists:get_value(port, Config),
- Node = proplists:get_value(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"}].
@@ -2081,7 +1933,6 @@ start_apps(Group) when Group == https_basic;
Group == https_auth_api;
Group == https_auth_api_dets;
Group == https_auth_api_mnesia;
- Group == https_htaccess;
Group == https_security;
Group == https_reload;
Group == https_not_sup;
@@ -2095,7 +1946,6 @@ start_apps(Group) when Group == http_basic;
Group == http_auth_api;
Group == http_auth_api_dets;
Group == http_auth_api_mnesia;
- Group == http_htaccess;
Group == http_security;
Group == http_logging;
Group == http_reload;
@@ -2185,10 +2035,6 @@ server_config(http_auth_api_mnesia, Config) ->
server_config(https_auth_api_mnesia, Config) ->
ServerRoot = proplists:get_value(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 = proplists:get_value(server_root, Config),
tl(auth_conf(ServerRoot)) ++ security_conf(ServerRoot) ++ server_config(http, Config);
@@ -2309,8 +2155,7 @@ not_sup_conf() ->
[{modules, [mod_get]}].
auth_access_conf() ->
- [{modules, [mod_alias, mod_htaccess, mod_dir, mod_get, mod_head]},
- {access_files, [".htaccess"]}].
+ [{modules, [mod_alias, mod_dir, mod_get, mod_head]}].
auth_conf(Root) ->
[{modules, [mod_alias, mod_auth, mod_dir, mod_get, mod_head]},
@@ -2541,103 +2386,6 @@ 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")),
diff --git a/lib/inets/test/httpd_mod_SUITE.erl b/lib/inets/test/httpd_mod_SUITE.erl
index 5ec4e0856d..ebef7eea6c 100644
--- a/lib/inets/test/httpd_mod_SUITE.erl
+++ b/lib/inets/test/httpd_mod_SUITE.erl
@@ -53,7 +53,6 @@ groups() ->
{mod_actions, [], []},
{mod_security, [], []},
{mod_auth, [], []},
- {mod_htaccess, [], []},
{mod_cgi, [], []},
{mod_esi, [], []},
{mod_head, [], []},
@@ -66,7 +65,6 @@ all_version_groups ()->
{group, mod_actions},
{group, mod_security},
{group, mod_auth},
- {group, mod_htaccess},
{group, mod_cgi},
{group, mod_esi},
{group, mod_head}