mirror of
https://github.com/processone/ejabberd.git
synced 2024-09-23 14:14:56 +02:00
Let user choose the desired oauth token TTL
This commit is contained in:
parent
490a758050
commit
1d317e8068
@ -39,7 +39,6 @@
|
|||||||
authenticate_user/2,
|
authenticate_user/2,
|
||||||
authenticate_client/2,
|
authenticate_client/2,
|
||||||
verify_resowner_scope/3,
|
verify_resowner_scope/3,
|
||||||
verify_client_scope/3,
|
|
||||||
associate_access_code/3,
|
associate_access_code/3,
|
||||||
associate_access_token/3,
|
associate_access_token/3,
|
||||||
associate_refresh_token/3,
|
associate_refresh_token/3,
|
||||||
@ -48,7 +47,7 @@
|
|||||||
process/2,
|
process/2,
|
||||||
opt_type/1]).
|
opt_type/1]).
|
||||||
|
|
||||||
-export([oauth_issue_token/2, oauth_list_tokens/0, oauth_revoke_token/1, oauth_list_scopes/0]).
|
-export([oauth_issue_token/3, oauth_list_tokens/0, oauth_revoke_token/1, oauth_list_scopes/0]).
|
||||||
|
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
@ -92,7 +91,7 @@ get_commands_spec() ->
|
|||||||
#ejabberd_commands{name = oauth_issue_token, tags = [oauth],
|
#ejabberd_commands{name = oauth_issue_token, tags = [oauth],
|
||||||
desc = "Issue an oauth token for the given jid",
|
desc = "Issue an oauth token for the given jid",
|
||||||
module = ?MODULE, function = oauth_issue_token,
|
module = ?MODULE, function = oauth_issue_token,
|
||||||
args = [{jid, string},{scopes, string}],
|
args = [{jid, string},{ttl, integer}, {scopes, string}],
|
||||||
policy = restricted,
|
policy = restricted,
|
||||||
args_example = ["user@server.com", "connected_users_number;muc_online_rooms"],
|
args_example = ["user@server.com", "connected_users_number;muc_online_rooms"],
|
||||||
args_desc = ["List of scopes to allow, separated by ';'"],
|
args_desc = ["List of scopes to allow, separated by ';'"],
|
||||||
@ -122,17 +121,16 @@ get_commands_spec() ->
|
|||||||
}
|
}
|
||||||
].
|
].
|
||||||
|
|
||||||
oauth_issue_token(Jid, ScopesString) ->
|
oauth_issue_token(Jid, TTLSeconds, ScopesString) ->
|
||||||
Scopes = [list_to_binary(Scope) || Scope <- string:tokens(ScopesString, ";")],
|
Scopes = [list_to_binary(Scope) || Scope <- string:tokens(ScopesString, ";")],
|
||||||
case jid:from_string(list_to_binary(Jid)) of
|
case jid:from_string(list_to_binary(Jid)) of
|
||||||
#jid{luser =Username, lserver = Server} ->
|
#jid{luser =Username, lserver = Server} ->
|
||||||
case oauth2:authorize_password({Username, Server}, Scopes, admin_generated) of
|
case oauth2:authorize_password({Username, Server}, Scopes, admin_generated) of
|
||||||
{ok, {Ctx,Authorization}} ->
|
{ok, {_Ctx,Authorization}} ->
|
||||||
{ok, {_AppCtx2, Response}} = oauth2:issue_token(Authorization, Ctx),
|
{ok, {_AppCtx2, Response}} = oauth2:issue_token(Authorization, [{expiry_time, seconds_since_epoch(TTLSeconds)}]),
|
||||||
{ok, AccessToken} = oauth2_response:access_token(Response),
|
{ok, AccessToken} = oauth2_response:access_token(Response),
|
||||||
{ok, Expires} = oauth2_response:expires_in(Response),
|
|
||||||
{ok, VerifiedScope} = oauth2_response:scope(Response),
|
{ok, VerifiedScope} = oauth2_response:scope(Response),
|
||||||
{AccessToken, VerifiedScope, integer_to_list(Expires) ++ " seconds"};
|
{AccessToken, VerifiedScope, integer_to_list(TTLSeconds) ++ " seconds"};
|
||||||
{error, Error} ->
|
{error, Error} ->
|
||||||
{error, Error}
|
{error, Error}
|
||||||
end;
|
end;
|
||||||
@ -158,7 +156,6 @@ oauth_list_scopes() ->
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
start_link() ->
|
start_link() ->
|
||||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||||
|
|
||||||
@ -264,37 +261,44 @@ get_cmd_scopes() ->
|
|||||||
end end, dict:new(), ejabberd_commands:get_commands()),
|
end end, dict:new(), ejabberd_commands:get_commands()),
|
||||||
ScopeMap.
|
ScopeMap.
|
||||||
|
|
||||||
%Scps = lists:flatmap(fun(Cmd) -> case ejabberd_commands:get_command_policy_and_scope(Cmd) of
|
|
||||||
% {ok, Policy, Scopes} when Policy =/= restricted -> Scopes;
|
|
||||||
% _ -> []
|
|
||||||
% end end,
|
|
||||||
% ejabberd_commands:get_commands()),
|
|
||||||
%lists:usort(Scps).
|
|
||||||
|
|
||||||
%% This is callback for oauth tokens generated through the command line. Only open and admin commands are
|
%% This is callback for oauth tokens generated through the command line. Only open and admin commands are
|
||||||
%% made available.
|
%% made available.
|
||||||
verify_client_scope({client, ejabberd_ctl}, Scope, Ctx) ->
|
%verify_client_scope({client, ejabberd_ctl}, Scope, Ctx) ->
|
||||||
RegisteredScope = dict:fetch_keys(get_cmd_scopes()),
|
% RegisteredScope = dict:fetch_keys(get_cmd_scopes()),
|
||||||
case oauth2_priv_set:is_subset(oauth2_priv_set:new(Scope),
|
% case oauth2_priv_set:is_subset(oauth2_priv_set:new(Scope),
|
||||||
oauth2_priv_set:new(RegisteredScope)) of
|
% oauth2_priv_set:new(RegisteredScope)) of
|
||||||
true ->
|
% true ->
|
||||||
{ok, {Ctx, Scope}};
|
% {ok, {Ctx, Scope}};
|
||||||
false ->
|
% false ->
|
||||||
{error, badscope}
|
% {error, badscope}
|
||||||
end.
|
% end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec seconds_since_epoch(integer()) -> non_neg_integer().
|
||||||
|
seconds_since_epoch(Diff) ->
|
||||||
|
{Mega, Secs, _} = os:timestamp(),
|
||||||
|
Mega * 1000000 + Secs + Diff.
|
||||||
|
|
||||||
|
|
||||||
associate_access_code(_AccessCode, _Context, AppContext) ->
|
associate_access_code(_AccessCode, _Context, AppContext) ->
|
||||||
%put(?ACCESS_CODE_TABLE, AccessCode, Context),
|
%put(?ACCESS_CODE_TABLE, AccessCode, Context),
|
||||||
{ok, AppContext}.
|
{ok, AppContext}.
|
||||||
|
|
||||||
associate_access_token(AccessToken, Context, AppContext) ->
|
associate_access_token(AccessToken, Context, AppContext) ->
|
||||||
|
{user, User, Server} = proplists:get_value(<<"resource_owner">>, Context, <<"">>),
|
||||||
|
Expire = case proplists:get_value(expiry_time, AppContext, undefined) of
|
||||||
|
undefined ->
|
||||||
|
proplists:get_value(<<"expiry_time">>, Context, 0);
|
||||||
|
E ->
|
||||||
|
%% There is no clean way in oauth2 lib to actually override the TTL of the generated token.
|
||||||
|
%% It always pass the global configured value. Here we use the app context to pass the per-case
|
||||||
|
%% ttl if we want to override it.
|
||||||
|
E
|
||||||
|
end,
|
||||||
{user, User, Server} = proplists:get_value(<<"resource_owner">>, Context, <<"">>),
|
{user, User, Server} = proplists:get_value(<<"resource_owner">>, Context, <<"">>),
|
||||||
Scope = proplists:get_value(<<"scope">>, Context, []),
|
Scope = proplists:get_value(<<"scope">>, Context, []),
|
||||||
Expire = proplists:get_value(<<"expiry_time">>, Context, 0),
|
|
||||||
R = #oauth_token{
|
R = #oauth_token{
|
||||||
token = AccessToken,
|
token = AccessToken,
|
||||||
us = {jid:nodeprep(User), jid:nodeprep(Server)},
|
us = {jid:nodeprep(User), jid:nodeprep(Server)},
|
||||||
@ -308,7 +312,6 @@ associate_refresh_token(_RefreshToken, _Context, AppContext) ->
|
|||||||
%put(?REFRESH_TOKEN_TABLE, RefreshToken, Context),
|
%put(?REFRESH_TOKEN_TABLE, RefreshToken, Context),
|
||||||
{ok, AppContext}.
|
{ok, 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),
|
||||||
@ -386,6 +389,17 @@ process(_Handlers,
|
|||||||
?INPUT(<<"hidden">>, <<"scope">>, Scope),
|
?INPUT(<<"hidden">>, <<"scope">>, Scope),
|
||||||
?INPUT(<<"hidden">>, <<"state">>, State),
|
?INPUT(<<"hidden">>, <<"state">>, State),
|
||||||
?BR,
|
?BR,
|
||||||
|
?LABEL(<<"ttl">>, [?CT(<<"Token TTL">>), ?CT(<<": ">>)]),
|
||||||
|
?XAE(<<"select">>, [{<<"name">>, <<"ttl">>}],
|
||||||
|
[
|
||||||
|
?XAC(<<"option">>, [{<<"selected">>, <<"selected">>},
|
||||||
|
{<<"value">>, jlib:integer_to_binary(expire())}],<<"Default (", (integer_to_binary(expire()))/binary, " seconds)">>),
|
||||||
|
?XAC(<<"option">>, [{<<"value">>, <<"3600">>}],<<"1 Hour">>),
|
||||||
|
?XAC(<<"option">>, [{<<"value">>, <<"86400">>}],<<"1 Day">>),
|
||||||
|
?XAC(<<"option">>, [{<<"value">>, <<"2592000">>}],<<"1 Month">>),
|
||||||
|
?XAC(<<"option">>, [{<<"value">>, <<"31536000">>}],<<"1 Year">>),
|
||||||
|
?XAC(<<"option">>, [{<<"value">>, <<"315360000">>}],<<"10 Years">>)]),
|
||||||
|
?BR,
|
||||||
?INPUTT(<<"submit">>, <<"">>, <<"Accept">>)
|
?INPUTT(<<"submit">>, <<"">>, <<"Accept">>)
|
||||||
]),
|
]),
|
||||||
Top =
|
Top =
|
||||||
@ -434,6 +448,11 @@ process(_Handlers,
|
|||||||
Password = proplists:get_value(<<"password">>, Q, <<"">>),
|
Password = proplists:get_value(<<"password">>, Q, <<"">>),
|
||||||
State = proplists:get_value(<<"state">>, Q, <<"">>),
|
State = proplists:get_value(<<"state">>, Q, <<"">>),
|
||||||
Scope = str:tokens(SScope, <<" ">>),
|
Scope = str:tokens(SScope, <<" ">>),
|
||||||
|
TTL = proplists:get_value(<<"ttl">>, Q, <<"">>),
|
||||||
|
ExpiresIn = case TTL of
|
||||||
|
<<>> -> undefined;
|
||||||
|
_ -> seconds_since_epoch(jlib:binary_to_integer(TTL))
|
||||||
|
end,
|
||||||
case oauth2:authorize_password({Username, Server},
|
case oauth2:authorize_password({Username, Server},
|
||||||
ClientId,
|
ClientId,
|
||||||
RedirectURI,
|
RedirectURI,
|
||||||
@ -441,10 +460,18 @@ process(_Handlers,
|
|||||||
{password, Password}) of
|
{password, Password}) of
|
||||||
{ok, {_AppContext, Authorization}} ->
|
{ok, {_AppContext, Authorization}} ->
|
||||||
{ok, {_AppContext2, Response}} =
|
{ok, {_AppContext2, Response}} =
|
||||||
oauth2:issue_token(Authorization, none),
|
oauth2:issue_token(Authorization, [{expiry_time, ExpiresIn} || ExpiresIn /= undefined ]),
|
||||||
{ok, AccessToken} = oauth2_response:access_token(Response),
|
{ok, AccessToken} = oauth2_response:access_token(Response),
|
||||||
{ok, Type} = oauth2_response:token_type(Response),
|
{ok, Type} = oauth2_response:token_type(Response),
|
||||||
{ok, Expires} = oauth2_response:expires_in(Response),
|
%%Ugly: workardound to return the correct expirity time, given than oauth2 lib doesn't really have
|
||||||
|
%%per-case expirity time.
|
||||||
|
Expires = case ExpiresIn of
|
||||||
|
undefined ->
|
||||||
|
{ok, Ex} = oauth2_response:expires_in(Response),
|
||||||
|
Ex;
|
||||||
|
_ ->
|
||||||
|
ExpiresIn
|
||||||
|
end,
|
||||||
{ok, VerifiedScope} = oauth2_response:scope(Response),
|
{ok, VerifiedScope} = oauth2_response:scope(Response),
|
||||||
%oauth2_wrq:redirected_access_token_response(ReqData,
|
%oauth2_wrq:redirected_access_token_response(ReqData,
|
||||||
% RedirectURI,
|
% RedirectURI,
|
||||||
|
Loading…
Reference in New Issue
Block a user