JWT Authentication Plugin

2020-01-12

Solr can support JSON Web Token (JWT) based Bearer authentication with the use of the JWTAuthPlugin. This allows Solr to assert that a user is already authenticated with an external Identity Provider by validating that the JWT formatted access token is digitally signed by the Identity Provider. The typical use case is to integrate Solr with an OpenID Connect enabled IdP.

Enable JWT Authentication

To use JWT Bearer authentication, the security.json file must have an authentication part which defines the class being used for authentication along with configuration parameters.

The simplest possible security.json for registering the plugin without configuration is:

{
  "authentication": {
    "class":"solr.JWTAuthPlugin"
  }
}

The plugin will NOT block anonymous traffic in this mode, since the default for blockUnknown is false. It is then possible to start configuring the plugin using REST API calls, which is described in section Editing JWT Authentication Plugin Configuration.

Configuration Parameters

Key Description Default

blockUnknown

Set to true in order to block requests from users without a token

false

realm

Name of the authentication realm to echo back in HTTP 401 responses. Will also be displayed in Admin UI login page

'solr-jwt'

scope

Whitespace separated list of valid scopes. If configured, the JWT access token MUST contain a scope claim with at least one of the listed scopes. Example: solr:read solr:admin

requireIss

Fails requests that lacks an iss (issuer) claim

true

requireExp

Fails requests that lacks an exp (expiry time) claim

true

algWhitelist

JSON array with algorithms to accept: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384, PS512, `none

Default is to allow all algorithms

jwkCacheDur

Duration of JWK cache in seconds

3600 (1 hour)

principalClaim

What claim id to pull principal from

sub

claimsMatch

JSON object of claims (key) that must match a regular expression (value). Example: { "foo" : "A|B" } will require the foo claim to be either "A" or "B".

adminUiScope

Define what scope is requested when logging in from Admin UI

If not defined, the first scope from scope parameter is used

redirectUris

Valid location(s) for redirect after external authentication. Takes a string or array of strings. Must be the base URL of Solr, e.g., https://solr1.example.com:8983/solr/ and must match the list of redirect URIs registered with the Identity Provider beforehand.

Defaults to empty list, i.e., any node is assumed to be a valid redirect target.

issuers

List of issuers (Identity providers) to support. See section Issuer configuration for configuration syntax

Issuer Configuration

This plugin supports one or more token issuers (IdPs). Issuers are configured as a list of JSON objects under the issuers configuration key. The first issuer in the list is the "Primary Issuer", which is the one used for logging in to the Admin UI.

Key Description Default

name

A unique name of the issuer. Used to manipulate list through API.

wellKnownUrl

URL to an OpenID Connect Discovery endpoint

clientId

Client identifier for use with OpenID Connect. Required to authenticate with Admin UI. Needed for primary issuer only

jwksUrl

A URL to a JWKs endpoint. Must use https protocol. Optionally an array of URLs in which case all public keys from all URLs will be consulted when validating signatures.

Auto configured if wellKnownUrl is provided

jwk

As an alternative to jwksUrl you may provide a static JSON object containing the public key(s) of the issuer. The format is either JWK or JWK Set, see RFC7517 for examples.

iss

Unique issuer id as configured on the IdP. Incoming tokens must have a matching iss claim. Also used to resolve issuer when multiple issuers configured.

Auto configured if wellKnownUrl is provided

aud

Validates that the aud (audience) claim equals this string

Uses clientId if configured

authorizationEndpoint

The URL for the Id Provider’s authorization endpoint

Auto configured if wellKnownUrl is provided

Tip
For backwards compatibility, all the configuration keys for the primary issuer may be configured as top-level keys, except name.

More Configuration Examples

With JWKS URL

To start enforcing authentication for all users, requiring a valid JWT in the Authorization header, you need to configure the plugin with one or more JSON Web Keys (JWK). This is a JSON document containing the key used to sign/encrypt the JWT. It could be a symmetric or asymmetric key. The JWK can either be fetched (and cached) from an external HTTPS endpoint or specified directly in security.json. Below is an example of the former:

{
  "authentication": {
    "class": "solr.JWTAuthPlugin",
    "blockUnknown": true,
    "jwksUrl": "https://my.key.server/jwk.json"
  }
}
Tip
The configuration key jwkUrl is also supported as an alternative to jwksUrl for backwards compatibility with early versions of the plugin.

With Admin UI Support

The next example shows configuring using OpenID Connect Discovery with a well-known URI for automatic configuration of many common settings, including ability to use the Admin UI with an OpenID Connect enabled Identity Provider.

{
  "authentication": {
    "class": "solr.JWTAuthPlugin",
    "blockUnknown": true,
    "wellKnownUrl": "https://idp.example.com/.well-known/openid-configuration",
    "clientId": "xyz",
    "redirectUri": "https://my.solr.server:8983/solr/"
  }
}

In this case, jwksUrl, iss and authorizationEndpoint will be automatically configured from the fetched configuration.

Complex Example

Let’s look at a more complex configuration, this time with two issuers configured, where one uses a static embedded JWK:

{
  "authentication": {
    "class": "solr.JWTAuthPlugin", (1)
    "blockUnknown": true, (2)
    "principalClaim": "solruid", (3)
    "claimsMatch": { "foo" : "A|B", "dept" : "IT" }, (4)
    "scope": "solr:read solr:write solr:admin", (5)
    "algWhitelist" : [ "RS256", "RS384", "RS512" ], (6)
    "issuers": [ (7)
      {
        "name": "example1-static", (8)
        "jwk": { (9)
          "e": "AQAB",
          "kid": "k1",
          "kty": "RSA",
          "n": "3ZF6w....vjbCXxw"
        },
        "clientId": "solr-client-12345", (10)
        "iss": "https://example.com/idp", (11)
        "aud": "https://example.com/solr" (12)
      },
      {
        "name": "example2",
        "wellKnownUrl": "https://example2.com/.well-known/oidc", (13)
        "aud": "https://example2.com/solr"
      }
    ]
  }
}

Let’s comment on this config:

  1. Plugin class

  2. Make sure to block anyone without a valid token

  3. Fetch the user id from another claim than the default sub

  4. Require that the roles claim is one of "A" or "B" and that the dept claim is "IT"

  5. Require one of the scopes solr:read, solr:write or solr:admin

  6. Only accept RSA algorithms for signatures

  7. Array of issuer configurations

  8. Each issuer object should have a unique name

  9. Here we pass the JWK inline instead of referring to a URL with jwksUrl

  10. Set the client id registered with Identity Provider

  11. Configure the issuer id. Will be used for validating tokens. A token’s 'iss' claim must match one of the configured issuer IDs.

  12. Configure the audience claim. A token’s 'aud' claim must match 'aud' for one of the configured issuers.

  13. This issuer is auto configured through discovery, so 'iss' and JWK settings are not required

Editing JWT Authentication Plugin Configuration

All properties mentioned above, except the 'issuers' array, can be set or changed using the Authentication API. You can thus start with a simple configuration with only class configured and then configure the rest using the API.

Set a Configuration Property

Set properties for the authentication plugin. Each of the configuration keys in the table above can be used as parameter keys for the set-property command.

Example:

V1 API

curl http://localhost:8983/solr/admin/authentication -H 'Content-type:application/json' -H 'Authorization: Bearer xxx.yyy.zzz' -d '{"set-property": {"blockUnknown":true, "wellKnownUrl": "https://example.com/.well-knwon/openid-configuration", "scope": "solr:read solr:write"}}'

V2 API

curl http://localhost:8983/api/cluster/security/authentication -H 'Content-type:application/json' -H 'Authorization: Bearer xxx.yyy.zzz' -d -d '{"set-property": {"blockUnknown":true, "wellKnownUrl": "https://example.com/.well-knwon/openid-configuration", "scope": "solr:read solr:write"}}'

Insert a valid JWT access token in compact serialization format (xxx.yyy.zzz above) to authenticate with Solr once the plugin is active, or leave blockUnknown=false until configuration is complete and then switch it to true to start enforcing.

Note
There is currently no support for adding multiple token issuers though REST API, but you can configure one issuer through the API by using the 'issuer' properties as top-level properties.

Using Clients with JWT Auth

SolrJ

SolrJ does not currently support supplying JWT tokens per request.

cURL

To authenticate with Solr when using the cURL utility, supply a valid JWT access token in an Authorization header, as follows (replace xxxxxx.xxxxxx.xxxxxx with your JWT compact token):

curl -H "Authorization: Bearer xxxxxx.xxxxxx.xxxxxx" http://localhost:8983/solr/admin/info/system

Admin UI

When this plugin is enabled, users will be redirected to a login page in the Admin UI once they attempt to do a restricted action. The page has a button that users will click and be redirected to the Identity Provider’s login page. If more than one issuer (IdP) is configured, the first in the list will be used for Admin UI. Once authenticated, the user will be redirected back to Solr Admin UI to the last known location. The session will last as long as the JWT token expiry time and is valid for one Solr server only. That means you have to login again when navigating to another Solr node. There is also a logout menu in the left column where user can explicitly log out.

Using the Solr Control Script with JWT Auth

The control script (bin/solr) does not currently support JWT Auth.