<filename>app/handlers/authentication_handlers.py
"""
* Copyright 2015, <NAME> <EMAIL>
* https://github.com/RobertoPrevato/Flask-three-template
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/MIT
*
* Authentication strategy.
* Contains global request handler used for user authentication and session management.
"""
from core.encryption.aes import AesEncryptor
from flask import render_template, request
from bll.membership.membershipprovider import MembershipProvider
import sys


def authentication_handlers(app):
    """
     Registers a global request handler for authentication.

     NB: An alternative, if needed, is to initialize a membership provider for each logical area (e.g. admin, public, etc.);
     which allows to use different database structures to store accounts and sessions for different parts of
     the application and to have different, parallel authentication mechanisms.
     This template includes a global membership provider, because it is a simpler model that suffices in most cases.
    """

    if not hasattr(app, "membership"):
        raise Exception("The application is not initialized with a MembershipProvider.")

    membership_provider = app.membership

    # the name of the cookie used to store a session key
    session_cookie = "authtoken"
    SECURE_COOKIES = app.config["SECURE_COOKIES"]
    ENCRYPTION_KEY = app.config["ENCRYPTION_KEY"]


    def initialize_anonymous_session():
        client_ip = request.remote_addr
        result = membership_provider.initialize_anonymous_session(client_ip, {
            "user_agent": request.headers["User-Agent"] if "User-Agent" in request.headers else None
        })

        # set a flag to set a session cookie
        request.set_session_cookie = True
        principal = result["principal"]
        session = result["session"]

        # set information inside the request
        setattr(request, "user", principal)
        setattr(request, "session", session)


    @app.before_request
    def authenticate_request(*args, **kwargs):
        session_key = request.cookies.get(session_cookie)
        if session_key is None:
            # initialize an anonymous session
            initialize_anonymous_session()
        else:
            # decrypt
            session_guid = AesEncryptor.decrypt(session_key, ENCRYPTION_KEY)
            # try to perform login by session key
            success, result = membership_provider.try_login_by_session_key(session_guid)

            if success:
                # result is a principal object
                principal = result["principal"]
                session = result["session"]

                # set information inside the request
                setattr(request, "user", principal)
                setattr(request, "session", session)
            else:
                # set a flag to unset session cookie
                request.unset_session_cookie = True
                # initialize an anonymous session
                initialize_anonymous_session()


    @app.after_request
    def set_auth_cookie(response):
        set_session_cookie = hasattr(request, "set_session_cookie")
        unset_session_cookie = hasattr(request, "unset_session_cookie")
        set_aft_cookie = hasattr(request, "set_aft_cookie")

        if set_session_cookie:
            session = request.session
            session_guid = str(session.guid)
            # encrypt:
            session_token = AesEncryptor.encrypt(session_guid, ENCRYPTION_KEY)

            response.set_cookie(session_cookie,
                                value=session_token,
                                expires=session.expiration,
                                httponly=True,
                                secure=SECURE_COOKIES)
        if unset_session_cookie:
            # instruct the browser to delete the session cookie
            response.set_cookie(session_cookie, value="", expires=0)

        if set_aft_cookie:
            session = request.session
            aft = request.set_aft_cookie
            # set the cookie in the response
            response.set_cookie("aftck",
                                value=aft,
                                expires=session.expiration,
                                httponly=True,
                                secure=SECURE_COOKIES)
            # force XSS protection, otherwise it would be pointless to issue an antiforgery token
            response.headers["X-Frame-Options"] = "SAMEORIGIN"

        return response


<filename>app/handlers/authentication_handlers.py
"""
* Copyright 2015, <NAME> <EMAIL>
* https://github.com/RobertoPrevato/Flask-three-template
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/MIT
*
* Authentication strategy.
* Contains global request handler used for user authentication and session management.
"""
from core.encryption.aes import AesEncryptor
from flask import render_template, request
from bll.membership.membershipprovider import MembershipProvider
import sys


def authentication_handlers(app):
    """
     Registers a global request handler for authentication.

     NB: An alternative, if needed, is to initialize a membership provider for each logical area (e.g. admin, public, etc.);
     which allows to use different database structures to store accounts and sessions for different parts of
     the application and to have different, parallel authentication mechanisms.
     This template includes a global membership provider, because it is a simpler model that suffices in most cases.
    """

    if not hasattr(app, "membership"):
        raise Exception("The application is not initialized with a MembershipProvider.")

    membership_provider = app.membership

    # the name of the cookie used to store a session key
    session_cookie = "authtoken"
    SECURE_COOKIES = app.config["SECURE_COOKIES"]
    ENCRYPTION_KEY = app.config["ENCRYPTION_KEY"]


    def initialize_anonymous_session():
        client_ip = request.remote_addr
        result = membership_provider.initialize_anonymous_session(client_ip, {
            "user_agent": request.headers["User-Agent"] if "User-Agent" in request.headers else None
        })

        # set a flag to set a session cookie
        request.set_session_cookie = True
        principal = result["principal"]
        session = result["session"]

        # set information inside the request
        setattr(request, "user", principal)
        setattr(request, "session", session)


    @app.before_request
    def authenticate_request(*args, **kwargs):
        session_key = request.cookies.get(session_cookie)
        if session_key is None:
            # initialize an anonymous session
            initialize_anonymous_session()
        else:
            # decrypt
            session_guid = AesEncryptor.decrypt(session_key, ENCRYPTION_KEY)
            # try to perform login by session key
            success, result = membership_provider.try_login_by_session_key(session_guid)

            if success:
                # result is a principal object
                principal = result["principal"]
                session = result["session"]

                # set information inside the request
                setattr(request, "user", principal)
                setattr(request, "session", session)
            else:
                # set a flag to unset session cookie
                request.unset_session_cookie = True
                # initialize an anonymous session
                initialize_anonymous_session()


    @app.after_request
    def set_auth_cookie(response):
        set_session_cookie = hasattr(request, "set_session_cookie")
        unset_session_cookie = hasattr(request, "unset_session_cookie")
        set_aft_cookie = hasattr(request, "set_aft_cookie")

        if set_session_cookie:
            session = request.session
            session_guid = str(session.guid)
            # encrypt:
            session_token = AesEncryptor.encrypt(session_guid, ENCRYPTION_KEY)

            response.set_cookie(session_cookie,
                                value=session_token,
                                expires=session.expiration,
                                httponly=True,
                                secure=SECURE_COOKIES)
        if unset_session_cookie:
            # instruct the browser to delete the session cookie
            response.set_cookie(session_cookie, value="", expires=0)

        if set_aft_cookie:
            session = request.session
            aft = request.set_aft_cookie
            # set the cookie in the response
            response.set_cookie("aftck",
                                value=aft,
                                expires=session.expiration,
                                httponly=True,
                                secure=SECURE_COOKIES)
            # force XSS protection, otherwise it would be pointless to issue an antiforgery token
            response.headers["X-Frame-Options"] = "SAMEORIGIN"

        return response


* Copyright 2015, <NAME> <EMAIL> * https://github.com/RobertoPrevato/Flask-three-template * * Licensed under the MIT license: * http://www.opensource.org/licenses/MIT * * Authentication strategy. * Contains global request handler used for user authentication and session management. Registers a global request handler for authentication.       NB: An alternative, if needed, is to initialize a membership provider for each logical area (e.g. admin, public, etc.);      which allows to use different database structures to store accounts and sessions for different parts of      the application and to have different, parallel authentication mechanisms.      This template includes a global membership provider, because it is a simpler model that suffices in most cases. # the name of the cookie used to store a session key # set a flag to set a session cookie # set information inside the request # initialize an anonymous session # decrypt # try to perform login by session key # result is a principal object # set information inside the request # set a flag to unset session cookie # initialize an anonymous session # encrypt: # instruct the browser to delete the session cookie # set the cookie in the response # force XSS protection, otherwise it would be pointless to issue an antiforgery token