1

Looking at the Flask-Login docs and several relatively old threads on Stackoverflow, I am concerned about the security of my solution for passing the restricted page URL through the login process.

First, I was getting Attribution Error when trying to use @login_manager.unauthorized_handler. ("login_manager does not have an attribute unauthorized_handler.") This a separate issue altogether, because it really should have worked. (See app factory below.)

When I applied a redirect_destination function without the modified @login_manager.unauthorized_handler, the login failed to redirect to the target destination.

def redirect_destination(dest_url, fallback):
    try:
        dest_url = url_for(dest_url)
    except:
        return redirect(fallback)
    return redirect(dest_url)

Then I applied a session instance to be passed from the destination URL through login along with the fresh_login_required decorator and .is_authenticated property instead of the standard login_required.

target blueprint:

@target.route('/target', methods=['GET', 'POST'])
@fresh_login_required
def target():
    if current_user.is_authenticated:
        ...
        return render_template('target.html')
    else:
        session['dest_url']=request.endpoint
        return redirect(url_for('account.login'))

auth blueprint:

@account.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('main.index'))
    dest_url = session.get('dest_url')
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()

        if not user:
            return redirect(url_for('account.login'))

        if user.check_password(form.password.data):
            login_user(user, remember=form.remember_me.data)
            ...
            return redirect_destination(dest_url, fallback=url_for('main.index'))
        else:
            return redirect(url_for('account.login'))

    return render_template('account/login.html')

app factory:

...

login_manager = LoginManager()
login_manager.login_view = 'account.login' #hard-coded view
login_manager.refresh_view = 'account.refresh' #hard-coded view

def create_app():  
    app = Flask(__name__,
                static_url_path='/',
                static_folder='../app/static',
                template_folder='../app/templates')
            
    db.init_app(app)
    login_manager.init_app(app)

    from app import models

    from .templates.account import account
    from .templates.main import main
    from .templates.target import target


    app.register_blueprint(main)
    app.register_blueprint(account)
    app.register_blueprint(target)

    return app

So, this solution works, and it can be applied to multiple blueprints. My concern is that I am missing some important details that necessitated other, more complex solutions. Is there a security weak point? Other issues?

References:

https://flask-login.readthedocs.io/en/latest/

How do I pass through the "next" URL with Flask and Flask-login?

Flask/Werkzeug, how to return previous page after login

Flask how to redirect to previous page after successful login

Get next URL using flask redirect

Flask Basic HTTP Auth use login page

grommit
  • 57
  • 1
  • 8

0 Answers0