GithubHelp home page GithubHelp logo

casbin / pycasbin Goto Github PK

View Code? Open in Web Editor NEW
1.3K 27.0 182.0 514 KB

An authorization library that supports access control models like ACL, RBAC, ABAC in Python

Home Page: https://casbin.org

License: Apache License 2.0

Python 100.00%
casbin python pycasbin access-control authorization rbac abac acl auth authz

pycasbin's Introduction

PyCasbin

GitHub Action Coverage Status Version PyPI - Wheel Pyversions Download Discord

Sponsored by

Build auth with fraud prevention, faster.
Try Stytch for API-first authentication, user & org management, multi-tenant SSO, MFA, device fingerprinting, and more.

💖 Looking for an open-source identity and access management solution like Okta, Auth0, Keycloak ? Learn more about: Casdoor

casdoor

News: 🔥 How to use it with Django ? Try Django Authorization, an authorization library for Django framework.

News: Async is now supported by Pycasbin >= 1.23.0!

News: still worry about how to write the correct Casbin policy? Casbin online editor is coming to help! Try it at: http://casbin.org/editor/

Casbin is a powerful and efficient open-source access control library for Python projects. It provides support for enforcing authorization based on various access control models.

All the languages supported by Casbin:

golang java nodejs php
Casbin jCasbin node-Casbin PHP-Casbin
production-ready production-ready production-ready production-ready
python dotnet c++ rust
PyCasbin Casbin.NET Casbin-CPP Casbin-RS
production-ready production-ready beta-test production-ready

Table of contents

Supported models

  1. ACL (Access Control List)
  2. ACL with superuser
  3. ACL without users: especially useful for systems that don't have authentication or user log-ins.
  4. ACL without resources: some scenarios may target for a type of resources instead of an individual resource by using permissions like write-article, read-log. It doesn't control the access to a specific article or log.
  5. RBAC (Role-Based Access Control)
  6. RBAC with resource roles: both users and resources can have roles (or groups) at the same time.
  7. RBAC with domains/tenants: users can have different role sets for different domains/tenants.
  8. ABAC (Attribute-Based Access Control): syntax sugar like resource.Owner can be used to get the attribute for a resource.
  9. RESTful: supports paths like /res/*, /res/:id and HTTP methods like GET, POST, PUT, DELETE.
  10. Deny-override: both allow and deny authorizations are supported, deny overrides the allow.
  11. Priority: the policy rules can be prioritized like firewall rules.

How it works?

In Casbin, an access control model is abstracted into a CONF file based on the PERM metamodel (Policy, Effect, Request, Matchers). So switching or upgrading the authorization mechanism for a project is just as simple as modifying a configuration. You can customize your own access control model by combining the available models. For example, you can get RBAC roles and ABAC attributes together inside one model and share one set of policy rules.

The most basic and simplest model in Casbin is ACL. ACL's model CONF is:

# Request definition
[request_definition]
r = sub, obj, act

# Policy definition
[policy_definition]
p = sub, obj, act

# Policy effect
[policy_effect]
e = some(where (p.eft == allow))

# Matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

An example policy for ACL model is like:

p, alice, data1, read
p, bob, data2, write

It means:

  • alice can read data1
  • bob can write data2

We also support multi-line mode by appending '\' in the end:

# Matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj \ 
  && r.act == p.act

Further more, if you are using ABAC, you can try operator in like following in Casbin golang edition (jCasbin and Node-Casbin are not supported yet):

# Matchers
[matchers]
m = r.obj == p.obj && r.act == p.act || r.obj in ('data2', 'data3')

But you SHOULD make sure that the length of the array is MORE than 1, otherwise there will cause it to panic.

For more operators, you may take a look at govaluate

Features

What Casbin does:

  1. enforce the policy in the classic {subject, object, action} form or a customized form as you defined, both allow and deny authorizations are supported.
  2. handle the storage of the access control model and its policy.
  3. manage the role-user mappings and role-role mappings (aka role hierarchy in RBAC).
  4. support built-in superuser like root or administrator. A superuser can do anything without explict permissions.
  5. multiple built-in operators to support the rule matching. For example, keyMatch can map a resource key /foo/bar to the pattern /foo*.

What Casbin does NOT do:

  1. authentication (aka verify username and password when a user logs in)
  2. manage the list of users or roles. I believe it's more convenient for the project itself to manage these entities. Users usually have their passwords, and Casbin is not designed as a password container. However, Casbin stores the user-role mapping for the RBAC scenario.

Installation

pip install casbin

Documentation

https://casbin.org/docs/overview

Online editor

You can also use the online editor (http://casbin.org/editor/) to write your Casbin model and policy in your web browser. It provides functionality such as syntax highlighting and code completion, just like an IDE for a programming language.

Tutorials

https://casbin.org/docs/tutorials

Get started

  1. New a Casbin enforcer with a model file and a policy file:
import casbin
e = casbin.Enforcer("path/to/model.conf", "path/to/policy.csv")

Note: you can also initialize an enforcer with policy in DB instead of file, see Policy persistence section for details.

  1. Add an enforcement hook into your code right before the access happens:
sub = "alice"  # the user that wants to access a resource.
obj = "data1"  # the resource that is going to be accessed.
act = "read"  # the operation that the user performs on the resource.

if e.enforce(sub, obj, act):
    # permit alice to read data1
    pass
else:
    # deny the request, show an error
    pass
  1. Besides the static policy file, Casbin also provides API for permission management at run-time. For example, You can get all the roles assigned to a user as below:
roles = e.get_roles_for_user("alice")

See Policy management APIs for more usage.

  1. Please refer to the tests files for more usage.

Policy management

Casbin provides two sets of APIs to manage permissions:

  • Management API: the primitive API that provides full support for Casbin policy management. See here for examples.
  • RBAC API: a more friendly API for RBAC. This API is a subset of Management API. The RBAC users could use this API to simplify the code. See here for examples.

We also provide a web-based UI for model management and policy management:

model editor

policy editor

Policy persistence

https://casbin.org/docs/adapters

Role manager

https://casbin.org/docs/role-managers

Async Enforcer

If your code use async / await and is heavily dependent on I/O operations, you can adopt Async Enforcer!

  1. Create an async engine and new a Casbin AsyncEnforcer with a model file and an async Pycasbin adapter (AsyncAdapter subclass):
import asyncio
import os

import casbin
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker

from casbin_async_sqlalchemy_adapter import Adapter, CasbinRule


async def get_enforcer():
    engine = create_async_engine("sqlite+aiosqlite://", future=True)
    adapter = Adapter(engine)
    await adapter.create_table()

    async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession)
    async with async_session() as s:
        s.add(CasbinRule(ptype="p", v0="alice", v1="data1", v2="read"))
        s.add(CasbinRule(ptype="p", v0="bob", v1="data2", v2="write"))
        s.add(CasbinRule(ptype="p", v0="data2_admin", v1="data2", v2="read"))
        s.add(CasbinRule(ptype="p", v0="data2_admin", v1="data2", v2="write"))
        s.add(CasbinRule(ptype="g", v0="alice", v1="data2_admin"))
        await s.commit()

    e = casbin.AsyncEnforcer("path/to/model.conf", adapter)
    await e.load_policy()
    return e

Note: you can see all supported adapters in Adapters | Casbin.

Built-in async adapters are available in casbin.persist.adapters.asyncio.

  1. Add an enforcement hook into your code right before the access happens:
async def main():
    e = await get_enforcer()
    if e.enforce("alice", "data1", "read"):
        print("alice can read data1")
    else:
        print("alice can not read data1")
  1. Run the code:
asyncio.run(main())
  1. Please refer to the tests files for more usage.

Benchmarks

https://casbin.org/docs/benchmark

Examples

Model Model file Policy file
ACL basic_model.conf basic_policy.csv
ACL with superuser basic_model_with_root.conf basic_policy.csv
ACL without users basic_model_without_users.conf basic_policy_without_users.csv
ACL without resources basic_model_without_resources.conf basic_policy_without_resources.csv
RBAC rbac_model.conf rbac_policy.csv
RBAC with resource roles rbac_model_with_resource_roles.conf rbac_policy_with_resource_roles.csv
RBAC with domains/tenants rbac_model_with_domains.conf rbac_policy_with_domains.csv
ABAC abac_model.conf N/A
RESTful keymatch_model.conf keymatch_policy.csv
Deny-override rbac_model_with_deny.conf rbac_policy_with_deny.csv
Priority priority_model.conf priority_policy.csv

Middlewares

Authz middlewares for web frameworks: https://casbin.org/docs/middlewares

Our adopters

https://casbin.org/docs/adopters

Contributors

This project exists thanks to all the people who contribute.

Backers

Thank you to all our backers! 🙏 [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]

License

This project is licensed under the Apache 2.0 license.

Contact

If you have any issues or feature requests, please contact us. PR is welcomed.

pycasbin's People

Contributors

abichinger avatar abingcbc avatar amisadmin avatar asyncee avatar bustdot avatar cs1137195420 avatar divy9881 avatar divyagar avatar elfisworking avatar favipcj avatar ffyuanda avatar hsluoyz avatar huonw avatar jalinwang avatar leeqvip avatar nekotoxin avatar nghnam avatar sallycaoyu avatar semantic-release-bot avatar shblhy avatar sheny1xuan avatar shivansh-yadav13 avatar stuartbeattie84 avatar swagatsbhuyan avatar terry-xuan-gao avatar timabilov avatar tl24 avatar xhy-5000 avatar yyellowsun avatar zxilly 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  avatar  avatar  avatar  avatar  avatar  avatar

pycasbin's Issues

About GSoC

Hi metors, sorry for late. Right now is there any chances about taking part in GSoC in pycasbin project ?

Before and after login, the debug log printed by caspin shows that the users accessed are anonymous

Before and after login, the debug log printed by caspin shows that the users accessed are anonymous. In theory, after the authentication is successful, the authenticated user information should be displayed. How should this inform the user to obtain the setting of caspin and identify the authenticated user normally

[2020-03-27 17:34:42,218] INFO in views: 登出成功
127.0.0.1 - - [27/Mar/2020 17:34:42] "GET /auth/logout/ HTTP/1.1" 302 -
2020-03-27 17:34:42,230 - INFO - Request: anonymous, /auth/, GET ---> True
127.0.0.1 - - [27/Mar/2020 17:34:42] "GET /auth/ HTTP/1.1" 200 -
2020-03-27 17:34:44,792 - INFO - Request: anonymous, /auth/login/, GET ---> True
127.0.0.1 - - [27/Mar/2020 17:34:44] "GET /auth/login/ HTTP/1.1" 200 -
2020-03-27 17:34:52,642 - INFO - Request: anonymous, /auth/login/, POST ---> True
[2020-03-27 17:34:52,680] INFO in views: test login sucess

Custom RoleManager

Hello. In this doc page, the maintainers of Casbin seem to imply that you can choose/write your own RoleManager class. However, this seems to be hardcoded in. Is there a way to supply a custom class? Can one be made with relative ease?

def _initialize(self):
self.rm = default_role_manager.RoleManager(10)
self.eft = DefaultEffector()
self.watcher = None
self.enabled = True
self.auto_save = True
self.auto_build_role_links = True

Tests are install directly to site-packages rather than within the casbin package

I ran into this issue because pycasbin was causing problems with test module discovery using pytest.

Running pip install casbin then pip uninstall casbin illustrates the problem:

Uninstalling casbin-0.8.2:
  Would remove:
    ~/.virtualenvs/casbin/README.md
    ~/.virtualenvs/casbin/lib/python3.7/site-packages/casbin-0.8.2.dist-info/*
    ~/.virtualenvs/casbin/lib/python3.7/site-packages/casbin/*
    ~/.virtualenvs/casbin/lib/python3.7/site-packages/tests/*

That last line indicates that the tests are being placed directly into site-packages, which is incorrect and causes errors in test discovery.

pycasbin adapters for django?

I find some supported adapters such as SQLAlchemy Adapter and Peewee Adapter in doc. How about adapters for django web frame?

Make enforcer singleton?

Enforcer load policy into memory, if there have multiple instances of enforcer and they modify policy, how can they keep sync?
Make enforcer singleton should solve this problem?
Or can you explain why enforcer shouldn't be singleton?

Restful(Keymatch2) in v0.8.4 get wrong result

My model.conf is

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = r.sub == p.sub && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act)

Policy is

p, ops, /process/cancel, POST
p, ops, /process, POST

and Request is
ops, /process/approve, POST

the result should False, but in fact it is:
2020-07-20 13:53:23,985 - INFO - Request: ops, /process/approve, POST ---> True

Did I code something wrong?

Returning a value of the policy rule as effect

Let's say that in a policy, instead of providing a boolean kind of right, it grants some amount of a resource. For instance

p, sub, act, obj, amount

Is it possible to define a model so I get that amount as a result of calling Enforce instead of a true/false effect?

eval function - ABAC with policy

HiI am struggling with using eval functions for ABAC with policy in pycasbin
Model-taken from example

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub_rule, obj, act

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = eval(p.sub_rule) && r.obj == p.obj && r.act == p.act

Policy - taken from example

p, r.sub.Age > 18 && r.sub.Age < 60, /data1, read
Data{ Age: 40}, /data1, read
ErrorTraceback (most recent call last):
  File "/home/tomer/.local/lib/python3.8/site-packages/simpleeval.py", line 406, in _eval_call
    func = self.functions[node.func.id]
KeyError: 'eval'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "Test.py", line 8, in <module>
    print (e.enforce(sub, obj, act))
  File "/usr/local/lib/python3.8/dist-packages/casbin-0.8.4-py3.8.egg/casbin/core_enforcer.py", line 237, in enforce
    result = expression.eval(parameters)
  File "/usr/local/lib/python3.8/dist-packages/casbin-0.8.4-py3.8.egg/casbin/util/expression.py", line 29, in eval
    return self._eval(self.expr_parsed_value)
  File "/home/tomer/.local/lib/python3.8/site-packages/simpleeval.py", line 343, in _eval
    return handler(node)
  File "/home/tomer/.local/lib/python3.8/site-packages/simpleeval.py", line 375, in _eval_boolop
    vout = self._eval(value)
  File "/home/tomer/.local/lib/python3.8/site-packages/simpleeval.py", line 343, in _eval
    return handler(node)
  File "/home/tomer/.local/lib/python3.8/site-packages/simpleeval.py", line 408, in _eval_call
    raise FunctionNotDefined(node.func.id, self.expr)
simpleeval.FunctionNotDefined: Function 'eval' not defined, for expression 'eval(p_sub_rule) and r_obj == p_obj and r_act == p_act'.

also i see this function is not registered: https://github.com/casbin/pycasbin/blob/master/casbin/model/function.py

Appreciate any help  

AttributeError: 'Model' object has no attribute 'add_policy'

import casbin


def test():
    enforcer = casbin.Enforcer('path/to/model.conf',
                               'path/to/policy.csv')

    added = enforcer.add_policy('alice', 'data1', 'read')

    result = enforcer.enforce('alice', 'data1', 'read')

    print('result: {}'.format(result))


if __name__ == "__main__":
    test()

output:

Traceback (most recent call last):
  File "C:/Users/Ken/PycharmProjects/casbin_test/app1/test.py", line 22, in <module>
    test()
  File "C:/Users/Ken/PycharmProjects/casbin_test/app1/test.py", line 14, in test
    added = enforcer.add_policy('alice', 'data1', 'read')
  File "C:\Users\Ken\PycharmProjects\casbin_test\venv\lib\site-packages\casbin\management_api.py", line 92, in add_policy
    return self.add_named_policy('p', *params)
  File "C:\Users\Ken\PycharmProjects\casbin_test\venv\lib\site-packages\casbin\management_api.py", line 110, in add_named_policy
    rule_added = self._add_policy('p', ptype, policy)
  File "C:\Users\Ken\PycharmProjects\casbin_test\venv\lib\site-packages\casbin\internal_api.py", line 5, in _add_policy
    rule_added = self.model.add_policy(sec, ptype, rule)
AttributeError: 'Model' object has no attribute 'add_policy'

Support for Filtered Adapters

Running PyCasbin in a production environment with a decent size of rules (~30k) pycasbin starts to fall apart. Looping over the policy to find out if each rule matches only to find out that r.obj != s.obj is pretty painful.

Without completely obliterating the internals of casbin to hard code certain checks exist and using things like sets or dictionaries to get the performance up, filtered queries are very much required.

Best practice

Hi,

I'm wondering about best practice in pycasbin.

Example 1

Say I have a DB table of stores:

# id name description
1 1 Store 1 Store 1
2 2 Store 2 Store 2
3 3 Store 3 Store 3
4 4 Store 4 Store 4
5 5 Store 5 Store 5

A DB table of policies:

# id ptype v0 v1 v2 v3 v4 v5
1 1 p alice Store 1 read NULL NULL NULL
2 2 p alice Store 2 write NULL NULL NULL
3 3 p alice Store 3 write NULL NULL NULL
4 4 p alice Store 4 read NULL NULL NULL

Would this be the best way to get a list of stores that Alice has access to?:

permissions = e.get_implicit_permissions_for_user("alice")

for permission in permissions:
    result = session.query(Store).filter(Store.name == permission[1]).first()
    print(f"Store Name: {result.name} - Store Description: {result.description}")

Example 2

As another example; if I wanted to use DB table ID's instead of Store names, would I use the table name as a domain?

# id ptype v0 v1 v2 v3 v4 v5
2 3 p Store Manager Store 1 write NULL NULL
3 4 p Store Manager Store 2 write NULL NULL
4 5 p Store Manager Store 3 write NULL NULL
5 6 p Store Manager Store 4 write NULL NULL
14 16 g alice Store Manager Store NULL NULL NULL
permissions = e.get_implicit_permissions_for_user("Alice", "Store")

for permission in permissions:
    result = session.query(Store).filter(Store.id == permission[2]).first()
    print(f"Store Name: {result.name} - Store Description: {result.description}")

One last question: I am using the casbin_sqlalchemy_adapter, what are all of the v0-v5 columns for?

Thanks for any feedback :-)

Performance of pycasbin vs go casbin

(Please note I had submitted this issue on casbin, and was told to move it to pycasbin, which I am doing verbatim).

We have profiled a simple Casbin enforcement call over an (admittedly abnormally large) policy set. We did this with a go and a python script. The python version takes about 30x the time per enforcement call (1.5 seconds on an i5).

2 things I would like to ask the authors (who suggested I opened this issue):

  1. does it check out that the Python implementation would take so much more than the go one?
  2. even in go, Enforce takes a time that grows linearly with the number of policies, even when the actual policy being asked is laid out explicitly in the policy file (naively, I'd say a lookup shouldn't take linear time, but then we're using a model with deny). Is this normal?
    I am attaching a zipfile with the go script, the python script, the model, and the policy file.

perf.zip

Rule based on foreign key relationship

hi,

I have a series of relationships set up like this:

User
id
customer_id

Customer
id
distributor_id

Distributor
id

I have an endpoint like /user/, and I want to restrict users to only be able to see other users whose user.customer.distributor_id is the same as their user.customer.distributor_id

How would I go about setting up a rule for a scenario like this? Is it even possible to abstract these kinds of relationships into an ABAC schema?

Queries become very slow after I added 30000+ policies

I'm using pycasbin, with sqlalchemy-adapter as adapter. Policies are stored in mysql.
When I'm testing, with about 20 policies. everything is perfect.
After I stored 30000+ policies in mysql, queries become very slow, about 3-4 seconds per query.

Here is the example code.

import casbin
from casbin import persist
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from casbin.model import Model

Base = declarative_base()

MYSQL_CONF = "mysql+pymysql://.........." 
TABLE_NAME = 'auth_rule' 

DOM = 'test'
LOG_ENABLED = False

class CasbinRule(Base):
    __tablename__ = TABLE_NAME

    id = Column(Integer, primary_key=True)
    ptype = Column(String(255))
    v0 = Column(String(255))
    v1 = Column(String(255))
    v2 = Column(String(255))
    v3 = Column(String(255))
    v4 = Column(String(255))
    v5 = Column(String(255))

class Adapter(persist.Adapter):
    """the interface for Casbin adapters."""

    def __init__(self, dsn):
        self._engine = create_engine(dsn)
        session = sessionmaker(bind=self._engine)
        self._session = session()

        Base.metadata.create_all(self._engine)

    def load_policy(self, model):
        """loads all policy rules from the storage."""
        lines = self._session.query(CasbinRule).all()
        for line in lines:
            text = line.ptype

            if line.v0:
                text = text + ', ' + line.v0
            if line.v1:
                text = text + ', ' + line.v1
            if line.v2:
                text = text + ', ' + line.v2
            if line.v3:
                text = text + ', ' + line.v3
            if line.v4:
                text = text + ', ' + line.v4
            if line.v5:
                text = text + ', ' + line.v5

            persist.load_policy_line(text, model)

    def _save_policy_line(self, ptype, rule):
        line = CasbinRule(ptype=ptype)
        if len(rule) > 0:
            line.v0 = rule[0]
        if len(rule) > 1:
            line.v1 = rule[1]
        if len(rule) > 2:
            line.v2 = rule[2]
        if len(rule) > 3:
            line.v3 = rule[3]
        if len(rule) > 4:
            line.v4 = rule[4]
        if len(rule) > 5:
            line.v5 = rule[5]
        self._session.add(line)
        self._session.commit()

    def save_policy(self, model):
        """saves all policy rules to the storage."""
        for sec in ["p", "g"]:
            if sec not in model.model.keys():
                continue
            for ptype, ast in model.model[sec].items():
                for rule in ast.policy:
                    self._save_policy_line(ptype, rule)
        return True

    def __del__(self):
        self._session.close()

class Auth:

    mysql_conf = MYSQL_CONF

    def __init__(self):
        self.adapter = Adapter(self.mysql_conf)
        self.new_model_conf = Model()
        self.new_model_conf.add_def("r","r","sub, obj, act, dom") #
        self.new_model_conf.add_def("p","p","sub, obj, act, dom") #
        self.new_model_conf.add_def("g","g","_, _")
        self.new_model_conf.add_def("g","g2","_, _, _") #
        self.new_model_conf.add_def("g","g3","_, _, _") #
        self.new_model_conf.add_def("e","e","some(where (p.eft == allow))")
        self.new_model_conf.add_def("m","m",'g(r.sub, p.sub) && (g2(r.obj, p.obj, r.dom) || p.obj == "*") && (g3(r.act, p.act, r.dom) || p.act == "*") && r.dom == p.dom')
        self.e = casbin.Enforcer(self.new_model_conf, self.adapter, LOG_ENABLED)

    def check_auth(self, sub, obj, act, dom=DOM):
        sub = str(sub)
        obj = str(obj)
        act = str(act)
        dom = str(dom)
        return self.e.enforce(sub, obj, act, dom):



######CasbinRule and Adapter are from github project: 
######pycasbin/sqlalchemy-adapter/casbin_sqlalchemy_adapter/adapter.py

auth = Auth()
result = auth.e.enforce('1234','2345','read', 'test')

roles = e.get_roles("alice") is wrong!

https://github.com/casbin/pycasbin

In the following introduction:

Besides the static policy file, Casbin also provides API for permission management at run-time. For example, You can get all the roles assigned to a user as below:
roles = e.get_roles("alice")

There is no such method like get_roles("alice")! use get_roles_for_user("alice") instead!

Issue with pycasbin logging

PyCasbin currently sets up its own logger:
https://github.com/casbin/pycasbin/tree/master/casbin/log

Since pycasbin is a supporting module to an application it should differ the logging setup to the application that would leverage the module. This is done by the module class setting self.logger = logging.getLogger() to get the root logger.
Then when calls are made with self.logger.[method]([message]) it will either log as expected or if no logger is gotten then it just wont log as expected. Currently there is no way to override the default pycasbin log level because it is statically set and if you disable the logger you disable all log messages. There is also no good way to override the enforcer class logger since it is not class property.

https://github.com/casbin/pycasbin/blob/master/casbin/log/default_logger.py#L11
https://github.com/casbin/pycasbin/blob/master/casbin/core_enforcer.py#L1
https://github.com/casbin/pycasbin/blob/master/casbin/core_enforcer.py#L25
https://github.com/casbin/pycasbin/blob/master/casbin/core_enforcer.py#L289

The current behavior of pycasbin results in duplicate logs when the application sets up a logger of its own.

2020-10-13 15:54:01,688 - INFO - Request: isadmin, /api/v1/applications, GET ---> True
[2020-10-13 15:54:01,688] INFO in default_logger: Request: isadmin, /api/endpoint, GET ---> True

I will open a PR for these changes when I can unless someones gets to it before me.

keyMatch2(r.obj, p.obj) Breaking the rules on homepage when the url is /

when I use allow-and-deny model in my project , fllow is my define :
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act, eft

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))

[matchers]
m = g(r.sub, p.sub) && (r.obj == p.obj || p.obj == "" || keyMatch(r.obj, p.obj) || keyMatch2(r.obj, p.obj)) && (r.act == p.act || p.act == "")

I want to use keyMatch2 func to match the “:” expression ,but when I use the '/' to represent the home page, the authority management loses control, and all the URLs under the same user can be accessed

Here is my definition of police:
p, anonymous, /users/index/, *, allow
p, alice, /, *, allow

alice can access any url! But it seems to work in the editor!

Bug Python3 : Can't iterate on a dict in all_roles.keys

File : rbac/default_role_manager/role_manager.py
Line : 15~16

 def has_role(self, name):
        return name in self.all_roles.keys()

Error : In python3 you can't iterate on a dict

Fix :

-        return name in self.all_roles.keys()
+        return name in list(self.all_roles.keys())

permission is empty for root role user

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, "role_root") || (g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act)
p, data1_read, data1, read
p, data2_read, data2, read
p, data2_write, data2, write

g, alice, data2_read
g, bob, role_root
import casbin
e = casbin.Enforcer("model.conf", "policy.csv")

sub = "bob"  # the user that wants to access a resource.
obj = "data2"  # the resource that is going to be accessed.
act = "write"  # the operation that the user performs on the resource.

e.enforce(sub, obj, act)

e.get_implicit_permissions_for_user('alice')
e.get_implicit_permissions_for_user('bob')

I expect e.get_implicit_permissions_for_user('bob') to return all permissions defined, but it is empty.

save_policy() unavailable on built-in file adapter

question

I am using the model file default rbac_with_domains_model.conf and policy file rbac_with_domains_policy.csv

loading it as

import casbin
x = casbin.Enforcer('<model file>','<conf file>')

I am assigning a new role for the user to it as

y.add_role_for_user_in_domain('prashant','admin', 'domain1')

now I want to save this policy, so I am doing

x.save_policy()

but this is not saving my new added policy in a file.

when I see the save_policy code in codebase no procedure to save is written ie

 def save_policy(self):
       pass

my question is, shouldn't it be a new method to save all the policy in the file be there? or I am doing something wrong with my approach. if I am doing wrong please help me to correct it.

Is really production ready?

Hello, I have read the sources and have few questions.

  1. Is this project really production ready? I have found hard coded effect expressions in different parts of source code. I thought that it is implemented using some dsl interpretation but there are at most 4 cases that can be used as effects (see effectors module). That looks very strange to me.

  2. The official paper https://arxiv.org/pdf/1903.09756.pdf states that casbin is implemented in lua and used in interpreter-in-interpreter way. In fact all casbin implementations are just straightforward ports from golang version. Can we trust this paper? Also the benchmarks section of this paper has nothing in common with actual implementation of pycasbin.

  3. Some parts of code look not optimized and not pythonic, for example a function that removes duplicates from a string array.

Wrapping up: casbin is great on paper but i’m a bit worried if I really can use it in production due to questions above.

P.S.: I appreciate the work been done on this project and thank you for making it open sourced.

Wrong policy list when add manually

Model config:

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act, eft

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))

[matchers]
m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)

Code:

import casbin

enforcer = casbin.Enforcer("casbin_model.conf")
enforcer.add_named_policy("p", "sub1", "obj1", "read", "deny")
enforcer.add_named_policy("p", "group1", "obj1", "read", "allow")
enforcer.add_named_grouping_policy('g', 'sub1', 'group1')

print('Objects:', enforcer.get_all_objects())
print('Subjects:', enforcer.get_all_subjects())
print('Actions:', enforcer.get_all_actions())

Here is output:

Objects: ['obj1', 'group1']
Subjects: ['sub1', 'group1']
Traceback (most recent call last):
  File "test_casbin.py", line 10, in <module>
    print('Actions:', enforcer.get_all_actions())
  File "/Users/namnh/.venvs/casbin/lib/python3.7/site-packages/casbin/management_enforcer.py", line 27, in get_all_actions
    return self.get_all_named_actions('p')
  File "/Users/namnh/.venvs/casbin/lib/python3.7/site-packages/casbin/management_enforcer.py", line 31, in get_all_named_actions
    return self.model.get_values_for_field_in_policy('p', ptype, 2)
  File "/Users/namnh/.venvs/casbin/lib/python3.7/site-packages/casbin/model/policy.py", line 100, in get_values_for_field_in_policy
    values.append(rule[field_index])
IndexError: list index out of range

It shows wrong object list, right list only has obj1, and does not has group1 . And get_all_actions() is failed.

I found problem is in Assertion class, which has policy attribute. It is class attribute, so it is shared between instances. So when you add policy p, it is also added to g.
Debug:

print(enforcer.model.model['p']['p'].policy)
print(enforcer.model.model['g']['g'].policy)
print(id(enforcer.model.model['p']['p'].policy))
print(id(enforcer.model.model['g']['g'].policy))

Output:

[['sub1', 'obj1', 'read', 'deny'], ['group1', 'obj1', 'read', 'allow'], ['sub1', 'group1']]
[['sub1', 'obj1', 'read', 'deny'], ['group1', 'obj1', 'read', 'allow'], ['sub1', 'group1']]
4411842880
4411842880

It`s wrong in keyMatch2!

in builtin_operators.py

def regex_match(key1, key2):
    """determines whether key1 matches the pattern of key2 in regular expression."""

    res = re.match(key2, key1)
    if res:
        return True
    else:
        return False

when url is / that can match any url

Assigning custom Role Manager changes enforcement result

    m = casbin.model.Model()
    a = casbin.persist.Adapter()
    e = casbin.Enforcer(m, a)
    e.set_role_manager(casbin.rbac.default_role_manager.RoleManager(10))
    m.add_def("r", "r", "sub, obj, act")
    m.add_def("p", "p", "sub, obj, act")
    m.add_def("g", "g", "_, _")
    m.add_def("e", "e", "some(where (p.eft == allow))")
    m.add_def("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act")
    a.add_policy("p", "p", ["alice", "data1", "read"])
    a.add_policy("p", "p", ["bob", "data2", "write"])

    assert e.enforce("alice", "data1", "read")
    assert not e.enforce("alice", "data1", "write")

    assert e.enforce("bob", "data2", "write")
    assert not e.enforce("bob", "data1", "write")

Fails at assert e.enforce("alice", "data1", "read").

pip cannot find casbin

There's an issue with the pypi repository.

$ virtualenv --python=python3 venv && source ./venv/bin/activate && pip install casbin
Already using interpreter /usr/bin/python3
Using base prefix '/usr'
New python executable in /repos/agosto/gcp/project_template/venv/bin/python3
Also creating executable in /repos/agosto/gcp/project_template/venv/bin/python
Installing setuptools, pkg_resources, pip, wheel...done.
Collecting casbin
  Could not find a version that satisfies the requirement casbin (from versions: )
No matching distribution found for casbin

Running tests and coverage

I tried using py.test but get module not found errors. Can you please let me know how I can run tests and see coverage?

Is there a way to pass the RoleManager to a custom matcher function

Is there any way to pass a Role Manager to a custom matcher function so inherited roles could be tested using a matcher function?

The alternative would be to pass a matcher function to a g function.

An example showing the need for this is:

g, permission::read, permission_group::admin
g, permission::write, permission_group::admin
g, permission::execute, permission_group::admin
g, permission::read, permission_group::readwrite
g, permission::write, permission_group::readwrite
g, permission::read, permission_group::readonly

g, /resource_1, resource_group::engineering
g, /resource_2, resource_group::engineering
g, /resource_3/*, resource_group::engineering

p, user::[email protected], resource_group::engineering, permission_group::admin, allow

In the above example, I can match enforcement requests for /resource_1 and /resource_2 with a g function. However, there is no way I can think of to match to /resource_3/foo and /resource_3/bar using a matcher function such as the built in keyMatch.

Is there an alternative way to approach this problem?

New Release (0.9.0?)

With filtered policy support available it would be awesome to have this available in a general release rather than needing to us git repos.

Bringing pycasbin in track with casbin-core.

I am sure there must be some features or functionalities which are not in track with casbin-core, why should we not track those features and bring them here and implement it.

advice on performance

We've been growing our test data set to about 2.5k rules in the policy set, which is making calls to the enforcer quite slow. Is there something that can be done to speed things up, or did I just pick a terrible model for performance?

model:

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && r.act == p.act

example policy:

g,act.io/org:acmecorp/group:admins,act.io/org:acmecorp/group:members
p,act.io/org:acmecorp/group:admins,act.io/org:acmecorp/info,edit
p,act.io/org:acmecorp/group:admins,act.io/org:acmecorp/group:members,manage
p,act.io/org:acmecorp/group:members,act.io/org:acmecorp,view
p,act.io/org:acmecorp/group:members,act.io/org:acmecorp/plan:*,view
p,act.io/org:acmecorp/group:members,act.io/org:acmecorp/plan:*,create

g,act.io/user:cde7860e-5459-413c-969a-9536edbb1980,act.io/org:acmecorp/group:admins
g,act.io/user:554a09e6-2d6a-406d-aef0-2ea0e09a0e9f,act.io/org:acmecorp/group:members

g,act.io/org:acmecorp/campaign:1/group:admins,act.io/org:acmecorp/campaign:1/group:members
p,act.io/org:acmecorp/campaign:1/group:admins,act.io/org:acmecorp/campaign:1/info,edit
p,act.io/org:acmecorp/campaign:1/group:admins,act.io/org:acmecorp/campaign:1/group:members,manage
p,act.io/org:acmecorp/campaign:1/group:members,act.io/org:acmecorp/campaign:1,view
p,act.io/org:acmecorp/campaign:1/group:members,act.io/org:acmecorp/campaign:1/submission:*,approve
p,act.io/org:acmecorp/campaign:1/group:members,act.io/org:acmecorp/campaign:1/version:*,create
p,act.io/org:acmecorp/campaign:1/group:members,act.io/org:acmecorp/campaign:1/version:*,read
p,act.io/org:acmecorp/campaign:1/group:members,act.io/org:acmecorp/campaign:1/version:*,update

g,act.io/user:cde7860e-5459-413c-969a-9536edbb1980,act.io/org:acmecorp/campaign:1/group:admins
g,act.io/user:3ae34b92-a0f8-4b3f-a7bd-877c9ba303a4,act.io/org:acmecorp/campaign:1/group:members

g,act.io/org:acmecorp/campaign:2/group:admins,act.io/org:acmecorp/campaign:2/group:members
p,act.io/org:acmecorp/campaign:2/group:admins,act.io/org:acmecorp/campaign:2/info,edit
p,act.io/org:acmecorp/campaign:2/group:admins,act.io/org:acmecorp/campaign:2/group:members,manage
p,act.io/org:acmecorp/campaign:2/group:members,act.io/org:acmecorp/campaign:2,view
p,act.io/org:acmecorp/campaign:2/group:members,act.io/org:acmecorp/campaign:2/submission:*,approve
p,act.io/org:acmecorp/campaign:2/group:members,act.io/org:acmecorp/campaign:2/version:*,create
p,act.io/org:acmecorp/campaign:2/group:members,act.io/org:acmecorp/campaign:2/version:*,read
p,act.io/org:acmecorp/campaign:2/group:members,act.io/org:acmecorp/campaign:2/version:*,update

g,act.io/user:925d614b-12f4-4048-91c5-adf9f278dcb9,act.io/org:acmecorp/campaign:2/group:admins
g,act.io/user:6e48501a-eff8-4ec7-8215-638c7726e163,act.io/org:acmecorp/campaign:2/group:members

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.