abs-auth-rbac-core 0.1.14__tar.gz → 0.1.16__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of abs-auth-rbac-core might be problematic. Click here for more details.
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/PKG-INFO +2 -1
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/rbac/service.py +114 -10
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/pyproject.toml +3 -2
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/README.md +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/__init__.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/auth/__init__.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/auth/auth_functions.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/auth/jwt_functions.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/auth/middleware.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/__init__.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/base_model.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/gov_casbin_rule.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/permissions.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/rbac_model.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/role_permission.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/roles.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/seeder/permission_seeder.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/user.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/user_permission.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/user_role.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/rbac/__init__.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/rbac/decorator.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/rbac/policy.conf +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/schema/__init__.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/schema/permission.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/util/__init__.py +0 -0
- {abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/util/permission_constants.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: abs-auth-rbac-core
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.16
|
|
4
4
|
Summary: RBAC and Auth core utilities including JWT token management.
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: AutoBridgeSystems
|
|
@@ -11,6 +11,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.13
|
|
12
12
|
Requires-Dist: abs-exception-core (>=0.1.0,<0.2.0)
|
|
13
13
|
Requires-Dist: casbin (>=1.41.0,<2.0.0)
|
|
14
|
+
Requires-Dist: casbin-redis-watcher (>=1.3.0,<2.0.0)
|
|
14
15
|
Requires-Dist: casbin-sqlalchemy-adapter (>=1.4.0,<2.0.0)
|
|
15
16
|
Requires-Dist: fastapi[standard] (>=0.115.12,<0.116.0)
|
|
16
17
|
Requires-Dist: passlib (>=1.7.4,<2.0.0)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from typing import List, Optional, Callable,Any,Tuple
|
|
2
2
|
import os
|
|
3
|
+
from pydantic import BaseModel
|
|
3
4
|
import casbin
|
|
4
5
|
from casbin_sqlalchemy_adapter import Adapter
|
|
6
|
+
from casbin_redis_watcher import RedisWatcher, WatcherOptions,new_watcher
|
|
5
7
|
from sqlalchemy import and_, select
|
|
6
8
|
from sqlalchemy.orm import Session, joinedload
|
|
7
9
|
from ..schema import CreatePermissionSchema
|
|
@@ -13,7 +15,9 @@ from ..models import (
|
|
|
13
15
|
Permission,
|
|
14
16
|
UserPermission
|
|
15
17
|
)
|
|
18
|
+
from abs_utils.logger import setup_logger
|
|
16
19
|
|
|
20
|
+
logger = setup_logger(__name__)
|
|
17
21
|
from abs_exception_core.exceptions import (
|
|
18
22
|
DuplicatedError,
|
|
19
23
|
NotFoundError,
|
|
@@ -21,9 +25,17 @@ from abs_exception_core.exceptions import (
|
|
|
21
25
|
)
|
|
22
26
|
|
|
23
27
|
from ..models.gov_casbin_rule import GovCasbinRule
|
|
28
|
+
from redis import Redis
|
|
29
|
+
|
|
30
|
+
class RedisWatcherSchema(BaseModel):
|
|
31
|
+
host: str
|
|
32
|
+
port: int
|
|
33
|
+
channel: str
|
|
34
|
+
ssl: Optional[bool] = False
|
|
35
|
+
password: Optional[str] = None
|
|
24
36
|
|
|
25
37
|
class RBACService:
|
|
26
|
-
def __init__(self, session: Callable[...,Session]):
|
|
38
|
+
def __init__(self, session: Callable[...,Session],redis_config:Optional[RedisWatcherSchema]=None):
|
|
27
39
|
"""
|
|
28
40
|
Service For Managing the RBAC
|
|
29
41
|
Args:
|
|
@@ -31,9 +43,10 @@ class RBACService:
|
|
|
31
43
|
"""
|
|
32
44
|
self.db = session
|
|
33
45
|
self.enforcer = None
|
|
34
|
-
self._initialize_casbin()
|
|
46
|
+
self._initialize_casbin(redis_config)
|
|
47
|
+
self.watcher = None
|
|
35
48
|
|
|
36
|
-
def _initialize_casbin(self):
|
|
49
|
+
def _initialize_casbin(self,redis_config:Optional[RedisWatcherSchema]=None):
|
|
37
50
|
"""
|
|
38
51
|
Initiates the casbin policy using the default rules
|
|
39
52
|
"""
|
|
@@ -54,6 +67,44 @@ class RBACService:
|
|
|
54
67
|
# Load policies
|
|
55
68
|
self.enforcer.load_policy()
|
|
56
69
|
|
|
70
|
+
if redis_config:
|
|
71
|
+
try:
|
|
72
|
+
# Create Redis client with proper configuration
|
|
73
|
+
redis_client = Redis(
|
|
74
|
+
host=redis_config.host,
|
|
75
|
+
port=redis_config.port,
|
|
76
|
+
password=redis_config.password if hasattr(redis_config, 'password') else None,
|
|
77
|
+
ssl=redis_config.ssl,
|
|
78
|
+
decode_responses=True,
|
|
79
|
+
socket_connect_timeout=5,
|
|
80
|
+
socket_timeout=5,
|
|
81
|
+
retry_on_timeout=True,
|
|
82
|
+
health_check_interval=30
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Test Redis connection
|
|
86
|
+
redis_client.ping()
|
|
87
|
+
|
|
88
|
+
# Create Watcher and Options
|
|
89
|
+
test_option = WatcherOptions()
|
|
90
|
+
test_option.pub_client = redis_client
|
|
91
|
+
test_option.sub_client = redis_client
|
|
92
|
+
test_option.channel = redis_config.channel
|
|
93
|
+
test_option.optional_update_callback = lambda _: self.enforcer.load_policy()
|
|
94
|
+
|
|
95
|
+
# Create watcher
|
|
96
|
+
watcher = new_watcher(test_option)
|
|
97
|
+
|
|
98
|
+
self.enforcer.set_watcher(watcher)
|
|
99
|
+
self.watcher = watcher
|
|
100
|
+
self.enforcer.save_policy()
|
|
101
|
+
|
|
102
|
+
except Exception as e:
|
|
103
|
+
logger.error(f"Failed to initialize Redis watcher: {e}")
|
|
104
|
+
self.watcher = None
|
|
105
|
+
else:
|
|
106
|
+
logger.info("Redis watcher not configured - Casbin will work without real-time policy updates")
|
|
107
|
+
|
|
57
108
|
def add_policy(self,role:str,resource:str,action:str,module:str):
|
|
58
109
|
"""
|
|
59
110
|
Add a policy to the casbin enforcer
|
|
@@ -104,13 +155,14 @@ class RBACService:
|
|
|
104
155
|
"""
|
|
105
156
|
with self.db() as session:
|
|
106
157
|
try:
|
|
107
|
-
if hasattr(permissions
|
|
108
|
-
|
|
158
|
+
if hasattr(permissions,'model_dump'):
|
|
159
|
+
add_permissions = [Permission(**permission.model_dump()) for permission in permissions]
|
|
109
160
|
else:
|
|
110
|
-
|
|
111
|
-
|
|
161
|
+
add_permissions = [Permission(**permission) for permission in permissions]
|
|
162
|
+
|
|
163
|
+
session.bulk_save_objects(add_permissions)
|
|
112
164
|
session.commit()
|
|
113
|
-
return
|
|
165
|
+
return add_permissions
|
|
114
166
|
except Exception as e:
|
|
115
167
|
raise e
|
|
116
168
|
|
|
@@ -161,7 +213,7 @@ class RBACService:
|
|
|
161
213
|
self.revoke_user_permissions(user_uuid,list(remove_permissions))
|
|
162
214
|
if add_permissions:
|
|
163
215
|
self.attach_permissions_to_user(user_uuid,list(add_permissions))
|
|
164
|
-
return
|
|
216
|
+
return self.get_user_permissions(user_uuid)
|
|
165
217
|
|
|
166
218
|
def attach_permissions_to_user(self, user_uuid: str, permission_uuids: List[str]):
|
|
167
219
|
with self.db() as session:
|
|
@@ -181,7 +233,7 @@ class RBACService:
|
|
|
181
233
|
if added_policies:
|
|
182
234
|
self.enforcer.save_policy()
|
|
183
235
|
self.enforcer.load_policy()
|
|
184
|
-
return
|
|
236
|
+
return self.get_user_permissions(user_uuid)
|
|
185
237
|
|
|
186
238
|
|
|
187
239
|
def revoke_user_permissions(self, user_uuid: str, permission_uuids: List[str]):
|
|
@@ -852,3 +904,55 @@ class RBACService:
|
|
|
852
904
|
else:
|
|
853
905
|
with self.db() as session:
|
|
854
906
|
return query_role(session)
|
|
907
|
+
|
|
908
|
+
def is_watcher_active(self) -> bool:
|
|
909
|
+
"""Check if Redis watcher is active and connected"""
|
|
910
|
+
return self.watcher is not None and hasattr(self.watcher, 'pub_client') and self.watcher.pub_client is not None
|
|
911
|
+
|
|
912
|
+
def get_watcher_status(self) -> dict:
|
|
913
|
+
"""Get detailed watcher status information"""
|
|
914
|
+
if not self.is_watcher_active():
|
|
915
|
+
return {
|
|
916
|
+
"active": False,
|
|
917
|
+
"message": "Watcher not initialized or not active"
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
try:
|
|
921
|
+
# Test Redis connection
|
|
922
|
+
self.watcher.pub_client.ping()
|
|
923
|
+
return {
|
|
924
|
+
"active": True,
|
|
925
|
+
"host": self.watcher.pub_client.connection_pool.connection_kwargs.get('host'),
|
|
926
|
+
"port": self.watcher.pub_client.connection_pool.connection_kwargs.get('port'),
|
|
927
|
+
"channel": getattr(self.watcher, 'channel', 'unknown'),
|
|
928
|
+
"connected": True
|
|
929
|
+
}
|
|
930
|
+
except Exception as e:
|
|
931
|
+
return {
|
|
932
|
+
"active": False,
|
|
933
|
+
"error": str(e),
|
|
934
|
+
"message": "Watcher exists but Redis connection failed"
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
def reload_policies(self) -> bool:
|
|
938
|
+
"""Manually reload policies from database"""
|
|
939
|
+
try:
|
|
940
|
+
self.enforcer.load_policy()
|
|
941
|
+
return True
|
|
942
|
+
except Exception as e:
|
|
943
|
+
print(f"Failed to reload policies: {e}")
|
|
944
|
+
return False
|
|
945
|
+
|
|
946
|
+
def get_policy_count(self) -> int:
|
|
947
|
+
"""Get the total number of policies in the enforcer"""
|
|
948
|
+
return len(self.enforcer.get_policy())
|
|
949
|
+
|
|
950
|
+
def clear_all_policies(self) -> bool:
|
|
951
|
+
"""Clear all policies from the enforcer (use with caution)"""
|
|
952
|
+
try:
|
|
953
|
+
self.enforcer.clear_policy()
|
|
954
|
+
self.enforcer.save_policy()
|
|
955
|
+
return True
|
|
956
|
+
except Exception as e:
|
|
957
|
+
print(f"Failed to clear policies: {e}")
|
|
958
|
+
return False
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "abs-auth-rbac-core"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.16"
|
|
4
4
|
description = "RBAC and Auth core utilities including JWT token management."
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "AutoBridgeSystems", email = "info@autobridgesystems.com"}
|
|
@@ -16,7 +16,8 @@ dependencies = [
|
|
|
16
16
|
"sqlalchemy (>=2.0.40,<3.0.0)",
|
|
17
17
|
"casbin (>=1.41.0,<2.0.0)",
|
|
18
18
|
"casbin-sqlalchemy-adapter (>=1.4.0,<2.0.0)",
|
|
19
|
-
"psycopg2-binary (>=2.9.10,<3.0.0)"
|
|
19
|
+
"psycopg2-binary (>=2.9.10,<3.0.0)",
|
|
20
|
+
"casbin-redis-watcher (>=1.3.0,<2.0.0)"
|
|
20
21
|
]
|
|
21
22
|
|
|
22
23
|
[build-system]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/auth/auth_functions.py
RENAMED
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/auth/jwt_functions.py
RENAMED
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/auth/middleware.py
RENAMED
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/__init__.py
RENAMED
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/base_model.py
RENAMED
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/gov_casbin_rule.py
RENAMED
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/permissions.py
RENAMED
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/rbac_model.py
RENAMED
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/role_permission.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/user_permission.py
RENAMED
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/models/user_role.py
RENAMED
|
File without changes
|
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/rbac/decorator.py
RENAMED
|
File without changes
|
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/schema/__init__.py
RENAMED
|
File without changes
|
{abs_auth_rbac_core-0.1.14 → abs_auth_rbac_core-0.1.16}/abs_auth_rbac_core/schema/permission.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|