Ensure Variables
This filter enforces certain attributes of a request like a header, cookie, or query string and optionally moves it to another location. The filter can be configured to reject the request completely if one of these variables is not present. This is meant to act as a normalization filter that makes it easier for downstream filters to find and use variables.
The original motivation of this filter came during the implementation of OpenID Connect authentication filters. An access token which comes from Identity Provider is in a query string; while it will be in cookie when coming from a user facing application such as Dashboard. We found ourselves checking all these locations multiple times and thought "wouldn't it be nice if there was a filter that looked for these locations and copied it to one location other filters expect?". That was the original intention. In doing so, we came up with this generic solution that can be configured to suit a variety of needs that may arise.
Filter Configuration Options
Name
Type
Default
Example
Description
rules
array
n/a
A list of rules to compare to the incoming request. Rules are checked in order of appearance in the list.
rules.key
string
n/a
"Authorization"
The key to check in the incoming request
rules.location
enum[header, cookie, queryString, metadata]
header
cookie
The location to check for the specified key/value pair
rules.metadataFilter
string
""
"gm.oidc-authentication"
The name of the filter to read dynamic metadata from. Required if rules.location=metadata
rules.enforce
bool
false
true
Whether to completely reject the request if a rule doesn't match
rules.enforceResponseCode
string
403
500
The status code to send back if a rule does not match and enforce
is true.
rules.removeOriginal
bool
false
true
Whether to remove the original matching key/value pair from the request.
rules.value.matchType
enum[exact, prefix, suffix, regex]
exact
regex
The type of comparison between the key/value pair and the incoming request
rules.value.matchString
string
n/a
Bearer\s+(\S+).*
The string to match against the incoming request
rules.value.copyTo
array
n/a
A list of locations where the matched variable may be copied (optional)
rules.value.copyTo.location
enum[header, cookie, queryString, metadata]
header
cookie
Location to copy the matched variable to
rules.value.copyTo.key
string
n/a
"access_token"
Name of the key where the value will be stored
rules.value.copyTo.direction
enum[default, request, response, both]
default
response
Whether to copy the variable to the request, response, or both. Default will be request or response depending on the location
. See (#hiromis-section for more information.)
rules.value.copyTo.cookieOptions.httpOnly
bool
false
true
rules.value.copyTo.cookieOptions.secure
bool
false
true
Whether the cookie being created should only be sent to the server over HTTPS.
rules.value.copyTo.cookieOptions.maxAge
string
session
12h
The Max-Age
of the new cookie. The value is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "s", "m", "h" ("ns", "us"/"µs", and "ms" are also valid but the value gets rounded to the nearest second as Max-Age
is defined as "number of seconds until the cookie expires"). If maxAge
is not set, the cookie will have Expires/Max-Age
of Session
.
rules.value.copyTo.cookieOptions.path
string
""
/ping
Path indicates a URL path that must exist in the requested URL in order to send the Cookie header. The %x2F ("/") character is considered a directory separator, and subdirectories will match as well.
rules.value.copyTo.cookieOptions.domain
string
""
localhost
Domain specifies allowed hosts to receive the cookie. If unspecified, it defaults to the host of the current document location, excluding subdomains. If Domain is specified, then subdomains are always included.
Design Decisions
Value match
This field came about when we were dealing with Authorization Bearer token. The key is Authorization
and the value looks something like Bearer eyJraWQiOiJtOEpPX0l4SndNMG...
. The first thing we wanted to make sure was that the value starts with Bearer
and not something like Basic
(for basic authorization). We also wanted to extract the actual token value before copying it to another location. So we allow the regular expression to optionally have a capturing group.
CopyTo field
copyTo
has a field called direction
. This can be thought of as "who should see this copied variable". If the answer is "the service which is receiving this request", then the direction should be request
. If it is "the user or application that initiated this request", then the direction is response
. You can also set it to both
. Because some combinations of location
and direction
are not feasible, we will make some assertions.
Copying to header
If no direction is set, it will default to request
.
Copying to cookie
Cookies are stored in browsers, so copying to cookie
will always add a Set-Cookie
header to the response (even if direction is set to request
). In cases such as a Bearer token or a user information token is passed around in a cookie, the service who is receiving the request may want to see what would be stored in cookie once this request is complete. You can allow this by setting the direction to both
(request
will also work because we will always add a cookie to response). This will only allow the service to see what will be in Set-Cookie
header in the response. So if a service is expecting the Bearer token in the cookie, it will need to check both Cookie
and Set-Cookie
headers.
If no direction is set, it will default to response
.
Copying to query string
Query strings can only be read by the service receiving this request. Hence setting the direction to response
will results in a warning getting logged and have no effect.
If no direction is set, it will default to request
.
Sample Configurations
The following sample configurations can be easily tested in docs/examples/ensure-variable/config.yaml
. Update the configuration starting on line 38 and use the sample queries to experiment.
Enforcing a header
Assert that requests must have an Authorization: Bearer
header, otherwise return a 404.
Passing requests:
Rejected requests:
Checking a header and copying it to a cookie
Check that an Authorization header exists on the request. If it does, copy the value to an httpOnly cookie and set on the request and response (defaults to response). If not, let the request pass through (notice enforce: false
.)
Requests that will set set-cookie header:
Requests that will pass through without setting anything:
Enforcing a query string
Rejects all requests that don't have a query string with a key of username
and a value prefixed with jane
. Sends back a default 403 status code.
Passing requests:
Rejected requests:
Enforcing a cookie and then removing it
Checks for a cookie with a user_dn
value that exactly matches matchString
and then removes the cookie from the browser. You'll notice the following header on a successful response: set-cookie: user_dn=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Max-Age=0
. This will remove the cookie from the user's browser by expiring it and removing the value.
Passing request:
Rejected requests:
Setting multiple copyTo locations
Checks for the existence of an id_token query string. If it exists, it is copied to a response cookie with a key of userinfoCookie. It also copies this value to a header on the request and response with a key of x-userinfo
.
Passing requests:
Rejected requests:
Setting multiple rules
The following configuration checks:
An
Authorization: Bearer <somevalue>
header exists. If it does, it copies<somevalue>
to a cookie with a key ofaccess_key
.An
id_token
queryString exists with any value (notice how there is novalue
block set). If the key exists, it copies the value to a cookie with a key ofuserinfo
.
Passing requests:
Rejected requests:
Last updated
Was this helpful?