Skip to content

Commit

Permalink
Merge pull request #3178 from esl/mu-fix-ldap-types
Browse files Browse the repository at this point in the history
Tag should be an atom, it's binary in ldap types
  • Loading branch information
chrzaszcz committed Jul 12, 2021
2 parents de27b3f + 5b35e43 commit 2a6381f
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 87 deletions.
77 changes: 34 additions & 43 deletions src/auth/ejabberd_auth_ldap.erl
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,15 @@

-record(state,
{host_type :: mongooseim:host_type(),
eldap_id :: {jid:lserver(), binary()},
bind_eldap_id :: {jid:lserver(), binary()},
base = <<"">> :: binary(),
eldap_id :: eldap_utils:eldap_id(),
bind_eldap_id :: eldap_utils:eldap_id(),
base = <<>> :: binary(),
uids = [] :: [{binary()} | {binary(), binary()}],
ufilter = <<"">> :: binary(),
sfilter = <<"">> :: binary(),
ufilter = <<>> :: binary(),
sfilter = <<>> :: binary(),
lfilter :: {any(), any()} | undefined,
deref = neverDerefAliases :: neverDerefAliases |
derefInSearching |
derefFindingBaseObj |
derefAlways,
dn_filter :: binary() | undefined,
deref = neverDerefAliases :: eldap_utils:deref(),
dn_filter :: eldap_utils:dn() | undefined,
dn_filter_attrs = [] :: [binary()]
}).
-type state() :: #state{}.
Expand Down Expand Up @@ -151,14 +148,13 @@ check_password(HostType, LUser, LServer, Password, _Digest,
LUser :: jid:luser(),
LServer :: jid:lserver(),
Password :: binary())
-> ok | {error, not_allowed | invalid_jid}.
-> ok | {error, not_allowed | invalid_jid | user_not_found}.
set_password(HostType, LUser, LServer, Password) ->
{ok, State} = eldap_utils:get_state(HostType, ?MODULE),
case find_user_dn(LUser, LServer, State) of
false -> {error, user_not_found};
DN ->
eldap_pool:modify_passwd(State#state.eldap_id, DN,
Password)
eldap_pool:modify_passwd(State#state.eldap_id, DN, Password)
end.

%% TODO Support multiple domains
Expand Down Expand Up @@ -285,7 +281,7 @@ get_users_from_ldap_entries(LDAPEntries, UIDs, LServer, State) ->
object_name = DN}) ->
case is_valid_dn(DN, LServer, Attrs, State) of
false -> [];
_ ->
true ->
get_user_from_ldap_attributes(UIDs, Attrs, LServer)
end
end,
Expand Down Expand Up @@ -322,21 +318,15 @@ handle_call(stop, _From, State) ->
handle_call(_Request, _From, State) ->
{reply, bad_request, State}.


-spec find_user_dn(LUser :: jid:luser(),
LServer :: jid:lserver(),
State :: state()) -> 'false' | binary().
State :: state()) -> false | eldap_utils:dn().
find_user_dn(LUser, LServer, State) ->
ResAttrs = result_attrs(State),
case eldap_filter:parse(State#state.ufilter,
[{<<"%u">>, LUser}])
of
case eldap_filter:parse(State#state.ufilter, [{<<"%u">>, LUser}]) of
{ok, Filter} ->
case eldap_pool:search(State#state.eldap_id,
[{base, State#state.base}, {filter, Filter},
{deref, State#state.deref},
{attributes, ResAttrs}])
of
SearchOpts = find_user_opts(Filter, ResAttrs, State),
case eldap_pool:search(State#state.eldap_id, SearchOpts) of
#eldap_search_result{entries =
[#eldap_entry{attributes = Attrs,
object_name = DN}
Expand All @@ -347,53 +337,54 @@ find_user_dn(LUser, LServer, State) ->
_ -> false
end.

find_user_opts(Filter, ResAttrs, State) ->
[{base, State#state.base}, {filter, Filter},
{deref, State#state.deref}, {attributes, ResAttrs}].


%% @doc apply the dn filter and the local filter:
-spec dn_filter(DN :: binary(),
-spec dn_filter(DN :: eldap_utils:dn(),
LServer :: jid:lserver(),
Attrs :: [{binary(), [any()]}],
State :: state()) -> 'false' | binary().
State :: state()) -> false | eldap_utils:dn().
dn_filter(DN, LServer, Attrs, State) ->
case check_local_filter(Attrs, State) of
false -> false;
true -> is_valid_dn(DN, LServer, Attrs, State)
true ->
case is_valid_dn(DN, LServer, Attrs, State) of
true -> DN;
false -> false
end
end.


%% @doc Check that the DN is valid, based on the dn filter
-spec is_valid_dn(DN :: binary(),
-spec is_valid_dn(DN :: eldap_utils:dn(),
LServer :: jid:lserver(),
Attrs :: [{binary(), [any()]}],
State :: state()) -> 'false' | binary().
is_valid_dn(DN, _LServer, _, #state{dn_filter = undefined}) -> DN;
State :: state()) -> boolean().
is_valid_dn(_DN, _LServer, _, #state{dn_filter = undefined}) -> true;
is_valid_dn(DN, LServer, Attrs, State) ->
DNAttrs = State#state.dn_filter_attrs,
UIDs = State#state.uids,
Values = [{<<"%s">>,
eldap_utils:get_ldap_attr(Attr, Attrs), 1}
Values = [{<<"%s">>, eldap_utils:get_ldap_attr(Attr, Attrs), 1}
|| Attr <- DNAttrs],
SubstValues = case eldap_utils:find_ldap_attrs(UIDs,
Attrs)
of
<<"">> -> Values;
SubstValues = case eldap_utils:find_ldap_attrs(UIDs, Attrs) of
<<>> -> Values;
{S, UAF} ->
case eldap_utils:get_user_part(S, UAF) of
{ok, U} -> [{<<"%u">>, U} | Values];
_ -> Values
end
end
++ [{<<"%d">>, LServer}, {<<"%D">>, DN}],
case eldap_filter:parse(State#state.dn_filter,
SubstValues)
of
end ++ [{<<"%d">>, LServer}, {<<"%D">>, DN}],
case eldap_filter:parse(State#state.dn_filter, SubstValues) of
{ok, EldapFilter} ->
case eldap_pool:search(State#state.eldap_id,
[{base, State#state.base},
{filter, EldapFilter},
{deref, State#state.deref},
{attributes, [<<"dn">>]}])
of
#eldap_search_result{entries = [_ | _]} -> DN;
#eldap_search_result{entries = [_ | _]} -> true;
_ -> false
end;
_ -> false
Expand Down
2 changes: 1 addition & 1 deletion src/auth/mongoose_gen_auth.erl
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
User :: jid:luser(),
Server :: jid:lserver(),
Password :: binary()) ->
ok | {error, not_allowed | invalid_jid}.
ok | {error, not_allowed | invalid_jid | user_not_found}.

-callback remove_user(HostType :: mongooseim:host_type(),
User :: jid:luser(),
Expand Down
5 changes: 4 additions & 1 deletion src/eldap_pool.erl
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ delete(PoolName, DN) ->
R -> R
end.

%% Applies eldap:add/3
add(PoolName, DN, Attrs) ->
do_request(PoolName, {add, [maybe_b2list(DN), parse_add_atrs(Attrs)]}).

Expand All @@ -92,5 +93,7 @@ parse_add_attr({N, List}) ->
%% Internal functions
%%====================================================================

do_request({Host, PoolTag}, Request) ->
%% Calls mongoose_ldap_worker
%% Which calls eldap:F
do_request({Host, PoolTag}, {_F, _Args} = Request) ->
mongoose_wpool:call(ldap, Host, PoolTag, Request).
10 changes: 10 additions & 0 deletions src/eldap_utils.erl
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@
-include("mongoose.hrl").
-include("eldap.hrl").

-type dn() :: binary().
-type deref() :: neverDerefAliases | derefInSearching
| derefFindingBaseObj | derefAlways.
%% Used to access mongoose_wpool
-type eldap_id() :: {HostType :: mongooseim:host_type(), Tag :: mongoose_wpool:tag()}.

-export_type([dn/0,
deref/0,
eldap_id/0]).

%% @doc Generate an 'or' LDAP query on one or several attributes
%% If there is only one attribute
-spec generate_subfilter([{binary()} | {binary(), binary()}]) -> binary().
Expand Down
51 changes: 25 additions & 26 deletions src/mod_shared_roster_ldap.erl
Original file line number Diff line number Diff line change
Expand Up @@ -61,24 +61,21 @@
-define(LDAP_SEARCH_TIMEOUT, 5).

-record(state,
{host = <<"">> :: binary(),
eldap_id :: {jid:lserver(), binary()},
base = <<"">> :: binary(),
uid = <<"">> :: binary(),
deref = neverDerefAliases :: neverDerefAliases |
derefInSearching |
derefFindingBaseObj |
derefAlways,
group_attr = <<"">> :: binary(),
group_desc = <<"">> :: binary(),
user_desc = <<"">> :: binary(),
user_uid = <<"">> :: binary(),
uid_format = <<"">> :: binary(),
uid_format_re = <<"">> :: binary(),
filter = <<"">> :: binary(),
ufilter = <<"">> :: binary(),
rfilter = <<"">> :: binary(),
gfilter = <<"">> :: binary(),
{host = <<>> :: binary(),
eldap_id :: eldap_utils:eldap_id(),
base = <<>> :: binary(),
uid = <<>> :: binary(),
deref = neverDerefAliases :: eldap_utils:deref(),
group_attr = <<>> :: binary(),
group_desc = <<>> :: binary(),
user_desc = <<>> :: binary(),
user_uid = <<>> :: binary(),
uid_format = <<>> :: binary(),
uid_format_re = <<>> :: binary(),
filter = <<>> :: binary(),
ufilter = <<>> :: binary(),
rfilter = <<>> :: binary(),
gfilter = <<>> :: binary(),
auth_check = true :: boolean(),
user_cache_size = ?CACHE_SIZE :: non_neg_integer(),
group_cache_size = ?CACHE_SIZE :: non_neg_integer(),
Expand Down Expand Up @@ -189,7 +186,7 @@ get_subscription_lists(Acc, #jid{lserver = LServer} = JID) ->
get_group_users(LServer, Group)
end,
DisplayedGroups)),
SRJIDs = [{U1, S1, <<"">>} || {U1, S1} <- SRUsers],
SRJIDs = [{U1, S1, <<>>} || {U1, S1} <- SRUsers],
NewLists = {lists:usort(SRJIDs ++ F), lists:usort(SRJIDs ++ T), P},
mongoose_acc:set(roster, subscription_lists, NewLists, Acc).

Expand Down Expand Up @@ -351,13 +348,8 @@ get_user_to_groups_map({_, Server} = US, SkipUS) ->
eldap_search(State, FilterParseArgs, AttributesList) ->
case apply(eldap_filter, parse, FilterParseArgs) of
{ok, EldapFilter} ->
case eldap_pool:search(State#state.eldap_id,
[{base, State#state.base},
{filter, EldapFilter},
{timeout, ?LDAP_SEARCH_TIMEOUT},
{deref, State#state.deref},
{attributes, AttributesList}])
of
SearchOpts = search_opts(EldapFilter, AttributesList, State),
case eldap_pool:search(State#state.eldap_id, SearchOpts) of
#eldap_search_result{entries = Es} ->
%% A result with entries. Return their list.
Es;
Expand All @@ -370,6 +362,13 @@ eldap_search(State, FilterParseArgs, AttributesList) ->
[]
end.

search_opts(EldapFilter, AttributesList, State) ->
[{base, State#state.base},
{filter, EldapFilter},
{timeout, ?LDAP_SEARCH_TIMEOUT},
{deref, State#state.deref},
{attributes, AttributesList}].

get_user_displayed_groups({User, Host}) ->
{ok, State} = eldap_utils:get_state(Host, ?MODULE),
GroupAttr = State#state.group_attr,
Expand Down
31 changes: 15 additions & 16 deletions src/mod_vcard_ldap.erl
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,22 @@
-define(PROCNAME, ejabberd_mod_vcard_ldap).

-record(state,
{serverhost = <<"">> :: binary(),
myhost = <<"">> :: binary(),
eldap_id :: {jid:lserver(), binary()},
base = <<"">> :: binary(),
password = <<"">> :: binary(),
{serverhost = <<>> :: binary(),
myhost = <<>> :: binary(),
eldap_id :: eldap_utils:eldap_id(),
base = <<>> :: binary(),
password = <<>> :: binary(),
uids = [] :: [{binary()} | {binary(), binary()}],
vcard_map = [] :: [{binary(), binary(), [binary()]}],
vcard_map_attrs = [] :: [binary()],
user_filter = <<"">> :: binary(),
user_filter = <<>> :: binary(),
search_filter :: eldap:filter(),
search_fields = [] :: [{binary(), binary()}],
search_reported = [] :: [{binary(), binary()}],
search_reported_attrs = [] :: [binary()],
search_operator :: 'or' | 'and',
binary_search_fields :: [binary()],
deref = neverDerefAliases :: neverDerefAliases | derefInSearching
| derefFindingBaseObj | derefAlways,
deref = neverDerefAliases :: eldap_utils:deref(),
matches = 0 :: non_neg_integer() | infinity}).

-define(VCARD_MAP,
Expand Down Expand Up @@ -244,15 +243,15 @@ find_ldap_user(User, State) ->
end.

eldap_pool_search(EldapID, Base, EldapFilter, Deref, Attrs, NoResultRes) ->
case eldap_pool:search(EldapID,
SearchOpts = search_opts(Base, EldapFilter, Deref, Attrs),
case eldap_pool:search(EldapID, SearchOpts) of
#eldap_search_result{entries = E} -> E;
_ -> NoResultRes
end.

search_opts(Base, EldapFilter, Deref, Attrs) ->
[{base, Base}, {filter, EldapFilter},
{deref, Deref},
{attributes, Attrs}])
of
#eldap_search_result{entries = E} -> E;
_ ->
NoResultRes
end.
{deref, Deref}, {attributes, Attrs}].

ldap_attributes_to_vcard(Attributes, VCardMap, UD) ->
Attrs = lists:map(fun ({VCardName, _, _}) ->
Expand Down

0 comments on commit 2a6381f

Please sign in to comment.