Django force password expiration - django

Are there any django apps for force expiring the password of the user after certain interval like 30 days? I am using djangp's auth and want to extend it or use a community app.
What I have tried so far:
Added a field to user profile for storing the date of last password updated.
Extended the login method to check for this date and redirect the user to password change page.
What I am confused about:
To block the user accessing the site till the password is changed.
User should not be able to login or just type urls to access the page directly.
Please note that I don't want to use middleware as it will be a resource constraint.

You seem on the right track. Set the date of the last password updated, check if the timedelta is greater than 30 days, if so redirect to the change password page. Your Login view should essentially stay the same except don't actually login the user to the request object if the timedelta is greater than 30 days.
from datetime import date, timedelta
from django.contrib.auth import authenticate, login
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
if date.today() - user.password_date > timedelta(days=30):
# Redirect to password change page
else:
login(request, user)
# Redirect to a success page.
else:
# Return a 'disabled account' error message
else:
# Return an 'invalid login' error message.

Well, there is django-passwords-policies-iplweb, https://github.com/iplweb/django-password-policies-iplweb, which is a friendly maitained fork of http://tarak.github.io/django-password-policies/ , which is currently not maintained.

Related

How do I create a Login System in Django Using Sessions?

I am trying to create a website which is authenticated by a custom login. But I have a custom Model for users. How do I authenticate my Website from anonymous Users. Is it possible to create login systems using based on sessions. Actually this is my first django project. Please Guide me. Thank you.
While login, after checking username and password create a session in which set their user object or it's object id in it. In this case i kept user id.
def login(request):
if request.method == "GET":
if (Users.objects.filter(username = request.GET.get("uname"), password = request.GET.get("upswd"))).exists():
user = Users.objects.get(username = request.GET.get("uname"), password = request.GET.get("upswd"))
request.session["user"] = user.id
# request.session.set_expiry(10)
# it shows home page
return render(request,"home.html")
#it shows again login page
return render(request,"Login.html")
only in login page you will set session, In remaining you will check whether page contains that session or not.For example, in after login in home page you should check whether request contains user session or not.
if request.session.has_key("user"):
userid = request.session["user"]
#displaying all items in database
context={"items":Products.objects.all()}
return render(request,"home.html",context)
It is better to use a POST form instead of a GET request as against the answer above. Also, instead of querying for username and password against your database, use authenticate() function.
from django.contrib.auth import authenticate, login
if request.POST:
if login_form.is_valid():
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user:
login(request, user)
# do something or redirect
You don't need to set the user id in the session object, to retrieve the currently logged in user, use request.user

Django: How to delete token after it is used?

In Django, I am generating tokens for account activation. Here is the actual code:
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': default_token_generator.make_token(user),
For instance:
http://localhost:8000/reset/MjQ/4uf-785b6e83f11ac22b6943/
In the above url MjQ is uid and 4uf-785b6e83f11ac22b6943 is token.
The account activation code goes like this:
def activate_account(request, uidb64, token):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = get_user_model().objects.get(pk=uid)
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if (user is not None and default_token_generator.check_token(user, token)):
user.is_active = True
user.save()
messages.add_message(request, messages.INFO, 'Account activated. Please login.')
return redirect('login')
The problem is once it is used it is still valid. However, Django password reset mechanism (password_reset_confirm() view) somehow invalidates the token after it is used. How can I do the same?
The token is not stored. It is a hash value based on:
the user's password
the user's last login date
Thus when Django's password reset confirm actually changes the password, the token hash is automatically invalidated.
If you want to manually invalidate the hash, you can do so by either:
generate and store a random password for that user (this may not be
what you want if you to retain the user's previous password):
password = User.objects.make_random_password()
user.set_password(password)
or reset the user's last login date to the current timestamp
from django.utils import timezone
user.last_login = timezone.now()
Why taking care of deleting stuff? It is much better to use something what expires automatically after some time.
See django.core.signing.TimestampSigner
https://docs.djangoproject.com/en/2.0/topics/signing/#verifying-timestamped-values
for nice how-to see this page I will only extend it by wrapping the generated key in base64.urlsafe_b64encode(...) and then before unsigning base64.urlsafe_b64decode(...)

Requesting user-only page without context

I have a login webpage which authenticates the user correctly. When login page accepts user info and sends them to a default logged in page, django correctly gets user info and populates the page accordingly.
Also, when sent to login page from another django's webpage, or when logged in as a user, django will automatically redirect to a default page correctly.
However, after I just logged in as a standard user, entering login page by entering 127.0.0.1:8000/login/ in browser's addressbar or when linked to this page,
request.user.is_authenticated() will always return False.
Why is this happening? How come this isn't happening when logged in as superuser?
EDIT:
Here's the code in views.py:
if request.user.is_authenticated():
#redirect to logged in page
if request.method == "POST":
email = request.POST.get("email_input")
password = request.POST.get("password_input")
users = UserProfile.objects.all() # FIXME: Inefficient GET request
for user in users:
if user.user.email == email and check_password(password, user.user.password):
login(request, authenticate(username=email, password=password))
#go to logged in page
return render(request, "login/login.html", {"error_message": "Invalid email/password combination. Please retry",
"email": email})
return render(request, "login/login.html")
That's a funny implementation. I would suggest you use what's stated in the documentation instead:
from django.contrib.auth import authenticate, login
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
# Redirect to a success page.
else:
# Return a 'disabled account' error message
else:
# Return an 'invalid login' error message.

Django- how to use built-in login view with email instead of username?

I am using built-in login in my app. There is some custom backends or packages to handle this. but many of them are not what i am looking.
i made email unique via django-registration while registering. now all i want is to ask email in login page instead of username.
but if i use some custom backends like django email as username it crashes when using with django-registration.
i dont want to change all authentication backend , i just want to change login page.
in the rest of site , i am gonna use username. p.e in my custom admin page when i write:
welcome {{user}}
it must render username. not e-mail.
i need to find the way out from this. i am stuck.
thank you.
By default django.contrib.auth.urls will create a log in page from this pattern
(r'^login/$', 'django.contrib.auth.views.login'),
You need to avoid/override this url then create a new view to handle a new type of login.
e.g.
create a new login url in your urls.py
(r'^emaillogin/$', 'email_login_view'),
create view to support login with email in views.py
# get default authenticate backend
from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User
# create a function to resolve email to username
def get_user(email):
try:
return User.objects.get(email=email.lower())
except User.DoesNotExist:
return None
# create a view that authenticate user with email
def email_login_view(request):
email = request.POST['email']
password = request.POST['password']
username = get_user(email)
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
# Redirect to a success page.
else:
# Return a 'disabled account' error message
else:
# Return an 'invalid login' error message.
Ref : https://docs.djangoproject.com/en/1.4/topics/auth/#django.contrib.auth.login
The above approach does not work anymore on django 1.9. A different approach might be to override the auth form used in the view as:
class EmailLoginForm(AuthenticationForm):
def clean(self):
try:
self.cleaned_data["username"] = get_user_model().objects.get(email=self.data["username"])
except ObjectDoesNotExist:
self.cleaned_data["username"] = "a_username_that_do_not_exists_anywhere_in_the_site"
return super(EmailLoginForm, self).clean()
Then when defining the login url, define as this:
url(r'^login/$', django.contrib.auth.views.login, name="login", kwargs={"authentication_form": EmailLoginForm}),
url(r'^', include('django.contrib.auth.urls')),
The best thing about the above approach you are not really touching anything in the auth process. It's not really a "clean" solution but it's a quick workaround. As you define the login path before including auth.urls, it will be evaluated instead of the base login form

Django, Redirecting staff from login to the admin site

So my site basically has 2 kinds of ways to login, one of them is for the common users, who get the regular screen that asks them for username and password, the other way its for staff.
The staff login should redirect them to the admin site after logging in, but for some reason the redirect doesnt happen, it stays on the same login page.
I use this condition on the login view.
if user is not None and user.is_active and user.is_staff:
auth.login(request,user)
return HttpResponseRedirect("/admin/")
The admin site its up and running in my url configuration and everything, but i dont know if this is the correct way to redirect to the admin site already on session.
Thanks, any help would be appreciated.
When a user logs in, login() will automatically redirect the user skipping the following line in your code:
return HttpResponseRedirect("/admin/")
Two possibilities:
If REDIRECT_FIELD_NAME (aka 'next') exists in your REQUEST fields, then the user is redirected to it right away.
If REDIRECT_FIELD_NAME is not found, then the user is redirected to LOGIN_REDIRECT_URL which you may have defined in your settings.py & if not, then it redirects to the default value for LOGIN_REDIRECT_URL.
So, it seems that your code doesn't set REDIRECT_FIELD_NAME, so naturally all users will end up being redirected to the path of LOGIN_REDIRECT_URL whatever that may be.
To solve this, set request.REQUEST['next'] = '/admin/' when you know the user is staff.
Then the redirect will happen automatically.
One way of logging in the the users and redirecting them according to their status could be:
from django.shortcuts import redirect
from django.contrib.auth import authenticate, login
def user_login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user.is_active:
# Redirecting to the required login according to user status.
if user.is_superuser or user.is_staff:
login(request, user)
return redirect('/admin/') # or your url name
else:
login(request, user)
return redirect('/')