Skip to content

Commit 7ac0ec3

Browse files
committed
ldap: Add mTLS authentication support to LDAP backend
1 parent 43487d4 commit 7ac0ec3

4 files changed

Lines changed: 62 additions & 14 deletions

File tree

internal/bootstrap/service_bootstrap.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ func (app *BootstrapApp) initServices() (Services, error) {
3737
BaseDN: app.config.Ldap.BaseDN,
3838
Insecure: app.config.Ldap.Insecure,
3939
SearchFilter: app.config.Ldap.SearchFilter,
40+
AuthCert: app.config.Ldap.AuthCert,
41+
AuthKey: app.config.Ldap.AuthKey,
4042
})
4143

4244
err = ldapService.Init()

internal/config/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ type LdapConfig struct {
6666
BaseDN string `description:"Base DN for LDAP searches." yaml:"baseDn"`
6767
Insecure bool `description:"Allow insecure LDAP connections." yaml:"insecure"`
6868
SearchFilter string `description:"LDAP search filter." yaml:"searchFilter"`
69+
AuthCert string `description:"Certificate for mTLS authentication." yaml:"authCert"`
70+
AuthKey string `description:"Certificate key for mTLS authentication." yaml:"authKey"`
6971
}
7072

7173
type ExperimentalConfig struct {

internal/service/auth_service.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func (auth *AuthService) VerifyUser(search config.UserSearch, password string) b
101101
return false
102102
}
103103

104-
err = auth.ldap.Bind(auth.ldap.Config.BindDN, auth.ldap.Config.BindPassword)
104+
err = auth.ldap.BindService()
105105
if err != nil {
106106
log.Error().Err(err).Msg("Failed to rebind with service account after user authentication")
107107
return false

internal/service/ldap_service.go

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@ type LdapServiceConfig struct {
1919
BaseDN string
2020
Insecure bool
2121
SearchFilter string
22+
AuthCert string
23+
AuthKey string
2224
}
2325

2426
type LdapService struct {
2527
Config LdapServiceConfig // exported so as the auth service can use it
2628
conn *ldapgo.Conn
2729
mutex sync.RWMutex
30+
cert *tls.Certificate
2831
}
2932

3033
func NewLdapService(config LdapServiceConfig) *LdapService {
@@ -34,6 +37,15 @@ func NewLdapService(config LdapServiceConfig) *LdapService {
3437
}
3538

3639
func (ldap *LdapService) Init() error {
40+
// Check whether authentication with client certificate is possible
41+
if ldap.Config.AuthCert != "" && ldap.Config.AuthKey != "" {
42+
cert, err := tls.LoadX509KeyPair(ldap.Config.AuthCert, ldap.Config.AuthKey)
43+
if err != nil {
44+
return fmt.Errorf("failed to initalize LDAP with mTLS authentication: %w", err)
45+
}
46+
ldap.cert = &cert
47+
log.Info().Msg("Using LDAP with mTLS authentication")
48+
}
3749
_, err := ldap.connect()
3850
if err != nil {
3951
return fmt.Errorf("failed to connect to LDAP server: %w", err)
@@ -60,22 +72,41 @@ func (ldap *LdapService) connect() (*ldapgo.Conn, error) {
6072
ldap.mutex.Lock()
6173
defer ldap.mutex.Unlock()
6274

63-
conn, err := ldapgo.DialURL(ldap.Config.Address, ldapgo.DialWithTLSConfig(&tls.Config{
64-
InsecureSkipVerify: ldap.Config.Insecure,
65-
MinVersion: tls.VersionTLS12,
66-
}))
67-
if err != nil {
68-
return nil, err
69-
}
75+
if ldap.cert != nil {
76+
conn, err := ldapgo.DialURL(ldap.Config.Address, ldapgo.DialWithTLSConfig(&tls.Config{
77+
MinVersion: tls.VersionTLS12,
78+
Certificates: []tls.Certificate{*ldap.cert},
79+
}))
80+
if err != nil {
81+
return nil, err
82+
}
7083

71-
err = conn.Bind(ldap.Config.BindDN, ldap.Config.BindPassword)
72-
if err != nil {
73-
return nil, err
84+
err = conn.ExternalBind()
85+
if err != nil {
86+
log.Error().Err(err).Msg("LDAP mTLS bind failed?")
87+
return nil, err
88+
}
89+
// Set and return the connection
90+
ldap.conn = conn
91+
return conn, nil
92+
} else {
93+
conn, err := ldapgo.DialURL(ldap.Config.Address, ldapgo.DialWithTLSConfig(&tls.Config{
94+
InsecureSkipVerify: ldap.Config.Insecure,
95+
MinVersion: tls.VersionTLS12,
96+
}))
97+
if err != nil {
98+
return nil, err
99+
}
100+
101+
err = conn.Bind(ldap.Config.BindDN, ldap.Config.BindPassword)
102+
if err != nil {
103+
return nil, err
104+
}
105+
// Set and return the connection
106+
ldap.conn = conn
107+
return conn, nil
74108
}
75109

76-
// Set and return the connection
77-
ldap.conn = conn
78-
return conn, nil
79110
}
80111

81112
func (ldap *LdapService) Search(username string) (string, error) {
@@ -107,6 +138,19 @@ func (ldap *LdapService) Search(username string) (string, error) {
107138
return userDN, nil
108139
}
109140

141+
func (ldap *LdapService) BindService() error {
142+
ldap.mutex.Lock()
143+
defer ldap.mutex.Unlock()
144+
145+
var err error
146+
if ldap.cert != nil {
147+
err = ldap.conn.ExternalBind()
148+
} else {
149+
err = ldap.conn.Bind(ldap.Config.BindDN, ldap.Config.BindPassword)
150+
}
151+
return err
152+
}
153+
110154
func (ldap *LdapService) Bind(userDN string, password string) error {
111155
ldap.mutex.Lock()
112156
defer ldap.mutex.Unlock()

0 commit comments

Comments
 (0)