2006-10-17 14:35:47 +02:00
|
|
|
%%%----------------------------------------------------------------------
|
|
|
|
%%% File : eldap_utils.erl
|
2007-12-24 14:57:53 +01:00
|
|
|
%%% Author : Mickael Remond <mremond@process-one.net>
|
2006-10-17 14:35:47 +02:00
|
|
|
%%% Purpose : ejabberd LDAP helper functions
|
2007-12-24 14:57:53 +01:00
|
|
|
%%% Created : 12 Oct 2006 by Mickael Remond <mremond@process-one.net>
|
|
|
|
%%%
|
|
|
|
%%%
|
2008-09-16 16:39:57 +02:00
|
|
|
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
|
2007-12-24 14:57:53 +01:00
|
|
|
%%%
|
|
|
|
%%% This program is free software; you can redistribute it and/or
|
|
|
|
%%% modify it under the terms of the GNU General Public License as
|
|
|
|
%%% published by the Free Software Foundation; either version 2 of the
|
|
|
|
%%% License, or (at your option) any later version.
|
|
|
|
%%%
|
|
|
|
%%% This program is distributed in the hope that it will be useful,
|
|
|
|
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
%%% General Public License for more details.
|
|
|
|
%%%
|
|
|
|
%%% You should have received a copy of the GNU General Public License
|
|
|
|
%%% along with this program; if not, write to the Free Software
|
|
|
|
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
|
|
%%% 02111-1307 USA
|
|
|
|
%%%
|
2006-10-17 14:35:47 +02:00
|
|
|
%%%----------------------------------------------------------------------
|
|
|
|
|
|
|
|
-module(eldap_utils).
|
2007-12-24 14:57:53 +01:00
|
|
|
-author('mremond@process-one.net').
|
2006-10-17 14:35:47 +02:00
|
|
|
|
|
|
|
-export([generate_subfilter/1,
|
|
|
|
find_ldap_attrs/2,
|
|
|
|
get_ldap_attr/2,
|
|
|
|
usort_attrs/1,
|
|
|
|
get_user_part/2,
|
2006-11-04 16:33:20 +01:00
|
|
|
make_filter/2,
|
2007-01-27 17:40:37 +01:00
|
|
|
get_state/2,
|
|
|
|
case_insensitive_match/2,
|
|
|
|
uids_domain_subst/2]).
|
2006-10-17 14:35:47 +02:00
|
|
|
|
|
|
|
%% 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.
|
|
|
|
|
2007-01-27 17:40:37 +01:00
|
|
|
get_state(Server, Module) ->
|
|
|
|
Proc = gen_mod:get_module_proc(Server, Module),
|
|
|
|
gen_server:call(Proc, get_state).
|
|
|
|
|
|
|
|
%% From the list of uids attribute:
|
|
|
|
%% we look from alias domain (%d) and make the substitution
|
|
|
|
%% with the actual host domain
|
|
|
|
%% This help when you need to configure many virtual domains.
|
|
|
|
uids_domain_subst(Host, UIDs) ->
|
|
|
|
lists:map(fun({U,V}) ->
|
|
|
|
{U, eldap_filter:do_sub(V,[{"%d", Host}])};
|
|
|
|
(A) -> A
|
|
|
|
end,
|
2007-12-06 23:12:27 +01:00
|
|
|
UIDs).
|