Skip to content

Commit ef63d66

Browse files
authored
fix: make LDAP verification context-aware (#4768)
I forked go-ldap/ldap from someone else's PR that had partial work to add contexts, then added just enough to have context on Bind, which could block if the server does the delay-on-bad-password thing, in addition to the Dial itself timing out. there's more room to improve LDAP verification but for now it can't hold up scanning
1 parent c3e599b commit ef63d66

4 files changed

Lines changed: 50 additions & 38 deletions

File tree

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ require (
4646
github.com/getsentry/sentry-go v0.32.0
4747
github.com/go-errors/errors v1.5.1
4848
github.com/go-git/go-git/v5 v5.13.2
49-
github.com/go-ldap/ldap/v3 v3.4.11
5049
github.com/go-logr/logr v1.4.3
5150
github.com/go-logr/zapr v1.3.0
5251
github.com/go-redis/redis v6.15.9+incompatible
@@ -70,6 +69,7 @@ require (
7069
github.com/lestrrat-go/jwx/v3 v3.0.12
7170
github.com/lib/pq v1.10.9
7271
github.com/lrstanley/bubblezone v0.0.0-20250404061050-e13639e27357
72+
github.com/mariduv/ldap-verify v0.0.2
7373
github.com/marusama/semaphore/v2 v2.5.0
7474
github.com/mattn/go-isatty v0.0.20
7575
github.com/mholt/archives v0.0.0-20241216060121-23e0af8fe73d
@@ -130,7 +130,7 @@ require (
130130
dario.cat/mergo v1.0.0 // indirect
131131
filippo.io/edwards25519 v1.1.0 // indirect
132132
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
133-
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
133+
github.com/Azure/go-ntlmssp v0.1.0 // indirect
134134
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 // indirect
135135
github.com/DataDog/zstd v1.5.5 // indirect
136136
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect

go.sum

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occ
5757
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI=
5858
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
5959
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
60-
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
61-
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
60+
github.com/Azure/go-ntlmssp v0.1.0 h1:DjFo6YtWzNqNvQdrwEyr/e4nhU3vRiwenz5QX7sFz+A=
61+
github.com/Azure/go-ntlmssp v0.1.0/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk=
6262
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 h1:kYRSnvJju5gYVyhkij+RTJ/VR6QIUaCfWeaFm2ycsjQ=
6363
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
6464
github.com/BobuSumisu/aho-corasick v1.0.3 h1:uuf+JHwU9CHP2Vx+wAy6jcksJThhJS9ehR8a+4nPE9g=
@@ -96,8 +96,6 @@ github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc
9696
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
9797
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
9898
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
99-
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
100-
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
10199
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
102100
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
103101
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
@@ -327,8 +325,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
327325
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
328326
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
329327
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
330-
github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU=
331-
github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM=
332328
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
333329
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
334330
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
@@ -450,8 +446,6 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
450446
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
451447
github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=
452448
github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=
453-
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
454-
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
455449
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
456450
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
457451
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
@@ -471,18 +465,6 @@ github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk
471465
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
472466
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
473467
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
474-
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
475-
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
476-
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
477-
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
478-
github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg=
479-
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
480-
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
481-
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
482-
github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8=
483-
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
484-
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
485-
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
486468
github.com/jedib0t/go-pretty/v6 v6.6.8 h1:JnnzQeRz2bACBobIaa/r+nqjvws4yEhcmaZ4n1QzsEc=
487469
github.com/jedib0t/go-pretty/v6 v6.6.8/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=
488470
github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg=
@@ -546,6 +528,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2
546528
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
547529
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
548530
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
531+
github.com/mariduv/ldap-verify v0.0.2 h1:NBdDTYyWDr71CONVcizasqL/AA9tQ2RNgLhTgnyfquI=
532+
github.com/mariduv/ldap-verify v0.0.2/go.mod h1:d/7+kkMBGDs9LPZ/7hmduYqtOkRIJcgpa8dL+9CsveE=
549533
github.com/marusama/semaphore/v2 v2.5.0 h1:o/1QJD9DBYOWRnDhPwDVAXQn6mQYD0gZaS1Tpx6DJGM=
550534
github.com/marusama/semaphore/v2 v2.5.0/go.mod h1:z9nMiNUekt/LTpTUQdpp+4sJeYqUGpwMHfW0Z8V8fnQ=
551535
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=

pkg/detectors/ldap/ldap.go

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ package ldap
33
import (
44
"context"
55
"crypto/tls"
6+
"errors"
67
"fmt"
78
"net"
89
"net/url"
910
"strings"
1011
"time"
1112

12-
"github.com/go-ldap/ldap/v3"
13+
ldap "github.com/mariduv/ldap-verify"
1314
regexp "github.com/wasilibs/go-re2"
1415

1516
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -72,7 +73,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
7273
}
7374

7475
if verify {
75-
verificationErr := verifyLDAP(username[1], password[1], ldapURL)
76+
verificationErr := verifyLDAP(ctx, username[1], password[1], ldapURL)
7677
s1.Verified = verificationErr == nil
7778
if !isErrDeterminate(verificationErr) {
7879
s1.SetVerificationError(verificationErr, password[1])
@@ -102,7 +103,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
102103
}
103104

104105
if verify {
105-
verificationError := verifyLDAP(username, password, ldapURL)
106+
verificationError := verifyLDAP(ctx, username, password, ldapURL)
106107

107108
s1.Verified = verificationError == nil
108109
if !isErrDeterminate(verificationError) {
@@ -117,32 +118,32 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
117118
}
118119

119120
func isErrDeterminate(err error) bool {
120-
switch e := err.(type) {
121-
case *ldap.Error:
122-
switch e.Err.(type) {
123-
case *net.OpError:
124-
return false
125-
}
121+
var neterr *net.OpError
122+
123+
if errors.As(err, &neterr) ||
124+
errors.Is(err, context.DeadlineExceeded) ||
125+
errors.Is(err, context.Canceled) {
126+
return false
126127
}
127128

128129
return true
129130
}
130131

131-
func verifyLDAP(username, password string, ldapURL *url.URL) error {
132+
func verifyLDAP(ctx context.Context, username, password string, ldapURL *url.URL) error {
132133
// Tests with non-TLS, TLS, and STARTTLS
133134

134135
uri := ldapURL.String()
135136

136137
switch ldapURL.Scheme {
137138
case "ldap":
138139
// Non-TLS dial
139-
l, err := ldap.DialURL(uri)
140+
l, err := ldap.DialURL(uri, ldap.DialWithContext(ctx))
140141
if err != nil {
141142
return err
142143
}
143144
defer l.Close()
144145
// Non-TLS verify
145-
err = l.Bind(username, password)
146+
err = l.BindContext(ctx, username, password)
146147
if err == nil {
147148
return nil
148149
}
@@ -153,20 +154,23 @@ func verifyLDAP(username, password string, ldapURL *url.URL) error {
153154
return err
154155
}
155156
// STARTTLS verify
156-
return l.Bind(username, password)
157+
return l.BindContext(ctx, username, password)
157158
case "ldaps":
158159
// TLS dial
159-
l, err := ldap.DialURL(uri, ldap.DialWithTLSConfig(&tls.Config{InsecureSkipVerify: true}))
160+
l, err := ldap.DialURL(
161+
uri,
162+
ldap.DialWithContext(ctx),
163+
ldap.DialWithTLSConfig(&tls.Config{InsecureSkipVerify: true}),
164+
)
160165
if err != nil {
161166
return err
162167
}
163168
defer l.Close()
164169
// TLS verify
165-
return l.Bind(username, password)
170+
return l.BindContext(ctx, username, password)
166171
default:
167172
return fmt.Errorf("unknown ldap scheme %q", ldapURL.Scheme)
168173
}
169-
170174
}
171175

172176
func (s Scanner) Type() detectorspb.DetectorType {

pkg/detectors/ldap/ldap_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package ldap
33
import (
44
"context"
55
"fmt"
6+
"net"
67
"testing"
78

89
"github.com/google/go-cmp/cmp"
10+
ldap "github.com/mariduv/ldap-verify"
911

1012
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
1113
"github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick"
@@ -84,3 +86,25 @@ func TestLdap_Pattern(t *testing.T) {
8486
})
8587
}
8688
}
89+
90+
func Test_isErrDeterminate(t *testing.T) {
91+
if isErrDeterminate(fmt.Errorf("anything")) != true {
92+
t.Errorf("general errors should be determinate")
93+
}
94+
95+
if isErrDeterminate(&ldap.Error{Err: fmt.Errorf("anything")}) != true {
96+
t.Errorf("ldap general errors should be determinate")
97+
}
98+
99+
if isErrDeterminate(&ldap.Error{Err: &net.OpError{}}) == true {
100+
t.Errorf("ldap net.OpError{} should be indeterminate")
101+
}
102+
103+
if isErrDeterminate(&ldap.Error{Err: context.DeadlineExceeded}) == true {
104+
t.Errorf("ldap context deadline should be indeterminate")
105+
}
106+
107+
if isErrDeterminate(&ldap.Error{Err: context.Canceled}) == true {
108+
t.Errorf("ldap context deadline should be indeterminate")
109+
}
110+
}

0 commit comments

Comments
 (0)