[GH-ISSUE #114] Add role based security or any kind of access control #58

Open
opened 2026-02-26 01:33:01 +03:00 by kerem · 4 comments
Owner

Originally created by @supersexy on GitHub (Jul 11, 2019).
Original GitHub issue: https://github.com/jeffknupp/sandman2/issues/114

Interesting project, but I can not find any hint about how to control access to data, also the documentation does not provide any concept regarding data security.

Some kind of access control system seems like a very basic requirement for any data access software - is this something that is planned for the future?

Originally created by @supersexy on GitHub (Jul 11, 2019). Original GitHub issue: https://github.com/jeffknupp/sandman2/issues/114 Interesting project, but I can not find any hint about how to control access to data, also the documentation does not provide any concept regarding data security. Some kind of access control system seems like a very basic requirement for any data access software - is this something that is planned for the future?
Author
Owner

@dkatz23238 commented on GitHub (Oct 12, 2019):

This would be a killer feature. Currently using nginx as a proxy.

<!-- gh-comment-id:541338890 --> @dkatz23238 commented on GitHub (Oct 12, 2019): This would be a killer feature. Currently using nginx as a proxy.
Author
Owner

@Carelvd commented on GitHub (Nov 5, 2019):

If one cracks open the code one finds the following for the create application method

def get_app(
        database_uri,
        exclude_tables=None,
        user_models=None,
        reflect_all=True,
        read_only=False,
        schema=None):
    """..."""
    app = Flask('sandman2')
    app.config['SQLALCHEMY_DATABASE_URI'] = database_uri
    app.config['SANDMAN2_READ_ONLY'] = read_only
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    app.classes = []
    db.init_app(app)
    admin = Admin(app, base_template='layout.html', template_mode='bootstrap3')
    _register_error_handlers(app)
    if user_models:
        with app.app_context():
            _register_user_models(user_models, admin, schema=schema)
    elif reflect_all:
        with app.app_context():
            _reflect_all(exclude_tables, admin, read_only, schema=schema)

    @app.route('/')
    def index():
        """Return a list of routes to the registered classes."""
        routes = {}
        for cls in app.classes:
            routes[cls.__model__.__name__] = '{}{{/{}}}'.format(
                cls.__model__.__url__,
                cls.__model__.primary_key())
        return jsonify(routes)
    return app

Which one can restructure as follows

def create_app(
        database_uri,
        exclude_tables=None,
        user_models=None,
        reflect_all=True,
        read_only=False,
        schema=None):
    app = Flask('sandman2')
    app.config['SQLALCHEMY_DATABASE_URI'] = database_uri
    app.config['SANDMAN2_READ_ONLY'] = read_only
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    app.classes = []
    sandman(
        application,
        database_uri,
        exclude_tables=None,
        user_models=None,
        reflect_all=True,
        read_only=False,
        schema=None)
    
def sandman(
        application,
        database_uri,
        exclude_tables=None,
        user_models=None,
        reflect_all=True,
        read_only=False,
        schema=None):
    """..."""
    db.init_app(application)
    admin = Admin(application, base_template='layout.html', template_mode='bootstrap3')
    _register_error_handlers(application)
    if user_models:
        with application.app_context():
            _register_user_models(user_models, admin, schema=schema)
    elif reflect_all:
        with application.app_context():
            _reflect_all(exclude_tables, admin, read_only, schema=schema)

    @application.route('/')
    def index():
        """Return a list of routes to the registered classes."""
        routes = {}
        for cls in application.classes:
            routes[cls.__model__.__name__] = '{}{{/{}}}'.format(
                cls.__model__.__url__,
                cls.__model__.primary_key())
        return jsonify(routes)

Once this is done it becomes rather trivial to add security to the application.

from flask_jwt_extended import JWTManager

def create_app(
        database_uri,
        exclude_tables=None,
        user_models=None,
        reflect_all=True,
        read_only=False,
        schema=None):
    app = Flask('sandman2')
    app.config['SQLALCHEMY_DATABASE_URI'] = database_uri
    app.config['SANDMAN2_READ_ONLY'] = read_only
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    app.classes = []
    jwt = JWTManager(app)
    sandman(
        application,
        database_uri,
        exclude_tables=None,
        user_models=None,
        reflect_all=True,
        read_only=False,
        schema=None)

Then add the endpoints one wants as necessary. Similarly it is possible to secure ones administration interface by adding say Flask-Login but one must also then subclass the AdminView and AdminIndexView and pass these through the the Admin invocation in the "new" sandman method.

I have submitted a PR that already does this refactoring and am awaiting its acceptance.

<!-- gh-comment-id:550055216 --> @Carelvd commented on GitHub (Nov 5, 2019): If one cracks open the code one finds the following for the create application method def get_app( database_uri, exclude_tables=None, user_models=None, reflect_all=True, read_only=False, schema=None): """...""" app = Flask('sandman2') app.config['SQLALCHEMY_DATABASE_URI'] = database_uri app.config['SANDMAN2_READ_ONLY'] = read_only app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.classes = [] db.init_app(app) admin = Admin(app, base_template='layout.html', template_mode='bootstrap3') _register_error_handlers(app) if user_models: with app.app_context(): _register_user_models(user_models, admin, schema=schema) elif reflect_all: with app.app_context(): _reflect_all(exclude_tables, admin, read_only, schema=schema) @app.route('/') def index(): """Return a list of routes to the registered classes.""" routes = {} for cls in app.classes: routes[cls.__model__.__name__] = '{}{{/{}}}'.format( cls.__model__.__url__, cls.__model__.primary_key()) return jsonify(routes) return app Which one can restructure as follows def create_app( database_uri, exclude_tables=None, user_models=None, reflect_all=True, read_only=False, schema=None): app = Flask('sandman2') app.config['SQLALCHEMY_DATABASE_URI'] = database_uri app.config['SANDMAN2_READ_ONLY'] = read_only app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.classes = [] sandman( application, database_uri, exclude_tables=None, user_models=None, reflect_all=True, read_only=False, schema=None) def sandman( application, database_uri, exclude_tables=None, user_models=None, reflect_all=True, read_only=False, schema=None): """...""" db.init_app(application) admin = Admin(application, base_template='layout.html', template_mode='bootstrap3') _register_error_handlers(application) if user_models: with application.app_context(): _register_user_models(user_models, admin, schema=schema) elif reflect_all: with application.app_context(): _reflect_all(exclude_tables, admin, read_only, schema=schema) @application.route('/') def index(): """Return a list of routes to the registered classes.""" routes = {} for cls in application.classes: routes[cls.__model__.__name__] = '{}{{/{}}}'.format( cls.__model__.__url__, cls.__model__.primary_key()) return jsonify(routes) Once this is done it becomes rather trivial to add security to the application. from flask_jwt_extended import JWTManager def create_app( database_uri, exclude_tables=None, user_models=None, reflect_all=True, read_only=False, schema=None): app = Flask('sandman2') app.config['SQLALCHEMY_DATABASE_URI'] = database_uri app.config['SANDMAN2_READ_ONLY'] = read_only app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.classes = [] jwt = JWTManager(app) sandman( application, database_uri, exclude_tables=None, user_models=None, reflect_all=True, read_only=False, schema=None) Then add the endpoints one wants as necessary. Similarly it is possible to secure ones administration interface by adding say ``Flask-Login`` but one must also then subclass the ``AdminView`` and ``AdminIndexView`` and pass these through the the ``Admin`` invocation in the "new" ``sandman`` method. I have submitted a PR that already does this refactoring and am awaiting its acceptance.
Author
Owner

@zeluspudding commented on GitHub (Jan 28, 2020):

Yes, authentication is a must. I believe sandman1 had it. Was expecting sandman2 to do it better... not less... But I as a beggar cannot be a boss. But we can choose another approach, such as dreamfactory. Will start playing with that now... hopefully it's not crazy hard to setup.

<!-- gh-comment-id:579367570 --> @zeluspudding commented on GitHub (Jan 28, 2020): Yes, authentication is a must. I believe `sandman1` had it. Was expecting `sandman2` to do it better... not less... But I as a beggar cannot be a boss. But we can choose another approach, such as dreamfactory. Will start playing with that now... hopefully it's not crazy hard to setup.
Author
Owner

@Carelvd commented on GitHub (Jan 28, 2020):

@zeluspudding My example above was meant to illustrate that forcing a security solution upon the user is unnecessary and that, with minor refactoring of the code, it becomes trivial for persons using the library to set this up.

To setup security layer for the interim one need only copy the create_app/get_app code and extend it yourself, as I have above. There are multiple libraries that deal with this e.g. flask_jwt, flask_jwt_extended, flask-login and the like.

@jeffknupp When my PR is accepted/rejected I will push up my documentation for the changes and I can happily document the methods by which security can be added.

<!-- gh-comment-id:579384966 --> @Carelvd commented on GitHub (Jan 28, 2020): @zeluspudding My example above was meant to illustrate that forcing a security solution upon the user is unnecessary and that, with minor refactoring of the code, it becomes trivial for persons using the library to set this up. To setup security layer for the interim one need only copy the `create_app`/`get_app` code and extend it yourself, as I have above. There are multiple libraries that deal with this e.g. flask_jwt, flask_jwt_extended, flask-login and the like. @jeffknupp When my PR is accepted/rejected I will push up my documentation for the changes and I can happily document the methods by which security can be added.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/sandman2-jeffknupp#58
No description provided.