Commits

Fred T-H committed 432b2a5

**UNSTABLE** Adding authentication to the server

This branch is unstable and shouldn't be used as of this commit.
Basic *UNTESTED* authentication has been added to the web server.
The client.js file will need updating and whatnot.
Sorry for the lousy commit message, I've got two weeks off and I'm leaving
this right now in case I want to work on it more somewhere else.
Irresponsible, I know. I'm the only dev working on this though. Sorry,
again.

  • Participants
  • Parent commits d28074a
  • Branches add-auth

Comments (0)

Files changed (2)

src/chut_auth.erl

 -export([authentify/3, can_contact/3]).
 -include_lib("eunit/include/eunit.hrl").
 
--define(AUTH_PATH, "auth").
--define(CONTACT_PATH, "can-contact").
 -define(CT_POST, {"Content-Type","application/x-www-form-urlencoded"}).
 
 %%--------------------------------------------------------------------
 %% pas the said token to Chut. This function allows Chut to contact
 %% the base site to close the loop and make sure the token is valid.
 %%--------------------------------------------------------------------
-authentify(BaseUrl, User, Token) ->
+authentify(Url, User, Token) ->
     Body = postify([{"user",User},{"token",Token}]),
-    Url = BaseUrl++?AUTH_PATH,
     {ok, "200", _Header, Reply} = ibrowse:send_req(Url, [?CT_POST], post, Body),
     if Reply =:= "true" -> true;
        Reply =:= "false"  -> false
 %% than forcing them to be reimplemented here (with data duplication
 %% and synchronisation being necessary.)
 %%--------------------------------------------------------------------
-can_contact(BaseUrl, UserA, UserB) ->
+can_contact(Url, UserA, UserB) ->
     Body = postify([{"from",UserA}, {"to",UserB}]),
-    Url = BaseUrl ++ ?CONTACT_PATH,
     {ok, "200", _Header, Reply} = ibrowse:send_req(Url, [?CT_POST], post, Body),
     if Reply =:= "true"  -> true;
        Reply =:= "false" -> false

src/chut_webserver.erl

 -module(chut_webserver).
 -behaviour(gen_server).
 -define(SERVER, ?MODULE).
-
+%% TODO: replace error returns par throws.
 %% API
--export([start_link/1, dispatch_requests/1, stop/0]).
+-export([start_link/1, dispatch_requests/2, stop/0]).
 %% gen_server callbacks
 -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
          terminate/2, code_change/3]).
 
 init([Port]) ->
     process_flag(trap_exit, true),
+    %% load conf
+    {ok, Conf} = file:consult("conf/auth.cfg"),
     io:format("~p (~p) starting on port ~p...~n", [?MODULE, self(), Port]),
     mochiweb_http:start([{port, Port},
-                         {loop, fun(Req) -> dispatch_requests(Req) end}]),
+                         {loop, fun(Req) -> dispatch_requests(Req, Conf) end}]),
     {ok, []}.
 
 stop() ->
     gen_server:cast(?SERVER, stop).
 
-dispatch_requests(Req) ->
+dispatch_requests(Req, Conf) ->
     Path = Req:get(path),
-    handle(Path, Req).
+    try 
+        handle(Path, Req, Conf)
+    catch
+        throw:{params, Names} -> 
+            Req:respond({400,
+                        [],
+                        ["Some parameters are undefined:",
+                        string:join(Names, ", ")]});
+        throw:authentify ->
+            Req:respond({403, [], "Wrong Token"});
+        throw:can_contact ->
+            Req:respond({403, [], "Can not contact user"})
+    end.
 
 handle_call(_Request, _From, State) ->
     Reply = ok,
     {ok, State}.
 
 %% Internal functions
-handle("/message", Req) ->
+handle("/message", Req, Conf) ->
     io:format("message call~n"),
     Params = Req:parse_qs(),
     From = proplists:get_value("from", Params),
     To = proplists:get_value("to", Params),
     Message = proplists:get_value("msg", Params),
-    ok = check_params(Req, [From, To, Message], ["from", "to", "msg"]),
+    Token = proplists:get_value("token", Params),
+    check_params([From, To, Message, Token], ["from", "to", "msg", "token"]),
+    permissions(From, To, Token, Conf),
     {ok, H} = chut_client:connect(From),
     chut_client:message(From, To, Message),
     chut_client:disconnect(From, H),
     lib:flush_receive(),
     reply(Req, mochijson2:encode(ok), Params);
 
-handle("/listen", Req) ->
+handle("/listen", Req, Conf) ->
     io:format("listen call~n"),
     Params = Req:parse_qs(),
     Nick = proplists:get_value("id", Params),
-    ok = check_params(Req, [Nick], ["id"]),
+    Token = proplists:get_value("token", Params),
+    check_params([Nick, Token], ["id", "token"]),
+    permissions(Nick, Token, Conf),
     {ok,Handler} = chut_client:connect(Nick),
     Msgs = chut_client:listen(Nick,Handler),
     JSON = mochijson2:encode([json_prepare(M) || M <- Msgs]),
     chut_client:disconnect(Nick, Handler),
     reply(Req, JSON, Params);
 
-handle("/history", Req) ->
+handle("/history", Req, Conf) ->
     io:format("history call~n"),
     Params = Req:parse_qs(),
     Nick = proplists:get_value("id",Params),
-    ok = check_params(Req, [Nick], ["id"]),
+    Token = proplists:get_value("token", Params),
+    check_params([Nick, Token], ["id", "token"]),
+    permissions(Nick, Token, Conf),
     {ok, Handler} = chut_client:connect(Nick),
     Msgs = chut_client:history(Nick),
     JSON = mochijson2:encode([json_prepare(M) || M <- Msgs]),
     reply(Req, JSON, Params);
 
 %% Test functions for auth and permissions
-handle("/auth", Req) ->
+handle("/auth", Req, _) ->
     io:format("auth call~n"),
     Params = Req:parse_post(),
     io:format("Params: ~p~n",[Params]),
     Req:respond({200, [{"Content-Type", "text/plain"}], "true"});
-handle("/can-contact", Req) ->
+handle("/can-contact", Req, _) ->
     io:format("auth call~n"),
     Params = Req:parse_post(),
     io:format("Params: ~p~n",[Params]),
     Req:respond({200, [{"Content-Type", "text/plain"}], "true"});
 
-handle(Path, Req) ->
+handle(Path, Req, _) ->
     io:format("Unexpected ~p call~n", [Path]),
     Params = Req:parse_qs(),
     reply(Req, mochijson2:encode([error,list_to_binary(Path)]), Params).
        Callback =:= undefined ->
         Req:respond({400, [], "Callback undefined"})
     end.
+
             
 %% replies with an error whenever some parameters are undefined      
-check_params(Req, Params, Names) ->
+check_params(Params, Names) ->
     case lists:any(fun(X) -> X =:= undefined end, Params) of
-        true -> Req:respond({400,
-                             [],
-                             ["Some parameters are undefined:",
-                              string:join(Names, ", ")]});
+        true  -> throw({params, Names});
         false -> ok
     end.
+
+permissions(From, Token, Conf) ->
+    {base, Url} = lists:keyfind(base, 1, Conf),
+    {auth, Auth} = lists:keyfind(auth, 1, Conf),
+    case chut_auth:authentify(Url++Auth, From, Token) of
+        true -> ok;
+        false -> throw(authentify)
+    end.
+    
+permissions(From, To, Token, Conf) ->
+    permissions(From, Token, Conf),
+    {base, Url} = lists:keyfind(base, 1, Conf),
+    {can_contact, Can} = lists:keyfind(can_contact, 1, Conf), 
+    case chut_auth:can_contact(Url++Can, From, To) of
+        true -> ok;
+        false -> throw(can_contact)
+    end.