diff --git a/big_tests/run_common_test.erl b/big_tests/run_common_test.erl index f6a0bd59634..97bc316eb1c 100644 --- a/big_tests/run_common_test.erl +++ b/big_tests/run_common_test.erl @@ -179,7 +179,7 @@ run_test(Test, PresetsToRun, CoverOpts) -> end, Presets) end, Length = length(Presets1), - Names = preset_names(Presets), + Names = preset_names(Presets1), error_logger:info_msg("Starting test of ~p configurations: ~n~p~n", [Length, Names]), Zip = lists:zip(lists:seq(1, Length), Presets1), diff --git a/big_tests/test.config b/big_tests/test.config index f0fe52640af..b3442e46018 100644 --- a/big_tests/test.config +++ b/big_tests/test.config @@ -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"}, diff --git a/big_tests/tests/ldap_helper.erl b/big_tests/tests/ldap_helper.erl index fd332de6aec..84351fb856f 100644 --- a/big_tests/tests/ldap_helper.erl +++ b/big_tests/tests/ldap_helper.erl @@ -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}]). diff --git a/big_tests/tests/shared_roster_SUITE.erl b/big_tests/tests/shared_roster_SUITE.erl index 7f8d4e2aeec..f6bd9b861a9 100644 --- a/big_tests/tests/shared_roster_SUITE.erl +++ b/big_tests/tests/shared_roster_SUITE.erl @@ -23,7 +23,7 @@ require_rpc_nodes/1, rpc/4]). --import(domain_helper, [domain/0]). +-import(domain_helper, [host_type/0]). %%-------------------------------------------------------------------- %% Suite configuration @@ -47,7 +47,7 @@ suite() -> %%-------------------------------------------------------------------- init_per_suite(Config0) -> - Config = dynamic_modules:save_modules(domain(), Config0), + Config = dynamic_modules:save_modules(host_type(), Config0), case get_auth_method() of ldap -> start_roster_module(ldap), @@ -141,29 +141,29 @@ add_user(Config) -> %%-------------------------------------------------------------------- start_roster_module(ldap) -> - dynamic_modules:ensure_modules(domain(), [{mod_shared_roster_ldap, get_ldap_args()}]); + dynamic_modules:ensure_modules(host_type(), [{mod_shared_roster_ldap, get_ldap_opts()}]); start_roster_module(_) -> ok. get_auth_method() -> - XMPPDomain = domain(), - case rpc(mim(), mongoose_config, get_opt, [[{auth, XMPPDomain}, methods], []]) of + HT = host_type(), + case rpc(mim(), mongoose_config, get_opt, [[{auth, HT}, methods], []]) of [Method|_] -> Method; _ -> none end. -get_ldap_args() -> - [ - {ldap_base, "ou=Users,dc=esl,dc=com"}, - {ldap_groupattr, "ou"}, - {ldap_memberattr, "cn"},{ldap_userdesc, "cn"}, - {ldap_filter, "(objectClass=inetOrgPerson)"}, - {ldap_rfilter, "(objectClass=inetOrgPerson)"}, - {ldap_group_cache_validity, 1}, - {ldap_user_cache_validity, 1} - ]. +get_ldap_opts() -> + Opts = #{base => <<"ou=Users,dc=esl,dc=com">>, + groupattr => <<"ou">>, + memberattr => <<"cn">>, + userdesc => <<"cn">>, + filter => <<"(objectClass=inetOrgPerson)">>, + rfilter => <<"(objectClass=inetOrgPerson)">>, + group_cache_validity => 1, + user_cache_validity => 1}, + maps:merge(config_parser_helper:default_mod_config(mod_shared_roster_ldap), Opts). no_stanzas(Users) -> lists:foreach(fun escalus_assert:has_no_stanzas/1, Users). diff --git a/big_tests/tests/vcard_SUITE.erl b/big_tests/tests/vcard_SUITE.erl index 374bd12a747..18fcc7c21a0 100644 --- a/big_tests/tests/vcard_SUITE.erl +++ b/big_tests/tests/vcard_SUITE.erl @@ -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). diff --git a/big_tests/tests/vcard_simple_SUITE.erl b/big_tests/tests/vcard_simple_SUITE.erl index bc6f8cae079..080d1cfa3c2 100644 --- a/big_tests/tests/vcard_simple_SUITE.erl +++ b/big_tests/tests/vcard_simple_SUITE.erl @@ -454,14 +454,12 @@ 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"]}]}, + LDAPOptsWithDefaults = config_parser_helper:config([modules, mod_vcard, ldap], LDAPOpts), + config_parser_helper:mod_config(mod_vcard, #{backend => ldap, ldap => LDAPOptsWithDefaults}). ensure_started(HostType, Opts) -> dynamic_modules:stop(HostType, mod_vcard), diff --git a/doc/migrations/5.0.0_5.1.0.md b/doc/migrations/5.0.0_5.1.0.md index 8ec7b08e6eb..959734ec443 100644 --- a/doc/migrations/5.0.0_5.1.0.md +++ b/doc/migrations/5.0.0_5.1.0.md @@ -28,6 +28,8 @@ The rules for overriding global options in the `host_config` section have been s * `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_mam_meta` does not have the `rdbms_message_format` and `simple` options anymore. Use [`db_jid_format`](../modules/mod_mam.md#modulesmod_mam_metadb_jid_format) and [`db_message_format`](../modules/mod_mam.md#modulesmod_mam_metadb_message_format) instead. +* `mod_vcard` LDAP options are moved into an LDAP subsection. +* `mod_shared_roster_ldap` all options have their `ldap_` prefix dropped. ## Async workers diff --git a/doc/modules/mod_shared_roster_ldap.md b/doc/modules/mod_shared_roster_ldap.md index 3a6f1d40d6e..bfa3799b639 100644 --- a/doc/modules/mod_shared_roster_ldap.md +++ b/doc/modules/mod_shared_roster_ldap.md @@ -1,137 +1,134 @@ ## Module Description -This module, when enabled, will inject roster entries fetched from LDAP. -It might get quite complicated to configure it properly, so fasten your seatbelts and prepare for a ride. - -When a default value for an option is defined with "top-level/XXX", it means that the default value is equal to a top-level parameter in `mongooseim.toml` of the same name. -If it is not defined, XXX becomes the default value. +This module injects roster entries fetched from LDAP. +It might get quite complicated to configure it properly, so proceed with caution. !!! warning This module does not support [dynamic domains](../configuration/general.md#generalhost_types). ## Options: general -### `modules.mod_shared_roster_ldap.ldap_pool_tag` -### `modules.mod_shared_roster_ldap.ldap_base` -### `modules.mod_shared_roster_ldap.ldap_deref` +### `modules.mod_shared_roster_ldap.pool_tag` +### `modules.mod_shared_roster_ldap.base` +### `modules.mod_shared_roster_ldap.deref` These 3 options are the same as for the [LDAP authentication module](../authentication-methods/ldap.md#configuration-options). ## Options: attributes -### `modules.mod_shared_roster_ldap.ldap_groupattr` +### `modules.mod_shared_roster_ldap.groupattr` * **Syntax:** string * **Default:** `"cn"` -* **Example:** `ldap_groupattr = "cn"` +* **Example:** `groupattr = "cn"` Provides a group name. -### `modules.mod_shared_roster_ldap.ldap_groupdesc` +### `modules.mod_shared_roster_ldap.groupdesc` * **Syntax:** string -* **Default:** the value of `ldap_groupattr` -* **Example:** `ldap_groupdesc = "cn"` +* **Default:** the value of `groupattr` +* **Example:** `groupdesc = "cn"` Provides a group description. -### `modules.mod_shared_roster_ldap.ldap_userdesc` +### `modules.mod_shared_roster_ldap.userdesc` * **Syntax:** string * **Default:** `"cn"` -* **Example:** `ldap_userdesc = "cn"` +* **Example:** `userdesc = "cn"` Provides a human-readable user name. -### `modules.mod_shared_roster_ldap.ldap_useruid` +### `modules.mod_shared_roster_ldap.useruid` * **Syntax:** string * **Default:** `"cn"` -* **Example:** `ldap_useruid = "cn"` +* **Example:** `useruid = "cn"` Provides a username. -### `modules.mod_shared_roster_ldap.ldap_memberattr` +### `modules.mod_shared_roster_ldap.memberattr` * **Syntax:** string * **Default:** `"memberUid"` -* **Example:** `ldap_memberattr = "memberUid"` +* **Example:** `memberattr = "memberUid"` Holds group members' IDs. -### `modules.mod_shared_roster_ldap.ldap_memberattr_format` +### `modules.mod_shared_roster_ldap.memberattr_format` * **Syntax:** string * **Default:** `"%u"` -* **Example:** `ldap_memberattr_format = "%u"` +* **Example:** `memberattr_format = "%u"` Simple LDAP expression for extracting a user ID. -### `modules.mod_shared_roster_ldap.ldap_memberattr_format_re` +### `modules.mod_shared_roster_ldap.memberattr_format_re` * **Syntax:** string * **Default:** `""` -* **Example:** `ldap_memberattr_format_re = ""` +* **Example:** `memberattr_format_re = ""` Allows extracting the user ID with a regular expression. ## Options: parameters -### `modules.mod_shared_roster_ldap.ldap_auth_check` +### `modules.mod_shared_roster_ldap.auth_check` * **Syntax:** boolean * **Default:** `true` -* **Example:** `ldap_auth_check = true` +* **Example:** `auth_check = true` Enables checking if a shared roster entry actually exists in the XMPP database. -### `modules.mod_shared_roster_ldap.ldap_user_cache_validity` +### `modules.mod_shared_roster_ldap.user_cache_validity` * **Syntax:** positive integer -* **Default:** top-level/`300` -* **Example:** `ldap_user_cache_validity = 300` +* **Default:** `300` +* **Example:** `user_cache_validity = 300` Specifies in seconds how long are the roster entries kept in the cache. -### `modules.mod_shared_roster_ldap.ldap_group_cache_validity` +### `modules.mod_shared_roster_ldap.group_cache_validity` * **Syntax:** positive integer -* **Default:** top-level/`300` -* **Example:** `ldap_group_cache_validity = 300` +* **Default:** `300` +* **Example:** `group_cache_validity = 300` Specifies in seconds how long is the user's membership in a group kept in the cache. -### `modules.mod_shared_roster_ldap.ldap_user_cache_size` +### `modules.mod_shared_roster_ldap.user_cache_size` * **Syntax:** positive integer -* **Default:** top-level/`1000` -* **Example:** `ldap_user_cache_size = 1000` +* **Default:** `1000` +* **Example:** `user_cache_size = 1000` Specifies how many shared roster items are kept in the cache. -### `modules.mod_shared_roster_ldap.ldap_group_cache_size` +### `modules.mod_shared_roster_ldap.group_cache_size` * **Syntax:** positive integer -* **Default:** top-level/`1000` -* **Example:** `ldap_group_cache_size = 1000` +* **Default:** `1000` +* **Example:** `group_cache_size = 1000` Specifies how many roster group entries are kept in cache. ## Options: LDAP filters -### `modules.mod_shared_roster_ldap.ldap_rfilter` +### `modules.mod_shared_roster_ldap.rfilter` * **Syntax:** string -* **Default:** top-level/`""` -* **Example:** `ldap_rfilter = "(objectClass=inetOrgPerson)"` +* **Default:** `""` +* **Example:** `rfilter = ""` Used to find names of all shared roster groups. -### `modules.mod_shared_roster_ldap.ldap_gfilter` +### `modules.mod_shared_roster_ldap.gfilter` * **Syntax:** string -* **Default:** top-level/`""` -* **Example:** `ldap_gfilter = ""` +* **Default:** `""` +* **Example:** `gfilter = ""` Used for retrieving the human-readable name and the members of a group. -### `modules.mod_shared_roster_ldap.ldap_ufilter` +### `modules.mod_shared_roster_ldap.ufilter` * **Syntax:** string -* **Default:** top-level/`""` -* **Example:** `ldap_ufilter = ""` +* **Default:** `""` +* **Example:** `ufilter = ""` Used for retrieving the human-readable name of the roster entries. -### `modules.mod_shared_roster_ldap.ldap_filter` +### `modules.mod_shared_roster_ldap.filter` * **Syntax:** string -* **Default:** top-level/`""` -* **Example:** `ldap_filter = "(objectClass=inetOrgPerson)"` +* **Default:** `""` +* **Example:** `filter = "(objectClass=inetOrgPerson)"` Filter AND-ed with previous filters. @@ -139,12 +136,12 @@ Filter AND-ed with previous filters. ```toml [modules.mod_shared_roster_ldap] - ldap_base = "ou=Users,dc=ejd,dc=com" - ldap_groupattr = "ou" - ldap_memberattr = "cn" - ldap_userdesc = "cn" - ldap_filter = "(objectClass=inetOrgPerson)" - ldap_rfilter = "(objectClass=inetOrgPerson)" - ldap_group_cache_validity = 1 - ldap_user_cache_validity = 1 + base = "ou=Users,dc=ejd,dc=com" + groupattr = "ou" + memberattr = "cn" + userdesc = "cn" + filter = "(objectClass=inetOrgPerson)" + rfilter = "(objectClass=inetOrgPerson)" + group_cache_validity = 1 + user_cache_validity = 1 ``` diff --git a/doc/modules/mod_vcard.md b/doc/modules/mod_vcard.md index 623259eb9b6..20e4b25487f 100644 --- a/doc/modules/mod_vcard.md +++ b/doc/modules/mod_vcard.md @@ -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. @@ -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" ``` @@ -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. | diff --git a/include/mod_vcard.hrl b/include/mod_vcard.hrl index bacb5c02a5e..6e7daee6b6a 100644 --- a/include/mod_vcard.hrl +++ b/include/mod_vcard.hrl @@ -12,6 +12,8 @@ orgname, lorgname, orgunit, lorgunit}). -record(vcard, {us, vcard}). +-type vcard_search() :: #vcard_search{}. +-export_type([vcard_search/0]). -define(TLFIELD(Type, Label, Var), #xmlel{name = <<"field">>, diff --git a/src/auth/ejabberd_auth_ldap.erl b/src/auth/ejabberd_auth_ldap.erl index bea0091316a..585d7a7275d 100644 --- a/src/auth/ejabberd_auth_ldap.erl +++ b/src/auth/ejabberd_auth_ldap.erl @@ -102,30 +102,19 @@ stop(HostType) -> -spec config_spec() -> mongoose_config_spec:config_section(). config_spec() -> - #section{ - items = #{<<"pool_tag">> => #option{type = atom, - validate = non_empty}, - <<"bind_pool_tag">> => #option{type = atom, - validate = non_empty}, - <<"base">> => #option{type = binary}, - <<"uids">> => #list{items = mongoose_ldap_config:uids()}, - <<"filter">> => #option{type = binary, - validate = ldap_filter}, - <<"dn_filter">> => mongoose_ldap_config:dn_filter(), - <<"local_filter">> => mongoose_ldap_config:local_filter(), - <<"deref">> => #option{type = atom, - validate = {enum, [never, always, finding, searching]}} - }, - defaults = #{<<"pool_tag">> => default, - <<"bind_pool_tag">> => bind, - <<"base">> => <<>>, - <<"uids">> => [{<<"uid">>, <<"%u">>}], - <<"filter">> => <<>>, - <<"dn_filter">> => {undefined, []}, - <<"local_filter">> => undefined, - <<"deref">> => never}, - format_items = map - }. + CommonLDAPSpec = mongoose_ldap_config:spec(), + Items = #{<<"bind_pool_tag">> => #option{type = atom, + validate = non_empty}, + <<"uids">> => #list{items = mongoose_ldap_config:uids()}, + <<"dn_filter">> => mongoose_ldap_config:dn_filter(), + <<"local_filter">> => mongoose_ldap_config:local_filter()}, + Defaults = #{<<"bind_pool_tag">> => bind, + <<"base">> => <<>>, + <<"uids">> => [{<<"uid">>, <<"%u">>}], + <<"dn_filter">> => {undefined, []}, + <<"local_filter">> => undefined}, + CommonLDAPSpec#section{items = maps:merge(CommonLDAPSpec#section.items, Items), + defaults = maps:merge(CommonLDAPSpec#section.defaults, Defaults)}. -spec start_link(HostType :: mongooseim:host_type()) -> {ok, pid()} | {error, any()}. start_link(HostType) -> @@ -467,17 +456,20 @@ result_attrs(#state{uids = UIDs, -spec parse_options(HostType :: mongooseim:host_type()) -> state(). parse_options(HostType) -> Opts = mongoose_config:get_opt([{auth, HostType}, ldap]), - EldapID = {HostType, maps:get(pool_tag, Opts)}, - BindEldapID = {HostType, maps:get(bind_pool_tag, Opts)}, - Base = maps:get(base, Opts), - DerefAliases = eldap_utils:deref_aliases(maps:get(deref, Opts)), - RawUIDs = maps:get(uids, Opts), + #{pool_tag := PoolTag, + bind_pool_tag := BindPoolTag, + base := Base, + deref := Deref, + uids := RawUIDs, + filter := RawUserFilter, + dn_filter := {DNFilter, DNFilterAttrs}, + local_filter := LocalFilter} = Opts, + EldapID = {HostType, PoolTag}, + BindEldapID = {HostType, BindPoolTag}, + DerefAliases = eldap_utils:deref_aliases(Deref), UIDs = eldap_utils:uids_domain_subst(HostType, RawUIDs), - RawUserFilter = maps:get(filter, Opts), UserFilter = eldap_utils:process_user_filter(UIDs, RawUserFilter), SearchFilter = eldap_utils:get_search_filter(UserFilter), - {DNFilter, DNFilterAttrs} = maps:get(dn_filter, Opts), - LocalFilter = maps:get(local_filter, Opts), #state{host_type = HostType, eldap_id = EldapID, bind_eldap_id = BindEldapID, diff --git a/src/config/mongoose_config_spec.erl b/src/config/mongoose_config_spec.erl index 3e21ea71e9b..18cf5ae4a35 100644 --- a/src/config/mongoose_config_spec.erl +++ b/src/config/mongoose_config_spec.erl @@ -620,8 +620,8 @@ outgoing_pool_connection(<<"ldap">>) -> #section{ items = #{<<"port">> => #option{type = integer, validate = port}, - <<"rootdn">> => #option{type = string}, - <<"password">> => #option{type = string}, + <<"rootdn">> => #option{type = binary}, + <<"password">> => #option{type = binary}, <<"encrypt">> => #option{type = atom, validate = {enum, [none, tls]}}, <<"servers">> => #list{items = #option{type = string}}, @@ -633,8 +633,8 @@ outgoing_pool_connection(<<"ldap">>) -> }, format_items = map, include = always, - defaults = #{<<"rootdn">> => "", - <<"password">> => "", + defaults = #{<<"rootdn">> => <<>>, + <<"password">> => <<>>, <<"encrypt">> => none, <<"servers">> => ["localhost"], <<"connect_interval">> => 10000} diff --git a/src/eldap_utils.erl b/src/eldap_utils.erl index 84dac528b77..a8c6c42a7c6 100644 --- a/src/eldap_utils.erl +++ b/src/eldap_utils.erl @@ -34,12 +34,7 @@ make_filter/3, 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, @@ -221,53 +216,11 @@ uids_domain_subst(Host, UIDs) -> end, UIDs). - --spec get_mod_opt(atom(), list(), fun(), any()) -> any(). -get_mod_opt(Key, Opts, F, Default) -> - case gen_mod:get_opt(Key, Opts, Default) of - Default -> - Default; - Val -> - prepare_opt_val(Key, Val, F, Default) - end. - --type check_fun() :: fun((any()) -> any()) | {module(), atom()}. --spec prepare_opt_val(any(), any(), check_fun(), any()) -> any(). -prepare_opt_val(Opt, Val, F, Default) -> - Res = case F of - {Mod, Fun} -> - catch Mod:Fun(Val); - _ -> - catch F(Val) - end, - case Res of - {'EXIT', _} -> - ?LOG_ERROR(#{what => configuration_error, option => Opt, - value => Val, default => Default}), - 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 diff --git a/src/mod_shared_roster_ldap.erl b/src/mod_shared_roster_ldap.erl index 57fd756c8b0..ffac8d703d2 100644 --- a/src/mod_shared_roster_ldap.erl +++ b/src/mod_shared_roster_ldap.erl @@ -72,7 +72,7 @@ user_desc = <<>> :: binary(), user_uid = <<>> :: binary(), uid_format = <<>> :: binary(), - uid_format_re = <<>> :: binary(), + uid_format_re = <<>> :: binary() | re:mp(), filter = <<>> :: binary(), ufilter = <<>> :: binary(), rfilter = <<>> :: binary(), @@ -105,34 +105,48 @@ stop(Host) -> -spec config_spec() -> mongoose_config_spec:config_section(). config_spec() -> - #section{ - items = #{<<"ldap_pool_tag">> => #option{type = atom, - validate = pool_name}, - <<"ldap_base">> => #option{type = string}, - <<"ldap_deref">> => #option{type = atom, - validate = {enum, [never, always, finding, searching]}}, - <<"ldap_groupattr">> => #option{type = string}, - <<"ldap_groupdesc">> => #option{type = string}, - <<"ldap_userdesc">> => #option{type = string}, - <<"ldap_useruid">> => #option{type = string}, - <<"ldap_memberattr">> => #option{type = string}, - <<"ldap_memberattr_format">> => #option{type = string}, - <<"ldap_memberattr_format_re">> => #option{type = string}, - <<"ldap_auth_check">> => #option{type = boolean}, - <<"ldap_user_cache_validity">> => #option{type = integer, - validate = positive}, - <<"ldap_group_cache_validity">> => #option{type = integer, - validate = positive}, - <<"ldap_user_cache_size">> => #option{type = integer, - validate = positive}, - <<"ldap_group_cache_size">> => #option{type = integer, - validate = positive}, - <<"ldap_rfilter">> => #option{type = string}, - <<"ldap_gfilter">> => #option{type = string}, - <<"ldap_ufilter">> => #option{type = string}, - <<"ldap_filter">> => #option{type = string} - } - }. + CommonLDAPSpec = mongoose_ldap_config:spec(), + Items = #{<<"groupattr">> => #option{type = binary}, + <<"groupdesc">> => #option{type = binary}, + <<"userdesc">> => #option{type = binary}, + <<"useruid">> => #option{type = binary}, + <<"memberattr">> => #option{type = binary}, + <<"memberattr_format">> => #option{type = binary}, + <<"memberattr_format_re">> => #option{type = binary}, + <<"auth_check">> => #option{type = boolean}, + <<"user_cache_validity">> => #option{type = integer, + validate = positive}, + <<"group_cache_validity">> => #option{type = integer, + validate = positive}, + <<"user_cache_size">> => #option{type = integer, + validate = positive}, + <<"group_cache_size">> => #option{type = integer, + validate = positive}, + <<"rfilter">> => #option{type = binary}, + <<"gfilter">> => #option{type = binary}, + <<"ufilter">> => #option{type = binary} + }, + Defaults = #{<<"groupattr">> => <<"cn">>, + <<"userdesc">> => <<"cn">>, + <<"useruid">> => <<"cn">>, + <<"memberattr">> => <<"memberUid">>, + <<"memberattr_format">> => <<"%u">>, + <<"memberattr_format_re">> => <<>>, + <<"auth_check">> => true, + <<"user_cache_validity">> => ?USER_CACHE_VALIDITY, + <<"group_cache_validity">> => ?GROUP_CACHE_VALIDITY, + <<"user_cache_size">> => ?CACHE_SIZE, + <<"group_cache_size">> => ?CACHE_SIZE, + <<"rfilter">> => <<>>, + <<"gfilter">> => <<>>, + <<"ufilter">> => <<>>}, + CommonLDAPSpec#section{items = maps:merge(CommonLDAPSpec#section.items, Items), + defaults = maps:merge(CommonLDAPSpec#section.defaults, Defaults), + process = fun process_ldap_options/1}. + +process_ldap_options(Opts = #{groupattr := GroupAttr}) -> + GroupDesc = maps:get(groupdesc, Opts, GroupAttr), + Opts#{groupdesc => GroupDesc}. %%-------------------------------------------------------------------- %% Hooks @@ -205,7 +219,7 @@ get_jid_info({Subscription, Groups}, _HostType, ToJID, JID) -> error -> {Subscription, Groups} end. --spec in_subscription(Acc:: mongoose_acc:t(), +-spec in_subscription(Acc :: mongoose_acc:t(), ToJID :: jid:jid(), FromJID :: jid:jid(), Type :: mod_roster:sub_presence(), @@ -220,9 +234,9 @@ in_subscription(Acc, ToJID, FromJID, Type, _Reason) -> _ -> Acc end. --spec out_subscription(Acc:: mongoose_acc:t(), +-spec out_subscription(Acc :: mongoose_acc:t(), FromJID :: jid:jid(), - ToJID ::jid:jid(), + ToJID :: jid:jid(), Type :: mod_roster:sub_presence()) -> mongoose_acc:t() | {stop, mongoose_acc:t()}. out_subscription(Acc, FromJID, ToJID, Type) -> @@ -231,7 +245,7 @@ out_subscription(Acc, FromJID, ToJID, Type) -> {stop, Acc}; {stop, false} -> {stop, Acc}; - false -> Acc + false -> Acc end. process_subscription(Direction, #jid{luser = LUser, lserver = LServer}, ToJID, _Type) -> @@ -342,7 +356,7 @@ eldap_search(State, FilterParseArgs, AttributesList) -> %% Something else. Pretend we got no results. [] end; - _-> + _ -> %% Filter parsing failed. Pretend we got no results. [] end. @@ -373,7 +387,7 @@ get_group_users(Host, Group) -> {ok, State} = eldap_utils:get_state(Host, ?MODULE), case cache_tab:dirty_lookup(shared_roster_ldap_group, {Group, Host}, - fun () -> search_group_info(State, Group) end) + fun() -> search_group_info(State, Group) end) of {ok, #group_info{members = Members}} when Members /= undefined -> @@ -385,7 +399,7 @@ get_group_name(Host, Group) -> {ok, State} = eldap_utils:get_state(Host, ?MODULE), case cache_tab:dirty_lookup(shared_roster_ldap_group, {Group, Host}, - fun () -> search_group_info(State, Group) end) + fun() -> search_group_info(State, Group) end) of {ok, #group_info{desc = GroupName}} when GroupName /= undefined -> @@ -397,7 +411,7 @@ get_user_name(User, Host) -> {ok, State} = eldap_utils:get_state(Host, ?MODULE), case cache_tab:dirty_lookup(shared_roster_ldap_user, {User, Host}, - fun () -> search_user_name(State, User) end) + fun() -> search_user_name(State, User) end) of {ok, UserName} -> UserName; error -> User @@ -420,7 +434,7 @@ search_group_info(State, Group) -> end, AuthChecker = case State#state.auth_check of true -> fun ejabberd_auth:does_user_exist/1; - _ -> fun (_U, _S) -> true end + false -> fun(_JID) -> true end end, Host = State#state.host, case eldap_search(State, @@ -432,7 +446,7 @@ search_group_info(State, Group) -> error; LDAPEntries -> {GroupDesc, MembersLists} = ldap_entries_to_group(LDAPEntries, Host, Group, State, - Extractor, AuthChecker), + Extractor, AuthChecker), {ok, #group_info{desc = GroupDesc, members = lists:usort(MembersLists)}} end. @@ -503,65 +517,27 @@ get_user_part_re(String, Pattern) -> _ -> {error, badmatch} end. -parse_options(Host, Opts) -> - EldapID = eldap_utils:get_mod_opt(ldap_pool_tag, Opts, - fun(A) when is_atom(A) -> A end, default), - Base = eldap_utils:get_base(Opts), - DerefAliases = eldap_utils:get_deref_aliases(Opts), - GroupAttr = eldap_utils:get_mod_opt(ldap_groupattr, Opts, - fun iolist_to_binary/1, - <<"cn">>), - GroupDesc = eldap_utils:get_mod_opt(ldap_groupdesc, Opts, - fun iolist_to_binary/1, - GroupAttr), - UserDesc = eldap_utils:get_mod_opt(ldap_userdesc, Opts, - fun iolist_to_binary/1, - <<"cn">>), - UserUID = eldap_utils:get_mod_opt(ldap_useruid, Opts, - fun iolist_to_binary/1, - <<"cn">>), - UIDAttr = eldap_utils:get_mod_opt(ldap_memberattr, Opts, - fun iolist_to_binary/1, - <<"memberUid">>), - UIDAttrFormat = eldap_utils:get_mod_opt(ldap_memberattr_format, Opts, - fun iolist_to_binary/1, - <<"%u">>), - UIDAttrFormatRe = eldap_utils:get_mod_opt(ldap_memberattr_format_re, Opts, - fun(S) -> - Re = iolist_to_binary(S), - {ok, MP} = re:compile(Re), - MP - end, <<"">>), - AuthCheck = eldap_utils:get_mod_opt(ldap_auth_check, Opts, - fun(false) -> false; - (true) -> true - end, true), - UserCacheValidity = eldap_utils:get_mod_opt( - ldap_user_cache_validity, Opts, - fun(I) when is_integer(I), I>0 -> I end, - ?USER_CACHE_VALIDITY), - GroupCacheValidity = eldap_utils:get_mod_opt( - ldap_group_cache_validity, Opts, - fun(I) when is_integer(I), I>0 -> I end, - ?GROUP_CACHE_VALIDITY), - UserCacheSize = eldap_utils:get_mod_opt( - ldap_user_cache_size, Opts, - fun(I) when is_integer(I), I>0 -> I end, - ?CACHE_SIZE), - GroupCacheSize = eldap_utils:get_mod_opt( - ldap_group_cache_size, Opts, - fun(I) when is_integer(I), I>0 -> I end, - ?CACHE_SIZE), - ConfigFilter = eldap_utils:get_mod_opt(ldap_filter, Opts, - fun check_filter/1, <<"">>), - ConfigUserFilter = eldap_utils:get_mod_opt(ldap_ufilter, Opts, - fun check_filter/1, <<"">>), - ConfigGroupFilter = eldap_utils:get_mod_opt(ldap_gfilter, Opts, - fun check_filter/1, <<"">>), - RosterFilter = eldap_utils:get_mod_opt(ldap_rfilter, Opts, - fun check_filter/1, <<"">>), + +parse_options(Host, #{base := Base, pool_tag := EldapID, deref := Deref, filter := FilterIn, + groupattr := GroupAttr, groupdesc := GroupDesc, userdesc := UserDesc, + useruid := UserUID, memberattr := UIDAttr, memberattr_format := UIDAttrFormat, + memberattr_format_re := UIDAttrFormatReIn, auth_check := AuthCheck, + user_cache_validity := UserCacheValidity, group_cache_validity := GroupCacheValidity, + user_cache_size := UserCacheSize, group_cache_size := GroupCacheSize, + ufilter := UFilterIn, gfilter := GFilterIn, rfilter := RFilterIn}) -> + DerefAliases = eldap_utils:deref_aliases(Deref), + ConfigFilter = check_filter(FilterIn), + ConfigUserFilter = check_filter(UFilterIn), + ConfigGroupFilter = check_filter(GFilterIn), + RosterFilter = check_filter(RFilterIn), SubFilter = <<"(&(", UIDAttr/binary, "=", UIDAttrFormat/binary, ")(", GroupAttr/binary, "=%g))">>, + UIDAttrFormatRe = case UIDAttrFormatReIn of + <<>> -> UIDAttrFormatReIn; + RE -> + {ok, MP} = re:compile(RE), + MP + end, UserSubFilter = case ConfigUserFilter of <<"">> -> eldap_filter:do_sub(SubFilter, [{<<"%g">>, <<"*">>}]); @@ -603,7 +579,7 @@ parse_options(Host, Opts) -> group_cache_size = GroupCacheSize, group_cache_validity = GroupCacheValidity}. +check_filter(<<>>) -> <<>>; check_filter(F) -> - NewF = iolist_to_binary(F), - {ok, _} = eldap_filter:parse(NewF), - NewF. + {ok, _} = eldap_filter:parse(F), + F. diff --git a/src/mongoose_ldap_config.erl b/src/mongoose_ldap_config.erl index 0cfe6b7fcaf..e1daab6e841 100644 --- a/src/mongoose_ldap_config.erl +++ b/src/mongoose_ldap_config.erl @@ -1,7 +1,8 @@ -module(mongoose_ldap_config). %% Config spec --export([uids/0, +-export([spec/0, + uids/0, dn_filter/0, local_filter/0]). @@ -12,6 +13,20 @@ -include("mongoose_config_spec.hrl"). +spec() -> + #section{ + items = #{<<"pool_tag">> => #option{type = atom, + validate = pool_name}, + <<"base">> => #option{type = binary}, + <<"deref">> => #option{type = atom, + validate = {enum, [never, always, finding, searching]}}, + <<"filter">> => #option{type = binary}}, + defaults = #{<<"pool_tag">> => default, + <<"deref">> => never, + <<"filter">> => <<>>}, + format_items = map + }. + uids() -> #section{ items = #{<<"attr">> => #option{type = binary}, diff --git a/src/mongoose_ldap_worker.erl b/src/mongoose_ldap_worker.erl index 543cf7d604a..8f0a637f536 100644 --- a/src/mongoose_ldap_worker.erl +++ b/src/mongoose_ldap_worker.erl @@ -25,7 +25,7 @@ %% gen_server callbacks --spec init(list()) -> {ok, state()}. +-spec init(gen_mod:module_opts()) -> {ok, state()}. init(Options) -> State = initial_state(Options), self() ! connect, @@ -58,33 +58,15 @@ code_change(_OldVsn, State, _Extra) -> %% internal functions -initial_state(Opts) -> - Servers = eldap_utils:get_mod_opt(servers, Opts, - fun(L) -> - lists:map(fun(H) when is_list(H) -> H end, L) - end, ["localhost"]), - Encrypt = eldap_utils:get_mod_opt(encrypt, Opts, - fun(tls) -> tls; - (none) -> none - end, none), - TLSOptions = eldap_utils:get_mod_opt(tls_options, Opts, - fun(L) when is_list(L) -> L end, []), - Port = eldap_utils:get_mod_opt(port, Opts, - fun(I) when is_integer(I), I>0 -> I end, - case Encrypt of - tls -> ?LDAPS_PORT; - starttls -> ?LDAP_PORT; - _ -> ?LDAP_PORT - end), - RootDN = eldap_utils:get_mod_opt(rootdn, Opts, - fun iolist_to_binary/1, - <<"">>), - Password = eldap_utils:get_mod_opt(password, Opts, - fun iolist_to_binary/1, - <<"">>), - ConnectInterval = eldap_utils:get_mod_opt(connect_interval, Opts, - fun(I) when is_integer(I), I>0 -> I end, - default_connect_interval()), +initial_state(Opts = #{servers := Servers, encrypt := Encrypt, rootdn := RootDN, password := Password, + connect_interval := ConnectInterval}) -> + TLSOptions = maps:get(tls_options, Opts, []), + DefaultPort = case Encrypt of + tls -> ?LDAPS_PORT; + starttls -> ?LDAP_PORT; + _ -> ?LDAP_PORT + end, + Port = maps:get(port, Opts, DefaultPort), #{handle => none, servers => Servers, encrypt => Encrypt, @@ -149,6 +131,3 @@ retry_call_eldap(Request, State) -> do_call_eldap(_Request, #{handle := none}) -> {error, not_connected}; do_call_eldap({F, Args}, #{handle := Handle}) -> apply(eldap, F, [Handle | Args]). - -default_connect_interval() -> - 10000. diff --git a/src/vcard/mod_vcard.erl b/src/vcard/mod_vcard.erl index 8e24000eff2..1fe9bbe2d5b 100644 --- a/src/vcard/mod_vcard.erl +++ b/src/vcard/mod_vcard.erl @@ -221,39 +221,40 @@ 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), + include = always}. + ldap_vcard_map_spec() -> #section{ items = #{<<"vcard_field">> => #option{type = binary, @@ -317,8 +318,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 diff --git a/src/vcard/mod_vcard_ldap.erl b/src/vcard/mod_vcard_ldap.erl index 8a8c783bcdc..a310e3b9d98 100644 --- a/src/vcard/mod_vcard_ldap.erl +++ b/src/vcard/mod_vcard_ldap.erl @@ -23,15 +23,12 @@ %%% %%%---------------------------------------------------------------------- -%%TODO gen_server is created only to store the state -%% and create/destroy pool, should it be replaced ? - -module(mod_vcard_ldap). -author('alexey@process-one.net'). -behaviour(mod_vcard_backend). -%% mod_vcards callbacks +%% mod_vcard_backend callbacks -export([init/2, tear_down/1, remove_user/3, @@ -119,31 +116,34 @@ %%-------------------------------------------------------------------- -%% mod_vcards callbacks +%% mod_vcard_backend callbacks %%-------------------------------------------------------------------- - +-spec init(mongooseim:host_type(), gen_mod:module_opts()) -> ok. init(_HostType, _Opts) -> ok. -tear_down(_HostType) -> +-spec tear_down(mongooseim:host_type()) -> ok. +tear_down(HostType) -> + clear_persistent_term(HostType), ok. +-spec remove_user(mongooseim:host_type(), jid:luser(), jid:lserver()) -> ok. remove_user(_HostType, _LUser, _LServer) -> %% no need to handle this - in ldap %% removing user = delete all user info ok. +-spec get_vcard(mongooseim:host_type(), jid:luser(), jid:lserver()) -> {ok, [exml:element()]}. get_vcard(HostType, LUser, LServer) -> State = get_state(HostType, LServer), - LServer = State#state.serverhost, 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; @@ -151,17 +151,22 @@ get_vcard(HostType, LUser, LServer) -> {ok, []} end. +-spec set_vcard(mongooseim:host_type(), jid:luser(), jid:lserver(), exml:element(), mod_vcard:vcard_search()) -> + {error, exml:element()}. set_vcard(_HostType, _User, _LServer, _VCard, _VCardSearch) -> {error, mongoose_xmpp_errors:not_allowed()}. +-spec search(mongooseim:host_type(), jid:lserver(), [{binary(), [binary()]}]) -> [eldap:eldap_entry()]. search(HostType, LServer, Data) -> State = get_state(HostType, LServer), search_internal(State, Data). +-spec search_fields(mongooseim:host_type(), jid:lserver()) -> [{binary(), binary()}]. search_fields(HostType, LServer) -> State = get_state(HostType, LServer), State#state.search_fields. +-spec search_reported_fields(mongooseim:host_type(), jid:lserver(), binary()) -> exml:element(). search_reported_fields(HostType, LServer, Lang) -> State = get_state(HostType, LServer), SearchReported = State#state.search_reported, @@ -417,44 +422,41 @@ process_pattern(Str, {User, Domain}, AttrValues) -> [{<<"%s">>, V, 1} || V <- AttrValues]). get_state(HostType, LServer) -> + Key = config_key(HostType, LServer), + case persistent_term:get(Key, undefined) of + undefined -> + State = create_state(HostType, LServer), + persistent_term:put(Key, State), + State; + State -> + State + end. + +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 @@ -464,11 +466,9 @@ get_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, @@ -480,3 +480,16 @@ get_state(HostType, LServer) -> search_reported_attrs = SearchReportedAttrs, search_operator = SearchOperator, matches = Matches}. + +clear_persistent_term(HostType) -> + Terms = persistent_term:get(), + States = lists:filter(fun({K, _V}) -> is_host_type_config_key(HostType, K) end, Terms), + [persistent_term:erase(Key) || {Key, _V} <- States]. + +is_host_type_config_key(HostType, {?MODULE, HostType, _LServer}) -> + true; +is_host_type_config_key(_HT, _K) -> + false. + +config_key(HostType, LServer) -> + {?MODULE, HostType, LServer}. diff --git a/src/wpool/mongoose_wpool_ldap.erl b/src/wpool/mongoose_wpool_ldap.erl index ff33ccb7d63..675d37b1f07 100644 --- a/src/wpool/mongoose_wpool_ldap.erl +++ b/src/wpool/mongoose_wpool_ldap.erl @@ -9,8 +9,7 @@ init() -> ok. -start(HostType, Tag, WpoolOpts, ConnOptsIn) -> - ConnOpts = maps:to_list(ConnOptsIn), +start(HostType, Tag, WpoolOpts, ConnOpts) -> WorkerSpec = {mongoose_ldap_worker, ConnOpts}, ProcName = mongoose_wpool:make_pool_name(ldap, HostType, Tag), mongoose_wpool:start_sup_pool(ldap, ProcName, [{worker, WorkerSpec} | WpoolOpts]). diff --git a/test/common/config_parser_helper.erl b/test/common/config_parser_helper.erl index e53c0c38775..dace7639354 100644 --- a/test/common/config_parser_helper.erl +++ b/test/common/config_parser_helper.erl @@ -318,8 +318,8 @@ options("outgoing_pools") -> request_timeout => 2000}}, #{type => ldap, scope => host, tag => default, opts => #{workers => 5}, - conn_opts => #{password => "ldap-admin-password", - rootdn => "cn=admin,dc=example,dc=com", + conn_opts => #{password => <<"ldap-admin-password">>, + rootdn => <<"cn=admin,dc=example,dc=com">>, servers => ["ldap-server.example.com"]}}, #{type => rabbit, scope => host, tag => event_pusher, opts => #{workers => 20}, @@ -503,14 +503,16 @@ all_modules() -> modules => [mod_muc, mod_disco]}]}), mod_last => #{backend => mnesia, iqdisc => {queues, 10}}, mod_shared_roster_ldap => - [{ldap_base, "ou=Users,dc=ejd,dc=com"}, - {ldap_filter, "(objectClass=inetOrgPerson)"}, - {ldap_group_cache_validity, 1}, - {ldap_groupattr, "ou"}, - {ldap_memberattr, "cn"}, - {ldap_rfilter, "(objectClass=inetOrgPerson)"}, - {ldap_user_cache_validity, 1}, - {ldap_userdesc, "cn"}], + mod_config(mod_shared_roster_ldap, + #{base => <<"ou=Users,dc=ejd,dc=com">>, + filter => <<"(objectClass=inetOrgPerson)">>, + group_cache_validity => 1, + groupattr => <<"ou">>, + groupdesc => <<"ou">>, % would be added with incorrect value by mod_config/2 + memberattr => <<"cn">>, + rfilter => <<"(objectClass=inetOrgPerson)">>, + user_cache_validity => 1, + userdesc => <<"cn">>}), mod_mam_mnesia_prefs => #{muc => true}, mod_jingle_sip => [{listen_port, 5600}, @@ -636,13 +638,17 @@ all_modules() -> mod_vcard => mod_config(mod_vcard, #{host => {fqdn, <<"directory.example.com">>}, - ldap_search_fields => - [{<<"User">>, <<"%u">>}, {<<"Full Name">>, <<"displayName">>}], - ldap_search_reported => - [{<<"Full Name">>, <<"FN">>}, {<<"Given Name">>, <<"FIRST">>}], - ldap_vcard_map => - [{<<"FAMILY">>, <<"%s">>, [<<"sn">>]}, - {<<"FN">>, <<"%s">>, [<<"displayName">>]}], + backend => ldap, + ldap => #{search_fields => + [{<<"User">>, <<"%u">>}, {<<"Full Name">>, <<"displayName">>}], + search_reported => + [{<<"Full Name">>, <<"FN">>}, {<<"Given Name">>, <<"FIRST">>}], + vcard_map => + [{<<"FAMILY">>, <<"%s">>, [<<"sn">>]}, + {<<"FN">>, <<"%s">>, [<<"displayName">>]}], + pool_tag => default, deref => never, filter => <<"">>, + uids => [{<<"uid">>, <<"%u">>}], search_operator => 'and', + binary_search_fields => []}, matches => 1, search => true}), mod_mam_muc_rdbms_arch => @@ -802,8 +808,8 @@ default_pool_conn_opts(http) -> #{path_prefix => "/", request_timeout => 2000}; default_pool_conn_opts(ldap) -> - #{rootdn => "", - password => "", + #{rootdn => <<"">>, + password => <<"">>, encrypt => none, servers => ["localhost"], connect_interval => 10000}; @@ -850,6 +856,12 @@ default_mod_config(mod_private) -> #{iqdisc => one_queue, backend => rdbms}; default_mod_config(mod_roster) -> #{iqdisc => one_queue, versioning => false, store_current_id => false, backend => mnesia}; +default_mod_config(mod_shared_roster_ldap) -> + #{pool_tag => default, deref => never, filter => <<"">>, + groupattr => <<"cn">>, groupdesc => <<"cn">>, userdesc => <<"cn">>, useruid => <<"cn">>, + memberattr => <<"memberUid">>, memberattr_format => <<"%u">>, memberattr_format_re => <<"">>, + auth_check => true, user_cache_validity => 300, group_cache_validity => 300, user_cache_size => 1000, + group_cache_size => 1000, rfilter => <<"">>, gfilter => <<"">>, ufilter => <<"">>}; default_mod_config(mod_sic) -> #{iqdisc => one_queue}; default_mod_config(mod_time) -> @@ -859,53 +871,7 @@ default_mod_config(mod_vcard) -> host => {prefix, <<"vjud.">>}, search => true, backend => mnesia, - matches => 30, - ldap_pool_tag => default, - ldap_uids => [{<<"uid">>, <<"%u">>}], - ldap_vcard_map => [{<<"NICKNAME">>, <<"%u">>, []}, - {<<"FN">>, <<"%s">>, [<<"displayName">>]}, - {<<"FAMILY">>, <<"%s">>, [<<"sn">>]}, - {<<"GIVEN">>, <<"%s">>, [<<"givenName">>]}, - {<<"MIDDLE">>, <<"%s">>, [<<"initials">>]}, - {<<"ORGNAME">>, <<"%s">>, [<<"o">>]}, - {<<"ORGUNIT">>, <<"%s">>, [<<"ou">>]}, - {<<"CTRY">>, <<"%s">>, [<<"c">>]}, - {<<"LOCALITY">>, <<"%s">>, [<<"l">>]}, - {<<"STREET">>, <<"%s">>, [<<"street">>]}, - {<<"REGION">>, <<"%s">>, [<<"st">>]}, - {<<"PCODE">>, <<"%s">>, [<<"postalCode">>]}, - {<<"TITLE">>, <<"%s">>, [<<"title">>]}, - {<<"URL">>, <<"%s">>, [<<"labeleduri">>]}, - {<<"DESC">>, <<"%s">>, [<<"description">>]}, - {<<"TEL">>, <<"%s">>, [<<"telephoneNumber">>]}, - {<<"EMAIL">>, <<"%s">>, [<<"mail">>]}, - {<<"BDAY">>, <<"%s">>, [<<"birthDay">>]}, - {<<"ROLE">>, <<"%s">>, [<<"employeeType">>]}, - {<<"PHOTO">>, <<"%s">>, [<<"jpegPhoto">>]}], - ldap_search_fields => [{<<"User">>, <<"%u">>}, - {<<"Full Name">>, <<"displayName">>}, - {<<"Given Name">>, <<"givenName">>}, - {<<"Middle Name">>, <<"initials">>}, - {<<"Family Name">>, <<"sn">>}, - {<<"Nickname">>, <<"%u">>}, - {<<"Birthday">>, <<"birthDay">>}, - {<<"Country">>, <<"c">>}, {<<"City">>, <<"l">>}, - {<<"Email">>, <<"mail">>}, - {<<"Organization Name">>, <<"o">>}, - {<<"Organization Unit">>, <<"ou">>}], - ldap_search_reported => [{<<"Full Name">>, <<"FN">>}, - {<<"Given Name">>, <<"FIRST">>}, - {<<"Middle Name">>, <<"MIDDLE">>}, - {<<"Family Name">>, <<"LAST">>}, - {<<"Nickname">>, <<"NICK">>}, - {<<"Birthday">>, <<"BDAY">>}, - {<<"Country">>, <<"CTRY">>}, - {<<"City">>, <<"LOCALITY">>}, - {<<"Email">>, <<"EMAIL">>}, - {<<"Organization Name">>, <<"ORGNAME">>}, - {<<"Organization Unit">>, <<"ORGUNIT">>}], - ldap_search_operator => 'and', - ldap_binary_search_fields => []}; + matches => 30}; default_mod_config(mod_version) -> #{iqdisc => no_queue, os_info => false}; default_mod_config(mod_mam_meta) -> @@ -935,7 +901,56 @@ default_config([modules, mod_mam_meta, async_writer]) -> default_config([modules, mod_mam_meta, riak]) -> #{bucket_type => <<"mam_yz">>, search_index => <<"mam">>}; default_config([modules, mod_roster, riak]) -> - #{bucket_type => <<"rosters">>, version_bucket_type => <<"roster_versions">>}. + #{bucket_type => <<"rosters">>, version_bucket_type => <<"roster_versions">>}; +default_config([modules, mod_vcard, ldap]) -> % included when backend => ldap + #{pool_tag => default, + deref => never, + filter => <<"">>, + uids => [{<<"uid">>, <<"%u">>}], + vcard_map => [{<<"NICKNAME">>, <<"%u">>, []}, + {<<"FN">>, <<"%s">>, [<<"displayName">>]}, + {<<"FAMILY">>, <<"%s">>, [<<"sn">>]}, + {<<"GIVEN">>, <<"%s">>, [<<"givenName">>]}, + {<<"MIDDLE">>, <<"%s">>, [<<"initials">>]}, + {<<"ORGNAME">>, <<"%s">>, [<<"o">>]}, + {<<"ORGUNIT">>, <<"%s">>, [<<"ou">>]}, + {<<"CTRY">>, <<"%s">>, [<<"c">>]}, + {<<"LOCALITY">>, <<"%s">>, [<<"l">>]}, + {<<"STREET">>, <<"%s">>, [<<"street">>]}, + {<<"REGION">>, <<"%s">>, [<<"st">>]}, + {<<"PCODE">>, <<"%s">>, [<<"postalCode">>]}, + {<<"TITLE">>, <<"%s">>, [<<"title">>]}, + {<<"URL">>, <<"%s">>, [<<"labeleduri">>]}, + {<<"DESC">>, <<"%s">>, [<<"description">>]}, + {<<"TEL">>, <<"%s">>, [<<"telephoneNumber">>]}, + {<<"EMAIL">>, <<"%s">>, [<<"mail">>]}, + {<<"BDAY">>, <<"%s">>, [<<"birthDay">>]}, + {<<"ROLE">>, <<"%s">>, [<<"employeeType">>]}, + {<<"PHOTO">>, <<"%s">>, [<<"jpegPhoto">>]}], + search_fields => [{<<"User">>, <<"%u">>}, + {<<"Full Name">>, <<"displayName">>}, + {<<"Given Name">>, <<"givenName">>}, + {<<"Middle Name">>, <<"initials">>}, + {<<"Family Name">>, <<"sn">>}, + {<<"Nickname">>, <<"%u">>}, + {<<"Birthday">>, <<"birthDay">>}, + {<<"Country">>, <<"c">>}, {<<"City">>, <<"l">>}, + {<<"Email">>, <<"mail">>}, + {<<"Organization Name">>, <<"o">>}, + {<<"Organization Unit">>, <<"ou">>}], + search_reported => [{<<"Full Name">>, <<"FN">>}, + {<<"Given Name">>, <<"FIRST">>}, + {<<"Middle Name">>, <<"MIDDLE">>}, + {<<"Family Name">>, <<"LAST">>}, + {<<"Nickname">>, <<"NICK">>}, + {<<"Birthday">>, <<"BDAY">>}, + {<<"Country">>, <<"CTRY">>}, + {<<"City">>, <<"LOCALITY">>}, + {<<"Email">>, <<"EMAIL">>}, + {<<"Organization Name">>, <<"ORGNAME">>}, + {<<"Organization Unit">>, <<"ORGUNIT">>}], + search_operator => 'and', + binary_search_fields => []}. common_mam_config() -> #{no_stanzaid_element => false, diff --git a/test/config_parser_SUITE.erl b/test/config_parser_SUITE.erl index 5b60ba09f81..8c345caeb70 100644 --- a/test/config_parser_SUITE.erl +++ b/test/config_parser_SUITE.erl @@ -1364,12 +1364,12 @@ pool_ldap_encrypt(_Config) -> ?err(pool_conn_raw(<<"ldap">>, #{<<"encrypt">> => true})). pool_ldap_rootdn(_Config) -> - ?cfg(pool_config(#{type => ldap, conn_opts => #{rootdn => "my_rootdn"}}), + ?cfg(pool_config(#{type => ldap, conn_opts => #{rootdn => <<"my_rootdn">>}}), pool_conn_raw(<<"ldap">>, #{<<"rootdn">> => <<"my_rootdn">>})), ?err(pool_conn_raw(<<"ldap">>, #{<<"rootdn">> => false})). pool_ldap_password(_Config) -> - ?cfg(pool_config(#{type => ldap, conn_opts => #{password => "pass"}}), + ?cfg(pool_config(#{type => ldap, conn_opts => #{password => <<"pass">>}}), pool_conn_raw(<<"ldap">>, #{<<"password">> => <<"pass">>})), ?err(pool_conn_raw(<<"ldap">>, #{<<"password">> => true})). @@ -2831,71 +2831,72 @@ mod_roster(_Config) -> ?errh(T(#{<<"riak">> => #{<<"bucket_type">> => 1}})). mod_shared_roster_ldap(_Config) -> + check_module_defaults(mod_shared_roster_ldap), + P = [modules, mod_shared_roster_ldap], T = fun(Opts) -> #{<<"modules">> => #{<<"mod_shared_roster_ldap">> => Opts}} end, - M = fun(Cfg) -> modopts(mod_shared_roster_ldap, Cfg) end, - ?cfgh(M([{ldap_pool_tag, default}]), - T(#{<<"ldap_pool_tag">> => <<"default">>})), - ?cfgh(M([{ldap_base, "string"}]), - T(#{<<"ldap_base">> => <<"string">>})), - ?cfgh(M([{ldap_deref, never}]), - T(#{<<"ldap_deref">> => <<"never">>})), + ?cfgh(P ++ [pool_tag], my_tag, + T(#{<<"pool_tag">> => <<"my_tag">>})), + ?cfgh(P ++ [base], <<"string">>, + T(#{<<"base">> => <<"string">>})), + ?cfgh(P ++ [deref], always, + T(#{<<"deref">> => <<"always">>})), %% Options: attributes - ?cfgh(M([ {ldap_groupattr, "cn"}]), - T(#{<<"ldap_groupattr">> => <<"cn">>})), - ?cfgh(M([{ldap_groupdesc, "default"}]), - T(#{<<"ldap_groupdesc">> => <<"default">>})), - ?cfgh(M([{ldap_userdesc, "cn"}]), - T(#{<<"ldap_userdesc">> => <<"cn">>})), - ?cfgh(M([{ldap_useruid, "cn"}]), - T(#{<<"ldap_useruid">> => <<"cn">>})), - ?cfgh(M([{ldap_memberattr, "memberUid"}]), - T(#{<<"ldap_memberattr">> => <<"memberUid">>})), - ?cfgh(M([{ldap_memberattr_format, "%u"}]), - T(#{<<"ldap_memberattr_format">> => <<"%u">>})), - ?cfgh(M([{ldap_memberattr_format_re,""}]), - T(#{<<"ldap_memberattr_format_re">> => <<"">>})), + ?cfgh(P ++ [groupattr], <<"cn">>, + T(#{<<"groupattr">> => <<"cn">>})), + ?cfgh(P ++ [groupdesc], <<"default">>, + T(#{<<"groupdesc">> => <<"default">>})), + ?cfgh(P ++ [userdesc], <<"cn">>, + T(#{<<"userdesc">> => <<"cn">>})), + ?cfgh(P ++ [useruid], <<"cn">>, + T(#{<<"useruid">> => <<"cn">>})), + ?cfgh(P ++ [memberattr], <<"memberUid">>, + T(#{<<"memberattr">> => <<"memberUid">>})), + ?cfgh(P ++ [memberattr_format], <<"%u">>, + T(#{<<"memberattr_format">> => <<"%u">>})), + ?cfgh(P ++ [memberattr_format_re], <<"">>, + T(#{<<"memberattr_format_re">> => <<"">>})), %% Options: parameters - ?cfgh(M([ {ldap_auth_check, true}]), - T(#{<<"ldap_auth_check">> => true})), - ?cfgh(M([{ldap_user_cache_validity, 300}]), - T(#{<<"ldap_user_cache_validity">> => 300})), - ?cfgh(M([{ldap_group_cache_validity, 300}]), - T(#{<<"ldap_group_cache_validity">> => 300})), - ?cfgh(M([{ldap_user_cache_size, 300}]), - T(#{<<"ldap_user_cache_size">> => 300})), - ?cfgh(M([{ldap_group_cache_size, 300}]), - T(#{<<"ldap_group_cache_size">> => 300})), + ?cfgh(P ++ [auth_check], true, + T(#{<<"auth_check">> => true})), + ?cfgh(P ++ [user_cache_validity], 300, + T(#{<<"user_cache_validity">> => 300})), + ?cfgh(P ++ [group_cache_validity], 300, + T(#{<<"group_cache_validity">> => 300})), + ?cfgh(P ++ [user_cache_size], 300, + T(#{<<"user_cache_size">> => 300})), + ?cfgh(P ++ [group_cache_size], 300, + T(#{<<"group_cache_size">> => 300})), %% Options: LDAP filters - ?cfgh(M([{ldap_rfilter, "rfilter_test"}]), - T(#{<<"ldap_rfilter">> => <<"rfilter_test">>})), - ?cfgh(M([{ldap_gfilter, "gfilter_test"}]), - T(#{<<"ldap_gfilter">> => <<"gfilter_test">>})), - ?cfgh(M([{ldap_ufilter, "ufilter_test"}]), - T(#{<<"ldap_ufilter">> => <<"ufilter_test">>})), - ?cfgh(M([{ldap_filter, "filter_test"}]), - T(#{<<"ldap_filter">> => <<"filter_test">>})), - ?errh(T(#{<<"ldap_pool_tag">> => 1})), - ?errh(T(#{<<"ldap_base">> => 1})), - ?errh(T(#{<<"ldap_deref">> => 1})), + ?cfgh(P ++ [rfilter], <<"rfilter_test">>, + T(#{<<"rfilter">> => <<"rfilter_test">>})), + ?cfgh(P ++ [gfilter], <<"gfilter_test">>, + T(#{<<"gfilter">> => <<"gfilter_test">>})), + ?cfgh(P ++ [ufilter], <<"ufilter_test">>, + T(#{<<"ufilter">> => <<"ufilter_test">>})), + ?cfgh(P ++ [filter], <<"filter_test">>, + T(#{<<"filter">> => <<"filter_test">>})), + ?errh(T(#{<<"pool_tag">> => 1})), + ?errh(T(#{<<"base">> => 1})), + ?errh(T(#{<<"deref">> => 1})), %% Options: attributes - ?errh(T(#{<<"ldap_groupattr">> => 1})), - ?errh(T(#{<<"ldap_groupdesc">> => 1})), - ?errh(T(#{<<"ldap_userdesc">> => 1})), - ?errh(T(#{<<"ldap_useruid">> => 1})), - ?errh(T(#{<<"ldap_memberattr">> => 1})), - ?errh(T(#{<<"ldap_memberattr_format">> => 1})), - ?errh(T(#{<<"ldap_memberattr_format_re">> => 1})), + ?errh(T(#{<<"groupattr">> => 1})), + ?errh(T(#{<<"groupdesc">> => 1})), + ?errh(T(#{<<"userdesc">> => 1})), + ?errh(T(#{<<"useruid">> => 1})), + ?errh(T(#{<<"memberattr">> => 1})), + ?errh(T(#{<<"memberattr_format">> => 1})), + ?errh(T(#{<<"memberattr_format_re">> => 1})), %% Options: parameters - ?errh(T(#{<<"ldap_auth_check">> => 1})), - ?errh(T(#{<<"ldap_user_cache_validity">> => -1})), - ?errh(T(#{<<"ldap_group_cache_validity">> => -1})), - ?errh(T(#{<<"ldap_user_cache_size">> => -1})), - ?errh(T(#{<<"ldap_group_cache_size">> => -1})), + ?errh(T(#{<<"auth_check">> => 1})), + ?errh(T(#{<<"user_cache_validity">> => -1})), + ?errh(T(#{<<"group_cache_validity">> => -1})), + ?errh(T(#{<<"user_cache_size">> => -1})), + ?errh(T(#{<<"group_cache_size">> => -1})), %% Options: LDAP filters - ?errh(T(#{<<"ldap_rfilter">> => 1})), - ?errh(T(#{<<"ldap_gfilter">> => 1})), - ?errh(T(#{<<"ldap_ufilter">> => 1})), - ?errh(T(#{<<"ldap_filter">> => 1})). + ?errh(T(#{<<"rfilter">> => 1})), + ?errh(T(#{<<"gfilter">> => 1})), + ?errh(T(#{<<"ufilter">> => 1})), + ?errh(T(#{<<"filter">> => 1})). mod_sic(_Config) -> check_module_defaults(mod_sic), @@ -2953,18 +2954,20 @@ mod_vcard(_Config) -> ?cfgh(P ++ [matches], infinity, T(#{<<"matches">> => <<"infinity">>})), %% ldap - ?cfgh(P ++ [ldap_pool_tag], default, - T(#{<<"ldap_pool_tag">> => <<"default">>})), - ?cfgh(P ++ [ldap_base], "ou=Users,dc=ejd,dc=com", - T(#{<<"ldap_base">> => <<"ou=Users,dc=ejd,dc=com">>})), - ?cfgh(P ++ [ldap_filter], <<"(&(objectClass=shadowAccount)(memberOf=Jabber Users))">>, - T(#{<<"ldap_filter">> => <<"(&(objectClass=shadowAccount)(memberOf=Jabber Users))">>})), - ?cfgh(P ++ [ldap_deref], never, - T(#{<<"ldap_deref">> => <<"never">>})), - ?cfgh(P ++ [ldap_search_operator], 'or', - T(#{<<"ldap_search_operator">> => <<"or">>})), - ?cfgh(P ++ [ldap_binary_search_fields], [<<"PHOTO">>], - T(#{<<"ldap_binary_search_fields">> => [<<"PHOTO">>]})), + ?cfgh(P ++ [ldap], config_parser_helper:default_config(P ++ [ldap]), + T(#{<<"backend">> => <<"ldap">>})), + ?cfgh(P ++ [ldap, pool_tag], my_tag, + T(#{<<"backend">> => <<"ldap">>, <<"ldap">> => #{<<"pool_tag">> => <<"my_tag">>}})), + ?cfgh(P ++ [ldap, base], <<"ou=Users,dc=ejd,dc=com">>, + T(#{<<"backend">> => <<"ldap">>, <<"ldap">> => #{<<"base">> => <<"ou=Users,dc=ejd,dc=com">>}})), + ?cfgh(P ++ [ldap, filter], <<"(&(objectClass=shadowAccount)(memberOf=Jabber Users))">>, + T(#{<<"backend">> => <<"ldap">>, <<"ldap">> => #{<<"filter">> => <<"(&(objectClass=shadowAccount)(memberOf=Jabber Users))">>}})), + ?cfgh(P ++ [ldap, deref], always, + T(#{<<"backend">> => <<"ldap">>, <<"ldap">> => #{<<"deref">> => <<"always">>}})), + ?cfgh(P ++ [ldap, search_operator], 'or', + T(#{<<"backend">> => <<"ldap">>, <<"ldap">> => #{<<"search_operator">> => <<"or">>}})), + ?cfgh(P ++ [ldap, binary_search_fields], [<<"PHOTO">>], + T(#{<<"backend">> => <<"ldap">>, <<"ldap">> => #{<<"binary_search_fields">> => [<<"PHOTO">>]}})), %% riak ?cfgh(P ++ [riak, bucket_type], <<"vcard">>, T(#{<<"backend">> => <<"riak">>, <<"riak">> => #{<<"bucket_type">> => <<"vcard">>}})), @@ -2990,9 +2993,10 @@ mod_vcard(_Config) -> ?errh(T(#{<<"riak">> => #{<<"search_index">> => 1}})). mod_vcard_ldap_uids(_Config) -> - P = [modules, mod_vcard, ldap_uids], + P = [modules, mod_vcard, ldap, uids], T = fun(Opts) -> #{<<"modules">> => - #{<<"mod_vcard">> => #{<<"ldap_uids">> => Opts}}} end, + #{<<"mod_vcard">> => #{<<"backend">> => <<"ldap">>, + <<"ldap">> => #{<<"uids">> => Opts}}}} end, RequiredOpts = #{<<"attr">> => <<"name">>}, ExpectedCfg = <<"name">>, ?cfgh(P, [], T([])), @@ -3006,9 +3010,10 @@ mod_vcard_ldap_uids(_Config) -> ?errh(T(RequiredOpts#{<<"format">> => true})). mod_vcard_ldap_vcard_map(_Config) -> - P = [modules, mod_vcard, ldap_vcard_map], + P = [modules, mod_vcard, ldap, vcard_map], T = fun(Opts) -> #{<<"modules">> => - #{<<"mod_vcard">> => #{<<"ldap_vcard_map">> => Opts}}} end, + #{<<"mod_vcard">> => #{<<"backend">> => <<"ldap">>, + <<"ldap">> => #{<<"vcard_map">> => Opts}}}} end, RequiredOpts = #{<<"vcard_field">> => <<"FAMILY">>, <<"ldap_pattern">> => <<"%s">>, <<"ldap_field">> => <<"sn">>}, @@ -3021,9 +3026,10 @@ mod_vcard_ldap_vcard_map(_Config) -> ?errh(T(RequiredOpts#{<<"ldap_field">> := -1})). mod_vcard_ldap_search_fields(_Config) -> - P = [modules, mod_vcard, ldap_search_fields], + P = [modules, mod_vcard, ldap, search_fields], T = fun(Opts) -> #{<<"modules">> => - #{<<"mod_vcard">> => #{<<"ldap_search_fields">> => Opts}}} end, + #{<<"mod_vcard">> => #{<<"backend">> => <<"ldap">>, + <<"ldap">> => #{<<"search_fields">> => Opts}}}} end, RequiredOpts = #{<<"search_field">> => <<"Full Name">>, <<"ldap_field">> => <<"cn">>}, ExpectedCfg = {<<"Full Name">>, <<"cn">>}, @@ -3034,9 +3040,10 @@ mod_vcard_ldap_search_fields(_Config) -> ?errh(T(RequiredOpts#{<<"ldap_field">> := -1})). mod_vcard_ldap_search_reported(_Config) -> - P = [modules, mod_vcard, ldap_search_reported], + P = [modules, mod_vcard, ldap, search_reported], T = fun(Opts) -> #{<<"modules">> => - #{<<"mod_vcard">> => #{<<"ldap_search_reported">> => Opts}}} end, + #{<<"mod_vcard">> => #{<<"backend">> => <<"ldap">>, + <<"ldap">> => #{<<"search_reported">> => Opts}}}} end, RequiredOpts = #{<<"search_field">> => <<"Full Name">>, <<"vcard_field">> => <<"FN">>}, ExpectedCfg = {<<"Full Name">>, <<"FN">>}, diff --git a/test/config_parser_SUITE_data/modules.toml b/test/config_parser_SUITE_data/modules.toml index 47fb8da400b..d62308b0867 100644 --- a/test/config_parser_SUITE_data/modules.toml +++ b/test/config_parser_SUITE_data/modules.toml @@ -248,14 +248,14 @@ store_current_id = true [modules.mod_shared_roster_ldap] - ldap_base = "ou=Users,dc=ejd,dc=com" - ldap_groupattr = "ou" - ldap_memberattr = "cn" - ldap_userdesc = "cn" - ldap_filter = "(objectClass=inetOrgPerson)" - ldap_rfilter = "(objectClass=inetOrgPerson)" - ldap_group_cache_validity = 1 - ldap_user_cache_validity = 1 + base = "ou=Users,dc=ejd,dc=com" + groupattr = "ou" + memberattr = "cn" + userdesc = "cn" + filter = "(objectClass=inetOrgPerson)" + rfilter = "(objectClass=inetOrgPerson)" + group_cache_validity = 1 + user_cache_validity = 1 [modules.mod_stream_management] buffer_max = 30 @@ -269,30 +269,31 @@ matches = 1 search = true host = "directory.example.com" + backend = "ldap" - [[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"