Decorators
IG provides the following decorators to extend what objects can do.
For an overview of how decorators are implemented in IG, see Decorators.
BaseUriDecorator
Overrides the scheme, host, and port of the existing request URI, rebasing the URI and so making requests relative to a new base URI. Rebasing changes only the scheme, host, and port of the request URI. Rebasing does not affect the path, query string, or fragment.
Decorator Usage
{
"name": string,
"type": "BaseUriDecorator"
}
A BaseUriDecorator does not have configurable properties.
IG creates a default BaseUriDecorator named baseURI at startup time in the top-level heap, so you can use baseURI as the decorator name without adding the decorator declaration
Decorated Object Usage
{
"name": string,
"type": string,
"config": object,
decorator name: runtime expression<uri string>
}
"name"
: string, required except for inline objects-
The unique name of the object, just like an object that is not decorated
"type"
: string, required-
The class name of the decorated object, which must be either a Filter or a Handler. See also Filters and Handlers.
"config"
: object, required unless empty-
The configuration of the object, just like an object that is not decorated
- decorator name: runtime expression<uri string>, required
-
The scheme, host, and port of the new base URI. The port is optional when using the defaults (80 for HTTP, 443 for HTTPS).
The value of the string must not contain underscores, and must conform to the syntax specified in RFC 3986.
Examples
Add a custom decorator to the heap named myBaseUri:
{
"name": "myBaseUri",
"type": "BaseUriDecorator"
}
Set a Router’s base URI to https://www.example.com:8443
:
{
"name": "Router",
"type": "Router",
"myBaseUri": "https://www.example.com:8443/"
}
CaptureDecorator
Captures request and response messages in SLF4J logs, named in this format:
org.forgerock.openig.decoration.capture.CaptureDecorator.<decoratorName>.<decoratedObjectName>
If the decorated object is not named, the object path is used in the log.
During debugging, consider using a CaptureDecorator to capture the entity and context of requests and responses. However, increased logging consumes resources, such as disk space, and can cause performance issues. In production, reduce logging by disabling the CaptureDecorator properties |
Decorator Usage
{
"name": string,
"type": "CaptureDecorator",
"config": {
"captureEntity": configuration expression<boolean>,
"captureContext": configuration expression<boolean>,
"maxEntityLength": configuration expression<integer>,
"masks": object
}
}
"captureEntity"
: configuration expression<boolean>, optional-
When
true
, capture the message entity and write it to the logs. The message entity is the body of the HTTP message, which can be a JSON document, XML, HTML, image, or other information.When
false
, do not capture the message entity, and write nothing to the logs.The decorator excludes binary entities from the capture, instead of writing a
[binary entity]
marker.Default:
false
"captureContext"
: configuration expression<boolean>, optional-
When
true
, capture the the context as JSON. The context chain is used when processing the request inside IG in the filters and handlers.Default:
false
"maxEntityLength"
: configuration expression<integer>, optional-
The maximum number of bytes that can be captured for an entity. This property is used when
captureEntity
istrue
.If the captured entity is bigger than
maxEntityLength
, everything up tomaxEntityLength
is captured, and an[entity truncated]
message is written in the log.Set
maxEntityLength
to be big enough to allow capture of normal entities, but small enough to prevent excessive memory use orOutOfMemoryError
errors. SettingmaxEntityLength
to 2 GB or more causes an exception at startup.Default: 524 288 bytes (512 KB)
"masks"
: object, optional-
The configuration to mask the values of headers and attributes in the logs.
For an example, see Masking Values of Headers and Attributes.
{ "masks": { "headers": configuration expression<array>, "attributes": configuration expression<array>, "mask": configuration expression<string> } }
"headers"
: configuration expression<array>, optional-
Name of one or more headers whose value to mask in the logs.
The header name can be a regular expression, and is case-insensitive. The following value would mask headers called
X-OpenAM-Username
,X-OpenAM-Password
andx-openam-token
:"headers": ["X-OpenAM-.*"]
Default: None
"attributes"
: configuration expression<array>, optional-
Name of one or more attributes whose value to mask in the logs.
The attribute name can be a regular expression, and is case-insensitive.
Default: None
"mask"
: configuration expression<string>, optional-
Text to replace the masked header value or attribute value in the logs.
Default:
*****
Decorated Object Usage
{
"name": string,
"type": string,
"config": object,
decorator name: capture point(s)
}
"name"
: string, required except for inline objects-
The unique name of the decorated object.
"type"
: string, required-
The class name of the decorated object, which must be either a Filter or a Handler. See also Filters and Handlers.
"config"
: object, required unless empty-
The configuration of the decorated object, as documented in the object reference page.
- decorator name: capture point(s), optional
-
The decorator name must match the name of the CaptureDecorator. For example, if the CaptureDecorator has
"name": "capture"
, then decorator name is capture.The capture point(s) are either a single string, or an array of strings. The strings are documented here in lowercase, but are not case-sensitive:
"all"
-
Capture at all available capture points.
"none"
-
Disable capture. If
none
is configured with other capture points,none
takes precedence. "request"
-
Capture the request as it enters the Filter or Handler.
"filtered_request"
-
Capture the request as it leaves the Filter. Only applies to Filters.
"response"
-
Capture the response as it enters the Filter or leaves the Handler.
"filtered_response"
-
Capture the response as it leaves the Filter. Only applies to Filters.
Examples
The following example decorator is configured to log the entity:
{
"name": "capture",
"type": "CaptureDecorator",
"config": {
"captureEntity": true
}
}
The following example decorator is configured not to log the entity:
{
"name": "capture",
"type": "CaptureDecorator"
}
The following example decorator is configured to log the context in JSON format, excluding the request and the response:
{
"name": "capture",
"type": "CaptureDecorator",
"config": {
"captureContext": true
}
}
The following example decorator is configured to log requests and responses with the entity, before sending the request and before returning the response:
{
"heap": [
{
"name": "capture",
"type": "CaptureDecorator",
"config": {
"captureEntity": true
}
},
{
"name": "ReverseProxyHandler",
"type": "ReverseProxyHandler",
"capture": [
"request",
"response"
]
}
],
"handler": "ReverseProxyHandler"
}
The following example uses the default CaptureDecorator to capture transformed requests and responses, as they leave filters:
{
"handler": {
"type": "Chain",
"config": {
"filters": [{
"type": "HeaderFilter",
"config": {
"messageType": "REQUEST",
"add": {
"X-RequestHeader": [
"Capture at filtered_request point",
"And at filtered_response point"
]
}
}
},
{
"type": "HeaderFilter",
"config": {
"messageType": "RESPONSE",
"add": {
"X-ResponseHeader": [
"Capture at filtered_response point"
]
}
}
}
],
"handler": {
"type": "StaticResponseHandler",
"config": {
"status": 200,
"reason": "OK",
"headers": {
"Content-Type": [ "text/html" ]
},
"entity": "<html><body><p>Hello world!</p></body></html>"
}
}
}
},
"capture": [
"filtered_request",
"filtered_response"
]
}
The following example captures the context as JSON, excluding the request and response, before sending the request and before returning the response:
{
"heap": [
{
"name": "capture",
"type": "CaptureDecorator",
"config": {
"captureContext": true
}
},
{
"name": "ReverseProxyHandler",
"type": "ReverseProxyHandler",
"capture": [
"request",
"response"
]
}
],
"handler": "ReverseProxyHandler"
}
This example captures the context, and then masks the value of the cookies
and credentials in the logs. To try it, set up the example in
Log In With Credentials From a File,
replace that route with the following route, and search the route log file for
the text MASKED
:
{
"heap": [{
"name": "maskedCapture",
"type": "CaptureDecorator",
"config": {
"captureContext": true,
"masks": {
"headers": [ "cookie*", "set-cookie*" ],
"attributes": [ "credentials" ],
"mask": "MASKED"
}
}
}],
"name": "02-file-masked",
"condition": "${find(request.uri.path, '^/profile')}",
"maskedCapture": "all",
"handler": {
"type": "Chain",
"baseURI": "http://app.example.com:8081",
"config": {
"filters": [
{
"type": "PasswordReplayFilter",
"config": {
"loginPage": "${matches(request.uri.path, '^/profile/george') and (request.method == 'GET')}",
"credentials": {
"type": "FileAttributesFilter",
"config": {
"file": "/tmp/userfile.txt",
"key": "email",
"value": "george@example.com",
"target": "${attributes.credentials}"
}
},
"request": {
"method": "POST",
"uri": "http://app.example.com:8081/login",
"form": {
"username": [
"${attributes.credentials.username}"
],
"password": [
"${attributes.credentials.password}"
]
}
}
}
}
],
"handler": "ReverseProxyHandler"
}
}
}
TimerDecorator
Records time to process filters, handlers, and access token resolvers.
Decorator Usage
{
"name": string,
"type": "TimerDecorator",
"config": {
"timeUnit": string
}
}
IG configures a default TimerDecorator named timer
. Use
timer
as the decorator name without explicitly declaring a decorator named
timer.
"timeUnit"
: duration string, optional-
Unit of time used in the decorator output. The unit of time can be any unit allowed in the
duration
field.Default:
ms
Decorated Object Usage
{
"name": string,
"type": string,
"config": object,
decorator name: boolean
}
"name"
: string, required except for inline objects-
The unique name of the object to decorate.
"type"
: string, required-
The class name of the object to decorate, which must be a filter, handler, or the
accessTokenResolver
property of OAuth2ResourceServerFilter.See also Filters, Handlers, and OAuth2ResourceServerFilter
"config"
: object, required unless empty-
The configuration of the object, just like an object that is not decorated.
decorator name
: boolean, required-
IG looks for the presence of the decorator name field for the TimerDecorator.
To activate the timer, set the value of the decorator name field to
true
.To deactivate the TimerDecorator temporarily, set the value to
false
.
Timer Metrics At the Prometheus Scrape Endpoint
This section describes the timer metrics recorded at the Prometheus Scrape Endpoint. For more information about metrics, see Monitoring Endpoints.
When IG is set up as described in the documentation, the endpoint is http://openig.example.com:8080/openig/metrics/prometheus.
Each timer metric is labelled with the following fully qualified names:
-
decorated_object
-
heap
-
name
(decorator name) -
route
-
router
Name | Monitoring Type | Description |
---|---|---|
|
|
Time to process the request and response in the decorated handler. |
|
|
Time to process the request and response in the decorated filter and its downstream filters and handler. |
|
|
Time to process the request and response in the decorated filter. |
|
|
Time to process the request and response in filters and handlers that are downstream of the decorated filter. |
Timer Metrics At the Common REST Monitoring Endpoint
This section describes the metrics recorded at the the ForgeRock Common REST Monitoring Endpoint. For more information about metrics, see Monitoring Endpoints.
When IG is set up as described in the documentation, the endpoint is http://openig.example.com:8080/openig/metrics/api?_queryFilter=true.
Metrics are published with an _id
in the following pattern:
heap.router-name.route-name.decorator-name.object
Name | Monitoring Type | Description |
---|---|---|
|
|
Time to process the request and response in the decorated handler, or in the decorated filter and its downstream filters and handler. |
|
|
Time to process the request and response in the decorated filter. |
|
|
Time to process the request and response in filters and handlers that are downstream of the decorated filter. |
Timer Metrics in SLF4J Logs
SLF4J logs are named in this format:
<className>.<decoratorName>.<decoratedObjectName>
If the decorated object is not named, the object path is used in the log.
When a route’s top-level handler is decorated, the timer decorator records the elapsed time for operations traversing the whole route:
2018-09-04T12:16:08,994Z | INFO | I/O dispatcher 17 | o.f.o.d.t.T.t.top-level-handler | @myroute | Elapsed time: 13 ms
When an individual handler in the route is decorated, the timer decorator records the elapsed time for operations traversing the handler:
2018-09-04T12:44:02,161Z | INFO | http-nio-8080-exec-8 | o.f.o.d.t.T.t.StaticResponseHandler-1 | @myroute | Elapsed time: 1 ms
Examples
The following example uses the default timer decorator to record the time that TokenIntrospectionAccessTokenResolver takes to process a request:
{
"accessTokenResolver": {
"name": "TokenIntrospectionAccessTokenResolver-1",
"type": "TokenIntrospectionAccessTokenResolver",
"config": {
"amService": "AmService-1",
...
},
"timer": true
}
}
The following example defines a customized timer decorator in the heap, and uses it to record the time that the SingleSignOnFilter takes to process a request:
{
"heap": [
{
"name": "mytimerdecorator",
"type": "TimerDecorator",
"config": {
"timeUnit": "nano"
}
},
...
],
"handler": {
"type": "Chain",
"config": {
"filters": [
{
"type": "SingleSignOnFilter",
"config": {
...
},
"mytimerdecorator": true
}
],
"handler": "ReverseProxyHandler"
}
}
}