Skip to content

Commit 5022486

Browse files
ldap: Support customer dialer for Kerberos connections
1 parent 9e73f80 commit 5022486

File tree

5 files changed

+179
-46
lines changed

5 files changed

+179
-46
lines changed

compat/compat.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Package compat holds compatibility functions for interoperability between
2+
// forks or different libraries for the same purpose.
3+
package compat
4+
5+
import (
6+
"github.com/jcmturner/gokrb5/v8/config"
7+
"github.com/jcmturner/gokrb5/v8/credentials"
8+
"github.com/jcmturner/gokrb5/v8/keytab"
9+
gokrb5ForkConfig "github.com/oiweiwei/gokrb5.fork/v9/config"
10+
gokrb5ForkCredentials "github.com/oiweiwei/gokrb5.fork/v9/credentials"
11+
gokrb5ForkKeytab "github.com/oiweiwei/gokrb5.fork/v9/keytab"
12+
gokrb5ForkTypes "github.com/oiweiwei/gokrb5.fork/v9/types"
13+
14+
"github.com/jcmturner/gokrb5/v8/types"
15+
)
16+
17+
func Gokrb5ForkV9KerberosConfig(cfg *config.Config) *gokrb5ForkConfig.Config {
18+
realms := make([]gokrb5ForkConfig.Realm, 0, len(cfg.Realms))
19+
20+
for _, realm := range cfg.Realms {
21+
realms = append(realms, gokrb5ForkConfig.Realm(realm))
22+
}
23+
24+
return &gokrb5ForkConfig.Config{
25+
LibDefaults: gokrb5ForkConfig.LibDefaults(cfg.LibDefaults),
26+
Realms: realms,
27+
DomainRealm: gokrb5ForkConfig.DomainRealm(cfg.DomainRealm),
28+
}
29+
}
30+
31+
func Gokrb5ForkV9CCache(ccache *credentials.CCache) *gokrb5ForkCredentials.CCache {
32+
creds := make([]*gokrb5ForkCredentials.Credential, 0, len(ccache.Credentials))
33+
34+
for _, cred := range ccache.Credentials {
35+
addrs := make([]gokrb5ForkTypes.HostAddress, 0, len(cred.Addresses))
36+
37+
for _, addr := range cred.Addresses {
38+
addrs = append(addrs, gokrb5ForkTypes.HostAddress(addr))
39+
}
40+
41+
adEntries := make([]gokrb5ForkTypes.AuthorizationDataEntry, 0, len(cred.AuthData))
42+
43+
for _, adEntry := range cred.AuthData {
44+
adEntries = append(adEntries, gokrb5ForkTypes.AuthorizationDataEntry(adEntry))
45+
}
46+
47+
creds = append(creds, &gokrb5ForkCredentials.Credential{
48+
Client: Gokrb5ForkV9Principal(cred.Client.Realm, cred.Client.PrincipalName),
49+
Server: Gokrb5ForkV9Principal(cred.Server.Realm, cred.Server.PrincipalName),
50+
Key: gokrb5ForkTypes.EncryptionKey(cred.Key),
51+
AuthTime: cred.AuthTime,
52+
StartTime: cred.StartTime,
53+
EndTime: cred.EndTime,
54+
RenewTill: cred.RenewTill,
55+
IsSKey: cred.IsSKey,
56+
TicketFlags: cred.TicketFlags,
57+
Addresses: addrs,
58+
AuthData: adEntries,
59+
Ticket: cred.Ticket,
60+
SecondTicket: cred.SecondTicket,
61+
})
62+
}
63+
64+
return &gokrb5ForkCredentials.CCache{
65+
Version: ccache.Version,
66+
DefaultPrincipal: Gokrb5ForkV9Principal(ccache.DefaultPrincipal.Realm, ccache.DefaultPrincipal.PrincipalName),
67+
Credentials: creds,
68+
Path: ccache.Path,
69+
}
70+
}
71+
72+
func Gokrb5ForkV9Principal(realm string, principalName types.PrincipalName) gokrb5ForkCredentials.Principal {
73+
return gokrb5ForkCredentials.Principal{
74+
Realm: realm,
75+
PrincipalName: gokrb5ForkTypes.PrincipalName(principalName),
76+
}
77+
}
78+
79+
func Gokrb5ForkV9Keytab(keytab *keytab.Keytab) *gokrb5ForkKeytab.Keytab {
80+
entries := make([]gokrb5ForkKeytab.Entry, 0, len(keytab.Entries))
81+
82+
for _, entry := range keytab.Entries {
83+
entries = append(entries, gokrb5ForkKeytab.Entry{
84+
Principal: gokrb5ForkKeytab.Principal{
85+
NumComponents: entry.Principal.NumComponents,
86+
Realm: entry.Principal.Realm,
87+
Components: entry.Principal.Components,
88+
NameType: entry.Principal.NameType,
89+
},
90+
Timestamp: entry.Timestamp,
91+
KVNO8: entry.KVNO8,
92+
Key: gokrb5ForkTypes.EncryptionKey(entry.Key),
93+
KVNO: entry.KVNO,
94+
})
95+
}
96+
97+
return &gokrb5ForkKeytab.Keytab{
98+
Version: 2,
99+
Entries: entries,
100+
}
101+
}

go.mod

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/jcmturner/gokrb5/v8 v8.4.4
99
github.com/oiweiwei/go-msrpc v1.2.1
1010
github.com/oiweiwei/gokrb5.fork/v9 v9.0.2
11-
github.com/spf13/pflag v1.0.5
11+
github.com/spf13/pflag v1.0.6
1212
github.com/vadimi/go-ntlm v1.2.1
1313
software.sslmate.com/src/go-pkcs12 v0.5.0
1414
)
@@ -28,8 +28,8 @@ require (
2828
github.com/mattn/go-isatty v0.0.20 // indirect
2929
github.com/oiweiwei/go-smb2.fork v1.0.0 // indirect
3030
github.com/rs/zerolog v1.33.0 // indirect
31-
golang.org/x/crypto v0.32.0 // indirect
32-
golang.org/x/net v0.34.0 // indirect
33-
golang.org/x/sys v0.29.0 // indirect
34-
golang.org/x/text v0.21.0 // indirect
31+
golang.org/x/crypto v0.35.0 // indirect
32+
golang.org/x/net v0.35.0 // indirect
33+
golang.org/x/sys v0.30.0 // indirect
34+
golang.org/x/text v0.22.0 // indirect
3535
)

go.sum

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
5858
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
5959
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
6060
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
61-
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
62-
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
61+
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
62+
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
6363
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
6464
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
6565
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -79,8 +79,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
7979
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
8080
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
8181
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
82-
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
83-
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
82+
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
83+
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
8484
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
8585
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
8686
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
@@ -97,8 +97,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
9797
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
9898
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
9999
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
100-
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
101-
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
100+
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
101+
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
102102
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
103103
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
104104
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -119,8 +119,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
119119
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
120120
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
121121
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
122-
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
123-
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
122+
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
123+
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
124124
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
125125
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
126126
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -138,8 +138,9 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
138138
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
139139
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
140140
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
141-
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
142141
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
142+
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
143+
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
143144
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
144145
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
145146
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

ldapauth/gssapi.go

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,29 @@ import (
99
"encoding/hex"
1010
"errors"
1111
"fmt"
12+
"net"
1213
"strings"
1314

15+
"github.com/RedTeamPentesting/adauth/compat"
1416
"github.com/RedTeamPentesting/adauth/pkinit"
15-
"github.com/jcmturner/gokrb5/v8/client"
1617
"github.com/jcmturner/gokrb5/v8/config"
17-
"github.com/jcmturner/gokrb5/v8/iana/chksumtype"
18-
"github.com/jcmturner/gokrb5/v8/iana/etypeID"
19-
"github.com/jcmturner/gokrb5/v8/iana/flags"
20-
"github.com/jcmturner/gokrb5/v8/iana/nametype"
21-
"github.com/jcmturner/gokrb5/v8/krberror"
22-
"github.com/jcmturner/gokrb5/v8/types"
2318

24-
krb5GSSAPI "github.com/jcmturner/gokrb5/v8/gssapi"
25-
"github.com/jcmturner/gokrb5/v8/spnego"
19+
"github.com/oiweiwei/gokrb5.fork/v9/client"
20+
"github.com/oiweiwei/gokrb5.fork/v9/iana/chksumtype"
21+
"github.com/oiweiwei/gokrb5.fork/v9/iana/etypeID"
22+
"github.com/oiweiwei/gokrb5.fork/v9/iana/flags"
23+
"github.com/oiweiwei/gokrb5.fork/v9/iana/nametype"
24+
"github.com/oiweiwei/gokrb5.fork/v9/krberror"
25+
"github.com/oiweiwei/gokrb5.fork/v9/types"
2626

27-
krb5Crypto "github.com/jcmturner/gokrb5/v8/crypto"
28-
"github.com/jcmturner/gokrb5/v8/iana/keyusage"
29-
"github.com/jcmturner/gokrb5/v8/messages"
27+
krb5GSSAPI "github.com/oiweiwei/gokrb5.fork/v9/gssapi"
28+
"github.com/oiweiwei/gokrb5.fork/v9/spnego"
3029

31-
"github.com/jcmturner/gokrb5/v8/credentials"
30+
krb5Crypto "github.com/oiweiwei/gokrb5.fork/v9/crypto"
31+
"github.com/oiweiwei/gokrb5.fork/v9/iana/keyusage"
32+
"github.com/oiweiwei/gokrb5.fork/v9/messages"
33+
34+
"github.com/oiweiwei/gokrb5.fork/v9/credentials"
3235
)
3336

3437
type gssapiClient struct {
@@ -42,21 +45,24 @@ type gssapiClient struct {
4245
}
4346

4447
func newClientFromCCache(
45-
username string, domain string, ccachePath string, krb5Conf *config.Config,
48+
username string, domain string, ccachePath string, krb5Conf *config.Config, dialer Dialer,
4649
) (*gssapiClient, error) {
4750
ccache, err := credentials.LoadCCache(ccachePath)
4851
if err != nil {
4952
return nil, err
5053
}
5154

52-
c, err := client.NewFromCCache(ccache, krb5Conf, client.DisablePAFXFAST(true))
53-
if err != nil && strings.Contains(strings.ToLower(err.Error()), "tgt not found") {
54-
// client.NewFromCCache only accepts ccaches that contain at least one
55-
// TGT, however, we want to support ccaches that only contain a service
55+
c, err := client.NewFromCCache(
56+
ccache, compat.Gokrb5ForkV9KerberosConfig(krb5Conf),
57+
client.DisablePAFXFAST(true), client.Dialer(dialer))
58+
if err != nil && strings.Contains(strings.ToLower(err.Error()), "tgt") {
59+
// client.NewFromCCache only accepts CCaches that contain at least one
60+
// TGT, however, we want to support CCaches that only contain a service
5661
// ticket. Therefore, we use a dummy client, and pull the service ticket
5762
// from the ccache ourselves instead of asking the client.
5863
return &gssapiClient{
59-
Client: client.NewWithPassword(username, domain, "", krb5Conf, client.DisablePAFXFAST(true)),
64+
Client: client.NewWithPassword(
65+
username, domain, "", compat.Gokrb5ForkV9KerberosConfig(krb5Conf), client.DisablePAFXFAST(true)),
6066
ccache: ccache,
6167
}, nil
6268
}
@@ -70,14 +76,21 @@ func newClientFromCCache(
7076

7177
func newPKINITClient(
7278
ctx context.Context, username string, domain string, cert *x509.Certificate, key *rsa.PrivateKey,
73-
krb5Conf *config.Config, opts ...pkinit.Option,
79+
krb5Conf *config.Config, dialer Dialer,
7480
) (*gssapiClient, error) {
75-
ccache, err := pkinit.Authenticate(ctx, username, domain, cert, key, krb5Conf, opts...)
81+
ctxDialer, ok := dialer.(pkinit.ContextDialer)
82+
if !ok {
83+
ctxDialer = nopContextDialer(dialer.Dial)
84+
}
85+
86+
ccache, err := pkinit.Authenticate(ctx, username, domain, cert, key, krb5Conf, pkinit.WithDialer(ctxDialer))
7687
if err != nil {
7788
return nil, fmt.Errorf("pkinit: %w", err)
7889
}
7990

80-
c, err := client.NewFromCCache(ccache, krb5Conf, client.DisablePAFXFAST(true))
91+
c, err := client.NewFromCCache(
92+
compat.Gokrb5ForkV9CCache(ccache), compat.Gokrb5ForkV9KerberosConfig(krb5Conf),
93+
client.DisablePAFXFAST(true), client.Dialer(dialer))
8194
if err != nil {
8295
return nil, fmt.Errorf("initialize Kerberos client from PKINIT ccache: %w", err)
8396
}
@@ -364,3 +377,9 @@ func krb5TokenAuthenticator(
364377

365378
return auth, nil
366379
}
380+
381+
type nopContextDialer func(string, string) (net.Conn, error)
382+
383+
func (f nopContextDialer) DialContext(ctx context.Context, net string, addr string) (net.Conn, error) {
384+
return f(net, addr)
385+
}

ldapauth/ldap.go

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@ import (
1919
"time"
2020

2121
"github.com/RedTeamPentesting/adauth"
22+
"github.com/RedTeamPentesting/adauth/compat"
2223
"github.com/RedTeamPentesting/adauth/othername"
2324
"github.com/RedTeamPentesting/adauth/pkinit"
2425
"software.sslmate.com/src/go-pkcs12"
2526

2627
"github.com/go-ldap/ldap/v3"
27-
"github.com/jcmturner/gokrb5/v8/client"
28+
"github.com/oiweiwei/gokrb5.fork/v9/client"
2829
"github.com/spf13/pflag"
2930
)
3031

@@ -57,11 +58,12 @@ type Options struct {
5758
StartTLS bool
5859
// DialOptions can be used to customize the connection. However
5960
// ldap.DialWithTLSConfig will be ignored, because TLS setup is handled
60-
// internally.
61+
// internally. Note that setting a custom dialer with DialOptions only
62+
// affects LDAP/LDAPS connections, not Kerberos connections. A custom dialer
63+
// for Kerberos connections can be set with KerberosDialer.
6164
DialOptions []ldap.DialOpt
62-
// PKINITOptions can be used to modify the behavior of PKINIT when it is
63-
// used.
64-
PKINITOptions []pkinit.Option
65+
// KerberosDialer is the dialer that is used to request Kerberos tickets.
66+
KerberosDialer Dialer
6567
}
6668

6769
// RegisterFlags registers LDAP specific flags to a pflag.FlagSet such as the
@@ -273,6 +275,10 @@ func kerberosClient(
273275
return nil, fmt.Errorf("configure Kerberos: %w", err)
274276
}
275277

278+
if opts.KerberosDialer == nil {
279+
opts.KerberosDialer = &net.Dialer{Timeout: pkinit.DefaultKerberosRoundtripDeadline}
280+
}
281+
276282
var (
277283
authClient *gssapiClient
278284
cert *x509.Certificate
@@ -292,8 +298,9 @@ func kerberosClient(
292298
creds.Username,
293299
strings.ToUpper(creds.Domain),
294300
creds.Password,
295-
krbConf,
301+
compat.Gokrb5ForkV9KerberosConfig(krbConf),
296302
client.DisablePAFXFAST(true),
303+
client.Dialer(opts.KerberosDialer),
297304
),
298305
}
299306

@@ -310,9 +317,10 @@ func kerberosClient(
310317
Client: client.NewWithKeytab(
311318
creds.Username,
312319
strings.ToUpper(creds.Domain),
313-
keyTab,
314-
krbConf,
320+
compat.Gokrb5ForkV9Keytab(keyTab),
321+
compat.Gokrb5ForkV9KerberosConfig(krbConf),
315322
client.DisablePAFXFAST(true),
323+
client.Dialer(opts.KerberosDialer),
316324
),
317325
BindCertificate: cert,
318326
}
@@ -322,12 +330,12 @@ func kerberosClient(
322330
opts.Debug("authenticating using GSSAPI bind (PKINIT)")
323331

324332
return newPKINITClient(ctx, creds.Username, strings.ToUpper(creds.Domain),
325-
creds.ClientCert, creds.ClientCertKey, krbConf, opts.PKINITOptions...)
333+
creds.ClientCert, creds.ClientCertKey, krbConf, opts.KerberosDialer)
326334
case creds.CCache != "":
327335
opts.Debug("authenticating using GSSAPI bind (ccache)")
328336

329337
authClient, err = newClientFromCCache(
330-
creds.Username, strings.ToUpper(creds.Domain), creds.CCache, krbConf)
338+
creds.Username, strings.ToUpper(creds.Domain), creds.CCache, krbConf, opts.KerberosDialer)
331339
if err != nil {
332340
return nil, fmt.Errorf("create GSSAPI client from CCACHE: %w", err)
333341
}
@@ -489,3 +497,7 @@ func ChannelBindingHash(cert *x509.Certificate) []byte {
489497

490498
return hash
491499
}
500+
501+
type Dialer interface {
502+
Dial(net string, addr string) (net.Conn, error)
503+
}

0 commit comments

Comments
 (0)