From fd6f0f94b5b4b9e3abc7e65e8d639864c9774563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Fri, 14 Oct 2016 13:55:50 +0200 Subject: [PATCH] Convert ejabberd_xmlrpc to new api_permissions --- src/ejabberd_access_permissions.erl | 5 +- src/ejabberd_commands.erl | 2 +- src/ejabberd_xmlrpc.erl | 80 +++++++++++++++++++++-------- 3 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/ejabberd_access_permissions.erl b/src/ejabberd_access_permissions.erl index 153be0940..7ce75aa9c 100644 --- a/src/ejabberd_access_permissions.erl +++ b/src/ejabberd_access_permissions.erl @@ -129,7 +129,8 @@ init([]) -> handle_call({can_access, Cmd, CallerInfo}, _From, State) -> CallerModule = maps:get(caller_module, CallerInfo, none), Host = maps:get(caller_host, CallerInfo, global), - {State2, Defs} = get_definitions(State), + {State2, Defs0} = get_definitions(State), + Defs = maps:get(extra_permissions, CallerInfo, []) ++ Defs0, Res = lists:foldl( fun({Name, _} = Def, none) -> case matches_definition(Def, Cmd, CallerModule, Host, CallerInfo) of @@ -257,7 +258,7 @@ get_definitions(#state{definitions = Defs, fragments_generators = Gens} = State) {State#state{definitions = NDefs}, NDefs}. matches_definition({_Name, {From, Who, What}}, Cmd, Module, Host, CallerInfo) -> - case lists:member(Cmd, What) of + case What == all orelse lists:member(Cmd, What) of true -> case From == [] orelse lists:member(Module, From) of true -> diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index 173071d6f..8d74ad5a2 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -460,7 +460,7 @@ get_commands_definition(Version) -> lists:foldl(F, [], L). execute_command2(Name, Arguments, CallerInfo) -> - execute_command(Name, Arguments, CallerInfo, ?DEFAULT_VERSION). + execute_command2(Name, Arguments, CallerInfo, ?DEFAULT_VERSION). execute_command2(Name, Arguments, CallerInfo, Version) -> Command = get_command_definition(Name, Version), diff --git a/src/ejabberd_xmlrpc.erl b/src/ejabberd_xmlrpc.erl index 6680451e4..1dd88f837 100644 --- a/src/ejabberd_xmlrpc.erl +++ b/src/ejabberd_xmlrpc.erl @@ -47,7 +47,8 @@ -record(state, {access_commands = [] :: list(), auth = noauth :: noauth | {binary(), binary(), binary()}, - get_auth = true :: boolean()}). + get_auth = true :: boolean(), + ip :: inet:ip_address()}). %% Test: @@ -195,7 +196,7 @@ socket_type() -> raw. %% ----------------------------- %% HTTP interface %% ----------------------------- -process(_, #request{method = 'POST', data = Data, opts = Opts}) -> +process(_, #request{method = 'POST', data = Data, opts = Opts, ip = {IP, _}}) -> AccessCommandsOpts = gen_mod:get_opt(access_commands, Opts, fun(L) when is_list(L) -> L end, undefined), @@ -206,7 +207,7 @@ process(_, #request{method = 'POST', data = Data, opts = Opts}) -> lists:flatmap( fun({Ac, AcOpts}) -> Commands = gen_mod:get_opt( - commands, AcOpts, + commands, lists:flatten(AcOpts), fun(A) when is_atom(A) -> A; (L) when is_list(L) -> @@ -219,15 +220,15 @@ process(_, #request{method = 'POST', data = Data, opts = Opts}) -> options, AcOpts, fun(L) when is_list(L) -> L end, []), - [{Ac, Commands, CommOpts}]; + [{<<"ejabberd_xmlrpc compatibility shim">>, {[?MODULE], [{access, Ac}], Commands}}]; (Wrong) -> ?WARNING_MSG("wrong options format for ~p: ~p", [?MODULE, Wrong]), [] - end, AccessCommandsOpts) + end, lists:flatten(AccessCommandsOpts)) end, GetAuth = true, - State = #state{access_commands = AccessCommands, get_auth = GetAuth}, + State = #state{access_commands = AccessCommands, get_auth = GetAuth, ip = IP}, case fxml_stream:parse_element(Data) of {error, _} -> {400, [], @@ -258,21 +259,35 @@ process(_, _) -> %% Access verification %% ----------------------------- -get_auth(AuthList) -> - Admin = - case lists:keysearch(admin, 1, AuthList) of - {value, {admin, true}} -> true; - _ -> false - end, +extract_auth(AuthList) -> + ?DEBUG("AUTHLIST ~p", [AuthList]), try get_attrs([user, server, token], AuthList) of - [U, S, T] -> {U, S, {oauth, T}, Admin} + [U0, S0, T] -> + U = jid:nodeprep(U0), + S = jid:nameprep(S0), + case ejabberd_oauth:check_token(T) of + {ok, {U, S}, Scope} -> + #{usr => {U, S, <<"">>}, oauth_scope => Scope, caller_server => S}; + {false, Reason} -> + {error, Reason}; + _ -> + {error, not_found} + end catch exit:{attribute_not_found, _Attr, _} -> try get_attrs([user, server, password], AuthList) of - [U, S, P] -> {U, S, P, Admin} + [U0, S0, P] -> + U = jid:nodeprep(U0), + S = jid:nameprep(S0), + case ejabberd_auth:check_password(U, <<"">>, S, P) of + true -> + #{usr => {U, S, <<"">>}, caller_server => S}; + false -> + {error, invalid_auth} + end catch - exit:{attribute_not_found, Attr, _} -> - throw({error, missing_auth_arguments, Attr}) + exit:{attribute_not_found, _Attr, _} -> + #{} end end. @@ -300,12 +315,28 @@ get_auth(AuthList) -> %% xmlrpc:call({127, 0, 0, 1}, 4560, "/", {call, echothis, [{struct, [{user, "badlop"}, {server, "localhost"}, {password, "79C1574A43BC995F2B145A299EF97277"}]}, 152]}). %% {ok,{response,[152]}} -handler(#state{get_auth = true, auth = noauth} = State, +handler(#state{get_auth = true, auth = noauth, ip = IP} = State, {call, Method, [{struct, AuthList} | Arguments] = AllArgs}) -> - try get_auth(AuthList) of + try extract_auth(AuthList) of + {error, invalid_auth} -> + build_fault_response(-118, + "Invalid authentication data", + []); + {error, not_found} -> + build_fault_response(-118, + "Invalid oauth token", + []); + {error, expired} -> + build_fault_response(-118, + "Invalid oauth token", + []); + {error, Value} -> + build_fault_response(-118, + "Invalid authentication data: ~p", + [Value]); Auth -> - handler(State#state{get_auth = false, auth = Auth}, + handler(State#state{get_auth = false, auth = Auth#{ip => IP, caller_module => ?MODULE}}, {call, Method, Arguments}) catch {error, missing_auth_arguments, _Attr} -> @@ -393,9 +424,14 @@ build_fault_response(Code, ParseString, ParseArgs) -> do_command(AccessCommands, Auth, Command, AttrL, ArgsF, ResultF) -> ArgsFormatted = format_args(AttrL, ArgsF), + Auth2 = case AccessCommands of + V when is_list(V) -> + Auth#{extra_permissions => AccessCommands}; + _ -> + Auth + end, Result = - ejabberd_commands:execute_command(AccessCommands, Auth, - Command, ArgsFormatted), + ejabberd_commands:execute_command2(Command, ArgsFormatted, Auth2), ResultFormatted = format_result(Result, ResultF), {command_result, ResultFormatted}. @@ -489,6 +525,8 @@ process_unicode_codepoints(Str) -> format_result({error, Error}, _) -> throw({error, Error}); +format_result({error, _Type, _Code, Error}, _) -> + throw({error, Error}); format_result(String, string) -> lists:flatten(String); format_result(Atom, {Name, atom}) -> {struct,