-
Notifications
You must be signed in to change notification settings - Fork 286
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
Add score based password verification #2557
Add score based password verification #2557
Conversation
57023ae
to
ac2175e
Compare
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 security improvement around the passwords.
@willyborankin Would you mind creating a separate issue to discuss making these options the default? I think this would be a good security posture improvement and would want contributors / community members to have a chance to weight in without delaying the functionality getting merged.
A quick note on performance - looking at the documentation [link] there is a typically small impact of ~5-20ms
I think this is a worthwhile tradeoff as password scoring only happens when passwords are set/updated.
src/main/java/org/opensearch/security/dlic/rest/api/AccountApiAction.java
Outdated
Show resolved
Hide resolved
src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java
Outdated
Show resolved
Hide resolved
src/main/java/org/opensearch/security/dlic/rest/validation/AccountValidator.java
Outdated
Show resolved
Hide resolved
src/main/java/org/opensearch/security/dlic/rest/validation/CredentialsValidator.java
Outdated
Show resolved
Hide resolved
src/main/java/org/opensearch/security/dlic/rest/validation/InternalUsersValidator.java
Outdated
Show resolved
Hide resolved
src/main/java/org/opensearch/security/dlic/rest/validation/CredentialsValidator.java
Outdated
Show resolved
Hide resolved
src/main/java/org/opensearch/security/dlic/rest/validation/CredentialsValidator.java
Outdated
Show resolved
Hide resolved
src/main/java/org/opensearch/security/dlic/rest/validation/CredentialsValidator.java
Outdated
Show resolved
Hide resolved
src/main/java/org/opensearch/security/dlic/rest/validation/CredentialsValidator.java
Outdated
Show resolved
Hide resolved
src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java
Outdated
Show resolved
Hide resolved
Sure, I will prepare an issue to discuss and address your comments. I will try to do it today,. |
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 work @willyborankin ! This is of great value to security posture!
One generic comment is to add a brief documentation on the new files. This would help in debugging in future.
final boolean isDebugEnabled = log.isDebugEnabled(); | ||
|
||
final String username = Utils.coalesce(request.param("name"), hasParams() ? (String) param[0] : null); | ||
if (!Strings.isNullOrEmpty(regex) || useScoreBasedValidation) { |
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 you add a brief comment here stating what this condition does?
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 changed code so there is no such condition anymore
log.debug("Username must not match password"); | ||
} | ||
this.errorType = ErrorType.INVALID_PASSWORD; | ||
return false; | ||
} | ||
} | ||
if (!Strings.isNullOrEmpty(regex)) { | ||
return regexBasedPasswordValidation(regex, password); | ||
} else if (useScoreBasedValidation) { |
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.
why either or here? Why not have both?
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.
Changed it
} | ||
final Strength strength = new Zxcvbn().measure(password, ImmutableList.of(username)); | ||
if (strength.getScore() < scoreStrength.score()) { | ||
this.errorType = ErrorType.INVALID_PASSWORD; |
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.
What do you think about changing the errorType to say WEAK_PASSWORD
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.
I added WEAK_PASSWORD
an SIMILAR_PASSWORD
error types
src/main/java/org/opensearch/security/dlic/rest/validation/CredentialsValidator.java
Outdated
Show resolved
Hide resolved
final boolean similar = strength.getSequence() | ||
.stream() | ||
.filter(m -> m.matchedWord != null) | ||
.anyMatch(m -> m.matchedWord.equals("similar")); |
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
src/main/java/org/opensearch/security/support/PasswordValidationScoreStrength.java
Outdated
Show resolved
Hide resolved
|
||
addUserWithPassword("ok4", "$1aAAAAAAAAC", HttpStatus.SC_OK); | ||
|
||
//its not allowed to use the username as password (case insensitive) |
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.
What is the behavior when username and password is only 1 or 2 letters off? Will the password be allowed as valid?
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 this case the score == 0 which means a weak password
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 work @willyborankin! This is definitely a huge enhancement for current password mechanism. I also left some thoughts attach to the previous comments with some details about the human understandable wording and some of the validation conditions.
src/main/java/org/opensearch/security/dlic/rest/validation/CredentialsValidator.java
Outdated
Show resolved
Hide resolved
src/main/java/org/opensearch/security/support/PasswordValidationScoreStrength.java
Outdated
Show resolved
Hide resolved
src/main/java/org/opensearch/security/dlic/rest/validation/CredentialsValidator.java
Outdated
Show resolved
Hide resolved
@peternied, @DarshitChanpura and @RyanL1997 thank you for the feedback I will address all you comments asap. As @peternied suggested I created a feature request #2569 and tried to explain how the library works and how to improve existing password verification functionality in it. So lets move our discussion there. |
ac2175e
to
2d21b17
Compare
2d21b17
to
c3c13ec
Compare
src/main/java/org/opensearch/security/dlic/rest/validation/PasswordValidator.java
Show resolved
Hide resolved
src/main/java/org/opensearch/security/support/ConfigConstants.java
Outdated
Show resolved
Hide resolved
src/main/java/org/opensearch/security/dlic/rest/validation/PasswordValidator.java
Outdated
Show resolved
Hide resolved
src/main/java/org/opensearch/security/dlic/rest/validation/PasswordValidator.java
Show resolved
Hide resolved
src/main/java/org/opensearch/security/dlic/rest/validation/PasswordValidator.java
Show resolved
Hide resolved
src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java
Outdated
Show resolved
Hide resolved
src/main/java/org/opensearch/security/dlic/rest/validation/CredentialsValidator.java
Outdated
Show resolved
Hide resolved
c3c13ec
to
1c2e47e
Compare
Codecov Report
@@ Coverage Diff @@
## main #2557 +/- ##
============================================
+ Coverage 61.31% 61.34% +0.03%
+ Complexity 3408 3347 -61
============================================
Files 272 261 -11
Lines 18846 18591 -255
Branches 3295 3277 -18
============================================
- Hits 11555 11405 -150
+ Misses 5690 5592 -98
+ Partials 1601 1594 -7
|
c2b2065
to
a156c99
Compare
|
||
private static final int MAX_LENGTH = 100; | ||
private final static Predicate<Match> USERNAME_SIMILARITY_CHECK = m -> | ||
m.pattern == com.nulabinc.zxcvbn.Pattern.Dictionary && m.dictionaryName.equals("user_inputs"); |
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 my understanding why the pattern check against hard code string "user_inputs"?
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.
user_inputs
the default dictionary which library creates automatically to check similarity. I will add a comment otherwise it is confusing. So all you need is just check the dictionary name since matchedWord
is a password.
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.
okay..thank yoU!
import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_PASSWORD_SCORE_BASED_VALIDATION_STRENGTH; | ||
import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_PASSWORD_VALIDATION_REGEX; | ||
|
||
public class PasswordValidatorTest { |
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.
nicely done! 👏
a156c99
to
92c82bf
Compare
|
||
ErrorType validate(final String username, final String password) { | ||
if (minPasswordLength > 0 && password.length() < minPasswordLength) { | ||
logger.debug( |
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.
These seems like well written error messages seem valuable, could we return this messages instead to be visible to the user. If we did that, we could remove the password_validation_error_message (and related) value that is in the config. What do you think?
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.
Well I would prefer to stay it as is. The main reason, that some companies prefer to send the same error message when a user creates/updates the password (kinda less possibilities for attackers to know what is the password creation rules :-) which I personally do not believe in since if somebody wanna hack the system it will do 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.
Still a couple of outstanding comments, but I'm happy with the change as is. Thanks for the great new feature @willyborankin !
Hi @willyborankin, thanks for all the follow-ups! My comments have been resolved, and I'm happy to merge this change if we resolve the branch conflicts. |
b6ba386
to
7411d38
Compare
Signed-off-by: Andrey Pleskach <ples@aiven.io>
7411d38
to
df5109a
Compare
@peternied, @scrawfor99, @RyanL1997 and @DarshitChanpura all tests now green |
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.
Thank you @willyborankin. This looks great.
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.
Thank you for another great contribution @willyborankin !
The backport to
To backport manually, run these commands in your terminal: # Fetch latest updates from GitHub
git fetch
# Create a new working tree
git worktree add .worktrees/backport-2.x 2.x
# Navigate to the new working tree
cd .worktrees/backport-2.x
# Create a new branch
git switch --create backport/backport-2557-to-2.x
# Cherry-pick the merged commit of this pull request and resolve the conflicts
git cherry-pick -x --mainline 1 15860b65f33861f875b62ed57b6d8b7ab3c8a65d
# Push it to GitHub
git push --set-upstream origin backport/backport-2557-to-2.x
# Go back to the original working tree
cd ../..
# Delete the working tree
git worktree remove .worktrees/backport-2.x Then, create a pull request where the |
Signed-off-by: Andrey Pleskach <ples@aiven.io>
Signed-off-by: Andrey Pleskach <ples@aiven.io> Signed-off-by: Maciej Mierzwa <dev.maciej.mierzwa@gmail.com>
Signed-off-by: Andrey Pleskach <ples@aiven.io> Signed-off-by: Maciej Mierzwa <dev.maciej.mierzwa@gmail.com>
Signed-off-by: Andrey Pleskach <ples@aiven.io>
Signed-off-by: Andrey Pleskach <ples@aiven.io> Signed-off-by: Sam <samuel.costa@eliatra.com>
Description
The aim of this PR is to add support for a score-based password verification using
zxcvbn
library.For that 2 new settings were added to the plugin configuration:
plugins.security.restapi.password_min_length
- minimum password length, default and minimum is8
plugins.security.restapi.password_score_based_validation_strength
- the strength of the valid passwordPossible values:
fair
- very guessable password: protection from throttled online attacksgood
- somewhat guessable password: protection from unthrottled online attacksstrong
- safely unguessable password: moderate protection from offline slow-hash scenariovery_strong
- very unguessable password: strong protection from offline slow-hash scenarioBy default the plugin always checks strength of the password and its minimal length together with the regular expression if its set.
The calculation time for passwords around
100
characters is~100ms
as result to avoid of performance degradation for big passwords I suggest to set max length of the password to100
.All other settings I mentioned before are not needed.
Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.