Skip to content
This repository was archived by the owner on Sep 26, 2018. It is now read-only.

password expiration policy - DO NOT MERGE - #36

Open
piyushabad88 wants to merge 8 commits into
facebookarchive:masterfrom
piyushabad88:sprint2_password_expiration_feature
Open

password expiration policy - DO NOT MERGE#36
piyushabad88 wants to merge 8 commits into
facebookarchive:masterfrom
piyushabad88:sprint2_password_expiration_feature

Conversation

@piyushabad88

Copy link
Copy Markdown
Contributor

Please review password expiration policy implementation which include the below features:

  • Password Expiry Status pop-up comes to change user password for last seven days from PASSWORD_EXPIRED_DAY i.e 90 days configured.
  • New password rule (min 8 character length,combination of alphanumeric and special character)
  • Block user If user does not change password for last 90 days.

@9muir 9muir left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good at a high level. Nice job breaking out into a much smaller PR.

Comment thread cloud/endagaweb/tasks.py

@app.task(bind=True)
def block_user(self):
""" Block User if User password is not updated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make the comment reflect the fact that the number of days is configured in a setting.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments incorporated in commit id 1703300.

Comment thread cloud/endagaweb/tasks.py Outdated
""" Block User if User password is not updated
for last 90 days
"""
six_month_ago = (django.utils.timezone.now() -

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

six_month_ago is not a good name for a variable that might not represent a date exactly six months ago.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments incorporated in commit id 1703300

Comment thread cloud/endagaweb/views/user.py Outdated
return JsonResponse({'permissions': list(role_permission)})
return HttpResponseBadRequest()

def validate_password_strength(value):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to have some unit tests to validate that this rejects 'weak' passwords, especially since the regex is kinda incomprehensible. It might be clearer if the code was structured as a conjunction of three simpler regex checks: one for a number, one for a letter, and one for a special character.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added test cases and made simpler regex checks for digit,alphabet,length and special character.
Updated in commit 1703300.

Comment thread cloud/endagaweb/views/user.py Outdated


@login_required(login_url='/login/')
def role_default_permissions(request):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this function is logically part of this PR

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, removed function.

Comment thread cloud/endagaweb/views/user.py Outdated
next_url = request.POST['next']
if (today - user_profile.last_pwd_update).days >= \
settings.ENDAGA['PASSSWORD_EXPIRED_LAST_SEVEN_DAYS']:
text = str(user) + ' , your account will be blocked in next '\

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

text should include words to the effect of '... unless you change your password.'

As a style point, I'd pretty much always use string formatting operator (%) rather than concatenating a bunch of strings.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments incorporated in commit id 1703300.

Comment thread cloud/endagaweb/models.py
# For example to get a list of networks the user can view:
# >>> get_objects_for_user(user_profile.user, 'view_network', klass=Network)
network = models.ForeignKey('Network', null=True, on_delete=models.SET_NULL)
network = models.ForeignKey('Network', null=True,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert this accidental change.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reverted.

@facebook-github-bot

Copy link
Copy Markdown

@aricent-ccm updated the pull request - view changes

@facebook-github-bot

Copy link
Copy Markdown

@aricent-ccm updated the pull request - view changes

@kkroo kkroo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Awesome test cases. Some small changes

@@ -153,6 +153,19 @@ def __init__(self, *args, **kwargs):

class ChangePasswordForm(PasswordChangeForm):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Built in validators here: https://docs.djangoproject.com/en/dev/topics/auth/passwords/#password-validation
Do you really need to override all of these fields to show a message? The validators should print their own policy text in a ValidationError on form submission.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks,yes ,As django have four default validators and they having their own policy text.
But as per our requirement we don't need UserAttributeSimilarityValidator,CommonPasswordValidator. so only NumericPasswordValidator and MinimumLengthValidator we could use.But NumericPasswordValidator only check numeric ,it doesn't check alphanumeric and they don't have validator check for special character.For that regexValidator need to use.
For all this , made custom validator custom_password_validators, which validated min_length,alphanumeric and special character. And our custom policy provided as help text.
Removed override of all those fields , added custom validators to display our policy and validate password strength.

commitId:1f9e597e4ffae62e4e54c4447c02bc4e7f3a1232
defaultdjangovalidator

</style>
<html lang="en">
<head>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use the same version of jquery across the project: 1.10.2

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments incorporated in commit id 1f9e597

if 'next' in request.POST and request.POST['next']:
next_url = request.POST['next']
return redirect(next_url)
if user.is_active:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to check user is not None first in the case authenticate returns None

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments incorporated in commit id 1f9e597

Comment thread cloud/endagaweb/views/user.py Outdated
return redirect("/dashboard/profile")
return HttpResponseBadRequest()

def validate_password_strength(password):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already built into Django. See my previous comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed and now validating fields in form itself.

Comment thread cloud/endagaweb/views/user.py Outdated
tags = 'password alert alert-danger'
messages.error(request, text, extra_tags=tags)
return redirect(redirect_url)
if request.POST['old_password'] == request.POST['new_password1']:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be doing this validation in the PasswordForm using the clean_new_password1 method. See this example: https://docs.djangoproject.com/en/1.8/_modules/django/contrib/auth/forms/#SetPasswordForm

Comment thread cloud/endagaweb/views/user.py Outdated
tags = 'password alert alert-danger'
messages.error(request, text, extra_tags=tags)
return redirect(redirect_url)
if not validate_password_strength(request.POST['new_password1']):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is builtin. See my comments

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added custom validators which validate in form itself

@facebook-github-bot

Copy link
Copy Markdown

@9muir has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@9muir 9muir left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what's going on with the 'for' loops in the HTML templates

</h4>
</div>
<div class='modal-body'>
{% for message in messages %}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really a loop? I assume we're only going to prompt a single user, the one that is logged in, to change their password.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks,yes, there is one message need to prompt.But as per django message framework, message it store in FallbackStorage is the default storage.As per its definition This class first uses CookieStorage for all messages, falling back to using SessionStorage for the messages that could not fit in a single cookie. Since it is uses SessionStorage, it also requires Django's contrib.sessions application.
so it seems need to iterate in for loop for displaying message in template.If we not iterate and directly shows messages, it show like
Hi <django.contrib.messages.storage.fallback. at 0x7f1b7cb75590> Please change your password.

<div class='modal-body'>
{% for message in messages %}
<p>
{% if message.text %} {% endif %} Hi {{ message }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what this {% if ... %} {% endif %} block is doing, it looks like nothing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not required ,removed

{% for message in messages %}
<p>
{% if message.text %} {% endif %} Hi {{ message }}
{% endfor %}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really weird place to put the {% endfor %}, but if you remove the 'for' construct it goes away anyway.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

require to close for loop added close

,please see above comments regarding messages.storage.fallback.

<h4>Change Password</h4>
{% crispy change_pass_form %}

{% for message in messages %}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another 'for' loop that I don't understand. If this really is a loop there should be a comment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we not give ,it's not show message.please see above comments regarding messages.storage.fallback.

@facebook-github-bot

Copy link
Copy Markdown

@aricent-ccm updated the pull request - view changes - changes since last import

@facebook-github-bot

Copy link
Copy Markdown

@aricent-ccm updated the pull request - view changes - changes since last import

@facebook-github-bot

Copy link
Copy Markdown

@aricent-ccm updated the pull request - view changes - changes since last import

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants