new option ldap_tls_verify is added (EJAB-1229)
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>
Mon, 10 May 2010 09:37:37 +0000 (19:37 +1000)
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>
Mon, 10 May 2010 09:37:37 +0000 (19:37 +1000)
doc/guide.tex
src/ejabberd_auth_ldap.erl
src/eldap/eldap.erl
src/eldap/eldap_pool.erl
src/mod_vcard_ldap.erl

index fea9d55e639239e1d1f6b04bafcf3b9ce95d615c..bef001c3267ba64778ff89278eb9ee8ace7d777a 100644 (file)
@@ -2187,6 +2187,11 @@ Allowed values are: \term{none}, \term{tls}.
 The value \term{tls} enables encryption by using LDAP over SSL.
 Note that STARTTLS encryption is not supported.
 The default value is: \term{none}.
+\titem{\{ldap\_tls\_verify, false|soft|hard\}} \ind{options!ldap\_tls\_verify}
+This option specifies whether to verify LDAP server certificate or not when TLS is enabled.
+When \term{hard} is enabled \ejabberd{} doesn't proceed if a certificate is invalid.
+When \term{soft} is enabled \ejabberd{} proceeds even if check fails.
+The default is \term{false} which means no checks are performed.
 \titem{\{ldap\_port, Number\}} \ind{options!ldap\_port}Port to connect to your LDAP server.
 The default port is~389 if encryption is disabled; and 636 if encryption is enabled.
 If you configure a value, it is stored in \ejabberd{}'s database.
index 9c490bb9301ee26f7f65ec77c2537ae84d878cbf..b96571366d7dc8961ce7376ac940fdfaa032008a 100644 (file)
@@ -66,7 +66,7 @@
                servers,
                backups,
                port,
-               encrypt,
+               tls_options,
                dn,
                password,
                base,
@@ -119,19 +119,19 @@ terminate(_Reason, _State) ->
 init(Host) ->
     State = parse_options(Host),
     eldap_pool:start_link(State#state.eldap_id,
-                    State#state.servers,
-                    State#state.backups,
-                    State#state.port,
-                    State#state.dn,
-                    State#state.password,
-                    State#state.encrypt),
+                         State#state.servers,
+                         State#state.backups,
+                         State#state.port,
+                         State#state.dn,
+                         State#state.password,
+                         State#state.tls_options),
     eldap_pool:start_link(State#state.bind_eldap_id,
-                    State#state.servers,
-                    State#state.backups,
-                    State#state.port,
-                    State#state.dn,
-                    State#state.password,
-                    State#state.encrypt),
+                         State#state.servers,
+                         State#state.backups,
+                         State#state.port,
+                         State#state.dn,
+                         State#state.password,
+                         State#state.tls_options),
     {ok, State}.
 
 plain_password_required() ->
@@ -373,6 +373,7 @@ parse_options(Host) ->
                   Backups -> Backups
                   end,
     LDAPEncrypt = ejabberd_config:get_local_option({ldap_encrypt, Host}),
+    LDAPTLSVerify = ejabberd_config:get_local_option({ldap_tls_verify, Host}),
     LDAPPort = case ejabberd_config:get_local_option({ldap_port, Host}) of
                   undefined -> case LDAPEncrypt of
                                    tls -> ?LDAPS_PORT;
@@ -417,7 +418,8 @@ parse_options(Host) ->
           servers = LDAPServers,
           backups = LDAPBackups,
           port = LDAPPort,
-          encrypt = LDAPEncrypt,
+          tls_options = [{encrypt, LDAPEncrypt},
+                         {tls_verify, LDAPTLSVerify}],
           dn = RootDN,
           password = Password,
           base = LDAPBase,
index 5bc0c425af91d282cea28e3403a22258f21d33b3..82f0df47869a155aa56e957ccdb1f816ecc2b0c9 100644 (file)
@@ -130,9 +130,10 @@ start_link(Name) ->
     Reg_name = list_to_atom("eldap_" ++ Name),
     gen_fsm:start_link({local, Reg_name}, ?MODULE, [], []).
 
-start_link(Name, Hosts, Port, Rootdn, Passwd, Encrypt) ->
+start_link(Name, Hosts, Port, Rootdn, Passwd, Opts) ->
     Reg_name = list_to_atom("eldap_" ++ Name),
-    gen_fsm:start_link({local, Reg_name}, ?MODULE, {Hosts, Port, Rootdn, Passwd, Encrypt}, []).
+    gen_fsm:start_link({local, Reg_name}, ?MODULE,
+                      {Hosts, Port, Rootdn, Passwd, Opts}, []).
 
 %%% --------------------------------------------------------------------
 %%% Get status of connection.
@@ -423,15 +424,19 @@ get_handle(Name) when is_list(Name) -> list_to_atom("eldap_" ++ Name).
 %%----------------------------------------------------------------------
 init([]) ->
     case get_config() of
-       {ok, Hosts, Rootdn, Passwd, Encrypt} ->
-           init({Hosts, Rootdn, Passwd, Encrypt});
+       {ok, Hosts, Rootdn, Passwd, Opts} ->
+           init({Hosts, Rootdn, Passwd, Opts});
        {error, Reason} ->
            {stop, Reason}
     end;
-init({Hosts, Port, Rootdn, Passwd, Encrypt}) ->
+init({Hosts, Port, Rootdn, Passwd, Opts}) ->
     catch ssl:start(),
     {X1,X2,X3} = erlang:now(),
     ssl:seed(integer_to_list(X1) ++ integer_to_list(X2) ++ integer_to_list(X3)),
+    Encrypt = case proplists:get_value(encrypt, Opts) of
+                 tls -> tls;
+                 _ -> none
+             end,
     PortTemp = case Port of
                   undefined ->
                       case Encrypt of
@@ -444,7 +449,14 @@ init({Hosts, Port, Rootdn, Passwd, Encrypt}) ->
                       end;
                   PT -> PT
               end,
-    TLSOpts = [verify_none],
+    TLSOpts = case proplists:get_value(tls_verify, Opts) of
+                 soft ->
+                     [{verify, 1}];
+                 hard ->
+                     [{verify, 2}];
+                 _ ->
+                     [{verify, 0}]
+             end,
     {ok, connecting, #eldap{hosts = Hosts,
                            port = PortTemp,
                            rootdn = Rootdn,
@@ -958,7 +970,7 @@ connect_bind(S) ->
                     tls ->
                         SockMod = ssl,
                         SslOpts = [{packet, asn1}, {active, true}, {keepalive, true},
-                                   binary],
+                                   binary | S#eldap.tls_options],
                         ssl:connect(Host, S#eldap.port, SslOpts);
                     %% starttls -> %% TODO: Implement STARTTLS;
                     _ ->
@@ -1074,8 +1086,8 @@ get_config() ->
     case file:consult(File) of
        {ok, Entries} ->
            case catch parse(Entries) of
-               {ok, Hosts, Port, Rootdn, Passwd, Encrypt} ->
-                   {ok, Hosts, Port, Rootdn, Passwd, Encrypt};
+               {ok, Hosts, Port, Rootdn, Passwd, Opts} ->
+                   {ok, Hosts, Port, Rootdn, Passwd, Opts};
                {error, Reason} ->
                    {error, Reason};
                {'EXIT', Reason} ->
@@ -1091,7 +1103,7 @@ parse(Entries) ->
      get_integer(port, Entries),
      get_list(rootdn, Entries),
      get_list(passwd, Entries),
-     get_atom(encrypt, Entries)}.
+     get_list(options, Entries)}.
 
 get_integer(Key, List) ->
     case lists:keysearch(Key, 1, List) of
@@ -1113,15 +1125,15 @@ get_list(Key, List) ->
            throw({error, "No Entry in Config for " ++ atom_to_list(Key)})
     end.
 
-get_atom(Key, List) ->
-    case lists:keysearch(Key, 1, List) of
-       {value, {Key, Value}} when is_atom(Value) ->
-           Value;
-       {value, {Key, _Value}} ->
-           throw({error, "Bad Value in Config for " ++ atom_to_list(Key)});
-       false ->
-           throw({error, "No Entry in Config for " ++ atom_to_list(Key)})
-    end.
+%% get_atom(Key, List) ->
+%%     case lists:keysearch(Key, 1, List) of
+%%     {value, {Key, Value}} when is_atom(Value) ->
+%%         Value;
+%%     {value, {Key, _Value}} ->
+%%         throw({error, "Bad Value in Config for " ++ atom_to_list(Key)});
+%%     false ->
+%%         throw({error, "No Entry in Config for " ++ atom_to_list(Key)})
+%%     end.
 
 get_hosts(Key, List) ->
     lists:map(fun({Key1, {A,B,C,D}}) when is_integer(A),
index 2331b2c05f246fb97f881550595416611349f242..ed03692e7e526651941e42a54e855ca4c6373fc8 100644 (file)
@@ -49,18 +49,20 @@ search(PoolName, Opts) ->
 modify_passwd(PoolName, DN, Passwd) ->
     do_request(PoolName, {modify_passwd, [DN, Passwd]}).
 
-start_link(Name, Hosts, Backups, Port, Rootdn, Passwd, Encrypt) ->
+start_link(Name, Hosts, Backups, Port, Rootdn, Passwd, Opts) ->
     PoolName = make_id(Name),
     pg2:create(PoolName),
-    lists:foreach(fun(Host) ->
-                         ID = erlang:ref_to_list(make_ref()),
-                         case catch eldap:start_link(ID, [Host|Backups], Port, Rootdn, Passwd, Encrypt) of
-                             {ok, Pid} ->
-                                 pg2:join(PoolName, Pid);
-                             _ ->
-                                 error
-                         end
-                 end, Hosts).
+    lists:foreach(
+      fun(Host) ->
+             ID = erlang:ref_to_list(make_ref()),
+             case catch eldap:start_link(ID, [Host|Backups], Port,
+                                         Rootdn, Passwd, Opts) of
+                 {ok, Pid} ->
+                     pg2:join(PoolName, Pid);
+                 _ ->
+                     error
+             end
+      end, Hosts).
 
 %%====================================================================
 %% Internal functions
index f4078dfc439abcf61820d5f18bf2be2a620f3e6e..ed52a05939f2560fc40faba750a7f92ccd546b1c 100644 (file)
@@ -62,7 +62,7 @@
                servers,
                backups,
                port,
-               encrypt,
+               tls_options,
                dn,
                base,
                password,
@@ -181,7 +181,7 @@ init([Host, Opts]) ->
                     State#state.port,
                     State#state.dn,
                     State#state.password,
-                    State#state.encrypt),
+                    State#state.tls_options),
     case State#state.search of
        true ->
            ejabberd_router:register_route(State#state.myhost);
@@ -686,6 +686,11 @@ parse_options(Host, Opts) ->
                          ejabberd_config:get_local_option({ldap_encrypt, Host});
                      E -> E
                  end,
+    LDAPTLSVerify = case gen_mod:get_opt(ldap_tls_verify, Opts, undefined) of
+                       undefined ->
+                           ejabberd_config:get_local_option({ldap_tls_verify, Host});
+                       Verify -> Verify
+                   end,
     LDAPPortTemp = case gen_mod:get_opt(ldap_port, Opts, undefined) of
                       undefined ->
                           ejabberd_config:get_local_option({ldap_port, Host});
@@ -766,7 +771,8 @@ parse_options(Host, Opts) ->
           servers = LDAPServers,
           backups = LDAPBackups,
           port = LDAPPort,
-          encrypt = LDAPEncrypt,
+          tls_options = [{encrypt, LDAPEncrypt},
+                         {tls_verify, LDAPTLSVerify}],
           dn = RootDN,
           base = LDAPBase,
           password = Password,