Skip to content

Commit 9cf9ff5

Browse files
author
Власов Роман Сергеевич
committed
https://github.com/go-ldap/ldap/pull/449
1 parent cdbbc30 commit 9cf9ff5

File tree

4 files changed

+452
-2
lines changed

4 files changed

+452
-2
lines changed

go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74
88
github.com/go-asn1-ber/asn1-ber v1.5.5
99
github.com/google/uuid v1.3.1
10-
github.com/stretchr/testify v1.8.0
10+
github.com/jcmturner/gokrb5/v8 v8.4.4
11+
github.com/stretchr/testify v1.8.1
1112
golang.org/x/crypto v0.13.0 // indirect
1213
)

go.sum

+28-1
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,50 @@ github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD
99
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
1010
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
1111
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
12+
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
13+
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
14+
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
15+
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
16+
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
17+
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
18+
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
19+
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
20+
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
21+
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
22+
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
23+
github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg=
24+
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
25+
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
26+
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
27+
github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8=
28+
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
29+
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
30+
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
1231
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1332
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
1433
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
1534
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
35+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
36+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
1637
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
17-
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
1838
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
39+
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
40+
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
1941
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
2042
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
2143
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
44+
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
2245
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
2346
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
2447
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
2548
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
2649
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
50+
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
2751
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
2852
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
2953
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
54+
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
55+
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
3056
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
3157
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
3258
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -57,6 +83,7 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
5783
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
5884
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
5985
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
86+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
6087
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
6188
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
6289
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

gssapi/client.go

+211
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
package gssapi
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/jcmturner/gokrb5/v8/client"
7+
"github.com/jcmturner/gokrb5/v8/config"
8+
"github.com/jcmturner/gokrb5/v8/credentials"
9+
"github.com/jcmturner/gokrb5/v8/crypto"
10+
"github.com/jcmturner/gokrb5/v8/gssapi"
11+
"github.com/jcmturner/gokrb5/v8/iana/keyusage"
12+
"github.com/jcmturner/gokrb5/v8/keytab"
13+
"github.com/jcmturner/gokrb5/v8/messages"
14+
"github.com/jcmturner/gokrb5/v8/spnego"
15+
"github.com/jcmturner/gokrb5/v8/types"
16+
)
17+
18+
// Client implements ldap.GSSAPIClient interface.
19+
type Client struct {
20+
*client.Client
21+
22+
ekey types.EncryptionKey
23+
Subkey types.EncryptionKey
24+
}
25+
26+
// NewClientWithKeytab creates a new client from a keytab credential.
27+
// Set the realm to empty string to use the default realm from config.
28+
func NewClientWithKeytab(username, realm, keytabPath, krb5confPath string, settings ...func(*client.Settings)) (*Client, error) {
29+
krb5conf, err := config.Load(krb5confPath)
30+
if err != nil {
31+
return nil, err
32+
}
33+
34+
keytab, err := keytab.Load(keytabPath)
35+
if err != nil {
36+
return nil, err
37+
}
38+
39+
client := client.NewWithKeytab(username, realm, keytab, krb5conf, settings...)
40+
41+
return &Client{
42+
Client: client,
43+
}, nil
44+
}
45+
46+
// NewClientWithPassword creates a new client from a password credential.
47+
// Set the realm to empty string to use the default realm from config.
48+
func NewClientWithPassword(username, realm, password string, krb5confPath string, settings ...func(*client.Settings)) (*Client, error) {
49+
krb5conf, err := config.Load(krb5confPath)
50+
if err != nil {
51+
return nil, err
52+
}
53+
54+
client := client.NewWithPassword(username, realm, password, krb5conf, settings...)
55+
56+
return &Client{
57+
Client: client,
58+
}, nil
59+
}
60+
61+
// NewClientFromCCache creates a new client from a populated client cache.
62+
func NewClientFromCCache(ccachePath, krb5confPath string, settings ...func(*client.Settings)) (*Client, error) {
63+
krb5conf, err := config.Load(krb5confPath)
64+
if err != nil {
65+
return nil, err
66+
}
67+
68+
ccache, err := credentials.LoadCCache(ccachePath)
69+
if err != nil {
70+
return nil, err
71+
}
72+
73+
client, err := client.NewFromCCache(ccache, krb5conf, settings...)
74+
if err != nil {
75+
return nil, err
76+
}
77+
78+
return &Client{
79+
Client: client,
80+
}, nil
81+
}
82+
83+
// Close deletes any established secure context and closes the client.
84+
func (client *Client) Close() error {
85+
client.Client.Destroy()
86+
return nil
87+
}
88+
89+
// DeleteSecContext destroys any established secure context.
90+
func (client *Client) DeleteSecContext() error {
91+
client.ekey = types.EncryptionKey{}
92+
client.Subkey = types.EncryptionKey{}
93+
return nil
94+
}
95+
96+
// InitSecContext initiates the establishment of a security context for
97+
// GSS-API between the client and server.
98+
// See RFC 4752 section 3.1.
99+
func (client *Client) InitSecContext(target string, input []byte) ([]byte, bool, error) {
100+
gssapiFlags := []int{gssapi.ContextFlagInteg, gssapi.ContextFlagConf, gssapi.ContextFlagMutual}
101+
102+
switch input {
103+
case nil:
104+
tkt, ekey, err := client.Client.GetServiceTicket(target)
105+
if err != nil {
106+
return nil, false, err
107+
}
108+
client.ekey = ekey
109+
110+
token, err := spnego.NewKRB5TokenAPREQ(client.Client, tkt, ekey, gssapiFlags, []int{})
111+
if err != nil {
112+
return nil, false, err
113+
}
114+
115+
output, err := token.Marshal()
116+
if err != nil {
117+
return nil, false, err
118+
}
119+
120+
return output, true, nil
121+
122+
default:
123+
var token spnego.KRB5Token
124+
125+
err := token.Unmarshal(input)
126+
if err != nil {
127+
return nil, false, err
128+
}
129+
130+
var completed bool
131+
132+
if token.IsAPRep() {
133+
completed = true
134+
135+
encpart, err := crypto.DecryptEncPart(token.APRep.EncPart, client.ekey, keyusage.AP_REP_ENCPART)
136+
if err != nil {
137+
return nil, false, err
138+
}
139+
140+
part := &messages.EncAPRepPart{}
141+
142+
if err = part.Unmarshal(encpart); err != nil {
143+
return nil, false, err
144+
}
145+
client.Subkey = part.Subkey
146+
}
147+
148+
if token.IsKRBError() {
149+
return nil, !false, token.KRBError
150+
}
151+
152+
return make([]byte, 0), !completed, nil
153+
}
154+
}
155+
156+
// NegotiateSaslAuth performs the last step of the SASL handshake.
157+
// See RFC 4752 section 3.1.
158+
func (client *Client) NegotiateSaslAuth(input []byte, authzid string) ([]byte, error) {
159+
token := &gssapi.WrapToken{}
160+
err := token.Unmarshal(input, true)
161+
if err != nil {
162+
return nil, err
163+
}
164+
165+
if (token.Flags & 0b1) == 0 {
166+
return nil, fmt.Errorf("got a Wrapped token that's not from the server")
167+
}
168+
169+
key := client.ekey
170+
if (token.Flags & 0b100) != 0 {
171+
key = client.Subkey
172+
}
173+
174+
_, err = token.Verify(key, keyusage.GSSAPI_ACCEPTOR_SEAL)
175+
if err != nil {
176+
return nil, err
177+
}
178+
179+
pl := token.Payload
180+
if len(pl) != 4 {
181+
return nil, fmt.Errorf("server send bad final token for SASL GSSAPI Handshake")
182+
}
183+
184+
// We never want a security layer
185+
b := [4]byte{0, 0, 0, 0}
186+
payload := append(b[:], []byte(authzid)...)
187+
188+
encType, err := crypto.GetEtype(key.KeyType)
189+
if err != nil {
190+
return nil, err
191+
}
192+
193+
token = &gssapi.WrapToken{
194+
Flags: 0b100,
195+
EC: uint16(encType.GetHMACBitLength() / 8),
196+
RRC: 0,
197+
SndSeqNum: 1,
198+
Payload: payload,
199+
}
200+
201+
if err := token.SetCheckSum(key, keyusage.GSSAPI_INITIATOR_SEAL); err != nil {
202+
return nil, err
203+
}
204+
205+
output, err := token.Marshal()
206+
if err != nil {
207+
return nil, err
208+
}
209+
210+
return output, nil
211+
}

0 commit comments

Comments
 (0)