Django: How do I use is_active of auth_user table? - python

I don't know what it is good time to use the param.
djangoproject it describes below:
Boolean. Designates whether this user account should be considered active. We recommend that you set this flag to False instead of deleting accounts; that way, if your applications have any foreign keys to users, the foreign keys won’t break.
This doesn’t necessarily control whether or not the user can log in. Authentication backends aren’t required to check for the is_active flag, and the default backends do not. If you want to reject a login based on is_active being False, it’s up to you to check that in your own login view or a custom authentication backend. However, the AuthenticationForm used by the login() view (which is the default) does perform this check, as do the permission-checking methods such as has_perm() and the authentication in the Django admin. All of those functions/methods will return False for inactive users.
readthedocs it describes below:
Authorization for inactive users
An inactive user is a one that is authenticated but has its attribute is_active set to False. However this does not mean they are not authorized to do anything. For example they are allowed to activate their account.
The support for anonymous users in the permission system allows for a scenario where anonymous users have permissions to do something while inactive authenticated users do not.
Do not forget to test for the is_active attribute of the user in your own backend permission methods.
Anyone can give some example that let me know the param needs to notice or how to use it.

from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None: #to check whether user is available or not?
# the password verified for the user
if user.is_active:
print("User is valid, active and authenticated")
else:
print("The password is valid, but the account has been disabled!")
else:
# the authentication system was unable to verify the username and password
print("The username and password were incorrect.")
This will be helpful for you to understand django authentication.

An inactive user is one that has its is_active field set to False.
As of django version 1.10: The ModelBackend (the default authentication backend) and RemoteUserBackend authentication backend prohibits these inactive users from authenticating. So, if you use those backends you won't need to use the following style:
#authentication has been successful now...
if user.is_active:
login(request,user)
#redirect to success page
else:
#return disabled account error message
If a custom user model doesn’t have an is_active field, all users will be allowed to authenticate.
Previous to version 1.10 ModelBackend allowed inactive users to authenticate- this was useful first where you allowed the user to authenticate and then you allowed a user to activate their account (only after they had successfully authenticated).
Please note that the #login_required decorator does not check for the is_active flag on the user. #login_required
check AUTHENTICATION_BACKENDS to see which ones you are using.
see https://docs.djangoproject.com/en/1.10/topics/auth/customizing/

def MyFormView(request):
if request.method == 'POST':
m_form = myform(request.POST)
a_form = AccountForm(request.POST)
if m_form.is_valid() and a_form.is_valid():
user = m_form.save()
user.is_active = True
a_form.instance.user = user
a_form.save()
messages.success(request,f'Your Account Has Been created')
return redirect('/')
else:
m_form = myform()
a_form = AccountForm()
return render(request, 'app/index.html', {'m_form':m_form, 'a_form':a_form})

Related

Django PasswordResetView does not work for inactive users

I have a simple django app where users can create and login to their accounts.
When a user is registering for a new account, the user object is created and saved in the database with the is_active flag set to false. Once the user clicks the confirmation email, the user object has its is_active flag set to true.
I have built out a password reset flow using Django's views: PasswordResetView, PasswordResetDoneView, PasswordResetConfirmView, and PasswordResetCompleteView.
Everything works as expected unless I am trying to reset the password for an account which has not yet been activated (is_active == False), in which case, the reset password email is never sent to the user.
The edge case I am considering here is for a user who created an account, and never clicked the registration link which expires after 72 hours, and thus have a user account which exists but is not active. Then the user wants to get a new registration link, and to do so I require a user to enter their username and password (so that no malicious actors can spam a random users email inbox with new registration link emails). If the user has since forgotten their password, they are bricked and cannot activate their account, nor can they refresh their password.
How can I send a password reset link to accounts which are not active?
I was able to solve this by creating my own child of Django's PasswordResetForm and overriding the get_users method which checks if a user is_active.
class ResetPasswordForm(PasswordResetForm):
# Override the get_users method and delete the requirement that a user is_active
# This is to account for the edge case where a user registered an account
# but never accepted the registration email, then they also forget their
# password, we need to be able to send a password reset link for a non active
# user.
def get_users(self, email):
"""Given an email, return matching user(s) who should receive a reset.
This allows subclasses to more easily customize the default policies
that prevent inactive users and users with unusable passwords from
resetting their password.
"""
email_field_name = UserModel.get_email_field_name()
active_users = UserModel._default_manager.filter(**{
'%s__iexact' % email_field_name: email
})
return (
u for u in active_users
if u.has_usable_password() and
_unicode_ci_compare(email, getattr(u, email_field_name))
)
The is_active requirement was originally introduced to Djangos PasswordResetForm here.
have you tried to use django-allauth?
I think it solves this.
Django AllAuth - How to manually send a reset-password email?

Multiple Password DJANGO

I am creating an app that authenticates with users for AD, but then it also needs separate passwords to authenticate for two other services. Is there a way to use 3 passwords to verify login? I can set up log in verification individually for each service, but I was wondering if I could store all three passwords in the same session. Reason being is because users will need to authenticate with multiple services to use all functions of this app.
here is roughly what I am doing in my view.py
request.session['pass_kinit2030'] = password
request.session['reg_pass'] = reg_pass
request.session['oraclepass'] = oraclepass
I can see several options:
If all your 3 passwords are equal, I suppose you just define your own AUTHENTICATION_BACKEND in Django. In such backend you would just take the password and check if it's valid in all three services.
In yourapp/auth.py:
from django.contrib.auth.backends import BaseBackend
class MyAuthBackend(BaseBackend):
def authenticate(self, request, username=None, password=None):
# Check reg and oracle - if valid, return request.user, else return None
In settings.py:
AUTHENTICATION_BACKENDS = ['yourapp.auth.MyAuthBackend']
But since you said separate passwords, I suppose they are not equal.
In case passwords are not equal, it is questionable to ask for 2 other passwords in this single app, in the first place. You shouldn't ask the user for 2 other passwords in the login form. Normally, you should authenticate your other two apps using some kind of token. You then connect your apps with such token in a different view than login view. Having such token, you should keep its value in a new model that has OneToOneField relationship to the user:
from django.conf import settings
from django.db import models
class UserTokens(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
reg_token = forms.CharField(
null=True,
max_length=100)
oracle_token = models.CharField(
null=True,
max_length=100)
You might as well use a password as a token, as long as the password is generated in a similar way to a token (and cannot be changed to a value given by the user - I know such cases).
Last but not least, you may not like the idea of tokens or may not have them implemented in related two apps. Then the question is, how these two apps are accessed? Are they HTTP servers? If yes, you are all set. The browser should keep the login session to two other apps separately. And, still you can redirect to these apps / iframe them or do JavaScript GETs or POSTs, if we talk about API of some kind - yes JS requests will use the login session.
I ended up using multiple try/except methods to testing the logging in on the other other services.
try:
try:
a = add_user().login(username=creds['user'], password=creds['banpass'])
add_user().logout(a)
except:
messages.error(request, 'Banner Password Is Incorrect')
return redirect('login')
if Usermanager(creds=creds).test_login():
pass
else:
messages.error(request, 'Wrong Regular Account Credentials')
return redirect('login')
if user is not None:
auth.login(request, user)
return redirect('userinfo')
else:
messages.error(request, 'Wrong AdminCredentials')
return redirect('login')

How to make a login view for django custom user?

I have made a custom user model using the AbstractUser , removed the username and replaced it with email and extended the model, tried creating superuser and it worked and also created some users by a signup form , logged in the admin interface and it worked however when tried to create a login form for the users it fails
I tried this but it didn't work
def LoginView(request):
if request.method == 'POST':
form = AuthenticationForm(data=request.POST)
if form.is_valid():
user = form.get_user()
login(request,user)
return redirect('accounts:login')
else:
form = AuthenticationForm()
return render(request,'accounts/login.html', {'form':form})
then i tried this
class LoginView(FormView):
form_class = AuthenticationForm
template_name = 'login.html'
def form_valid(self, form):
email = form.cleaned_data['email']
password = form.cleaned_data['password']
user = authenticate(email=email, password=password)
# Check here if the user is an admin
if user is not None and user.is_active:
login(self.request, user)
return HttpResponseRedirect(self.success_url)
else:
return self.form_invalid(form)
Obviously i expect the user to be logged in
i think the code in this post is badly formatted. mainly it's my fault as i'm new to this platform
I've developed almost the same setup that you're describing (I didn't remove the username field, just stopped using it). If you haven't already seen it, Django's documentation at https://docs.djangoproject.com/en/2.2/topics/auth/customizing/#substituting-a-custom-user-model is quite helpful.
There are a couple of important things that need to be set up correctly for this to work.
The USERNAME_FIELD on your model should be set to the name of your email field.
The AUTH_USER_MODEL needs to point to your custom user model.
class MyUser(AbstractUser):
USERNAME_FIELD = 'email'
AUTH_USER_MODEL = 'customauth.MyUser'
Since you've removed the username field altogether you might need to subclass django.contrib.auth.forms.AuthenticationForm and django.contrib.auth.views.LoginView to avoid breaking things, but Django should handle a different authentication field quite well.
If you do wind up needing to subclass the view, https://ccbv.co.uk/projects/Django/2.2/django.contrib.auth.views/LoginView/ is a great place to look over all the methods to see what's going on.
Edit - On Subclassing and it's necessity
What I was saying about possibly needing to subclass certain things was influenced by https://docs.djangoproject.com/en/2.2/topics/auth/customizing/#writing-a-manager-for-a-custom-user-model. I wasn't sure if there were other parts of the authentication system that would need you to customize them because you removed the username field.
I've read through some of the source code for Django's authentication system. Here's the path that's being followed.
When the POST request is made to Django's authentication view the authentication form is validated. https://github.com/django/django/blob/2.2.2/django/contrib/auth/forms.py#L191
The authenticate function is called. This iterates through the backends set up and tries to authenticate on each of them. https://github.com/django/django/blob/2.2.2/django/contrib/auth/__init__.py#L62
Django's built-in authentication backend gets the user if it exists using the natural key. https://github.com/django/django/blob/2.2.2/django/contrib/auth/backends.py#L16
We can see in the base manager that the natural key used is the field named by USERNAME_FIELD. https://github.com/django/django/blob/2.2.2/django/contrib/auth/base_user.py#L43
If the form is valid, meaning that the user is authenticated properly, the user is then logged in. https://github.com/django/django/blob/2.2.2/django/contrib/auth/views.py#L88
My reaction is that it looks like Django should work out of the box for your use case. You shouldn't need to write a backend. Here's the extent of the code my gut says you should have to write.
from django.contrib.auth import views as auth_views
from django.shortcuts import resolve_url
class LoginView(auth_views.LoginView):
template_name = 'accounts/login.html'
def get_success_url(self):
return resolve_url('accounts:login')
I don't know if this could be of any use to somebody but I can confirm that Django can authenticate you well with its own Login view if you just replace the username with an email field on your custom user model (as long as you specify the USERNAME_FIELD on the custom user model and are indeed using it by declaring it in the settings).
As I was expecting this behavior I designed a custom HTML form with email/password inputs and used the same principles I would use with the original user model authentication. It was failing though and I understood it was because I wasn't adapting my form to the original Login view expectations or would have worked from the start.
Just make sure to remember that the form HTML input tag for the email address needs to have "type" set to "email" but "id" set to "id_username" and "name" to "username".
This means you can just replace username with an email field and authenticate normally. I did not even declare a Login view for my login form to work, the Django view automacally used from the core is just being called at /accounts/login and working on its own. I'm working on Django 3.2

Using the django authentication system

I want to login with handler.
I have a code use session but i want to use handler:
I have visit :
https://docs.djangoproject.com/en/1.11/topics/auth/default/
But i don't understand complete.
I want to log user (with username or email and password)
Do you have a code for example or project in stackoverflow or github or . . . ???
login the user is easy if you are using default user model from django.contrib.auth.models
from django.contrib.auth import authenticate, login
def user_login(request):
# check here that request.method is POST or not.
user = authenticate(username=request.POST.get('username'), password=request.POST.get('password'))
if user is not None:
login(request, user)
# send some http response here that login successful or redirect to some other page
else:
# return an error page saying that username password not correct
authenticate function will check for username and password in User table in the database if it founds a user matching query then it returns the user object else it will return None. You might not want to manage sessions as django already sets a cookie for every user that successfully logs in so if user has logged in once then he will not be required to enter password again.

Django Custom Backend Documentation Discrepancy

I am having difficulty understanding how Django's documentation has outlined the overriding of the authenticate method in contrib.auth.models.Users. According to the code below from here, wouldnt the authenticate method succeed if the method was passed a valid username and a valid hash that exists anywhere in the database regardless of whether it matches the password for the supplied primary key field (username, email, etc...) or not. Is there something that check_password is doing that I am not seeing like ensuring that the field that was passed alongside of the password is checked behind the scenes? Because this supplied example appears to have a flaw.
# From Django 1.10 Documentation
def authenticate(self, username=None, password=None):
login_valid = (settings.ADMIN_LOGIN == username)
pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
if login_valid and pwd_valid:
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
# Create a new user. There's no need to set a password
# because only the password from settings.py is checked.
user = User(username=username)
user.is_staff = True
user.is_superuser = True
user.save()
return user
return None
Thanks.
authenticate() function returns user for which you attach session using login()
Use authenticate() to verify a set of credentials. It takes
credentials as keyword arguments, username and password for the
default case, checks them against each authentication backend, and
returns a User object if the credentials are valid for a backend. If
the credentials aren’t valid for any backend or if a backend raises
PermissionDenied, it returns None.:
In case of the following authentication backend username and password are passed to it.
Password is compared with one set in Django settings and user object
is queried from database.
If user with that username does not exist backend creates new user.
This backend works even though from security aspect it is not best one :)

Categories