-
Notifications
You must be signed in to change notification settings - Fork 177
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
Prevent invalid credentials: no missing server URL or username #62
Conversation
Signed-off-by: Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
credentials/error.go
Outdated
// was caused by not having a credentials server URL when | ||
// required. | ||
func IsCredentialsMissingServerURLMessage(err string) bool { | ||
return err == errCredentialsMissingServerURLMessage |
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.
Is there a use for this utility function?
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.
(and the other Is..Message
functions
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.
You're right, I forgot to add the error checks in the output logs from credentials store client.
Done in : b69480e
credentials/error.go
Outdated
// required. | ||
func IsCredentialsMissingUsernameMessage(err string) bool { | ||
return err == errCredentialsMissingUsernameMessage | ||
} |
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.
nit: missing newline at end of file
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.
done!
Signed-off-by: Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
Signed-off-by: Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
/cc @vdemeester 😇 |
Signed-off-by: Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
Are empty strings the only value that can trigger this issue? I know that the OS X keychain API returns the first "matching" credential, but I'm not sure whether "matching" means an exact match for all non-empty strings, or if prefix matching is done in some cases. |
client/client.go
Outdated
// isValidCredsMessage checks if 'msg' contains invalid credentials error message. | ||
// It returns whether the logs are free of invalid credentials errors and the error if it isn't. | ||
// error values can be errCredentialsMissingServerURL or errCredentialsMissingUsername. | ||
func isValidCredsMessage(msg string) (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.
Can we use a return code, or something similar, to convey this information? I really don't like the idea of baking an exact error string into the "protocol" here.
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.
That was being done before this PR.
You're totally right, I'd certainly prefer a return code too but this should go in another PR imho as I prefer not to alter anything that was here before and just add additional checks to fix the issue asap.
The helpers should use errors from credentials
package so I guess that makes sense in the meantime.
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 probably could just have this function only return an error
instead of (bool, error)
- I don't see a use-case for them not matching
@aaronlehmann Regarding your question, when trying to do get creds by the prefix of the stored credentials' |
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.
LGTM 🐯
client/client.go
Outdated
// isValidCredsMessage checks if 'msg' contains invalid credentials error message. | ||
// It returns whether the logs are free of invalid credentials errors and the error if it isn't. | ||
// error values can be errCredentialsMissingServerURL or errCredentialsMissingUsername. | ||
func isValidCredsMessage(msg string) (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 probably could just have this function only return an error
instead of (bool, error)
- I don't see a use-case for them not matching
cmd := program("store") | ||
|
||
buffer := new(bytes.Buffer) | ||
if err := json.NewEncoder(buffer).Encode(credentials); err != nil { | ||
if err := json.NewEncoder(buffer).Encode(creds); err != nil { | ||
return err | ||
} | ||
cmd.Input(buffer) | ||
|
||
out, err := cmd.Output() | ||
if err != nil { | ||
t := strings.TrimSpace(string(out)) |
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.
for a followup PR: it might be useful to combine the cmd.Output()
, strings.TrimSpace
, and isValidCredsMessage
parsing into a shared function that all of these exported functions can use.
The same functionality seems to be replicated across Get
, Store
, Erase
, etc.
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.
Indeed, added to my todo list :)
@@ -100,13 +120,17 @@ func Get(helper Helper, reader io.Reader, writer io.Writer) error { | |||
} | |||
|
|||
serverURL := strings.TrimSpace(buffer.String()) | |||
if len(serverURL) == 0 { |
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.
instead of this individual check, should we instead call resp.isValid()
after forming it below? That way we can also verify the username
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.
the Get
operation on a credentials store only needs a server URL, username is not needed, as the operation is the following:
- I have a repository
foobar.io
, get me the credentials for this repo so I can authenticate on it
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.
got it. But potentially, the username could create an invalid Credentials
struct in the code below right? I would prefer to validate so that any invalid Credentials
struct is rejected, in case the semantics of the Get
operation change.
This can be a followup since I acknowledge the importance of this fix and that this is not an issue at present - I can help with the PR.
Signed-off-by: Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
client/client.go
Outdated
return err | ||
} | ||
cmd.Input(buffer) | ||
|
||
out, err := cmd.Output() | ||
if err != nil { | ||
t := strings.TrimSpace(string(out)) | ||
|
||
if err := isValidCredsMessage(t); err != nil { | ||
return err |
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.
It the error is one of these "special cases", only the bare message is returned, whereas other errors will show "error storing credentials - err: ..."
Without that it may be less apparent in what stage the error occurred (storing or retrieving the credentials)
Is there a reason doing so? If we need to have access to the plain error message, perhaps we should consider using errors.Wrap()
?
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 was actually following the "CredentialsNotFound" error check behavior, a follow-up PR fixing this is ready.
I prefer to have it separately though and not modify existing code.
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.
Are you ok with an additional parameter on errCredentialsMissingUsername
and errCredentialsMissingServerURL
errors that would include the operation in the error message?
Signed-off-by: Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
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.
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.
still LGTM 👼
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.
Thanks for giving me enough context to review. :) Looks good to me!
I'm squashing and merging, this will go in 17.06. Thanks all for reviewing. |
We should not do operations on credential stores with invalid (empty) server URLs or usernames.
This causes credentials management issues in some platforms' helpers depending on the credentials management system implementation.
This needs to be merged ASAP as next
docker
version is probably released tomorrow (05/23) morning CET.Signed-off-by: Nassim 'Nass' Eddequiouaq eddequiouaq.nassim@gmail.com