Initializing Flask-Session breaks Session in Dependency

55 Views Asked by At

I'm trying to use enter link description here. If I use their minimal example, everything works fine but in my actual application, I use Flask-Session myself. Now the Flask-MonitoringDashboard also uses Flask-Session to store a session cookie and indicate if the user is logged in or not.

Here's a working example that also set's the secret key:

from flask import Flask, session
import flask_monitoringdashboard as dashboard

from flask_session import Session

class Config:
    SECRET_KEY = "top-sercet!"

app = Flask(__name__)
app.config.from_object(Config)


dashboard.config.init_from(file='/home/pascal/test/dashboard_minimal/config.cfg')
dashboard.bind(app)

sess = Session()
#sess.init_app(app)

@app.route('/')
def index():
    return 'Hello World!'

if __name__ == '__main__':
  app.run(debug=True)

Note: I use absolute paths just to be sure.

Also here's config.cfg (copy pasted from their example)

[dashboard]
APP_VERSION=1.0
GIT=/home/pascal/test/dashboard_minimal/.git/
CUSTOM_LINK=dashboard
MONITOR_LEVEL=3
OUTLIER_DETECTION_CONSTANT=2.5
SAMPLING_PERIOD=20
ENABLE_LOGGING=True

[authentication]
USERNAME=admin
PASSWORD=admin
SECURITY_TOKEN=cc83733cb0af8b884ff6577086b87909

[database]
TABLE_PREFIX=fmd
DATABASE=sqlite://///home/pascal/test/dashboard_minimal/dashboard.db

[visualization]
TIMEZONE=Europe/Amsterdam
COLORS={'main':'[0,97,255]',
        'static':'[255,153,0]'}

Now if you run flask --app main run and go to localhost:5000/dashboard you can login with admin and admin.

Now if we add Flask-Session to the app ourselves i.e. we uncomment sess.init_app(app) we get the error

RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.

which is weird, since we did infact set it. The error is probably due to us not setting a interface. So we do that by changing the Config class to

class Config:
    SECRET_KEY = "top-sercet!"
    SESSION_TYPE = "memcached"

The error is gone but now we are in a infinite login loop when we try to login! This is, because Flask-MonitoringDashboard uses a @secure decorator where they read the session and check if the user is logged in but the value is never set! Here's what they do:

In [flask_monitoringdashboard/views/auth.py][3] we see the route that handles the login:

import flask

...

@blueprint.route('/login', methods=['GET', 'POST'])
def login():
    """
    User for logging into the system. The POST-request checks whether the logging is valid.
    If this is the case, the user is redirected to the main page.
    :return:
    """
    if flask.session.get(config.link + '_logged_in'):
        return redirect(url_for(MAIN_PAGE))

    if request.method == 'POST':
        name = request.form['name']
        password = request.form['password']

        user = get_user(username=name, password=password)
        if user is not None:
            on_login(user=user)
            return redirect(url_for(MAIN_PAGE))
    return render_template('fmd_login.html', 
        blueprint_name=config.blueprint_name, 
        show_login_banner=config.show_login_banner, 
        show_login_footer=config.show_login_footer,
    )

  

If we aren't logged in, we proceed to start authentication. In the on_login function they set the session:

from flask import session, redirect, url_for

def on_login(user):
    session[config.link + '_user_id'] = user.id
    session[config.link + '_logged_in'] = True
    if user.is_admin:
        session[config.link + '_admin'] = True

Once logged in, we get redirected return redirect(url_for(MAIN_PAGE)) which at some point calls the @secure decorator:

from flask import session, redirect, url_for

...

def secure(func):
    """
    When the user is not logged into the system, the user is requested to the login page.
    There are two types of user-modes:
    - admin: Can be visited with this wrapper.
    - guest: Can be visited with this wrapper.
    :param func: the endpoint to be wrapped.
    """

    @wraps(func)
    def wrapper(*args, **kwargs):
        if session and session.get(config.link + '_logged_in'):
            return func(*args, **kwargs)
        return redirect(url_for(config.blueprint_name + '.login'))

    return wrapper

Not the different way of importing session. They have a name conflict in the first file, which is why they use flask.session.

Am I simply not initializing Flask-Session correctly or is there another issue? Any help is appreciated.

0

There are 0 best solutions below