25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-10-13 15:16:49 +02:00

* src/ejabberd_auth_ldap.erl: LDAP authentication now allows to

match on several alternative attributes.
* src/mod_vcard_ldap.erl: Likewise.
* doc/guide.tex: Updated.
* eldap_utils.erl: Refactoring.
* src/eldap/Makefile.in: Likewise.

SVN Revision: 661
This commit is contained in:
Mickaël Rémond 2006-10-17 12:35:47 +00:00
parent 95e2726f71
commit d5792ed75e
7 changed files with 234 additions and 208 deletions

View File

@ -1,3 +1,12 @@
2006-10-17 Mickael Remond <mickael.remond@process-one.net>
* src/ejabberd_auth_ldap.erl: LDAP authentication now allows to
match on several alternative attributes.
* src/mod_vcard_ldap.erl: Likewise.
* doc/guide.tex: Updated.
* eldap_utils.erl: Refactoring.
* src/eldap/Makefile.in: Likewise.
2006-10-09 Alexey Shchepin <alexey@sevcom.net>
* src/mod_privacy_odbc.erl: Privacy rules support using odbc

View File

@ -521,7 +521,7 @@ Domain <TT>example.net</TT> is using the internal authentication method while
{host_config, "example.com", [{auth_method, ldap},
{ldap_servers, ["localhost"]},
{ldap_uidattr, "uid"},
{ldap_uids, [{"uid"}]},
{ldap_rootdn, "dc=localdomain"},
{ldap_rootdn, "dc=example,dc=com"},
{ldap_password, ""}]}.
@ -534,7 +534,7 @@ Domain <TT>example.net</TT> is using the internal authentication method while
{host_config, "example.com", [{auth_method, ldap},
{ldap_servers, ["localhost", "otherhost"]},
{ldap_uidattr, "uid"},
{ldap_uids, [{"uid"}]},
{ldap_rootdn, "dc=localdomain"},
{ldap_rootdn, "dc=example,dc=com"},
{ldap_password, ""}]}.
@ -1372,15 +1372,26 @@ and SASL authentication.<BR>
<A NAME="sec:ldapauth"></A>
You can authenticate users against an LDAP directory. Available options are:
<DL CLASS="description" COMPACT=compact><DT CLASS="dt-description">
<B><TT>ldap_base</TT></B><DD CLASS="dd-description">LDAP base directory which stores users
accounts. This option is required.
<DT CLASS="dt-description"><B><TT>ldap_uidattr</TT></B><DD CLASS="dd-description">LDAP attribute which holds
<B><TT>ldap_base</TT></B><DD CLASS="dd-description">LDAP base directory which stores
users accounts. This option is required.
<DT CLASS="dt-description"><B><TT>ldap_uids</TT></B><DD CLASS="dd-description">LDAP attribute which holds a list
of attributes to use as alternatives for getting the JID. The value is of
the form: <TT>[{ldap_uidattr}]</TT> or <TT>[{ldap_uidattr,
ldap_uidattr_format}]</TT>. You can use as many comma separated tuples
<TT>{ldap_uidattr, ldap_uidattr_format}</TT> that is needed. The default
value is <TT>[{"uid", "%u"}]</TT>. The defaut <TT>ldap_uidattr_format</TT>
is <TT>"%u"</TT>. The values for <TT>ldap_uidattr</TT> and
<TT>ldap_uidattr_format</TT> are described as follow:
<DL CLASS="description" COMPACT=compact><DT CLASS="dt-description">
<B><TT>ldap_uidattr</TT></B><DD CLASS="dd-description">LDAP attribute which holds
the user's part of a JID. The default value is <TT>"uid"</TT>.
<DT CLASS="dt-description"><B><TT>ldap_uidattr_format</TT></B><DD CLASS="dd-description">Format of the
<TT>ldap_uidattr</TT> variable. The format <EM>must</EM> contain one and only one
pattern variable <TT>"%u"</TT> which will be replaced by the user's part of a
JID. For example, <TT>"%u@example.org"</TT>. The default value is <TT>"%u"</TT>.
<DT CLASS="dt-description"><B><TT>ldap_filter</TT></B><DD CLASS="dd-description">
<DT CLASS="dt-description"><B><TT>ldap_uidattr_format</TT></B><DD CLASS="dd-description">Format of
the <TT>ldap_uidattr</TT> variable. The format <EM>must</EM> contain one and
only one pattern variable <TT>"%u"</TT> which will be replaced by the
user's part of a JID. For example, <TT>"%u@example.org"</TT>. The default
value is <TT>"%u"</TT>.
</DL>
<DT CLASS="dt-description"><B><TT>ldap_filter</TT></B><DD CLASS="dd-description">
<A HREF="http://www.faqs.org/rfcs/rfc2254.html">RFC 2254</A> LDAP filter. The
default is <TT>none</TT>. Example:
<TT>"(&amp;(objectClass=shadowAccount)(memberOf=Jabber Users))"</TT>. Please, do
@ -1431,10 +1442,9 @@ Also we want users to search each other. Let's see how we can set it up:
{ldap_password, ""},
%% define the addressbook's base
{ldap_base, "ou=AddressBook,dc=example,dc=org"},
%% user's part of JID is located in the "mail" attribute
{ldap_uidattr, "mail"},
%% common format for our emails
{ldap_uidattr_format, "%u@mail.example.org"},
%% uidattr: user's part of JID is located in the "mail" attribute
%% uidattr_format: common format for our emails
{ldap_uids, [{"mail", "%u@mail.example.org"}]},
%% We have to define empty filter here, because entries in addressbook does not
%% belong to shadowAccount object class
{ldap_filter, ""},
@ -1480,7 +1490,7 @@ configuration is showed below:
{ldap_base, "DC=office,DC=org"}. % Search base of LDAP directory
{ldap_rootdn, "CN=Administrator,CN=Users,DC=office,DC=org"}. % LDAP manager
{ldap_password, "*******"}. % Password to LDAP manager
{ldap_uidattr, "sAMAccountName"}.
{ldap_uids, [{"sAMAccountName"}]}.
{ldap_filter, "(memberOf=*)"}.
{mod_vcard_ldap,
@ -2881,10 +2891,9 @@ Also we want users to search each other. Let's see how we can set it up:
{ldap_password, ""},
%% define the addressbook's base
{ldap_base, "ou=AddressBook,dc=example,dc=org"},
%% user's part of JID is located in the "mail" attribute
{ldap_uidattr, "mail"},
%% common format for our emails
{ldap_uidattr_format, "%u@mail.example.org"},
%% uidattr: user's part of JID is located in the "mail" attribute
%% uidattr_format: common format for our emails
{ldap_uids, [{"mail","%u@mail.example.org"}]},
%% We have to define empty filter here, because entries in addressbook does not
%% belong to shadowAccount object class
{ldap_filter, ""},

View File

@ -378,7 +378,7 @@ Examples:
{host_config, "example.com", [{auth_method, ldap},
{ldap_servers, ["localhost"]},
{ldap_uidattr, "uid"},
{ldap_uids, [{"uid"}]},
{ldap_rootdn, "dc=localdomain"},
{ldap_rootdn, "dc=example,dc=com"},
{ldap_password, ""}]}.
@ -392,7 +392,7 @@ Examples:
{host_config, "example.com", [{auth_method, ldap},
{ldap_servers, ["localhost", "otherhost"]},
{ldap_uidattr, "uid"},
{ldap_uids, [{"uid"}]},
{ldap_rootdn, "dc=localdomain"},
{ldap_rootdn, "dc=example,dc=com"},
{ldap_password, ""}]}.
@ -1230,15 +1230,27 @@ and SASL authentication.
You can authenticate users against an LDAP directory. Available options are:
\begin{description}
\titem{ldap\_base}\ind{options!ldap\_base}LDAP base directory which stores users
accounts. This option is required.
\titem{ldap\_uidattr}\ind{options!ldap\_uidattr}LDAP attribute which holds
the user's part of a JID. The default value is \term{"uid"}.
\titem{ldap\_uidattr\_format}\ind{options!ldap\_uidattr\_format}Format of the
\term{ldap\_uidattr} variable. The format \emph{must} contain one and only one
pattern variable \term{"\%u"} which will be replaced by the user's part of a
JID. For example, \term{"\%u@example.org"}. The default value is \term{"\%u"}.
\titem{ldap\_filter}\ind{options!ldap\_filter}\ind{protocols!RFC 2254: The String Representation of LDAP Search Filters}
\titem{ldap\_base}\ind{options!ldap\_base}LDAP base directory which stores
users accounts. This option is required.
\titem{ldap\_uids}\ind{options!ldap\_uids}LDAP attribute which holds a list
of attributes to use as alternatives for getting the JID. The value is of
the form: \term{[\{ldap\_uidattr\}]} or \term{[\{ldap\_uidattr,
ldap\_uidattr\_format\}]}. You can use as many comma separated tuples
\term{\{ldap\_uidattr, ldap\_uidattr\_format\}} that is needed. The default
value is \term{[\{"uid", "\%u"\}]}. The defaut \term{ldap\_uidattr\_format}
is \term{"\%u"}. The values for \term{ldap\_uidattr} and
\term{ldap\_uidattr\_format} are described as follow:
\begin{description}
\titem{ldap\_uidattr}\ind{options!ldap\_uidattr}LDAP attribute which holds
the user's part of a JID. The default value is \term{"uid"}.
\titem{ldap\_uidattr\_format}\ind{options!ldap\_uidattr\_format}Format of
the \term{ldap\_uidattr} variable. The format \emph{must} contain one and
only one pattern variable \term{"\%u"} which will be replaced by the
user's part of a JID. For example, \term{"\%u@example.org"}. The default
value is \term{"\%u"}.
\end{description}
\titem{ldap\_filter}\ind{options!ldap\_filter}\ind{protocols!RFC 2254: The
String Representation of LDAP Search Filters}
\footahref{http://www.faqs.org/rfcs/rfc2254.html}{RFC 2254} LDAP filter. The
default is \term{none}. Example:
\term{"(\&(objectClass=shadowAccount)(memberOf=Jabber Users))"}. Please, do
@ -1289,10 +1301,9 @@ Also we want users to search each other. Let's see how we can set it up:
{ldap_password, ""},
%% define the addressbook's base
{ldap_base, "ou=AddressBook,dc=example,dc=org"},
%% user's part of JID is located in the "mail" attribute
{ldap_uidattr, "mail"},
%% common format for our emails
{ldap_uidattr_format, "%u@mail.example.org"},
%% uidattr: user's part of JID is located in the "mail" attribute
%% uidattr_format: common format for our emails
{ldap_uids, [{"mail", "%u@mail.example.org"}]},
%% We have to define empty filter here, because entries in addressbook does not
%% belong to shadowAccount object class
{ldap_filter, ""},
@ -1339,7 +1350,7 @@ configuration is showed below:
{ldap_base, "DC=office,DC=org"}. % Search base of LDAP directory
{ldap_rootdn, "CN=Administrator,CN=Users,DC=office,DC=org"}. % LDAP manager
{ldap_password, "*******"}. % Password to LDAP manager
{ldap_uidattr, "sAMAccountName"}.
{ldap_uids, [{"sAMAccountName"}]}.
{ldap_filter, "(memberOf=*)"}.
{mod_vcard_ldap,
@ -2599,10 +2610,9 @@ Also we want users to search each other. Let's see how we can set it up:
{ldap_password, ""},
%% define the addressbook's base
{ldap_base, "ou=AddressBook,dc=example,dc=org"},
%% user's part of JID is located in the "mail" attribute
{ldap_uidattr, "mail"},
%% common format for our emails
{ldap_uidattr_format, "%u@mail.example.org"},
%% uidattr: user's part of JID is located in the "mail" attribute
%% uidattr_format: common format for our emails
{ldap_uids, [{"mail","%u@mail.example.org"}]},
%% We have to define empty filter here, because entries in addressbook does not
%% belong to shadowAccount object class
{ldap_filter, ""},

View File

@ -50,8 +50,7 @@
dn,
password,
base,
uidattr,
uidattr_format,
uids,
ufilter,
sfilter,
dn_filter,
@ -188,11 +187,10 @@ handle_call({check_pass, User, Password}, _From, State) ->
{reply, Reply, State};
handle_call(get_vh_registered_users, _From, State) ->
UA = State#state.uidattr,
UAF = State#state.uidattr_format,
UIDs = State#state.uids,
Eldap_ID = State#state.eldap_id,
Server = State#state.host,
SortedDNAttrs = usort_attrs(State#state.dn_filter_attrs),
SortedDNAttrs = eldap_utils:usort_attrs(State#state.dn_filter_attrs),
Reply = case eldap_filter:parse(State#state.sfilter) of
{ok, EldapFilter} ->
case eldap:search(Eldap_ID, [{base, State#state.base},
@ -205,10 +203,10 @@ handle_call(get_vh_registered_users, _From, State) ->
case is_valid_dn(DN, Attrs, State) of
false -> [];
_ ->
case get_ldap_attr(UA, Attrs) of
case eldap_utils:find_ldap_attrs(UIDs, Attrs) of
"" -> [];
User ->
case get_user_part(User, UAF) of
{User, UIDFormat} ->
case eldap_utils:get_user_part(User, UIDFormat) of
{ok, U} ->
case jlib:nodeprep(U) of
error -> [];
@ -241,7 +239,7 @@ handle_call(_Request, _From, State) ->
{reply, bad_request, State}.
find_user_dn(User, State) ->
DNAttrs = usort_attrs(State#state.dn_filter_attrs),
DNAttrs = eldap_utils:usort_attrs(State#state.dn_filter_attrs),
case eldap_filter:parse(State#state.ufilter, [{"%u", User}]) of
{ok, Filter} ->
case eldap:search(State#state.eldap_id, [{base, State#state.base},
@ -262,13 +260,12 @@ is_valid_dn(DN, _, #state{dn_filter = undefined}) ->
is_valid_dn(DN, Attrs, State) ->
DNAttrs = State#state.dn_filter_attrs,
UA = State#state.uidattr,
UAF = State#state.uidattr_format,
Values = [{"%s", get_ldap_attr(Attr, Attrs), 1} || Attr <- DNAttrs],
SubstValues = case get_ldap_attr(UA, Attrs) of
UIDs = State#state.uids,
Values = [{"%s", eldap_utils:get_ldap_attr(Attr, Attrs), 1} || Attr <- DNAttrs],
SubstValues = case eldap_utils:find_ldap_attrs(UIDs, Attrs) of
"" -> Values;
S ->
case get_user_part(S, UAF) of
{S, UAF} ->
case eldap_utils:get_user_part(S, UAF) of
{ok, U} -> [{"%u", U} | Values];
_ -> Values
end
@ -291,46 +288,6 @@ is_valid_dn(DN, Attrs, State) ->
%%%----------------------------------------------------------------------
%%% Auxiliary functions
%%%----------------------------------------------------------------------
get_user_part(String, Pattern) ->
F = fun(S, P) ->
First = string:str(P, "%u"),
TailLength = length(P) - (First+1),
string:sub_string(S, First, length(S) - TailLength)
end,
case catch F(String, Pattern) of
{'EXIT', _} ->
{error, badmatch};
Result ->
case regexp:sub(Pattern, "%u", Result) of
{ok, String, _} -> {ok, Result};
_ -> {error, badmatch}
end
end.
case_insensitive_match(X, Y) ->
X1 = stringprep:tolower(X),
Y1 = stringprep:tolower(Y),
if
X1 == Y1 -> true;
true -> false
end.
get_ldap_attr(LDAPAttr, Attributes) ->
Res = lists:filter(
fun({Name, _}) ->
case_insensitive_match(Name, LDAPAttr)
end, Attributes),
case Res of
[{_, [Value|_]}] -> Value;
_ -> ""
end.
usort_attrs(Attrs) when is_list(Attrs) ->
lists:usort(Attrs);
usort_attrs(_) ->
[].
parse_options(Host) ->
Eldap_ID = atom_to_list(gen_mod:get_module_proc(Host, ?MODULE)),
Bind_Eldap_ID = atom_to_list(gen_mod:get_module_proc(Host, bind_ejabberd_auth_ldap)),
@ -347,15 +304,11 @@ parse_options(Host) ->
undefined -> "";
Pass -> Pass
end,
UIDAttr = case ejabberd_config:get_local_option({ldap_uidattr, Host}) of
undefined -> "uid";
UA -> UA
end,
UIDAttrFormat = case ejabberd_config:get_local_option({ldap_uidattr_format, Host}) of
undefined -> "%u";
UAF -> UAF
end,
SubFilter = "(" ++ UIDAttr ++ "=" ++ UIDAttrFormat ++ ")",
UIDs = case ejabberd_config:get_local_option({ldap_uids, Host}) of
undefined -> [{"uid", "%u"}];
UI -> UI
end,
SubFilter = lists:flatten(eldap_utils:generate_subfilter(UIDs)),
UserFilter = case ejabberd_config:get_local_option({ldap_filter, Host}) of
undefined -> SubFilter;
"" -> SubFilter;
@ -376,8 +329,7 @@ parse_options(Host) ->
dn = RootDN,
password = Password,
base = LDAPBase,
uidattr = UIDAttr,
uidattr_format = UIDAttrFormat,
uids = UIDs,
ufilter = UserFilter,
sfilter = SearchFilter,
dn_filter = DNFilter,

View File

@ -13,7 +13,8 @@ EFLAGS = -I .. -pz ..
OBJS = \
$(OUTDIR)/eldap.beam \
$(OUTDIR)/ELDAPv3.beam \
$(OUTDIR)/eldap_filter.beam
$(OUTDIR)/eldap_filter.beam \
$(OUTDIR)/eldap_utils.beam
all: $(OBJS)

110
src/eldap/eldap_utils.erl Normal file
View File

@ -0,0 +1,110 @@
%%%----------------------------------------------------------------------
%%% File : eldap_utils.erl
%%% Author : Mickael Remond <mickael.remond@process-one.net>
%%% Purpose : ejabberd LDAP helper functions
%%% Created : 12 Oct 2006 by Mickael Remond <mickael.remond@process-one.net>
%%% Id : $Id: ejabberd_auth_ldap.erl 623 2006-09-23 09:52:53Z mremond $
%%%----------------------------------------------------------------------
-module(eldap_utils).
-author('mickael.remond@process-one.net').
-svn('$Revision: $ ').
-export([generate_subfilter/1,
find_ldap_attrs/2,
get_ldap_attr/2,
usort_attrs/1,
get_user_part/2,
make_filter/2]).
%% Generate an 'or' LDAP query on one or several attributes
%% If there is only one attribute
generate_subfilter([UID]) ->
subfilter(UID);
%% If there is several attributes
generate_subfilter(UIDs) ->
"(|" ++ [subfilter(UID) || UID <- UIDs] ++ ")".
%% Subfilter for a single attribute
subfilter({UIDAttr, UIDAttrFormat}) ->
"(" ++ UIDAttr ++ "=" ++ UIDAttrFormat ++ ")";
%% The default UiDAttrFormat is %u
subfilter({UIDAttr}) ->
"(" ++ UIDAttr ++ "=" ++ "%u)".
%% Not tail-recursive, but it is not very terribly.
%% It stops finding on the first not empty value.
find_ldap_attrs([{Attr, Format} | Rest], Attributes) ->
case get_ldap_attr(Attr, Attributes) of
Value when is_list(Value), Value /= "" ->
{Value, Format};
_ ->
find_ldap_attrs(Rest, Attributes)
end;
find_ldap_attrs([], _) ->
"".
get_ldap_attr(LDAPAttr, Attributes) ->
Res = lists:filter(
fun({Name, _}) ->
case_insensitive_match(Name, LDAPAttr)
end, Attributes),
case Res of
[{_, [Value|_]}] -> Value;
_ -> ""
end.
usort_attrs(Attrs) when is_list(Attrs) ->
lists:usort(Attrs);
usort_attrs(_) ->
[].
get_user_part(String, Pattern) ->
F = fun(S, P) ->
First = string:str(P, "%u"),
TailLength = length(P) - (First+1),
string:sub_string(S, First, length(S) - TailLength)
end,
case catch F(String, Pattern) of
{'EXIT', _} ->
{error, badmatch};
Result ->
case regexp:sub(Pattern, "%u", Result) of
{ok, String, _} -> {ok, Result};
_ -> {error, badmatch}
end
end.
make_filter(Data, UIDs) ->
NewUIDs = [{U, eldap_filter:do_sub(UF, [{"%u", "*%u*", 1}])} || {U, UF} <- UIDs],
Filter = lists:flatmap(
fun({Name, [Value | _]}) ->
case Name of
"%u" when Value /= "" ->
case eldap_filter:parse(
lists:flatten(generate_subfilter(NewUIDs)),
[{"%u", Value}]) of
{ok, F} -> [F];
_ -> []
end;
_ when Value /= "" ->
[eldap:substrings(Name, [{any, Value}])];
_ ->
[]
end
end, Data),
case Filter of
[F] ->
F;
_ ->
eldap:'and'(Filter)
end.
case_insensitive_match(X, Y) ->
X1 = stringprep:tolower(X),
Y1 = stringprep:tolower(Y),
if
X1 == Y1 -> true;
true -> false
end.

View File

@ -46,8 +46,7 @@
dn,
base,
password,
uid,
uid_format,
uids,
vcard_map,
vcard_map_attrs,
user_filter,
@ -552,10 +551,9 @@ search(State, Data) ->
Base = State#state.base,
SearchFilter = State#state.search_filter,
Eldap_ID = State#state.eldap_id,
UA = State#state.uid,
UAF = State#state.uid_format,
UIDs = State#state.uids,
ReportedAttrs = State#state.search_reported_attrs,
Filter = eldap:'and'([SearchFilter, make_filter(Data, UA, UAF)]),
Filter = eldap:'and'([SearchFilter, eldap_utils:make_filter(Data, UIDs)]),
case eldap:search(Eldap_ID, [{base, Base},
{filter, Filter},
{attributes, ReportedAttrs}]) of
@ -569,8 +567,7 @@ search_items(Entries, State) ->
LServer = State#state.serverhost,
SearchReported = State#state.search_reported,
VCardMap = State#state.vcard_map,
UIDAttr = State#state.uid,
UIDAttrFormat = State#state.uid_format,
UIDs = State#state.uids,
Attributes = lists:map(
fun(E) ->
#eldap_entry{attributes = Attrs} = E,
@ -578,12 +575,13 @@ search_items(Entries, State) ->
end, Entries),
lists:flatmap(
fun(Attrs) ->
U = get_ldap_attr(UIDAttr, Attrs),
case get_user_part(U, UIDAttrFormat) of
{ok, Username} ->
case ejabberd_auth:is_user_exists(Username, LServer) of
true ->
RFields = lists:map(
case eldap_utils:find_ldap_attrs(UIDs, Attrs) of
{U, UIDAttrFormat} ->
case eldap_utils:get_user_part(U, UIDAttrFormat) of
{ok, Username} ->
case ejabberd_auth:is_user_exists(Username, LServer) of
true ->
RFields = lists:map(
fun({_, VCardName}) ->
{VCardName,
map_vcard_attr(
@ -592,41 +590,20 @@ search_items(Entries, State) ->
VCardMap,
{Username, ?MYNAME})}
end, SearchReported),
Result = [?FIELD("jid", Username ++ "@" ++ LServer)] ++
[?FIELD(Name, Value) || {Name, Value} <- RFields],
[{xmlelement, "item", [], Result}];
_ ->
[]
end;
_ ->
Result = [?FIELD("jid", Username ++ "@" ++ LServer)] ++
[?FIELD(Name, Value) || {Name, Value} <- RFields],
[{xmlelement, "item", [], Result}];
_ ->
[]
end;
_ ->
[]
end;
"" ->
[]
end
end
end, Attributes).
make_filter(Data, UAttr, UAttrFormat) ->
Filter = lists:flatmap(
fun({Name, [Value | _]}) ->
case Name of
"%u" when Value /= "" ->
{ok, UAF, _} = regexp:sub(UAttrFormat, "%u", "*%u*"),
case eldap_filter:parse(
"("++UAttr++"="++UAF++")", [{"%u", Value}]) of
{ok, F} -> [F];
_ -> []
end;
_ when Value /= "" ->
[eldap:substrings(Name, [{any, Value}])];
_ ->
[]
end
end, Data),
case Filter of
[F] ->
F;
_ ->
eldap:'and'(Filter)
end.
remove_user(_User) ->
true.
@ -634,39 +611,15 @@ remove_user(_User) ->
%%% Auxiliary functions.
%%%-----------------------
get_user_part(String, Pattern) ->
F = fun(S, P) ->
First = string:str(P, "%u"),
TailLength = length(P) - (First+1),
string:sub_string(S, First, length(S) - TailLength)
end,
case catch F(String, Pattern) of
{'EXIT', _} ->
{error, badmatch};
Result ->
case regexp:sub(Pattern, "%u", Result) of
{ok, String, _} -> {ok, Result};
_ -> {error, badmatch}
end
end.
case_insensitive_match(X, Y) ->
X1 = stringprep:tolower(X),
Y1 = stringprep:tolower(Y),
if
X1 == Y1 -> true;
true -> false
end.
map_vcard_attr(VCardName, Attributes, Pattern, UD) ->
Res = lists:filter(
fun({Name, _, _}) ->
case_insensitive_match(Name, VCardName)
eldap_utils:case_insensitive_match(Name, VCardName)
end, Pattern),
case Res of
[{_, Str, Attrs}] ->
process_pattern(Str, UD,
[get_ldap_attr(X, Attributes) || X<-Attrs]);
[eldap_utils:get_ldap_attr(X, Attributes) || X<-Attrs]);
_ -> ""
end.
@ -674,16 +627,6 @@ process_pattern(Str, {User, Domain}, AttrValues) ->
eldap_filter:do_sub(Str,
[{"%s", V, 1} || V <- AttrValues] ++ [{"%u", User},{"%d", Domain}]).
get_ldap_attr(LDAPAttr, Attributes) ->
Res = lists:filter(
fun({Name, _}) ->
case_insensitive_match(Name, LDAPAttr)
end, Attributes),
case Res of
[{_, [Value|_]}] -> Value;
_ -> ""
end.
find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) ->
find_xdata_el1(SubEls).
@ -721,22 +664,14 @@ parse_options(Host, Opts) ->
ejabberd_config:get_local_option({ldap_base, Host});
B -> B
end,
UIDAttr = case gen_mod:get_opt(ldap_uidattr, Opts, undefined) of
undefined ->
case ejabberd_config:get_local_option({ldap_uidattr, Host}) of
undefined -> "uid";
UA -> UA
end;
UA -> UA
end,
UIDAttrFormat = case gen_mod:get_opt(ldap_uidattr_format, Opts, undefined) of
undefined ->
case ejabberd_config:get_local_option({ldap_uidattr_format, Host}) of
undefined -> "%u";
UAF -> UAF
end;
UAF -> UAF
end,
UIDs = case gen_mod:get_opt(ldap_uids, Opts, undefined) of
undefined ->
case ejabberd_config:get_local_option({ldap_uids, Host}) of
undefined -> [{"uid", "%u"}];
UI -> UI
end;
UI -> UI
end,
RootDN = case gen_mod:get_opt(ldap_rootdn, Opts, undefined) of
undefined ->
case ejabberd_config:get_local_option({ldap_rootdn, Host}) of
@ -753,7 +688,7 @@ parse_options(Host, Opts) ->
end;
Pass -> Pass
end,
SubFilter = "("++UIDAttr++"="++UIDAttrFormat++")",
SubFilter = lists:flatten(eldap_utils:generate_subfilter(UIDs)),
UserFilter = case gen_mod:get_opt(ldap_filter, Opts, undefined) of
undefined ->
case ejabberd_config:get_local_option({ldap_filter, Host}) of
@ -772,8 +707,9 @@ parse_options(Host, Opts) ->
%% In search requests we need to fetch only attributes defined
%% in vcard-map and search-reported. In some cases,
%% this will essentially reduce network traffic from an LDAP server.
UIDAttrs = [UAttr || {UAttr, _} <- UIDs],
VCardMapAttrs = lists:usort(
lists:append([A || {_, _, A} <- VCardMap]) ++ [UIDAttr]),
lists:append([A || {_, _, A} <- VCardMap]) ++ UIDAttrs),
SearchReportedAttrs =
lists:usort(lists:flatmap(
fun({_, N}) ->
@ -781,7 +717,7 @@ parse_options(Host, Opts) ->
{value, {_, _, L}} -> L;
_ -> []
end
end, SearchReported) ++ [UIDAttr]),
end, SearchReported) ++ UIDAttrs),
#state{serverhost = Host,
myhost = MyHost,
eldap_id = Eldap_ID,
@ -791,8 +727,7 @@ parse_options(Host, Opts) ->
dn = RootDN,
base = LDAPBase,
password = Password,
uid = UIDAttr,
uid_format = UIDAttrFormat,
uids = UIDs,
vcard_map = VCardMap,
vcard_map_attrs = VCardMapAttrs,
user_filter = UserFilter,