-
Notifications
You must be signed in to change notification settings - Fork 358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[bugfix] Added APOptions []int in client.GSSAPIBindRequest(...) and client.InitSecContext(...), fixes #536 #537
base: master
Are you sure you want to change the base?
Conversation
c76a77b
to
3a20a5c
Compare
…tSecContext(...), fixes go-ldap#536
3a20a5c
to
fe5ed31
Compare
Hi @p0dalirius, thank you very much for your PR and the work you put into debugging this issue (#536)! My strengths are not at all in Kerberos and my knowledge of the protocol is practically zero, so thank you again! But: Modifying the signature of an existing function will definitely interfere with existing code. Even the addition of changes that are only noticed by linters has caused trouble in the past (#463). If there is really no other way to implement Kerberos authentication, I would be willing to do so and include it in the next release, but only if no one objects. @go-ldap/committers thoughts? |
…id changing the func prototypes
@cpuschma, before merging, It would be nice if someone can try to connect to a UNIX ldap server with GSSAPI to confirm that it still works with this fix I will try to setup one and test it |
Using functional options instead of a slice of ints should not break existing implementations |
Could someone please advise if this will be merged soon? :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of the difficulties with this PR is the lack of GSSAPI knowledge by many of the maintainers - if someone with GSSAPI experience could weigh in that would be helpful.
That being said there are some things that should be done differently, and I've tried to point out some of them in this review.
I like the idea of using functional options to avoid future breaking changes, but I'm not sure there's really a need for it in this particular case.
v3/gssapi/client.go
Outdated
@@ -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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not break the API.
I suggest adding a new func (*Client) InitSecContextWithOptions(string, []byte, []int) ([]byte, bool, error)
and then modify the internals of the original InitSecContext
to simply call the new InitSecContextWithOptions
, passing in suitable defaults.
v3/gssapi/client.go
Outdated
@@ -212,3 +216,48 @@ func (client *Client) NegotiateSaslAuth(input []byte, authzid string) ([]byte, e | |||
|
|||
return output, nil | |||
} | |||
|
|||
func UnmarshalWrapToken(wt *gssapi.WrapToken, data []byte, expectFromAcceptor bool) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate this new function that appears to do more robust checking while unmarshalling the input, however:
- We should not export the function (and thereby add to our API), unless absolutely necessary.
- I would be much more comfortable if there were some unit tests asserting that this function actually works as intended.
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") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we anticipate any kind of code handling of these errors it may be kinder to actually create named errors (var ErrInvalidGSSAPIFooBarHeaderLength = "bytes shorter ..."
), that can be used with the errors.Is
and related helper functions.
// 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])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In cases where returning additional context with the error it may be nice for it to wrap a simpler 'known' error as the related comment says.
eg return fmt.Errorf("wrong blah blah. expected %s, was %s: %w", x, y, ErrUnmarshalFault)
or something like that
v3/bind.go
Outdated
@@ -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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in the comment on the implementation; let's not modify (break) an existing API - we should add a new method if we really need to.
The earlier commits would have broken the client in (I think it makes sense to add asserts that both clients implement the interface to make breaking changes less likely, although you would still have to build for Windows (looks like CI only builds for linux) to be sure.) |
Fixing Kerberos authentication due to missing APOption "MutualRequired"
Overview of the fix
In
client.InitSecContext(...)
I have changed the
client.InitSecContext(...)
prototype from:to:
to be able to pass specific flags through the
APOptions []int
to the call tospnego.NewKRB5TokenAPREQ(client.Client, tkt, ekey, gssapiFlags, APOptions)
In
client.GSSAPIBind(...)
I have left this function as it was, so it can be used in the generic case of GSSAPI authentication without the need to pass specific AP Options flags in parameters.
In
client.GSSAPIBindRequest(...)
I have changed the
client.GSSAPIBindRequest(...)
prototype from:to
Example of a working code for Kerberos authentication
Summary
These
APOptions []int
can now be set when callingclient.GSSAPIBindRequest(...)
, which will then pass it to the underlyingclient.InitSecContext(...)
, which will then be processed in the call tospnego.NewKRB5TokenAPREQ(client.Client, tkt, ekey, gssapiFlags, APOptions)
Best Regards,