abs-auth-rbac-core 0.1.4__tar.gz → 0.1.6__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.

Files changed (27) hide show
  1. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/PKG-INFO +1 -1
  2. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/auth/middleware.py +1 -1
  3. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/models/__init__.py +2 -1
  4. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/models/permissions.py +6 -0
  5. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/models/user.py +7 -1
  6. abs_auth_rbac_core-0.1.6/abs_auth_rbac_core/models/user_permission.py +15 -0
  7. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/rbac/decorator.py +3 -3
  8. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/rbac/service.py +188 -22
  9. abs_auth_rbac_core-0.1.6/abs_auth_rbac_core/schema/__init__.py +1 -0
  10. abs_auth_rbac_core-0.1.6/abs_auth_rbac_core/schema/permission.py +9 -0
  11. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/pyproject.toml +1 -1
  12. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/README.md +0 -0
  13. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/__init__.py +0 -0
  14. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/auth/__init__.py +0 -0
  15. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/auth/auth_functions.py +0 -0
  16. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/auth/jwt_functions.py +0 -0
  17. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/models/base_model.py +0 -0
  18. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/models/gov_casbin_rule.py +0 -0
  19. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/models/rbac_model.py +0 -0
  20. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/models/role_permission.py +0 -0
  21. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/models/roles.py +0 -0
  22. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/models/seeder/permission_seeder.py +0 -0
  23. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/models/user_role.py +0 -0
  24. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/rbac/__init__.py +0 -0
  25. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/rbac/policy.conf +0 -0
  26. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/abs_auth_rbac_core/util/__init__.py +0 -0
  27. {abs_auth_rbac_core-0.1.4 → abs_auth_rbac_core-0.1.6}/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.4
3
+ Version: 0.1.6
4
4
  Summary: RBAC and Auth core utilities including JWT token management.
5
5
  License: MIT
6
6
  Author: AutoBridgeSystems
@@ -43,7 +43,7 @@ def auth_middleware(
43
43
 
44
44
  # Attach user to request state
45
45
  request.state.user = user
46
- return user # Still return user for backward compatibility
46
+ return user
47
47
 
48
48
  except Exception as e:
49
49
  logger.error(f"Authentication error: {str(e)}", exc_info=True)
@@ -3,5 +3,6 @@ from .roles import Role
3
3
  from .user_role import UserRole
4
4
  from .user import Users
5
5
  from .role_permission import RolePermission
6
+ from .user_permission import UserPermission
6
7
 
7
- __all__ = ["Permission", "Role", "UserRole", "Users","RolePermission"]
8
+ __all__ = ["Permission", "Role", "UserRole", "Users","RolePermission","UserPermission"]
@@ -24,3 +24,9 @@ class Permission(RBACBaseModel):
24
24
  roles = relationship(
25
25
  "Role", secondary="gov_role_permissions", back_populates="permissions"
26
26
  )
27
+
28
+ user_permissions = relationship(
29
+ "UserPermission",
30
+ back_populates="permission",
31
+ cascade="all, delete-orphan"
32
+ )
@@ -24,4 +24,10 @@ class Users(BaseModel):
24
24
  overlaps="roles"
25
25
  )
26
26
 
27
- eagers = ["roles"]
27
+ user_permissions = relationship(
28
+ "UserPermission",
29
+ back_populates="user",
30
+ cascade="all, delete-orphan"
31
+ )
32
+
33
+ eagers = ["roles","user_permissions"]
@@ -0,0 +1,15 @@
1
+ from sqlalchemy import Column, ForeignKey, String
2
+ from sqlalchemy.orm import relationship
3
+ from abs_auth_rbac_core.models.base_model import BaseModel
4
+
5
+
6
+ class UserPermission(BaseModel):
7
+ """Association model between users and permissions"""
8
+
9
+ __tablename__ = "gov_user_permissions"
10
+
11
+ user_uuid = Column(String(36), ForeignKey("gov_users.uuid"), index=True)
12
+ permission_uuid = Column(String(36), ForeignKey("gov_permissions.uuid"), index=True)
13
+
14
+ user = relationship("Users", back_populates="user_permissions")
15
+ permission = relationship("Permission", back_populates="user_permissions")
@@ -23,8 +23,8 @@ def rbac_require_permission(permissions: Union[str, List[str]]):
23
23
  request:Request,
24
24
  *args,rbac_service:RBACService, **kwargs,
25
25
  ):
26
- current_user_id = request.state.user.uuid
27
- if not current_user_id:
26
+ current_user_uuid = request.state.user.uuid
27
+ if not current_user_uuid:
28
28
  raise PermissionDeniedError(
29
29
  detail="User not found (missing 'uuid')."
30
30
  )
@@ -37,7 +37,7 @@ def rbac_require_permission(permissions: Union[str, List[str]]):
37
37
  )
38
38
 
39
39
  has_permission = rbac_service.check_permission(
40
- user_uuid=current_user_id, resource=resource, action=action,module=module
40
+ user_uuid=current_user_uuid, resource=resource, action=action,module=module
41
41
  )
42
42
 
43
43
  if not has_permission:
@@ -1,16 +1,17 @@
1
- from typing import List, Optional, Callable,Any
1
+ from typing import List, Optional, Callable,Any,Tuple
2
2
  import os
3
3
  import casbin
4
4
  from casbin_sqlalchemy_adapter import Adapter
5
5
  from sqlalchemy import and_, select
6
6
  from sqlalchemy.orm import Session, joinedload
7
-
7
+ from ..schema import CreatePermissionSchema
8
8
  from ..models import (
9
9
  Role,
10
10
  RolePermission,
11
11
  UserRole,
12
12
  Users,
13
- Permission
13
+ Permission,
14
+ UserPermission
14
15
  )
15
16
 
16
17
  from abs_exception_core.exceptions import (
@@ -52,8 +53,151 @@ class RBACService:
52
53
  )
53
54
  # Load policies
54
55
  self.enforcer.load_policy()
56
+
57
+ def add_policy(self,role:str,resource:str,action:str,module:str):
58
+ """
59
+ Add a policy to the casbin enforcer
60
+ """
61
+ self.enforcer.add_policy(role,resource,action,module)
62
+ self.enforcer.save_policy()
63
+
64
+ def remove_policy(self,role:str,resource:str,action:str,module:str):
65
+ """
66
+ Remove a policy from the casbin enforcer
67
+ """
68
+ self.enforcer.remove_policy(role,resource,action,module)
69
+ self.enforcer.save_policy()
70
+
71
+ def add_policies(self,policies:List[Tuple[str,str,str,str]]):
72
+ """
73
+ Add a list of policies to the casbin enforcer
74
+ """
75
+ self.enforcer.add_policies(policies)
76
+ self.enforcer.save_policy()
77
+
78
+ def remove_policies(self,policies:List[List[str]]):
79
+ """
80
+ Remove a list of policies from the casbin enforcer
81
+ """
82
+ self.enforcer.remove_policies(policies)
83
+ self.enforcer.save_policy()
84
+
85
+ def enforce_policy(self,role:str,resource:str,action:str,module:str):
86
+ """
87
+ Enforce a policy
88
+ """
89
+ return self.enforcer.enforce(role,resource,action,module)
90
+
91
+ def remove_filter_policy(self,index:int,value:str):
92
+ """
93
+ Remove a policy by filtering the policy
94
+ Args:
95
+ index: The index of the policy to remove
96
+ value: The value of the policy to remove
97
+ """
98
+ self.enforcer.remove_filtered_policy(index,value)
99
+ self.enforcer.save_policy()
100
+
101
+ async def bulk_create_permissions(self,permissions:List[CreatePermissionSchema]):
102
+ """
103
+ Bulk create permissions for user
104
+ """
105
+ with self.db() as session:
106
+ try:
107
+ permission_objs = [Permission(**permission.model_dump()) for permission in permissions]
108
+ session.bulk_save_objects(permission_objs)
109
+ session.commit()
110
+ return permission_objs
111
+ except Exception as e:
112
+ raise e
55
113
 
114
+ async def get_permissions_by_condition(self, condition: dict, use_filter_by: bool = True):
115
+ """
116
+ Get permission(s) based on a condition dict.
117
+ If use_filter_by is True, assumes all conditions are `==`.
118
+ """
119
+ with self.db() as session:
120
+ try:
121
+ query = session.query(Permission)
122
+ if use_filter_by:
123
+ query = query.filter_by(**condition)
124
+ else:
125
+ filters = [getattr(Permission, k) == v for k, v in condition.items()]
126
+ query = query.filter(*filters)
127
+ return query.all()
128
+ except Exception as e:
129
+ raise e
130
+
131
+ async def delete_permission_by_uuids(self,permission_uuids:List[str]):
132
+ """
133
+ Delete a permission by uuids
134
+ """
135
+ with self.db() as session:
136
+ try:
137
+ permissions = session.query(Permission).filter(Permission.uuid.in_(permission_uuids))
138
+ for permission in permissions:
139
+ self.enforcer.remove_filtered_policy(1,permission.resource)
140
+ self.enforcer.save_policy()
141
+
142
+ permissions.delete(synchronize_session=False)
143
+ session.commit()
144
+ return True
145
+ except Exception as e:
146
+ raise e
147
+
148
+ def assign_permissions_to_user(self,user_uuid:str,permission_uuids:List[str]):
149
+ """
150
+ Assign permissions to a user
151
+ """
152
+ with self.db() as session:
153
+ current_permissions = session.query(UserPermission).filter(UserPermission.user_uuid==user_uuid).all()
154
+ current_permission_uuids = [permission.permission_uuid for permission in current_permissions]
155
+ remove_permissions = set(current_permission_uuids) - set(permission_uuids)
156
+ add_permissions = set(permission_uuids) - set(current_permission_uuids)
157
+ if remove_permissions:
158
+ self.revoke_user_permissions(user_uuid,list(remove_permissions))
159
+ if add_permissions:
160
+ self.attach_permissions_to_user(user_uuid,list(add_permissions))
161
+ return True
56
162
 
163
+ def attach_permissions_to_user(self, user_uuid: str, permission_uuids: List[str]):
164
+ with self.db() as session:
165
+ user_permissions = [
166
+ UserPermission(user_uuid=user_uuid, permission_uuid=permission_uuid)
167
+ for permission_uuid in permission_uuids
168
+ ]
169
+ session.bulk_save_objects(user_permissions)
170
+ session.commit()
171
+
172
+ permissions = session.query(Permission).filter(Permission.uuid.in_(permission_uuids)).all()
173
+ policies = [
174
+ [f"user:{user_uuid}", permission.resource, permission.action, permission.module]
175
+ for permission in permissions
176
+ ]
177
+ self.enforcer.add_policies(policies)
178
+ self.enforcer.save_policy()
179
+ return user_permissions
180
+
181
+
182
+ def revoke_user_permissions(self, user_uuid: str, permission_uuids: List[str]):
183
+ with self.db() as session:
184
+ user_permissions = session.query(UserPermission).filter(
185
+ UserPermission.user_uuid == user_uuid,
186
+ UserPermission.permission_uuid.in_(permission_uuids)
187
+ )
188
+
189
+ permissions = session.query(Permission).filter(Permission.uuid.in_(permission_uuids)).all()
190
+ policies = [
191
+ [f"user:{user_uuid}", permission.resource, permission.action, permission.module]
192
+ for permission in permissions
193
+ ]
194
+ self.enforcer.remove_policies(policies)
195
+ self.enforcer.save_policy()
196
+
197
+ user_permissions.delete(synchronize_session=False)
198
+ session.commit()
199
+ return True
200
+
57
201
  def list_roles(self) -> Any:
58
202
  """
59
203
  Get the list of all roles
@@ -136,7 +280,7 @@ class RBACService:
136
280
 
137
281
  # Batch add Casbin policies
138
282
  policies = [
139
- (role.name, permission.resource, permission.action, permission.module)
283
+ [role.uuid, permission.resource, permission.action, permission.module]
140
284
  for permission in existing_permissions
141
285
  ]
142
286
  self.enforcer.add_policies(policies)
@@ -213,13 +357,11 @@ class RBACService:
213
357
  existing_permissions = role.permissions
214
358
 
215
359
  # Remove Casbin policies for existing permissions
216
- for existing_permission in existing_permissions:
217
- self.enforcer.remove_policy(
218
- role.name,
219
- existing_permission.resource,
220
- existing_permission.action,
221
- existing_permission.module
222
- )
360
+ remove_policies = [
361
+ [role_uuid, existing_permission.resource, existing_permission.action, existing_permission.module]
362
+ for existing_permission in existing_permissions
363
+ ]
364
+ self.enforcer.remove_policies(remove_policies)
223
365
  self.enforcer.save_policy()
224
366
 
225
367
  # Delete existing role permissions
@@ -250,11 +392,11 @@ class RBACService:
250
392
  session.bulk_insert_mappings(RolePermission, role_permissions)
251
393
 
252
394
  # Add Casbin policies
253
- for permission in permissions_objs:
254
- self.enforcer.add_policy(
255
- role.name, permission.resource, permission.action, permission.module
256
- )
257
-
395
+ policies = [
396
+ [role_uuid, permission.resource, permission.action, permission.module]
397
+ for permission in permissions_objs
398
+ ]
399
+ self.enforcer.add_policies(policies)
258
400
  self.enforcer.save_policy()
259
401
 
260
402
  session.commit()
@@ -290,7 +432,7 @@ class RBACService:
290
432
 
291
433
  # Collect all policies to remove from the eagerly loaded permissions
292
434
  remove_policies = [
293
- [role.name, permission.resource, permission.action, permission.module]
435
+ [role.uuid, permission.resource, permission.action, permission.module]
294
436
  for permission in role.permissions
295
437
  ]
296
438
 
@@ -317,6 +459,30 @@ class RBACService:
317
459
  with self.db() as session:
318
460
  return session.query(Permission).filter(Permission.module == module).all()
319
461
 
462
+ def get_user_only_permissions(self, user_uuid: str) -> List[Any]:
463
+ """Get all allowed permissions for a user"""
464
+ with self.db() as session:
465
+ user_permissions = (
466
+ session.query(UserPermission)
467
+ .filter(UserPermission.user_uuid == user_uuid)
468
+ .options(joinedload(UserPermission.permission))
469
+ .all()
470
+ )
471
+ result = []
472
+ for user_permission in user_permissions:
473
+ result.append(
474
+ {
475
+ "permission_id": user_permission.permission.id,
476
+ "created_at": user_permission.permission.created_at,
477
+ "updated_at": user_permission.permission.updated_at,
478
+ "name": user_permission.permission.name,
479
+ "resource": user_permission.permission.resource,
480
+ "action": user_permission.permission.action,
481
+ "module": user_permission.permission.module
482
+ }
483
+ )
484
+ return result
485
+
320
486
  def get_user_permissions(self, user_uuid: str) -> List[Any]:
321
487
  """Get all allowed permissions for a user"""
322
488
  with self.db() as session:
@@ -397,7 +563,7 @@ class RBACService:
397
563
 
398
564
  # Remove Casbin policies
399
565
  policies_to_remove = [
400
- (role.name, permission.resource, permission.action, permission.module)
566
+ (role.uuid, permission.resource, permission.action, permission.module)
401
567
  for permission in permissions_to_revoke
402
568
  ]
403
569
  self.enforcer.remove_policies(policies_to_remove)
@@ -465,7 +631,7 @@ class RBACService:
465
631
 
466
632
  # Add Casbin policies
467
633
  policies_to_add = [
468
- (role.name, permission.resource, permission.action, permission.module)
634
+ (role.uuid, permission.resource, permission.action, permission.module)
469
635
  for permission in new_permissions
470
636
  ]
471
637
  self.enforcer.add_policies(policies_to_add)
@@ -648,15 +814,15 @@ class RBACService:
648
814
  )
649
815
  for role in roles:
650
816
  # Try with module first
651
- if self.enforcer.enforce(role.name, resource, action, module):
817
+ if self.enforcer.enforce(role.uuid, resource, action, module):
652
818
  return True
653
819
  return False
654
820
 
655
821
  def check_permission_by_role(
656
- self, role_name: str, resource: str, action: str, module: str
822
+ self, role_uuid: str, resource: str, action: str, module: str
657
823
  ) -> bool:
658
824
  # Try with module first
659
- if self.enforcer.enforce(role_name, resource, action, module):
825
+ if self.enforcer.enforce(role_uuid, resource, action, module):
660
826
  return True
661
827
  return False
662
828
 
@@ -0,0 +1 @@
1
+ from .permission import CreatePermissionSchema
@@ -0,0 +1,9 @@
1
+ from pydantic import BaseModel
2
+ from typing import Optional
3
+
4
+ class CreatePermissionSchema(BaseModel):
5
+ name: str
6
+ description: Optional[str] = None
7
+ resource: str
8
+ action: str
9
+ module: str
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "abs-auth-rbac-core"
3
- version = "0.1.4"
3
+ version = "0.1.6"
4
4
  description = "RBAC and Auth core utilities including JWT token management."
5
5
  authors = [
6
6
  {name = "AutoBridgeSystems", email = "info@autobridgesystems.com"}