<Destinations>
<TokenResolver id="keycloak" cacheFor="300s">
...
</TokenResolver>
</Destinations>
28 October 2021
Some destinations, like the Http destination, may require some additional tokens to be established prior to performing the actual http reqeust. To support that, you can register token resolvers within the destinations file.
<Destinations>
<TokenResolver id="keycloak" cacheFor="300s">
...
</TokenResolver>
</Destinations>
You can define as many token resolvers as needed, just ensure that each have a unique identifier.
The cacheFor
directive specifies the duration how long the generated tokens may be reused.
The tokens are cached per url/header/payload combination, meaning that if your token resolver
uses dynamic values, the caching is sensitive to the resolved values and thus each token resolver may contain many cache entries.
On a high level, the token resolver configuration contains three parts:
Defines how the request will be constructed when requesting the tokens. There is support for constructing requests using either x-www-form-url-encoded key/value pairs or JSON request bodies.
Defines what data from the response we are interested in when contructing our tokens. Currently you can take values from response headers and/or JSON values from the response body.
Specifies the tokens to be used and how to build these.
Below is a complete example for a token resolver that works against Keycloak to establish an authorization token according to the OAuth2 client credentials flow.
<Destinations>
<TokenResolver id="keycloak-1" cacheFor="5m">
<Request url="http://localhost:30180/auth/realms/${job.param.keycloak_realm}/protocol/openid-connect/token">
<Params>
<Param name="grant_type" value="client_credentials" />
<Param name="scope" value="${job.param.keycloak.scopes}" />
<Param name="client_id" value="tif" />
<Param name="client_secret" value="${tif.setting.keycloak.tif.secret}" />
</Params>
</Request>
<Response>
<Json>
<Map jsonPath="$.access_token" as="access_token" />
<Map jsonPath="$.token_type" as="token_type" />
</Json>
</Response>
<Tokens>
<Token name="Authorization" macro="${token_type} ${access_token}" />
</Tokens>
</TokenResolver>
<Http id="http-dest-with-keycloak" tokenResolver="keycloak-1" url="..." />
</Destinations>
In this example, the request is a param name/value request and the response is of type JSON.
It is also possible to send out JSON data and map the response headers into tokens, see example below:
<TokenResolver id="monitor" cacheFor="24H">
<Request
url="http://monitor:8001/${tif.setting.monitorLanguageCode}/${job.param.companyNumber}/login">
<Json> <!-- implies application/json + method = POST -->
<Object>
<Property name="Username" string="${job.param.monitorUserName}" />
<Property name="Password" string="${job.param.monitorPassword}" />
<Property name="ForceRelogin" bool="true" />
</Object>
</Json>
</Request>
<Response>
<Header name="X-Monitor-SessionId" as="sessionId" />
</Response>
<Tokens>
<Token name="X-Monitor-SessionId" value="${sessionId}" />
</Tokens>
</TokenResolver>
The details of each element is described below.
The top level element <TokenResolver>
supports the following attributes.
Attribute | Description | Required |
---|---|---|
id |
A unique identifier among all token resolvers. |
Yes |
cacheFor |
An optional duration definition specifying how long time the token may be cached. If omitted, no caching takes place. Example values:
|
No |
Supported child elements:
<Request>
<Response>
<Tokens>
Specifies how the request will be constructed.
This element supports the following attributes
Attribute | Description | Required |
---|---|---|
url |
The URL to perform the request against |
Yes |
method |
Specifies request method. If omitted, GET is used in case no body is configured and POST is used if a body is configured. |
No |
contentEncoding |
Can be used to control the content encoding. Default is UTF-8 |
No |
proxyOverride |
Can be used to override global proxy settings in TIF |
No |
disableProxy |
Can be used to disable using proxy server for token resolving. |
No |
The request will per default use the global http/https proxy setting unless overridden via the See this document for details around proxy settings in TIF. |
Supported child elements:
Element | Description | Required |
---|---|---|
|
Defines that you will send JSON data to the server. |
No |
|
Defines that you will send key/value parameters |
No |
|
Defines additional headers to be part of the request |
No |
The Json element is used to declare a JSON structure to be generated
See example below how to construct such Json definition:
<Request ...>
<Json>
<Object>
<Property name="Username" string="${job.param.monitorUserName}" />
<Property name="Password" string="${job.param.monitorPassword}" />
<Property name="ForceRelogin" bool="true" />
<Array name="test">
<Property int="1" />
<Property int="2" />
</Array>
</Object>
</Json>
</Request>
This will generate a JSON payload like the example below:
{
"Username" : "the resolved value from the job param monitorUserName",
"Password" : "the resolved value from the job param monitorPassword",
"ForceRelogin" : true,
"test" : [ 1, 2 ]
}
You can use <Object>
, <Array>
and <Property>
to define the structure.
The Property element supports the following attributes:
Attribute | Description |
---|---|
string |
Defines that the value is of type string |
bool |
Defines that the value is of type boolean |
int |
Defines that the value is of type int64 |
double |
Defines that the value is of type double |
number |
Defines that the value is of type number |
splitValueBy |
Specify optional separator that can be used to split the value into an array instead |
The <Params>
element is used to define a payload that is x-www-form-urlencoded (e.g. a form post).
Example:
<Request ...>
<Params>
<Param name="grant_type" value="client_credentials" />
<Param name="scope" value="${job.param.keycloak.scopes}" />
<Param name="test" value="a,b,c,d" splitBy="," />
</Params>
</Request>
This will generate a payload like below
grant_type=client_credentials&scope=s1+s2+s3+s4&test=a&test=b&test=c&test=d
The <Params>
element contains one or more <Param>
elements, which supports the following attributes.
Attribute | Description | Required |
---|---|---|
name |
Name of parameter |
Yes |
value |
The value of the parameter |
Yes |
splitValueBy |
Specify optional separator that can be used to split the value into an array instead |
No |
The <Response>
element defines what data you are interested in from the response.
You can save values from headers and/or data from a JSON response body.
The idea is that you will define what data you are interested in and associate that with a variable. Later on, you will use those variables to construct the final tokens.
When working with JSON response data you will use so called JSON paths to select data from the JSON structure to be saved.
For more detailed information about JSON path, see this document
Below is an example where the properties token_type and access_token are saved from the JSON object. Note that selecting anything else than plain literals (strings, numbers, booleans) are typically not supported.
<Response>
<Json>
<Map jsonPath="$.token_type" as="tokenType" />
<Map jsonPath="$.access_token" as="accessToken" />
</Json>
</Response>
The <Map>
element supports the following attributes
Attribute | Description | Required |
---|---|---|
jsonPath |
The JSON path expression to use |
Yes |
as |
The name of the variable to save the value as |
Yes |
To save some header values into a named variable, see the example below:
<Response>
<Header name="X-Monitor-SessionId" as="sessionId" />
<Header name="Another-Header" as="another" />
</Response>
The <Header>
element supports the following attributes
Attribute | Description | Required |
---|---|---|
name |
Name of header to take |
Yes |
as |
The name of the variable to save the value as |
Yes |
ignoreCase |
If header names are case sensitive or not. Default is to ignore case. |
No |
The final tokens to use are defined within the <Tokens>
element.
See example below where the Authorization token is generated based upon the variables token_type
and access_token
<TokenResolver>
...
<Tokens>
<Token name="Authorization" macro="${token_type} ${access_token}" />
</Tokens>
</TokenResolver>
The <Token>
element supports the following attributes
Attribute | Description | Required |
---|---|---|
name |
Name of the token |
Yes |
macro |
The macro to use when resolving the token value |
Yes |
value |
The fallback value to use |
No |