Policy Source
The PolicySource
interface alleviates the responsibility of retrieving available policies from the DecisionPoint
.
They could be in memory, or stored in a DB or available from another service.
A PolicySource
defines a single method for retrieving a set of deny
and allow
policies based on
an AccessRequest
(or left null to fetch all policies).
The simplest Policy source is PolicySourceInMemory
.
val policySource = PolicySourceInMemory(
allow = listOf(
// Some set of policies that allow access.
),
deny = listOf(
// Some set of policies that deny access.
)
)
Information Point
An InformationPoint
is used by the DecisionPoint
and it lets us enrich partially complete attributes of
an AccessRequest
with more attributes. Possible scenarios are:
- There may be other entities or resources associated with a given resource, but which we want to use in our policy rules. We can fetch and merge those attributes into the existing attributes of the primary resource.
- When you fetch a resource by ID, generally all you know is the ID and the type. A workaround is to only check the authorization after you have retrieved the resource, but what if you want to just check permissions?
The InformationPoint
enrich function gets full access to the request, and so you can implement the retrieval and
enrichment of attributes as you wish.
Example of an InformationPoint that enriches User subjects with user roles
class InformationPointUserRoles : InformationPoint {
/**
* Add user roles to user if missing
*/
override suspend fun enrich(request: AccessRequest): AccessRequest {
val subjectType = request.subject["type"] ?: "not_user"
val userID = request.subject["id"]
val subjectRoles = request.subject["roles"]
if (subjectType == "User" && userID != null && subjectRoles == null) {
val userRoles = getUserRolesFromSomewhere(userID)
return request.copy(
subject = request.subject + mapOf("roles" to userRoles)
)
}
return request
}
}
Decision Point
The DecisionPoint
is where most of the work is done for allowing/denying an AccessRequest
.
- The
DecisionPoint
will enrich the attributes of theAccessRequest
with theInformationPoint
- The
DecisionPoint
will retrieve Policies based on the access request itself from aPolicySource
. - The
DecisionPoint
will evaluate all allow and deny policies for theAccessRequest
and return a result.
The evaluation works over a set of allow
policies and a set of deny
policies provided by the InformationPoint
. The
result of the evaluation will depend on:
- if there is not an
allow
policy that grants access, there is no access. - if there is an
allow
policy that grants access, but the is also adeny
policy that grants access, there is no access. - if there is an
allow
policy that grants access and nodeny
policy that grants access, there is access.
Example of wiring up a DecisionPointLocal
with an in memory PolicySource
and our InformationPoint
from the
previous example.
val allowPolicies = listOf<Policy>(
// Some set of policies
)
val denyPolicies = listOf<Policy>(
// Some set of policies
)
val decisionPoint = DecisionPointLocal(
policySource = PolicySourceInMemory(
allow = allowPolicies,
deny = denyPolicies
),
informationPoint = InformationPointUserRoles()
)
Enforcement Point
An EnforcementPoint
converts the result of a DesicionPoint
evaluation into a thrown NotAuthorizedException
if
access was denied.
The purpose of the EnforcementPoint
call is to prevent any further processing of the AccessRequest
Example of wiring up the default EnforcementPoint
with the DecisionPoint
from our previous example
val enforcementPoint = EnforcementPointDefault(
decisionPoint = decisionPoint
)
...but if we want to get up and running with an EnforcementPoint
without worrying about everything else, it has a
convenience constructor that will take the allow
and deny
policies.
val allowPolicies = listOf<Policy>(
// Some set of policies
)
val denyPolicies = listOf<Policy>(
// Some set of policies
)
val enforcementPointFromPolicies = EnforcementPointDefault(
allow = allowPolicies,
deny = denyPolicies
)