📄 mod_htaccess.erl
字号:
%% ``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%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%%%% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%-module(mod_htaccess).-export([do/1, load/2]).-include("httpd.hrl").%% We will not make the change to use base64 in stdlib in inets just yet.%% it will be included in the next major release of inets. -compile({nowarn_deprecated_function, {http_base_64, encode, 1}}).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 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=httpd_conf:clean(FileNames), {ok,[],{access_files,string:tokens(CleanFileNames," ")}}.%----------------------------------------------------------------------% Public method that the webbserver calls to control the page %----------------------------------------------------------------------do(Info)-> case httpd_util:key1search(Info#mod.data,status) 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 regexp:match(UserNetwork, formatRegexp(Net)) of {match,1,_}-> 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -