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")
Related
I'm manually creating an OTP authenticator using django. I have created a class which creates an otp and sends it to the user by email. I've not written the code to send email. I'll complete it by send_email() inbuilt function. Please look after the code in views.py, I would like to use another function to verify the otp. But once I create the same object in the second function it reinitializes the variable.
def register(request):
""" Other stuffs like password matching goes here """
""" This will be provoked first in production """
g=globals()
g["user" + str(request.POST['username'])] = OTPclass()
g["user" + str(request.POST['username'])].send_otp()
def verify(request):
""" This method will be provoked once the user enters the OTP received in the email """
g=globals()
g["user" + str(request.POST["username"])] = OTPclass()
#In this part the value reinitializes to 0, but I must get the otp which was sent to the user
if(int(request.POST['otp']) == g["user" + str(request.POST["username"])].the_otp):
return redirect(login)
else:
print(g["user" + str(request.POST["username"])].the_otp)
return HttpResponse("<html><body><h2>OTP mismatch</h2></body></html>")
class OTPclass:
the_otp = 0
def send_otp(self):
self.the_otp = random.randint(1000,9999)
""" send_email() will be used here to send the otp to the user """
Kindly suggest a way to get the value which was sent to the user in verify(). Globally declaring a variable in views.py leads to overwriting the value when multiple users access the function.
I'm not into django, but i was facing the same problem with Flask.
You could use sessions to save data from one request to another.
https://docs.djangoproject.com/en/3.2/topics/http/sessions/
# set password:
request.session['one_time_password'] = 'secret'
# check password:
if request.session.get('one_time_password', False):
if request.session['one_time_password'] == provided_password:
# login
this might be one solution.
another idea is to memorize the OTP in the Class. (If you dont want to use an database)
OTP = OTPclass()
def register(request):
""" Other stuffs like password matching goes here """
""" This will be provoked first in production """
OTP.send_otp("user" + str(request.POST['username']))
def verify(request):
""" This method will be provoked once the user enters the OTP received in the email """
if(OTP.check_otp("user" + str(request.POST["username"]),int(request.POST['otp']):
return redirect(login)
else:
return HttpResponse("<html><body><h2>OTP mismatch</h2></body></html>")
class OTPclass:
memo = {}
def send_otp(self, user):
self.memo[user] = random.randint(1000,9999)
""" send_email() will be used here to send the otp to the user """
def check_otp(self,user, password):
if user in memo and memo[user] == password:
return True
else:
return False
keep in mind, that this sollution only works with one thread/process.
I've scoured stackoverflow and tried several different solutions, but my test code always goes to the login redirect.
This is what I have:
class LoggedInSetup(TestCase):
def setUp(self):
self.client = Client()
self.user = User.objects.create(username="lolwutboi", password="whatisthepassword")
self.client.login(username='lolwutboi', password='whatisthepassword')
number_of_submissions = 13
for sub in range(number_of_submissions):
Submission.objects.create(title='Amazing', description='This is the body of the post',
author=str(self.user), pub_date=timezone.now())
class LoggedInTestCases(LoggedInSetup):
def test_logged_in_post_reachable(self):
self.client.login(username='lolwutboi', password='whatisthepassword')
resp = self.client.get(reverse('submission_post'))
self.assertEqual(resp.status_code, 200)
You can't set the password like that - the password stored in the database is a hashed value and you are setting it to the password string itself. This means the validation will fail.
You would need to set the password like so:
self.user = User.objects.create(username="lolwutboi")
self.user.set_password("whatisthepassword")
self.user.save()
However, since all you really need is to log in the test user, use force_login in the test:
self.client.force_login(self.user)
Which will log in the user without you having to worry about passwords.
i don't want to use django default user table so i created a user table with username and hashed password. I hashed the password with make_password() when posting to database but when i tried retrieving information from the database using the same method to hash user input password, i get a different hash for same password. below is the view code for saving the user and retrieving the details.
view.py
class HMUser(APIView):
def post(self, request):
request.data['password'] = make_password(request.data['password'])
print(request.data['password'])
serialize = serializers.HMUserSerializer(data=request.data)
if serialize.is_valid():
serialize.save()
return Response(1, status=status.HTTP_201_CREATED)
return Response(serialize.errors,
status=status.HTTP_400_BAD_REQUEST)
class Login(APIView):
def get(self, request, username, password):
print("pass ", password)
userpassword = make_password(password)
print("Hash", userpassword)
user_details = models.HMUser.objects.get(username=username,
password=userpassword)
serialize = serializers.HMUserSerializer(user_details)
return Response(serialize.data)
Mismatch of salt is your problem,
Salt is seed or random number which is used in addition to a password to make it more secure, Since there is no salt specified it generates random at runtime making new value each time for the same password.
Ideal way is to use check_password() which is much more friendly,
Workaround is to specify your own salt, something like make_password(salt='mySalt',password=realPassword)
You need to ensure that salt use while creating a password and verifying are same.
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
According to Flask's documentation:
user_loader(callback):
This sets the callback for reloading a user from the session. The function you set should take a user ID (a unicode) and return a user object, or None if the user does not exist.
From where is this funciton supposed to load the User object? User data is stored in the session, but that isn't a user object, its just a JSON blob of info about the user. Without storing user objects in some global dictionary or something, I have no idea how this function is supposed to take a user_id and return the associate user except by creating a new user with that id, and mapping all previous data to it.
I should mention that I am not using a database (and even if I were the same problem would present itself--databases can't store user objects, they just store data about users) because I am using authentication credentials stored in an LDAP server.
Here is some code:
class User(object):
def __init__(self, user_id, password, active=True, authenticated=False, anonymous=False):
self.user_id = user_id.upper()
self.password = password
self.active = active
self.authenticated = authenticated
self.anonymous = anonymous
def is_active(self):
return self.active
def is_anonymous(self):
return self.anonymous
def is_active(self):
return self.active
def is_authenticated(self):
return self.authenticated
def get_id(self):
return self.user_id
and my view function:
#mod.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm(request.form)
if request.method == 'POST' and form.validate():
user_id = form.user_id.data
password = form.password.data
user = User(user_id=user_id, password=password)
conn = get_ldap_connection(user.user_id, user.password)
if conn:
login_user(user)
user.authenticated = True
next = request.args.get('next')
if next:
print("next: ", next)
return flask.abort(400)
return redirect('/mmt')
return render_template('auth/login.html', form=form)
Every example I can find of an implementation for the user_loader function makes use of SQLALchemy.session.add(user) but as I mentioned I'm not storing my users in a database... they already exist in a different database.
You don't store the user in the session, you store a unique value to identify the user. Then you use that id to load the user. In the case of a database, you would store the primary key of the user, then query by that key. You can do the exact same thing with LDAP: store some unique value in the session, then load from LDAP based on that value.
The user just has to be an object that inherits from flask_login.UserMixin (or implements everything it does, which your example code doesn't, the _is attributes should be properties). So you'd load the record from LDAP and pass that data to your User class to create a user.
In your login view, create a user object based on the record you load from LDAP, and call login_user(user) with it. Flask-Login calls the user object's get_id method to store a unique value in the login cookie. On subsequent requests, Flask-Login calls user_loader to load the user based on the value in the cookie; this function would perform an LDAP query and create a user, similar to the login view. The user object you return from user_loader is stored in current_user for the duration of the request.