mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-22 16:20:52 +01: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:
parent
95e2726f71
commit
d5792ed75e
@ -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
|
||||
|
@ -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>"(&(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, ""},
|
||||
|
@ -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, ""},
|
||||
|
@ -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,
|
||||
|
@ -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
110
src/eldap/eldap_utils.erl
Normal 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.
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user