Skip to content

Commit

Permalink
Extract common LDAP options in mod_vcard to a subsection
Browse files Browse the repository at this point in the history
  • Loading branch information
gustawlippa committed Mar 1, 2022
1 parent 0a6b32a commit e2c100b
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 171 deletions.
4 changes: 2 additions & 2 deletions big_tests/test.config
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,8 @@
filter = \"(objectClass=inetOrgPerson)\""},
{mod_vcard, " backend = \"ldap\"
host = \"vjud.@HOST@\"
ldap_base = \"ou=Users,dc=esl,dc=com\"
ldap_filter = \"(objectClass=inetOrgPerson)\"\n"}]},
ldap.base = \"ou=Users,dc=esl,dc=com\"
ldap.filter = \"(objectClass=inetOrgPerson)\"\n"}]},
{riak_mnesia,
[{dbs, [redis, riak]},
{auth_method, "riak"},
Expand Down
2 changes: 1 addition & 1 deletion big_tests/tests/ldap_helper.erl
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ get_usp(Spec) ->
{Username, Server, Password}.

get_ldap_base(Server) ->
list_to_binary(rpc(mim(), gen_mod, get_module_opt, [Server, mod_vcard, ldap_base, ""])).
rpc(mim(), gen_mod, get_module_opt, [Server, mod_vcard, [ldap, base]]).

call_ldap(Server, F, Args) ->
rpc(mim(), mongoose_wpool, call, [ldap, Server, default, {F, Args}]).
10 changes: 7 additions & 3 deletions big_tests/tests/vcard_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1189,11 +1189,15 @@ params_ldap_only(Config) ->
{<<"Organization Name">>, <<"ORGNAME">>},
{<<"Organization Unit">>, <<"ORGUNIT">>},
{<<"Photo">>, <<"PHOTO">>}],
add_backend_param(#{ldap_search_operator => 'or',
ldap_binary_search_fields => [<<"PHOTO">>],
ldap_search_reported => Reported},
add_backend_param(#{ldap => #{search_operator => 'or',
binary_search_fields => [<<"PHOTO">>],
search_reported => Reported}},
?config(mod_vcard_opts, Config)).

add_backend_param(Opts = #{ldap := LDAPOpts},
CurrentVCardConfig = #{backend := ldap, ldap := CurrentLDAPOpts}) ->
NewLDAPOpts = maps:merge(CurrentLDAPOpts, LDAPOpts),
maps:merge(CurrentVCardConfig, Opts#{ldap => NewLDAPOpts});
add_backend_param(Opts, CurrentVCardConfig) ->
maps:merge(CurrentVCardConfig, Opts).

Expand Down
15 changes: 7 additions & 8 deletions big_tests/tests/vcard_simple_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -454,14 +454,13 @@ configure_mod_vcard(Config) ->
end.

ldap_opts() ->
VCardOpts = #{backend => ldap,
host => subhost_pattern("vjud.@HOST@"),
ldap_uids => [{<<"uid">>}], %% equivalent to {<<"uid">>, <<"%u">>}
ldap_filter => <<"(objectClass=inetOrgPerson)">>,
ldap_base => "ou=Users,dc=esl,dc=com",
ldap_search_fields => [{"Full Name", "cn"}, {"User", "uid"}],
ldap_vcard_map => [{"FN", "%s", ["cn"]}]},
config_parser_helper:mod_config(mod_vcard, VCardOpts).
LDAPOpts = #{filter => <<"(objectClass=inetOrgPerson)">>,
base => "ou=Users,dc=esl,dc=com",
search_fields => [{"Full Name", "cn"}, {"User", "uid"}],
vcard_map => [{"FN", "%s", ["cn"]}]},
#{ldap := DefaultLDAPOpts} = config_parser_helper:default_mod_config(mod_vcard),
LDAPOptsWithDefaults = maps:merge(DefaultLDAPOpts, LDAPOpts),
config_parser_helper:mod_config(mod_vcard, #{ldap => LDAPOptsWithDefaults}).

ensure_started(HostType, Opts) ->
dynamic_modules:stop(HostType, mod_vcard),
Expand Down
2 changes: 2 additions & 0 deletions doc/migrations/5.0.0_5.1.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ The rules for overriding global options in the `host_config` section have been s
### Extension modules

* `mod_auth_token` has a new configuration format - if you are using this module, amend the [`validity_period`](../modules/mod_auth_token.md#modulesmod_auth_tokenvalidity_period) option.
* `mod_vcard` LDAP options are moved into an LDAP subsection.
* `shared_roster_ldap` all options have their `ldap_` prefix dropped.

## Async workers

Expand Down
52 changes: 26 additions & 26 deletions doc/modules/mod_vcard.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,46 +47,46 @@ Maximum search results to be returned to the user.

The following options are the same as for the [LDAP authentication module](../authentication-methods/ldap.md#configuration-options):

* #### [`modules.mod_vcard.ldap_pool_tag`](../authentication-methods/ldap.md#authldappool_tag)
* #### [`modules.mod_vcard.ldap_base`](../authentication-methods/ldap.md#authldapbase)
* #### [`modules.mod_vcard.ldap_uids`](../authentication-methods/ldap.md#authldapuids)
* #### [`modules.mod_vcard.ldap_filter`](../authentication-methods/ldap.md#authldapfilter)
* #### [`modules.mod_vcard.ldap_deref`](../authentication-methods/ldap.md#authldapderef)
* #### [`modules.mod_vcard.ldap.pool_tag`](../authentication-methods/ldap.md#authldappool_tag)
* #### [`modules.mod_vcard.ldap.base`](../authentication-methods/ldap.md#authldapbase)
* #### [`modules.mod_vcard.ldap.uids`](../authentication-methods/ldap.md#authldapuids)
* #### [`modules.mod_vcard.ldap.filter`](../authentication-methods/ldap.md#authldapfilter)
* #### [`modules.mod_vcard.ldap.deref`](../authentication-methods/ldap.md#authldapderef)

#### `modules.mod_vcard.ldap_vcard_map`
#### `modules.mod_vcard.ldap.vcard_map`
* **Syntax:** Array of TOML tables with the following keys: `"vcard_field"`, `"ldap_pattern"`, `"ldap_field"` and string values.
* **Default:** see description
* **Example:** `ldap_vcard_map = [{vcard_field = "FN", ldap_pattern = "%s", ldap_field = "displayName"}]`
* **Example:** `vcard_map = [{vcard_field = "FN", ldap_pattern = "%s", ldap_field = "displayName"}]`

Mappings between VCard and LDAP fields. For the default settings, please see `[MongooseIM root]/src/mod_vcard_ldap.erl`.

#### `modules.mod_vcard.ldap_search_fields`
#### `modules.mod_vcard.ldap.search_fields`
* **Syntax:** Array of TOML tables with the following keys: `"search_field"`, `"ldap_field"` and string values.
* **Default:** see description
* **Example:** `ldap_search_fields = [{search_field = "User", ldap_field = "%u"}]`
* **Example:** `search_fields = [{search_field = "User", ldap_field = "%u"}]`

Mappings between the human-readable search fields and LDAP fields.
For the default settings, please see `[MongooseIM root]/src/mod_vcard_ldap.erl`.

#### `modules.mod_vcard.ldap_search_reported`
#### `modules.mod_vcard.ldap.search_reported`
* **Syntax:** Array of TOML tables with the following keys: `"search_field"`, `"vcard_field"` and string values.
* **Default:** see description
* **Example:** `ldap_search_reported = [{search_field = "Full Name", vcard_field = "FN"}]`
* **Example:** `search_reported = [{search_field = "Full Name", vcard_field = "FN"}]`

Mappings between the human-readable search fields and VCard fields.
For the default settings, please see `[MongooseIM root]/src/mod_vcard_ldap.erl`.

#### `modules.mod_vcard.ldap_search_operator`
#### `modules.mod_vcard.ldap.search_operator`
* **Syntax:** string, one of `"or"`, `"and"`
* **Default:** `"and"`
* **Example:** `ldap_search_operator = "or"`
* **Example:** `search_operator = "or"`

A default operator used for search query items.

#### `modules.mod_vcard.ldap_binary_search_fields`
#### `modules.mod_vcard.ldap.binary_search_fields`
* **Syntax:** array of strings
* **Default:** `[]`
* **Example:** `ldap_binary_search_fields = ["User", "Full Name"]`
* **Example:** `binary_search_fields = ["User", "Full Name"]`

An array of search fields, which values should be Base64-encoded by MongooseIM before sending to LDAP.

Expand Down Expand Up @@ -114,29 +114,29 @@ Riak index name.
search = true
host = "directory.example.com"

[[modules.mod_vcard.ldap_vcard_map]]
[[modules.mod_vcard.ldap.vcard_map]]
vcard_field = "FAMILY"
ldap_pattern = "%s"
ldap_field = "sn"

[[modules.mod_vcard.ldap_vcard_map]]
[[modules.mod_vcard.ldap.vcard_map]]
vcard_field = "FN"
ldap_pattern = "%s"
ldap_field = "displayName"

[[modules.mod_vcard.ldap_search_fields]]
[[modules.mod_vcard.ldap.search_fields]]
search_field = "User"
ldap_field = "%u"

[[modules.mod_vcard.ldap_search_fields]]
[[modules.mod_vcard.ldap.search_fields]]
search_field = "Full Name"
ldap_field = "displayName"

[[modules.mod_vcard.ldap_search_reported]]
[[modules.mod_vcard.ldap.search_reported]]
search_field = "Full Name"
vcard_field = "FN"

[[modules.mod_vcard.ldap_search_reported]]
[[modules.mod_vcard.ldap.search_reported]]
search_field = "Given Name"
vcard_field = "FIRST"
```
Expand All @@ -145,8 +145,8 @@ Riak index name.

If you'd like to learn more about metrics in MongooseIM, please visit [MongooseIM metrics](../operation-and-maintenance/MongooseIM-metrics.md) page.

| Backend action | Description (when it gets incremented) |
| ---- | -------------------------------------- |
| `set_vcard` | A vCard is set in a DB. |
| `get_vcard` | A specific vCard is retrieved from a DB. |
| `search` | A vCard search is performed. |
| Backend action | Description (when it gets incremented) |
|----------------|------------------------------------------|
| `set_vcard` | A vCard is set in a DB. |
| `get_vcard` | A specific vCard is retrieved from a DB. |
| `search` | A vCard search is performed. |
18 changes: 0 additions & 18 deletions src/eldap_utils.erl
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,7 @@
get_state/2,
case_insensitive_match/2,
get_mod_opt/4,
get_base/1,
get_deref_aliases/1,
deref_aliases/1,
get_uids/2,
get_user_filter/2,
process_user_filter/2,
get_search_filter/1,
decode_octet_string/3,
Expand Down Expand Up @@ -249,25 +245,11 @@ prepare_opt_val(Opt, Val, F, Default) ->
Res
end.

get_base(Opts) ->
get_mod_opt(ldap_base, Opts, fun iolist_to_binary/1, <<"">>).

get_deref_aliases(Opts) ->
get_mod_opt(ldap_deref, Opts, fun deref_aliases/1, neverDerefAliases).

deref_aliases(never) -> neverDerefAliases;
deref_aliases(searching) -> derefInSearching;
deref_aliases(finding) -> derefFindingBaseObj;
deref_aliases(always) -> derefAlways.

get_uids(Host, Opts) ->
UIDsTemp = get_mod_opt(ldap_uids, Opts, fun(V) -> V end, [{<<"uid">>, <<"%u">>}]),
uids_domain_subst(Host, UIDsTemp).

get_user_filter(UIDs, Opts) ->
RawUserFilter = get_mod_opt(ldap_filter, Opts, fun(V) -> V end, <<>>),
process_user_filter(UIDs, RawUserFilter).

process_user_filter(UIDs, RawUserFilter) ->
SubFilter = generate_subfilter(UIDs),
case RawUserFilter of
Expand Down
51 changes: 27 additions & 24 deletions src/vcard/mod_vcard.erl
Original file line number Diff line number Diff line change
Expand Up @@ -221,39 +221,39 @@ config_spec() ->
validate = {module, mod_vcard}},
<<"matches">> => #option{type = int_or_infinity,
validate = non_negative},
<<"ldap_pool_tag">> => #option{type = atom,
validate = pool_name},
<<"ldap_base">> => #option{type = string},
<<"ldap_uids">> => #list{items = mongoose_ldap_config:uids()},
<<"ldap_filter">> => #option{type = binary},
<<"ldap_deref">> => #option{type = atom,
validate = {enum, [never, always, finding, searching]}},
<<"ldap_vcard_map">> => #list{items = ldap_vcard_map_spec()},
<<"ldap_search_fields">> => #list{items = ldap_search_fields_spec()},
<<"ldap_search_reported">> => #list{items = ldap_search_reported_spec()},
<<"ldap_search_operator">> => #option{type = atom,
validate = {enum, ['or', 'and']}},
<<"ldap_binary_search_fields">> => #list{items = #option{type = binary,
validate = non_empty}},
<<"ldap">> => ldap_section(),
<<"riak">> => riak_config_spec()
},
defaults = #{<<"iqdisc">> => parallel,
<<"host">> => mongoose_subdomain_utils:make_subdomain_pattern("vjud.@HOST@"),
<<"search">> => true,
<<"backend">> => mnesia,
<<"matches">> => 30,
<<"ldap_pool_tag">> => default,
<<"ldap_uids">> => [{<<"uid">>, <<"%u">>}],
<<"ldap_vcard_map">> => mod_vcard_ldap:default_vcard_map(),
<<"ldap_search_fields">> => mod_vcard_ldap:default_search_fields(),
<<"ldap_search_reported">> => mod_vcard_ldap:default_search_reported(),
<<"ldap_search_operator">> => 'and',
<<"ldap_binary_search_fields">> => []
<<"matches">> => 30
},
format_items = map,
process = fun remove_unused_backend_opts/1
}.

ldap_section() ->
CommonLDAPSpec = mongoose_ldap_config:spec(),
Items = #{
<<"uids">> => #list{items = mongoose_ldap_config:uids()},
<<"vcard_map">> => #list{items = ldap_vcard_map_spec()},
<<"search_fields">> => #list{items = ldap_search_fields_spec()},
<<"search_reported">> => #list{items = ldap_search_reported_spec()},
<<"search_operator">> => #option{type = atom,
validate = {enum, ['or', 'and']}},
<<"binary_search_fields">> => #list{items = #option{type = binary,
validate = non_empty}}},
Defaults = #{<<"uids">> => [{<<"uid">>, <<"%u">>}],
<<"vcard_map">> => mod_vcard_ldap:default_vcard_map(),
<<"search_fields">> => mod_vcard_ldap:default_search_fields(),
<<"search_reported">> => mod_vcard_ldap:default_search_reported(),
<<"search_operator">> => 'and',
<<"binary_search_fields">> => []},
CommonLDAPSpec#section{items = maps:merge(CommonLDAPSpec#section.items, Items),
defaults = maps:merge(CommonLDAPSpec#section.defaults, Defaults)}.

ldap_vcard_map_spec() ->
#section{
items = #{<<"vcard_field">> => #option{type = binary,
Expand Down Expand Up @@ -317,8 +317,11 @@ process_search_reported_spec(KVs) ->
proplists:split(KVs, [search_field, vcard_field]),
{SF, VF}.

remove_unused_backend_opts(Opts = #{backend := riak}) -> Opts;
remove_unused_backend_opts(Opts) -> maps:remove(riak, Opts).
remove_unused_backend_opts(Opts = #{backend := riak}) -> maps:remove(ldap, Opts);
remove_unused_backend_opts(Opts = #{backend := ldap}) -> maps:remove(riak, Opts);
remove_unused_backend_opts(Opts) ->
M = maps:remove(riak, Opts),
maps:remove(ldap, M).

%%--------------------------------------------------------------------
%% mongoose_packet_handler callbacks for search
Expand Down
67 changes: 24 additions & 43 deletions src/vcard/mod_vcard_ldap.erl
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@
%%%
%%%----------------------------------------------------------------------

%%TODO gen_server is created only to store the state
%% and create/destroy pool, should it be replaced ?

-module(mod_vcard_ldap).
-author('[email protected]').

Expand Down Expand Up @@ -142,11 +139,11 @@ get_vcard(HostType, LUser, LServer) ->
JID = jid:make(LUser, LServer, <<>>),
case ejabberd_auth:does_user_exist(JID) of
true ->
VCardMap = State#state.vcard_map,
case find_ldap_user(LUser, State) of
#eldap_entry{attributes = Attributes} ->
Vcard = ldap_attributes_to_vcard(Attributes, VCardMap, {LUser, LServer}),
{ok, Vcard};
VCardMap = State#state.vcard_map,
VCard = ldap_attributes_to_vcard(Attributes, VCardMap, {LUser, LServer}),
{ok, VCard};
_ ->
{ok, []}
end;
Expand Down Expand Up @@ -437,43 +434,29 @@ get_state(HostType, LServer) ->

create_state(HostType, LServer) ->
Opts = gen_mod:get_loaded_module_opts(HostType, mod_vcard),
Val = gen_mod:get_opt(host, Opts),
MyHost = mongoose_subdomain_utils:get_fqdn(Val, LServer),
Matches = gen_mod:get_opt(matches, Opts),
EldapID = gen_mod:get_opt(ldap_pool_tag, Opts),
Base = eldap_utils:get_base(Opts),
DerefAliases = eldap_utils:get_deref_aliases(Opts),
UIDs = eldap_utils:get_uids(LServer, Opts),
UserFilter = eldap_utils:get_user_filter(UIDs, Opts),
{ok, SearchFilter} =
eldap_filter:parse(eldap_utils:get_search_filter(UserFilter)),
VCardMap = eldap_utils:get_mod_opt(ldap_vcard_map, Opts,
fun(Ls) ->
lists:map(
fun({S, P, L}) ->
{iolist_to_binary(S),
iolist_to_binary(P),
[iolist_to_binary(E)
|| E <- L]}
end, Ls)
end, ?VCARD_MAP),
SearchFields = eldap_utils:get_mod_opt(ldap_search_fields, Opts,
fun(Ls) ->
[{iolist_to_binary(S),
iolist_to_binary(P)}
|| {S, P} <- Ls]
end, ?SEARCH_FIELDS),
SearchReported = eldap_utils:get_mod_opt(ldap_search_reported, Opts,
fun(Ls) ->
[{iolist_to_binary(S),
iolist_to_binary(P)}
|| {S, P} <- Ls]
end, ?SEARCH_REPORTED),
Host = gen_mod:get_opt(host, Opts),
LDAPOpts = gen_mod:get_opt(ldap, Opts),
#{pool_tag := PoolTag,
base := Base,
deref := Deref,
uids := RawUIDs,
filter := RawUserFilter,
vcard_map := VCardMap,
search_fields := SearchFields,
search_reported := SearchReported,
search_operator := SearchOperator,
binary_search_fields := BinaryFields} = LDAPOpts,
MyHost = mongoose_subdomain_utils:get_fqdn(Host, LServer),
DerefAliases = eldap_utils:deref_aliases(Deref),
UIDs = eldap_utils:uids_domain_subst(LServer, RawUIDs),
UserFilter = eldap_utils:process_user_filter(UIDs, RawUserFilter),
{ok, SearchFilter} = eldap_filter:parse(eldap_utils:get_search_filter(UserFilter)),

UIDAttrs = lists:map(fun({UID, _}) -> UID;
({UID}) -> UID end, UIDs),
VCardMapAttrs = lists:usort(lists:append([A
|| {_, _, A} <- VCardMap])
++ UIDAttrs),
VCardMapAttrs = lists:usort(lists:append([A || {_, _, A} <- VCardMap])
++ UIDAttrs),
SearchReportedAttrs = lists:usort(lists:flatmap(
fun ({_, N}) ->
case lists:keysearch(N, 1, VCardMap) of
Expand All @@ -483,11 +466,9 @@ create_state(HostType, LServer) ->
end
end,
SearchReported) ++ UIDAttrs),
SearchOperator = gen_mod:get_opt(ldap_search_operator, Opts),
BinaryFields = gen_mod:get_opt(ldap_binary_search_fields, Opts),
#state{serverhost = LServer,
myhost = MyHost,
eldap_id = {HostType, EldapID},
eldap_id = {HostType, PoolTag},
base = Base,
deref = DerefAliases,
uids = UIDs, vcard_map = VCardMap,
Expand Down
Loading

0 comments on commit e2c100b

Please sign in to comment.