Contrast that to the typical externalised authorization model, with a policy enforcement point (PEP) and policy decision point (PDP). Something being protected, sends in a request to a central PDP. That request is likely to contain the object descriptor, a token representing the subject and some contextual data. The PDP will have a load of pre-built signatures or policies that would be looked up and processed. The net-net is the PDP sends back a deny/allow style decision which the PEP (either in the form of an SDK or a policy agent) complies with.
So what is this blog about? Well it’s the juxtaposition of the typical OAuth2 construct, with externalised PDP style authorization.
So the first step is to set up a basic policy within ForgeRock Access Management that protects a basic web URL – http://app.example.com:8080/index.html. In honesty the thing being protected could be a URL, button, image, physical object or any other schema you see fit.
|Out of the box authorization policy summary|
|REST request payload to PDP|
Application Service Account
So, there are a couple of extra steps to take. Firstly, we need to give our calling application their own service account. Simply add a new group and associated application service user. This account could then authenticate either via shared secret, JWT, x509 or any other authentication method configured. Make sure to give the associated group the account is in, privileges to the call the REST PDP endpoint. So back to the use case...
This REST PDP request is the same as any other. We have the resource being protected which maps into the policy and the OAuth2 access_token that was generated out of band, presented to the PDP as an environment variable.
OAuth2 Validation Script
The main validation is now happening in a simple Policy Condition script. The script does a few things: performs a call to the AM ../introspect endpoint to perform basic validation - is the token AM issued, valid, within exp and so on. In addition there are two switches - perform auth_level validation and also perform scope_validation. Each of these functions takes a configurable setting. If performAuthLevelCheck is true, make sure to set the acceptableAuthLevel value. As of AM 5.5, the issued OAuth2 access_token now contains a value called "auth_level". This value just ties in the authentication assurance level that has been in AM since the OpenSSO days. This numeric value is useful to differentiate how a user was validated during OAuth2 issuance. The script basically allows a simple way to perform a minimum acceptable value check.
The other configurable switch, is the performScopeCheck boolean. If true, the script checks to make sure that the submitted access_token, is associated with atleast a minimum set of required scopes. The access_token may have more scopes, but it must, as a minimum have the ones configured in the acceptableScopes attribute.
Once the script is in place lets run through some examples where access is denied. The first simple one is if the auth_level of the access_token is less than the configured acceptable value.
|acceptable_auth_level_not_met advice message|
Next up, is the situation where the scopes associated with the submitted access_token fall short of what is required. There are two advice payloads that could be sent back here. Firstly, if the number of scopes is fundamentally too small, the following advice is sent back:
|acceptable_scopes_not_met - submitted scopes too few|
|acceptable_scopes_not_met - scope entry missing|
All being well though, a successful response back would look something like the following - depending on what actions you had configured in your policy:
|Successful PDP response|
Augmenting with Additional Environmental Conditions
So we have an OAuth2-compatible PDP. Cool! But what else can we do. Well, we can augment the scripted decision making, with a couple of other conditions. Namely the time based, IP address based and LDAP based conditions.
|IP and Time based augmentation of access_token validation|
Note, any of the environmental conditions that require session validation, would fail, the script isn't linking any access_token to AM session at this point - in some cases (depending on how the access_token was generated) may never have a session associated. So beware they will not work.
The code for the scripted condition is available here.