Skip to content

Commit

Permalink
Testing kerberos auth
Browse files Browse the repository at this point in the history
Signed-off-by: Ruben Vargas <ruben.vp8510@gmail.com>
  • Loading branch information
rubenvp8510 committed May 8, 2019
1 parent e1cae9a commit 282954a
Show file tree
Hide file tree
Showing 5 changed files with 375 additions and 72 deletions.
57 changes: 56 additions & 1 deletion broker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"testing"
"time"

metrics "github.com/rcrowley/go-metrics"
"github.com/rcrowley/go-metrics"
)

func ExampleBroker() {
Expand Down Expand Up @@ -477,6 +477,61 @@ func TestSASLPlainAuth(t *testing.T) {
}
}

func TestGSSAPIKerberosAuth_Authorize(t *testing.T) {

mockBroker := NewMockBroker(t, 0)
// broker executes SASL requests against mockBroker

mockBroker.SetGSSAPIHandler(func(bytes []byte) []byte {
return nil
})
broker := NewBroker(mockBroker.Addr())
broker.requestRate = metrics.NilMeter{}
broker.outgoingByteRate = metrics.NilMeter{}
broker.incomingByteRate = metrics.NilMeter{}
broker.requestSize = metrics.NilHistogram{}
broker.responseSize = metrics.NilHistogram{}
broker.responseRate = metrics.NilMeter{}
broker.requestLatency = metrics.NilHistogram{}
conf := NewConfig()
conf.Net.SASL.Mechanism = SASLTypeGSSAPI
conf.Net.SASL.GSSAPI.ServiceName = "kafka"
conf.Net.SASL.GSSAPI.KerberosConfigPath = "password"
conf.Net.SASL.GSSAPI.Realm = "EXAMPLE"
conf.Net.SASL.GSSAPI.Username = "kafka"
conf.Net.SASL.GSSAPI.Password = "kafka"
conf.Net.SASL.GSSAPI.KeyTabPath = "kafka.keytab"

broker.conf = conf
broker.conf.Version = V1_0_0_0
dialer := net.Dialer{
Timeout: conf.Net.DialTimeout,
KeepAlive: conf.Net.KeepAlive,
LocalAddr: conf.Net.LocalAddr,
}

conn, err := dialer.Dial("tcp", mockBroker.listener.Addr().String())

if err != nil {
t.Fatal(err)
}
kerberosClient := NewKerberosMockClient()
gssapiHandler := KafkaGSSAPIHandler{
client: kerberosClient,
}
mockBroker.SetGSSAPIHandler(gssapiHandler.MockKafkaGSSAPI)
broker.conn = conn
kerberosAuthenticator := NewGSSAPIKerberosAuthenticator(&broker.conf.Net.SASL.GSSAPI)
kerberosAuthenticator.client = kerberosClient
err = kerberosAuthenticator.Authorize(broker)
if err != nil {
t.Errorf("Expected success authentication, got %s", err)

}
mockBroker.Close()

}

func TestBuildClientInitialResponse(t *testing.T) {

testTable := []struct {
Expand Down
80 changes: 80 additions & 0 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,86 @@ func TestNetConfigValidates(t *testing.T) {
cfg.Net.SASL.Password = "stong_password"
},
"A SCRAMClientGeneratorFunc function must be provided to Net.SASL.SCRAMClientGeneratorFunc"},
{"SASL.Mechanism GSSAPI (Kerberos) - Using User/Password, Missing password field",
func(cfg *Config) {
cfg.Net.SASL.Enable = true
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
cfg.Net.SASL.GSSAPI.AuthType = KRB5_USER_AUTH
cfg.Net.SASL.GSSAPI.Username = "sarama"
cfg.Net.SASL.GSSAPI.ServiceName = "kafka"
cfg.Net.SASL.GSSAPI.Realm = "kafka"
cfg.Net.SASL.GSSAPI.KerberosConfigPath = "/etc/krb5.conf"
},
"Net.SASL.GSSAPI.Password must not be empty when GSS-API " +
"mechanism is used and Net.SASL.GSSAPI.AuthType = KRB5_USER_AUTH"},
{"SASL.Mechanism GSSAPI (Kerberos) - Using User/Password, Missing KeyTabPath field",
func(cfg *Config) {
cfg.Net.SASL.Enable = true
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
cfg.Net.SASL.GSSAPI.AuthType = KRB5_KEYTAB_AUTH
cfg.Net.SASL.GSSAPI.Username = "sarama"
cfg.Net.SASL.GSSAPI.ServiceName = "kafka"
cfg.Net.SASL.GSSAPI.Realm = "kafka"
cfg.Net.SASL.GSSAPI.KerberosConfigPath = "/etc/krb5.conf"
},
"Net.SASL.GSSAPI.KeyTabPath must not be empty when GSS-API mechanism is used" +
" and Net.SASL.GSSAPI.AuthType = KRB5_KEYTAB_AUTH"},
{"SASL.Mechanism GSSAPI (Kerberos) - Missing username",
func(cfg *Config) {
cfg.Net.SASL.Enable = true
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
cfg.Net.SASL.GSSAPI.AuthType = KRB5_USER_AUTH
cfg.Net.SASL.GSSAPI.Password = "sarama"
cfg.Net.SASL.GSSAPI.ServiceName = "kafka"
cfg.Net.SASL.GSSAPI.Realm = "kafka"
cfg.Net.SASL.GSSAPI.KerberosConfigPath = "/etc/krb5.conf"
},
"Net.SASL.GSSAPI.Username must not be empty when GSS-API mechanism is used"},
{"SASL.Mechanism GSSAPI (Kerberos) - Missing ServiceName",
func(cfg *Config) {
cfg.Net.SASL.Enable = true
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
cfg.Net.SASL.GSSAPI.AuthType = KRB5_USER_AUTH
cfg.Net.SASL.GSSAPI.Username = "sarama"
cfg.Net.SASL.GSSAPI.Password = "sarama"
cfg.Net.SASL.GSSAPI.Realm = "kafka"
cfg.Net.SASL.GSSAPI.KerberosConfigPath = "/etc/krb5.conf"
},
"Net.SASL.GSSAPI.ServiceName must not be empty when GSS-API mechanism is used"},
{"SASL.Mechanism GSSAPI (Kerberos) - Missing AuthType",
func(cfg *Config) {
cfg.Net.SASL.Enable = true
cfg.Net.SASL.GSSAPI.ServiceName = "kafka"
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
cfg.Net.SASL.GSSAPI.Username = "sarama"
cfg.Net.SASL.GSSAPI.Password = "sarama"
cfg.Net.SASL.GSSAPI.Realm = "kafka"
cfg.Net.SASL.GSSAPI.KerberosConfigPath = "/etc/krb5.conf"
},
"Net.SASL.GSSAPI.AuthType is invalid. Possible values are KRB5_USER_AUTH and KRB5_KEYTAB_AUTH"},
{"SASL.Mechanism GSSAPI (Kerberos) - Missing KerberosConfigPath",
func(cfg *Config) {
cfg.Net.SASL.Enable = true
cfg.Net.SASL.GSSAPI.ServiceName = "kafka"
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
cfg.Net.SASL.GSSAPI.AuthType = KRB5_USER_AUTH
cfg.Net.SASL.GSSAPI.Username = "sarama"
cfg.Net.SASL.GSSAPI.Password = "sarama"
cfg.Net.SASL.GSSAPI.Realm = "kafka"
},
"Net.SASL.GSSAPI.KerberosConfigPath must not be empty when GSS-API mechanism is used"},
{"SASL.Mechanism GSSAPI (Kerberos) - Missing Realm",
func(cfg *Config) {
cfg.Net.SASL.Enable = true
cfg.Net.SASL.GSSAPI.ServiceName = "kafka"
cfg.Net.SASL.Mechanism = SASLTypeGSSAPI
cfg.Net.SASL.GSSAPI.AuthType = KRB5_USER_AUTH
cfg.Net.SASL.GSSAPI.Username = "sarama"
cfg.Net.SASL.GSSAPI.Password = "sarama"
cfg.Net.SASL.GSSAPI.KerberosConfigPath = "/etc/krb5.conf"

},
"Net.SASL.GSSAPI.Realm must not be empty when GSS-API mechanism is used"},
}

for i, test := range tests {
Expand Down
39 changes: 15 additions & 24 deletions gssapi_kerberos.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,20 @@ import (
"time"
)




const (
TOK_ID_KRB_AP_REQ = "0100"
GSS_API_GENERIC_TAG = 0x60
KRB5_USER_AUTH = 1
KRB5_KEYTAB_AUTH = 2
KRB5_USER_AUTH = 1
KRB5_KEYTAB_AUTH = 2
)

type GSSAPIConfig struct {
AuthType int
AuthType int
KeyTabPath string
KerberosConfigPath string
ServiceName string
Username string
Password string
Password string
Realm string
}

Expand All @@ -54,22 +51,22 @@ type KerberosClient interface {
}

type KerberosGoKrb5Client struct {
client *krb5client.Client
client *krb5client.Client
}

func (c *KerberosGoKrb5Client)Login() error {
func (c *KerberosGoKrb5Client) Login() error {
return c.client.Login()
}

func (c *KerberosGoKrb5Client)GetServiceTicket(spn string) (messages.Ticket, types.EncryptionKey, error) {
func (c *KerberosGoKrb5Client) GetServiceTicket(spn string) (messages.Ticket, types.EncryptionKey, error) {
return c.client.GetServiceTicket(spn)
}

func (c *KerberosGoKrb5Client)Domain() string {
func (c *KerberosGoKrb5Client) Domain() string {
return c.client.Credentials.Domain()
}

func (c *KerberosGoKrb5Client)CName() types.PrincipalName {
func (c *KerberosGoKrb5Client) CName() types.PrincipalName {
return c.client.Credentials.CName()
}

Expand All @@ -83,9 +80,9 @@ func (c *KerberosGoKrb5Client)CName() types.PrincipalName {
*/
func createKerberosClient(config *GSSAPIConfig) (*KerberosGoKrb5Client, error) {
cfg, err := krb5config.Load(config.KerberosConfigPath)
var client *krb5client.Client
var client *krb5client.Client
if err != nil {
return nil,err
return nil, err
}
if config.AuthType == KRB5_KEYTAB_AUTH {
kt, err := keytab.Load(config.KeyTabPath)
Expand Down Expand Up @@ -142,14 +139,11 @@ func (krbAuth *GSSAPIKerberosAuth) readPackage(broker *Broker) ([]byte, int, err
return payloadBytes, bytesRead, nil
}

func (krbAuth *GSSAPIKerberosAuth) newAuthenticatorChecksum(flags []int) []byte {
func (krbAuth *GSSAPIKerberosAuth) newAuthenticatorChecksum() []byte {
a := make([]byte, 24)
flags := []int{gssapi.ContextFlagInteg, gssapi.ContextFlagConf}
binary.LittleEndian.PutUint32(a[:4], 16)
for _, i := range flags {
if i == gssapi.ContextFlagDeleg {
x := make([]byte, 28-len(a))
a = append(a, x...)
}
f := binary.LittleEndian.Uint32(a[20:24])
f |= uint32(i)
binary.LittleEndian.PutUint32(a[20:24], f)
Expand All @@ -164,14 +158,13 @@ func (krbAuth *GSSAPIKerberosAuth) newAuthenticatorChecksum(flags []int) []byte
*
*/
func (krbAuth *GSSAPIKerberosAuth) createKrb5Token(client KerberosClient, ticket messages.Ticket, sessionKey types.EncryptionKey) ([]byte, error) {
var GSSAPIFlags = []int{gssapi.ContextFlagInteg, gssapi.ContextFlagConf}
auth, err := types.NewAuthenticator(client.Domain(), client.CName())
if err != nil {
return nil, err
}
auth.Cksum = types.Checksum{
CksumType: chksumtype.GSSAPI,
Checksum: krbAuth.newAuthenticatorChecksum(GSSAPIFlags),
Checksum: krbAuth.newAuthenticatorChecksum(),
}
APReq, err := messages.NewAPReq(
ticket,
Expand Down Expand Up @@ -215,12 +208,10 @@ func (krbAuth *GSSAPIKerberosAuth) appendGSSAPIHeader(payload []byte) ([]byte, e
return GSSPackage, nil
}



/* This does the handshake for authorization */
func (krbAuth *GSSAPIKerberosAuth) Authorize(broker *Broker) error {
if krbAuth.client == nil {
kerberosClient, err :=createKerberosClient(krbAuth.config)
kerberosClient, err := createKerberosClient(krbAuth.config)
if err != nil {
Logger.Printf("Kerberos client error: %s", err)
return err
Expand Down
Loading

0 comments on commit 282954a

Please sign in to comment.