I am having login forms in all static pages. I have enabled csrf middleware in my project. Now when the user submits the form from http static page i get the error,
csrf verification failed
Is there a way to ensure cross site validation, even when posted from non-scure to secure page?
I want to neither add scrf exempt decorator nor change the page to https.
This is my template:
<form action='{{login_url}}' method = 'post'>
{% csrf_token %}
<div class="searchbox login">
<input autocomplete="off" id="id_fakeusername" type="text" name="fakeusername" maxlength="100" value='Email' style="color: #727272" onfocus="$('#id_fakeusername').hide();$('#id_username').show();
$('#id_username').focus();" />
<input autocomplete="off" type='text' id="id_username" type="text" name="username" maxlength="100" style="display: none" value='' onblur="if ($('#id_username').attr('value') == '') {$('#id_username').hide();$('#id_fakeusername').show();}" />
</div>
<div class="searchbox login">
<input autocomplete="off" id="id_fakepassword" type="text" name="fakepassword" maxlength="50" style="color: #727272" value='Password' onfocus="$('#id_fakepassword').hide(); $('#id_password').show(); $('#id_password').focus();" />
<input autocomplete="off" type='password' id="id_password" name="password" type="text" style="display: none" value='' onblur="if ($('#id_password').attr('value') == '') {$('#id_password').hide();$('#id_fakepassword').show();}" />
</div>
{% block nativewin %}
<div class="loginbut"><input type="submit" border="0" title="Login" value="Login" /></div>
{% endblock nativewin %}
</form>
From the CsrfViewMiddleware code [1]:
# Suppose user visits http://example.com/
# An active network attacker (man-in-the-middle, MITM) sends a
# POST form that targets https://example.com/detonate-bomb/ and
# submits it via JavaScript.
#
# The attacker will need to provide a CSRF cookie and token, but
# that's no problem for a MITM and the session-independent
# nonce we're using. So the MITM can circumvent the CSRF
# protection. This is true for any HTTP connection, but anyone
# using HTTPS expects better! For this reason, for
# https://example.com/ we need additional protection that treats
# http://example.com/ as completely untrusted. Under HTTPS,
# Barth et al. found that the Referer header is missing for
# same-domain requests in only about 0.2% of cases or less, so
# we can use strict Referer checking.
So I think the answer to your question is 'no', using the built-in protection!
[1] https://github.com/django/django/blob/master/django/middleware/csrf.py#L118
Did you included the {{ csrf_token }} in your template?
<form action="/contact/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
Did you included a RequestContext in render_to_response?
from django.template import RequestContext
from django.shortcuts import render_to_response
return render_to_response('contact.html', {'form': form},
context_instance=RequestContext(request))
If it still not work, follow the steps as described in the docs.
Related
i almost finished my register form, but something went wrong and i totally don't know what. It is a little difficult to describe but i will try.
So, as you can see here is login form:
login.html
<h1>login page</h1>
<table>
<tr>return to register page<br> </tr>
<tr>return to home page </tr>
</table>
<br>
<div>
<form method="post">
{% csrf_token %}
<div>
<div><label>Login/Email </label><input type="text" name="login_name" placeholder="Login/Email"></div>
<div><label>Password </label><input type="password" name="login_password" placeholder="enter password"></div>
<div><input type="submit" value="Login"></div>
</div>
</form>
</div>
and here is register form:
register.html
<h1>Register page</h1>
<table>
<tr>return to login page <br></tr>
<tr>return to home page </tr>
</table>
<br>
<div>
<form method="POST">
{% csrf_token %}
<div>
<div><label>Name </label><input type="text" name="registerFrom_name" placeholder="Enter the name"></div>
<div><label>Surname </label><input type="text" name="registerFrom_surname" placeholder="Enter the surname"></div>
<div><label>Login/Email </label><input type="text" name="registerFrom_login" placeholder="Login/Email"></div>
<div><label>Password </label><input type="registerForm_password" name="registerFrom_password" placeholder="Enter password"></div>
<div><label>Email </label><input type="text" name="registerForm_email"></div>
<div><input type="submit" value="Register"> </div>
</div>
</form>
</div>
Bellow my own backend to handle froms:
view.html
# BACKEND
from django.shortcuts import render
from django.views import View
from . import ValidateUser, RegisterUser
# Create your views here.
CSRF_COOKIE_SECURE = True
class WebServiceView(View):
# INDEX - MAIN PAGE
def indexPage(self, request):
return render(request, "index.html")
def register(self, request):
res = RegisterUser.RegisterUser("user", "user", "login", "test", "emai#email")
res.createUser()
return render(request, "register.html")
def login(self, request):
print("Login function")
res = ValidateUser.ValidateUser('/config/dbConfig.ini', '127.0.0.1') # Connection to mysql database
formParametr = request.POST
print(formParametr)
login = formParametr['register_name']
password = formParametr['register_password']
res.checkUser(login, password.encode("utf8"))
return render(request, "login.html")
Problem rise when i first open register.html and then i will go to the login.html page. Django throw MultiValueDictKeyError at /shop/login.html. I completely don't understand why. As you can see, a key "name" has 'register_name' already. So what can cause problem ?
Below Full error:
'register_name'
Request Method: GET
Request URL: http://127.0.0.1:8000/shop/login.html
Django Version: 2.2.5
Exception Type: MultiValueDictKeyError
Exception Value:
'register_name'
Exception Location: /usr/local/lib/python3.7/dist-packages/django/utils/datastructures.py in __getitem__, line 80
Python Executable: /usr/bin/python3.7
Python Version: 3.7.4
Python Path:
['/home/reg3x/PycharmProjects/lovLevelMusic',
'/usr/lib/python37.zip',
'/usr/lib/python3.7',
'/usr/lib/python3.7/lib-dynload',
'/usr/local/lib/python3.7/dist-packages',
'/usr/lib/python3/dist-packages',
'/usr/lib/python3.7/dist-packages']
It's a KeyError. It's telling you that you don't have a key for register_name in your POST dictionary. And that's because you used login_name in the template.
Really, you should be using Django forms for this, which would a) take care of outputting the fields in the template with the correct names and b) ensure the data was valid and fully populated before you accessed it in the view.
(There are other things in your code that make me very concerned as well. Why have you got login and register methods within a view class? That's not how class-based views work. And why is your URL ending in .html? That's not how Django URLs work. And, most importantly, what is ValidateUser and RegisterUser? Why are you connecting to your database explicitly in each view? Why do you have those classes? That is not how you work with the database in Django. Why are you doing any of this?)
I tried to make some pages only visible when logged in.
I tried it with:
def backend(request):
if request.user.is_authenticated:
return render(request, 'web/backend-index.html')
else:
return redirect(reverse('web:login'))
and also with:
#login_required
def backend(request):
return render(request, 'web/backend-index.html')
The first code does not let me log in.
The second code does not let me log in but the url changes too:
http://127.0.0.1:8000/login/?next=/backend/
If I just render the view without checking if logged in, the login is working fine and I´ll be passed to the backend page.
The whole code is on github: https://github.com/psmaster1/BrainSystems/tree/master/smarthome/web
I don't get any error messages. It's just redirecting to the login page...
Your login form is incorrect - that's why you never actually authenticate. It was sending POST request to incorrect endpoint and it was not rendering actual form. This is how you can render fields manually
Change it to this:
<section class="login-form">
<div class="login-fields">
<h3>Login</h3>
<form method="POST">
{% csrf_token %}
<div class="form-group">
{{ login_form.username }}
<label for="{{ login_form.username.id_for_label }}" class="control-label">Username</label><i class="bar"></i>
{{ login_form.username.errors }}
</div>
<div class="form-group">
{{ login_form.password }}
<label for="{{ login_form.password.id_for_label }}" class="control-label">Passwort</label><i class="bar"></i>
{{ login_form.password.errors }}
</div>
<div class="button-container">
<input type="submit" class="button" value="Login" />
</div>
</form>
<p>Noch nicht Registriert?</p>
Registrieren
</div>
</section>
Already fixed it! The Problem was the action attribute in the form tag. It causes the troubles. Just removed it from the form tag and make a redirect in the login() method. Thanks guys! :)
I am trying to write a test to see if my login redirects to the correct page. At the moment I am using this code which isn't working:
class TestAuth(TestCase):
def setUp(self):
self.client = Client()
#classmethod
def setUpTestData(cls):
user_login = get_user_model().objects.create(username='admin', email='admin#test.co.uk', password='asdf1234')
cls.user_login = user_login
def test_login_redirect(self):
response = self.client.post(
reverse('udt:login'),
{
'username': 'admin',
'password': 'asdf1234'
}
)
self.assertRedirects(response, reverse('udt:table_list'))
where udt:login equates to '/udt/accounts/login/' and udt:table_list equates to '/udt/table/'.
The login functionality is Django's built-in login with a custom template. When I run the test I get the following error:
AssertionError: 200 != 302 : Response didn't redirect as expected: Response code was 200 (expected 302)
However, when I actually test the login functionality in the app I get this:
[2017/05/30 14:43:22] HTTP POST /udt/accounts/login/ 302 [0.13, 127.0.0.1:60127]
[2017/05/30 14:43:22] HTTP GET /udt/table/ 200 [0.15, 127.0.0.1:60127]
which to me seems like it is in fact redirecting correctly.
So, my question is what is wrong with my test that is causing the assertion error? I am pretty new to testing in Django so it could just be something that I am missing, but it seems like the test should be passing to me.
Any help with this would be much appreciated.
UPDATE
The login template looks like this (just took the standard Django login template and added some bootstrap class names to it):
{% load bootstrap3 %}
<form id="login-form" method="post" action="{% url 'udt:login' %}">
{% csrf_token %}
<table class="table">
<tr>
<td><label for="id_username">Username</label></td>
<td><input id="id_username" name="username" type="text" class="form-control"></td>
</tr>
<tr>
<td><label for="id_password">Password</label></td>
<td><input id="id_password" name="password" type="password" class="form-control"></td>
</tr>
</table>
{% if form.errors %}
<p class=" label label-danger">
Your username and password didn't match.
Please try again.
</p>
{% endif %}
<input type="submit" value="Login" class="btn btn-primary pull-right" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
url for login looks like so:
url(r'^login/$', auth_views.login, {'template_name': 'auth/login.html'}, name='login')
I am using Django v.1.11.1.
You are creating the user incorrectly. You should use create_user instead of create(), so that the password is correctly hashed.
#classmethod
def setUpTestData(cls):
user_login = get_user_model().objects.create_user(username='admin', email='admin#test.co.uk', password='asdf1234')
As an aside, you can remove your setUp method as it is unnecessary. Django's TestCase class takes care of setting up self.client for you.
One more thing - your URL pattern is fine for Django 1.11, but you could update it to use LoginView to be compatible with Django 2.1+:
url(r'^login/$', auth_views.LoginView.as_view(template_name= 'auth/login.html'), name='login'),
I would like to call a function which is in /inscription/views.py since all views (because it's for the login). And I need to pass the username and the password in parameters to log the user.
def login_user(request):
if request.method =='POST':
auth_form=AuthenticationForm(data=request.POST)
if auth_form.is_valid():
username = request.POST.get('username')
password = request.POST.get('password')
uti = authenticate(username = username,password = password)
if uti:
if uti.is_active:
login(request, uti)
return HttpResponseRedirect('/accueil')
else:
return HttpResponse("Your account is disabled.")
else:
return HttpResponse("Invalid login details supplied.")
else:
auth_form=AuthenticationForm()
return render_to_response('authentication.html',
{'auth_form': auth_form}, RequestContext(request))
def logout_user(request):
logout(request)
And In my base.html I would like to add something like :
<label class="form_login">pseudo : </label>
<input type="text" name="username" id="id_username" class="login_input">
<label class="form_login">mot de passe : </label>
<input type="text" name="password" id="id_password" class="login_input">
<input value="login" type="submit"/>
<button>logout</button>
If I understand your question correctly, what you need is to force the user to login if he is not already logged in before he can access your views. To do this, all you need to do is to decorate your views with login_required decorator
from django.contrib.auth.decorators import login_required
#login_required
def my_view(request):
...
From the docs:
login_required() does the following:
- If the user isn’t logged in, redirect to settings.LOGIN_URL, passing
the current absolute path in the query string. Example:
/accounts/login/?next=/polls/3/.
- If the user is logged in, execute the view normally. The view code is
free to assume the user is logged in.
Update:
From your comment, now I understand that you need to make a form in all pages for the user to login, or a logout link if he is already logged in. First you need to define your URLs for these views:
url(r'^login/$', 'inscription.views.login', name='auth_login'),
url(r'^logout/$', 'inscription.views.logout', name='auth_logout'),
And in your base.html:
{% if user.is_authenticated %}
Logout
{% else %}
<form method="post" action="{% url 'auth_login' %}">
{% csrf_token %}
<input type="text" name="username" id="id_username">
<input type="text" name="password" id="id_password">
<input type="submit" value="Log in" />
</form>
{% endif %}
As a side note, I highly recommend you to use one of these reusable apps for auth and registration. unless you have strange requirements.
http://django-registration-redux.readthedocs.org/en/latest/
http://django-allauth.readthedocs.org/en/latest/
The problem which you are facing is , that u want the login and logout to work from other pages also, So, for this you need not to go for any extra function. All you need to do is, u just extend your base.html to all other html pages. Then you will surely be able to login and logout from all the pages.
Suppose you have login/logout in base.html
<label class="form_login">pseudo :</label>
<input type="text" name="username" id="id_username" class="login_input">
<label class="form_login">mot de passe : </label>
<input type="text" name="password" id="id_password" class="login_input">
<input value="login" type="submit"/>
<button>logout</button>
Now make some other html say test.html
There at the beginning you write
{% extends 'base.html' %}
followed by your HTML markup.
Don't forget to use
{% block content %} {% endblock %} **template tags**
In base as well as other HTML pages.
In other pages u try to write the complete code in template tags.
For query https://docs.djangoproject.com/en/1.7/topics/templates/
Also try using the concept of decorator.
My login works fine except for not showing all errors. When i type an invalid username or password, these errors don't show and the page just refreshes without putting any errors down.
However when i leave one field blank, it shows the correct error:
So the missing errors are(from source):
error_messages = {
'invalid_login': _("Please enter a correct %(username)s and password. "
"Note that both fields may be case-sensitive."),
'inactive': _("This account is inactive."),
}
my code:
def login_user(request):
"""Logs a user into the application."""
auth_form = AuthenticationForm(None, request.POST or None)
# The form itself handles authentication and checking to make sure password and such are supplied.
if auth_form.is_valid():
(request, auth_form.get_user())
return HttpResponseRedirect(reverse('index'))
return render(request, 'login.html', {'auth_form': auth_form})
My template:
<form action="{% url 'login_user' %}" method="post" class="login">{% csrf_token %}
<div>
<input name="username" placeholder="Username:" type="text" name="username" value="" id="username" class="login">
{{ auth_form.username.errors }}
</div>
<div>
<input name="password" placeholder="Password:" type="password" name="password" value="" id="password" class="login">
{{ auth_form.password.errors }}
</div>
<div>
<center>
<a href="{% url 'register_user' %}">
register
</a>
<button type="submit" class="link">
login
</button>
</center>
</div>
</form>
what do i do wrong?
You aren't including form.non_field_errors in your template. See the docs on customizing the form template for an example.
As an aside, the AuthenticationForm takes the request as its first argument. It looks slightly strange that you are passing None instead of request.