./ct_report/coverage/mongoose_ldap_worker.COVER.html

1 -module(mongoose_ldap_worker).
2
3 -behaviour(gen_server).
4
5 %% gen_server callbacks
6 -export([init/1,
7 handle_call/3,
8 handle_cast/2,
9 handle_info/2,
10 terminate/2,
11 code_change/3]).
12
13 -include("mongoose.hrl").
14
15 -type state() :: #{handle := none | eldap_utils:handle(),
16 servers := [string()],
17 tls_options := list(),
18 port := pos_integer(),
19 root_dn := binary(),
20 password := binary(),
21 connect_interval := pos_integer()}.
22 -type request() :: {function(), Args :: [any()]}.
23
24 %% gen_server callbacks
25
26 -spec init(gen_mod:module_opts()) -> {ok, state()}.
27 init(Options) ->
28 1000 State = initial_state(Options),
29 1000 self() ! connect,
30 1000 {ok, State}.
31
32 -spec handle_call(request(), {pid(), any()}, state()) -> {reply, any(), state()}.
33 handle_call(Request, _From, State) ->
34 26095 {Result, NewState} = call_eldap(Request, State),
35 26095 {reply, Result, NewState}.
36
37 -spec handle_cast(any(), state()) -> {noreply, state()}.
38 handle_cast(Cast, State) ->
39
:-(
?UNEXPECTED_CAST(Cast),
40
:-(
{noreply, State}.
41
42 -spec handle_info(any(), state()) -> {noreply, state()}.
43 handle_info(connect, State) ->
44 1000 {noreply, connect(State)};
45 handle_info(Info, State) ->
46
:-(
?UNEXPECTED_INFO(Info),
47
:-(
{noreply, State}.
48
49 -spec terminate(any(), state()) -> ok.
50
:-(
terminate(_Reason, #{handle := none}) -> ok;
51
:-(
terminate(_Reason, #{handle := Handle}) -> eldap:close(Handle).
52
53 -spec code_change(any(), state(), any()) -> {ok, state()}.
54 code_change(_OldVsn, State, _Extra) ->
55
:-(
{ok, State}.
56
57 %% internal functions
58
59 initial_state(Opts) ->
60 1000 Opts#{handle => none}.
61
62 call_eldap(Request, State) ->
63 26095 case do_call_eldap(Request, State) of
64 {error, Reason} when Reason =:= ldap_closed;
65 Reason =:= {gen_tcp_error, closed} ->
66
:-(
?LOG_INFO(#{what => ldap_request_failed, reason => Reason,
67
:-(
text => <<"LDAP request failed: connection closed, reconnecting...">>}),
68
:-(
eldap:close(maps:get(handle, State)),
69
:-(
NewState = connect(State#{handle := none}),
70
:-(
retry_call_eldap(Request, NewState);
71 Result ->
72 26095 {Result, State}
73 end.
74
75 connect(State = #{handle := none,
76 servers := Servers,
77 port := Port,
78 root_dn := RootDN,
79 password := Password,
80 connect_interval := ConnectInterval}) ->
81 1000 AnonAuth = RootDN =:= <<>> andalso Password =:= <<>>,
82 1000 SSLConfig = case State of
83 1000 #{tls := TLSOptions} -> [{sslopts, just_tls:make_ssl_opts(TLSOptions)}];
84
:-(
#{} -> []
85 end,
86 1000 case eldap:open(Servers, [{port, Port}, {anon_auth, AnonAuth}] ++ SSLConfig) of
87 {ok, Handle} ->
88 1000 case eldap:simple_bind(Handle, RootDN, Password) of
89 ok ->
90 1000 ?LOG_INFO(#{what => ldap_connected,
91 1000 text => <<"Connected to LDAP server">>}),
92 1000 State#{handle := Handle};
93 Error ->
94
:-(
?LOG_ERROR(#{what => ldap_auth_failed, reason => Error,
95 text => <<"LDAP bind returns an error">>,
96
:-(
ldap_servers => Servers, port => Port}),
97
:-(
eldap:close(Handle),
98
:-(
erlang:send_after(ConnectInterval, self(), connect),
99
:-(
State
100 end;
101 Error ->
102
:-(
?LOG_ERROR(#{what => ldap_connect_failed,
103 text => <<"LDAP open returns an error">>,
104
:-(
ldap_servers => Servers, port => Port, reason => Error}),
105
:-(
erlang:send_after(ConnectInterval, self(), connect),
106
:-(
State
107 end.
108
109 retry_call_eldap(Request, State) ->
110
:-(
Result = do_call_eldap(Request, State),
111
:-(
{Result, State}.
112
113
:-(
do_call_eldap(_Request, #{handle := none}) -> {error, not_connected};
114 26095 do_call_eldap({F, Args}, #{handle := Handle}) -> apply(eldap, F, [Handle | Args]).
Line Hits Source