Configuring Mapped Throttling
This section describes how to configure a mapped throttling policy, where the grouping policy defines criteria to group requests, and the rate policy defines the criteria by which rates are mapped.
The following image illustrates how different throttling rates can be applied to users.
The following image illustrates how each user with a gold
status has a throttling rate of 6 requests/10 seconds, and each user with a silver
status has 3 requests/10 seconds. The bronze
status is not mapped to a throttling rate, and so a user with the bronze
status has the default rate.
Set up AM:
Set up AM as described in "Validating Access_Tokens Through the Introspection Endpoint".
Select Scripts > OAuth2 Access Token Modification Script, and replace the default script as follows:
import org.forgerock.http.protocol.Request import org.forgerock.http.protocol.Response def attributes = identity.getAttributes(["mail", "employeeNumber"].toSet()) accessToken.setField("mail", attributes["mail"][0]) def mail = attributes['mail'][0] if (mail.endsWith('@example.com')) { status = "gold" } else if (mail.endsWith('@other.com')) { status = "silver" } else { status = "bronze" } accessToken.setField("status", status)
The AM script adds user profile information to the access_token, and defines the content of the users
status
field according to the email domain.
Set up IG:
Set an environment variable for the IG agent password, and then restart IG:
$
export AGENT_SECRET_ID='cGFzc3dvcmQ='
The password is retrieved by a SystemAndEnvSecretStore, and must be base64-encoded.
Add the following route to IG:
$HOME/.openig/config/routes/00-throttle-mapped.json
%appdata%\OpenIG\config\routes\00-throttle-mapped.json
{ "name": "00-throttle-mapped", "baseURI": "http://app.example.com:8081", "condition": "${matches(request.uri.path, '^/home/throttle-mapped')}", "heap": [ { "name": "SystemAndEnvSecretStore-1", "type": "SystemAndEnvSecretStore" }, { "name": "AmService-1", "type": "AmService", "config": { "agent": { "username": "ig_agent", "passwordSecretId": "agent.secret.id" }, "secretsProvider": "SystemAndEnvSecretStore-1", "url": "http://openam.example.com:8088/openam/", "version": "7" } } ], "handler": { "type": "Chain", "config": { "filters": [ { "name": "OAuth2ResourceServerFilter-1", "type": "OAuth2ResourceServerFilter", "config": { "scopes": [ "mail", "employeenumber" ], "requireHttps": false, "realm": "OpenIG", "accessTokenResolver": { "name": "token-resolver-1", "type": "TokenIntrospectionAccessTokenResolver", "config": { "amService": "AmService-1", "providerHandler": { "type": "Chain", "config": { "filters": [ { "type": "HttpBasicAuthenticationClientFilter", "config": { "username": "ig_agent", "passwordSecretId": "agent.secret.id", "secretsProvider": "SystemAndEnvSecretStore-1" } } ], "handler": "ForgeRockClientHandler" } } } } } }, { "name": "ThrottlingFilter-1", "type": "ThrottlingFilter", "config": { "requestGroupingPolicy": "${contexts.oauth2.accessToken.info.mail}", "throttlingRatePolicy": { "name": "MappedPolicy", "type": "MappedThrottlingPolicy", "config": { "throttlingRateMapper": "${contexts.oauth2.accessToken.info.status}", "throttlingRatesMapping": { "gold": { "numberOfRequests": 6, "duration": "10 s" }, "silver": { "numberOfRequests": 3, "duration": "10 s" }, "bronze": { "numberOfRequests": 1, "duration": "10 s" } }, "defaultRate": { "numberOfRequests": 1, "duration": "10 s" } } } } } ], "handler": "ReverseProxyHandler" } } }
For information about how to set up the IG route in Studio, see "Mapped Throttling Filter in Structured Editor".
Notice the following features of the route:
The route matches requests to
/home/throttle-mapped
.The OAuth2ResourceServerFilter validates requests with the AccessTokenResolver, and makes it available for downstream components in the
oauth2
context.The ThrottlingFilter bases the request grouping policy on the AM user's email. The throttling rate is applied independently to each email address.
The throttling rate is mapped to the AM user's
status
, which is defined by the email domain, in the AM script.
Test the setup:
Get an access_token for George from AM:
$
george_token=$(curl -s \ --user "client-application:password" \ --data "grant_type=password&username=george&password=C0stanza&scope=mail%20employeenumber" \ http://openam.example.com:8088/openam/oauth2/access_token | jq -r ".access_token")
Using the access_token for authentication, access the route multiple times. The following example accesses the route 10 times, and writes the output to a file:
$
curl -v http://openig.example.com:8080/home/throttle-mapped/\[01-10\] --header "Authorization:Bearer ${george_token}" > /tmp/george.txt 2>&1
Search the output file to see the result:
$
grep "< HTTP/1.1" /tmp/george.txt | sort | uniq -c
6 < HTTP/1.1 200 4 < HTTP/1.1 429
Notice that with a
gold
status, George can access the route 6 times in 10 seconds.In AM, change George's email to
george@other.com
, and then run the last two steps again to see how the access is reduced.
Considerations for Dynamic Throttling
The following image illustrates what can happen when the throttling rate defined by throttlingRateMapping
changes frequently or quickly:
In the image, George starts out with a gold
status. In a two second period, he sends five requests, is downgraded to silver, sends four requests, is upgraded back to gold
, and then sends three more requests.
After making five requests with a gold
status, George has almost reached his throttling rate. When his status is downgraded to silver, those requests are disregarded and the full throttling rate for silver
is applied. George can now make three more requests even though he had nearly reached his throttling rate with a gold
status.
After making three requests with a silver
status, George has reached his throttling rate. When he makes a fourth request, the request is refused.
George is now upgraded back to gold
and can now make six more requests even though he had reached his throttling rate with a silver
status.
When you configure requestGroupingPolicy
and throttlingRateMapper
, bear in mind what happens when the throttling rate defined by the throttlingRateMapper
is changed.