PAAP agent response
When PingAccess receives an agent request, it sends an agent response that includes an authorization decision and any additional actions for the agent to perform on the client request, or it requests additional information from the agent.
Any HTTP status code other than those listed below indicates that the client request was not permitted. In that case, the content of the agent response, including the status-line, the message-body, and all headers not named by the header defined later, is sent back to the client as the content of the client response. This lets PingAccess direct the client, when applicable, to PingFederate for user authentication through redirection or even auto-post form. This also lets PingAccess communicate error conditions and negative authorization decisions to the client with a consistent look and feel.
Custom HTTP status codes
The following custom status codes indicate that the client request is allowed or that additional information is needed in order to make a policy decision.
- HTTP 477 Request Body Required
-
A 477 response indicates that request requires the request body to make a policy decision. The agent should repeat the agent request and include the request body. The subsequent response will include the policy decision and any actions to be taken.
PingAccess does not need the message body to respond to the vast majority of agent requests. This status code allows for optimization of the protocol by not sending unnecessary data by default while providing a way to ask for it when needed. The only case where PingAccess currently requires the body is to evaluate an auto-posted OpenID Connect Authentication Response. This enables the agent to not have to know about or configure any callback redirect_uri locations, but rather push that off to PingAccess. The agent only knows it received a POST request and that PingAccess asked for the message-body in order to process it.
After the agent repeats the agent request with the request body, PingAccess responds to the agent with a generic HTTP response code. Because the only time a 477 is returned by PingAccess is to get the an auto-posted OpenID Connect Authentication Response at the redirect Uniform Resource Identifier (URI), PingAccess never returns a 277 after a 477.
PingAccess should never respond to a GET request with a 477.
- HTTP 277 Allowed
-
The 277 response indicates the client request is authorized and should be allowed to continue. Additional actions to perform on the client request and corresponding client response are indicated by one or more of the headers listed in the HTTP 277 headers section.
HTTP 277 headers
These headers can be included in the agent response if the response code HTTP 277 was used:
- vnd-pi-set-req-headers
-
The value of this header is a comma-delimited list of header names from the agent response to be included as headers for the client request. If any included headers already exist in the client request, the values are overwritten with the values from the corresponding agent response header. If a header is named that is not present in the agent response, it is removed from the client request.
This allows PingAccess to make user attribute information available to the protected application in the headers, and to guard against header injection by the client. In order to guard against malicious header injection by end users, use this mechanism to expose user data to the application. PingAccess should include all header names used in a given context, even if they have no value, so headers supplied by the client using the same names will be ignored.
- vnd-pi-append-req-headers
-
The value of this header is a comma-delimited list of header names from the agent response to add to the client request headers. Any existing named headers already present in the client request are not overwritten, but new headers are added with the values from the agent response. If a header is named that is not present in the agent response, no action is taken for that header name in the client request.
- vnd-pi-set-req-vars
-
The value of this header is a comma-delimited list of header names from the agent response to be set in the client request as request scoped variables or attributes in an appropriate manner for the environment in which the agent resides. Examples might include environment variables in Apache or request attributes in a servlet container.
- vnd-pi-sub
-
This header is used to identify the header that contains the subject or username for the transaction. This typically will be a header also named in
vnd-pi-set-req-headers
, as those generally expose user information to the backend application through headers in the modified client request. It might name a header not in thevnd-pi-set-req-headers
list if the agent or environment in which it’s deployed needs to know the username or subject in a way that differs from header injection to the client request. Thevnd-pi-sub
header should name a single-valued header, but if it names one with multiple values, the agent should use only one. Ifvnd-pi-sub
names a header that is not present in the agent response, it should be ignored by the agent. - vnd-pi-set-resp-headers
-
The value of this header is a comma-delimited list of header names from the agent response to be set as headers of the client response. If any of the named headers already exist in the client response, the values are overwritten with the values of those headers from the agent response. If a header is named that is not present in the agent response, it is removed from the client response.
- vnd-pi-append-resp-headers
-
The value of this header is a comma-delimited list of header names from the agent response to be added to the headers of the client response. Any existing named headers already present in the client response are not overwritten, but new headers are added with the values from the agent response. If a header is named that is not present in the agent response, no action is taken for that header name in the client response.
This allows PingAccess to set or reset the PingAccess Web Access Management (WAM) token as a cookie in the user’s browser.
In general, for any particular request or response header name, PingAccess should only indicate either a set or an append directive. However, with an agent response, the set directive takes precedence. One way the agent might accomplish that is by applying all append operations first, followed by the set operations.
Common headers
These headers can be used in an agent response of any status code:
- vnd-pi-omit-resp-headers
-
The value of this header is a comma-delimited list of header names from the agent response to omit from the headers in the client response. When present, this list implicitly includes the
vnd-pi-omit-resp-headers
header.
Caching
A number of caching directives are aimed at reducing calls from the agent to PingAccess and improving performance.
Resource Definition Caching
When the vnd-pi-resource-cache
request header is present in the agent request, PingAccess includes the following headers in the agent response. This enables the agent to make initial decisions on handling of client requests without having to consult PingAccess directly.
- vnd-pi-resource-cache
-
This is a multi-valued header and, in keeping with Section 4.2 of RFC 2616, the values might be comma-delimited, or multiple message-header fields with the same name might be included. The order of the values is significant and, in servicing future requests based on the cache, an agent should evaluate them in the order they were received.
Each value represents a group of resources and some directives about how the agent should handle requests for URIs within that group of resources. The values are made up of multiple parts delimited by semicolons.
- path
-
The path part defines the paths against which requests are matched. The value is one or more space-delimited quoted strings. Each quoted string is a path value, which might contain wildcards using the asterisk (
*
) character. So, for example,path="/app/*"
would match any requested path that starts with/app/
. Whilepath="/app1/*" "/app2/*"
would match anything under/app1/
or/app2/
. Similarly,path="*.jpg" "*.gif" "*.png"
would match anything ending with those common image file extensions. If no wildcard is present, the values must exactly match. - cs
-
Indicates if the values in the path are case-sensitive. Valid values are Y and N. If this component is omitted, the default value is Y.
- method
-
Indicates the method or methods against which requests are matched. The value is one or more space-delimited method names such as GET, POST, PUT, etc. If this component is omitted, all methods are allowed and should match for the resource.
- kind
-
Indicates the kind of resource and the general level of access control protection to be applied to it, such as whether access to the resource, and related resources as per the path values, requires an authorization token. Valid values are P, U, or C. The value P, meaning Protected, says that a token is required for access and the token-type and token-name indicate the token of interest so that the token value can be used in caching the response and response headers to service future requests. The value U, meaning Unprotected, indicates that no token is necessary for access and that any future request, within the cache time-to-live, will be allowed. The value C, meaning Consult with PingAccess, means that the agent must always make an agent request to PingAccess to service the client request.
- token-type
-
The token-type part indicates what kind of token was used in making the authorization decision and what token type to use in making future cache queries. Its value is either C or A. A value of C indicates that a cookie was used to make the access control decision and that future requests with the same cookie value for the cookie named in the token-name part can use the cached content. A value of A indicates that an authorization header was used to make the access control decision and that future requests with the same credentials for the authorization scheme named by the token-name directive can use the cached content.
- token-name
-
The token-type says what type of token for which to cache specific user details for a particular token. However, there might be more than one token for a particular type in a request. The token-name value disambiguates that situation by specifying which one to use. The token-name value is either the name of a cookie, for WAM), or the name of an authorization scheme, the Bearer value for OAuth, when token-type value is C or A, respectively.
When this value is a cookie, the cookie name is case-sensitive, as implied by RFC 6265. When this value is the name of an authorization scheme, per section 1.2 of RFC 2617, the value is not case-sensitive. When using the token-name header, ensure that the value follows the appropriate case-sensitivity requirements.
If the client request contains more than one token matching the name and type, the value from the first occurrence must be used as the key to lookup or establish a cache for a particular token and other occurrences must be ignored.
The resource-cache list is valid for and scoped to the host in the client request. When building the resource-cache, PingAccess includes resources associated with the virtual host that matches the host of the request as well as wildcard virtual host resources.
- vnd-pi-resource-cache-ttl
-
The value of the resource cache
time-to-live
header is an integer indicating the number of seconds from the time the response was sent that the values of thevnd-pi-resource-cache
header can be cached and used. For example, the following header instructs the agent to cache the resource definitions for the next ten minutes.vnd-pi-resource-cache-ttl: 600
The agent can use the
vnd-pi-resource-cache
header in an agent request to ask PingAccess for newvnd-pi-resource-cache
andvnd-pi-resource-cache-ttl
values when the time-to-live on its current resource cache has elapsed.PingAccess provides configurability over the resource cache
time-to-live
value to balance performance and security goals.
Example
An example vnd-pi-resource-cache
response header is shown in the following code. This example tells the client that all requests with a path starting with /pa/oidc/
are to have the agent make an agent request to PingAccess to determine what to do. Next, it tells PingAccess that requests with a .jpg
, .gif
, or .png
suffix are allowed to pass through. Requests for a path that starts with /canada/
require a PingAccess WAM token, which will be a cookie named PA.cad. Requests for a path that starts with /usa/
require a PingAccess WAM token which will be a cookie named PA.usd. All other requests, indicated by the slash wildcard path, are allowed. The request path is matched against the paths defined in the resource-cache in order from top to bottom. The vnd-pi-resource-cache-ttl
tells the agent to use the resource cache for the next hour.
vnd-pi-resource-cache: path="/pa/oidc/*"; kind=C vnd-pi-resource-cache: path="/*.jpg" "*.gif" "*.png"; method=GET; kind=U vnd-pi-resource-cache: path="/canada/*"; cs=N; kind=P; token-type=C; token-name=PA.cad vnd-pi-resource-cache: path="/usa/*"; kind=P; token-type=C; token-name=PA.usd vnd-pi-resource-cache: path="/*" ; kind=U vnd-pi-resource-cache-ttl: 3600
The above is semantically equivalent to the following headers where the multiple |
vnd-pi-resource-cache: path="/pa/oidc/*"; kind=C, path="/*.jpg" "*.gif" "*.png"; method=GET; kind=U, path="/canada/*"; cs=N; kind=P; token-type=C; token-name=PA.cad, path="/usa/*"; kind=P; token-type=C; token-name=PA.usd, path="/*" ; kind=U vnd-pi-resource-cache-ttl: 3600
Individual token and agent response caching
The resource-cache defined in the previous section gives the agent meta-information about caching data for request handling. This section describes how, in some cases, data from an individual agent response can be cached relative to a particular token and used to service future client requests with the same token so that PingAccess doesn’t need to be called on every client request.
The resource-cache defined in the previous section gives the agent directives about how to handle requests based on host, method and path. The agent iterates its resource-cache list in order until it finds a match based on those values. Additional caching can be done for particular kinds of resources as follows.
When the kind of the resource-cache is P, a token, as indicated by the token-type and token-name, is required but previous agent responses for a token can be cached for efficiency. If the agent does not have a cached agent response for a particular token value, it must make an agent request to PingAccess to determine how to handle the client request. The data from that agent response can then be cached using the value of the indicated token as a key. An empty, null, or missing token should also be considered a valid cache key to support the anonymous access use case, where a WAM token is not necessary for access but, if such a token is available, user attributes from it should be exposed to the application. An agent response to a request that does not have the indicated token-type or token-name will likely contain a vnd-pi-set-req-headers
directive that names non-existent headers to ensure they are stripped from the modified client request. This prevents injection of those header values by the client, even in an anonymous case.
When caching individual agent responses relative to particular tokens, the protocol directives state that the token value is obtained from the client request. However, there is one important special case where, for efficiency, the token value can be obtained from the agent response. That special case is for resources with a kind of P and token-type of C that receive a 277 agent response containing a positive vnd-pi-token-cache-ttl
header value and a vnd-pi-append-resp-headers
that includes the set-cookie
header. Under those conditions, the agent can examine the set-cookie
headers for a cookie name matching the token-name of the resource and use the value of that cookie as the token value to cache the agent response. The agent should also exclude that set-cookie
header from the cached agent response content. This allows the cache to be established for an individual token in only one agent request to PingAccess when the token in the cookie is updated and set on the client.
Though the token relative caching is primarily intended as an optimization to store and reuse data associated with status code 277 responses, the following cache header defined is valid on any agent response, and agents should be prepared to cache all agent responses, rather than just 277 responses.
In general, individual agent responses for resources of kind of C are not cached. The one exception is the special case of a 477 response code where an agent can cache the 477, which tells it to send the request body on the initial agent request along with a !477 value for the vnd-pi-expect
header, for a specific request URI, until the vnd-pi-resource-cache-ttl
passes.
A kind value of U indicates that no agent request or response is necessary for the client request, so no additional caching is necessary.
- vnd-pi-token-cache-ttl
-
Indicates the number of seconds from the time the agent response is issued that it can be cached relative to a specific token value. The agent must make a new agent request if the TTL on the cache entry of an individual token has expired or if no cache entry exists.
The TTL should correlate to the life of the token itself. For example, the time-to-live must be shorter than the expiration, and it needs to also allow for updates to the inactivity timeout within a reasonable threshold.
There are many tradeoffs involved, so PingAccess enables tuning and configuration options for the TTL directive.
In the event that the token is empty, null, or missing, such as the anonymous use case, the value of
vnd-pi-token-cache-ttl
can be the same as the value of thevnd-pi-resource-cache-ttl
.
Early Cache Invalidation
PingAccess might include the following header in an agent response to instruct the agent to invalidate its cache. The agent might need to do this, for example, as a result of configuration changes.
- vnd-pi-cache-invalidated
-
The value of this header is a numeric value representing the number of seconds from 1970-01-01T0:0:0Z UTC (the epoch) until the UTC date and time of the cache invalidation event. The value is an indicator of the most recent event that would trigger an invalidation of the cache associated with the host, or X-Forwarded-Host, of the agent request correlated to the agent response in which this header appears. An agent might ignore an invalidation directive for a timestamp that it has already processed.
It is difficult for PingAccess to know the cache state of any particular agent or group of agents. It is not reasonable to expect PingAccess to identify the exact responses that should include the cache invalidation directive. Use of the timestamp as the header value allows PingAccess to send the
vnd-pi-cache-invalidated
more indiscriminately while allowing the agent to relatively easily determine if it has taken, or needs to take, action with respect to a specific invalidation event.
Change Propagation and Caching
An agent populates and expunges its cache over time. As a result, configuration changes in PingAccess might take some time to propagate and might yield a mixed set of old and new behavior.
The invalidation directive set using the vnd-pi-cache-invalidated
header on the agent response is intended to provide some help seeing changes take effect inside the TTL window. Though caching does reduce the number of calls made from an agent to PingAccess, there are still many requests that will necessitate the call and allow the vnd-pi-cache-invalidated
header to be sent to an agent.
Example OpenID Connect authentication
This response is passed through to the client to begin the OpenID Connect authentication process. The status and headers are passed directly through to the client.
HTTP/1.1 302 Found Date: Wed, 17 Sep 2014 23:10:30 GMT Content-Length: 0 Location: https://rhel-test.englab.corp.pingidentity.com:9031/as/authorization.oauth2?response_type=x_post%20id_token&client_id=pa_wam&redirect_uri=http://example.com/pa/oidc/cb&state=aHR0cDovL3JoZWw2NS9hcHBsaWNhdGlvbi9oZWFkZXJzIEFwcGxpY2F0aW9uIFJvb3QrUmVzb3VyY2U&nonce=X18Sm8qrBQ8n0K-0sWnlT1ZploeECQnR2bMZ-gs0lMY&scope=openid%20profile%20address%20email%20phone Set-Cookie: nonce=b000c6a2-4a03-4bde-be29-956456cd1d2a; Path=/; HttpOnly vnd-pi-resource-cache: path="/pa/*";kind=C,path="/application/*" "/application";cs=Y;kind=P;token-type=C;token-name=PA.post,path="/protected/*" "/protected";cs=Y;kind=P;token-type=C;token-name=PA.post,path="/httpbin/headers*";cs=Y;kind=P;token-type=C;token-name=PA.post,path="/httpbin/*" "/httpbin";cs=Y;kind=P;token-type=C;token-name=PA.post vnd-pi-resource-cache-ttl: 900 vnd-pi-token-cache-ttl: 300
Example Request for POST body
This response requests the POST body that was omitted from the initial agent request
HTTP/1.1 477 Request Body Required Date: Wed, 17 Sep 2014 23:10:35 GMT Content-Length: 0 vnd-pi-resource-cache: path="/pa/*";kind=C,path="/application/*" "/application";cs=Y;kind=P;token-type=C;token-name=PA.post,path="/protected/*" "/protected";cs=Y;kind=P;token-type=C;token-name=PA.post,path="/httpbin/headers*";cs=Y;kind=P;token-type=C;token-name=PA.post,path="/httpbin/*" "/httpbin";cs=Y;kind=P;token-type=C;token-name=PA.post vnd-pi-resource-cache-ttl: 900
Example Redirect
This response issues a redirect. The status code and headers are passed directly through to the client.
HTTP/1.1 302 Found Date: Wed, 17 Sep 2014 23:10:36 GMT Content-Length: 0 Location: http://example.com/application/headers Set-Cookie: PA.post=eyJraWQiOiJhcCIsImFsZyI6IkVTMjU2In0.eyJ6b25laW5mbyI6IkFtZXJpY2FcL05ld19Zb3JrIiwic3ViIjoiam9lIiwicGhvbmVfbnVtYmVyIjoiKzEgKDQyNSkgNTU1LTEyMTIiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJsb2NhbGUiOiJlbl9VUyIsInByZWZlcnJlZF91c2VybmFtZSI6Im1nc2FtcGxlIiwiZ2l2ZW5fbmFtZSI6Ik1lcmlkaXRoIiwidXBkYXRlZF90aW1lIjoiMjAxMS0wMS0wM1QyMzo1ODo0MiswMDAwIiwiaWF0IjoxNDEwOTk1NDM2LCJuYW1lIjoiTWVyaWRpdGggR29vZCBTYW1wbGUiLCJiaXJ0aGRhdGUiOiIxOTc3LTEyLTMxIiwiZmFtaWx5X25hbWUiOiJTYW1wbGUiLCJnZW5kZXIiOiJmZW1hbGUiLCJwcm9maWxlIjoiaHR0cHM6XC9cL3d3dy5waW5naWRlbnRpdHkuY29tXC9wcm9kdWN0c1wvcGluZ2ZlZGVyYXRlXC8iLCJ3ZWJzaXRlIjoiaHR0cHM6XC9cL3d3dy5waW5naWRlbnRpdHkuY29tXC8iLCJuaWNrbmFtZSI6Ik1lcmkiLCJtaWRkbGVfbmFtZSI6Ikdvb2QiLCJpc3MiOiJQaW5nQWNjZXNzIiwicGljdHVyZSI6Imh0dHBzOlwvXC93d3cucGluZ2lkZW50aXR5LmNvbVwvaW1hZ2VzXC9waW5nLWxvZ28ucG5nIiwiZXhwIjoxNDEwOTk5MDM2LCJwaS5zcmkiOiIyRUpVREtlTk5HZlNEdzdITWkzeEYzYlBSMlUiLCJlbWFpbCI6ImF1c2VyQGV4YW1wbGUuY29tIiwiYWRkcmVzcyI6eyJyZWdpb24iOiJNRSIsImZvcm1hdHRlZCI6IjEyMyBNYWluIFN0cmVldCwgU21hbGx2aWxsZSwgTUUgIFVTQSAxMTIyMyIsInBvc3RhbF9jb2RlIjoiMTEyMjMiLCJsb2NhbGl0eSI6IlNtYWxsdmlsbGUiLCJzdHJlZXRfYWRkcmVzcyI6IjEyMyBNYWluIFN0cmVldCIsImNvdW50cnkiOiJVU0EifSwiYXVkIjoicG9zdCIsImp0aSI6IjY2NjVkYzllLTUxMWMtNDE0Ni05YWFhLTI0ODUzNTA5NTE4MSIsImdyb3VwIjoic2FsZXMifQ.VRsuSs0LBnlHoJ2k-j0BDdLoGeVdqWD35n9ZxFhphEHFe7tfQ6onKAjRdXLR5rtwPBkJHkLaTLD8Yqcsf0izVw; Path=/; HttpOnly Set-Cookie: nonce=; Path=/; Expires=Thu, 01-Jan-1970 00:00:00 GMT vnd-pi-resource-cache: path="/pa/*";kind=C,path="/application/*" "/application";cs=Y;kind=P;token-type=C;token-name=PA.post,path="/protected/*" "/protected";cs=Y;kind=P;token-type=C;token-name=PA.post,path="/httpbin/headers*";cs=Y;kind=P;token-type=C;token-name=PA.post,path="/httpbin/*" "/httpbin";cs=Y;kind=P;token-type=C;token-name=PA.post vnd-pi-resource-cache-ttl: 900
Example Grant access
This response grants access and allows the client request through to the application with the appropriate application headers set and with the caching directives.
HTTP/1.1 277 Allowed Date: Wed, 17 Sep 2014 23:10:36 GMT Content-Length: 0 vnd-pi-resource-cache: path="/pa/*";kind=C,path="/application/*" "/application";cs=Y;kind=P;token-type=C;token-name=PA.post,path="/protected/*" "/protected";cs=Y;kind=P;token-type=C;token-name=PA.post,path="/httpbin/headers*";cs=Y;kind=P;token-type=C;token-name=PA.post,path="/httpbin/*" "/httpbin";cs=Y;kind=P;token-type=C;token-name=PA.post vnd-pi-resource-cache-ttl: 900 vnd-pi-token-cache-ttl: 300 USER: joe vnd-pi-sub: USER vnd-pi-set-req-headers: USER