-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
feat: password complexity option on DB Auth #1687
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1687 +/- ##
==========================================
+ Coverage 76.43% 76.55% +0.12%
==========================================
Files 55 55
Lines 8032 8061 +29
==========================================
+ Hits 6139 6171 +32
+ Misses 1893 1890 -3
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
docs/security.rst
Outdated
- At least 3 Lowercase letters | ||
- At least 1 special character | ||
- At least 2 numeric digits | ||
- At least 10 total digits |
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 should be 'At least 10 total characters'.
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.
fixed, thks!
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, it has all the options I was looking for.
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 personal opinion + one minor improvement proposal
@@ -5,6 +5,7 @@ | |||
|
|||
from ..fieldwidgets import BS3PasswordFieldWidget, BS3TextFieldWidget | |||
from ..forms import DynamicForm | |||
from ..validators import PasswordComplexityValidator |
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.
Just an opinion, but while we're on the topic of improving typing/readability, I somehow always find fully qualified imports more pleasant to read:
from flask_appbuilder.validators import PasswordComplexityValidator
over
from ..validators import PasswordComplexityValidator
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.
Currently I prefer them also, but I'm following the current code base "convention", I plan to change them on a different PR
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.
Agree. Relative imports are evil.
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.
Coming as strong advise in Airflow 2.2: https://github.com/apache/airflow/blob/main/docs/apache-airflow/modules_management.rst#dont-use-relative-imports
flask_appbuilder/validators.py
Outdated
password_complexity_regex = re.compile( | ||
r"""( | ||
^(?=.*[A-Z].*[A-Z]) # at least two capital letters | ||
(?=.*[!@#$&*]) # at least one of these special characters |
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.
To not "force" users to use a highly restricted set of special characters, would it be better to do a negative match for non-special characters here? Something like
(?!([a-zA-Z0-9])).
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 point
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
Oh cool. did not have time to follow up on this one. let me take a look. |
@@ -47,6 +47,13 @@ class BaseInterface(object): | |||
def __init__(self, obj: Type[Any]): | |||
self.obj = obj | |||
|
|||
def __getattr__(self, name: str) -> Any: |
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. I did not know about it !
from ..base import FABTestCase | ||
|
||
|
||
class PasswordComplexityTestCase(FABTestCase): |
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.
Suggestion: Maybe you could use https://pypi.org/project/parameterized/ 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.
And few other places.
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.
did not know that one, only this: https://docs.pytest.org/en/6.2.x/parametrize.html#pytest-mark-parametrize-parametrizing-test-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.
added, looks better and it encourages to write more test cases (which I did) :)
password_complexity_validator(field.data) | ||
except PasswordComplexityValidationError as exc: | ||
raise ValidationError(str(exc)) | ||
if current_app.config.get("FAB_PASSWORD_COMPLEXITY_ENABLED", False): |
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 think the current set of configuration variables is a bit confusing.
When I see FAB_PASSWORD_COMPLEXITY_ENABLED
- I think this parameter configures password complexity check in general, so I expect that if FAB_PASSWORD_COMPLEXITY_ENABLED
is "false" then no validation is done (even if I have my own custom validator configured in FAB_PASSWORD_COMPLEXITY_VALIDATOR
).
Currently, in order to enable ONLY custom validator you have to have effectively this combination:
FAB_PASSWORD_COMPLEXITY_ENABLED = false
FAB_PASSWORD_COMPLEXITY_VALIDATOR = your_validator
This is pretty confusing (because I'd expect FAB_PASSWORD_COMPLEXITY_ENABLED = false
disables validation of password completely.
I think two one of the two approaches would be better:
a) FAB_PASSWORD_COMPLEXITY_ENABLED
- enables validation in general, and FAB_PASSWORD_COMPLEXITY_VALIDATOR
replaces the default validator with the custom one. In this case you cannot run both custom and default validation at the same time
b) FAB_PASSWORD_COMPLEXITY_ENABLED
- should be renamed to FAB_PASSWORD_DEFAULT_COMPLEXITY_VALIDATOR
- to not make impression that whole feature is disabled by setting it to false
I have slight preference for option a) (I think it's better to always run one validator - either default or custom, you can always derive your custom validator from the default one and use it internally) - but I think both a) and b) are better than current proposal.
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.
Very good point, went for option a)
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.
Cool. Looks great now. Then I have one more NIT comment :)
Thanks for that @dpgaspar - I had some other pressing issues in the meantime, so I did not pick it up as promised, sorry for that. I hoe you find my comments useful |
No worries at all, I had this one on my TODO list also. Thank you for the review and yes the comments were great, looks much better now! |
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.
Small NIT after choosing option a)
password_complexity_validator(field.data) | ||
except PasswordComplexityValidationError as exc: | ||
raise ValidationError(str(exc)) | ||
if current_app.config.get("FAB_PASSWORD_COMPLEXITY_ENABLED", False): |
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.
Cool. Looks great now. Then I have one more NIT comment :)
Co-authored-by: Jarek Potiuk <jarek@potiuk.com>
Fantastic! |
🎉 🎉 🎉 🎉 🎉 |
Description
New feature to support password complexity validation to AUTH database users.
Adds the following new optional config keys:
This PR also adds partial mypy type checking and a small test refactor
ADDITIONAL INFORMATION