Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/processone/ejabberd.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Shchepin <alexey@process-one.net>2019-10-03 06:18:07 +0300
committerAlexey Shchepin <alexey@process-one.net>2019-10-03 06:18:48 +0300
commit5d549dca96c643345ba92e67504e67eb1b6b0681 (patch)
tree8228edfd0595643c869420d1506e76ebf5c45146 /src/ejabberd_oauth.erl
parent949e71efb644f6b79030e26ed880bb2e74b93da0 (diff)
Check redirect_uri for OAUTH implicit grant
Diffstat (limited to 'src/ejabberd_oauth.erl')
-rw-r--r--src/ejabberd_oauth.erl131
1 files changed, 94 insertions, 37 deletions
diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl
index 4060b4b7b..27e211f13 100644
--- a/src/ejabberd_oauth.erl
+++ b/src/ejabberd_oauth.erl
@@ -50,7 +50,9 @@
-export([get_commands_spec/0,
oauth_issue_token/3, oauth_list_tokens/0, oauth_revoke_token/1,
- oauth_add_client/3, oauth_remove_client/1]).
+ oauth_add_client_password/3,
+ oauth_add_client_implicit/3,
+ oauth_remove_client/1]).
-include("xmpp.hrl").
-include("logger.hrl").
@@ -65,6 +67,11 @@
-callback lookup(binary()) -> {ok, #oauth_token{}} | error.
-callback clean(non_neg_integer()) -> any().
+-record(oauth_ctx, {
+ password :: binary() | admin_generated,
+ client :: #oauth_client{}
+ }).
+
%% There are two ways to obtain an oauth token:
%% * 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
@@ -99,12 +106,21 @@ get_commands_spec() ->
result = {tokens, {list, {token, {tuple, [{token, string}, {user, string}, {scope, string}, {expires_in, string}]}}}},
result_desc = "List of remaining tokens"
},
- #ejabberd_commands{name = oauth_add_client, tags = [oauth],
- desc = "Add OAUTH client_id",
- module = ?MODULE, function = oauth_add_client,
+ #ejabberd_commands{name = oauth_add_client_password, tags = [oauth],
+ desc = "Add OAUTH client_id with password grant type",
+ module = ?MODULE, function = oauth_add_client_password,
+ args = [{client_id, binary},
+ {client_name, binary},
+ {secret, binary}],
+ policy = restricted,
+ result = {res, restuple}
+ },
+ #ejabberd_commands{name = oauth_add_client_implicit, tags = [oauth],
+ desc = "Add OAUTH client_id with implicit grant type",
+ module = ?MODULE, function = oauth_add_client_implicit,
args = [{client_id, binary},
- {secret, binary},
- {grant_type, binary}],
+ {client_name, binary},
+ {redirect_uri, binary}],
policy = restricted,
result = {res, restuple}
},
@@ -146,18 +162,21 @@ oauth_revoke_token(Token) ->
ok = mnesia:dirty_delete(oauth_token, list_to_binary(Token)),
oauth_list_tokens().
-oauth_add_client(Client, Secret, SGrantType) ->
- case SGrantType of
- <<"password">> ->
- DBMod = get_db_backend(),
- DBMod:store_client(#oauth_client{client = Client,
- secret = Secret,
- grant_type = password,
- options = []}),
- {ok, []};
- _ ->
- {error, "Unsupported grant type"}
- end.
+oauth_add_client_password(ClientID, ClientName, Secret) ->
+ DBMod = get_db_backend(),
+ DBMod:store_client(#oauth_client{client_id = ClientID,
+ client_name = ClientName,
+ grant_type = password,
+ options = [{secret, Secret}]}),
+ {ok, []}.
+
+oauth_add_client_implicit(ClientID, ClientName, RedirectURI) ->
+ DBMod = get_db_backend(),
+ DBMod:store_client(#oauth_client{client_id = ClientID,
+ client_name = ClientName,
+ grant_type = implicit,
+ options = [{redirect_uri, RedirectURI}]}),
+ {ok, []}.
oauth_remove_client(Client) ->
DBMod = get_db_backend(),
@@ -216,9 +235,23 @@ terminate(_Reason, _State) ->
code_change(_OldVsn, State, _Extra) -> {ok, State}.
-get_client_identity(Client, Ctx) -> {ok, {Ctx, {client, Client}}}.
+get_client_identity({client, ClientID}, Ctx) ->
+ {ok, {Ctx, {client, ClientID}}}.
-verify_redirection_uri(_, _, Ctx) -> {ok, Ctx}.
+verify_redirection_uri(_ClientID, RedirectURI, Ctx) ->
+ case Ctx of
+ #oauth_ctx{client = #oauth_client{grant_type = implicit} = Client} ->
+ case get_redirect_uri(Client) of
+ RedirectURI ->
+ {ok, Ctx};
+ _ ->
+ {error, invalid_uri}
+ end;
+ #oauth_ctx{client = #oauth_client{}} ->
+ {error, invalid_client};
+ _ ->
+ {ok, Ctx}
+ end.
authenticate_user({User, Server}, Ctx) ->
case jid:make(User, Server) of
@@ -228,15 +261,16 @@ authenticate_user({User, Server}, Ctx) ->
case acl:match_rule(JID#jid.lserver, Access, JID) of
allow ->
case Ctx of
- {password, Password} ->
- case ejabberd_auth:check_password(User, <<"">>, Server, Password) of
- true ->
+ #oauth_ctx{password = admin_generated} ->
{ok, {Ctx, {user, User, Server}}};
- false ->
- {error, badpass}
- end;
- admin_generated ->
- {ok, {Ctx, {user, User, Server}}}
+ #oauth_ctx{password = Password}
+ when is_binary(Password) ->
+ case ejabberd_auth:check_password(User, <<"">>, Server, Password) of
+ true ->
+ {ok, {Ctx, {user, User, Server}}};
+ false ->
+ {error, badpass}
+ end
end;
deny ->
{error, badpass}
@@ -245,7 +279,20 @@ authenticate_user({User, Server}, Ctx) ->
{error, badpass}
end.
-authenticate_client(Client, Ctx) -> {ok, {Ctx, {client, Client}}}.
+authenticate_client(ClientID, Ctx) ->
+ case ejabberd_option:oauth_client_id_check() of
+ allow ->
+ {ok, {Ctx, {client, ClientID}}};
+ deny -> {error, not_allowed};
+ db ->
+ DBMod = get_db_backend(),
+ case DBMod:lookup_client(ClientID) of
+ {ok, #oauth_client{} = Client} ->
+ {ok, {Ctx#oauth_ctx{client = Client}, {client, ClientID}}};
+ _ ->
+ {error, not_allowed}
+ end
+ end.
-spec verify_resowner_scope({user, binary(), binary()}, [binary()], any()) ->
{ok, any(), [binary()]} | {error, any()}.
@@ -525,7 +572,7 @@ process(_Handlers,
ClientId,
RedirectURI,
Scope,
- {password, Password}) of
+ #oauth_ctx{password = Password}) of
{ok, {_AppContext, Authorization}} ->
{ok, {_AppContext2, Response}} =
oauth2:issue_token(Authorization, [{expiry_time, ExpiresIn} || ExpiresIn /= undefined ]),
@@ -597,13 +644,18 @@ process(_Handlers,
end,
DBMod = get_db_backend(),
case DBMod:lookup_client(ClientID) of
- {ok, #oauth_client{secret = Secret} = Client} ->
- case proplists:get_value(<<"grant_type">>, Q, <<"">>) of
- <<"password">> when
- Client#oauth_client.grant_type == password ->
- password;
+ {ok, #oauth_client{grant_type = password} = Client} ->
+ case get_client_secret(Client) of
+ Secret ->
+ case proplists:get_value(<<"grant_type">>, Q, <<"">>) of
+ <<"password">> when
+ Client#oauth_client.grant_type == password ->
+ password;
+ _ ->
+ unsupported_grant_type
+ end;
_ ->
- unsupported_grant_type
+ deny
end;
_ ->
deny
@@ -623,7 +675,7 @@ process(_Handlers,
end,
case oauth2:authorize_password({Username, Server},
Scope,
- {password, Password}) of
+ #oauth_ctx{password = Password}) of
{ok, {_AppContext, Authorization}} ->
{ok, {_AppContext2, Response}} =
oauth2:issue_token(Authorization, [{expiry_time, ExpiresIn} || ExpiresIn /= undefined ]),
@@ -663,6 +715,11 @@ get_db_backend() ->
DBType = ejabberd_option:oauth_db_type(),
list_to_existing_atom("ejabberd_oauth_" ++ atom_to_list(DBType)).
+get_client_secret(#oauth_client{grant_type = password, options = Options}) ->
+ proplists:get_value(secret, Options, false).
+
+get_redirect_uri(#oauth_client{grant_type = implicit, options = Options}) ->
+ proplists:get_value(redirect_uri, Options, false).
%% Headers as per RFC 6749
json_response(Code, Body) ->