diff options
Diffstat (limited to 'src/ejabberd_oauth_rest.erl')
-rw-r--r-- | src/ejabberd_oauth_rest.erl | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/src/ejabberd_oauth_rest.erl b/src/ejabberd_oauth_rest.erl new file mode 100644 index 000000000..6af67996b --- /dev/null +++ b/src/ejabberd_oauth_rest.erl @@ -0,0 +1,149 @@ +%%%------------------------------------------------------------------- +%%% File : ejabberd_oauth_rest.erl +%%% Author : Alexey Shchepin <alexey@process-one.net> +%%% Purpose : OAUTH2 REST backend +%%% Created : 26 Jul 2016 by Alexey Shchepin <alexey@process-one.net> +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2019 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License +%%% along with this program; if not, write to the Free Software +%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%------------------------------------------------------------------- + +-module(ejabberd_oauth_rest). +-behaviour(ejabberd_oauth). + +-export([init/0, + store/1, + lookup/1, + clean/1, + lookup_client/1, + store_client/1]). + +-include("ejabberd_oauth.hrl"). +-include("logger.hrl"). +-include("jid.hrl"). + +init() -> + rest:start(ejabberd_config:get_myname()), + ok. + +store(R) -> + Path = path(<<"store">>), + %% Retry 2 times, with a backoff of 500millisec + {User, Server} = R#oauth_token.us, + SJID = jid:encode({User, Server, <<"">>}), + case rest:with_retry( + post, + [ejabberd_config:get_myname(), Path, [], + {[{<<"token">>, R#oauth_token.token}, + {<<"user">>, SJID}, + {<<"scope">>, R#oauth_token.scope}, + {<<"expire">>, R#oauth_token.expire} + ]}], 2, 500) of + {ok, Code, _} when Code == 200 orelse Code == 201 -> + ok; + Err -> + ?ERROR_MSG("Failed to store oauth record ~p: ~p", [R, Err]), + {error, db_failure} + end. + +lookup(Token) -> + Path = path(<<"lookup">>), + case rest:with_retry(post, [ejabberd_config:get_myname(), Path, [], + {[{<<"token">>, Token}]}], + 2, 500) of + {ok, 200, {Data}} -> + SJID = proplists:get_value(<<"user">>, Data, <<>>), + JID = jid:decode(SJID), + US = {JID#jid.luser, JID#jid.lserver}, + Scope = proplists:get_value(<<"scope">>, Data, []), + Expire = proplists:get_value(<<"expire">>, Data, 0), + {ok, #oauth_token{token = Token, + us = US, + scope = Scope, + expire = Expire}}; + {ok, 404, _Resp} -> + error; + Other -> + ?ERROR_MSG("Unexpected response for oauth lookup: ~p", [Other]), + error + end. + +clean(_TS) -> + ok. + +path(Path) -> + Base = ejabberd_option:ext_api_path_oauth(), + <<Base/binary, "/", Path/binary>>. + +store_client(#oauth_client{client_id = ClientID, + client_name = ClientName, + grant_type = GrantType, + options = Options} = R) -> + Path = path(<<"store_client">>), + SGrantType = + case GrantType of + password -> <<"password">>; + implicit -> <<"implicit">> + end, + SOptions = misc:term_to_base64(Options), + %% Retry 2 times, with a backoff of 500millisec + case rest:with_retry( + post, + [ejabberd_config:get_myname(), Path, [], + {[{<<"client_id">>, ClientID}, + {<<"client_name">>, ClientName}, + {<<"grant_type">>, SGrantType}, + {<<"options">>, SOptions} + ]}], 2, 500) of + {ok, Code, _} when Code == 200 orelse Code == 201 -> + ok; + Err -> + ?ERROR_MSG("Failed to store oauth record ~p: ~p", [R, Err]), + {error, db_failure} + end. + +lookup_client(ClientID) -> + Path = path(<<"lookup_client">>), + case rest:with_retry(post, [ejabberd_config:get_myname(), Path, [], + {[{<<"client_id">>, ClientID}]}], + 2, 500) of + {ok, 200, {Data}} -> + ClientName = proplists:get_value(<<"client_name">>, Data, <<>>), + SGrantType = proplists:get_value(<<"grant_type">>, Data, <<>>), + GrantType = + case SGrantType of + <<"password">> -> password; + <<"implicit">> -> implicit + end, + SOptions = proplists:get_value(<<"options">>, Data, <<>>), + case misc:base64_to_term(SOptions) of + {term, Options} -> + {ok, #oauth_client{client_id = ClientID, + client_name = ClientName, + grant_type = GrantType, + options = Options}}; + _ -> + error + end; + {ok, 404, _Resp} -> + error; + Other -> + ?ERROR_MSG("Unexpected response for oauth lookup: ~p", [Other]), + error + end. |