|
1 | 1 | import logging |
2 | 2 | import uuid |
3 | 3 | from datetime import datetime |
4 | | -from typing import Optional, Tuple |
| 4 | +from typing import Optional |
5 | 5 |
|
6 | 6 | import jwt |
7 | | -from django.apps import apps |
8 | | -from django.conf import settings |
9 | 7 | from django.contrib.auth import get_user_model |
10 | 8 | from django.core.exceptions import ObjectDoesNotExist |
11 | | -from django.db.models import Model |
12 | 9 | from django.db.utils import IntegrityError |
13 | 10 | from rest_framework.authentication import BaseAuthentication |
14 | 11 | from rest_framework.exceptions import AuthenticationFailed |
|
19 | 16 | from ansible_base.lib.logging.runtime import log_excess_runtime |
20 | 17 | from ansible_base.lib.utils.auth import get_user_by_ansible_id |
21 | 18 | from ansible_base.lib.utils.translations import translatableConditionally as _ |
22 | | -from ansible_base.rbac.claims import get_claims_hash, get_user_claims, get_user_claims_hashable_form |
| 19 | +from ansible_base.rbac.claims import get_claims_hash, get_user_claims, get_user_claims_hashable_form, save_user_claims |
23 | 20 | from ansible_base.resource_registry.models import Resource, ResourceType |
24 | 21 | from ansible_base.resource_registry.rest_client import get_resource_server_client |
25 | 22 | from ansible_base.resource_registry.signals.handlers import no_reverse_sync |
@@ -241,25 +238,6 @@ def decode_jwt_token(self, unencrypted_token, decryption_key, additional_options |
241 | 238 | algorithms=["RS256"], |
242 | 239 | ) |
243 | 240 |
|
244 | | - @staticmethod |
245 | | - def get_role_definition(name: str) -> Optional[Model]: |
246 | | - """Simply get the RoleDefinition from the database if it exists and handler corner cases |
247 | | -
|
248 | | - If this is the name of a managed role for which we have a corresponding definition in code, |
249 | | - and that role can not be found in the database, it may be created here |
250 | | - """ |
251 | | - from ansible_base.rbac.models import RoleDefinition |
252 | | - |
253 | | - try: |
254 | | - return RoleDefinition.objects.get(name=name) |
255 | | - except RoleDefinition.DoesNotExist: |
256 | | - |
257 | | - constructor = permission_registry().get_managed_role_constructor_by_name(name) |
258 | | - if constructor: |
259 | | - rd, _ = constructor.get_or_create(apps) |
260 | | - return rd |
261 | | - return None |
262 | | - |
263 | 241 | def process_rbac_permissions(self): |
264 | 242 | """ |
265 | 243 | Process RBAC permissions using claims hash logic |
@@ -314,7 +292,7 @@ def process_rbac_permissions(self): |
314 | 292 | global_roles = gateway_claims.get('global_roles', []) |
315 | 293 |
|
316 | 294 | # Process the RBAC permissions with the gateway claims |
317 | | - self._apply_rbac_permissions(objects, object_roles, global_roles) |
| 295 | + save_user_claims(self.user, objects, object_roles, global_roles) |
318 | 296 |
|
319 | 297 | # Update cache with the new hash |
320 | 298 | self.cache.cache_claims_hash(user_ansible_id, jwt_claims_hash) |
@@ -345,110 +323,6 @@ def _fetch_jwt_claims_from_gateway(self, user_ansible_id: str) -> Optional[dict] |
345 | 323 | logger.error(f"Error fetching claims from gateway: {e}") |
346 | 324 | return None |
347 | 325 |
|
348 | | - @staticmethod |
349 | | - def _apply_rbac_permissions(user, objects: dict, object_roles: dict, global_roles: list) -> None: |
350 | | - """ |
351 | | - Apply RBAC permissions from claims data |
352 | | - """ |
353 | | - from ansible_base.rbac.models import RoleUserAssignment |
354 | | - |
355 | | - role_diff = RoleUserAssignment.objects.filter(user=user, role_definition__name__in=settings.ANSIBLE_BASE_JWT_MANAGED_ROLES) |
356 | | - |
357 | | - for system_role_name in global_roles: |
358 | | - logger.debug(f"Processing system role {system_role_name} for {user.username}") |
359 | | - rd = JWTCommonAuth.get_role_definition(system_role_name) |
360 | | - if rd: |
361 | | - if rd.name in settings.ANSIBLE_BASE_JWT_MANAGED_ROLES: |
362 | | - assignment = rd.give_global_permission(user) |
363 | | - role_diff = role_diff.exclude(pk=assignment.pk) |
364 | | - logger.info(f"Granted user {user.username} global role {system_role_name}") |
365 | | - else: |
366 | | - logger.error(f"Unable to grant {user.username} system level role {system_role_name} because it is not a JWT managed role") |
367 | | - else: |
368 | | - logger.error(f"Unable to grant {user.username} system level role {system_role_name} because it does not exist") |
369 | | - continue |
370 | | - |
371 | | - for object_role_name in object_roles.keys(): |
372 | | - rd = JWTCommonAuth.get_role_definition(object_role_name) |
373 | | - if rd is None: |
374 | | - logger.error(f"Unable to grant {user.username} object role {object_role_name} because it does not exist") |
375 | | - continue |
376 | | - elif rd.name not in settings.ANSIBLE_BASE_JWT_MANAGED_ROLES: |
377 | | - logger.error(f"Unable to grant {user.username} object role {object_role_name} because it is not a JWT managed role") |
378 | | - continue |
379 | | - |
380 | | - object_type = object_roles[object_role_name]['content_type'] |
381 | | - object_indexes = object_roles[object_role_name]['objects'] |
382 | | - |
383 | | - for index in object_indexes: |
384 | | - object_data = objects[object_type][index] |
385 | | - try: |
386 | | - resource, obj = JWTCommonAuth.get_or_create_resource(objects, object_type, object_data) |
387 | | - except IntegrityError as e: |
388 | | - logger.warning( |
389 | | - f"Got integrity error ({e}) on {object_data}. Skipping {object_type} assignment. " |
390 | | - "Please make sure the sync task is running to prevent this warning in the future." |
391 | | - ) |
392 | | - continue |
393 | | - |
394 | | - if resource is not None: |
395 | | - assignment = rd.give_permission(user, obj) |
396 | | - role_diff = role_diff.exclude(pk=assignment.pk) |
397 | | - logger.info(f"Granted user {user.username} role {object_role_name} to object {obj.name} with ansible_id {object_data['ansible_id']}") |
398 | | - |
399 | | - # Remove all permissions not authorized by the JWT |
400 | | - for role_assignment in role_diff: |
401 | | - rd = role_assignment.role_definition |
402 | | - content_object = role_assignment.content_object |
403 | | - if content_object: |
404 | | - rd.remove_permission(user, content_object) |
405 | | - else: |
406 | | - rd.remove_global_permission(user) |
407 | | - |
408 | | - @staticmethod |
409 | | - def get_or_create_resource(objects: dict, content_type: str, data: dict) -> Tuple[Optional[Resource], Optional[Model]]: |
410 | | - """ |
411 | | - Gets or creates a resource from a content type and its default data |
412 | | -
|
413 | | - This can only build or get organizations or teams |
414 | | - """ |
415 | | - object_ansible_id = data['ansible_id'] |
416 | | - try: |
417 | | - resource = Resource.objects.get(ansible_id=object_ansible_id) |
418 | | - logger.debug(f"Resource {object_ansible_id} already exists") |
419 | | - return resource, resource.content_object |
420 | | - except Resource.DoesNotExist: |
421 | | - pass |
422 | | - |
423 | | - # The resource was missing so we need to create its stub |
424 | | - if content_type == 'team': |
425 | | - # For a team we first have to make sure the org is there |
426 | | - org_id = data['org'] |
427 | | - organization_data = objects["organization"][org_id] |
428 | | - |
429 | | - # Now that we have the org we can build a team |
430 | | - org_resource, _ = JWTCommonAuth.get_or_create_resource("organization", organization_data) |
431 | | - |
432 | | - resource = Resource.create_resource( |
433 | | - ResourceType.objects.get(name="shared.team"), |
434 | | - {"name": data["name"], "organization": org_resource.ansible_id}, |
435 | | - ansible_id=data["ansible_id"], |
436 | | - ) |
437 | | - |
438 | | - return resource, resource.content_object |
439 | | - |
440 | | - elif content_type == 'organization': |
441 | | - resource = Resource.create_resource( |
442 | | - ResourceType.objects.get(name="shared.organization"), |
443 | | - {"name": data["name"]}, |
444 | | - ansible_id=data["ansible_id"], |
445 | | - ) |
446 | | - |
447 | | - return resource, resource.content_object |
448 | | - else: |
449 | | - logger.error(f"build_resource_stub does not know how to build an object of type {type}") |
450 | | - return None, None |
451 | | - |
452 | 326 |
|
453 | 327 | class JWTAuthentication(BaseAuthentication): |
454 | 328 | map_fields = default_mapped_user_fields |
|
0 commit comments