Files
gitea-MIRROR/services/auth/source/ldap/source_search_test.go
Trung Hehe 06b393e402 feat(ldap): support multiple comma-separated LDAP hosts for failover (#6898) (#40201)
Allows an LDAP auth source to list multiple comma-separated servers in
the Host field so logins continue working when one server is
unreachable. Entries can be plain hosts using the configured Port and
Security Protocol fields or `ldap://`, `ldaps://`, or `ldap+starttls://`
URLs with their own port and protocol (as proposed in
https://github.com/go-gitea/gitea/pull/31649#issuecomment-2505555133),
with TLS protocol consistency enforced so an entry cannot silently
downgrade encryption.

Hosts are tried in order with a 250 ms head start each so an
unresponsive server does not block logins for the full 60 s connect
timeout, and only connection failures fail over to the next host so
failed binds are not retried across servers. Existing single-host
configurations continue to work unchanged without a migration.

Docs: https://gitea.com/gitea/docs/pulls/635
Fixes https://github.com/go-gitea/gitea/issues/6898
/claim #6898

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-11-09 21:45:12 +00:00

42 lines
1.2 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package ldap
import (
"fmt"
"net"
"net/http/httptest"
"net/netip"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDial(t *testing.T) {
silent, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(t, err)
defer silent.Close()
tlsServer := httptest.NewTLSServer(nil)
defer tlsServer.Close()
conn, err := dial(&Source{Host: " , ldap://127.0.0.1:1 , 127.0.0.1 , ", Port: int(netip.MustParseAddrPort(silent.Addr().String()).Port())})
require.NoError(t, err)
conn.Close()
start := time.Now()
conn, err = dial(&Source{Host: fmt.Sprintf("ldaps://%s, ldaps://%s", silent.Addr(), tlsServer.Listener.Addr()), SecurityProtocol: SecurityProtocolLDAPS, SkipVerify: true})
require.NoError(t, err)
assert.Less(t, time.Since(start), 10*time.Second)
conn.Close()
_, err = dial(&Source{Host: "ldaps://127.0.0.1:1, ldap://127.0.0.1", SecurityProtocol: SecurityProtocolStartTLS})
assert.ErrorContains(t, err, "ldaps://127.0.0.1:1: ")
assert.ErrorContains(t, err, "ldap://127.0.0.1: unsupported LDAP URL")
_, err = dial(&Source{Host: " , "})
assert.EqualError(t, err, "no LDAP host configured")
}