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鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Network errors during pwnedpasswords.com check causing recursive loop #589
Conversation
The old code no error when ignoreNetworkErrors was set to true, but did not set a hash result which caused an infinite loop. This fixes #316.
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.
Good job!
if s.ignoreNetworkErrors { | ||
return nil | ||
} | ||
return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to check if password has been breached before: %s", err)) | ||
return s.ignoreNetworkErrors, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to check if password has been breached before: %s", 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.
Nice! Typically you would use the error as a value in "idiomatic" Go to avoid the mix of two return types. While the correctness of the code is obvious, it's just more "Go-style" to write it like this:
var ErrNetworkFailure = errors.new("unexpected network error")
// func () fetch() error {
// ...
if err != nil {
s.log().WithError(err).Errorf("Unable to check if password has been breached before")
return ErrNetworkFailure
}
// ...
if shouldIgnore, err := s.fetch(hpw); err != nil { | ||
if shouldIgnore { | ||
return nil | ||
} |
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 then you do this:
if shouldIgnore, err := s.fetch(hpw); err != nil { | |
if shouldIgnore { | |
return nil | |
} | |
if err := s.fetch(hpw); errors.Is(err, ErrNetworkFailure) { | |
return nil | |
} else if err != nil { | |
return err | |
} |
Thanks for the feedback! I was away on vacation so haven't seen this until now, but seems like you already fixed it so thank you 馃槃 |
No problem, I hope you had a good vacation and were able to regenerate :) |
Related issue
On network errors, the password validator ends up in a recursion loop until either the fault disappears - or more likely the stack overflows. Related to #316, @aeneasr .
Proposed changes
Change the validator code so that when
ignoreNetworkErrors = true
, a failure during the pwnedpasswords.com check returns no error, but the validation of the same password later would retry the online check.Added test cases that previously crashed or timed out the test suite (because of the loop), but they pass now. I also took the liberty to add a few more tests for the online password leak check.
Checklist
vulnerability. If this pull request addresses a security. vulnerability, I
confirm that I got green light (please contact
security@ory.sh) from the maintainers to push
the changes.
works.
Further comments
I implemented a
FakeHTTPClient
to use for these tests and feel like it should really live somewhere else to potentially be reused, but I couldn't find a good home for it. The internal/testhelpers package doesn't work as it causes an import cycle, any suggestions?This is also the first Go test I've written, so happy with any feedback if something is not perfect 馃檪