PingAccess

PAAP agent response

After PingAccess receives an agent request, it returns an agent response, which includes an authorization decision and instructions for any additional actions that the agent should perform on the client request or a request for additional information from the agent.

If the agent response contains an HTTP status code that isn’t described in this document, PingAccess did not permit the client request. In this case, the content of the agent response, including the status-line, the message-body, and all the headers that aren’t named by the header or defined later, is sent back to the client as the content of the client response. This method lets PingAccess:

  • Direct the client, when applicable, to PingFederate for user authentication through redirection or even auto-post form.

  • 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 to make a policy decision, PingAccess requires the agent to repeat the agent request and include the request body. Following that, the subsequent agent response will include the policy decision and any necessary actions to take.

Currently, PingAccess only requires agents to include the request body in the agent request if it needs to evaluate an auto-posted OpenID Connect Authentication Response. To optimize performance, agents don’t include the request body by default. The 477 response provides a means for PingAccess to ask for the request body when necessary.

This enables the agent to leave configuring any callback redirect_uri locations to PingAccess. All the agent knows is that it received a POST request and that PingAccess asked for the message-body to process it.

After the agent repeats the agent request with the request body included, PingAccess responds to the agent with a generic HTTP response code. PingAccess only returns a 477 response to get an auto-posted OpenID Connect Authentication Response at the redirect Uniform Resource Identifier (URI), so PingAccess never returns a 277 response after a 477 response.

PingAccess should never respond to a GET request with a 477.

HTTP 277 Allowed

A 277 response indicates that 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 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 include as headers for the client request. If any included headers already exist in the client request, the values are overwritten by the values from the corresponding agent response header. If a named header isn’t present in the agent response, it’s 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. 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 that 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 that are already present in the client request are not overwritten, but new headers are added with the values from the agent response. If a named header isn’t 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 set in the client request as request scoped variables or attributes in an appropriate manner for the environment that the agent resides in. 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. Typically, this is a header that’s also named in vnd-pi-set-req-headers because those headers generally expose user information to the backend application through headers in the modified client request. vnd-pi-sub might name a header that isn’t in the vnd-pi-set-req-headers list if the agent or the 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.

The vnd-pi-sub header should name a single-valued header, but if it names one with multiple values, the agent should use only one of those values. If vnd-pi-sub names a header that isn’t present in the agent response, the agent should ignore it.

vnd-pi-set-resp-headers

The value of this header is a comma-delimited list of header names from the agent response to 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 named header isn’t present in the agent response, it’s 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 add to the headers of the client response. Any existing named headers that are already present in the client response are’t overwritten, but new headers are added with the values from the agent response. If a named header isn’t 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.

Generally, for any particular request or response header name, PingAccess should only indicate either a set or an append directive. However, the set directive takes precedence with an agent response. 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. If present, this list implicitly includes the vnd-pi-omit-resp-headers header.

Caching

Caching directives aim to improve performance by reducing the number of calls made from the agent to PingAccess.

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 how to handle 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. Value ordering has a significant impact. When servicing future requests based on the cache, agents evaluate values in the order that 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. Specify a value of one or more space-delimited quoted strings. Each quoted string is a path value, which can contain wildcards using the asterisk (*) character.

For example, path="/app/*" would match any requested path that starts with /app/ while path="/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 there isn’t a wildcard, the values must match exactly.

If you’re using a Web + API application, PingAccess adds an additional path to the vnd-pi-resource-cache header to cache both cookie and authorization header token-types. For example:

 vnd-pi-resource-cache: path = “ /*”; cs = N, kind = P; token-type = C; token-name = <cookie_name>, path = “ /*”; cs = N, kind = P; token-type = A; token-name = <OAuth Bearer value>

Recording both bearer and cookie cache entries for the same path reduces the number of calls that an agent needs to make to PingAccess for access decisions, and enables setting more precise token time-to-live (TTL) values for both token-types.

When the application type is Web + API, PingAccess will only return the TTL header corresponding with the token-type that it used to make the access decision, vnd-pi-token-cache-ttl or vnd-pi-token-cache-oauth-ttl, even if the request included both a bearer token and cookie.

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 the vnd-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 new vnd-pi-resource-cache and vnd-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 previous is semantically equivalent to the following headers where the multiple vnd-pi-resource-cache header fields are combined into one:

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 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 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.

Generally, 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 the vnd-pi-resource-cache-ttl.

If you’re using a Web + API application, PingAccess returns this TTL header only if it uses the cookie token-type to make an access decision. Otherwise, it will return the vnd-pi-token-cache-oauth-ttl header.

vnd-pi-token-cache-oauth-ttl

The value of the resource cache OAuth time-to-live header is an integer indicating the number of seconds from the time the response was sent that the values of the vnd-pi-resource-cache header can be cached and used.

If you’re using a Web + API application, PingAccess returns this TTL header only if it uses the authorization header token-type to make an access decision. Otherwise, it will return the vnd-pi-token-cache-ttl header.

Early Cache Invalidation

PingAccess might include the following header in an agent response to instruct the agent to invalidate its cache. For example, the agent might need to do this 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. PingAccess can’t identify the exact responses that should include the cache invalidation directive. Using the timestamp as the header value allows PingAccess to send the vnd-pi-cache-invalidated more indiscriminately while allowing the agent to 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 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