Multiple Password DJANGO - python

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')

Related

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

Django - Using multiple models for authentication

I am kind of new to django and I am concerned about can we use multiple models for authentication for different types of users for our application e.g for Customers use Customer model, for Suppliers use Supplier model and also keep default User registration model for administration use only? If so can you point me in the right direction, how it can be done? Which package should be used?
There is one way that I came around is by adding a foreign key to each model viz needed for authentication but that will involve joins in every query which could result in performance issues. I need to know if there is a better way. An also these custom models can benefit for all permissions stuff available in admin panel.
Expert opinion will be really appreciated.
There are a few different options to handle that.
Maybe check first the Django-docu.
I've you'ld like to customize it to authenticate your users with a mail-address, here is an example written by knbk and rahul-gupta on the ex-documentation:
Django's default authentication works on username and password fields. Email authentication backend will authenticate users based on email and password.
from django.contrib.auth import get_user_model
class EmailBackend(object):
"""
Custom Email Backend to perform authentication via email
"""
def authenticate(self, username=None, password=None):
user_model = get_user_model()
try:
user = user_model.objects.get(email=username)
if user.check_password(password): # check valid password
return user # return user to be authenticated
except user_model.DoesNotExist: # no matching user exists
return None
def get_user(self, user_id):
user_model = get_user_model()
try:
return user_model.objects.get(pk=user_id)
except user_model.DoesNotExist:
return None
Add this authentication backend to the AUTHENTICATION_BACKENDS setting.
# settings.py
AUTHENTICATION_BACKENDS = (
'my_app.backends.EmailBackend',
...
)

Django: How do I use is_active of auth_user table?

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})

How to update a user's `extra_data` after they have been associated with account?

I've successfully managed to use django-socialauth to associate an account (in this case, an instagram account) with an existing user account. I've also set up my pipeline to collect additional user details:
def update_social_auth(backend, details, response, social_user, uid, user,
*args, **kwargs):
if getattr(backend, 'name', None) in ('instagram', 'tumblr'):
social_user.extra_data['username'] = details.get('username')
social_user.save()
This works great when an account is associated for the first time. However, if the account has already been associated, the username field will not be present in extra_data.
How can I update a user's extra_data after the association has already been made? Is there a way using django-socialauth to do this without disconnecting and reconnecting, or using the account's (e.g Instagram's) API?
If it helps, this is my pipeline at the moment:
SOCIAL_AUTH_PIPELINE = (
'social_auth.backends.pipeline.social.social_auth_user',
'social_auth.backends.pipeline.social.associate_user',
'social_auth.backends.pipeline.social.load_extra_data',
'social_auth.backends.pipeline.user.update_user_details',
'apps.utils.social.utils.update_social_auth'
)
Here is a snippet of code I use to add 'admin' and 'staff' options to an existing Django user; I don't know about django-socialauth or the extra_data field, but I'm guessing something like this might be applicable:
:
userqueryset = User.objects.filter(username=user_name)
if not userqueryset:
print("User %s does not exist"%user_name, file=sys.stderr)
return am_errors.AM_USERNOTEXISTS
# Have all the details - now update the user in the Django user database
# see:
# https://docs.djangoproject.com/en/1.7/ref/contrib/auth/#django.contrib.auth.models.User
# https://docs.djangoproject.c om/en/1.7/ref/contrib/auth/#manager-methods
user = userqueryset[0]
user.is_staff = True
user.is_superuser = True
user.save()
:
FWIW, my app is using 3rd party authentication (specifically atm OpenId Connect via Google+), so I think there's some common goal here. In my case I want to be able to add Django admin privileges to a user that has already been created.
The full module containing the above code is at github.com/gklyne/annalist/blob/develop/src/annalist_root/annalist_manager/am_createuser.py#L231

Django, How authenticate user with first name and last name?

i want to authenticate users using firstname and lastname
This is the code i am using
user = auth.authenticate(first_name=firstname,last_name=lastname,password=password)
it keep coming up with NoneType: None
i have checked the firstname and lastname plus password seen to be correct?
what i am doing wrong? thanks
The difficulty here is that normally you'd handle this by creating a custom authentication backend that implements authenticate and get_user. However, the function signature for authenticate is:
def authenticate(self, username=None, password=None):
Everywhere in Django that would be calling this will be passing only 2 parameters, username and password. This means that using any of the generic authentication forms and things like the admin interface will break if this is done any other way.
The only work around I could see, and this is kind of sketchy, is if the username were to be typed as a single entry with a string "First Last" (delimited by a space) in place of the username. You could then separate it out and use that value...
(this is all untested, but you get the idea)
class FirstLastNameBackend(object):
def authenticate(self, username=None, password=None):
first, last = username.split(' ', 1)
try:
user = User.objects.get(first_name=first, last_name=last)
if user:
# Check if the password is correct
# check if the user is active
# etc., etc.
return user
except:
pass
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except:
return None
The django doc provides a lot of helpful details on doing a custom backend: User auth with custom backend
On a side note, something to be careful of is last names that have a space(s) in them, like "de la Cruz". If you specify 1 for maxsplit on the split function, you'll avoid this problem.
Building a little from #T. Stone's idea. Why not have them register with their First and Last name and you just concatenate them together and use that as their username?. And everytime you have them login you setup your view to combine the two fields again and use that string.
You won't be able to use some of the auto forms they can produce for you but that's not a big deal. I'd just combine the two strings, lowercase them and slap that as the username and do the same for every login instance.
You can use any parameters in backend authentication function, i.e.:
class FirstLastNameBackend(object):
def authenticate(self, first_name=None, last_name=None, password=None):
pass #your user auth code goes here
In order to authenticate user you call
user = auth.authenticate(first_name=firstname,
last_name=lastname,
password=password)
One drawback, however, that you'll need to implement your own log in form and this authentication won't be supported in admin interface.
I like the idea of not making users remember a username, but I think a better solution to that is to have their email address be their user name. Is it fair for you to assume in your specific application that no two users will have the same first and last name? If that's not a fair assumption, how will your system handle that?

Categories