Skip to content

Commit

Permalink
make auth. passing for dynamic domains with dummy auth module
Browse files Browse the repository at this point in the history
esuring dialyzer is not complaning:
   ./rebar3 dialyzer
  • Loading branch information
DenysGonchar committed Apr 3, 2021
1 parent 7caff14 commit 05b6c6d
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 45 deletions.
1 change: 1 addition & 0 deletions include/ejabberd_c2s.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
tls_options = [],
tls_verify :: verify_none | verify_peer,
authenticated = false :: authenticated_state(),
host_type = <<>> :: binary(),
jid :: jid:jid() | undefined,
user = <<>> :: jid:user(),
server = <<>> :: jid:server(),
Expand Down
2 changes: 2 additions & 0 deletions include/mongoose.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
-define(MONGOOSE_VERSION, element(2, application:get_key(mongooseim,vsn))).

-define(MYHOSTS, ejabberd_config:get_global_option(hosts)).
-define(ALL_HOST_TYPES, ejabberd_config:get_global_option_or_default(hosts, []) ++
ejabberd_config:get_global_option_or_default(host_types, [])).
-define(MYNAME, hd(ejabberd_config:get_global_option(hosts))).
-define(MYLANG, ejabberd_config:get_global_option(language)).

Expand Down
42 changes: 25 additions & 17 deletions src/auth/ejabberd_auth.erl
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
%%%----------------------------------------------------------------------
-spec start() -> 'ok'.
start() ->
lists:foreach(fun start/1, ?MYHOSTS).
lists:foreach(fun start/1, ?ALL_HOST_TYPES).

-spec start(Host :: jid:server()) -> 'ok'.
start(Host) ->
Expand Down Expand Up @@ -122,9 +122,10 @@ get_opt(Host, Opt, Default) ->
get_opt(Host, Opt) ->
get_opt(Host, Opt, undefined).

-spec supports_sasl_module(jid:lserver(), cyrsasl:sasl_module()) -> boolean().
supports_sasl_module(Server, Module) ->
lists:any(fun(M) -> M:supports_sasl_module(Server, Module) end, auth_modules(Server)).
-spec supports_sasl_module(binary(), cyrsasl:sasl_module()) -> boolean().
supports_sasl_module(HostType, Module) ->
lists:any(fun(M) -> M:supports_sasl_module(HostType, Module) end,
auth_modules_for_host_type(HostType)).

-spec authorize(mongoose_credentials:t()) -> {ok, mongoose_credentials:t()}
| {error, any()}.
Expand Down Expand Up @@ -247,11 +248,11 @@ do_try_register_if_does_not_exist(true, _, _) ->
{error, exists};
do_try_register_if_does_not_exist(_, JID, Password) ->
{LUser, LServer} = jid:to_lus(JID),
case lists:member(LServer, ?MYHOSTS) of
true ->
timed_call(LServer, try_register,
case mongoose_domain_api:get_host_type(LServer) of
{ok, HostType} ->
timed_call(HostType, try_register,
fun do_try_register_if_does_not_exist_timed/3, [LUser, LServer, Password]);
false ->
{error, not_found} ->
{error, not_allowed}
end.

Expand Down Expand Up @@ -458,20 +459,27 @@ entropy(IOList) ->
auth_modules() ->
lists:usort(
lists:flatmap(
fun(Server) ->
auth_modules(Server)
end, ?MYHOSTS)).

fun(HostType) ->
auth_modules_for_host_type(HostType)
end, ?ALL_HOST_TYPES)).

%% Return the list of authenticated modules for a given host
%% Return the list of authenticated modules for a given domain
-spec auth_modules(Server :: jid:lserver()) -> [authmodule()].
auth_modules(LServer) ->
Methods = auth_methods(LServer),
case mongoose_domain_api:get_host_type(LServer) of
{ok, HostType} -> auth_modules_for_host_type(HostType);
{error, not_found} -> []
end.

%% Return the list of authenticated modules for a given host type
-spec auth_modules_for_host_type(HostType :: binary()) -> [authmodule()].
auth_modules_for_host_type(HostType) ->
Methods = auth_methods(HostType),
[list_to_atom("ejabberd_auth_" ++ atom_to_list(M)) || M <- Methods].

-spec auth_methods(jid:lserver()) -> [atom()].
auth_methods(LServer) ->
Method = ejabberd_config:get_local_option({auth_method, LServer}),
-spec auth_methods(binary()) -> [atom()].
auth_methods(HostType) ->
Method = ejabberd_config:get_local_option({auth_method, HostType}),
get_auth_method_as_a_list(Method).

get_auth_method_as_a_list(undefined) -> [];
Expand Down
24 changes: 13 additions & 11 deletions src/ejabberd_c2s.erl
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,12 @@ handle_stream_start({xmlstreamstart, _Name, Attrs}, #state{} = S0) ->
Lang = get_xml_lang(Attrs),
S = S0#state{server = Server, lang = Lang, stream_mgmt = StreamMgmtConfig},
case {xml:get_attr_s(<<"xmlns:stream">>, Attrs),
lists:member(Server, ?MYHOSTS)} of
{?NS_STREAM, true} ->
mongoose_domain_api:get_host_type(Server)} of
{?NS_STREAM, {ok, HostType}} ->
change_shaper(S, jid:make_noprep(<<>>, Server, <<>>)),
Version = xml:get_attr_s(<<"version">>, Attrs),
stream_start_by_protocol_version(Version, S);
{?NS_STREAM, false} ->
stream_start_by_protocol_version(Version, S#state{host_type = HostType});
{?NS_STREAM, {error, not_found}} ->
stream_start_error(mongoose_xmpp_errors:host_unknown(), S);
{_InvalidNS, _} ->
stream_start_error(mongoose_xmpp_errors:invalid_namespace(), S)
Expand Down Expand Up @@ -336,9 +336,11 @@ stream_start_negotiate_features(#state{} = S) ->
fsm_next_state(wait_for_session_or_sm, S)
end.

stream_start_features_before_auth(#state{server = Server} = S) ->
Creds = maybe_add_cert(mongoose_credentials:new(Server), S),
SASLState = cyrsasl:server_new(<<"jabber">>, Server, <<>>, [], Creds),
stream_start_features_before_auth(#state{server = Server,
host_type = HostType} = S) ->
Creds0 = mongoose_credentials:new(Server, HostType),
Creds = maybe_add_cert(Creds0, S),
SASLState = cyrsasl:server_new(<<"jabber">>, Server, HostType, <<>>, [], Creds),
SockMod = (S#state.sockmod):get_sockmod(S#state.socket),
send_element_from_server_jid(S, stream_features(determine_features(SockMod, S))),
fsm_next_state(wait_for_feature_before_auth,
Expand Down Expand Up @@ -395,8 +397,8 @@ maybe_compress_feature(SockMod, #state{zlib = {ZLib, _}}) ->
_ -> []
end.

maybe_sasl_mechanisms(#state{server = Server} = S) ->
case cyrsasl:listmech(Server) of
maybe_sasl_mechanisms(#state{host_type = HostType} = S) ->
case cyrsasl:listmech(HostType) of
[] -> [];
Mechanisms ->
[#xmlel{name = <<"mechanisms">>,
Expand Down Expand Up @@ -507,8 +509,8 @@ wait_for_feature_before_auth({xmlstreamelement, El}, StateData) ->
Mech = xml:get_attr_s(<<"mechanism">>, Attrs),
ClientIn = jlib:decode_base64(xml:get_cdata(Els)),
SaslState = StateData#state.sasl_state,
Server = StateData#state.server,
AuthMech = [M || M <- cyrsasl:listmech(Server), filter_mechanism(M, StateData)],
HostType = StateData#state.host_type,
AuthMech = [M || M <- cyrsasl:listmech(HostType), filter_mechanism(M, StateData)],
SocketData = #{socket => StateData#state.socket, auth_mech => AuthMech},
StepResult = cyrsasl:server_start(SaslState, Mech, ClientIn, SocketData),
{NewFSMState, NewStateData} = handle_sasl_step(StateData, StepResult),
Expand Down
20 changes: 18 additions & 2 deletions src/mongoose_credentials.erl
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
-module(mongoose_credentials).

-export([new/1,
new/2,
lserver/1,
host_type/1,
get/2, get/3,
set/3,
extend/2,
register/3]).

-export_type([t/0]).

-record(mongoose_credentials, {lserver, registry = [], extra = []}).
-record(mongoose_credentials, {lserver, host_type, registry = [], extra = []}).

-type auth_event() :: any().

-opaque t() ::
#mongoose_credentials{ %% These values are always present.
lserver :: jid:lserver(),
host_type :: {ok, binary()} | {error, not_found},
%% Authorization success / failure registry.
registry :: [{ejabberd_gen_auth:t(), auth_event()}],
%% These values are dependent on the ejabberd_auth backend in use.
Expand All @@ -24,7 +27,15 @@

-spec new(jid:lserver()) -> mongoose_credentials:t().
new(LServer) when is_binary(LServer) ->
#mongoose_credentials{lserver = LServer}.
Ret = mongoose_domain_api:get_host_type(LServer),
new_creds(LServer, Ret).

-spec new(jid:lserver(), binary()) -> mongoose_credentials:t().
new(LServer, HostType) when is_binary(LServer), is_binary(HostType) ->
new_creds(LServer, {ok, HostType}).

-spec host_type(t()) -> {ok, binary()} | {error, not_found}.
host_type(#mongoose_credentials{host_type = HostType}) -> HostType.

-spec lserver(t()) -> jid:lserver().
lserver(#mongoose_credentials{lserver = S}) -> S.
Expand Down Expand Up @@ -69,3 +80,8 @@ extend(#mongoose_credentials{} = C, KVPairs) ->
register(#mongoose_credentials{} = C, Mod, Event) ->
#mongoose_credentials{registry = R} = C,
C#mongoose_credentials{registry = [{Mod, Event} | R]}.

-spec new_creds(jid:lserver(), {ok, binary()} | {error, not_found}) ->
mongoose_credentials:t().
new_creds(LServer, HostType) ->
#mongoose_credentials{lserver = LServer, host_type = HostType}.
34 changes: 19 additions & 15 deletions src/sasl/cyrsasl.erl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
-author('alexey@process-one.net').

-export([listmech/1,
server_new/5,
server_new/6,
server_start/4,
server_step/2]).

Expand All @@ -38,6 +38,7 @@

-record(sasl_state, {service :: binary(),
myname :: jid:server(),
host_type :: binary(),
realm :: binary(),
mech_mod :: sasl_module(),
mech_state :: any(),
Expand Down Expand Up @@ -76,18 +77,20 @@ check_credentials(_State, Creds) ->
{ok, Creds}
end.

-spec listmech(jid:server()) -> [mechanism()].
listmech(Host) ->
[M:mechanism() || M <- get_modules(Host), is_module_supported(Host, M)].
-spec listmech(binary()) -> [mechanism()].
listmech(HostType) ->
[M:mechanism() || M <- get_modules(HostType), is_module_supported(HostType, M)].

-spec server_new(Service :: binary(),
ServerFQDN :: jid:server(),
HostType :: binary(),
UserRealm :: binary(),
_SecFlags :: [any()],
Creds :: mongoose_credentials:t()) -> sasl_state().
server_new(Service, ServerFQDN, UserRealm, _SecFlags, Creds) ->
server_new(Service, ServerFQDN, HostType, UserRealm, _SecFlags, Creds) ->
#sasl_state{service = Service,
myname = ServerFQDN,
host_type = HostType,
realm = UserRealm,
creds = Creds}.

Expand All @@ -99,9 +102,10 @@ server_new(Service, ServerFQDN, UserRealm, _SecFlags, Creds) ->
Result :: {ok, mongoose_credentials:t()}
| {'continue', _, sasl_state()}
| error().
server_start(State, Mech, ClientIn, SocketData) ->
Host = State#sasl_state.myname,
case [M || M <- get_modules(Host), M:mechanism() =:= Mech, is_module_supported(Host, M)] of
server_start(#sasl_state{myname = Host, host_type = HostType} = State,
Mech, ClientIn, SocketData) ->
case [M || M <- get_modules(HostType), M:mechanism() =:= Mech,
is_module_supported(HostType, M)] of
[Module] ->
{ok, MechState} = Module:mech_new(Host, State#sasl_state.creds, SocketData),
server_step(State#sasl_state{mech_mod = Module,
Expand All @@ -111,10 +115,10 @@ server_start(State, Mech, ClientIn, SocketData) ->
{error, <<"no-mechanism">>}
end.

is_module_supported(Host, cyrsasl_oauth) ->
gen_mod:is_loaded(Host, mod_auth_token);
is_module_supported(Host, Module) ->
mongoose_fips:supports_sasl_module(Module) andalso ejabberd_auth:supports_sasl_module(Host, Module).
is_module_supported(HostType, cyrsasl_oauth) ->
gen_mod:is_loaded(HostType, mod_auth_token);
is_module_supported(HostType, Module) ->
mongoose_fips:supports_sasl_module(Module) andalso ejabberd_auth:supports_sasl_module(HostType, Module).

-spec server_step(State :: sasl_state(), ClientIn :: binary()) -> Result when
Result :: {ok, mongoose_credentials:t()}
Expand All @@ -135,9 +139,9 @@ server_step(State, ClientIn) ->
{error, Error}
end.

-spec get_modules(jid:server()) -> [sasl_module()].
get_modules(Host) ->
case ejabberd_config:get_local_option({sasl_mechanisms, Host}) of
-spec get_modules(binary()) -> [sasl_module()].
get_modules(HostType) ->
case ejabberd_config:get_local_option({sasl_mechanisms, HostType}) of
undefined -> ejabberd_config:get_local_option_or_default(sasl_mechanisms, default_modules());
Modules -> Modules
end.
Expand Down

0 comments on commit 05b6c6d

Please sign in to comment.