RoleBasedResourcePolicyResolver

A configuration-backed ResourcePolicyResolver that resolves static, role-based masking rules.

This is Ihawu's batteries-included resolver: the default, no-external-dependency way to drive masking without standing up an external engine (OPA, Casbin, ...). Rules are supplied up front as a list of ResourcePolicy entries mapping resource -> role -> field policies; resolution is a pure lookup against the principal's roles. Ihawu stays a Policy Enforcement Point — the configuration is the pre-resolved policy, and no conditions are evaluated here.

Resolution semantics:

  • Union across roles — the field policies of every role the principal holds are combined.

  • Most-restrictive-wins — when two roles mask the same field, the stricter org.ihawu.core.masking.MaskingStrategy is kept (e.g. HIDE outranks REDACT).

  • Deterministic — ties between equal strategies are broken by role-name order, so the result never depends on Set iteration order.

  • Fail-open on absence — an unknown resource, a role with no configured policy, or a principal with no roles yields an empty list; the caller decides default visibility.

Rules are supplied directly as a List of ResourcePolicy. To load them from JSON configuration instead, use JacksonPolicyConfig.fromJson in the ihawu-jackson module.

Parameters

resourcePolicies

The static resource -> role -> field policies rules to resolve against.

See also

Samples

// Static rules: for the "employee" resource, the MANAGER role redacts salary.
val rules =
    listOf(
        ResourcePolicy(
            resourceName = "employee",
            roleFieldPolicies =
                mapOf(
                    "MANAGER" to listOf(FieldPolicy("salary", MaskingStrategy.REDACT, placeholder = "***")),
                ),
        ),
    )
val resolver = RoleBasedResourcePolicyResolver(rules)

val principal = IhawuPrincipal("u1", roles = setOf("MANAGER"), attributes = emptyMap())
val policies = resolver.resolve(principal, "employee")

check(policies == listOf(FieldPolicy("salary", MaskingStrategy.REDACT, "***")))
// The principal holds two roles that mask the same field; HIDE outranks REDACT.
val rules =
    listOf(
        ResourcePolicy(
            resourceName = "employee",
            roleFieldPolicies =
                mapOf(
                    "MANAGER" to listOf(FieldPolicy("salary", MaskingStrategy.REDACT, placeholder = "***")),
                    "AUDITOR" to listOf(FieldPolicy("salary", MaskingStrategy.HIDE)),
                ),
        ),
    )
val resolver = RoleBasedResourcePolicyResolver(rules)

val principal = IhawuPrincipal("u1", roles = setOf("MANAGER", "AUDITOR"), attributes = emptyMap())
val policies = resolver.resolve(principal, "employee")

check(policies == listOf(FieldPolicy("salary", MaskingStrategy.HIDE)))

Constructors

Link copied to clipboard
constructor(resourcePolicies: List<ResourcePolicy>)

Functions

Link copied to clipboard
open override fun resolve(principal: IhawuPrincipal, resource: String): List<FieldPolicy>

Resolves the resource field policies that apply when principal requests resource.