Skip to content

Commit

Permalink
Merge pull request #90 from tgrk/webadmin_auth
Browse files Browse the repository at this point in the history
Webadmin basic auth
  • Loading branch information
0xAX committed Apr 27, 2014
2 parents 9c4575a + 3b8e018 commit 8907129
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 31 deletions.
35 changes: 20 additions & 15 deletions src/web/web_admin.erl
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,54 @@
%%% @end
%%%-----------------------------------------------------------------------------
-module(web_admin).

-behaviour(gen_server).

-export([start_link/0]).

-export([docroot/1]).

%% gen_server callbacks
-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3]).

-record(state, {}).



%% ===================================================================
%% API functions
%% ===================================================================

start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

docroot(Append) ->
priv_dir() ++ "webadmin/" ++ Append.


%% ===================================================================
%% web admin process callbacks
%% ===================================================================

init([]) ->
% start server
ok = gen_server:cast(self(), start_serve),
% init internal state
{ok, #state{}}.

handle_call(_Request, _From, State) ->
{reply, ignored, State}.

handle_cast(start_serve, State) ->
% Get web admin config
{ok, WebAdmin} = application:get_env(ybot, web_admin),

% Get Host
{webadmin_host, Host} = lists:keyfind(webadmin_host, 1, WebAdmin),

% Get Port
{webadmin_port, Port} = lists:keyfind(webadmin_port, 1, WebAdmin),

Expand All @@ -56,11 +64,9 @@ handle_cast(start_serve, State) ->
{dir, docroot("css"), [{mimetypes, cow_mimetypes, all}]}},
{"/js/[...]", cowboy_static,
{dir, docroot("js"), [{mimetypes, cow_mimetypes, all}]}},
{"/", cowboy_static,
{file, docroot("index.html"), [{mimetypes, cow_mimetypes, all}]}},
{"/views/[...]", cowboy_static,
{dir, docroot("views"), [{mimetypes, cow_mimetypes, all}]}},
{"/admin", web_admin_req_handler, []}
{"/", web_admin_req_handler, []}
]}
]),
% start serving
Expand All @@ -70,21 +76,20 @@ handle_cast(start_serve, State) ->

handle_cast(_Msg, State) ->
{noreply, State}.

handle_info(_Info, State) ->
{noreply, State}.

terminate(_Reason, _State) ->
ok.

code_change(_OldVsn, State, _Extra) ->
{ok, State}.


%% ===================================================================
%% Internal functions
%% ===================================================================
docroot(Append) ->
priv_dir() ++ "webadmin/" ++ Append.

priv_dir() ->
case code:priv_dir(ybot) of
Expand Down
90 changes: 79 additions & 11 deletions src/web/web_admin_req_handler.erl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
-export([handle/2]).
-export([terminate/3]).


%%=============================================================================
%% Cowboy handler callback
%%=============================================================================
Expand All @@ -18,26 +19,58 @@ init(_Transport, Req, []) ->
{ok, Req, undefined}.

handle(Req, State) ->
% check body
case cowboy_req:has_body(Req) of
{ok, WebAdmin} = application:get_env(ybot, web_admin),

%% check access credentials if auth is enabled
case config_option(webadmin_auth, WebAdmin) of
true ->
% get body
case cowboy_req:body(Req) of
{ok, Body, Req2} ->
handle_request(Body, Req2, State);
_ ->
{ok, Req, State}
%% get configured credentials
AuthUser = list_to_binary(
config_option(webadmin_auth_user, WebAdmin)),
AuthPasswd = list_to_binary(
config_option(webadmin_auth_passwd, WebAdmin)),
case is_authorized(Req, AuthUser, AuthPasswd) of
{true, Req1} -> authorized(Req1, State);
{false, Req1} -> unauthorized(Req1, State)
end;
false ->
{ok, Req, State}
_ ->
authorized(Req, State)
end.

terminate(_Reason, _Req, _State) ->
ok.


%%=============================================================================
%% Internal functions
%%=============================================================================

authorized(Req, State) ->
{Path, Req1} = cowboy_req:path(Req),
case Path of
<<"/">> ->
{ok, Bin} = file:read_file(web_admin:docroot("index.html")),
{ok, Req2} = cowboy_req:reply(200,
[
{<<"content-type">>, <<"text/html">>}
], Bin, Req1),
{ok, Req2, State};
<<"/admin">> ->
%% check body
case cowboy_req:has_body(Req1) of
true ->
%% get body
case cowboy_req:body(Req1) of
{ok, Body, Req2} ->
handle_request(Body, Req2, State);
_ ->
{ok, Req1, State}
end;
false ->
{ok, Req1, State}
end
end.

handle_request(Body, Req, State) ->
% get method and params
{[{<<"method">>, Method},{<<"params">>, Params}]} = jiffy:decode(Body),
Expand Down Expand Up @@ -187,4 +220,39 @@ handle_request(Body, Req, State) ->

%% @doc Format plugins
format_plugins_helper(Plugins) ->
list_to_binary([Lang ++ " " ++ Name ++ " " ++ Path ++ "\n" || {plugin, Lang, Name, Path} <- Plugins]).
list_to_binary([Lang ++ " " ++ Name ++ " " ++ Path ++ "\n" || {plugin, Lang, Name, Path} <- Plugins]).

%% Authorization helpers
is_authorized(Req, User, Passwd) ->
{ok, Auth, Req1} = cowboy_req:parse_header(<<"authorization">>, Req),
case Auth of
{<<"basic">>, {User, Passwd}} ->
{true, Req1};
_ ->
{false, Req1}
end.

unauthorized(Req, State) ->
Req1 = cowboy_req:set_resp_header(<<"Www-Authenticate">>,
<<"Basic realm=\"Secure Area\"">>, Req),
Req2 = cowboy_req:set_resp_body(unauthorized_body(), Req1),
{ok, Req3} = cowboy_req:reply(401, Req2),
{ok, Req3, State}.

unauthorized_body() ->
<<"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"
\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dt\">
<html>
<head>
<title>Error</title>
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">
</head>
<body><h1>401 Unauthorized.</h1></body>
</html>
">>.

config_option(Key, Options) ->
case lists:keyfind(Key, 1, Options) of
{Key, Value} -> Value;
false -> false
end.
5 changes: 2 additions & 3 deletions src/web/ybot_web_admin_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).

%% @doc Start http server
%% @end
-spec start_web_admin() -> {ok, Pid :: pid()} | {error, Reason :: term()}.
Expand All @@ -43,12 +43,11 @@ init([]) ->

% http server child process
ChildSpec = [

{web_admin,
{web_admin, start_link, []},
temporary, 2000, worker, []
}
],

% init
{ok,{{simple_one_for_one, 10, 60}, ChildSpec}}.
{ok,{{simple_one_for_one, 10, 60}, ChildSpec}}.
8 changes: 6 additions & 2 deletions ybot.config.template
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,17 @@
% Ybot web interface
%
{web_admin,
[
[
% use web admin or not
{use_web_admin, true},
% Web interface host
{webadmin_host, <<"localhost">>},
% Web interface port
{webadmin_port, 8000}
{webadmin_port, 8000},
% Web interface authorization
{webadmin_auth, true},
{webadmin_auth_user, "foo"},
{webadmin_auth_passwd, "bar"}
]
},

Expand Down

0 comments on commit 8907129

Please sign in to comment.