Decorators
Decorators are heap objects to extend what other objects can do. PingGateway
defines baseURI
, capture
, and timer
decorators that you can use
without explicitly configuring them. For information about available decorators,
refer to Decorators.
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. PingGateway 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.
Decorate 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://am.example.com:8088/openam/"
}
}
],
"handler": {
"type": "Chain",
"config": {
"filters": [
{
"capture": "all",
"type": "SingleSignOnFilter",
"config": {
"amService": "AmService-1"
}
}
],
"handler": "ReverseProxyHandler"
}
}
}
Decorate 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://am.example.com:8088/openam/"
}
}
],
"capture": "all",
"handler": {
"type": "Chain",
"config": {
"filters": [
{
"type": "SingleSignOnFilter",
"config": {
"amService": "AmService-1"
}
}
],
"handler": "ReverseProxyHandler"
}
}
}
Decorate 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://am.example.com:8088/openam/"
}
}
],
"handler": {
"type": "Chain",
"config": {
"filters": [
{
"type": "SingleSignOnFilter",
"config": {
"amService": "AmService-1"
}
}
],
"handler": "ReverseProxyHandler"
}
}
}
Decorate named objects 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.
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://am.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.
Decorate PingGateway’s interactions with AM
To log interactions between PingGateway 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 PingGateway route of
Validate 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.
Decorate an object multiple times
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, PingGateway 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,
"headers": {
"Content-Type": [ "text/plain; charset=UTF-8" ]
},
"entity": "Hello world, from myroute!"
}
},
"condition": "${find(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://ig.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,
"headers": {
"Content-Type": [ "text/plain; charset=UTF-8" ]
}
"entity": "Hello, world from myroute1!"
}
},
"condition": "${find(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
.