Authorizers

Authorizers ensure that the subject obtained via an authenticator step has the required permissions to submit the given HTTP request and thus to execute the corresponding logic in the upstream service. E.g. a specific endpoint of the upstream service might only be accessible to a "user" from the "admin" group, or to an HTTP request if a specific HTTP header is set.

The following section describes the available authorizer types in more detail.

Authorizer Types

Allow

As the name implies, this authorizer allows any request passing through. This authorizer type also doesn’t have any configuration options.

To enable the usage of this authorizer, you have to set the type property to allow.

Example 1. Configuration of Allow authorizer
id: allow_any_request
type: allow

Deny

As the name implies, this authorizer denies any request (on HTTP response code level this is then mapped to Forbidden). It basically stops the successful execution of the pipeline resulting in the execution of the error handlers. This authorizer type doesn’t have any configuration options.

To enable the usage of this authorizer, you have to set the type property to deny.

Example 2. Configuration of Deny authorizer
id: deny_any_request
type: deny

Local

This authorizer allows definition of authorization requirements based on information available about the authenticated subject, as well as the actual request by using ECMAScript 5.1(+). The script is expected to either return false or raise an error if authorization fails. In such cases this authorizer denies the request. So, the successful execution of the pipeline stops, resulting in the execution of the error handlers. Otherwise, the authorizer assumes, the script allowed the request.

If the script makes use of raise the corresponding message will be logged as reason for the failed authorization, otherwise a generic "authorization failed" will be logged.

To enable the usage of this authorizer, you have to set the type property to local.

Configuration using the config property is mandatory. Following properties are available:

  • script: string (mandatory, overridable)

    ECMAScript which executes the actual authorization logic (see also Scripting). Heimdall expects the script to return either true, if the authorization was successful, or otherwise false, or to raise an error. In latter case the message from the raised error will also be logged.

Example 3. Authorization based on subject properties

In this example the subject is checked to be member of the "admin" group.

id: user_is_admin
type: local
config:
  script: |
    if (heimdall.Subject.Attributes["group"] !== "admin") {
      raise("user not in admin group")
    }
Example 4. Authorization based on subject and request properties

In this example the authorizer is configured to ensure anonymous access to a resource is possible for read-only requests only.

id: no_modification_allowed_by_anonymous
type: local
config:
  script: |
    if (heimdall.RequestMethod() !== "GET" &&
        heimdall.Subject.ID === "anonymous")
      raise("anonymous access is not allowed")
    }

The usage of this type of configuration makes sense in a pipeline, which combines multiple Authenticators, allowing anonymous and authenticated access.

Remote

This authorizer allows communication with other systems, like Open Policy Agent, Ory Keto, etc. for the actual authorization purpose. If the used endpoint answers with a not 2xx HTTP response code, this authorizer assumes, the authorization has failed and denies the request. So, the successful execution of the pipeline stops, resulting in the execution of the error handlers. Otherwise, if no script for the verification of the response if defined, the authorizer assumes, the request has been authorized. If a script is defined and does not fail, the authorization succeeds.

If your authorization system provides a payload in the response, Heimdall inspects the Content-Type header to prepare the payload for further usage, e.g. in the payload verification script, or in a Local authorizer. It can however deal only with a content type, which either ends with json or which is application/x-www-form-urlencoded. In these two cases, the payload is decoded and made available for the script as well as a map in the .Subject.Attributes. Otherwise, the payload is treated as string and made also available for the script and in the .Subject.Attributes property. To avoid overwriting of existing attributes, this object is however not available on the top level, but under a key named by the id of the authorizer (See also the example below).

To enable the usage of this authorizer, you have to set the type property to remote.

Configuration using the config property is mandatory. Following properties are available:

  • endpoint: Endpoint (mandatory, not overridable)

    The API endpoint of your authorization system. At least the url must be configured. This handler allows templating of the url and makes the Subject object available to it. By default, this authorizer will use HTTP POST to send the rendered payload to this endpoint. You can override this behavior by configuring method as well. Depending on the API requirements of your authorization system, you might need to configure further properties, like headers, etc.

  • payload: string (optional, overridable)

    Your template with definitions required to communicate to the authorization endpoint. See also Templating.

  • script: string (optional, overridable)

    ECMAScript which executed further authorization logic on the given response from the authorization endpoint (See also Scripting). Heimdall expects the script to return either true, if the authorization was successful, or otherwise false, or to raise an error. In latter case the message from the raised error will also be logged. Compared to the Local authorizer, only heimdall.Payload object is available, which contains the response from the authorization endpoint, as well as the console.log function, which enables logging from the script. Latter can become handy during development of debugging. The output is only available if debug log level is set.

  • forward_response_headers_to_upstream: string array (optional, overridable)

    Enables forwarding of any headers from the authorization endpoint response to the upstream service.

  • cache_ttl: Duration (optional, overridable)

    Allows caching of the authorization endpoint responses. Defaults to 0s, which means no caching. The cache key is calculated from the entire configuration of the authorizer instance and the available information about the current subject.

Example 5. Configuration of Remote authorizer to communicate with Open Policy Agent (OPA)

Here the remote authorizer is configured to communicate with OPA. Since OPA expects the query to be formatted as JSON, the corresponding Content-Type header is set. Since the responses are JSON objects as well, the Accept header is also provided. In addition, this examples uses the basic_auth auth type to authenticate against the endpoint.

id: user_can_write
type: remote
config:
  endpoint:
    url: https://opa.local/v1/data/myapi/policy/allow
    headers:
      Content-Type: json
      Accept: json
    auth:
      type: basic_auth
      config:
        user: MyOpaUser
        password: SuperSecretPassword
  payload: |
    { "input": { "user": {{ quote .Subject.ID }}, "access": "write" } }
  script: |
    heimdall.Payload.result === true

In this case, since an OPA response could look like { "result": true } or { "result": false }, heimdall makes the response also available under .Subject.Attributes["user_can_write"] as a map, with "user_can_write" being the id of the authorizer in this example.

Last updated on Nov 5, 2022