Verifying username and password input through flask python - python

My project requires I read and write input username and password to a text file (not db or json). From there when the user logs in, I need to verify that the username and password match. I have encrypted the password using sha256. Every time I attempt to login with a known username and password, it fails to find the user and flashes "Incorrect data. Please try again."
This is my Python Code:
#app.route('/LoginSuccess/', methods=['GET', 'POST'])
def login_success():
username = request.form.get("username")
password = request.form.get("password")
for line in open('users.txt', 'r').readlines():
login_info = line.split(',')
hashpass = login_info[2]
flash('Verifying inputs....')
if username == login_info[0]:
flash('Username correct')
if sha256_crypt.verify(password, hashpass):
flash('You are logged in!')
return render_template('index.html')
else:
flash('Incorrect data. Please try again.')
return render_template('login.html', username=username, password=password)
This is my HTML code:
{% extends "dashboard.html" %}
{% block body %}
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class="flashes">
{% for message in messages %}
<div class="message_flash">{{ message }}</div>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<h1>Login</h1>
<form action="/LoginSuccess/" method="POST">
<div>
<label for="username">Username</label>
<input type="text" class="form-control" name="username" placeholder="Username" required>
</div>
<div>
<label for="password">Password</label>
<input type="password" class="form-control" name="password" placeholder="Password" required>
</div>
<div class="submit">
<button type="submit" class="btn btn-default">Log In</button>
</div>
</form>
{% endblock %}

As #John Gordon commented, your code will render your login page (i.e. treat it as a failed login) if the first line (and only the first line) of your users.txt file does not match the credentials given. Instead you need to check the entire file before coming to that conclusion. So you need all of your iterations (through the users.txt file) to complete before executing the render login page if there were no matches. Basically, this means removing the else keyword and moving the last two lines of your code outside of the for block of code. e.g.
for line in open('users.txt', 'r').readlines():
login_info = line.split(',')
hashpass = login_info[2]
flash('Verifying inputs....')
if username == login_info[0]:
flash('Username correct')
if sha256_crypt.verify(password, hashpass):
flash('You are logged in!')
return render_template('index.html')
flash('Incorrect data. Please try again.')
return render_template('login.html', username=username, password=password)
These last two lines of code will only execute if the entire file has been read, and no correct user matches were found. (If a match was found however, then the user will be logged in before the for block runs out of iterations, and have been already taken to your index page.)
You will also want to add strip() to this line of code:
login_info = line.split(',')
like so:
login_info = line.strip().split(',')
otherwise you will get a newline character (in your hashpass variable) and your verification check may fail.

Related

How do I show an error message when I have an invalid log in?

I'm working on a web app right now and I don't know how to display an error message when the user types in an invalid log in name. How do I go about this?
this is my login.html
{% block body %}
<h1>Login</h1>
{% if error %}
<p>Invalid Username</p>
{% endif %}
<form method="POST" action="{{ url_for('login') }}">
<input type="text" name="username" placeholder="Your Username">
<input type="submit" value="Submit">
</form>
<a href='{{variable6}}'>Sign Up</a>
{% endblock %}
this is my app.py
#app.route("/login", methods=["GET", "POST"])
def login():
if flask.request.method == "GET":
return flask.render_template("login.html")
if flask.request.method == "POST":
username = flask.request.form["username"]
cursor.execute(
"SELECT user_name FROM public.users WHERE user_name = %s", [username]
)
results = cursor.fetchall()
if len(results) != 0: # if a user exists, "log" them in
return flask.redirect(flask.url_for("main"))
else:
return flask.render_template("login.html")
I believe that your problem is that you are not defining what the "error" variable is, you could fix this by when you are returning the render_template in the last line of app.py, adding error=True, leaving you with this as your last line for app.py.
return flask.render_template("login.html", error=True)
As otherwise Jinja (the templating language you used in login.html) would not know what error and would get the type None as the value of error in the {% if error %} statement in login.html and since None is not equal to true, it would skip over the code you want to run.
Hope this helps :)

Change password form not working in flask

I am trying to build a simple web app, which has a form to change one's password. I am using werkzeug.security functions (check_password_hash and generate_password_hash) to do so. This two functions work perfectly in during registering and logging in. But for some reason, when I change password, the password just doesn't match. I even wrote a code to check the password right away, passwordChange = check_password_hash(newHash, newPassword), then print(f'\n\n{passwordChange}\n\n')but for some reason it always returned false. Here is the full code. Any response is greatly appreciated :)
FLASK
#app.route("/passwordchange", methods=["GET", "POST"])
#login_required
def changepassword():
""""Change users' password"""
if request.method == "POST":
newPassword = request.form.get("newPassword")
newConfirmation = request.form.get("newConfirmation")
# Ensure that the user has inputted
if (not newPassword) or (not newConfirmation):
return apology("Please fill all of the provided fields!", 400)
# Check to see if password confirmation were the same or not
if newPassword != newConfirmation:
return apology("password did not match with password (again)", 400)
user_id = session["user_id"]
newHash = generate_password_hash("newPassword")
db.execute("UPDATE users SET hash = ? WHERE id = ?", newHash, user_id)
passwordChange = check_password_hash(newHash, newPassword)
print(f'\n\n{passwordChange}\n\n')
return redirect("/login")
else:
return render_template("password.html")
HTML
{% extends "layout.html" %}
{% block title %}
Change Password
{% endblock %}
{% block main %}
<form action="/passwordchange" method="post">
<div class="form-group">
<input class="form-control" name="newPassword" placeholder="New Password" type="password">
</div>
<div class="form-group">
<input class="form-control" name="newConfirmation" placeholder="New Password (again)" type="password">
</div>
<button class="btn btn-primary" type="submit">Change Password</button>
</form>
{% endblock %}

Issue with csrf_token while using Flask and WTForms

I'm trying to set up a basic "Contact" form for my website, which will basically take in values and then put them into a CSV file. The issue I'm having is that the entries cannot be validated cause they're missing a csrf_token?
Here's the relevant code from my app.py:
#app.route('/contact_end', methods=['POST'])
def handle_contact():
form = ContactForm()
print(form.name.data)
if form.validate_on_submit():
print("yup")
with open('data/messages.csv', 'a') as f:
print("oh shit")
writer = csv.writer(f)
writer.writerow([form.name.data, form.email.data, form.message.data])
print("waddup")
return redirect(url_for('contact_handler.html'), name=form.name.data)
print(form.errors)
return render_template('contact.html', form=form)
It skips over the if statement as it never ends out printing the "yup", and instead it prints out the error:
{'csrf_token': ['The CSRF token is missing.']}
The template that this connects to is:
{% extends "base_template.html" %}
{% block title %}Contact us {% endblock %}
{% block content %}
<p>Feel free to use the contact form below to send us any questions you might have.</p></br>
<form action="/contact_end" method="post">
{{ form.csrf_token }}
<label>Your Name <input type="text" name="name"/></label></br>
<label>Your Email <input type="text" name="email"/></label></br>
<label>Your Name <textarea name="message"></textarea></label></br>
<button type="submit">Send</button>
<button type="reset">Clear</button>
</form>
{% endblock %}
I've tried messing with form.csrf_token and .hidden_tags(), but with no success.
As well, this is the initial part of app.py that brings you to the page in the first place, the one above is the endpoint for the form:
#app.route('/contact')
def contact():
return render_template('contact.html', form=form)
Finally, here's my ContactForm class:
class ContactForm(FlaskForm):
print("yep")
name = StringField('Name', validators=[InputRequired()])
email = EmailField('Email', validators=[InputRequired(), Email()])
message = TextAreaField('Message', validators=[InputRequired()])
I've made sure to set my secret key, as well. Anyone have any idea why this isn't working? Many thanks.
You still need to create the form instance in your contact() function:
#app.route('/contact')
def contact():
form = ContactForm()
return render_template('contact.html', form=form)

Django - Autocompleting fields when re-rendering form

In my project, I have a Django form, which I then pass to my template. This form allows users to Signup for an account.
If the user makes a mistake, I use Django messages to return an error to the user, and then redirect to the same page with the error. This error is successfully displayed.
However all the previous data the user entered into the form is lost. What I want is too reload the page with the form filled in with all the previous data the user entered. This way they can correct the data easily without having to re-enter all the information again.
Does Anybody know how to accomplish this? Thank you.
views.py:
if form.cleaned_data['password'] != form.cleaned_data['confirmPassword']:
messages.error(request, 'Password fields do not match')
return redirect('signup')
else:
try:
user = User.objects.get(username=form.cleaned_data['username'])
messages.error(request, 'Username has already been taken')
return redirect('signup')
Template:
{% if messages %}
{% for message in messages %}
<span class="errorMessageSignup"> <img src="{% static 'wrongcross.png' %}" style="position:absolute;" height="17px" width="17px"> <b>{{ message }}</b></span>
{% endfor %}
{% endif %}
You can try like this in your template where you have form .
<input type="text" name="username" {% if form.username.value %} value="{{form.username.value}}" {% endif %}>
<input type="password" name="password" {% if form.password.value %} value="{{form.password.value}}" {% endif %}>
You need to save the username and password data and pass them to the template wherever you render it.
This little guide should help you :)

How to add username and e-mail option for password reset in Django password reset?

I am using Django in-build password to allow users to reset the password. My password_reset_form.html looks like this:
{% block title %}Reset Password{% endblock %}
{% block content %}
<p>Please specify your email address to receive instructions for resetting it.</p>
<form action="" method="post">
<div style="display:none">
<input type="hidden" value="{{ csrf_token }}" name="csrfmiddlewaretoken">
</div>
{{ form.email.errors }}
<p><label for="id_email">E-mail address:</label> {{ form.email }} <input type="submit" value="Reset password" /></p>
</form>
{% endblock %}
For now, user can enter their e-mail address and password reset instruction is send to the user. I want to modify this so that user can enter either their username or e-mail address and receive the password reset instruction in email. Should I directly go to dist-packages and start editing the password reset file or should I do something else?
I can find the e-mail address of user using their username if they enters their username:
if not '#' in new_mail:
email = User.objects.filter(username=new_mail).values_list('email')
new_mail1 = email[0]
How can I do this? Thank you
You definitely should not edit dist-packages files. Built-in views and forms don't support the behaviour you want. I think it's ok to copy implementation of the involved views and forms and modify them. Copy django.contrib.auth.views.password_reset view to your views file. Copy django.contrib.auth.forms.PasswordResetForm to your forms file and add username field to it and modify user search code to search on email or username depending on what has been specified. Change used form class in password_reset view to your new PasswordResetForm. This should be enough.
I'd do something like this
{% block title %}Reset Password{% endblock %}
{% block content %}
<p>Please specify your username or email address to receive instructions for resetting it.</p>
<form action="" method="POST">
{% csrf_token %}
{{ form.email.errors }}
<p>{{ form.email.label }}{{ form.email }} <button type="submit">Reset Password</button></p>
</form>
{% endblock %}
In your POST variable you now have an email or a password. You'd have to make a guess if people would use the email or username more. Based on that the following should work
from django.db.models import Q
email = request.POST.get('email, "")
u = User.objects.filter(Q(username=email)|Q(email=email))
if u.count() == 1:
email_address = u[0].email
# now you can send the user an email with instructions
if u.count() < 1:
# invalid username or email
return
if u.count() > 1:
# unlikely but lets account for this anyway. I'll leave this up to you
return
There might be a more elegant way to check for the user, but this way there's essentially only one query and might be quicker than matching email and username individually in try/except blocks. Personally I prefer a filter/count way of checking rather than try/except, but thats besides the point.

Categories

Resources