From fe5ed31ac25c187934e43ee2e594fe718aed6618 Mon Sep 17 00:00:00 2001 From: "Remi GASCOU (Podalirius)" <79218792+p0dalirius@users.noreply.github.com> Date: Thu, 14 Nov 2024 16:17:12 +0100 Subject: [PATCH 1/7] Added APOptions []int in client.GSSAPIBindRequest(...) and client.InitSecContext(...), fixes #536 --- bind.go | 18 +++++++++------ gssapi/client.go | 56 ++++++++++++++++++++++++++++++++++++++++++--- v3/bind.go | 18 +++++++++------ v3/gssapi/client.go | 56 ++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 128 insertions(+), 20 deletions(-) diff --git a/bind.go b/bind.go index a37f8e2c..b7011bda 100644 --- a/bind.go +++ b/bind.go @@ -576,7 +576,7 @@ type GSSAPIClient interface { // reply token is received from the server, passing the reply token // to InitSecContext via the token parameters. // See RFC 4752 section 3.1. - InitSecContext(target string, token []byte) (outputToken []byte, needContinue bool, err error) + InitSecContext(target string, token []byte, APOptions []int) (outputToken []byte, needContinue bool, err error) // NegotiateSaslAuth performs the last step of the Sasl handshake. // It takes a token, which, when unwrapped, describes the servers supported // security layers (first octet) and maximum receive buffer (remaining @@ -606,14 +606,18 @@ type GSSAPIBindRequest struct { // GSSAPIBind performs the GSSAPI SASL bind using the provided GSSAPI client. func (l *Conn) GSSAPIBind(client GSSAPIClient, servicePrincipal, authzid string) error { - return l.GSSAPIBindRequest(client, &GSSAPIBindRequest{ - ServicePrincipalName: servicePrincipal, - AuthZID: authzid, - }) + return l.GSSAPIBindRequest( + client, + &GSSAPIBindRequest{ + ServicePrincipalName: servicePrincipal, + AuthZID: authzid, + }, + []int{}, + ) } // GSSAPIBindRequest performs the GSSAPI SASL bind using the provided GSSAPI client. -func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest) error { +func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest, APOptions []int) error { //nolint:errcheck defer client.DeleteSecContext() @@ -624,7 +628,7 @@ func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest) er for { if needInit { // Establish secure context between client and server. - reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken) + reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken, APOptions) if err != nil { return err } diff --git a/gssapi/client.go b/gssapi/client.go index d6c6dbd4..2ae2c006 100644 --- a/gssapi/client.go +++ b/gssapi/client.go @@ -1,6 +1,10 @@ package gssapi import ( + "bytes" + "encoding/binary" + "encoding/hex" + "errors" "fmt" "github.com/jcmturner/gokrb5/v8/client" @@ -99,7 +103,7 @@ func (client *Client) DeleteSecContext() error { // InitSecContext initiates the establishment of a security context for // GSS-API between the client and server. // See RFC 4752 section 3.1. -func (client *Client) InitSecContext(target string, input []byte) ([]byte, bool, error) { +func (client *Client) InitSecContext(target string, input []byte, APOptions []int) ([]byte, bool, error) { gssapiFlags := []int{gssapi.ContextFlagInteg, gssapi.ContextFlagConf, gssapi.ContextFlagMutual} switch input { @@ -110,7 +114,7 @@ func (client *Client) InitSecContext(target string, input []byte) ([]byte, bool, } client.ekey = ekey - token, err := spnego.NewKRB5TokenAPREQ(client.Client, tkt, ekey, gssapiFlags, []int{}) + token, err := spnego.NewKRB5TokenAPREQ(client.Client, tkt, ekey, gssapiFlags, APOptions) if err != nil { return nil, false, err } @@ -160,7 +164,7 @@ func (client *Client) InitSecContext(target string, input []byte) ([]byte, bool, // See RFC 4752 section 3.1. func (client *Client) NegotiateSaslAuth(input []byte, authzid string) ([]byte, error) { token := &gssapi.WrapToken{} - err := token.Unmarshal(input, true) + err := UnmarshalWrapToken(token, input, true) if err != nil { return nil, err } @@ -212,3 +216,49 @@ func (client *Client) NegotiateSaslAuth(input []byte, authzid string) ([]byte, e return output, nil } + +func getGssWrapTokenId() *[2]byte { + return &[2]byte{0x05, 0x04} +} + +func UnmarshalWrapToken(wt *gssapi.WrapToken, b []byte, expectFromAcceptor bool) error { + // Check if we can read a whole header + if len(b) < 16 { + return errors.New("bytes shorter than header length") + } + // Is the Token ID correct? + if !bytes.Equal(getGssWrapTokenId()[:], b[0:2]) { + return fmt.Errorf("wrong Token ID. Expected %s, was %s", + hex.EncodeToString(getGssWrapTokenId()[:]), + hex.EncodeToString(b[0:2])) + } + // Check the acceptor flag + flags := b[2] + isFromAcceptor := flags&0x01 == 1 + if isFromAcceptor && !expectFromAcceptor { + return errors.New("unexpected acceptor flag is set: not expecting a token from the acceptor") + } + if !isFromAcceptor && expectFromAcceptor { + return errors.New("expected acceptor flag is not set: expecting a token from the acceptor, not the initiator") + } + // Check the filler byte + if b[3] != gssapi.FillerByte { + return fmt.Errorf("unexpected filler byte: expecting 0xFF, was %s ", hex.EncodeToString(b[3:4])) + } + checksumL := binary.BigEndian.Uint16(b[4:6]) + // Sanity check on the checksum length + if int(checksumL) > len(b)-gssapi.HdrLen { + return fmt.Errorf("inconsistent checksum length: %d bytes to parse, checksum length is %d", len(b), checksumL) + } + + payloadStart := 16 + checksumL + + wt.Flags = flags + wt.EC = checksumL + wt.RRC = binary.BigEndian.Uint16(b[6:8]) + wt.SndSeqNum = binary.BigEndian.Uint64(b[8:16]) + wt.CheckSum = b[16:payloadStart] + wt.Payload = b[payloadStart:] + + return nil +} diff --git a/v3/bind.go b/v3/bind.go index a37f8e2c..b7011bda 100644 --- a/v3/bind.go +++ b/v3/bind.go @@ -576,7 +576,7 @@ type GSSAPIClient interface { // reply token is received from the server, passing the reply token // to InitSecContext via the token parameters. // See RFC 4752 section 3.1. - InitSecContext(target string, token []byte) (outputToken []byte, needContinue bool, err error) + InitSecContext(target string, token []byte, APOptions []int) (outputToken []byte, needContinue bool, err error) // NegotiateSaslAuth performs the last step of the Sasl handshake. // It takes a token, which, when unwrapped, describes the servers supported // security layers (first octet) and maximum receive buffer (remaining @@ -606,14 +606,18 @@ type GSSAPIBindRequest struct { // GSSAPIBind performs the GSSAPI SASL bind using the provided GSSAPI client. func (l *Conn) GSSAPIBind(client GSSAPIClient, servicePrincipal, authzid string) error { - return l.GSSAPIBindRequest(client, &GSSAPIBindRequest{ - ServicePrincipalName: servicePrincipal, - AuthZID: authzid, - }) + return l.GSSAPIBindRequest( + client, + &GSSAPIBindRequest{ + ServicePrincipalName: servicePrincipal, + AuthZID: authzid, + }, + []int{}, + ) } // GSSAPIBindRequest performs the GSSAPI SASL bind using the provided GSSAPI client. -func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest) error { +func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest, APOptions []int) error { //nolint:errcheck defer client.DeleteSecContext() @@ -624,7 +628,7 @@ func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest) er for { if needInit { // Establish secure context between client and server. - reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken) + reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken, APOptions) if err != nil { return err } diff --git a/v3/gssapi/client.go b/v3/gssapi/client.go index d6c6dbd4..2ae2c006 100644 --- a/v3/gssapi/client.go +++ b/v3/gssapi/client.go @@ -1,6 +1,10 @@ package gssapi import ( + "bytes" + "encoding/binary" + "encoding/hex" + "errors" "fmt" "github.com/jcmturner/gokrb5/v8/client" @@ -99,7 +103,7 @@ func (client *Client) DeleteSecContext() error { // InitSecContext initiates the establishment of a security context for // GSS-API between the client and server. // See RFC 4752 section 3.1. -func (client *Client) InitSecContext(target string, input []byte) ([]byte, bool, error) { +func (client *Client) InitSecContext(target string, input []byte, APOptions []int) ([]byte, bool, error) { gssapiFlags := []int{gssapi.ContextFlagInteg, gssapi.ContextFlagConf, gssapi.ContextFlagMutual} switch input { @@ -110,7 +114,7 @@ func (client *Client) InitSecContext(target string, input []byte) ([]byte, bool, } client.ekey = ekey - token, err := spnego.NewKRB5TokenAPREQ(client.Client, tkt, ekey, gssapiFlags, []int{}) + token, err := spnego.NewKRB5TokenAPREQ(client.Client, tkt, ekey, gssapiFlags, APOptions) if err != nil { return nil, false, err } @@ -160,7 +164,7 @@ func (client *Client) InitSecContext(target string, input []byte) ([]byte, bool, // See RFC 4752 section 3.1. func (client *Client) NegotiateSaslAuth(input []byte, authzid string) ([]byte, error) { token := &gssapi.WrapToken{} - err := token.Unmarshal(input, true) + err := UnmarshalWrapToken(token, input, true) if err != nil { return nil, err } @@ -212,3 +216,49 @@ func (client *Client) NegotiateSaslAuth(input []byte, authzid string) ([]byte, e return output, nil } + +func getGssWrapTokenId() *[2]byte { + return &[2]byte{0x05, 0x04} +} + +func UnmarshalWrapToken(wt *gssapi.WrapToken, b []byte, expectFromAcceptor bool) error { + // Check if we can read a whole header + if len(b) < 16 { + return errors.New("bytes shorter than header length") + } + // Is the Token ID correct? + if !bytes.Equal(getGssWrapTokenId()[:], b[0:2]) { + return fmt.Errorf("wrong Token ID. Expected %s, was %s", + hex.EncodeToString(getGssWrapTokenId()[:]), + hex.EncodeToString(b[0:2])) + } + // Check the acceptor flag + flags := b[2] + isFromAcceptor := flags&0x01 == 1 + if isFromAcceptor && !expectFromAcceptor { + return errors.New("unexpected acceptor flag is set: not expecting a token from the acceptor") + } + if !isFromAcceptor && expectFromAcceptor { + return errors.New("expected acceptor flag is not set: expecting a token from the acceptor, not the initiator") + } + // Check the filler byte + if b[3] != gssapi.FillerByte { + return fmt.Errorf("unexpected filler byte: expecting 0xFF, was %s ", hex.EncodeToString(b[3:4])) + } + checksumL := binary.BigEndian.Uint16(b[4:6]) + // Sanity check on the checksum length + if int(checksumL) > len(b)-gssapi.HdrLen { + return fmt.Errorf("inconsistent checksum length: %d bytes to parse, checksum length is %d", len(b), checksumL) + } + + payloadStart := 16 + checksumL + + wt.Flags = flags + wt.EC = checksumL + wt.RRC = binary.BigEndian.Uint16(b[6:8]) + wt.SndSeqNum = binary.BigEndian.Uint64(b[8:16]) + wt.CheckSum = b[16:payloadStart] + wt.Payload = b[payloadStart:] + + return nil +} From 3bbd598a647fc79d4888bcf1407cf854d7d554cb Mon Sep 17 00:00:00 2001 From: "Remi GASCOU (Podalirius)" <79218792+p0dalirius@users.noreply.github.com> Date: Mon, 18 Nov 2024 10:41:33 +0100 Subject: [PATCH 2/7] Moving APOptions to GSSAPIBindRequest struct for coherence and to avoid changing the func prototypes --- bind.go | 8 +++++--- gssapi/client.go | 39 +++++++++++++++++++-------------------- v3/bind.go | 8 +++++--- v3/gssapi/client.go | 39 ++++++++++++++++++++------------------- 4 files changed, 49 insertions(+), 45 deletions(-) diff --git a/bind.go b/bind.go index b7011bda..07e11679 100644 --- a/bind.go +++ b/bind.go @@ -602,6 +602,8 @@ type GSSAPIBindRequest struct { AuthZID string // (Optional) Controls to send with the bind request Controls []Control + // (Optional) APOptions + APOptions []int } // GSSAPIBind performs the GSSAPI SASL bind using the provided GSSAPI client. @@ -611,13 +613,13 @@ func (l *Conn) GSSAPIBind(client GSSAPIClient, servicePrincipal, authzid string) &GSSAPIBindRequest{ ServicePrincipalName: servicePrincipal, AuthZID: authzid, + APOptions: []int{}, }, - []int{}, ) } // GSSAPIBindRequest performs the GSSAPI SASL bind using the provided GSSAPI client. -func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest, APOptions []int) error { +func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest) error { //nolint:errcheck defer client.DeleteSecContext() @@ -628,7 +630,7 @@ func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest, AP for { if needInit { // Establish secure context between client and server. - reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken, APOptions) + reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken, req.APOptions) if err != nil { return err } diff --git a/gssapi/client.go b/gssapi/client.go index 2ae2c006..2f234fbd 100644 --- a/gssapi/client.go +++ b/gssapi/client.go @@ -217,23 +217,20 @@ func (client *Client) NegotiateSaslAuth(input []byte, authzid string) ([]byte, e return output, nil } -func getGssWrapTokenId() *[2]byte { - return &[2]byte{0x05, 0x04} -} - -func UnmarshalWrapToken(wt *gssapi.WrapToken, b []byte, expectFromAcceptor bool) error { +func UnmarshalWrapToken(wt *gssapi.WrapToken, data []byte, expectFromAcceptor bool) error { // Check if we can read a whole header - if len(b) < 16 { + if len(data) < 16 { return errors.New("bytes shorter than header length") } + // Is the Token ID correct? - if !bytes.Equal(getGssWrapTokenId()[:], b[0:2]) { - return fmt.Errorf("wrong Token ID. Expected %s, was %s", - hex.EncodeToString(getGssWrapTokenId()[:]), - hex.EncodeToString(b[0:2])) + expectedWrapTokenId := [2]byte{0x05, 0x04} + if !bytes.Equal(expectedWrapTokenId[:], data[0:2]) { + return fmt.Errorf("wrong Token ID. Expected %s, was %s", hex.EncodeToString(expectedWrapTokenId[:]), hex.EncodeToString(data[0:2])) } + // Check the acceptor flag - flags := b[2] + flags := data[2] isFromAcceptor := flags&0x01 == 1 if isFromAcceptor && !expectFromAcceptor { return errors.New("unexpected acceptor flag is set: not expecting a token from the acceptor") @@ -241,24 +238,26 @@ func UnmarshalWrapToken(wt *gssapi.WrapToken, b []byte, expectFromAcceptor bool) if !isFromAcceptor && expectFromAcceptor { return errors.New("expected acceptor flag is not set: expecting a token from the acceptor, not the initiator") } + // Check the filler byte - if b[3] != gssapi.FillerByte { - return fmt.Errorf("unexpected filler byte: expecting 0xFF, was %s ", hex.EncodeToString(b[3:4])) + if data[3] != gssapi.FillerByte { + return fmt.Errorf("unexpected filler byte: expecting 0xFF, was %s ", hex.EncodeToString(data[3:4])) } - checksumL := binary.BigEndian.Uint16(b[4:6]) + checksumL := binary.BigEndian.Uint16(data[4:6]) + // Sanity check on the checksum length - if int(checksumL) > len(b)-gssapi.HdrLen { - return fmt.Errorf("inconsistent checksum length: %d bytes to parse, checksum length is %d", len(b), checksumL) + if int(checksumL) > len(data)-gssapi.HdrLen { + return fmt.Errorf("inconsistent checksum length: %d bytes to parse, checksum length is %d", len(data), checksumL) } payloadStart := 16 + checksumL wt.Flags = flags wt.EC = checksumL - wt.RRC = binary.BigEndian.Uint16(b[6:8]) - wt.SndSeqNum = binary.BigEndian.Uint64(b[8:16]) - wt.CheckSum = b[16:payloadStart] - wt.Payload = b[payloadStart:] + wt.RRC = binary.BigEndian.Uint16(data[6:8]) + wt.SndSeqNum = binary.BigEndian.Uint64(data[8:16]) + wt.CheckSum = data[16:payloadStart] + wt.Payload = data[payloadStart:] return nil } diff --git a/v3/bind.go b/v3/bind.go index b7011bda..07e11679 100644 --- a/v3/bind.go +++ b/v3/bind.go @@ -602,6 +602,8 @@ type GSSAPIBindRequest struct { AuthZID string // (Optional) Controls to send with the bind request Controls []Control + // (Optional) APOptions + APOptions []int } // GSSAPIBind performs the GSSAPI SASL bind using the provided GSSAPI client. @@ -611,13 +613,13 @@ func (l *Conn) GSSAPIBind(client GSSAPIClient, servicePrincipal, authzid string) &GSSAPIBindRequest{ ServicePrincipalName: servicePrincipal, AuthZID: authzid, + APOptions: []int{}, }, - []int{}, ) } // GSSAPIBindRequest performs the GSSAPI SASL bind using the provided GSSAPI client. -func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest, APOptions []int) error { +func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest) error { //nolint:errcheck defer client.DeleteSecContext() @@ -628,7 +630,7 @@ func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest, AP for { if needInit { // Establish secure context between client and server. - reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken, APOptions) + reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken, req.APOptions) if err != nil { return err } diff --git a/v3/gssapi/client.go b/v3/gssapi/client.go index 2ae2c006..6d115d4b 100644 --- a/v3/gssapi/client.go +++ b/v3/gssapi/client.go @@ -217,23 +217,22 @@ func (client *Client) NegotiateSaslAuth(input []byte, authzid string) ([]byte, e return output, nil } -func getGssWrapTokenId() *[2]byte { - return &[2]byte{0x05, 0x04} -} - -func UnmarshalWrapToken(wt *gssapi.WrapToken, b []byte, expectFromAcceptor bool) error { +func UnmarshalWrapToken(wt *gssapi.WrapToken, data []byte, expectFromAcceptor bool) error { // Check if we can read a whole header - if len(b) < 16 { + if len(data) < 16 { return errors.New("bytes shorter than header length") } + // Is the Token ID correct? - if !bytes.Equal(getGssWrapTokenId()[:], b[0:2]) { + expectedWrapTokenId := [2]byte{0x05, 0x04} + if !bytes.Equal(expectedWrapTokenId[:], data[0:2]) { return fmt.Errorf("wrong Token ID. Expected %s, was %s", - hex.EncodeToString(getGssWrapTokenId()[:]), - hex.EncodeToString(b[0:2])) + hex.EncodeToString(expectedWrapTokenId[:]), + hex.EncodeToString(data[0:2])) } + // Check the acceptor flag - flags := b[2] + flags := data[2] isFromAcceptor := flags&0x01 == 1 if isFromAcceptor && !expectFromAcceptor { return errors.New("unexpected acceptor flag is set: not expecting a token from the acceptor") @@ -241,24 +240,26 @@ func UnmarshalWrapToken(wt *gssapi.WrapToken, b []byte, expectFromAcceptor bool) if !isFromAcceptor && expectFromAcceptor { return errors.New("expected acceptor flag is not set: expecting a token from the acceptor, not the initiator") } + // Check the filler byte - if b[3] != gssapi.FillerByte { - return fmt.Errorf("unexpected filler byte: expecting 0xFF, was %s ", hex.EncodeToString(b[3:4])) + if data[3] != gssapi.FillerByte { + return fmt.Errorf("unexpected filler byte: expecting 0xFF, was %s ", hex.EncodeToString(data[3:4])) } - checksumL := binary.BigEndian.Uint16(b[4:6]) + checksumL := binary.BigEndian.Uint16(data[4:6]) + // Sanity check on the checksum length - if int(checksumL) > len(b)-gssapi.HdrLen { - return fmt.Errorf("inconsistent checksum length: %d bytes to parse, checksum length is %d", len(b), checksumL) + if int(checksumL) > len(data)-gssapi.HdrLen { + return fmt.Errorf("inconsistent checksum length: %d bytes to parse, checksum length is %d", len(data), checksumL) } payloadStart := 16 + checksumL wt.Flags = flags wt.EC = checksumL - wt.RRC = binary.BigEndian.Uint16(b[6:8]) - wt.SndSeqNum = binary.BigEndian.Uint64(b[8:16]) - wt.CheckSum = b[16:payloadStart] - wt.Payload = b[payloadStart:] + wt.RRC = binary.BigEndian.Uint16(data[6:8]) + wt.SndSeqNum = binary.BigEndian.Uint64(data[8:16]) + wt.CheckSum = data[16:payloadStart] + wt.Payload = data[payloadStart:] return nil } From 78ef5d4181a0846dd60a0902217731ee1434dfa7 Mon Sep 17 00:00:00 2001 From: "Remi GASCOU (Podalirius)" <79218792+p0dalirius@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:26:57 +0100 Subject: [PATCH 3/7] Unified UnmarshalWrapToken() with v3 and base --- v3/gssapi/client.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/v3/gssapi/client.go b/v3/gssapi/client.go index 6d115d4b..8017720a 100644 --- a/v3/gssapi/client.go +++ b/v3/gssapi/client.go @@ -22,7 +22,7 @@ import ( "github.com/jcmturner/gokrb5/v8/credentials" ) -// Client implements ldap.GSSAPIClient interface. +// Client implements ldapgithub.com/jcmturner/gokrb5/v8/spnego.GSSAPIClient interface. type Client struct { *client.Client @@ -226,9 +226,7 @@ func UnmarshalWrapToken(wt *gssapi.WrapToken, data []byte, expectFromAcceptor bo // Is the Token ID correct? expectedWrapTokenId := [2]byte{0x05, 0x04} if !bytes.Equal(expectedWrapTokenId[:], data[0:2]) { - return fmt.Errorf("wrong Token ID. Expected %s, was %s", - hex.EncodeToString(expectedWrapTokenId[:]), - hex.EncodeToString(data[0:2])) + return fmt.Errorf("wrong Token ID. Expected %s, was %s", hex.EncodeToString(expectedWrapTokenId[:]), hex.EncodeToString(data[0:2])) } // Check the acceptor flag From 1cad94493d83d74b77cb4cd3619ea05c1e14d959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20GASCOU=20=28Podalirius=29?= Date: Fri, 13 Dec 2024 09:00:25 +0100 Subject: [PATCH 4/7] Update client.go --- v3/gssapi/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v3/gssapi/client.go b/v3/gssapi/client.go index 8017720a..2f234fbd 100644 --- a/v3/gssapi/client.go +++ b/v3/gssapi/client.go @@ -22,7 +22,7 @@ import ( "github.com/jcmturner/gokrb5/v8/credentials" ) -// Client implements ldapgithub.com/jcmturner/gokrb5/v8/spnego.GSSAPIClient interface. +// Client implements ldap.GSSAPIClient interface. type Client struct { *client.Client From 1cc1eb3d6f0e867bc053f79a58bbe5f98b2c3902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20GASCOU=20=28Podalirius=29?= Date: Fri, 13 Dec 2024 09:32:14 +0100 Subject: [PATCH 5/7] Removed breaking API changes to InitSecContext, added APOptions in Client struct --- v3/bind.go | 7 ++----- v3/gssapi/client.go | 6 ++++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/v3/bind.go b/v3/bind.go index 07e11679..26ebbd7d 100644 --- a/v3/bind.go +++ b/v3/bind.go @@ -576,7 +576,7 @@ type GSSAPIClient interface { // reply token is received from the server, passing the reply token // to InitSecContext via the token parameters. // See RFC 4752 section 3.1. - InitSecContext(target string, token []byte, APOptions []int) (outputToken []byte, needContinue bool, err error) + InitSecContext(target string, token []byte) (outputToken []byte, needContinue bool, err error) // NegotiateSaslAuth performs the last step of the Sasl handshake. // It takes a token, which, when unwrapped, describes the servers supported // security layers (first octet) and maximum receive buffer (remaining @@ -602,8 +602,6 @@ type GSSAPIBindRequest struct { AuthZID string // (Optional) Controls to send with the bind request Controls []Control - // (Optional) APOptions - APOptions []int } // GSSAPIBind performs the GSSAPI SASL bind using the provided GSSAPI client. @@ -613,7 +611,6 @@ func (l *Conn) GSSAPIBind(client GSSAPIClient, servicePrincipal, authzid string) &GSSAPIBindRequest{ ServicePrincipalName: servicePrincipal, AuthZID: authzid, - APOptions: []int{}, }, ) } @@ -630,7 +627,7 @@ func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest) er for { if needInit { // Establish secure context between client and server. - reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken, req.APOptions) + reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken) if err != nil { return err } diff --git a/v3/gssapi/client.go b/v3/gssapi/client.go index 2f234fbd..bb55b46f 100644 --- a/v3/gssapi/client.go +++ b/v3/gssapi/client.go @@ -28,6 +28,8 @@ type Client struct { ekey types.EncryptionKey Subkey types.EncryptionKey + + APOptions []int } // NewClientWithKeytab creates a new client from a keytab credential. @@ -103,7 +105,7 @@ func (client *Client) DeleteSecContext() error { // InitSecContext initiates the establishment of a security context for // GSS-API between the client and server. // See RFC 4752 section 3.1. -func (client *Client) InitSecContext(target string, input []byte, APOptions []int) ([]byte, bool, error) { +func (client *Client) InitSecContext(target string, input []byte) ([]byte, bool, error) { gssapiFlags := []int{gssapi.ContextFlagInteg, gssapi.ContextFlagConf, gssapi.ContextFlagMutual} switch input { @@ -114,7 +116,7 @@ func (client *Client) InitSecContext(target string, input []byte, APOptions []in } client.ekey = ekey - token, err := spnego.NewKRB5TokenAPREQ(client.Client, tkt, ekey, gssapiFlags, APOptions) + token, err := spnego.NewKRB5TokenAPREQ(client.Client, tkt, ekey, gssapiFlags, client.APOptions) if err != nil { return nil, false, err } From f752bf8d98f2ff193c1ecfa69ad0f4fa6db16be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20GASCOU=20=28Podalirius=29?= Date: Fri, 13 Dec 2024 09:35:52 +0100 Subject: [PATCH 6/7] Removed breaking API changes to InitSecContext, added APOptions in Client struct --- bind.go | 7 ++----- gssapi/client.go | 6 ++++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/bind.go b/bind.go index 07e11679..26ebbd7d 100644 --- a/bind.go +++ b/bind.go @@ -576,7 +576,7 @@ type GSSAPIClient interface { // reply token is received from the server, passing the reply token // to InitSecContext via the token parameters. // See RFC 4752 section 3.1. - InitSecContext(target string, token []byte, APOptions []int) (outputToken []byte, needContinue bool, err error) + InitSecContext(target string, token []byte) (outputToken []byte, needContinue bool, err error) // NegotiateSaslAuth performs the last step of the Sasl handshake. // It takes a token, which, when unwrapped, describes the servers supported // security layers (first octet) and maximum receive buffer (remaining @@ -602,8 +602,6 @@ type GSSAPIBindRequest struct { AuthZID string // (Optional) Controls to send with the bind request Controls []Control - // (Optional) APOptions - APOptions []int } // GSSAPIBind performs the GSSAPI SASL bind using the provided GSSAPI client. @@ -613,7 +611,6 @@ func (l *Conn) GSSAPIBind(client GSSAPIClient, servicePrincipal, authzid string) &GSSAPIBindRequest{ ServicePrincipalName: servicePrincipal, AuthZID: authzid, - APOptions: []int{}, }, ) } @@ -630,7 +627,7 @@ func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest) er for { if needInit { // Establish secure context between client and server. - reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken, req.APOptions) + reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken) if err != nil { return err } diff --git a/gssapi/client.go b/gssapi/client.go index 2f234fbd..bb55b46f 100644 --- a/gssapi/client.go +++ b/gssapi/client.go @@ -28,6 +28,8 @@ type Client struct { ekey types.EncryptionKey Subkey types.EncryptionKey + + APOptions []int } // NewClientWithKeytab creates a new client from a keytab credential. @@ -103,7 +105,7 @@ func (client *Client) DeleteSecContext() error { // InitSecContext initiates the establishment of a security context for // GSS-API between the client and server. // See RFC 4752 section 3.1. -func (client *Client) InitSecContext(target string, input []byte, APOptions []int) ([]byte, bool, error) { +func (client *Client) InitSecContext(target string, input []byte) ([]byte, bool, error) { gssapiFlags := []int{gssapi.ContextFlagInteg, gssapi.ContextFlagConf, gssapi.ContextFlagMutual} switch input { @@ -114,7 +116,7 @@ func (client *Client) InitSecContext(target string, input []byte, APOptions []in } client.ekey = ekey - token, err := spnego.NewKRB5TokenAPREQ(client.Client, tkt, ekey, gssapiFlags, APOptions) + token, err := spnego.NewKRB5TokenAPREQ(client.Client, tkt, ekey, gssapiFlags, client.APOptions) if err != nil { return nil, false, err } From a55dbd6d99c12f37309fc10beb6a57de9a0bf784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20GASCOU=20=28Podalirius=29?= Date: Sun, 15 Dec 2024 21:22:15 +0100 Subject: [PATCH 7/7] Changing unmarshalWrapToken function to private --- gssapi/client.go | 4 ++-- v3/gssapi/client.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gssapi/client.go b/gssapi/client.go index bb55b46f..8e8ab5ca 100644 --- a/gssapi/client.go +++ b/gssapi/client.go @@ -166,7 +166,7 @@ func (client *Client) InitSecContext(target string, input []byte) ([]byte, bool, // See RFC 4752 section 3.1. func (client *Client) NegotiateSaslAuth(input []byte, authzid string) ([]byte, error) { token := &gssapi.WrapToken{} - err := UnmarshalWrapToken(token, input, true) + err := unmarshalWrapToken(token, input, true) if err != nil { return nil, err } @@ -219,7 +219,7 @@ func (client *Client) NegotiateSaslAuth(input []byte, authzid string) ([]byte, e return output, nil } -func UnmarshalWrapToken(wt *gssapi.WrapToken, data []byte, expectFromAcceptor bool) error { +func unmarshalWrapToken(wt *gssapi.WrapToken, data []byte, expectFromAcceptor bool) error { // Check if we can read a whole header if len(data) < 16 { return errors.New("bytes shorter than header length") diff --git a/v3/gssapi/client.go b/v3/gssapi/client.go index bb55b46f..8e8ab5ca 100644 --- a/v3/gssapi/client.go +++ b/v3/gssapi/client.go @@ -166,7 +166,7 @@ func (client *Client) InitSecContext(target string, input []byte) ([]byte, bool, // See RFC 4752 section 3.1. func (client *Client) NegotiateSaslAuth(input []byte, authzid string) ([]byte, error) { token := &gssapi.WrapToken{} - err := UnmarshalWrapToken(token, input, true) + err := unmarshalWrapToken(token, input, true) if err != nil { return nil, err } @@ -219,7 +219,7 @@ func (client *Client) NegotiateSaslAuth(input []byte, authzid string) ([]byte, e return output, nil } -func UnmarshalWrapToken(wt *gssapi.WrapToken, data []byte, expectFromAcceptor bool) error { +func unmarshalWrapToken(wt *gssapi.WrapToken, data []byte, expectFromAcceptor bool) error { // Check if we can read a whole header if len(data) < 16 { return errors.New("bytes shorter than header length")