pycasbin / sqlalchemy-adapter Goto Github PK
View Code? Open in Web Editor NEWSQLAlchemy Adapter for PyCasbin
Home Page: https://github.com/casbin/pycasbin
License: Apache License 2.0
SQLAlchemy Adapter for PyCasbin
Home Page: https://github.com/casbin/pycasbin
License: Apache License 2.0
I see the example and the issue about mysql db, but still confused. Can you give me any clue how I can connect to my postgresql db?
What should I do if I implement it myself
code:
adapter = Adapter(engine=engine)
ENFORCER = casbin.Enforcer(config.CASBIN_MODEL_CONF, adapter, True)
traceback:
INFO: Started reloader process [1]
2020-05-04 12:38:38,201 - INFO - Model:
INFO: Model:
2020-05-04 12:38:38,201 - INFO - r.r: sub, obj, act
INFO: r.r: sub, obj, act
2020-05-04 12:38:38,201 - INFO - p.p: sub, obj, act
INFO: p.p: sub, obj, act
2020-05-04 12:38:38,201 - INFO - e.e: some(where (p_eft == allow))
INFO: e.e: some(where (p_eft == allow))
2020-05-04 12:38:38,201 - INFO - m.m: g(r_sub, p_sub) && r_obj == p_obj && r_act == p_act
INFO: m.m: g(r_sub, p_sub) && r_obj == p_obj && r_act == p_act
2020-05-04 12:38:38,201 - INFO - g.g: _, _
INFO: g.g: _, _
Process SpawnProcess-1:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/multiprocessing/process.py", line 297, in _bootstrap
self.run()
File "/usr/local/lib/python3.7/multiprocessing/process.py", line 99, in run
self._target(*self._args, **self._kwargs)
File "/usr/local/lib/python3.7/site-packages/uvicorn/subprocess.py", line 61, in subprocess_started
target(sockets=sockets)
File "/usr/local/lib/python3.7/site-packages/uvicorn/main.py", line 382, in run
loop.run_until_complete(self.serve(sockets=sockets))
File "uvloop/loop.pyx", line 1456, in uvloop.loop.Loop.run_until_complete
File "/usr/local/lib/python3.7/site-packages/uvicorn/main.py", line 389, in serve
config.load()
File "/usr/local/lib/python3.7/site-packages/uvicorn/config.py", line 288, in load
self.loaded_app = import_from_string(self.app)
File "/usr/local/lib/python3.7/site-packages/uvicorn/importer.py", line 20, in import_from_string
module = importlib.import_module(module_str)
File "/usr/local/lib/python3.7/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 728, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "./main.py", line 12, in <module>
from interfaces.router import api_router
File "./interfaces/router.py", line 6, in <module>
from .endpoints import identity, authentication, permission
File "./interfaces/endpoints/identity.py", line 11, in <module>
from application.services.security import get_current_active_user, get_current_admin_user
File "./application/services/security.py", line 11, in <module>
from domain.permission.entity import Policy, verify_permission
File "./domain/permission/entity.py", line 19, in <module>
ENFORCER = casbin.Enforcer(config.CASBIN_MODEL_CONF, adapter, True)
File "/usr/local/lib/python3.7/site-packages/casbin/core_enforcer.py", line 31, in __init__
self.init_with_adapter(model, adapter)
File "/usr/local/lib/python3.7/site-packages/casbin/core_enforcer.py", line 47, in init_with_adapter
self.init_with_model_and_adapter(m, adapter)
File "/usr/local/lib/python3.7/site-packages/casbin/core_enforcer.py", line 63, in init_with_model_and_adapter
self.load_policy()
File "/usr/local/lib/python3.7/site-packages/casbin/core_enforcer.py", line 142, in load_policy
self.adapter.load_policy(self.model)
File "/usr/local/lib/python3.7/site-packages/casbin_sqlalchemy_adapter/adapter.py", line 50, in load_policy
lines = self._session.query(CasbinRule).all()
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 1558, in query
return self._query_cls(entities, self, **kwargs)
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 191, in __init__
self._set_entities(entities)
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 219, in _set_entities
self._set_entity_selectables(self._entities)
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 250, in _set_entity_selectables
ent.setup_entity(*d[entity])
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 4185, in setup_entity
self._with_polymorphic = ext_info.with_polymorphic_mappers
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 883, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/mapper.py", line 2141, in _with_polymorphic_mappers
configure_mappers()
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/mapper.py", line 3255, in configure_mappers
mapper._post_configure_properties()
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/mapper.py", line 1950, in _post_configure_properties
prop.init()
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/interfaces.py", line 196, in init
self.do_init()
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/relationships.py", line 1935, in do_init
self._process_dependent_arguments()
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/relationships.py", line 1997, in _process_dependent_arguments
self.target = self.entity.persist_selectable
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 977, in __getattr__
return self._fallback_getattr(key)
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 951, in _fallback_getattr
raise AttributeError(key)
AttributeError: entity
Adding new policies. groups which already exist now inserts a duplicate is there any way to avoid that also will be nice if we can give out a warning in that case or maybe something like an ignore_duplicate
flag
btw, Pycasbin has been really helpful in my projects, Cheers ✌️
Hey team 👋 happy new year 🎉
I have been debugging and testing different GitHub issues that were opened in the past, and looking through the documentation but I was not able to make work Py Casbin with RBAC with the domains model
I have the same conf that in the official documentation https://casbin.org/docs/rbac-with-domains. The only difference is that instead of using a CSV file I am using the SQL Alchemy Adapter
Looking through the unit test, I only found coverage for simple RBAC with sub, obj, and action and I believe that is the main reason the Enforcer is not returning True when it should because it is not implemented in the Adapter. Can you confirm this?
I have tested my configuration in the casbin online editor and the enforcer returns True
I saw that Pycasbin used to have an issue related RBAC with domain but was fixed here casbin/pycasbin#92
I found in the issue that I shared that the domain matching func should be added like this
enforcer = Enforcer("rbac-tenant.conf", Adapter(engine=settings.DATABASE_URL, db_class=RBAC))
enforcer.add_named_domain_matching_func("g", key_match2)
result = enforcer.enforce(user_id, organization_id, self.obj, self.action)
Also tried without adding it and many others but the Enforcer always return false
By the way, the connection with the Adapter is working perfectly because when I create an Organization Owner user, I am adding the policies and the group, and works totally fine
enforcer = Enforcer("rbac-tenant.conf", Adapter(engine=settings.DATABASE_URL, db_class=RBAC))
enforcer.add_role_for_user_in_domain(str(user_id), "ORGANIZATION_OWNER", str(organization_id))
enforcer.add_policy("ORGANIZATION_OWNER", str(organization_id), "organizations", "update")
enforcer.add_policy("ORGANIZATION_OWNER", str(organization_id), "organizations", "delete")
enforcer.add_policy("ORGANIZATION_OWNER", str(organization_id), "organizations", "read")
Thanks for the help
#36 while looking innocent enough is a breaking change and should have rolled minor versions at least and not been v0.3.1. Deleting the _commit()
functionality and reworking the internals so all inheritance exploded was definitely not something I was expecting for a patch roll.
I agree with the intent of the change, it is correct sessions are short lived so having this in theory is a correct change.
The issue comes from when session management is handled outside of the scope of casbin. I am a pretty big proponent of sessions should be explicitly managed and not hidden away in the library. I also must absolutely have the ability to force my casbin session and my other DB changes to be executed as part of a single operation.
The way I was previously able to do this was hijacking the _session
variable as part of the adapter and the self._commit()
function. I have an inherited adapter that just made sure _commit
was a noop and I could adjust the _session variable to my upstream session and things would work out ok.
This change also explodes things like autocommit
out of postgresql if that is how the engine is bound because session.commit()
will always explode because no background implicit session is created to be committed like this. Fortunately I hadn't upgraded that project code base yet.
Based on this change, I feel like two adapters being exposed from this library might make the most sense. the first being the core
adapter which is basically this class minus the definition of the constructor and the _session_scope(self)
function. This basically says "go ahead and role your extensions, we will guarantee to keep this interface" and a second one that extends the core with the default implementation so people will more basic needs still have a working out of the box experience.
Right now, CasbinRule has its own declarative_base
that is hard coded down in all levels of the code.
Situations come up in use where you want to have your own class for various reasons such as a single declarative base. Rather than forcing a copy and pasting of the entire adapter and making your own. Allow setting the class yourself and all other logic renames usable.
sqlalchemy-adapter/casbin_sqlalchemy_adapter/adapter.py
Lines 112 to 124 in 2118a94
Policy Subset Loading mention that SavePolicy
should disable while apply subset loading.
Hi,
Currently, there is no function to verify whether a policy already exists in the database. Hence, the adapter is allowing to create duplicate entries in the table whenever you re-run the script.
def add_policy(self, sec, ptype, rule):
"""adds a policy rule to the storage."""
self._save_policy_line(ptype, rule)
I guess, the above method didn't check for existing entries in the table, hence the issue might be occuring.
Code to reproduce:
Run the below code snippet for 5-6 times and in database you found those many entries of same policy.
import casbin_sqlalchemy_adapter
import casbin
adapter = casbin_sqlalchemy_adapter.Adapter('sqlite:///test.db')
e = casbin.Enforcer('path/to/model.conf', adapter, True)
e.add_policy('admin', 'domain1', 'data1', 'read')
print(e.get_policy())
Source code:
import casbin
import casbin_sqlalchemy_adapter
model = casbin.Model()
model.add_def("r", "r", "sub, obj, act")
model.add_def("p", "p", "sub, obj, act")
model.add_def("g", "g", "_, _")
model.add_def("e", "e", "some(where (p.eft == allow))")
model.add_def("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act")
adapter = casbin_sqlalchemy_adapter.Adapter('mysql+pymysql://db_account:[email protected]:3306/demo')
e = casbin.Enforcer(model, adapter)
e.add_policy('admin', 'r')
e.update_policy(['admin', 'r'], ['admin', 'w'])
Running results:
Traceback (most recent call last):
File "/Users/zhangyi/Documents/vianet/vnet.service.lib/casbinLib/casbinLib/__init__.py", line 106, in <module>
e.update_policy(['admin', 'r'], ['admin', 'w'])
File "/Users/zhangyi/.virtualenvs/vnet.service.lib/lib/python3.8/site-packages/casbin/management_enforcer.py", line 125, in update_policy
return self.update_named_policy("p", old_rule, new_rule)
File "/Users/zhangyi/.virtualenvs/vnet.service.lib/lib/python3.8/site-packages/casbin/management_enforcer.py", line 133, in update_named_policy
return self._update_policy("p", ptype, old_rule, new_rule)
File "/Users/zhangyi/.virtualenvs/vnet.service.lib/lib/python3.8/site-packages/casbin/internal_enforcer.py", line 52, in _update_policy
if self.adapter.update_policy(sec, ptype, old_rule, new_rule) is False:
AttributeError: 'Adapter' object has no attribute 'update_policy'
SQLAlchemy adapter object has no attribute update_policy, hope the author add, thank you!:)
Can you guys create a new release with the latest code as a v0.0.3, v0.0.2 doesn't contain the changes for delete_policy.
I am using python and casbin_sqlalchemy_adapter adapter.
I see that file adapter has support for policy subset loading. Is it possible in casbin_sqlalchemy_adapter
Readme has enforcer being initialized with the following line: e = casbin.Enforcer('path/to/model.conf', adapter, True)
BUT, CoreEnforcer init only has the following params: def __init__(self, model=None, adapter=None)
I get the following error when I leave the 3rd param as True: TypeError: __init__() takes from 1 to 3 positional arguments but 4 were given
If this is confirmed as a bug in the readme, please lmk if I can help to make the change as it would be my first 😄
Hi,
What would the connection look like for connecting to an MSSQL DB on Azure?
Thank you
Assume I have the following policies:
p, developer, domain, obj1, write
p, guest, domain, obj2, read
g, user, developer, domain
And I remove one of the policy using
policies_for_obj = enforcer.get_filtered_policy(2, "obj1") # This returns ['developer', 'domain', 'obj1', 'write']
enforcer.remove_policies(policies_for_obj)
Then all the policies are deleted.
In these lines,
sqlalchemy-adapter/casbin_sqlalchemy_adapter/adapter.py
Lines 159 to 160 in 602cfd6
the or_
will translate the filter into something like:
v0==developer or v1==domain or v2==obj1 or v3==write
and all the policies will match this filter since v1==domain
holds for all of them.
With all the changes now merged for loading filtered policy, and the PRs merged upstream as well. Should make a new release so we don't need to use git references in pip.
sqlalchemy-adapter/casbin_sqlalchemy_adapter/adapter.py
Lines 54 to 70 in aa7b1f5
When I pass in a rule the only value that gets written to the database is the last value field of the rule and this always gets written into v0 as it is the only column referenced in each case.
The column for each case should be updated to match the rule field index, line.v1 = rule[1]
, etc.
Moved from: casbin/pycasbin#136
When I visited the next day, I got this prompt:
StatementError at /api/test/admin/
(sqlalchemy.exc.InvalidRequestError) Can't reconnect until invalid transaction is rolled back
[SQL: SELECT casbin_rule.id AS casbin_rule_id, casbin_rule.ptype AS casbin_rule_ptype, casbin_rule.v0 AS casbin_rule_v0, casbin_rule.v1 AS casbin_rule_v1, casbin_rule.v2 AS casbin_rule_v2, casbin_rule.v3 AS casbin_rule_v3, casbin_rule.v4 AS casbin_rule_v4, casbin_rule.v5 AS casbin_rule_v5
FROM casbin_rule]
[parameters: [immutabledict({})]]
or:
OperationalError at /api/test/admin/
(MySQLdb._exceptions.OperationalError) (2006, 'MySQL server has gone away')
[SQL: SELECT casbin_rule.id AS casbin_rule_id, casbin_rule.ptype AS casbin_rule_ptype, casbin_rule.v0 AS casbin_rule_v0, casbin_rule.v1 AS casbin_rule_v1, casbin_rule.v2 AS casbin_rule_v2, casbin_rule.v3 AS casbin_rule_v3, casbin_rule.v4 AS casbin_rule_v4, casbin_rule.v5 AS casbin_rule_v5
FROM casbin_rule]
(Background on this error at: http://sqlalche.me/e/13/e3q8)
My environment:
Python:3.9.2 and 3.9.4
Django: 3.1.7
ServerHost:AliYun and QingYun
My configuration is as follows:
# casbin_middleware
import casbin
import casbin_sqlalchemy_adapter
from django.core.exceptions import PermissionDenied
from casbin_pro.settings import env
adapter = casbin_sqlalchemy_adapter.Adapter(env.get_value("CASBIN_URL"))
enforcer = casbin.Enforcer("casbin_middleware/authz_model.conf", adapter, True)
class CasbinMiddleware:
"""
Casbin middleware.
"""
def __init__(self, get_response):
self.get_response = get_response
# Initialize the Casbin enforcer, executed only on once.
self.enforcer = enforcer
...
...
CASBIN_URL=mysql+pymysql://root:[email protected]:3306/aliyun_casbin?autocommit=true
# or
CASBIN_URL=mysql://root:[email protected]:3306/aliyun_casbin?charset=utf8&autocommit=true
start-up:
gunicorn casbin_pro.asgi:application -b 0:8000 -w 2 -k uvicorn.workers.UvicornWorker --reload --log-level info -t 600
so far I've been unsuccessful in trying to use a custom model in place of CasbinRule. is this possible?
importing Base and adding a model to that still tries to create the casbin_rule table from CasbinRule
See how we did it for other repos.
Some other repos like https://github.com/pycasbin/postgresql-watcher also have this issue:
Trying to use the python's casbin_sqlalchemy_adapte
to access a Casbin policy stored on Postgres with Golang's sql-adapter
return the following error:
LINE 1: SELECT casbin_rule.id AS casbin_rule_id, casbin_rule.ptype A...```
This is due to the fact that the Golang's sql adapter does not add an `id` column which is actually required for the Python adapter.
The schema should be made consistent in order to allow interoperability of the same Casbin rule system/table across different languages.
Comparing how filtered policies work for something like the gorm go adapter https://github.com/casbin/gorm-adapter/blob/115228287704942b18ceb28d0b5ae5860025bee7/adapter.go#L401 and this adapter, the current implementation doesn't support filter sets. Currently it just takes whatever the first filter is and just runs with that.
Could you please release the v0.1.0 with the recent changes that completed the adapter interface?(maybe after #5 lands?) Thank you very much.
The docuemnt says:
This is unlike SavePolicy(), because the latter will delete all policy rules in the storage and save all policy rules from Casbin enforcer to the storage.
import casbin_sqlalchemy_adapter
import casbin
adapter = casbin_sqlalchemy_adapter.Adapter('sqlite:///test.db')
report_paths = [{'path': '/api/v1/report/product/ungrouped/items/', 'method': 'get', 'tags': 'report_product_ungrouped'}, {'path': '/api/v1/report/product/ungrouped/items2/', 'method': 'get', 'tags': 'report_product_ungrouped'}]
e = casbin.Enforcer('C:\\Users\\username\\Documents\\scripts\\myproject\\app\\casbin_model.conf', adapter, True)
e.enable_auto_save(False)
e.add_policy('alice', 'data5', 'read')
e.save_policy()
e.save_policy()
When I run the above code, it just save another record of the same policy to database.
self._db_class is used in multiple locations but no where is it ever assigned a value.
Hi,
I've opened a similar ticket yesterday but this time it's about an inconsistency between the pycasbin/sqlalchemy-adapter
and the casbin/gorm-adapter
When the casbin Rule Table is created through the gorm adapter, the 1st column is named p_type
.
When the same Table is created by SQLAlchemy, the 1st column is named ptype
.
This creates interoperability issues.
This could either be fixed in the Gorm Adaper by changing the name (see here) or in the SQLAlchemy adapter.
Let me know if you need some help with this.
Thank you
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.