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