Skip to content

Commit 282954a

Browse files
committed
Testing kerberos auth
Signed-off-by: Ruben Vargas <[email protected]>
1 parent e1cae9a commit 282954a

File tree

5 files changed

+375
-72
lines changed

5 files changed

+375
-72
lines changed

broker_test.go

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"testing"
99
"time"
1010

11-
metrics "github.com/rcrowley/go-metrics"
11+
"github.com/rcrowley/go-metrics"
1212
)
1313

1414
func ExampleBroker() {
@@ -477,6 +477,61 @@ func TestSASLPlainAuth(t *testing.T) {
477477
}
478478
}
479479

480+
func TestGSSAPIKerberosAuth_Authorize(t *testing.T) {
481+
482+
mockBroker := NewMockBroker(t, 0)
483+
// broker executes SASL requests against mockBroker
484+
485+
mockBroker.SetGSSAPIHandler(func(bytes []byte) []byte {
486+
return nil
487+
})
488+
broker := NewBroker(mockBroker.Addr())
489+
broker.requestRate = metrics.NilMeter{}
490+
broker.outgoingByteRate = metrics.NilMeter{}
491+
broker.incomingByteRate = metrics.NilMeter{}
492+
broker.requestSize = metrics.NilHistogram{}
493+
broker.responseSize = metrics.NilHistogram{}
494+
broker.responseRate = metrics.NilMeter{}
495+
broker.requestLatency = metrics.NilHistogram{}
496+
conf := NewConfig()
497+
conf.Net.SASL.Mechanism = SASLTypeGSSAPI
498+
conf.Net.SASL.GSSAPI.ServiceName = "kafka"
499+
conf.Net.SASL.GSSAPI.KerberosConfigPath = "password"
500+
conf.Net.SASL.GSSAPI.Realm = "EXAMPLE"
501+
conf.Net.SASL.GSSAPI.Username = "kafka"
502+
conf.Net.SASL.GSSAPI.Password = "kafka"
503+
conf.Net.SASL.GSSAPI.KeyTabPath = "kafka.keytab"
504+
505+
broker.conf = conf
506+
broker.conf.Version = V1_0_0_0
507+
dialer := net.Dialer{
508+
Timeout: conf.Net.DialTimeout,
509+
KeepAlive: conf.Net.KeepAlive,
510+
LocalAddr: conf.Net.LocalAddr,
511+
}
512+
513+
conn, err := dialer.Dial("tcp", mockBroker.listener.Addr().String())
514+
515+
if err != nil {
516+
t.Fatal(err)
517+
}
518+
kerberosClient := NewKerberosMockClient()
519+
gssapiHandler := KafkaGSSAPIHandler{
520+
client: kerberosClient,
521+
}
522+
mockBroker.SetGSSAPIHandler(gssapiHandler.MockKafkaGSSAPI)
523+
broker.conn = conn
524+
kerberosAuthenticator := NewGSSAPIKerberosAuthenticator(&broker.conf.Net.SASL.GSSAPI)
525+
kerberosAuthenticator.client = kerberosClient
526+
err = kerberosAuthenticator.Authorize(broker)
527+
if err != nil {
528+
t.Errorf("Expected success authentication, got %s", err)
529+
530+
}
531+
mockBroker.Close()
532+
533+
}
534+
480535
func TestBuildClientInitialResponse(t *testing.T) {
481536

482537
testTable := []struct {

config_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,86 @@ func TestNetConfigValidates(t *testing.T) {
117117
cfg.Net.SASL.Password = "stong_password"
118118
},
119119
"A SCRAMClientGeneratorFunc function must be provided to Net.SASL.SCRAMClientGeneratorFunc"},
120+
{"SASL.Mechanism GSSAPI (Kerberos) - Using User/Password, Missing password field",
121+
func(cfg *Config) {
122+
cfg.Net.SASL.Enable = true
123+
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
124+
cfg.Net.SASL.GSSAPI.AuthType = KRB5_USER_AUTH
125+
cfg.Net.SASL.GSSAPI.Username = "sarama"
126+
cfg.Net.SASL.GSSAPI.ServiceName = "kafka"
127+
cfg.Net.SASL.GSSAPI.Realm = "kafka"
128+
cfg.Net.SASL.GSSAPI.KerberosConfigPath = "/etc/krb5.conf"
129+
},
130+
"Net.SASL.GSSAPI.Password must not be empty when GSS-API " +
131+
"mechanism is used and Net.SASL.GSSAPI.AuthType = KRB5_USER_AUTH"},
132+
{"SASL.Mechanism GSSAPI (Kerberos) - Using User/Password, Missing KeyTabPath field",
133+
func(cfg *Config) {
134+
cfg.Net.SASL.Enable = true
135+
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
136+
cfg.Net.SASL.GSSAPI.AuthType = KRB5_KEYTAB_AUTH
137+
cfg.Net.SASL.GSSAPI.Username = "sarama"
138+
cfg.Net.SASL.GSSAPI.ServiceName = "kafka"
139+
cfg.Net.SASL.GSSAPI.Realm = "kafka"
140+
cfg.Net.SASL.GSSAPI.KerberosConfigPath = "/etc/krb5.conf"
141+
},
142+
"Net.SASL.GSSAPI.KeyTabPath must not be empty when GSS-API mechanism is used" +
143+
" and Net.SASL.GSSAPI.AuthType = KRB5_KEYTAB_AUTH"},
144+
{"SASL.Mechanism GSSAPI (Kerberos) - Missing username",
145+
func(cfg *Config) {
146+
cfg.Net.SASL.Enable = true
147+
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
148+
cfg.Net.SASL.GSSAPI.AuthType = KRB5_USER_AUTH
149+
cfg.Net.SASL.GSSAPI.Password = "sarama"
150+
cfg.Net.SASL.GSSAPI.ServiceName = "kafka"
151+
cfg.Net.SASL.GSSAPI.Realm = "kafka"
152+
cfg.Net.SASL.GSSAPI.KerberosConfigPath = "/etc/krb5.conf"
153+
},
154+
"Net.SASL.GSSAPI.Username must not be empty when GSS-API mechanism is used"},
155+
{"SASL.Mechanism GSSAPI (Kerberos) - Missing ServiceName",
156+
func(cfg *Config) {
157+
cfg.Net.SASL.Enable = true
158+
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
159+
cfg.Net.SASL.GSSAPI.AuthType = KRB5_USER_AUTH
160+
cfg.Net.SASL.GSSAPI.Username = "sarama"
161+
cfg.Net.SASL.GSSAPI.Password = "sarama"
162+
cfg.Net.SASL.GSSAPI.Realm = "kafka"
163+
cfg.Net.SASL.GSSAPI.KerberosConfigPath = "/etc/krb5.conf"
164+
},
165+
"Net.SASL.GSSAPI.ServiceName must not be empty when GSS-API mechanism is used"},
166+
{"SASL.Mechanism GSSAPI (Kerberos) - Missing AuthType",
167+
func(cfg *Config) {
168+
cfg.Net.SASL.Enable = true
169+
cfg.Net.SASL.GSSAPI.ServiceName = "kafka"
170+
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
171+
cfg.Net.SASL.GSSAPI.Username = "sarama"
172+
cfg.Net.SASL.GSSAPI.Password = "sarama"
173+
cfg.Net.SASL.GSSAPI.Realm = "kafka"
174+
cfg.Net.SASL.GSSAPI.KerberosConfigPath = "/etc/krb5.conf"
175+
},
176+
"Net.SASL.GSSAPI.AuthType is invalid. Possible values are KRB5_USER_AUTH and KRB5_KEYTAB_AUTH"},
177+
{"SASL.Mechanism GSSAPI (Kerberos) - Missing KerberosConfigPath",
178+
func(cfg *Config) {
179+
cfg.Net.SASL.Enable = true
180+
cfg.Net.SASL.GSSAPI.ServiceName = "kafka"
181+
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
182+
cfg.Net.SASL.GSSAPI.AuthType = KRB5_USER_AUTH
183+
cfg.Net.SASL.GSSAPI.Username = "sarama"
184+
cfg.Net.SASL.GSSAPI.Password = "sarama"
185+
cfg.Net.SASL.GSSAPI.Realm = "kafka"
186+
},
187+
"Net.SASL.GSSAPI.KerberosConfigPath must not be empty when GSS-API mechanism is used"},
188+
{"SASL.Mechanism GSSAPI (Kerberos) - Missing Realm",
189+
func(cfg *Config) {
190+
cfg.Net.SASL.Enable = true
191+
cfg.Net.SASL.GSSAPI.ServiceName = "kafka"
192+
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
193+
cfg.Net.SASL.GSSAPI.AuthType = KRB5_USER_AUTH
194+
cfg.Net.SASL.GSSAPI.Username = "sarama"
195+
cfg.Net.SASL.GSSAPI.Password = "sarama"
196+
cfg.Net.SASL.GSSAPI.KerberosConfigPath = "/etc/krb5.conf"
197+
198+
},
199+
"Net.SASL.GSSAPI.Realm must not be empty when GSS-API mechanism is used"},
120200
}
121201

122202
for i, test := range tests {

gssapi_kerberos.go

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,20 @@ import (
1919
"time"
2020
)
2121

22-
23-
24-
2522
const (
2623
TOK_ID_KRB_AP_REQ = "0100"
2724
GSS_API_GENERIC_TAG = 0x60
28-
KRB5_USER_AUTH = 1
29-
KRB5_KEYTAB_AUTH = 2
25+
KRB5_USER_AUTH = 1
26+
KRB5_KEYTAB_AUTH = 2
3027
)
3128

3229
type GSSAPIConfig struct {
33-
AuthType int
30+
AuthType int
3431
KeyTabPath string
3532
KerberosConfigPath string
3633
ServiceName string
3734
Username string
38-
Password string
35+
Password string
3936
Realm string
4037
}
4138

@@ -54,22 +51,22 @@ type KerberosClient interface {
5451
}
5552

5653
type KerberosGoKrb5Client struct {
57-
client *krb5client.Client
54+
client *krb5client.Client
5855
}
5956

60-
func (c *KerberosGoKrb5Client)Login() error {
57+
func (c *KerberosGoKrb5Client) Login() error {
6158
return c.client.Login()
6259
}
6360

64-
func (c *KerberosGoKrb5Client)GetServiceTicket(spn string) (messages.Ticket, types.EncryptionKey, error) {
61+
func (c *KerberosGoKrb5Client) GetServiceTicket(spn string) (messages.Ticket, types.EncryptionKey, error) {
6562
return c.client.GetServiceTicket(spn)
6663
}
6764

68-
func (c *KerberosGoKrb5Client)Domain() string {
65+
func (c *KerberosGoKrb5Client) Domain() string {
6966
return c.client.Credentials.Domain()
7067
}
7168

72-
func (c *KerberosGoKrb5Client)CName() types.PrincipalName {
69+
func (c *KerberosGoKrb5Client) CName() types.PrincipalName {
7370
return c.client.Credentials.CName()
7471
}
7572

@@ -83,9 +80,9 @@ func (c *KerberosGoKrb5Client)CName() types.PrincipalName {
8380
*/
8481
func createKerberosClient(config *GSSAPIConfig) (*KerberosGoKrb5Client, error) {
8582
cfg, err := krb5config.Load(config.KerberosConfigPath)
86-
var client *krb5client.Client
83+
var client *krb5client.Client
8784
if err != nil {
88-
return nil,err
85+
return nil, err
8986
}
9087
if config.AuthType == KRB5_KEYTAB_AUTH {
9188
kt, err := keytab.Load(config.KeyTabPath)
@@ -142,14 +139,11 @@ func (krbAuth *GSSAPIKerberosAuth) readPackage(broker *Broker) ([]byte, int, err
142139
return payloadBytes, bytesRead, nil
143140
}
144141

145-
func (krbAuth *GSSAPIKerberosAuth) newAuthenticatorChecksum(flags []int) []byte {
142+
func (krbAuth *GSSAPIKerberosAuth) newAuthenticatorChecksum() []byte {
146143
a := make([]byte, 24)
144+
flags := []int{gssapi.ContextFlagInteg, gssapi.ContextFlagConf}
147145
binary.LittleEndian.PutUint32(a[:4], 16)
148146
for _, i := range flags {
149-
if i == gssapi.ContextFlagDeleg {
150-
x := make([]byte, 28-len(a))
151-
a = append(a, x...)
152-
}
153147
f := binary.LittleEndian.Uint32(a[20:24])
154148
f |= uint32(i)
155149
binary.LittleEndian.PutUint32(a[20:24], f)
@@ -164,14 +158,13 @@ func (krbAuth *GSSAPIKerberosAuth) newAuthenticatorChecksum(flags []int) []byte
164158
*
165159
*/
166160
func (krbAuth *GSSAPIKerberosAuth) createKrb5Token(client KerberosClient, ticket messages.Ticket, sessionKey types.EncryptionKey) ([]byte, error) {
167-
var GSSAPIFlags = []int{gssapi.ContextFlagInteg, gssapi.ContextFlagConf}
168161
auth, err := types.NewAuthenticator(client.Domain(), client.CName())
169162
if err != nil {
170163
return nil, err
171164
}
172165
auth.Cksum = types.Checksum{
173166
CksumType: chksumtype.GSSAPI,
174-
Checksum: krbAuth.newAuthenticatorChecksum(GSSAPIFlags),
167+
Checksum: krbAuth.newAuthenticatorChecksum(),
175168
}
176169
APReq, err := messages.NewAPReq(
177170
ticket,
@@ -215,12 +208,10 @@ func (krbAuth *GSSAPIKerberosAuth) appendGSSAPIHeader(payload []byte) ([]byte, e
215208
return GSSPackage, nil
216209
}
217210

218-
219-
220211
/* This does the handshake for authorization */
221212
func (krbAuth *GSSAPIKerberosAuth) Authorize(broker *Broker) error {
222213
if krbAuth.client == nil {
223-
kerberosClient, err :=createKerberosClient(krbAuth.config)
214+
kerberosClient, err := createKerberosClient(krbAuth.config)
224215
if err != nil {
225216
Logger.Printf("Kerberos client error: %s", err)
226217
return err

0 commit comments

Comments
 (0)