Exemplo n.º 1
0
def register_handlers(app: Flask) -> Flask:
    """A function to register global request handlers.
    To register a handler add them like the example
    Example usage:

        def fn(request: Request):
            pass

        app.before_request(fn)

    Args:
        app (Flask): Flask Application instance

    Returns:
        Flask: Flask Application instance
    """
    identity_loaded.connect_via(app)(on_identity_loaded)

    app.errorhandler(PermissionDenied)(permission_denied)
    app.errorhandler(CSRFError)(invalid_csrf)
    app.errorhandler(NoAuthorizationError)(invalid_csrf)
    app.errorhandler(InvalidUsage)(invalid_error_handler)
    app.errorhandler(Exception)(normalize_errors)

    return app
Exemplo n.º 2
0
def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)

    # initialize plugins
    db.init_app(app)
    ma.init_app(app)
    migrate.init_app(app, db)
    login.init_app(app)
    login.login_view = 'user_views.login'
    login.login_message = 'Please log in to access this page.'
    login.session_protection = "strong"
    sess.init_app(app)
    bootstrap.init_app(app)
    admin.init_app(app)
    principal.init_app(app)
    excel.init_excel(app)

    register_blueprints(app)
    register_dashapps(app)

    # connect listener for identity loaded signal
    from app.user.roles import on_identity_loaded
    identity_loaded.connect_via(app)(on_identity_loaded)

    # custom overrides
    app.json_encoder = CustomJSONEncoder

    # App is behind https proxy
    from werkzeug.middleware.proxy_fix import ProxyFix
    app.wsgi_app = ProxyFix(app.wsgi_app)

    return app
Exemplo n.º 3
0
    def init_app(self, app, entry_point_actions='invenio_access.actions',
                 entry_point_system_roles='invenio_access.system_roles',
                 **kwargs):
        """Flask application initialization.

        :param app: The Flask application.
        :param entry_point_actions: The entrypoint for actions extensions.
            (Default: ``'invenio_access.actions'``)
        :param entry_point_system_roles: The entrypoint for  system roles
            extensions. (Default: ``'invenio_access.system_roles'``)
        :param cache: The cache system. (Default: ``None``)
        """
        self.init_config(app)
        state = _AccessState(
            app, entry_point_actions=entry_point_actions,
            entry_point_system_roles=entry_point_system_roles,
            cache=kwargs.get('cache'))
        app.extensions['invenio-access'] = state

        if app.config.get('ACCESS_LOAD_SYSTEM_ROLE_NEEDS', True):
            identity_loaded.connect_via(app)(
                load_permissions_on_identity_loaded
            )

        return state
Exemplo n.º 4
0
    def init_app(self, app):
        """Flask application initialization."""
        self.init_config(app)
        state = _OARepoCommunitiesState(app)

        app.extensions['oarepo-communities'] = state

        identity_loaded.connect_via(app)(on_identity_loaded)
Exemplo n.º 5
0
    def init_app(self,
                 app,
                 datastore=None,
                 register_blueprint=True,
                 login_form=None,
                 confirm_register_form=None,
                 register_form=None,
                 forgot_password_form=None,
                 reset_password_form=None,
                 change_password_form=None,
                 send_confirmation_form=None,
                 passwordless_login_form=None,
                 anonymous_user=None):
        """Initializes the Flask-Security extension for the specified
        application and datastore implentation.

        :param app: The application.
        :param datastore: An instance of a user datastore.
        :param register_blueprint: to register the Security blueprint or not.
        """
        self.app = app
        self.datastore = datastore

        for key, value in _default_config.items():
            app.config.setdefault('SECURITY_' + key, value)

        for key, value in _default_messages.items():
            app.config.setdefault('SECURITY_MSG_' + key, value)

        identity_loaded.connect_via(app)(_on_identity_loaded)

        state = _get_state(app,
                           self.datastore,
                           login_form=login_form,
                           confirm_register_form=confirm_register_form,
                           register_form=register_form,
                           forgot_password_form=forgot_password_form,
                           reset_password_form=reset_password_form,
                           change_password_form=change_password_form,
                           send_confirmation_form=send_confirmation_form,
                           passwordless_login_form=passwordless_login_form,
                           anonymous_user=anonymous_user)

        if register_blueprint:
            app.register_blueprint(create_blueprint(state, __name__))
            app.context_processor(_context_processor)

        state.render_template = self.render_template
        app.extensions['security'] = state

        if hasattr(app, 'cli'):
            from .cli import users, roles
            if state.cli_users_name:
                app.cli.add_command(users, state.cli_users_name)
            if state.cli_roles_name:
                app.cli.add_command(roles, state.cli_roles_name)

        return state
Exemplo n.º 6
0
    def init_app(self, app, datastore=None, register_blueprint=True,
                 login_form=None, confirm_register_form=None,
                 register_form=None, forgot_password_form=None,
                 reset_password_form=None, change_password_form=None,
                 send_confirmation_form=None, passwordless_login_form=None,
                 anonymous_user=None):
        """Initializes the Flask-Security extension for the specified
        application and datastore implentation.

        :param app: The application.
        :param datastore: An instance of a user datastore.
        :param register_blueprint: to register the Security blueprint or not.
        """
        self.app = app
        self.datastore = datastore

        for key, value in _default_config.items():
            app.config.setdefault('SECURITY_' + key, value)

        for key, value in _default_messages.items():
            app.config.setdefault('SECURITY_MSG_' + key, value)

        identity_loaded.connect_via(app)(_on_identity_loaded)

        state = _get_state(app, self.datastore,
                           login_form=login_form,
                           confirm_register_form=confirm_register_form,
                           register_form=register_form,
                           forgot_password_form=forgot_password_form,
                           reset_password_form=reset_password_form,
                           change_password_form=change_password_form,
                           send_confirmation_form=send_confirmation_form,
                           passwordless_login_form=passwordless_login_form,
                           anonymous_user=anonymous_user)

        if register_blueprint:
            app.register_blueprint(create_blueprint(state, __name__))
            app.context_processor(_context_processor)

        @app.before_first_request
        def _register_i18n():
            if '_' not in app.jinja_env.globals:
                app.jinja_env.globals['_'] = state.i18n_domain.gettext

        state.render_template = self.render_template
        app.extensions['security'] = state

        if hasattr(app, 'cli'):
            from .cli import users, roles
            if state.cli_users_name:
                app.cli.add_command(users, state.cli_users_name)
            if state.cli_roles_name:
                app.cli.add_command(roles, state.cli_roles_name)

        return state
Exemplo n.º 7
0
    def init_app(self, app, datastore=None, register_blueprint=None, **kwargs):
        """Initializes the Flask-Security extension for the specified
        application and datastore implementation.

        :param app: The application.
        :param datastore: An instance of a user datastore.
        :param register_blueprint: to register the Security blueprint or not.
        """
        self.app = app

        if datastore is None:
            datastore = self._datastore

        if register_blueprint is None:
            register_blueprint = self._register_blueprint

        for key, value in self._kwargs.items():
            kwargs.setdefault(key, value)

        if 'render_template' not in kwargs:
            kwargs.setdefault('render_template', self.render_template)
        if 'send_mail' not in kwargs:
            kwargs.setdefault('send_mail', self.send_mail)

        for key, value in _default_config.items():
            app.config.setdefault('SECURITY_' + key, value)

        for key, value in _default_messages.items():
            app.config.setdefault('SECURITY_MSG_' + key, value)

        identity_loaded.connect_via(app)(_on_identity_loaded)

        self._state = state = _get_state(app, datastore, **kwargs)

        if register_blueprint:
            app.register_blueprint(create_blueprint(state, __name__))
            app.context_processor(_context_processor)

        @app.before_first_request
        def _register_i18n():
            if '_' not in app.jinja_env.globals:
                app.jinja_env.globals['_'] = state.i18n_domain.gettext

        app.extensions['security'] = state

        if hasattr(app, 'cli'):
            from .cli import users, roles
            if state.cli_users_name:
                app.cli.add_command(users, state.cli_users_name)
            if state.cli_roles_name:
                app.cli.add_command(roles, state.cli_roles_name)

        return state
Exemplo n.º 8
0
def create():
    app = Flask(__name__)
    app.config.from_object(Config)

    from ayeauth.loader import (
        user_loader,
        # request_loader,
        identity_loader,
        on_identity_loaded,
        unauthorized_handler,
    )
    from ayeauth.models.user import AnonymousUser

    lm.login_view = "auth_bp.login"
    lm.anonymous_user = AnonymousUser
    lm.user_loader(user_loader)
    # lm.request_loader(request_loader)
    lm.unauthorized_handler(unauthorized_handler)
    pr.identity_loader(identity_loader)

    db.init_app(app)
    lm.init_app(app)
    pr.init_app(app)

    identity_loaded.connect_via(app)(on_identity_loaded)

    from ayeauth.models.user import User  # noqa: F401
    from ayeauth.models.role import Role  # noqa: F401
    from ayeauth.models.user_role import UserRole  # noqa: F401
    from ayeauth.models.user_authorized_application import (  # noqa: F401
        UserAuthorizedApplication, )
    from ayeauth.models.application import Application  # noqa: F401
    from ayeauth.models.scope import Scope  # noqa: F401
    from ayeauth.models.application_scope import ApplicationScope  # noqa: F401
    from ayeauth.models.authorization_code import AuthorizationCode  # noqa: F401

    from ayeauth.home.routes import home_bp
    from ayeauth.auth.routes import auth_bp
    from ayeauth.oauth.routes import oauth_bp
    from ayeauth.user.routes import user_bp
    from ayeauth.application.routes import application_bp

    app.register_blueprint(home_bp, url_prefix="/")
    app.register_blueprint(auth_bp, url_prefix="/")
    app.register_blueprint(oauth_bp, url_prefix="/oauth")
    app.register_blueprint(user_bp, url_prefix="/user")
    app.register_blueprint(application_bp, url_prefix="/application")

    return app
Exemplo n.º 9
0
    def init_app(self, app, datastore=None, register_blueprint=True,
                 login_form=None, confirm_register_form=None,
                 register_form=None, forgot_password_form=None,
                 reset_password_form=None, change_password_form=None,
                 send_confirmation_form=None, passwordless_login_form=None,
                 anonymous_user=None):
        """Initializes the Flask-Security extension for the specified
        application and datastore implentation.

        :param app: The application.
        :param datastore: An instance of a user datastore.
        :param register_blueprint: to register the Security blueprint or not.
        """
        datastore = datastore or self.datastore

        for key, value in _default_config.items():
            if key == 'EMAIL_SENDER' and app.config.get('MAIL_DEFAULT_SENDER'):
                app.config.setdefault(
                    'SECURITY_' + key, app.config.get('MAIL_DEFAULT_SENDER')
                )
            app.config.setdefault('SECURITY_' + key, value)

        for key, value in _default_messages.items():
            app.config.setdefault('SECURITY_MSG_' + key, value)

        identity_loaded.connect_via(app)(_on_identity_loaded)

        state = _get_state(app, datastore,
                           login_form=login_form,
                           confirm_register_form=confirm_register_form,
                           register_form=register_form,
                           forgot_password_form=forgot_password_form,
                           reset_password_form=reset_password_form,
                           change_password_form=change_password_form,
                           send_confirmation_form=send_confirmation_form,
                           passwordless_login_form=passwordless_login_form,
                           anonymous_user=anonymous_user)

        if register_blueprint:
            app.register_blueprint(create_blueprint(state, __name__))
            app.context_processor(_context_processor)

        state.render_template = self.render_template
        app.extensions['security'] = state

        return state
Exemplo n.º 10
0
def AccessToken(app):
    try:
        if not app.secret_key:
            app.secret_key = os.environ['FLASK_SECRET_KEY']
    except KeyError:
        print("app.secret_key or FLASK_SECRET_KEY environ variable should be defined")
    # add _require_access_token decorator into /<repo>/* urls

    app.add_url_rule("/invitation", "invitation", view_func=_InvitationView.as_view('invitation'))
    # A hack to move /invitation url rule before /<repo> url rule
    invt_rule = app.url_map._rules.pop()
    app.url_map._rules.insert(0, invt_rule)
    app.url_map._remap = True
    app.url_map.update()

    Principal(app)
    app.before_request(_on_before_request_access_token)
    identity_loaded.connect_via(app)(_on_identity_loaded)
Exemplo n.º 11
0
def create_app():
    templates = os.path.join(os.path.dirname(__file__), '../../', 'templates')
    settings = os.path.join(os.path.dirname(__file__), '../../',
                            'etc/local.py')
    static_folder = os.path.join(os.path.dirname(__file__), '../../',
                                 'assets/static')
    app = Flask(
        __name__,
        template_folder=templates,
    )
    app.config.from_pyfile(settings)

    app.static_folder = static_folder
    app.config.update({'SITE_TIME': datetime.datetime.now()})
    app.config.update({'SQLALCHEMY_ECHO': False})
    app.config.setdefault('SQLALCHEMY_TRACK_MODIFICATIONS', True)

    admin_test = Admin(app,
                       name='中瑞通航机务维修管理系统',
                       base_template='layout.html',
                       template_mode='bootstrap3',
                       index_view=IndexView())

    sec = Security(app, user_datastore)

    mysqldb.init_app(app)
    # mongodb.init_app(app)

    @sec.context_processor
    def security_context_processor():
        return dict(admin_base_template=admin_test.base_template,
                    admin_view=admin_test.index_view,
                    h=helpers,
                    get_url=url_for)

    identity_loaded.connect_via(app)(_on_identity_loaded)

    register_jinja(app)
    with app.app_context():
        init_mxp_view(admin_test, mongodb, category='维修方案管理')
    admin_test.add_view(UserAdminView(mysqldb.session))
    admin_test.add_view(RoleAdminView(mysqldb.session))

    return app
Exemplo n.º 12
0
    def init_app(self, app, datastore=None, register_blueprint=True,
                 login_form=None, confirm_register_form=None,
                 register_form=None, forgot_password_form=None,
                 reset_password_form=None, change_password_form=None,
                 send_confirmation_form=None, passwordless_login_form=None,
                 anonymous_user=None):
        """Initializes the Flask-Security extension for the specified
        application and datastore implentation.

        :param app: The application.
        :param datastore: An instance of a user datastore.
        :param register_blueprint: to register the Security blueprint or not.
        """
        self.app = app
        self.datastore = datastore

        for key, value in _default_config.items():
            app.config.setdefault('SECURITY_' + key, value)

        for key, value in _default_messages.items():
            app.config.setdefault('SECURITY_MSG_' + key, value)

        identity_loaded.connect_via(app)(_on_identity_loaded)

        state = _get_state(app, self.datastore,
                           login_form=login_form,
                           confirm_register_form=confirm_register_form,
                           register_form=register_form,
                           forgot_password_form=forgot_password_form,
                           reset_password_form=reset_password_form,
                           change_password_form=change_password_form,
                           send_confirmation_form=send_confirmation_form,
                           passwordless_login_form=passwordless_login_form,
                           anonymous_user=anonymous_user)

        if register_blueprint:
            app.register_blueprint(create_blueprint(state, __name__))
            app.context_processor(_context_processor)

        state.render_template = self.render_template
        app.extensions['security'] = state

        return state
Exemplo n.º 13
0
    def init_app(self, app: FlaskUnchained):
        # NOTE: the order of these `self.get_*` calls is important!
        self.confirm_serializer = self._get_serializer(app, 'confirm')
        self.hashing_context = self._get_hashing_context(app)
        self.login_manager = self._get_login_manager(
            app, app.config.SECURITY_ANONYMOUS_USER)
        self.login_serializer = self._get_serializer(app, 'login')
        self.principal = self._get_principal(app)
        self.pwd_context = self._get_pwd_context(app)
        self.remember_token_serializer = self._get_serializer(app, 'remember')
        self.reset_serializer = self._get_serializer(app, 'reset')

        self.context_processor(
            lambda: dict(security=_SecurityConfigProperties()))

        # FIXME: should this be easier to customize for end users, perhaps by making
        # FIXME: the function come from a config setting?
        identity_loaded.connect_via(app)(self._on_identity_loaded)
        app.extensions['security'] = self
Exemplo n.º 14
0
def setup_security(app, project):
    options = {
        "login_form": MeltanoLoginForm,
        "register_form": MeltanoRegisterFrom,
        "confirm_register_form": MeltanoConfirmRegisterForm,
    }

    if not app.config["MELTANO_AUTHENTICATION"]:
        # the FreeUser is free to do everything and has all
        # roles and permissions automatically.
        options["anonymous_user"] = FreeUser

    security.init_app(app, users, **options)
    security.unauthorized_handler(unauthorized_callback)
    identity_loaded.connect_via(app)(_identity_loaded_hook)

    jwt = JWTManager(app)

    @jwt.user_loader_callback_loader
    def jwt_user_load(identity):
        user = users.find_user(id=identity["id"])
        login_user(user)  # sets `flask_security` current_user

        return user

    bp = app.blueprints["security"]

    @bp.route("/bootstrap")
    @login_required
    def bootstrap_app():
        """Fire off the application with the current user logged in"""
        uri = app.config["MELTANO_UI_URL"]

        if not app.config["MELTANO_AUTHENTICATION"]:
            return redirect(uri)

        auth_identity = {"id": current_user.id, "username": current_user.username}
        access_token = create_access_token(identity=auth_identity)

        return redirect(uri + f"?auth_token={access_token}")

    app.register_blueprint(bp)
Exemplo n.º 15
0
def setup_security(app, project):
    options = {
        "login_form": MeltanoLoginForm,
        "register_form": MeltanoRegisterFrom,
        "confirm_register_form": MeltanoConfirmRegisterForm,
    }

    if not app.config["MELTANO_AUTHENTICATION"] and not app.config["MELTANO_READONLY"]:
        # the FreeUser is free to do everything and has all
        # roles and permissions automatically.
        options["anonymous_user"] = FreeUser
    else:
        # Use Flask's built-in AnonymousUser which is not deemed to be authenticated
        # and has no roles
        pass

    security.init_app(app, users, **options)
    security.unauthorized_handler(unauthorized_callback)
    user_logged_in.connect_via(app)(_user_logged_in_hook)
    identity_loaded.connect_via(app)(_identity_loaded_hook)
Exemplo n.º 16
0
    def init_app(self, app):
        self._state = super().init_app(app, self.datastore, **self._kwargs)

        # override the unauthorized action to use abort(401) instead of returning HTML
        self._state.unauthorized_handler(unauthorized_handler)

        # register a celery task to send emails asynchronously
        self._state.send_mail_task(send_mail_async)

        # load user's role hierarchy
        identity_loaded.connect_via(app)(on_identity_loaded)

        # only activate users after they've been confirmed
        if self.confirmable:
            user_confirmed.connect_via(app)(_on_user_confirmed)

        if not self._kwargs['register_blueprint']:
            app.context_processor(_context_processor)

        app.extensions['security'] = self
Exemplo n.º 17
0
    def init_app(self, app, provider=None):
        """Initialize app."""
        app.config.setdefault('CARAFE_AUTH_ENABLED', True)
        app.config.setdefault('CARAFE_AUTH_SESSION_ID_KEY', 'user_id')
        app.config.setdefault('CARAFE_AUTH_IDENTITY_ID_KEY', 'id')
        app.config.setdefault('CARAFE_AUTH_IDENTITY_ROLES_KEY', 'roles')

        if not app.config['CARAFE_AUTH_ENABLED']:  # pragma: no cover
            return

        if not hasattr(app, 'extensions'):  # pragma: no cover
            app.extensions = {}

        app.extensions[self._extension_name] = {'provider': provider}

        # NOTE: Instead of having principal use it's session loader, we'll use
        # ours.
        self.principal.init_app(app)
        self.principal.identity_loader(self.session_identity_loader)
        identity_loaded.connect_via(app)(self.on_identity_loaded)
Exemplo n.º 18
0
def setup_security(app, project):
    options = {
        "login_form": MeltanoLoginForm,
        "register_form": MeltanoRegisterFrom,
        "confirm_register_form": MeltanoConfirmRegisterForm,
    }

    settings_service = ProjectSettingsService(project)
    if not settings_service.get("ui.authentication"):
        # the FreeUser is free to do everything and has all
        # roles and permissions automatically.
        options["anonymous_user"] = FreeUser
    else:
        # Use Flask's built-in AnonymousUser which is not deemed to be authenticated
        # and has no roles
        pass

    security.init_app(app, users, **options)
    security.unauthorized_handler(unauthorized_callback)
    user_logged_in.connect_via(app)(_user_logged_in_hook)
    identity_loaded.connect_via(app)(_identity_loaded_hook)
Exemplo n.º 19
0
def create_app():
    app = Flask(__name__)
    app.config.from_object(Config)

    # flask_sqlalchemy
    # import ipdb; ipdb.set_trace()
    db.init_app(app)

    # flask_redis
    redis_cli.init_app(app)

    # flask_migrate
    Migrate(app, db)

    # flask_debug
    if app.config.get('DEBUG'):
        DebugToolbarExtension(app)

    # flask_login
    login_manager = LoginManager(app)
    login_manager.user_loader(load_user)
    login_manager.login_view = 'user_view.login'

    # flask_principal
    Principal(app)
    identity_loaded.connect_via(app)(_on_identity_loaded)

    # flask_wtf csrf
    csrf = CsrfProtect()
    csrf.init_app(app)
    app.before_request(check_csrf(csrf))

    # flask_babel
    Babel(app)

    # flask_limiter
    limiter.init_app(app)

    # flask_qiniu
    qiniu.init_app(app)

    # flask_admin
    admin.init_app(app)

    # register blueprint
    app.register_blueprint(content_bp)

    app.register_blueprint(user_bp)

    app.register_blueprint(user_api_bp)

    # import ipdb; ipdb.set_trace()
    app.register_blueprint(book_bp)
    app.register_blueprint(book_api_bp)
    app.register_blueprint(user_util_api_bp)
    app.register_blueprint(media_bp)
    app.register_blueprint(online_course_bp)

    # register subscriber
    user_connect(app)

    # register home page
    app.add_url_rule('/', 'index', index)

    with open(os.path.join(os.getcwd(), 'youjiao/static/assets.json.py'), 'r') as assets:
        app.assets = json.load(assets)

    return app
Exemplo n.º 20
0
def register_permissions_loader(app):
    """Register the permissions loader."""
    identity_loaded.connect_via(app)(_load_permissions_on_identity_loaded)
    app.before_first_request(_register_anonymous_loader)
Exemplo n.º 21
0
def create_app():
    app = Flask(__name__)
    app.config.from_object(youjiao_config)

    # flask_sqlalchemy
    # import ipdb; ipdb.set_trace()
    db.init_app(app)

    # flask_redis
    redis_cli.init_app(app)

    # flask_debug
    if app.config.get('DEBUG'):
        DebugToolbarExtension(app)

    # flask_login
    login_manager.user_loader(load_user)
    login_manager.login_view = 'user_view.login'
    login_manager.init_app(app)

    # flask_jwt
    jwt.init_app(app)

    # flask_principal
    Principal(app)
    identity_loaded.connect_via(app)(_on_identity_loaded)

    # flask_wtf csrf
    csrf = CsrfProtect()
    csrf.init_app(app)
    app.before_request(check_csrf(csrf))

    # flask_babel
    Babel(app)

    # flask_limiter
    limiter.init_app(app)

    # flask_qiniu
    flask_qiniu.init_app(app)

    # flask_admin
    admin.init_app(app)

    # register blueprint
    app.register_blueprint(content_bp)

    app.register_blueprint(user_bp)

    app.register_blueprint(user_api_bp)

    # import ipdb; ipdb.set_trace()
    app.register_blueprint(book_bp)
    app.register_blueprint(book_api_bp)
    app.register_blueprint(user_util_api_bp)
    app.register_blueprint(media_bp)
    app.register_blueprint(online_course_bp)

    # register subscriber
    user_connect(app)

    # register home page
    app.add_url_rule('/', 'index', index)

    with open(os.path.join(os.getcwd(), 'youjiao/static/assets.json.py'),
              'r') as assets:
        app.assets = json.load(assets)

    return app
Exemplo n.º 22
0
    def init_app(self, app, datastore=None, register_blueprint=None, **kwargs):
        """Initializes the Flask-Security extension for the specified
        application and datastore implementation.

        :param app: The application.
        :param datastore: An instance of a user datastore.
        :param register_blueprint: to register the Security blueprint or not.
        """
        self.app = app

        if datastore is None:
            datastore = self._datastore

        if register_blueprint is None:
            register_blueprint = self._register_blueprint

        for key, value in self._kwargs.items():
            kwargs.setdefault(key, value)

        if "render_template" not in kwargs:
            kwargs.setdefault("render_template", self.render_template)
        if "json_encoder_cls" not in kwargs:
            kwargs.setdefault("json_encoder_cls", FsJsonEncoder)
        if "totp_cls" not in kwargs:
            kwargs.setdefault("totp_cls", Totp)
        if "phone_util_cls" not in kwargs:
            kwargs.setdefault("phone_util_cls", PhoneUtil)
        if "mail_util_cls" not in kwargs:
            kwargs.setdefault("mail_util_cls", MailUtil)

        for key, value in _default_config.items():
            app.config.setdefault("SECURITY_" + key, value)

        for key, value in _default_messages.items():
            app.config.setdefault("SECURITY_MSG_" + key, value)

        identity_loaded.connect_via(app)(_on_identity_loaded)

        self._state = state = _get_state(app, datastore, **kwargs)
        if hasattr(datastore, "user_model") and not hasattr(
                datastore.user_model, "fs_uniquifier"):  # pragma: no cover
            raise ValueError(
                "User model must contain fs_uniquifier as of 4.0.0")

        if register_blueprint:
            bp = create_blueprint(app,
                                  state,
                                  __name__,
                                  json_encoder=kwargs["json_encoder_cls"])
            app.register_blueprint(bp)
            app.context_processor(_context_processor)

        @app.before_first_request
        def _register_i18n():
            # N.B. as of jinja 2.9 '_' is always registered
            # http://jinja.pocoo.org/docs/2.10/extensions/#i18n-extension
            if "_" not in app.jinja_env.globals:
                current_app.jinja_env.globals["_"] = state.i18n_domain.gettext
            # Register so other packages can reference our translations.
            current_app.jinja_env.globals[
                "_fsdomain"] = state.i18n_domain.gettext

        @app.before_first_request
        def _csrf_init():
            # various config checks - some of these are opinionated in that there
            # could be a reason for some of these combinations - but in general
            # they cause strange behavior.
            # WTF_CSRF_ENABLED defaults to True if not set in Flask-WTF
            if not current_app.config.get("WTF_CSRF_ENABLED", True):
                return
            csrf = current_app.extensions.get("csrf", None)

            # If they don't want ALL mechanisms protected, then they must
            # set WTF_CSRF_CHECK_DEFAULT=False so that our decorators get control.
            if cv("CSRF_PROTECT_MECHANISMS") != AUTHN_MECHANISMS:
                if not csrf:
                    # This isn't good.
                    raise ValueError("CSRF_PROTECT_MECHANISMS defined but"
                                     " CsrfProtect not part of application")
                if current_app.config.get("WTF_CSRF_CHECK_DEFAULT", True):
                    raise ValueError(
                        "WTF_CSRF_CHECK_DEFAULT must be set to False if"
                        " CSRF_PROTECT_MECHANISMS is set")
            # We don't get control unless they turn off WTF_CSRF_CHECK_DEFAULT if
            # they have enabled global CSRFProtect.
            if (cv("CSRF_IGNORE_UNAUTH_ENDPOINTS")
                    and csrf and current_app.config.get(
                        "WTF_CSRF_CHECK_DEFAULT", False)):
                raise ValueError(
                    "To ignore unauth endpoints you must set WTF_CSRF_CHECK_DEFAULT"
                    " to False")

            csrf_cookie = cv("CSRF_COOKIE")
            if csrf_cookie and csrf_cookie["key"] and not csrf:
                # Common use case is for cookie value to be used as contents for header
                # which is only looked at when CsrfProtect is initialized.
                # Yes, this is opinionated - they can always get CSRF token via:
                # 'get /login'
                raise ValueError(
                    "CSRF_COOKIE defined however CsrfProtect not part of application"
                )

            if csrf:
                csrf.exempt("flask_security.views.logout")
            if csrf_cookie and csrf_cookie["key"]:
                current_app.after_request(csrf_cookie_handler)
                # Add configured header to WTF_CSRF_HEADERS
                current_app.config["WTF_CSRF_HEADERS"].append(
                    cv("CSRF_HEADER"))

        state._phone_util = state.phone_util_cls(app)
        state._mail_util = state.mail_util_cls(app)

        app.extensions["security"] = state

        if hasattr(app, "cli"):
            from .cli import users, roles

            if state.cli_users_name:
                app.cli.add_command(users, state.cli_users_name)
            if state.cli_roles_name:
                app.cli.add_command(roles, state.cli_roles_name)

        # Migrate from TWO_FACTOR config to generic config.
        for newc, oldc in [
            ("SECURITY_SMS_SERVICE", "SECURITY_TWO_FACTOR_SMS_SERVICE"),
            ("SECURITY_SMS_SERVICE_CONFIG",
             "SECURITY_TWO_FACTOR_SMS_SERVICE_CONFIG"),
            ("SECURITY_TOTP_SECRETS", "SECURITY_TWO_FACTOR_SECRET"),
            ("SECURITY_TOTP_ISSUER", "SECURITY_TWO_FACTOR_URI_SERVICE_NAME"),
        ]:
            if not app.config.get(newc, None):
                app.config[newc] = app.config.get(oldc, None)

        # Check for pre-4.0 SECURITY_USER_IDENTITY_ATTRIBUTES format
        for uia in cv("USER_IDENTITY_ATTRIBUTES", app=app):  # pragma: no cover
            if not isinstance(uia, dict):
                raise ValueError(
                    "SECURITY_USER_IDENTITY_ATTRIBUTES changed semantics"
                    " in 4.0 - please see release notes.")
            if len(list(uia.keys())) != 1:
                raise ValueError(
                    "Each element in SECURITY_USER_IDENTITY_ATTRIBUTES"
                    " must have one and only one key.")

        # Two factor configuration checks and setup
        multi_factor = False
        if cv("UNIFIED_SIGNIN", app=app):
            multi_factor = True
            if len(cv("US_ENABLED_METHODS", app=app)) < 1:
                raise ValueError("Must configure some US_ENABLED_METHODS")
            if "sms" in cv("US_ENABLED_METHODS",
                           app=app) and not get_identity_attribute(
                               "us_phone_number", app=app):
                warnings.warn(
                    "'sms' was enabled in SECURITY_US_ENABLED_METHODS;"
                    " however 'us_phone_number' not configured in"
                    " SECURITY_USER_IDENTITY_ATTRIBUTES")
        if cv("TWO_FACTOR", app=app):
            multi_factor = True
            if len(cv("TWO_FACTOR_ENABLED_METHODS", app=app)) < 1:
                raise ValueError(
                    "Must configure some TWO_FACTOR_ENABLED_METHODS")

        if multi_factor:
            self._check_modules("pyqrcode", "TWO_FACTOR or UNIFIED_SIGNIN")
            self._check_modules("cryptography", "TWO_FACTOR or UNIFIED_SIGNIN")

            need_sms = (cv("UNIFIED_SIGNIN", app=app)
                        and "sms" in cv("US_ENABLED_METHODS", app=app)) or (cv(
                            "TWO_FACTOR", app=app) and "sms" in cv(
                                "TWO_FACTOR_ENABLED_METHODS", app=app))
            if need_sms:
                sms_service = cv("SMS_SERVICE", app=app)
                if sms_service == "Twilio":  # pragma: no cover
                    self._check_modules("twilio", "SMS")
                if state.phone_util_cls == PhoneUtil:
                    self._check_modules("phonenumbers", "SMS")

            secrets = cv("TOTP_SECRETS", app=app)
            issuer = cv("TOTP_ISSUER", app=app)
            if not secrets or not issuer:
                raise ValueError(
                    "Both TOTP_SECRETS and TOTP_ISSUER must be set")
            state.totp_factory(state.totp_cls(secrets, issuer))

        if cv("PASSWORD_COMPLEXITY_CHECKER", app=app) == "zxcvbn":
            self._check_modules("zxcvbn", "PASSWORD_COMPLEXITY_CHECKER")
        return state
Exemplo n.º 23
0
def init_app(app):
    db = init_db(app)
    mongo = PyMongo(app)

    sec = init_model(app)
    app.__version__ = __version__

    admin_obj = admin.Admin(app, name=app.config['SITE_TITLE'],
                            translations_path=os.path.join(
                                app.root_path, 'translations'),
                            base_template='layout.html',
                            template_mode='bootstrap3',
                            index_view=IndexView(
                                name='首页',
                                menu_icon_type='fa',
                                menu_icon_value='fa-home'))

    # WUJG: 针对不同公司的实现,其权限或角色名可能会不同,通过下述机制可以针对不同的公司进行配置
    # 类级的权限配置,该优先级高于用户配置的内容,如果不需要,就无需设置
    # CustomView.view_accept_roles = role_management_dict
    # MongoCustomView.view_accept_roles = role_management_dict

    # Flask-Security 使用Flask-Admin的相关样式
    @sec.context_processor
    def security_context_processor():
        return dict(admin_base_template=admin_obj.base_template,
                    admin_view=admin_obj.index_view,
                    h=admin_helpers,
                    get_url=url_for)

    @sec.login_context_processor
    def security_login_processor():
        year = datetime.datetime.now().year
        return dict(copy_right=app.config['COPYRIGHT_STR'].format(year))

    # 需要处理一些额外的与操作相关的权限设置
    identity_loaded.connect_via(app)(_on_identity_loaded)

    # 机务维修管理配置
    maintain_list = [
        RoutineWorkView, TechMaterialView, TrainingArchiveView,
        TrainigMaterialView, TrainingPlanView, AirworthinessView,
        EngineeringOrderView, MaintenanceRecordView, FaultReportsView,
        TroubleShootingView, ExamineRepairRecordView, RetainView,
        ReservedFaultView,
    ]

    navigational_list = [
        FlightLogView, CompanyDayRecordView, FlightlogStatisticsView,
        FormulaStatisticsView,
    ]

    quality_list = []
    # 航材管理配置
    airmaterial_list = [
        AirmaterialCategoryView, PurchaseApplicationView,
        LendApplicationView, ReturnMaterialOrderView,
        StorageView, DisassembleOrderView,
        BorrowingInReturnView, PutOutStoreView,
        AssembleApplicationView, AssembleView,
        LoanReturnOrderView, LoanApplicationOrderView,
        RepairApplicationView, RepairReturnOrderView,
        ManufacturerView, ScrapView, AirMaterialStorageListView,
        SupplierView, RepairSupplierView, ExpireWarningView,
        StockWarningView, CheckWarningView

    ]

    with app.app_context():
        app.mongodb = mongo.db
        admin_obj.add_view(Y5BView(
            mongo.db, 'y5b', name='维修方案', category=MAINTAINANCE_MANAGEMENT))

    register_view_by_category(
        admin_obj, db.session, maintain_list, MAINTAINANCE_MANAGEMENT)
    register_view_by_category(
        admin_obj, db.session, navigational_list, NAVIGATIONAL_MANAGEMENT)
    register_view_by_category(
        admin_obj, db.session, quality_list, Quality_MANAGEMENT)
    register_view_by_category(
        admin_obj, db.session, airmaterial_list, AIRMATERIAL_MANAGEMENT)
    custom_category_style(admin_obj, MAINTAINANCE_MANAGEMENT, 'fa', 'fa-book')

    with app.app_context():
        admin_obj.add_view(AircraftInformationView(
            mongo.db, AIRCRAFT_COL, 'aircraft', name='机队管理',
            category=MAINTAINANCE_MANAGEMENT))

    # 系统管理配置
    admin_obj.add_view(UserAdminView(db.session, category=SYSTEM_MANAGEMENT))
    admin_obj.add_view(RoleAdminView(db.session, category=SYSTEM_MANAGEMENT))
    admin_obj.add_view(NoticeView(db.session, category=SYSTEM_MANAGEMENT))
    admin_obj.add_view(AnnouncementView(
        db.session, category=SYSTEM_MANAGEMENT))
    admin_obj.add_view(ConfigurationView(category=SYSTEM_MANAGEMENT))
    admin_obj.add_view(
        CheckWaringConfigurationView(category=SYSTEM_MANAGEMENT))
    admin_obj.add_view(
        StockWaringConfigurationView(category=SYSTEM_MANAGEMENT))
    admin_obj.add_view(
        ExpireWaringConfigurationView(category=SYSTEM_MANAGEMENT))
    register_view_by_category(
        admin_obj, db.session, basic_data_views, category=SYSTEM_MANAGEMENT)
    custom_category_style(admin_obj, SYSTEM_MANAGEMENT, 'fa', 'fa-cog')
    custom_category_style(admin_obj, NAVIGATIONAL_MANAGEMENT, 'fa', 'fa-plane')
    custom_category_style(admin_obj, Quality_MANAGEMENT, 'fa', 'fa-sliders')
    custom_category_style(admin_obj, AIRMATERIAL_MANAGEMENT, 'fa', 'fa-cog')

    retrieve_unread_notifies(app)
    flight_log_notice(app)

    return db
def setup_permissions(state):
    identity_loaded.connect_via(state.app)(grant_permissions)
Exemplo n.º 25
0
def register_permissions_loader(app):
    """Register the permissions loader."""
    identity_loaded.connect_via(app)(_load_permissions_on_identity_loaded)
    app.before_first_request(_register_anonymous_loader)
Exemplo n.º 26
0
def create_app(package_name, package_path, settings_override=None, register_security_blueprint=True):
    """
    Create Flask application.
    Currently used modules that need to init includes:

    * `Flask-SQLAlchemy <https://pythonhosted.org/Flask-SQLAlchemy>`_
    * `Flask-Mail <http://pythonhosted.org/Flask-Mail/>`_
    * `Flask-Babel <http://pythonhosted.org/Flask-Babel/>`_
    * `Flask-Security <http://pythonhosted.org/Flask-Security/>`_
    * `Flask-Amdin(only init from the frontend) <http://flask-admin.readthedocs.org/en/latest/index.html>`_

    :param package_name: package name of the dxc.
    :param package_path: package path of the dxc.
    :param settings_override: setting that will override the existed setting items.
    :param register_security_blueprint: flag to specify if the Flask-Security to register blueprint or not.
    """
    app = Flask(package_name, instance_relative_config=True)
    # 增加matrix转换器
    app.url_map.converters['matrix'] = MatrixConverter


    # principal
    identity_loaded.connect_via(app)(_app_on_identity_loaded)
    # 公共配置
    app.config.from_object(setting)
    # 可以被覆盖的配置,如在测试情况里
    app.config.from_object(settings_override)
    # 加载security翻译配置
    if app.config.has_key('SECURITY_TRANSLATION_PATH'):
        import importlib
        security_translate = importlib.import_module(app.config['SECURITY_TRANSLATION_PATH'])
        app.config.from_object(security_translate)

    # 使用这样的方式init,不能调用db.create_all()
    db.init_app(app)

    mail.init_app(app)

    # init babel
    babel.init_app(app)

    # init Flask-Security
    security_datastore = SQLAlchemyUserDatastore(db, User, Role)
    security.init_app(app, security_datastore, register_blueprint=register_security_blueprint)

    # 注册view
    register_blueprints(app, package_name, package_path)

    # 邮件log
    if not app.debug and not app.testing:
        import logging
        from logging.handlers import RotatingFileHandler
        mail_handler = SslSTMPHandler((app.config['MAIL_SERVER'], app.config['MAIL_PORT']),
                                      app.config['MAIL_DEFAULT_SENDER'],
                                      app.config['ADMINS'], 'kinoris.com  failed!',
                                      credentials=(app.config['MAIL_USERNAME'], app.config['MAIL_PASSWORD']))
        mail_handler.setLevel(logging.ERROR)
        mail_handler.setFormatter(
            logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
        app.logger.addHandler(mail_handler)

        # 文件log
        import os
        if not os.path.exists(app.config['LOGGING_DIR']):
            os.makedirs(app.config['LOGGING_DIR'])

        # 一般日志
        file_handler = RotatingFileHandler(os.path.join(app.config['LOGGING_DIR'], 'app.log'), mode='a',
                                           maxBytes=5 * 1024 * 1024, backupCount=10, encoding='utf-8')
        file_handler.setFormatter(
            logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
        file_handler.setLevel(logging.INFO)
        app.logger.addHandler(file_handler)

        # 错误日志
        file_handler_error = RotatingFileHandler(os.path.join(app.config['LOGGING_DIR'], 'app_error.log'), mode='a',
                                                 maxBytes=5 * 1024 * 1024, backupCount=10, encoding='utf-8')
        file_handler_error.setFormatter(
            logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
        file_handler_error.setLevel(logging.ERROR)
        app.logger.addHandler(file_handler_error)

        # 默认log
        app.logger.setLevel(logging.INFO)
        app.logger.info(str.format('{0} startup.', app.name))

    return app
Exemplo n.º 27
0
 def _init_principal(self):
     self.principal = Principal(self.app, use_sessions=False)
     self.principal.identity_loader = self._identity_loader
     identity_loaded.connect_via(self.app)(self._on_identity_loaded)
Exemplo n.º 28
0
    def init_app(self, app, datastore=None, register_blueprint=None, **kwargs):
        """Initializes the Flask-Security extension for the specified
        application and datastore implementation.

        :param app: The application.
        :param datastore: An instance of a user datastore.
        :param register_blueprint: to register the Security blueprint or not.
        """
        self.app = app

        if datastore is None:
            datastore = self._datastore

        if register_blueprint is None:
            register_blueprint = self._register_blueprint

        for key, value in self._kwargs.items():
            kwargs.setdefault(key, value)

        if "render_template" not in kwargs:
            kwargs.setdefault("render_template", self.render_template)
        if "send_mail" not in kwargs:
            kwargs.setdefault("send_mail", self.send_mail)

        for key, value in _default_config.items():
            app.config.setdefault("SECURITY_" + key, value)

        for key, value in _default_messages.items():
            app.config.setdefault("SECURITY_MSG_" + key, value)

        identity_loaded.connect_via(app)(_on_identity_loaded)

        self._state = state = _get_state(app, datastore, **kwargs)

        if register_blueprint:
            app.register_blueprint(create_blueprint(state, __name__))
            app.context_processor(_context_processor)

        @app.before_first_request
        def _register_i18n():
            if "_" not in app.jinja_env.globals:
                app.jinja_env.globals["_"] = state.i18n_domain.gettext

        app.extensions["security"] = state

        if hasattr(app, "cli"):
            from .cli import users, roles

            if state.cli_users_name:
                app.cli.add_command(users, state.cli_users_name)
            if state.cli_roles_name:
                app.cli.add_command(roles, state.cli_roles_name)

        # Two factor configuration checks and setup
        if cv("TWO_FACTOR", app=app):
            if len(cv("TWO_FACTOR_ENABLED_METHODS", app=app)) < 1:
                raise ValueError(
                    "Must configure some TWO_FACTOR_ENABLED_METHODS")
            self.check_two_factor_modules("pyqrcode", "TWO_FACTOR",
                                          cv("TWO_FACTOR", app=app))
            self.check_two_factor_modules("cryptography", "TWO_FACTOR_SECRET",
                                          "has been set")

            if cv("TWO_FACTOR_SMS_SERVICE",
                  app=app) == "Twilio":  # pragma: no cover
                self.check_two_factor_modules(
                    "twilio",
                    "TWO_FACTOR_SMS_SERVICE",
                    cv("TWO_FACTOR_SMS_SERVICE", app=app),
                )
            state.totp_factory(tf_setup(app))

        return state
Exemplo n.º 29
0
    def init_app(self, app, datastore=None, register_blueprint=None, **kwargs):
        """Initializes the Flask-Security extension for the specified
        application and datastore implementation.

        :param app: The application.
        :param datastore: An instance of a user datastore.
        :param register_blueprint: to register the Security blueprint or not.
        """
        self.app = app

        if datastore is None:
            datastore = self._datastore

        if register_blueprint is None:
            register_blueprint = self._register_blueprint

        for key, value in self._kwargs.items():
            kwargs.setdefault(key, value)

        if "render_template" not in kwargs:
            kwargs.setdefault("render_template", self.render_template)
        if "json_encoder_cls" not in kwargs:
            kwargs.setdefault("json_encoder_cls", FsJsonEncoder)
        if "totp_cls" not in kwargs:
            kwargs.setdefault("totp_cls", Totp)

        for key, value in _default_config.items():
            app.config.setdefault("SECURITY_" + key, value)

        for key, value in _default_messages.items():
            app.config.setdefault("SECURITY_MSG_" + key, value)

        identity_loaded.connect_via(app)(_on_identity_loaded)

        self._state = state = _get_state(app, datastore, **kwargs)

        if register_blueprint:
            bp = create_blueprint(state,
                                  __name__,
                                  json_encoder=kwargs["json_encoder_cls"])
            app.register_blueprint(bp)
            app.context_processor(_context_processor)

        @app.before_first_request
        def _register_i18n():
            # N.B. as of jinja 2.9 '_' is always registered
            # http://jinja.pocoo.org/docs/2.10/extensions/#i18n-extension
            if "_" not in app.jinja_env.globals:
                current_app.jinja_env.globals["_"] = state.i18n_domain.gettext
            # Register so other packages can reference our translations.
            current_app.jinja_env.globals[
                "_fsdomain"] = state.i18n_domain.gettext

        @app.before_first_request
        def _csrf_init():
            # various config checks - some of these are opinionated in that there
            # could be a reason for some of these combinations - but in general
            # they cause strange behavior.
            # WTF_CSRF_ENABLED defaults to True if not set in Flask-WTF
            if not current_app.config.get("WTF_CSRF_ENABLED", True):
                return
            csrf = current_app.extensions.get("csrf", None)

            # If they don't want ALL mechanisms protected, then they must
            # set WTF_CSRF_CHECK_DEFAULT=False so that our decorators get control.
            if cv("CSRF_PROTECT_MECHANISMS") != AUTHN_MECHANISMS:
                if not csrf:
                    # This isn't good.
                    raise ValueError("CSRF_PROTECT_MECHANISMS defined but"
                                     " CsrfProtect not part of application")
                if current_app.config.get("WTF_CSRF_CHECK_DEFAULT", True):
                    raise ValueError(
                        "WTF_CSRF_CHECK_DEFAULT must be set to False if"
                        " CSRF_PROTECT_MECHANISMS is set")
            # We don't get control unless they turn off WTF_CSRF_CHECK_DEFAULT if
            # they have enabled global CSRFProtect.
            if (cv("CSRF_IGNORE_UNAUTH_ENDPOINTS")
                    and csrf and current_app.config.get(
                        "WTF_CSRF_CHECK_DEFAULT", False)):
                raise ValueError(
                    "To ignore unauth endpoints you must set WTF_CSRF_CHECK_DEFAULT"
                    " to False")

            csrf_cookie = cv("CSRF_COOKIE")
            if csrf_cookie and csrf_cookie["key"] and not csrf:
                # Common use case is for cookie value to be used as contents for header
                # which is only looked at when CsrfProtect is initialized.
                # Yes, this is opinionated - they can always get CSRF token via:
                # 'get /login'
                raise ValueError(
                    "CSRF_COOKIE defined however CsrfProtect not part of application"
                )

            if csrf:
                csrf.exempt("flask_security.views.logout")
            if csrf_cookie and csrf_cookie["key"]:
                current_app.after_request(csrf_cookie_handler)
                # Add configured header to WTF_CSRF_HEADERS
                current_app.config["WTF_CSRF_HEADERS"].append(
                    cv("CSRF_HEADER"))

        app.extensions["security"] = state

        if hasattr(app, "cli"):
            from .cli import users, roles

            if state.cli_users_name:
                app.cli.add_command(users, state.cli_users_name)
            if state.cli_roles_name:
                app.cli.add_command(roles, state.cli_roles_name)

        # Two factor configuration checks and setup
        if cv("TWO_FACTOR", app=app):
            if len(cv("TWO_FACTOR_ENABLED_METHODS", app=app)) < 1:
                raise ValueError(
                    "Must configure some TWO_FACTOR_ENABLED_METHODS")
            self._check_modules("pyqrcode", "TWO_FACTOR",
                                cv("TWO_FACTOR", app=app))
            self._check_modules("cryptography", "TWO_FACTOR_SECRET",
                                "has been set")

            if cv("TWO_FACTOR_SMS_SERVICE",
                  app=app) == "Twilio":  # pragma: no cover
                self._check_modules(
                    "twilio",
                    "TWO_FACTOR_SMS_SERVICE",
                    cv("TWO_FACTOR_SMS_SERVICE", app=app),
                )
            secrets = cv("TWO_FACTOR_SECRET", app=app)
            issuer = cv("TWO_FACTOR_URI_SERVICE_NAME", app=app)
            state.totp_factory(state.totp_cls(secrets, issuer))

        if cv("USE_VERIFY_PASSWORD_CACHE", app=app):
            self._check_modules("cachetools", "USE_VERIFY_PASSWORD_CACHE",
                                True)

        return state
Exemplo n.º 30
0
def create_app(test_config=None):
    from flowauth.config import get_config
    from flowauth.models import db
    from flowauth.cli import (
        init_db_command,
        add_admin_command,
        make_flowauth_fernet_key,
        demo_data,
    )
    from .admin import blueprint as admin_blueprint
    from .users import blueprint as users_blueprint
    from .groups import blueprint as groups_blueprint
    from .servers import blueprint as servers_blueprint
    from .token_management import blueprint as token_management_blueprint
    from .login import blueprint as login_blueprint
    from .user_settings import blueprint as user_settings_blueprint
    from .version import blueprint as version_blueprint

    app = Flask(__name__)

    app.config.from_mapping(get_config())

    # Connect the logger
    app.before_first_request(connect_logger)

    if test_config is not None:
        # load the test config if passed in
        app.config.update(test_config)

    # Connect the db

    db.init_app(app)

    # Set up flask-login
    login_manager = LoginManager()
    login_manager.init_app(app)

    # Set up flask-principal for roles management
    principals = Principal()
    principals.init_app(app)

    # Set up csrf protection
    csrf = CSRFProtect()
    csrf.init_app(app)
    csrf.exempt(login_blueprint)
    csrf.exempt(version_blueprint)

    app.register_blueprint(login_blueprint)
    app.register_blueprint(admin_blueprint, url_prefix="/admin")
    app.register_blueprint(groups_blueprint, url_prefix="/admin")
    app.register_blueprint(servers_blueprint, url_prefix="/admin")
    app.register_blueprint(users_blueprint, url_prefix="/admin")
    app.register_blueprint(token_management_blueprint, url_prefix="/tokens")
    app.register_blueprint(user_settings_blueprint, url_prefix="/user")

    app.register_blueprint(version_blueprint)

    if app.config["DEMO_MODE"]:  # Create demo data
        from flowauth.models import make_demodata

        app.before_first_request(make_demodata)
    else:
        # Initialise the database
        from flowauth.models import init_db
        from flowauth.models import add_admin

        app.before_first_request(lock(partial(init_db, force=app.config["RESET_DB"])))
        # Create an admin user

        app.before_first_request(
            lock(
                partial(
                    add_admin,
                    username=app.config["ADMIN_USER"],
                    password=app.config["ADMIN_PASSWORD"],
                )
            )
        )

    app.before_first_request(
        app.config["DB_IS_SET_UP"].wait
    )  # Cause workers to wait for db to set up

    app.after_request(set_xsrf_cookie)
    app.errorhandler(CSRFError)(handle_csrf_error)
    app.errorhandler(InvalidUsage)(handle_invalid_usage)
    app.before_request(before_request)
    login_manager.user_loader(load_user)
    identity_loaded.connect_via(app)(on_identity_loaded)
    # Add flask <command> CLI commands
    app.cli.add_command(demo_data)
    app.cli.add_command(init_db_command)
    app.cli.add_command(add_admin_command)
    app.cli.add_command(make_flowauth_fernet_key)
    return app