fix: fixed `should_reload` behaviour, close PostgreSQL connections, block until `PostgresqlWatcher` is ready, refactorings (#29)
* chore: updated dev requirements
* chore: format code with black
* chore: updated .gitignore
* fix: type hint, multiprocessing.Pipe is a Callable and not a type
* fix: make Watcher.should_reload return value consistent
* fix: Handle Connection and Process objects consistenly and close them before creating new ones
* feat: Customize the postgres channel name
* chore: Some code reorg
- Make PostgresqlWatcher.create_subscription_process a private method
- Rename casbin_subscription to _casbin_channel_subscription
* docs: added doc string for PostgresqlWatcher.update
* refactor: PostgresqlWatcher.set_update_callback
* refactor!: Rename 'start_process' flag to 'start_listening'
* docs: Added doc string to PostgresqlWatcher.__init__
* fix: Added proper destructor for PostgresqlWatcher
* chore: fix type hints and proper handling of the channel_name argument and its default value
* test: fix tests
decrease select timeout to one second in child Process
remove infinite timout in PostgresqlWatcher.should_reload
create a new watcher instance for every test case
* feat: Setup logging module for unit tests
* fix: typo
* feat: channel subscription with proper resource cleanup
Moved channel subscription function to separate file and added context
manager for the connection, that handles SIGINT, SIGTERM for proper resource
cleanup
* chore: removed unnecessary tests
* feat: Wait for Process to be ready to receive messages from PostgreSQL
* test: multiple instances of the watcher
* test: make sure every test case uses its own channel
* test: no update
* refactor: moved code into with block
* feat: automaticall call the update handler if it is provided
* refactor: sorted imports
* docs: updated README
* refactor: improved readibility
* refactor: resolve a potential infinite loop with a custom Exception
* refactor: make timeout configurable by the user
* fix: docs
* fix: ensure type hint compatibility with Python 3.9
* feat: make sure multiple calls of update() get resolved by one call of should_reload() thanks to @pradeepranwa1Casbin watcher based on PostgreSQL for monitoring updates to casbin policies.
pip install casbin-postgresql-watcher
from flask_authz import CasbinEnforcer from postgresql_watcher import PostgresqlWatcher from flask import Flask from casbin.persist.adapters import FileAdapter casbin_enforcer = CasbinEnforcer(app, adapter) watcher = PostgresqlWatcher(host=HOST, port=PORT, user=USER, password=PASSWORD, dbname=DBNAME) watcher.set_update_callback(casbin_enforcer.load_policy) casbin_enforcer.set_watcher(watcher) # Call should_reload before every call of enforce to make sure # the policy is update to date watcher.should_reload() if casbin_enforcer.enforce("alice", "data1", "read"): # permit alice to read data1 pass else: # deny the request, show an error pass
alternatively, if you need more control
from flask_authz import CasbinEnforcer from postgresql_watcher import PostgresqlWatcher from flask import Flask from casbin.persist.adapters import FileAdapter casbin_enforcer = CasbinEnforcer(app, adapter) watcher = PostgresqlWatcher(host=HOST, port=PORT, user=USER, password=PASSWORD, dbname=DBNAME) casbin_enforcer.set_watcher(watcher) # Call should_reload before every call of enforce to make sure # the policy is update to date if watcher.should_reload(): casbin_enforcer.load_policy() if casbin_enforcer.enforce("alice", "data1", "read"): # permit alice to read data1 pass else: # deny the request, show an error pass
See PostgresQL documentation for full details of SSL parameters.
... watcher = PostgresqlWatcher(host=HOST, port=PORT, user=USER, password=PASSWORD, dbname=DBNAME, sslmode="verify_full", sslcert=SSLCERT, sslrootcert=SSLROOTCERT, sslkey=SSLKEY) ...