Security Providers
Implemented Security Providers
Helidon provides the following security providers for endpoint protection:
| Provider | Type | Outbound supported | Description |
|---|---|---|---|
| OIDC Provider | Authentication | ✅ | Open ID Connect supporting JWT, Scopes, Groups and OIDC code flow |
| HTTP Basic Authentication | Authentication | ✅ | HTTP Basic Authentication support |
| HTTP Digest Authentication | Authentication | 🚫 | Deprecated! HTTP Digest Authentication support |
| Header Assertion | Authentication | ✅ | Asserting a user based on a header value |
| HTTP Signatures | Authentication | ✅ | Protecting service to service communication through signatures |
| IDCS Roles | Role Mapping | 🚫 | Retrieves roles from IDCS provider for authenticated user |
| ABAC Authorization | Authorization | 🚫 | Attribute based access control authorization policies |
The following providers are no longer evolved:
| Provider | Type | Outbound supported | Description |
|---|---|---|---|
| Google Login | Authentication | ✅ | Deprecated! Authenticates a token from request against Google servers |
| JWT Provider | Authentication | ✅ | JWT tokens passed from frontend |
OIDC Provider
Open ID Connect security provider.
Maven Coordinates
<dependency>
<groupId>io.helidon.security.providers</groupId>
<artifactId>helidon-security-providers-oidc</artifactId>
</dependency>
Usage
In Helidon SE, we need to register the redirection support with routing (in
addition to SecurityFeature that integrates with WebServer). This is not
required when redirect is set to false.
Adding support for OIDC redirects
WebServer.builder()
.addFeature(SecurityFeature.builder()
.config(config.get("security"))
.build())
.routing(r -> r.addFeature(OidcFeature.create(config)))
.build();
Configuration options
| Key | Type | Default | Description |
|---|---|---|---|
force- | Boolean | false | Force HTTPS for redirects to identity provider |
cors | Cross | Assign cross-origin resource sharing settings | |
cookie- | Boolean | true | Whether to encrypt refresh token cookie created by this microservice |
query- | String | id_ | Name of a query parameter that contains the JWT id token when parameter is used |
jwt- | String | groups | Path to the JWT payload claim containing the groups to add as role grants |
header- | Boolean | true | Whether to expect JWT in a header field |
header- | Token | A Token to process header containing a JWT | |
cookie- | String | JSESSIONID_ | The name of the cookie to use for the state storage |
cookie- | Boolean | true if server- | Whether to GZIP-compress the access token cookie when this reduces its size |
outbound | List< | Add a new target configuration | |
propagate | Boolean | false | Whether to propagate identity |
client- | Client | Set the configuration related to the client credentials flow | |
fallback- | Boolean | false | Whether unknown tenant ids should use default tenant configuration |
cookie- | String | JSESSIONID_ | The name of the cookie to use for the refresh token |
query- | String | h_ | Name of a query parameter that contains the tenant name when the parameter is used |
query- | String | access | Name of a query parameter that contains the JWT access token when parameter is used |
pkce- | Pkce | S256 | Proof Key Code Exchange (PKCE) challenge creation method |
optional | Boolean | false | Whether authentication is required |
redirect- | Redirect | PARAM | Configure the strategy used to count redirects to an identity server |
legacy- | Boolean | false | Whether password-based encrypted OIDC cookies should retry decryption with the alternate cookie format after primary decryption fails |
cookie- | String | Domain the cookie is valid for | |
jwt- | String | Separator used to split a string claim value into multiple groups | |
frontend- | String | Full URI of this application that is visible from user browser | |
cookie- | Same | LAX | When using cookie, used to set the SameSite cookie value |
cookie- | Boolean | true | Whether to encrypt id token cookie created by this microservice |
webclient | Web | WebClient configuration used for outbound requests to the identity server. This configuration sets the values to the OIDC WebClient default configuration | |
cookie- | Boolean | true | When using cookie, if set to true, the HttpOnly attribute will be configured |
cookie- | Boolean | true | Whether to encrypt token cookie created by this microservice |
pkce- | Boolean | false | Whether this provider should support PKCE |
proxy- | Integer | 80 | Proxy port |
cookie- | Boolean | true | Whether to encrypt tenant name cookie created by this microservice |
use- | Boolean | true | Claim groups from JWT will be used to automatically add groups to current subject (may be used with jakarta. annotation) |
cookie- | Boolean | true if server- | Whether to GZIP-compress the ID token cookie when this reduces its size |
token- | Boolean | true | Whether access token signature check should be enabled |
cookie- | String | JSESSIONID | Name of the cookie to use |
cookie- | Boolean | true | Whether to use cookie to store JWT between requests |
outbound- | Oidc | USER_ | Type of the OIDC outbound |
redirect | Boolean | false | Whether to redirect to OIDC server when authentication information is missing |
redirect- | String | /oidc/ | URI to register web server component on, used by the OIDC server to redirect authorization requests to after a user logs in or approves scopes |
cookie- | String | JSESSIONID_ | Name of the cookie to use for id token |
tenants | Tenant | Configurations of the tenants | |
cookie- | Long | When using cookie, used to set MaxAge attribute of the cookie, defining how long the cookie is valid | |
cookie- | List< | Master password for encryption/decryption of cookies. Configure the same value on each service that shares encrypted cookies. If encrypted cookies are enabled and neither this option nor cookie-encryption-name is configured, Helidon creates or reads .helidon-oidc-secret in the current working directory | |
cookie- | Boolean | true | Whether to encrypt state cookie created by this microservice |
cookie- | String | / | Path the cookie is valid for |
query- | Boolean | false | Whether to use a query parameter to send JWT token from application to this server |
cookie- | String | HELIDON_ | The name of the cookie to use for the tenant name |
cookie- | Boolean | false | When using cookie, if set to true, the Secure attribute will be configured |
legacy- | Boolean | false | Whether password-based encrypted OIDC cookies should be written without a version byte and with the legacy PBKDF2 iteration count |
cookie- | String | Name of the encryption configuration available through Security encryption. If configured and encryption is enabled for any cookie, Security must be registered in the global or current context | |
id- | Boolean | true | Whether id token signature check should be enabled |
max- | Integer | 5 | Configure maximal number of redirects when redirecting to an OIDC provider within a single authentication attempt |
access- | Boolean | true | Whether to check if current IP address matches the one access token was issued for |
redirect- | String | h_ | Configure the redirect attempt query parameter and cookie name prefix |
Deprecated Options
| Key | Type | Default | Description |
|---|---|---|---|
relative- | Boolean | false | Whether to force relative URIs in all requests |
proxy- | String | Proxy host to use | |
proxy- | String | http | Proxy protocol to use when proxy is used |
Configuration Example
security:
providers:
- oidc:
client-id: "client-id-of-this-service"
client-secret: "${CLEAR=changeit}"
identity-uri: "https://your-tenant.identity-server.com"
frontend-uri: "http://my-service:8080"
audience: "http://my-service"
outbound:
- name: "internal-services"
hosts: ["*.example.org"]
outbound-token:
header: "X-Internal-Auth"
Example
See the example on GitHub.
How does it work?
At Helidon startup, if OIDC provider is configured, the following will happen:
client-id,client-secret, andidentityUriare validated - these must provide values- Unless all resources are configured as local resources, the provider
attempts to contact the
oidc-metadata.resourceendpoint to retrieve all endpoints
At runtime, depending on configuration...
If a request comes without a token or with insufficient scopes:
- If
redirectis set totrue(default), request is redirected to the authorization endpoint of the identity server. If set to false,401is returned - User authenticates against the identity server
- The identity server redirects back to Helidon service with a code
- Helidon service contacts the identity server’s token endpoint, to exchange the code for a JWT
- The JWT is stored in a cookie (if cookie support is enabled, which it is by default)
- Helidon service redirects to original endpoint (on itself)
Redirect attempts are counted to prevent infinite login redirects. By default,
Helidon stores the count in the redirect-attempt-param query parameter. Set
redirect-attempt-counter-strategy to COOKIE to store the counter in a small
cookie instead. Set it to NONE to disable redirect attempt counting and
max-redirects loop protection. The redirect-attempt-param value is used as
the cookie name prefix when the COOKIE strategy is used; the full cookie name
also includes a tenant and original URI hash.
Cookie Encryption Secret
Some OIDC cookies are encrypted by default. For production deployments,
configure cookie-encryption-password or cookie-encryption-name explicitly.
The same secret or named encryption configuration must be available to every
service instance that shares encrypted OIDC cookies.
If encrypted cookies are enabled and neither cookie-encryption-password nor
cookie-encryption-name is configured, Helidon uses .helidon-oidc-secret in
the current working directory as a local fallback secret file. When Helidon
generates that fallback file, it logs a warning. This fallback is intended for a
single service instance.
On POSIX file systems, Helidon creates the file with owner read/write permissions only and accepts an existing fallback file only when it is a regular file with owner-only read or read/write permissions. On non-POSIX file systems, Helidon still rejects symlinks and non-regular existing files, and creates the fallback file with an exclusive best-effort create operation.
For rolling upgrades from nodes that used the legacy password-based cookie
encryption defaults, set legacy-cookie-encryption to true while both old and
new nodes are running. This makes upgraded nodes keep writing cookies that older
nodes can decrypt.
After all nodes run the new version, set legacy-cookie-encryption to false
and set legacy-cookie-fallback to true for at least one cookie lifetime or
session grace period. After legacy cookies have expired, set both flags to
false. These flags are temporary compatibility controls for upgrades, not
steady-state security settings.
These flags only affect password-based OIDC cookie encryption; named Security
encryption configured with cookie-encryption-name uses its own encryption
configuration.
For a top-level server-type=idcs, the access-token and ID-token cookies are
GZIP-compressed by default when compression reduces their size. Compression is
disabled by default for other server types and can be enabled explicitly with
cookie-compression-enabled for the access token and
cookie-compression-id-enabled for the ID token. Compression is applied before
encryption when encryption is enabled, and uses a cookie-safe encoded form
otherwise. During a rolling upgrade from a version that does not understand
compressed token cookies, set both options to false on all nodes before
upgrading. New nodes still read compressed cookies while these settings are
disabled, but write the older uncompressed format. Re-enable compression after
all nodes have been upgraded and the rollback window has closed. Older nodes
cannot read compressed cookies. Rolling back after compression has been
re-enabled therefore requires invalidating affected sessions or waiting for the
compressed cookies to expire and users to authenticate again.
Helidon obtains a token from request (from cookie, header, or query parameter):
- Token is parsed as a singed JWT
- We validate the JWT signature either against local JWK or against the identity server’s introspection endpoint depending on configuration
- We validate the issuer and audience of the token if it matches the configured values
- A subject is created from the JWT, including scopes from the token
- We validate that we have sufficient scopes to proceed, and return
403if not - Handling is returned to security to process other security providers
Multi Tenancy
The OIDC provider also supports multi tenancy. To enable this feature, it is required to do several steps.
- To enable the default multi-tenant support, add the
multi-tenant: trueoption to the OIDC provider configuration - Specify the desired way to provide the tenant name. This step is done over
adding the
tenant-id-styleconfiguration option. For more information, see the table below - Add the tenants section to the OIDC provider configuration
tenants:
- name: "example-tenant"
# ... tenant configuration options
There are four ways to provide the required tenant information to Helidon by default.
Possible tenant-id-style configuration options:
| key | description | additional config options |
|---|---|---|
host-header | Tenant configuration will be selected based on your host present in the Host header value. | |
domain | Similar to the host-header style, but now the tenant name is identified just as a part of the host name. By default, it selects the third domain level.Example: Host header value from inbound request is | tenant-id-domain-level: <domain level> |
token-handler | The tenant name information is expected to be provided through the configured custom header value. | tenant-id-handler:
header: "my-custom-header" |
none | No tenant name finding is used. Default tenant name @default is used instead. |
You can also implement a custom way of discovering the tenant name and tenant configuration. The custom tenant name discovery from request can be done by implementing SPI:
io.helidon.security.providers.oidc.common.spi.TenantIdProvider
and the custom tenant configuration discovery can be provided by implementing SPI:
io.helidon.security.providers.oidc.common.spi.TenantConfigProvider
Available tenant config options
Configuration options
| Key | Type | Default | Description |
|---|---|---|---|
audience | String | Audience of issued tokens | |
authorization- | URI | URI of an authorization endpoint used to redirect users to for logging-in | |
base- | String | openid | Configure base scopes |
check- | Boolean | true | Configure audience claim check |
client- | String | Client ID as generated by OIDC server | |
client- | String | Client secret as generated by OIDC server | |
client- | Duration | 30000 | Timeout of calls using web client |
decryption- | Configuration for decryption-keys | ||
identity- | URI | URI of the identity server, base used to retrieve OIDC metadata | |
introspect- | URI | Endpoint to use to validate JWT | |
issuer | String | Issuer of issued tokens | |
name | String | Name of the tenant | |
oidc- | Configuration for oidc-metadata | ||
oidc- | Boolean | true | If set to true, metadata will be loaded from default (well known) location, unless it is explicitly defined using oidc-metadata-resource |
optional- | Boolean | false | Allow audience claim to be optional |
scope- | String | Audience of the scope required by this application | |
server- | String | @default | Configure one of the supported types of identity servers |
sign- | Configuration for sign-jwk | ||
token- | Client | CLIENT_ | Type of authentication to use when invoking the token endpoint. With CLIENT_SECRET_BASIC, credentials are sent only to POST requests on the resolved token endpoint scheme, host, and path and, when JWT introspection is used, to POST requests on the resolved introspection endpoint scheme, host, and path |
token- | URI | URI of a token endpoint used to obtain a JWT based on the authentication code | |
validate- | Boolean | true | Use JWK (a set of keys to validate signatures of JWT) to validate tokens |
How does that work?
Multi-tenant support requires to obtain tenant name from the incoming request.
OIDC configuration is selected based on the received tenant name. The way this
tenant name has to be provided is configured via tenant-id-style
configuration. See How to enable tenants for more information.
After matching tenant configuration with the received name, the rest of the OIDC
flow if exactly the same as in How does OIDC work.
Base OIDC configuration is treated as a default tenant, which is used if no
tenant name is provided. This default tenant has the name @default. An
identified tenant name must match a configured tenant; unknown tenant names are
rejected by default. Set fallback-to-default-tenant-enabled: true only when
unknown tenant names should use the default tenant configuration.
It is also important to note, that each tenant configuration is based on the default tenant configuration (base OIDC configuration), and therefore its configuration do not need to change all the properties, if they do not differ from the base OIDC configuration.
CORS Settings
CORS is (now) a single component configured either through config (key cors),
or programmatically via io.helidon.webserver.cors.CorsFeature. To add proper
CORS setup for the OIDC endpoint, use one of these. Component specific CORS
setup will be removed from Helidon.
HTTP Basic Authentication Provider
HTTP Basic authentication support
Maven Coordinates
<dependency>
<groupId>io.helidon.security.providers</groupId>
<artifactId>helidon-security-providers-http-auth</artifactId>
</dependency>
Configuration options
| Key | Type | Default | Description |
|---|---|---|---|
outbound | List< | Add a new outbound target to configure identity propagation or explicit username/password | |
optional | Boolean | false | Whether authentication is required |
realm | String | helidon | Set the realm to use when challenging users |
principal- | Subject | USER | Principal type this provider extracts (and also propagates) |
users | List< | Set user store to validate users |
Configuration Example
security:
providers:
- http-basic-auth:
realm: "helidon"
users:
- login: "john"
password: "${CLEAR=changeit}"
roles: ["admin"]
- login: "jack"
password: "changeit"
roles: ["user", "admin"]
outbound:
- name: "internal-services"
hosts: ["*.example.org"]
# Propagates current user's identity or identity from request property
outbound-token:
header: "X-Internal-Auth"
- name: "partner-service"
hosts: ["*.partner.org"]
# Uses this username and password
username: "partner-user-1"
password: "${CLEAR=changeit}"
Example
See the example on GitHub.
How does it work?
See https://tools.ietf.org/html/rfc7617.
Authentication of request
When a request is received without the Authorization: basic ... header, a
challenge is returned to provide such authentication.
When a request is received with the Authorization: basic ... header, the
username and password is validated against configured users (and users obtained
from custom service if any provided).
Subject is created based on the username and roles provided by the user store.
Identity propagation
When identity propagation is configured, there are several options for identifying username and password to propagate:
- We propagate the current username and password (inbound request must be authenticated using basic authentication).
- We use username and password from an explicitly configured property (See
EndpointConfig.PROPERTY_OUTBOUND_IDandEndpointConfig.PROPERTY_OUTBOUND_SECRET) - We use username and password associated with an outbound target (see example configuration above)
Identity is propagated only if:
- There is an outbound target configured for the endpoint
- Or there is an explicitly configured username/password for the current request (through request property)
Custom user store
Java service loader service
io.helidon.security.providers.httpauth.spi.UserStoreService can be implemented
to provide users to the provider, such as when validated against an internal
database or LDAP server. The user store is defined so you never need the clear
text password of the user.
Warning on security of HTTP Basic Authentication (or lack thereof)
Basic authentication uses base64 encoded username and password and passes it over the network. Base64 is only encoding, not encryption - so anybody that gets hold of the header value can learn the actual username and password of the user. This is a security risk and an attack vector that everybody should be aware of before using HTTP Basic Authentication. We recommend using this approach only for testing and demo purposes.
HTTP Digest Authentication Provider
Maven Coordinates
<dependency>
<groupId>io.helidon.security.providers</groupId>
<artifactId>helidon-security-providers-http-auth</artifactId>
</dependency>
Configuration options
| Key | Type | Default | Description |
|---|---|---|---|
qop | Qop | NONE | Only `AUTH` supported. If left empty, uses the legacy approach (older RFC version). `AUTH-INT` is not supported |
server- | List< | The nonce is encrypted using this secret - to make sure the nonce we get back was generated by us and to make sure we can safely time-out nonce values | |
optional | Boolean | false | Whether authentication is required |
realm | String | Helidon | Set the realm to use when challenging users |
nonce- | Long | 86400000 | How long will the nonce value be valid. When timed-out, browser will re-request username/password |
principal- | Subject | USER | Principal type this provider extracts (and also propagates) |
users | List< | Set user store to obtain passwords and roles based on logins | |
algorithm | Algorithm | MD5 | Digest algorithm to use |
Configuration Example
security:
providers:
- http-digest-auth:
realm: "helidon"
server-secret: "${CLEAR=service-wide-secret-not-known-outside}"
users:
- login: "john"
password: "${CLEAR=changeit}"
roles: ["admin"]
- login: "jack"
password: "changeit"
roles: ["user", "admin"]
How does it work?
See https://tools.ietf.org/html/rfc7616.
Authentication of request
When a request is received without the Authorization: digest ... header, a
challenge is returned to provide such authentication using WWW-Authenticate
header.
When a request is received with the Authorization: digest ... header, the
request is validated against configured users (and users obtained from custom
service if any provided).
Subject is created based on the username and roles provided by the user store.
Custom user store
Java service loader service
io.helidon.security.providers.httpauth.spi.UserStoreService can be implemented
to provide users to the provider, such as when validated against an internal
database or LDAP server. The user store is defined so you never need the clear
text password of the user.
Note on security of HTTP Digest Authentication
This authentication scheme is obsolete and should only be used for local testing or short-lived compatibility work.
Header Authentication Provider
Asserts user or service identity based on a value of a header.
Maven Coordinates
<dependency>
<groupId>io.helidon.security.providers</groupId>
<artifactId>helidon-security-providers-header</artifactId>
</dependency>
Configuration options
| Key | Type | Default | Description |
|---|---|---|---|
atn- | Token | Token handler to extract username from request | |
authenticate | Boolean | true | Whether to authenticate requests |
outbound | List< | Configure outbound target for identity propagation | |
propagate | Boolean | false | Whether to propagate identity |
optional | Boolean | false | Whether authentication is required |
outbound- | Token | Token handler to create outbound headers to propagate identity | |
principal- | Subject | USER | Principal type this provider extracts (and also propagates) |
Configuration Example
security:
providers:
header-atn:
atn-token:
header: "X-AUTH-USER"
outbound:
- name: "internal-services"
hosts: ["*.example.org"]
# propagates the current user or service id using the same header as authentication
- name: "partner-service"
hosts: ["*.partner.org"]
# propagates an explicit username in a custom header
username: "service-27"
outbound-token:
header: "X-Service-Auth"
How does it work?
This provider inspects a specified request header and extracts the username/service name from it and asserts it as current subject’s principal.
This can be used when we use perimeter authentication (e.g. there is a gateway that takes care of authentication and propagates the user in a header).
Identity propagation
Identity is propagated only if an outbound target matches the target service.
The following options exist when propagating identity: 1. We propagate the current username using the configured header 2. We use username associated with an outbound target (see example configuration above)
Caution
When using this provider, you must be sure the header cannot be explicitly configured by a user or another service. All requests should go through a gateway that removes this header from inbound traffic, and only configures it for authenticated users/services. Another option is to use this with fully trusted parties (such as services within a single company, on a single protected network not accessible to any users), and of course for testing and demo purposes.
HTTP Signatures Provider
Support for HTTP Signatures.
Maven Coordinates
<dependency>
<groupId>io.helidon.security.providers</groupId>
<artifactId>helidon-security-providers-http-sign</artifactId>
</dependency>
Configuration options
| Key | Type | Default | Description |
|---|---|---|---|
headers | List< | Add a header that is validated on inbound requests | |
inbound- | Duration | PT5M | Configure the maximum accepted age or future skew for the signed Date header |
outbound | Outbound | Add outbound targets to this builder | |
inbound. | List< | Add inbound configuration | |
backward- | Boolean | false | Enable support for Helidon versions before 3.0.0 (exclusive) |
optional | Boolean | true | Set whether the signature is optional |
realm | String | helidon | Realm to use for challenging inbound requests that do not have "Authorization" header in case header is Http and singatures are not optional |
sign- | List< | Override the default inbound required headers (e.g |
Configuration Example
security:
providers:
- http-signatures:
inbound:
keys:
- key-id: "service1-hmac"
principal-name: "Service1 - HMAC signature"
hmac.secret: "${CLEAR=changeit}"
- key-id: "service1-rsa"
principal-name: "Service1 - RSA signature"
public-key:
keystore:
resource.path: "src/main/resources/keystore.p12"
passphrase: "changeit"
cert.alias: "service_cert"
outbound:
- name: "service2-hmac"
hosts: ["localhost"]
paths: ["/service2"]
signature:
key-id: "service1-hmac"
hmac.secret: "${CLEAR=changeit}"
- name: "service2-rsa"
hosts: ["localhost"]
paths: ["/service2-rsa.*"]
signature:
key-id: "service1-rsa"
private-key:
keystore:
resource.path: "src/main/resources/keystore.p12"
passphrase: "changeit"
key.alias: "myPrivateKey"
Example
See the example on GitHub.
Signature basics
- standard: based on https://tools.ietf.org/html/draft-cavage-http-signatures-03
- key-id: an arbitrary string used to locate signature configuration - when a request is received the provider locates validation configuration based on this id (e.g. HMAC shared secret or RSA public key). Commonly used meanings are: key fingerprint (RSA); API Key
How does it work?
Inbound Signatures We act as a server and another party is calling us with a signed HTTP request. We validate the signature and assume identity of the caller.
By default, inbound validation requires signed date, (request-target), and
host fields. The authorization field must also be signed when it is present,
unless the signature itself is carried in the Authorization header. The signed
Date value must be within PT5M of the server time; configure
inbound-date-validity to another duration, or to PT0S to disable date
freshness validation. Date freshness rejects stale or far-future signatures; it
does not provide nonce-based replay detection within the accepted time window.
The (request-target) field uses the lower-case HTTP method followed by a
space, the request path, and the raw query string from the security environment,
when present. Query parameter order and encoding are significant.
Use sign-headers to require additional signed fields such as digest,
content-length, or content-type for selected methods.
If a request carries the signature in the Authorization header, that header
value cannot be combined with any other authorization scheme. Use the standalone
Signature header when another Authorization value must be sent with the same
request.
Outbound Signatures We act as a client and we sign our outgoing requests. If
there is a matching outbound target specified in configuration, its
configuration will be applied for signing the outgoing request, otherwise there
is no signature added
By default, outbound signing includes date, (request-target), and host. It
also signs authorization when that field is present, unless the signature
itself is carried in the Authorization header. The provider adds date and
host when they are required but missing.
IDCS Role Mapper
A role mapper to retrieve roles from Oracle IDCS.
Maven Coordinates
<dependency>
<groupId>io.helidon.security.providers</groupId>
<artifactId>helidon-security-providers-idcs-mapper</artifactId>
</dependency>
Single-tenant IDCS Role Mapper
Configuration options
| Key | Type | Default | Description |
|---|---|---|---|
cache- | Evictable | Use explicit io. for role caching | |
default- | String | user | Configure subject type to use when requesting roles from IDCS |
oidc- | Oidc | Use explicit io. instance, e.g | |
subject- | List< | USER | Add a supported subject type |
Multi-tenant IDCS Role Mapper
Configuration options
| Key | Type | Default | Description |
|---|---|---|---|
cache- | Evictable | Use explicit io. for role caching | |
default- | String | user | Configure subject type to use when requesting roles from IDCS |
idcs- | Token | Configure token handler for IDCS Application name | |
oidc- | Oidc | Use explicit io. instance, e.g | |
subject- | List< | USER | Add a supported subject type |
idcs- | Token | Token handler for an IDCS tenant ID. The extracted tenant ID must be a single DNS label: 1 to 63 alphanumeric or hyphen characters, with no leading or trailing hyphen. Invalid tenant IDs fail before endpoint resolution |
Configuration Example
security:
providers:
- idcs-role-mapper:
multitenant: false
oidc-config:
client-id: "client-id"
client-secret: "changeit"
identity-uri: "IDCS identity server address"
Example
See the example on GitHub.
How does it work?
The provider asks the IDCS server to provide list of roles for the currently
authenticated user. The result is cached for a certain period of time (see
cache-config above).
ABAC Provider
Attribute based access control authorization provider.
Maven Coordinates
<dependency>
<groupId>io.helidon.security.providers</groupId>
<artifactId>helidon-security-providers-abac</artifactId>
</dependency>
Configuration options
| Key | Type | Default | Description |
|---|---|---|---|
fail- | Boolean | true | Whether to fail if NONE of the attributes is validated |
fail- | Boolean | true | Whether to fail if any attribute is left unvalidated |
Configuration Example
security:
providers:
- abac:
Example
See the example on GitHub.
How does it work?
ABAC uses available validators and validates them against attributes of the authenticated user.
Combinations of fail-on-unvalidated and fail-if-none-validated:
true&true: Will fail if any attribute is not validated and if any has failed validationfalse&true: Will fail if there is one or more attributes present and NONE of them is validated or if any has failed validation, Will NOT fail if there is at least one validated attribute and any number of not validated attributes (and NONE failed)false&false: Will fail if there is any attribute that failed validation, Will NOT fail if there are no failed validation or if there are NONE validated
Any attribute of the following objects can be used:
- environment (such as time of request) - e.g. env.time.year
- subject (user) - e.g. subject.principal.id
- subject (service) - e.g. service.principal.id
- object (must be explicitly invoked by developer in code, as object cannot be automatically added to security context) - e.g. object.owner
This provider checks that all defined ABAC validators are validated. If there is a definition for a validator that is not checked, the request is denied (depending on configuration as mentioned above).
ABAC provider also allows an object to be used in authorization process, such as when evaluating if an object’s owner is the current user. The following example uses the Expression language validator to demonstrate the point in a JAX-RS resource:
Example of using an object
@Authenticated
@Path("/abac")
public class AbacResource {
@GET
@Authorized(explicit = true)
@PolicyStatement("${env.time.year >= 2017 && object.owner == subject.principal.id}")
public Response process(@Context SecurityContext context) {
// probably looked up from a database
SomeResource res = new SomeResource("user");
AuthorizationResponse atzResponse = context.authorize(res);
if (atzResponse.isPermitted()) {
//do the update
return Response.ok().entity("fine, sir").build();
} else {
return Response.status(Response.Status.FORBIDDEN)
.entity(atzResponse.description().orElse("Access not granted"))
.build();
}
}
}
The following validators are implemented:
Role Validator
Checks whether user/service is in either of the required role(s).
Configuration Key: role-validator
Annotations: @RolesAllowed, @RoleValidator.Roles
Configuration example for WebServer
security:
web-server.paths:
- path: "/user/*"
roles-allowed: ["user"]
JAX-RS example
@RolesAllowed("user")
@RoleValidator.Roles(value = "service_role", subjectType = SubjectType.SERVICE)
@Authenticated
@Path("/abac")
public class AbacResource {
}
JAX-RS sub-resource locators
When using sub-resource locators in JAX-RS, the roles allowed are collected from each "level" of execution: - Application class annotations - Resource class annotations + resource method annotations - Sub-resource class annotations + sub-resource method annotations - Sub-resource class annotations + sub-resource method annotations (for every sub-resource on the path)
The RolesAllowed or Roles annotation to be used is the last one in the path
as defined above.
Example 1: There is a RolesAllowed("admin") defined on a sub-resource
locator resource class. In this case the required role is admin.
Example 2: There is a RolesAllowed("admin") defined on a sub-resource
locator resource class and a RolesAllowed("user") defined on the method of the
sub-resource that provides the response. In this case the required role is
user.
Scope Validator
Checks whether user has all the required scopes.
Configuration Key: scope-validator
Annotations: @Scope
Configuration example for WebServer
security:
web-server.paths:
- path: "/user/*"
abac.scopes:
["calendar_read", "calendar_edit"]
JAX-RS example
@Scope("calendar_read")
@Scope("calendar_edit")
@Authenticated
@Path("/abac")
public class AbacResource {
}
Expression Language Policy Validator
Policy executor using Java EE policy expression language (EL)
Configuration Key: policy-javax-el
Annotations: @PolicyStatement
Example of a policy statement: ${env.time.year >= 2017}
Configuration example for WebServer
security:
web-server.paths:
- path: "/user/*"
policy:
statement: "hasScopes('calendar_read','calendar_edit') AND timeOfDayBetween('8:15', '17:30')"
JAX-RS example
@PolicyStatement("${env.time.year >= 2017}")
@Authenticated
@Path("/abac")
public class AbacResource {
}
Configuration example for JAX-RS over the configuration
server:
features:
security:
endpoints:
- path: "/somePath"
config:
abac.policy-validator.statement: "\\${env.time.year >= 2017}"
Google Login Provider
Authenticates a token from request against Google identity provider.
Maven Coordinates
<dependency>
<groupId>io.helidon.security.providers</groupId>
<artifactId>helidon-security-providers-google-login</artifactId>
</dependency>
Configuration options
| Key | Type | Default | Description |
|---|---|---|---|
proxy- | Integer | 80 | Set proxy port when talking to Google |
outbound | Outbound | Outbound configuration - a set of outbound targets that will have the token propagated | |
proxy- | String | Set proxy host when talking to Google | |
optional | Boolean | false | If set to true, this provider will return io. instead of failing in case of invalid request |
realm | String | helidon | Set the authentication realm to build challenge, defaults to "helidon" |
client- | String | Google application client id, to validate that the token was generated by Google for us | |
token | Token | `Authorization` header with `bearer` prefix | Token provider to extract Google access token from request, defaults to "Authorization" header with a "bearer " prefix |
Configuration Example
security:
providers:
- provider:
client-id: "Google client id"
Example
See the example on GitHub.
How does it work?
We expect to receive a token (with sufficient scopes) from the inbound request,
such as when using the Google login button on a page. The page has access to the
token in JavaScript and can send it to backend with every request in a header
field (Authorization with bearer prefix is assumed by default).
Once we receive the token in Helidon, we parse it and:
- Validate if it timed out locally
- Return a cached response (see
EvictableCachewith default values) - Otherwise, verify using Google API -
GoogleIdTokenVerifier
We build a subject from the Google token with the following attributes filled (if in token):
- userId
- name
- emailVerified
- locale
- family_name
- given_name
- picture (URL)
Outbound security The token will be propagated to outbound calls if an
outbound target exists that matches the invoked endpoint (see outbound
configuration above).
JWT Provider
JWT token authentication and outbound security provider.
Maven Coordinates
<dependency>
<groupId>io.helidon.security.providers</groupId>
<artifactId>helidon-security-providers-jwt</artifactId>
</dependency>
Configuration options
| Key | Type | Default | Description |
|---|---|---|---|
allow- | Boolean | false | Whether to allow impersonation by explicitly overriding username from outbound requests using io. property |
allow- | Boolean | false | Configure support for unsigned JWT |
atn- | Configuration for atn-token | ||
authenticate | Boolean | true | Whether to authenticate requests |
jwt- | String | groups | Path to the JWT payload claim containing the groups to add as role grants |
jwt- | String | Separator used to split a string claim value into multiple groups | |
optional | Boolean | false | Whether authentication is required |
principal- | Subject | USER | Principal type this provider extracts (and also propagates) |
propagate | Boolean | true | Whether to propagate identity |
sign- | Outbound | Configuration of outbound rules | |
use- | Boolean | true | Claim groups from JWT will be used to automatically add groups to current subject (may be used with jakarta. annotation) |
Configuration Example
security:
providers:
- provider:
atn-token:
jwk.resource.resource-path: "verifying-jwk.json"
jwt-issuer: "http://trusted.issuer"
jwt-audience: "http://my.service"
sign-token:
jwk.resource.resource-path: "signing-jwk.json"
jwt-issuer: "http://my.server/identity"
outbound:
- name: "propagate-token"
hosts: ["*.internal.org"]
- name: "generate-token"
hosts: ["1.partner-service"]
jwk-kid: "partner-1"
jwt-kid: "helidon"
jwt-audience: "http://1.partner-service"
Example
See the example on GitHub.
How does it work?
JSON Web Token (JWT) provider has support for authentication and outbound security.
Authentication is based on validating the token (signature, valid before etc.) and on asserting the subject of the JWT subject claim.
For outbound, we support either token propagation (e.g. the token from request is propagated further) or support for generating a brand-new token based on configuration of this provider.