Decorators
Decorators are heap objects to extend what another object can do. IG defines baseURI
, capture
, and timer
decorators that you can use without explicitly configuring them. For more information about the types of decorators provided by IG, see Decorators.
The following sections provide an overview of how decorators are implemented in IG:
Decorating Objects, the Route Handler, and the Heap
Use decorations that are compatible with the object type. For example, timer
records the time to process filters and handlers, but does not record information for other object types. Similarly, baseURI
overrides the scheme, host, and ports, but has no other effect.
In a route, you can decorate individual objects, the route handler, and the heap. IG applies decorations in this order:
Decorations declared on individual objects. Local decorations that are part of an object's declaration are inherited wherever the object is used.
globalDecorations declared in parent routes, then in child routes, and then in the current route.
Decorations declared on the route handler.
The following sections describes where to place decorators in a route.
Decorating Individual Objects In a Route
To decorate individual objects, add the decorator's name value as a top-level field of the object, next to type
and config
.
In this example, the decorator captures all requests going into the SingleSignOnFilter, and all responses coming out of the SingleSignOnFilter:
{ "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": [ { "capture": "all", "type": "SingleSignOnFilter", "config": { "amService": "AmService-1" } } ], "handler": "ReverseProxyHandler" } } }
Decorating the Route Handler
To decorate the handler for a route, add the decorator as a top-level field of the route.
In this example, the decorator captures all requests and responses that traverse the route:
{ "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" } } ], "capture": "all", "handler": { "type": "Chain", "config": { "filters": [ { "type": "SingleSignOnFilter", "config": { "amService": "AmService-1" } } ], "handler": "ReverseProxyHandler" } } }
Decorating the Route Heap
To decorate all compatible objects in a route, configure globalDecorators as a top-level field of the route. The globalDecorators field takes a map of the decorations to apply.
To decorate all compatible objects declared in config.json
or admin.json
, configure globalDecorators as a top-level field in config.json
or admin.json
.
In the following example, the route has capture and timer decorations. The capture decoration applies to AmService, Chain, SingleSignOnFilter, and ReverseProxyHandler. The timer decoration doesn't apply to AmService because it is not a filter or handler, but does apply to Chain, SingleSignOnFilter, and ReverseProxyHandler:
{ "globalDecorators": { "capture": "all", "timer": true }, "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": [ { "type": "SingleSignOnFilter", "config": { "amService": "AmService-1" } } ], "handler": "ReverseProxyHandler" } } }
Decorating a Named Object Differently In Different Parts of the Configuration
When a filter or handler is configured in config.json
or in the heap, it can be used many times in the configuration. To decorate each use of the filter or handler individually, use a Delegate. For more information, see "Delegate"
In the following example, an AmService heap object configures an amHandler
to delegate tasks to ForgeRockClientHandler
, and capture all requests and responses passing through the handler.
{ "type": "AmService", "config": { "agent" : { "username" : "ig_agent", "passwordSecretId" : "agent.secret.id" }, "secretsProvider": "SystemAndEnvSecretStore-1", "amHandler": { "type": "Delegate", "capture": "all", "config": { "delegate": "ForgeRockClientHandler" } }, "url": "http://openam.example.com:8088/openam" } }
You can use the same ForgeRockClientHandler
in another part of the configuration, in a different route for example, without adding a capture decorator. Requests and responses that pass through that use of the handler are not captured.
Decorating IG's Interactions With AM
To log interactions between IG and AM, delegate message handling to a ForgeRockClientHandler, and capture the requests and responses passing through the handler. When the ForgeRockClientHandler communicates with an application, it sends ForgeRock Common Audit transaction IDs.
In the following example, the accessTokenResolver
delegates message handling to a decorated ForgeRockClientHandler:
"accessTokenResolver": { "name": "token-resolver-1", "type": "TokenIntrospectionAccessTokenResolver", "config": { "amService": "AmService-1", "providerHandler": { "capture": "all", "type": "Delegate", "config": { "delegate": "ForgeRockClientHandler" } } } }
To try the example, replace the accessTokenResolver
in the IG route of "Validating Access_Tokens Through the Introspection Endpoint". Test the setup as described for the example, and note that the route's log file contains an HTTP call to the introspection endpoint.
Using Multiple Decorators for the Same Object
Decorations can apply more than once. For example, if you set a decoration on a route and another decoration on an object defined within the route, IG applies the decoration twice. In the following route, the request is captured twice:
{ "handler": { "type": "ReverseProxyHandler", "capture": "request" }, "capture": "all" }
When an object has multiple decorations, the decorations are applied in the order they appear in the JSON.
In the following route, the handler is decorated with a baseURI
first, and a capture
second:
{ "name": "myroute", "baseURI": "http://app.example.com:8081", "capture": "all", "handler": { "type": "StaticResponseHandler", "config": { "status": 200, "reason": "OK", "headers": { "Content-Type": [ "text/plain" ] }, "entity": "Hello world, from myroute!" } }, "condition": "${matches(request.uri.path, '^/myroute1')}" }
The decoration can be represented as capture[ baseUri[ handler ] ]
. When a request is processed, it is captured, and then rebased, and then processed by the handler: The log for this route shows that the capture occurs before the rebase:
2018-09-10T13:23:18,990Z | INFO | http-nio-8080-exec-1 | o.f.o.d.c.C.c.top-level-handler | @myroute | --- (request) id:f792d2ad-4409-4907-bc46-28e1c3c19ac3-7 ---> GET http://openig.example.com:8080/myroute HTTP/1.1 ...
Conversely, in the following route, the handler is decorated with a capture
first, and a baseURI
second:
{ "name": "myroute", "capture": "all", "baseURI": "http://app.example.com:8081", "handler": { "type": "StaticResponseHandler", "config": { "status": 200, "reason": "OK", "headers": { "Content-Type": [ "text/plain" ] } "entity": "Hello, world from myroute1!" } }, "condition": "${matches(request.uri.path, '^/myroute')}" }
The decoration can be represented as baseUri[ capture[ handler ] ]
. When a request is processed, it is rebased, and then captured, and then processed by the handler. The log for this route shows that the rebase occurs before the capture:
2018-09-10T13:07:07,524Z | INFO | http-nio-8080-exec-1 | o.f.o.d.c.C.c.top-level-handler | @myroute | --- (request) id:3c26ab12-3cc0-403e-bec6-43bf5621f657-7 ---> GET http://app.example.com:8081/myroute HTTP/1.1 ...
Guidelines for Naming Decorators
To prevent unwanted behavior, consider the following points when you name decorators:
Avoid decorators named
comment
orcomments
, and avoid reserved field names. Instead of using alphanumeric field names, consider using dots in your decorator names, such asmy.decorator
.For heap objects, avoid the reserved names
config
,name
, andtype
.For routes, avoid the reserved names
auditService
,baseURI
,condition
,globalDecorators
,heap
,handler
,name
,secrets
, andsession
.In
config.json
, avoid the reserved nametemporaryStorage
.