Current section

Files

Jump to
erldns src admin erldns_admin_auth_middleware.erl
Raw

src/admin/erldns_admin_auth_middleware.erl

-module(erldns_admin_auth_middleware).
-moduledoc false.
-behaviour(cowboy_middleware).
-export([execute/2]).
-spec execute(Req, Env) -> {ok, Req, Env} | {stop, Req} when
Req :: cowboy_req:req(),
Env :: cowboy_middleware:env().
execute(Req0, #{credentials := {Username, Password}} = Env) ->
case is_authorized(Req0, Username, Password) of
true ->
{ok, Req0, Env};
{false, WwwAuthenticateHeader} ->
Req1 = set_www_authenticate_header(Req0, WwwAuthenticateHeader),
Req2 = maybe_delete_resp_header(Req1),
Req3 = reply_unauthorized(Req2),
{stop, Req3}
end.
-spec is_authorized(cowboy_req:req(), binary(), binary()) -> true | {false, iodata()}.
is_authorized(Req, ValidUsername, ValidPassword) ->
case cowboy_req:parse_header(~"authorization", Req) of
{basic, GivenUsername, GivenPassword} ->
is_authorized(GivenUsername, GivenPassword, ValidUsername, ValidPassword) orelse
{false, ~"basic realm=\"erldns admin\""};
_ ->
{false, ~"basic realm=\"erldns admin\""}
end.
-spec is_authorized(dynamic(), dynamic(), dynamic(), dynamic()) -> boolean().
is_authorized(GivenUsername, GivenPassword, ValidUsername, ValidPassword) ->
is_binary_of_equal_size(GivenUsername, ValidUsername) andalso
is_binary_of_equal_size(GivenPassword, ValidPassword) andalso
crypto:hash_equals(GivenUsername, ValidUsername) andalso
crypto:hash_equals(GivenPassword, ValidPassword).
-compile({inline, [is_binary_of_equal_size/2]}).
-spec is_binary_of_equal_size(dynamic(), dynamic()) -> boolean().
is_binary_of_equal_size(Bin1, Bin2) ->
is_binary(Bin1) andalso is_binary(Bin2) andalso byte_size(Bin1) =:= byte_size(Bin2).
-spec set_www_authenticate_header(cowboy_req:req(), iodata()) -> cowboy_req:req().
set_www_authenticate_header(Req, WwwAuthenticateHeader) ->
cowboy_req:set_resp_header(~"www-authenticate", WwwAuthenticateHeader, Req).
-spec maybe_delete_resp_header(cowboy_req:req()) -> cowboy_req:req().
maybe_delete_resp_header(Req) ->
case cowboy_req:has_resp_body(Req) of
true -> Req;
false -> cowboy_req:delete_resp_header(~"content-type", Req)
end.
-spec reply_unauthorized(cowboy_req:req()) -> cowboy_req:req().
reply_unauthorized(Req) ->
cowboy_req:reply(401, Req).