I am currently having difficulty customizing Djangos authentication system.
In my scenario there is no database and authentication happens through a http request. There are no tables to read from or write from.
This thread here deals pretty much with the same case I am dealing with however i do not understand how a user is being created in his example. I also read this from django manual regarding REMOTE_USER authentication.Coming back to the first link the user posted this code here.It consists of a backend and a user object
Backend - inherit from RemoteUserBackend
from django.contrib.auth.backends import RemoteUserBackend
class MyRemoteUserBackend (RemoteUserBackend):
# Create a User object if not already in the database?
create_unknown_user = False
def get_user (self, user_id):
user = somehow_create_an_instance_of (MyUser, user_id) ---->A
return user
def authenticate (self, **credentials):
check_credentials ()
user = somehow_create_an_instance_of (MyUser, credentials) ---->B
return user
Then the user:
from django.contrib.auth.models import User
class MyUser (User):
def save (self):
"""saving to DB disabled"""
pass
objects = None # we cannot really use this w/o local DB
username = "" # and all the other properties likewise.
# They're defined as model.CharField or similar,
# and we can't allow that
def get_group_permissions (self):
"""If you don't make your own permissions module,
the default also will use the DB. Throw it away"""
return [] # likewise with the other permission defs
def get_and_delete_messages (self):
"""Messages are stored in the DB. Darn!"""
return []
Now my question is I would like to do something like this in my view
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)
Now how can I have authenticate method from MyRemoteUserBackend be called in the above code snippet and what does the snippet mean by somehow_create_an_instance_of any suggestions on this would be great
Related
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)
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.
first excuse me for my english it isn't the best one.
I'm pretty new to django and python and i try to programm a user authentification.
I used the django documentation and everything works fine with these code below:
def anges(request):
username = []
password = []
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
render_to_response ('registration/login.html', {'username': username, 'password': password})
if user is not None:
if user.is_active:
login(request, user)
angestellte_list = Employee.objects.all().order_by('lastname')
return render_to_response(("emp/angestellte.html"), {'angestellte_list': angestellte_list})
else:
return HttpResponse('disabled account')
else:
return HttpResponse('invalid login')
else:
return render_to_response ('registration/login.html', {'username':username, 'password':password})
But this is just a function and i want to use this object oriented for my other functions in my views.py, because of DRY.
This is just a first test but it doesn't works because the debugger says:"global name 'request' is not defined"
That's my code:
class einloggen:
def __init__(self):
self.Username = request.POST['username']
def angestellte(self):
return HttpResponse("hello")
How can I use the request variable in classes or is there anything more to consider?
Quite obvious that you can't use the request variable in __init__ in the einloggen class, because, quite frankly, you don't send the request variable in to the constructor.
I can't see you making a einloggen object anywhere in your view either, but you should probably to something like:
class einloggen:
def __init__(self, request):
self.Username = request.POST.get('username')
and then in your view (where you've got the request variable):
def anges(request):
myobj = einloggen(request)
However, Django already has an authentication system. And you'd be much better off using that. You can use the beautiful decorators to make it really easy and nice to «protect» views.
I have this test case
def setUp(self):
self.user = User.objects.create(username="tauri", password='gaul')
def test_loginin_student_control_panel(self):
c = Client()
c.login(username="tauri", password="gaul")
response = c.get('/student/')
self.assertEqual(response.status_code, 200)
the view associated with the test case is this
#login_required
def student(request):
return render_to_response('student/controlpanel.html')
so my question is why the above test case redirects user to login
page? should not c.login suppose to take care authenticating user?
The problem is the way you create your User object.
Django does not store your password in plain text in the database, it stores its hash value. But in your code password is set in plain text.
So when you use c.login(...) internally Django will make a call to check_password method which will generate a hash value from the password you passed and will compare it to the password stored in the database and as a result will return False because 'gaul' from DB is not equal to get_hexdigest('gaul')
There are two options:
1) Use a User.objects.create_user method that will take care of password hashing:
def setUp(self):
self.user = User.objects.create_user(username='tauri',
password='gaul',
email='')
2) Or set a password with a set_password method:
def setUp(self):
self.user = user = User.objects.create(username='tauri')
user.set_password('gaul')
user.save()
Did you make sure to create the user entry in your setUp function?
User.objects.create_user(username="tauri", password="gual")