Git Product home page Git Product logo

flask-rbac's Introduction

Build Status Coverage Status PyPI Version

Flask-RBAC

Adds RBAC support to Flask

Installation

$ pip install flask-rbac

Links

Contributes

You can send a pull request on GitHub.

flask-rbac's People

Contributors

aurigadl avatar carlosgalvez-tiendeo avatar dependabot[bot] avatar joe-gordian-software avatar lixxu avatar shonenada avatar tonyseek avatar trendsetter37 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flask-rbac's Issues

RoleMixin __init__ hasattr fails

I have a class Role as follows (following your example in the docs):

class Role(Base, RoleMixin):

    id = Column(Integer, primary_key=True)
    name = Column(String(20))
    parents = relationship(
        'Role',
        secondary=roles_parents,
        primaryjoin=(id == roles_parents.c.role_id),
        secondaryjoin=(id == roles_parents.c.parent_id),
        backref=backref('children', lazy='joined'),
        lazy='joined'
    )

    def __init__(self, name):
        RoleMixin.__init__(self)
        self.name = name
...

However in Python 3.6.3 with flask-rbac 0.2.1 I have some problems.

$ pip show flask-rbac
Name: Flask-RBAC
Version: 0.2.1
Summary: RBAC support for Flask
Home-page: https://github.com/shonenada/flask-rbac
Author: Yaoda Liu
Author-email: [email protected]
License: UNKNOWN
Location: c:\program files (x86)\python\lib\site-packages
Requires: Flask
Required-by:

I can narrow it down to the RoleMixin.init:

    def __init__(self, name=None):
        self.name = name
        if not hasattr(self.__class__, 'parents'):
            self.parents = set()
        if not hasattr(self.__class__, 'children'):
            self.children = set()
        RoleMixin.roles[name] = self

hasattr(self.class, 'parents') returns False
hasattr(self.class, 'children') returns False

I would expect the Role class to have a parent attribute and therefor this method to return False.
In my case, self.parents and self.children get set to set() which messes up the rest of the method calls when checking for an access control decision.

I believe children and parents should be set by my class. Parents are already set to the relationship and children are set via SQLAlchemy via a backref. This is probably done dynamically and might explain why hasattr(self.class, 'children') returns False.

It is unclear to me why hasattr(self.class, 'parents') returns False in my case.

view function address may change

I added deny rules for test function:
@rbac.deny(['admin'], methods=['POST', 'GET'])
def verify_test():
...
checked self._denied in init.py:
[(u'admin', 'POST', <function verify_test at 0x7f7b203282a8>), (u'admin', 'GET', <function verify_test at 0x7f7b203282a8>)]

Then I send request to verify_test, check verify_test fucntion address, found it has been changed, so this deny rules could not work!
<function verify_test at 0x7f7b20328050>

Have you met this issue?

'RBAC' object has no attribute 'as_role_model'

The last version when I install with "pip install flask-rbac" the library does not have some method like as_role_model, but they are in the repository.

when I install with "pip install git+https://github.com/shonenada/flask-rbac" is all is well

Flask_RBAC-0.2.0-py2.7.egg-info
pip 1.5.6
Python 2.7.6

Unable to use @rbac.exempt with Blueprints

PR-29 Added the ability to specify endpoints for the @rbac.allow and @rbac.deny to allow them to play nicely with blueprints

@rbac.exempt still uses the view_func.__name__ and hence, doesn't work with blueprints. For backwards compatibility, I suppose it might be useful to provide another exempt function that can take an endpoint parameter

If this is affecting any, the work around to inhert the RBAC and redefine the exempt decorator

class MRBAC(RBAC):
    def exempt(self, endpoint=None):
        def decorator(view_func):
            self.acl.exempt(endpoint or view_func.__name__)
            return view_func

        return decorator

rbac = MRBAC()

@blueprint.route('/everyone/can/access')
@rbac.exempt(endpoint='blueprint.everyone_can_access')
def everyone_can_access():
    return 'Hello~'

flask.ext.rbac extension hook deprecation error

When going through the quick start and using

from flask import Flask
from flask.ext.rbac import RBAC

app = Flask(__name__)
rbac = RBAC(app)

I receive the following error.

.../lib/python3.5/site-packages/flask/exthook.py:71: ExtDeprecationWarning: Importing flask.ext.rbac is deprecated, use flask_rbac instead.
  .format(x=modname), ExtDeprecationWarning

Changing the import statement as suggested prevents the warning.

TypeError: <app.models.user.AnonymousUser object at 0x7fd11ad8a590> is not an instance of <class 'flask_sqlalchemy._ BoundDeclarativeMeta'>

I was trying to use flask_rbac with flask_Login Manager AnonymousUserMixin.
my Role Model
`
from app import db, rbac
from flask_rbac import RoleMixin

roles_parents = db.Table(
'roles_parents',
db.Column('role_id', db.Integer, db.ForeignKey('role.id')),
db.Column('parent_id', db.Integer, db.ForeignKey('role.id'))
)

@rbac.as_role_model
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20))
date_created = db.Column(db.DateTime, default=db.func.current_timestamp())
date_modified = db.Column(db.DateTime, default=db.func.current_timestamp(
), onupdate=db.func.current_timestamp())
parents = db.relationship(
'Role',
secondary=roles_parents,
primaryjoin=(id == roles_parents.c.role_id),
secondaryjoin=(id == roles_parents.c.parent_id),
backref=db.backref('children', lazy='dynamic')
)

def __init__(self, name):
    RoleMixin.__init__(self)
    self.name = name

def add_parent(self, parent):
    # You don't need to add this role to parent's children set,
    # relationship between roles would do this work automatically
    self.parents.append(parent)

def add_parents(self, *parents):
    for parent in parents:
        self.add_parent(parent)

@staticmethod
def get_by_name(name):
    return Role.query.filter_by(name=name).first()

def __repr__(self):
    return 'Role <%r>' % self.name`

###My User Model:
`
import flask_login as fl
@rbac.as_user_model
class User(UserMixin, db.Model, fl.UserMixin):

 id = db.Column(db.Integer, primary_key=True)
# User Name
username = db.Column(db.String(128), nullable=False,
                     unique=True, index=True)
# Identification Data: email & password
email = db.Column(db.String(128), nullable=False, index=True)
password_hash = db.Column(db.String(128), nullable=False)
# Authorisation Data: role & status

status = db.Column(db.SmallInteger, nullable=True, default=True)
# New instance instantiation procedure
date_created = db.Column(db.DateTime, default=db.func.current_timestamp())
date_modified = db.Column(db.DateTime, default=db.func.current_timestamp(
), onupdate=db.func.current_timestamp())
roles = db.relationship(
    'Role',
    secondary=users_roles,
    backref=db.backref('roles', lazy='dynamic')
)

@loginManager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
`

I use a separate AnonymousUser class to handle Anonymous user. the main reason is to protect my flask-admin routes from unauthorized entry.
`
from flask_login import AnonymousUserMixin
class AnonymousUser(fl.AnonymousUserMixin):
'''
Added this to protect flask-admin blueprint
'''

def is_admin(self):
    return False

loginManager.anonymous_user = AnonymousUserI get following error:File "/home/rezwan/visual_code_projects/flask_boilerplate_new/venv/lib/python2.7/site-packages/flask_rbac/init.py", line 362, in _authenticate
(current_user, self.user_model.class))
TypeError: <app.models.user.AnonymousUser object at 0x7fe2fd7085d0> is not an instance of <class 'flask_sqlalchemy.

BoundDeclarativeMeta'>If I don't use tha class I get follwing error:TypeError: <flask_login.mixins.AnonymousUserMixin object at 0x7f9b97dbd410> is not an instance of <class 'flask_sqlalchemy._BoundDeclarativeMeta'>`

What is the proper way to handle anonymous user or use rbac with AnonymousUSerMixin

Flask version 3 and _request_ctx_stack

_request_ctx_stack is depreciated in flask v3, any plans to update?

`
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

import flask
from flask_rbac import RBAC
Traceback (most recent call last):
File "", line 1, in
File "/home/work/BRF/backend/env/lib/python3.10/site-packages/flask_rbac/init.py", line 12, in
from flask import request, abort, _request_ctx_stack
ImportError: cannot import name '_request_ctx_stack' from 'flask' (/home/work/BRF/backend/env/lib/python3.10/site-packages/flask/init.py)
print(flask.version)
:1: DeprecationWarning: The 'version' attribute is deprecated and will be removed in Flask 3.1. Use feature detection or 'importlib.metadata.version("flask")' instead.
3.0.0

`

in get_current_user

There appears to be a typo in the docs. Currently in get_current_user you have:

def get_current_user():
    with curren_app.request_context():
        return g.current_user

But shouldn't it be:

def get_current_user():
    with current_app.request_context():
        return g.current_user

anonymous role when RBAC_USE_WHITE = true doesn't work

When the white list is placed as true, it don't make successful validations for the anonymous role.
I'm not using flask-login, maybe this influence but I make the changes in the source code and now you can place the decorator @rbac.allow ([ 'anonymous'] methods = [ 'GET'], with_children = False) and working properly.

Unable to use Flask-FontAwesome: the css and js are 403 blocked

Note, I have app.config['RBAC_USE_WHITE'] = True in my app.

This issue probably applies to other packages that initialise the css/js from the app and include it in the html headers like

<head>
    ...
    {{ fontawesome_html() }}
    ...
</head>

The solution in my case is to exempt the endpoint "fontawesome.static". Decided to work-around thusly in order to populate the _exempt list for each instance:

MRBAC.py

from flask_rbac import RBAC


class MRBAC(RBAC):

    ADDITIONAL_EXEMPTIONS = [
        "fontawesome.static"
    ]

    def __init__(self):
        super().__init__()
        self.do_additional_exemptions()

    def do_additional_exemptions(self):
        for e in self.ADDITIONAL_EXEMPTIONS:
            self.acl.exempt(e)


rbac = MRBAC()

and in the application's init.py:

from app.MRBAC import MRBAC
rbac = MRBAC()

Typo in documentation

There is a typo in the documentation. When setting multiple roles, the function name should be 'add_roles', as shown below.

`

def add_role(self, role):
    self.roles.append(role)

def add_roles(self, roles):
    for role in roles:
        self.add_role(role)

def get_roles(self):
    for role in self.roles:
        yield role`

AttributeError: 'Flask' object has no attribute 'before_first_request'.

It seems that flask_rbac is using deprecated API. before_first_request is no longer supported.

 Traceback (most recent call last):
   File "app/uwsgi.py", line 4, in <module>
     app = create_app()
           ^^^^^^^^^^^^
   File "/opt/www/gaas-bms/app/__init__.py", line 32, in create_app
     rbac.init_app(app)
   File "/opt/www/gaas-bms/venv/lib64/python3.11/site-packages/flask_rbac/__init__.py", line 179, in init_app
     app.before_first_request(self._setup_acl)
     ^^^^^^^^^^^^^^^^^^^^^^^^
 AttributeError: 'Flask' object has no attribute 'before_first_request'.

flask.ext.login import Warning

relates to issue #13.

The offending code is located in the flask_rbac/__init__.py file.

try:
    from flask.ext.login import current_user
except ImportError:
    current_user = None

This yiels a

ExtDeprecationWarning: Importing flask.ext.login is deprecated, use flask_login instead.

warning.

Implementation issue

Hi
Currently, I'm trying to R&D RBAC authorization mechanism for my flask API, I read your project documentation and other RBAC implementations in a few projects, but in your project, I can't see any permissions, in RBAC implementation like K8s (rbac.authorization.k8s/v1) we assign some permissions to our specific role like watch, list and get operations on pods resources to my-test-role

like this:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: my-test-role 
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

or in this RBAC implementation (repository) we can set access permissions on our roles like this:

acl.resource_read_rule(everyone_role, 'GET', '/api/v1/employee/1/info')
acl.resource_delete_rule(admin_role, 'DELETE', '/api/v1/employee/1/')

and I think something like this may be good in flask...

from enum import Enum
from flask import blueprints

class Permission(Enum):
    READ="READ"
    CREATE="CREATE"
    UPDATE="UPDATE"
    DELETE="DELETE"
    
class Roles(Enum):
    OWNER = {Permission.CREATE,Permission.READ,Permission.UPDATE,Permission.DELETE}
    ADMIN = {Permission.CREATE,Permission.READ,Permission.UPDATE}
    USER  = {Permission.READ}

    
resource = blueprints("routes",__name__)

#
# (User PUT request).roles = [ADMIN,USER]
#        |
#        โ†“ 
@resource.route("/product/update",["PUT"])
@rbac.allow(allow_perms={Permission.UPDATE}) # This decorator will check if the user has any role that have this permission
def update_product():
    pass

We assign permission to resources(in Flask API probably our routes) and permissions to roles and roles to users.

Thank you for your attention.

allow() with "with_children=true" not working for child roles

Referring to the unit test as an example, my expectation is that accessing /e as a staff_role_user should work because staff_role_user is a child of everyone. But from my testing, this is not true.

  @app.route('/e')
  @after_decorator
  @rbac.deny(roles=['everyone'], methods=['GET'], with_children=True)
  @before_decorator
  def e():
      return Response('Hello from /e')
.
.
.
  def test_allow_get_view(self):
      global current_user
      current_user = normal_user
      self.assertEqual(self.client.open('/d').data.decode('utf-8'), 'Hello from /d')

      current_user = staff_role_user
      self.assertEqual(self.client.open('/d').data.decode('utf-8'), 'Hello from /d')
      self.assertEqual(self.client.open('/e').data.decode('utf-8'), 'Hello from /e') #Condition not tested

My suspicion is that during the _setup_acl method, there is no check for acls already in the allow list before adding to deny list AND with_children needs to be removed so that allow's with_children can take effect.


        for rn, method, resource, with_children in self.before_acl['deny']:
            role = self._role_model.get_by_name(rn)
            if not self.acl.is_allowed(rn,method,resource): #This check is missing
                self.acl.deny(role, method, resource) #with_children needs to be removed


I'm new to flask-rbac, appreciate if someone can confirm my findings above.

Thank you.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.