How to? : RBAC implementation in React SPA + Django Backend using Azure AD token claims, roles, groups. #342

am looking for guidance on how to implement RBAC using django-auth-adfs in following scenario.

# Scenario/Setup.

  1. Backend Service: Django DRF REST APIs
    a. Manages ‘Employee’ information.
    b. Manage ‘Team’ information. Team ‘Model’ has 'Employee’s.
    c. Employees will be added/deleted from Team from time to time. Such ‘management action’ of addition/deletion to ‘Team’ should automatically result in ‘adding’ access or ‘revoking’ access - if we have done some initial setup for RBAC.
    d. ‘Group’ Model: Not yet defined. But, thinking of defining ‘Group’ Model. A ‘Team’ can have associated ‘Group’.
    e. ‘Group’ can exist without ‘Team’ Model as well. But, every ‘Team’ must have a ‘Group’.
    f. Group creation/deletion should be synced to Azure AD Groups (may be via Celery Task)
    g. ‘Group’ membership adding/deleting should also be synced to Azure AD Groups (may be via Celery Task)
  2. Frontend App: React SPA Application
    a. User can login to React SPA App with Microsoft login id/password/MFA. This works. Able to get ID Token. Able to get ‘MS Graph’ access token and call ‘MS Graph’ API successfully.
    b. User is able to get ‘Access Token’ for ‘Backend Web API’. Able to call ‘Backend Web API’ successfully.
    c. Backend ‘Access Token’ contains:
    i. Groups: But they are only GUIDS (because it is Azure AD Cloud Only setup)
    ii. Roles: Contains ‘roles’ defined in ‘Azure AD App’.
  3. Authentication/Identity Server: Azure AD (cloud ONLY)
    a. Defined ‘role’ in ‘Azure AD App’ and assigned to ‘Users’. [I will assign to ‘Group’ when I upgrade my license]

# Requirements:

  1. Management Team should be able to update ‘Teams’ information in ‘Backend Service’ (via some React Portal - not relevant) and this should automatically result in ‘permission/access’ ‘granted’ or ‘revoked’ for various services/apps in our tech infrastructure for company.
  2. React SPA need to have some ‘conditional code’ to show some features/UI/operations. We should be able to ‘define roles’ and assign to ‘Groups’.
  3. Backend Service (Django) should also have ‘permissions’ based on roles/groups on various REST APIs (views).
  4. These ‘roles’ or ‘groups’ should be somehow linked to ‘Groups’ defined for ‘Teams’ so that ‘automatic access control’ requirement mentioned in (1) is effective.
  5. If we come up with any new ‘React SPA’ or new ‘Backend Service’ (Django) in future, they should be able to follow similar approach easily and implement authorization for their service/apps. If required, they can also suggest and add new ‘Teams’ in this first/main ‘Backend Service’ (Django).

# Solution-1:

  1. Create ‘Groups’ in Django Backend Service. Sync them to Azure AD periodically.
  2. Define ‘roles’ n ‘Azure AD App’. Assign ‘roles’ to ‘Azure AD Groups’. [Hierarchical Azure AD Groups can be created to manage this well.]
  3. Get ‘roles’ in ‘access token’.
  4. Write code in Django Backend Service by checking if ‘request.user.token.roles’ contains [Required set of role names] for each view. ‘Required set of role names’ is hardcoded in Django Backend Service code.

## Problems with Solution-1:

  1. ‘Required set of groups (roles)’ is hard code in Django Backend Code. Any change will require ‘Backend Service’ re-deployment.
    a. Can we expose this by defining custom permission model and updating this dynamically if there are any changes?

# Solution-2:

  1. Create ‘Groups’ in Django Backend Service. Sync them to Azure AD periodically.
  2. Define ‘roles’ n ‘Azure AD App’. Assign ‘roles’ to ‘Azure AD Groups’. [Hierarchical Azure AD Groups can be created to manage this well.]
  3. Get ‘roles’ in ‘access token’.
  4. Q: With GROUPS_CLAIM = roles and MIRROR_GROUPS = True, I think ‘groups’ with same name as ‘roles’ will be created in Django. User will be added or removed from these group on every request. I am yet to try this. Please confirm if my understanding is correct.
  5. Write code in Django Backend Service by checking if ‘request.user’ belongs to [Required set of groups] for each view. ‘Required set of groups’ is hardcoded in Django Backend Service code. These groups are same as ‘role names’. I think new ‘roles’ get added less often so, this hardcoding should be fine.

## Problems with Solution-2:

  1. For every request received, user group membership is completely erased and group membership is added based on ‘roles’ in token. Too much churning for every request?

# Questions:

  1. There are inline questions as well in above descriptions. If someone can help in that, it will be great.
  2. Does django-auth-adfs automatically give us all ‘claims’ as part of ‘request’ OR I will need to write my own middleware for it?
  3. How can I implement RBAC in this setup and requirements? I am not happy with both above solutions due to problems mentioned with it. Anyone has any recommendations for solution?