Skip to content

Commit cce5557

Browse files
author
Jon Gyllenswärd
authored
LDAP: All LDAP servers should be tried even if one of them returns a connection error (grafana#20077)
All ldap servers are now being tried and the first one that gives back an answer is used if a previous one is failing. Applies to login and syncing
1 parent 5210a8f commit cce5557

File tree

2 files changed

+84
-6
lines changed

2 files changed

+84
-6
lines changed

pkg/services/multildap/multildap.go

+33-6
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,17 @@ func (multiples *MultiLDAP) Login(query *models.LoginUserQuery) (
109109
return nil, ErrNoLDAPServers
110110
}
111111

112-
for _, config := range multiples.configs {
112+
for index, config := range multiples.configs {
113113
server := newLDAP(config)
114114

115115
if err := server.Dial(); err != nil {
116-
return nil, err
116+
logDialFailure(err, config)
117+
118+
// Only return an error if it is the last server so we can try next server
119+
if index == len(multiples.configs)-1 {
120+
return nil, err
121+
}
122+
continue
117123
}
118124

119125
defer server.Close()
@@ -155,11 +161,17 @@ func (multiples *MultiLDAP) User(login string) (
155161
}
156162

157163
search := []string{login}
158-
for _, config := range multiples.configs {
164+
for index, config := range multiples.configs {
159165
server := newLDAP(config)
160166

161167
if err := server.Dial(); err != nil {
162-
return nil, *config, err
168+
logDialFailure(err, config)
169+
170+
// Only return an error if it is the last server so we can try next server
171+
if index == len(multiples.configs)-1 {
172+
return nil, *config, err
173+
}
174+
continue
163175
}
164176

165177
defer server.Close()
@@ -192,11 +204,17 @@ func (multiples *MultiLDAP) Users(logins []string) (
192204
return nil, ErrNoLDAPServers
193205
}
194206

195-
for _, config := range multiples.configs {
207+
for index, config := range multiples.configs {
196208
server := newLDAP(config)
197209

198210
if err := server.Dial(); err != nil {
199-
return nil, err
211+
logDialFailure(err, config)
212+
213+
// Only return an error if it is the last server so we can try next server
214+
if index == len(multiples.configs)-1 {
215+
return nil, err
216+
}
217+
continue
200218
}
201219

202220
defer server.Close()
@@ -228,3 +246,12 @@ func isSilentError(err error) bool {
228246

229247
return false
230248
}
249+
250+
func logDialFailure(err error, config *ldap.ServerConfig) {
251+
logger.Debug(
252+
"unable to dial LDAP server",
253+
"host", config.Host,
254+
"port", config.Port,
255+
"error", err,
256+
)
257+
}

pkg/services/multildap/multildap_test.go

+51
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,24 @@ func TestMultiLDAP(t *testing.T) {
171171
teardown()
172172
})
173173

174+
Convey("Should still try to auth with the second server after receiving a dial error from the first", func() {
175+
mock := setup()
176+
177+
expectedError := errors.New("Dial error")
178+
mock.dialErrReturn = expectedError
179+
180+
multi := New([]*ldap.ServerConfig{
181+
{}, {},
182+
})
183+
_, err := multi.Login(&models.LoginUserQuery{})
184+
185+
So(mock.dialCalledTimes, ShouldEqual, 2)
186+
187+
So(err, ShouldEqual, expectedError)
188+
189+
teardown()
190+
})
191+
174192
Convey("Should return unknown error", func() {
175193
mock := setup()
176194

@@ -287,9 +305,42 @@ func TestMultiLDAP(t *testing.T) {
287305

288306
teardown()
289307
})
308+
309+
Convey("Should still try to auth with the second server after receiving a dial error from the first", func() {
310+
mock := setup()
311+
312+
expectedError := errors.New("Dial error")
313+
mock.dialErrReturn = expectedError
314+
315+
multi := New([]*ldap.ServerConfig{
316+
{}, {},
317+
})
318+
_, _, err := multi.User("test")
319+
320+
So(mock.dialCalledTimes, ShouldEqual, 2)
321+
So(err, ShouldEqual, expectedError)
322+
323+
teardown()
324+
})
290325
})
291326

292327
Convey("Users()", func() {
328+
Convey("Should still try to auth with the second server after receiving a dial error from the first", func() {
329+
mock := setup()
330+
331+
expectedError := errors.New("Dial error")
332+
mock.dialErrReturn = expectedError
333+
334+
multi := New([]*ldap.ServerConfig{
335+
{}, {},
336+
})
337+
_, err := multi.Users([]string{"test"})
338+
339+
So(mock.dialCalledTimes, ShouldEqual, 2)
340+
So(err, ShouldEqual, expectedError)
341+
342+
teardown()
343+
})
293344
Convey("Should return error for absent config list", func() {
294345
setup()
295346

0 commit comments

Comments
 (0)