I am working on openedx(which runs on django) and the user will be redirected here from other site and i'm being given the hashed password from there.
Authenticate(username,password) excepts raw password like "dragon" not the hashed one,
So I need to use the authenticate() with the hashed password so that I can get the ".backend" attribute and move on with my life.
When I use login(request,user) without the authenticate method. this error appears:
request.session[BACKEND_SESSION_KEY] = user.backend
AttributeError: 'User' object has no attribute 'backend'
So I need to use the authenticate function to get that .backend attribute in my user object.
user = authenticate(username=username, password=password) is the format of the authenticate function,
the password here is a raw password like "abc", what I have is a hashed password (which is the way this "abc" password will be stored in db).
I am stuck now, is there a way to authenticate and login using hashed passwords in django?
You can create a custom authentication backend for django and override its authenticate and get_user method to authenticate using hashed password and username.
Since hashed password is just another modelfield with text in it, you can lookup for users with username and the hash pass value in db.
Something like this should work:
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
class HashedPasswordAuthBackend(ModelBackend):
def authenticate(self, username=None, password=None):
try:
return User.objects.get(username=username, password=password)
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
After that, Include the path of this auth backend in your project settings.
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'yourapp.backends.HashedPasswordAuthBackend',
]
Open edX uses the ratelimitbackend.backends.RateLimitModelBackend for authentication, as we can see in the settings. This backend requires the un-hashed password for authentication.
If you wish to authenticate a user based on its hashed password, you need to create a new authentication backend, as described in the django documentation.
I suggest you draw some inspiration from the Django ModelBackend, as implemented in django.contrib.auth.backends.
The error you see relative to the missing backend attribute is something that I have experienced before. In the impersonate_user view of FUN (an Open edX project) this is how we solve this problem (note the comment inside the source code of the view function):
user = get_object_or_404(User, username=username, is_superuser=False, is_active=True)
user.backend = None
login(request, user)
Related
In Django default user authentication is integrated through Username and Password. In my project profile page, I have an option to change Username. So, it is necessary to change my authentication system in back end and front end with email and password.
Using authentication backend i can change default authentication system through email and password in admin. Here is the code -
class EmailBackend(object):
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
user = UserModel.objects.get(email=username)
except UserModel.DoesNotExist:
return None
else:
if getattr(user, 'is_active', False) and user.check_password(password):
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
In settings.py -
AUTHENTICATION_BACKENDS = (
'apps.account.email-auth.EmailBackend',
)
I was wondering how could i do the authentication through in front end. Already, I prepared front login page through email and password.
But see form.errors and predict must be missing any front authentication like AUTHENTICATION_BACKENDS
Thank you very much for your help!
Actually answer is within the method -
def authenticate(self, username=None, password=None, **kwargs):
In front-end, naming the user input with email wouldn't be passed within the method then form errors show up with don't match credentials. So, simply taking input as username solves the trick.
There is a package django-allauth. It handles the authentication.
It allows using 'email' and 'password' or 'username' and 'password' for authentication. It includes forms and everything else needed.
Django-cookiecutter project template uses this package to handle authentication, so you can look there and use it as a sample.
I am using Django 1.9.
Base on the Django documentation:
" To log a user in, from a view, use login(). It takes an HttpRequest object and a User object. login() saves the user’s ID in the session, using Django’s session framework."
So how do I retrieve the information in that session.
For example: (this is also taken from the documentation)
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:
How do I retrieve the user information such as username or if possible the password out on the success page.
P.S
If you could also kinda explain the solution in layman term as possible
EDIT
I was playing around with the framework back then. So I was testing if it can be done.
You don't get it from the session.
The authentication middleware adds the current user to the request, as request.user.
(And you definitely do not ever retrieve or display the password.)
I know there is documentation for this question here https://docs.djangoproject.com/en/1.9/topics/auth/customizing/, however I need some clarification on my use case.
I basically have an api that I created. What this api does is submit user form data to an external url, and once submitted, the data is saved to that external urls database.
I can then get a specific user through another api call. The user is returned as an object. Now I am trying to log that user in on my end using the django.contrib.auth through my system but what I have isn't working.
Here is my process:
A. I added a custom authentication backend to my settings.py file
AUTHENTICATION_BACKENDS =(
'new_app.backends.SettingsBackend',
'django.contrib.auth.backends.ModelBackend',
)
B. In my new_app's backend file, I have the following code:
class SettingsBackend(object):
def authenticate(self, username=None, password=None):
if username and password:
user = api.get_user()
#add pk to user object to satisfy django error warning
user.pk = user.unique_field
return user
return None
def get_user(self, user_id):
try:
if self.user.pk == user_id:
return self.user
except:
return None
In a signin view, I am trying to log the user in using this:
def login_user(request, username, password):
from django.contrib import auth
if not username and password:
raise ValueError("Invalid username and password")
auth_user = auth.authenticate(username=username, password=password)
if auth_user is None:
raise ValueError("Invalid username and password")
auth.login(request, auth_user)
return auth_user
I get the error saying:
'api.get_user()' object has no attribute 'save'
The error is occuring on the auth.login(request, auth_user) line.
I think the reason is because the django.contrib.auth thinks my user object is a django model. So, the question is how should I tackle this to make it work given my scenario? Thanks for the time.
I'm not an expert at django subtleties (as it's been a while I left django for microframeworks).
That said, if I were you, what I'd do is to make sure that whatever api.get_user() is returning, implement whatever API django is expecting from that object, which means starting with an empty save() method on it.
But I'd also do standard django stuff, like #RA123 suggests in a comment, by setting AUTH_USER_MODEL up.
I was working with a legacy database where there was a table 'tbl_personaldetails', from where i ported data to custome user model.
In code to port data from tbl_personaldetails, i use user.set_password(password) which sets password as hash in user table.
Trouble is when i try to authenticate(username=username, password=password) where password and username are plain text, authenticate returns None (Even for superuser account from which i can login in admin section).
The code to login is as follows:
class LoginView(FormView):
form_class = LoginForm
template_name = 'account/login.html'
def get_success_url(self):
return reverse("userHomeAfterLogin")
def form_valid(self, form):
email = form.cleaned_data['email'].lower().strip()
password = form.cleaned_data['password']
user = authenticate(email=email, password=password)
if user:
login(self.request, user)
return redirect(self.get_success_url())
else:
try:
user = User.objects.get(email__iexact=email)
if not check_password(password, user.password):
form._errors['password'] = ErrorList([u'That is not the correct Password.'])
except User.DoesNotExist:
form._errors['email'] = ErrorList([u'This email is not registered with us.'])
context = self.get_context_data(form=form)
return self.render_to_response(context)
As of now it flows like this:
1.authenticate returns none, landing up in else part:
2. can retrieve the user with email and check_password is correct.
3. it renders the form w/o any error message
.
what is it that i am doing wrong, everything looks fine though
As far as I understand from the code snippet, you are using email as your username. With email address, Django's authenticate will never work. It expects username instead. See code below.
def authenticate(**credentials):
"""
If the given credentials are valid, return a User object.
"""
for backend in get_backends():
try:
user = backend.authenticate(**credentials)
except TypeError:
# This backend doesn't accept these credentials as arguments. Try the next one.
continue
if user is None:
continue
# Annotate the user object with the path of the backend.
user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__)
return user
In order to use email address as the username field, please refer to http://justcramer.com/2008/08/23/logging-in-with-email-addresses-in-django/.
Hope this helps.
Hay I was wondering if anyone knew a better way to do this.
def login_user(request):
username = request.POST.get('username')
password = request.POST.get('password')
user = User.objects.filter(username=username)
if user:
user = user[0]
if user.password == generate_password(password):
return HttpResponse("password fine")
else:
return HttpResponse("password incorrect")
else:
return HttpResponse("no user found by that username")
and the generate_password function is just
generate_password(string):
return hashlib.sha224(str(string)).hexdigest()
Any ideas would be great.
Thanks
Why don't use Django auth default views ?
the only amelioration i see is use get instead of filter (it will save you one line)
user = User.objects.get(username=username)
Looking at the level of control you want to have, you'll want to make use of the authenticate and maybe login functions in django.contrib.auth. These are the main functions for accessing authentication. I should stress that you really, really should use these instead of finding the user and checking the password hash manually. There are a number of reasons why:
they will make use of whatever authentication backend you or someone else in the future have installed
your version will be far less tested than Django's and is more likely to open security holes
it's quicker, shorter, more flexible and more readable
Django's auth app will probably change in the near future, sticking to authenticate will help you migrate to the new auth app when it gets written/committed/released
If you do want to rewrite the way a user is found and authenticated, write your own Authenticate backend, which will be used when you call authentication (even in someone else's app, like the admin). This is the only place you should rewrite authentication in Django.
The following examples are from the Django auth docs.
1. Checking a user's password:
from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
if user.is_active:
print "You provided a correct username and password!"
else:
print "Your account has been disabled!"
else:
print "Your username and password were incorrect."
2. Custom authentication backend:
Here is a backend that uses the same authenticate method as Django's, which you can find at django.contrib.auth.backends.ModelBackend:
from django.contrib.auth.models import User
class MyBackend:
def authenticate(self, username=None, password=None):
try:
user = User.objects.get(username=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
You should download django-registration and go through the code. It manages everything for you, including cleaning the code. Your original code will not handle empty submissions.
http://bitbucket.org/ubernostrum/django-registration/