Problem with custom authentication backend - python

I am trying to make a custom authentication for my django project.I am using a custom user model by subclassing AbstractUser. Now after creating a superuser account and trying to login from admin page, i am getting the error Please enter the correct username and password for a staff account. Note that both fields may be case-sensitive..I've double checked that my username and password are right.
After doing some research, found out that something is wrong with the custom authentication backend i am making.
from support.models import CustomUser
class UsernameIdModelBackend(object):
def authenticate(self,username,password,uid):
if username:
try:
user = CustomUser.objects.get(username=username)
if user.check_password(password):
return user
except CustomUser.DoesNotExist:
return None
else:
try:
user= CustomUser.objects.get(uid=uid)
return user
except CustomUser.DoesNotExist:
return None
def get_user(self, user_id):
try:
return CustomUser.objects.get(pk=user_id)
except CustomUser.DoesNotExist:
return None
Ive also set AUTHENTICATION_BACKENDS in settings.py. What should be changed to correct this.Can someone please point me the right way.
PS. iam new to custom authentication and is looking forward to create one with 2 types of login.

Rather than doing it like this, you can just add Authentication Backend for login with uid, like this(as per documentation):
class UsernameIdModelBackend(object):
def authenticate(self, request, uid=None):
try:
user= CustomUser.objects.get(uid=uid)
return user
except CustomUser.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
And add it to AUTHENTICATION_BACKENDS like this:
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'your_path_to.backend.UsernameIdModelBackend',
)

Related

Custom User Model, Custom Authentication not working

I am a beginner in Django and I am working on a project which requires Custom user model as I Don't require is_staff, is_superuser, is_admin.
So, but searching and other ways I made my own Custom user model. But it is not working and I am stuck on it for days.
It will be a huge help if someone can help me with the code.
settings.py
AUTH_USER_MODEL = 'accounts.Usermanagement'
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'accounts.backends.EmailAuthBackend',
]
backends.py
#backends.py
# from django.contrib.auth.models import User
from django.contrib.auth.hashers import check_password
from django.contrib.auth import get_user_model
Usermanagement = get_user_model()
class EmailAuthBackend:
def authenticate(self,request,username=None,password=None):
print(request)
try:
user = Usermanagement.objects.get(emailid=username)
print(password)
print(user.password)
# print(check_password(password))
# print(user.check_password(password))
if user.check_password(password):
return user
return None
except user.DoesNotExist:
return None
def get_user(self,user_id):
try:
return user.objects.get(pk=user_id)
except user.DoesNotExist:
return None
views.py
# views.py
def loginPage(request):
# POST
if request.method == 'POST':
form = AuthenticationForm(request,data=request.POST)
# loginPage.html the html tag has attribute name = username for email ,
# name = password for password
if form.is_valid(): # Form Valid
email = request.POST['username']
password = request.POST['password']
#Check
print("EMAIL: ",email)
print("PASSWORD: ",password)
# Authentication USER
user = authenticate(request,username=email,password=password)
print("Authenticated ",user) # Check
# check
print(user)
if user is not None: # If User found
login(request,user,backend='accounts.backends.EmailAuthBackend')
messages.info(request, f"You are now logged in as {email}.")
return redirect("home")
else: # If User Not found
messages.error(request,"User not found")
return HttpResponse("User not found, not able to login")
else: # Form InValid
messages.error(request,"Invalid username or password.")
return HttpResponse("Form Invalid")
# GET
else:
form = AuthenticationForm()
context = {"form":form}
return render(request,"loginPage.html",context=context)
urls.py and other configurations are correct.
Problems:
check_password : always False
In DB I have unencrypted password ( ex:- password=admin )
DB is a legacy(existing) DB , so I first made the DB and then I did "python manage.py inspectdb" , which created models for me and then I changed few things, but did not changed the field names or the db_table name.
I am very much ok to create user through SHELL.
In loginPage.html the html tag has attribute name = username for email , name = password for password
if any other requirements I will edit the Questions
i think you cannot use the check_password function in your case, because it has been created for encrypted password case. Just make a user.password == password in your EmailAuthBackend
For second problem with get_user(), I think your userId is not the primary key for Django maybe, problem probably can be solved by filter directly by userId:
def get_user(self, user_id):
try:
return user.objects.get(userId=user_id)
except User.DoesNotExist:
return None
Concerning the problem No.2
Remove the password=password in your user=self.model()
It's making it difficult to make reference to the password in your user.set_password()

django allauth - get() returned more than one User -- it returned 2! in production

I'm trying to add google auth service to my site, it is working correctly in localhost, but in the server, I've got an error when a new user tries to sign up although the old users can connect their account to google account without any problems
get() returned more than one User -- it returned 2!
there is no duplicated either in the user model or social account
model.
before I added social auth users could only log in or sign in with their email addresses, so now my AUTHENTICATION_BACKENDS is like that:
AUTHENTICATION_BACKENDS = (
'user_profile.backends.EmailBackend',
'allauth.account.auth_backends.AuthenticationBackend',)
and my EmailBackend file in like this:
class EmailBackend(ModelBackend):
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
user = UserModel.objects.get(email=username.lower())
except UserModel.DoesNotExist:
return None
else:
if user.check_password(password):
return user
return None
class MySocialAccountAdapter(DefaultSocialAccountAdapter):
def pre_social_login(self, request, sociallogin):
user = sociallogin.user
if user.id:
return
try:
customer = User.objects.get(email=user.email) # if user exists, connect the account to the existing account and login
sociallogin.state['process'] = 'connect'
perform_login(request, customer, 'none')
except User.DoesNotExist:
pass
and in my settings.py:
SOCIALACCOUNT_ADAPTER = 'user_profile.backends.MySocialAccountAdapter'
thanks a lot, it has been a disaster

Django 2 model 1 authentication system

In my project, I should create personal type user and company type user they have different attributes. I can create them with different models but I cannot implement both in auth system at the same time? I wonder if it is possible?
As stated in django docs you can write your own AUTHENTICATION_BACKENDS.
For example:
class UserProfileModelBackend(ModelBackend):
def authenticate(self, username=None, password=None):
try:
user = self.user_class.objects.get(username=username)
if user.check_password(password):
return user
except self.user_class.DoesNotExist:
return None
def get_user(self, user_id):
try:
return self.user_class.objects.get(pk=user_id)
except self.user_class.DoesNotExist:
return None
#property
def user_class(self):
if not hasattr(self, '_user_class'):
self._user_class = apps.get_model(*settings.AUTH_USER_MODEL.split('.', 2))
if not self._user_class:
raise ImproperlyConfigured('Could not get custom user model')
return self._user_class
And then add this auth-backend to in AUTHENTICATION_BACKENDS in settings.py.
For more information see Writing an authentication backend
When somebody calls django.contrib.auth.authenticate() Django tries authenticating across all of its authentication backends. If the first authentication method fails, Django tries the second one, and so on, until all backends have been attempted.
Be careful:
The order of AUTHENTICATION_BACKENDS matters, so if the same username and password is valid in multiple backends, Django will stop processing at the first positive match.

How do I send 401 error codes instead of 403 with a custom permission class?

I'm using a custom authentication scheme and I cannot figure out how to get it to send 401 HTTP responses instead of 403. The guide at http://www.django-rest-framework.org/api-guide/authentication/#custom-authentication says to override the authenticate_header method, but this doesn't seem to do anything. The part that is sending the 403 is where the AuthenticationFailed exception is being raised. I assigned the OwnerCredentialsFound to a ModelViewSet via the permission_classes property.
from rest_framework import exceptions
from rest_framework import permissions
from django.contrib.auth.models import User
def authenticateUser(username, password):
try:
user = User.objects.get(username=username)
return user.check_password(password)
except:
return False
class OwnerCredentialsFound(permissions.IsAuthenticated):
def has_permission(self, request, view):
#Check credentials
#If the fields don't exist, the given default value is used
username = request.POST.get('username', None)
password = request.POST.get('password', None)
authenticated = authenticateUser(username, password)
if(not authenticated and username is not None and password is not None):
raise exceptions.AuthenticationFailed('Username/password pair not found')
elif(not authenticated):
authenticated = permissions.IsAuthenticated.has_permission(self, request, view)
else:
#set the user
view.request.user = User.objects.get(username=username)
return authenticated
def authenticate_header(self, request):
return '{"username" : <username>, "password" : <password>}'
UPDATE: It seems that I've confused the authentication and permission classes. I'm using a permission class, but it is the authentication class that has a method called authenticate_header.
Basically, I didn't really understand the difference between permissions and authentications, so that led to confusion. The permissions class has no authenticate_header method, but the authentication class does. Here is what I did to solve the problem:
from rest_framework import exceptions
from rest_framework import authentication
from django.contrib.auth.models import User
def authenticateUser(username, password):
try:
user = User.objects.get(username=username)
return user.check_password(password)
except:
return False
class CustomAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
username = request.POST.get('username', None)
password = request.POST.get('password', None)
authenticated = authenticateUser(username, password)
if(not authenticated and username is not None and password is not None):
#authentication attempted and failed
raise exceptions.AuthenticationFailed('Username/password pair not found')
elif(not authenticated):
#authentication not attempted (try other authentications)
return None
else:
#authentication attempted and suceeded
return (User.objects.get(username=username), None)
def authenticate_header(self, request):
return '{"username" : <username>, "password" : <password>}'
In my view:
permission_classes = (IsAuthenticated,)
authentication_classes = (CustomAuthentication, SessionAuthentication)
This confusion of permissions and authentication also explains why my attempt to combine multiple permission classes failed (you may note in my original code that I inherited from a permission class and called its has_permission method in order to get around this). I no longer need a custom permission class because I can just use two authentication classes.
Note that it is mandatory to implement:
def authenticate_header(self, request):
Otherwise you will also get a 403.
When You return False from has_permission, under the hood DRF raises PermissionDenied exception. Then the exception is caught and processed in a fuction named exception_hanlder like this:
elif isinstance(exc, PermissionDenied):
msg = _('Permission denied.')
data = {'detail': six.text_type(msg)}
set_rollback()
return Response(data, status=status.HTTP_403_FORBIDDEN)
It looks like You can define some custom Exception, throw it on error in OwnerCredentialsFound.has_permission and then use a custom exception handler to catch it Yourself. Please read more here:
http://www.django-rest-framework.org/api-guide/exceptions/#custom-exception-handling

Allowing inactive users to login via custom django backend

I have a custom auth backend that I'm playing with. I want to allow inactive users to log in. Setting the supports_inactive_user flag to true doesn't seem to do the trick, even though I can verify that the user is being returned.
class AuthenticationBackend(ModelBackend):
supports_object_permissions = False
supports_anonymous_user = True
supports_inactive_user = True
def authenticate(self, username=None, password=None):
"""
Allow login with email inplace of username
"""
user = None
if username is not None:
username = username.strip()
if email_re.search(username):
try:
user = User.objects.get(email__iexact=username)
except User.DoesNotExist:
pass
if not user:
try:
user = User.objects.get(username__iexact=username)
except User.DoesNotExist:
return None
if user.check_password(password):
return user
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
I'm using django 1.4. What am I missing?
Your user gets authenticated successfully, but it's the AuthenticationForm that raises a ValidationError when the user is inactive. You can override the clean method in a subclass to catch the corresponding ValidationError:
class InactiveAuthenticationForm(AuthenticationForm):
# a bit messy but it should work
def clean(self):
try:
return super(InactiveAuthenticationForm, self).clean()
except ValidationError as e:
if self.cached_user is not None: # user exists but is not active
# behavior that's skipped because of the validation error
self.check_for_test_cookie()
return self.cleaned_data
else:
raise e
However, consider that a user's is_active flag is a replacement for actually deleting the user. You might want to reconsider your use of is_active. If you want users to be able to login as soon as they've created an account, there are better ways to achieve that.

Categories