abs-auth-rbac-core 0.1.14__py3-none-any.whl → 0.1.16__py3-none-any.whl

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.

@@ -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[0], "model_dump"):
108
- permission_objs = [Permission(**permission.model_dump()) for permission in permissions]
158
+ if hasattr(permissions,'model_dump'):
159
+ add_permissions = [Permission(**permission.model_dump()) for permission in permissions]
109
160
  else:
110
- permission_objs = [Permission(**permission) for permission in permissions]
111
- session.bulk_save_objects(permission_objs)
161
+ add_permissions = [Permission(**permission) for permission in permissions]
162
+
163
+ session.bulk_save_objects(add_permissions)
112
164
  session.commit()
113
- return permission_objs
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 True
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 user_permissions
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
  Metadata-Version: 2.3
2
2
  Name: abs-auth-rbac-core
3
- Version: 0.1.14
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)
@@ -17,11 +17,11 @@ abs_auth_rbac_core/models/user_role.py,sha256=20pqmtJPzlUrI9ulHGouk8XlFgrGG7I6ik
17
17
  abs_auth_rbac_core/rbac/__init__.py,sha256=oYjtpmfrkEbwWCBAWuRoU1fM4fCpBxkF_lwQrelK1As,79
18
18
  abs_auth_rbac_core/rbac/decorator.py,sha256=pEFAW0Nn2iE4KBctPhNOmO_VLeJFDX2V9v2LsCu6kHY,1824
19
19
  abs_auth_rbac_core/rbac/policy.conf,sha256=wghhhKxgZH0rPhh1QFrIpq9nevJT3s7OxxvXiU3zzuI,305
20
- abs_auth_rbac_core/rbac/service.py,sha256=xOG-tReDkvxJg4npWJIdS_S82U2sJJilcOsZotEYB1U,32888
20
+ abs_auth_rbac_core/rbac/service.py,sha256=zphCthuPGe_oRN6kMhGFzu4S-nOO8zPlI59qGeE62ZY,37048
21
21
  abs_auth_rbac_core/schema/__init__.py,sha256=v9xibJ8Wr9k0u6PEYNK0LCGUJD71SB5vxu9BZG0S7tM,46
22
22
  abs_auth_rbac_core/schema/permission.py,sha256=XvxPU68FY0PFgkF4GR2bSrzNvFB8c8OgY_d0JOJvMc8,203
23
23
  abs_auth_rbac_core/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  abs_auth_rbac_core/util/permission_constants.py,sha256=ICnn7mDoNt4_adUcbMjWtBeY2MgJu4F9qS5jRgR3nNU,92039
25
- abs_auth_rbac_core-0.1.14.dist-info/METADATA,sha256=OIzt2mP-ylG3n8BR3qfstFleu9pv0nBMufjzZJGb-8A,6636
26
- abs_auth_rbac_core-0.1.14.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
27
- abs_auth_rbac_core-0.1.14.dist-info/RECORD,,
25
+ abs_auth_rbac_core-0.1.16.dist-info/METADATA,sha256=CPCikBY4I10HbHfW0kYYG8Z5k73h8kpR3ERmDVeW1Kk,6689
26
+ abs_auth_rbac_core-0.1.16.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
27
+ abs_auth_rbac_core-0.1.16.dist-info/RECORD,,