mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-20 16:15:59 +01:00
Add DB backend support for ejabberd_oauth
This commit is contained in:
parent
5d4f8bcf0d
commit
839490b0d9
26
include/ejabberd_oauth.hrl
Normal file
26
include/ejabberd_oauth.hrl
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%%
|
||||||
|
%%% ejabberd, Copyright (C) 2002-2016 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.,
|
||||||
|
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
%%%
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-record(oauth_token, {
|
||||||
|
token = <<"">> :: binary() | '_',
|
||||||
|
us = {<<"">>, <<"">>} :: {binary(), binary()} | '_',
|
||||||
|
scope = [] :: [binary()] | '_',
|
||||||
|
expire :: integer() | '$1'
|
||||||
|
}).
|
@ -56,6 +56,7 @@
|
|||||||
|
|
||||||
-include("ejabberd_http.hrl").
|
-include("ejabberd_http.hrl").
|
||||||
-include("ejabberd_web_admin.hrl").
|
-include("ejabberd_web_admin.hrl").
|
||||||
|
-include("ejabberd_oauth.hrl").
|
||||||
|
|
||||||
-include("ejabberd_commands.hrl").
|
-include("ejabberd_commands.hrl").
|
||||||
|
|
||||||
@ -64,17 +65,12 @@
|
|||||||
%% * Using the web form/api results in the token being generated in behalf of the user providing the user/pass
|
%% * Using the web form/api results in the token being generated in behalf of the user providing the user/pass
|
||||||
%% * Using the command line and oauth_issue_token command, the token is generated in behalf of ejabberd' sysadmin
|
%% * Using the command line and oauth_issue_token command, the token is generated in behalf of ejabberd' sysadmin
|
||||||
%% (as it has access to ejabberd command line).
|
%% (as it has access to ejabberd command line).
|
||||||
-record(oauth_token, {
|
|
||||||
token = {<<"">>, <<"">>} :: {binary(), binary()},
|
|
||||||
us = {<<"">>, <<"">>} :: {binary(), binary()},
|
|
||||||
scope = [] :: [binary()],
|
|
||||||
expire :: integer()
|
|
||||||
}).
|
|
||||||
|
|
||||||
-define(EXPIRE, 3600).
|
-define(EXPIRE, 3600).
|
||||||
|
|
||||||
start() ->
|
start() ->
|
||||||
init_db(mnesia, ?MYNAME),
|
DBMod = get_db_backend(),
|
||||||
|
DBMod:init(),
|
||||||
Expire = expire(),
|
Expire = expire(),
|
||||||
application:set_env(oauth2, backend, ejabberd_oauth),
|
application:set_env(oauth2, backend, ejabberd_oauth),
|
||||||
application:set_env(oauth2, expiry_time, Expire),
|
application:set_env(oauth2, expiry_time, Expire),
|
||||||
@ -172,15 +168,8 @@ handle_cast(_Msg, State) -> {noreply, State}.
|
|||||||
handle_info(clean, State) ->
|
handle_info(clean, State) ->
|
||||||
{MegaSecs, Secs, MiniSecs} = os:timestamp(),
|
{MegaSecs, Secs, MiniSecs} = os:timestamp(),
|
||||||
TS = 1000000 * MegaSecs + Secs,
|
TS = 1000000 * MegaSecs + Secs,
|
||||||
F = fun() ->
|
DBMod = get_db_backend(),
|
||||||
Ts = mnesia:select(
|
DBMod:clean(TS),
|
||||||
oauth_token,
|
|
||||||
[{#oauth_token{expire = '$1', _ = '_'},
|
|
||||||
[{'<', '$1', TS}],
|
|
||||||
['$_']}]),
|
|
||||||
lists:foreach(fun mnesia:delete_object/1, Ts)
|
|
||||||
end,
|
|
||||||
mnesia:async_dirty(F),
|
|
||||||
erlang:send_after(trunc(expire() * 1000 * (1 + MiniSecs / 1000000)),
|
erlang:send_after(trunc(expire() * 1000 * (1 + MiniSecs / 1000000)),
|
||||||
self(), clean),
|
self(), clean),
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
@ -191,16 +180,6 @@ terminate(_Reason, _State) -> ok.
|
|||||||
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
||||||
|
|
||||||
|
|
||||||
init_db(mnesia, _Host) ->
|
|
||||||
mnesia:create_table(oauth_token,
|
|
||||||
[{disc_copies, [node()]},
|
|
||||||
{attributes,
|
|
||||||
record_info(fields, oauth_token)}]),
|
|
||||||
mnesia:add_table_copy(oauth_token, node(), disc_copies);
|
|
||||||
init_db(_, _) ->
|
|
||||||
ok.
|
|
||||||
|
|
||||||
|
|
||||||
get_client_identity(Client, Ctx) -> {ok, {Ctx, {client, Client}}}.
|
get_client_identity(Client, Ctx) -> {ok, {Ctx, {client, Client}}}.
|
||||||
|
|
||||||
verify_redirection_uri(_, _, Ctx) -> {ok, Ctx}.
|
verify_redirection_uri(_, _, Ctx) -> {ok, Ctx}.
|
||||||
@ -305,7 +284,8 @@ associate_access_token(AccessToken, Context, AppContext) ->
|
|||||||
scope = Scope,
|
scope = Scope,
|
||||||
expire = Expire
|
expire = Expire
|
||||||
},
|
},
|
||||||
mnesia:dirty_write(R),
|
DBMod = get_db_backend(),
|
||||||
|
DBMod:store(R),
|
||||||
{ok, AppContext}.
|
{ok, AppContext}.
|
||||||
|
|
||||||
associate_refresh_token(_RefreshToken, _Context, AppContext) ->
|
associate_refresh_token(_RefreshToken, _Context, AppContext) ->
|
||||||
@ -315,10 +295,11 @@ associate_refresh_token(_RefreshToken, _Context, AppContext) ->
|
|||||||
check_token(User, Server, ScopeList, Token) ->
|
check_token(User, Server, ScopeList, Token) ->
|
||||||
LUser = jid:nodeprep(User),
|
LUser = jid:nodeprep(User),
|
||||||
LServer = jid:nameprep(Server),
|
LServer = jid:nameprep(Server),
|
||||||
case catch mnesia:dirty_read(oauth_token, Token) of
|
DBMod = get_db_backend(),
|
||||||
[#oauth_token{us = {LUser, LServer},
|
case DBMod:lookup(Token) of
|
||||||
|
#oauth_token{us = {LUser, LServer},
|
||||||
scope = TokenScope,
|
scope = TokenScope,
|
||||||
expire = Expire}] ->
|
expire = Expire} ->
|
||||||
{MegaSecs, Secs, _} = os:timestamp(),
|
{MegaSecs, Secs, _} = os:timestamp(),
|
||||||
TS = 1000000 * MegaSecs + Secs,
|
TS = 1000000 * MegaSecs + Secs,
|
||||||
TokenScopeSet = oauth2_priv_set:new(TokenScope),
|
TokenScopeSet = oauth2_priv_set:new(TokenScope),
|
||||||
@ -330,10 +311,11 @@ check_token(User, Server, ScopeList, Token) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
check_token(ScopeList, Token) ->
|
check_token(ScopeList, Token) ->
|
||||||
case catch mnesia:dirty_read(oauth_token, Token) of
|
DBMod = get_db_backend(),
|
||||||
[#oauth_token{us = US,
|
case DBMod:lookup(Token) of
|
||||||
|
#oauth_token{us = US,
|
||||||
scope = TokenScope,
|
scope = TokenScope,
|
||||||
expire = Expire}] ->
|
expire = Expire} ->
|
||||||
{MegaSecs, Secs, _} = os:timestamp(),
|
{MegaSecs, Secs, _} = os:timestamp(),
|
||||||
TS = 1000000 * MegaSecs + Secs,
|
TS = 1000000 * MegaSecs + Secs,
|
||||||
TokenScopeSet = oauth2_priv_set:new(TokenScope),
|
TokenScopeSet = oauth2_priv_set:new(TokenScope),
|
||||||
@ -548,6 +530,15 @@ process(_Handlers,
|
|||||||
process(_Handlers, _Request) ->
|
process(_Handlers, _Request) ->
|
||||||
ejabberd_web:error(not_found).
|
ejabberd_web:error(not_found).
|
||||||
|
|
||||||
|
-spec get_db_backend() -> module().
|
||||||
|
|
||||||
|
get_db_backend() ->
|
||||||
|
DBType = ejabberd_config:get_option(
|
||||||
|
oauth_db_type,
|
||||||
|
fun(T) -> ejabberd_config:v_db(?MODULE, T) end,
|
||||||
|
mnesia),
|
||||||
|
list_to_atom("ejabberd_oauth_" ++ atom_to_list(DBType)).
|
||||||
|
|
||||||
|
|
||||||
%% Headers as per RFC 6749
|
%% Headers as per RFC 6749
|
||||||
json_response(Code, Body) ->
|
json_response(Code, Body) ->
|
||||||
@ -688,4 +679,6 @@ opt_type(oauth_expire) ->
|
|||||||
fun(I) when is_integer(I), I >= 0 -> I end;
|
fun(I) when is_integer(I), I >= 0 -> I end;
|
||||||
opt_type(oauth_access) ->
|
opt_type(oauth_access) ->
|
||||||
fun acl:access_rules_validator/1;
|
fun acl:access_rules_validator/1;
|
||||||
opt_type(_) -> [oauth_expire, oauth_access].
|
opt_type(oauth_db_type) ->
|
||||||
|
fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
||||||
|
opt_type(_) -> [oauth_expire, oauth_access, oauth_db_type].
|
||||||
|
65
src/ejabberd_oauth_mnesia.erl
Normal file
65
src/ejabberd_oauth_mnesia.erl
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% File : ejabberd_oauth_mnesia.erl
|
||||||
|
%%% Author : Alexey Shchepin <alexey@process-one.net>
|
||||||
|
%%% Purpose : OAUTH2 mnesia backend
|
||||||
|
%%% Created : 20 Jul 2016 by Alexey Shchepin <alexey@process-one.net>
|
||||||
|
%%%
|
||||||
|
%%%
|
||||||
|
%%% ejabberd, Copyright (C) 2002-2016 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_mnesia).
|
||||||
|
|
||||||
|
-export([init/0,
|
||||||
|
store/1,
|
||||||
|
lookup/1,
|
||||||
|
clean/1]).
|
||||||
|
|
||||||
|
-include("ejabberd_oauth.hrl").
|
||||||
|
|
||||||
|
init() ->
|
||||||
|
mnesia:create_table(oauth_token,
|
||||||
|
[{disc_copies, [node()]},
|
||||||
|
{attributes,
|
||||||
|
record_info(fields, oauth_token)}]),
|
||||||
|
mnesia:add_table_copy(oauth_token, node(), disc_copies),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
store(R) ->
|
||||||
|
mnesia:dirty_write(R).
|
||||||
|
|
||||||
|
lookup(Token) ->
|
||||||
|
case catch mnesia:dirty_read(oauth_token, Token) of
|
||||||
|
[R] ->
|
||||||
|
R;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end.
|
||||||
|
|
||||||
|
clean(TS) ->
|
||||||
|
F = fun() ->
|
||||||
|
Ts = mnesia:select(
|
||||||
|
oauth_token,
|
||||||
|
[{#oauth_token{expire = '$1', _ = '_'},
|
||||||
|
[{'<', '$1', TS}],
|
||||||
|
['$_']}]),
|
||||||
|
lists:foreach(fun mnesia:delete_object/1, Ts)
|
||||||
|
end,
|
||||||
|
mnesia:async_dirty(F).
|
||||||
|
|
Loading…
Reference in New Issue
Block a user