Katkat

Implement Role-Aware User Information Views

IntuitStaff Software Engineer · Technical Screen

Last updated

Implement a field-level access control engine that redacts sensitive attributes from user profile records based on viewer permissions, context, and ownership relationships.

Problem Statement

In multi-tenant financial and HR platforms, user profile data contains varying levels of sensitivity (e.g., public display names, internal email addresses, and restricted data such as compensation or tax identifiers).

Implement a role-aware profile sanitizer ProfileSanitizer that filters user profile records before returning them to clients. The sanitizer must enforce field-level permissions based on the viewer's role, the viewer's relationship to the target user (horizontal access control), and the query context ("detail" vs "list").

Access Rules

  1. Roles: A user can have one of three roles: "ADMIN", "MANAGER", or "EMPLOYEE".
  2. Field Policies:
    • id, name: Visible to everyone in all contexts.
    • department: Visible to everyone in all contexts.
    • email: Visible to ADMIN, the user themselves (SELF), or any colleague in the same department.
    • phone: Visible to ADMIN, the user's direct manager (MANAGER), or SELF.
    • salary, ssn: Visible only to ADMIN, and to the user's direct manager only when viewing in "detail" context. A user cannot view their own ssn via this endpoint.
  3. Context Sensitivity:
    • In "list" context, salary and ssn are always excluded, even for ADMIN.

Interface

class ProfileSanitizer:
    def __init__(self):
        pass

    def sanitize_profile(
        self, 
        viewer: dict, 
        target_user: dict, 
        context: str = "detail"
    ) -> dict:
        """
        Returns a new dictionary containing only the fields the viewer
        is authorized to see for target_user under the given context.
        """
        pass

Input Format

  • viewer: {"id": str, "role": str, "department": str}
  • target_user: {"id": str, "name": str, "department": str, "manager_id": str, "email": str, "phone": str, "salary": int, "ssn": str}
  • context: Either "detail" or "list".

Example 1

viewer = {"id": "u2", "role": "EMPLOYEE", "department": "Engineering"}
target = {
    "id": "u1",
    "name": "Alice",
    "department": "Engineering",
    "manager_id": "u3",
    "email": "[email protected]",
    "phone": "555-0100",
    "salary": 120000,
    "ssn": "000-00-0000"
}
sanitizer = ProfileSanitizer()
result = sanitizer.sanitize_profile(viewer, target, context="detail")

Output:

{
    "id": "u1",
    "name": "Alice",
    "department": "Engineering",
    "email": "[email protected]"
}

Explanation: The viewer is in the same department (Engineering), so email is allowed. However, the viewer is not Alice (SELF), not Alice's manager, and not an ADMIN, so phone, salary, and ssn are stripped.

Constraints

  • viewer and target_user dictionaries will always contain their required schema keys.
  • context is guaranteed to be either "detail" or "list".
  • The function must return a new dictionary without mutating target_user.

Hints

Hint 1

Determine the viewer-to-target relationship first (is_self, is_admin, is_manager, is_same_dept) before evaluating individual field predicates.

Hint 2

Decouple field visibility rules into a declarative policy map rather than using nested if-else blocks.

Hint 3

Remember that context rules can override role permissions (for instance, list context always suppressing salary and ssn regardless of viewer role).

Follow-up questions

  • How would you optimize this sanitizer when transforming a paginated list of 1,000 target users for the same viewer?
  • How would you integrate this authorization logic with GraphQL field resolvers or an ORM without causing N+1 query problems?
  • If business requirements demand audit logging whenever restricted fields like SSN are accessed, where and how would you hook that in without coupling audit side-effects to the sanitizer logic?