Verifying username and password input through flask python

Question:

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 %}
Asked By: evogamer

||

Answers:

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.

Answered By: bigkeefer