Implemented Security Providers

Helidon provides the following security providers for endpoint protection:

ProviderTypeOutbound supportedDescription
OIDC ProviderAuthenticationOpen ID Connect supporting JWT, Scopes, Groups and OIDC code flow
HTTP Basic AuthenticationAuthenticationHTTP Basic Authentication support
HTTP Digest AuthenticationAuthentication🚫HTTP Digest Authentication support
Header AssertionAuthenticationAsserting a user based on a header value
HTTP SignaturesAuthenticationProtecting service to service communication through signatures
IDCS RolesRole Mapping🚫Retrieves roles from IDCS provider for authenticated user
ABAC AuthorizationAuthorization🚫Attribute based access control authorization policies

The following providers are no longer evolved:

ProviderTypeOutbound supportedDescription
Google LoginAuthenticationDeprecated! Authenticates a token from request against Google servers
JWT ProviderAuthenticationJWT tokens passed from frontend

OIDC Provider

Open ID Connect security provider.

Setup

Maven dependency
<dependency>
    <groupId>io.helidon.microprofile</groupId>
    <artifactId>helidon-microprofile-oidc</artifactId>
</dependency>
Copied

Configuration options

KeyKindTypeDefault ValueDescription
access-token-ip-checkVALUEBooleantrueWhether to check if current IP address matches the one access token was issued for
client-credentials-configVALUEi.h.s.p.o.c.ClientCredentialsConfig Set the configuration related to the client credentials flow
cookie-domainVALUEString Domain the cookie is valid for
cookie-encryption-enabledVALUEBooleanfalseWhether to encrypt token cookie created by this microservice
cookie-encryption-id-enabledVALUEBooleantrueWhether to encrypt id token cookie created by this microservice
cookie-encryption-nameVALUEString Name of the encryption configuration available through Security#encrypt(String, byte[) and Security#decrypt(String, String)]
cookie-encryption-passwordLISTString Master password for encryption/decryption of cookies
cookie-encryption-refresh-enabledVALUEBooleantrueWhether to encrypt refresh token cookie created by this microservice
cookie-encryption-state-enabledVALUEBooleantrueWhether to encrypt state cookie created by this microservice
cookie-encryption-tenant-enabledVALUEBooleantrueWhether to encrypt tenant name cookie created by this microservice
cookie-http-onlyVALUEBooleantrueWhen using cookie, if set to true, the HttpOnly attribute will be configured
cookie-max-age-secondsVALUELong When using cookie, used to set MaxAge attribute of the cookie, defining how long the cookie is valid
cookie-nameVALUEStringJSESSIONIDName of the cookie to use
cookie-name-id-tokenVALUEStringJSESSIONID_2Name of the cookie to use for id token
cookie-name-refresh-tokenVALUEStringJSESSIONID_3The name of the cookie to use for the refresh token
cookie-name-stateVALUEStringJSESSIONID_3The name of the cookie to use for the state storage
cookie-name-tenantVALUEStringHELIDON_TENANTThe name of the cookie to use for the tenant name
cookie-pathVALUEString/Path the cookie is valid for
cookie-same-siteVALUEi.h.h.S.SameSiteLAXWhen using cookie, used to set the SameSite cookie value
cookie-secureVALUEBooleanfalseWhen using cookie, if set to true, the Secure attribute will be configured
cookie-useVALUEBooleantrueWhether to use cookie to store JWT between requests
corsVALUEi.h.c.CrossOriginConfig Assign cross-origin resource sharing settings
force-https-redirectsVALUEBooleanfalseForce HTTPS for redirects to identity provider
frontend-uriVALUEString Full URI of this application that is visible from user browser
header-tokenVALUEi.h.s.u.TokenHandler A TokenHandler to process header containing a JWT
header-useVALUEBooleantrueWhether to expect JWT in a header field
id-token-signature-validationVALUEBooleantrueWhether id token signature check should be enabled
max-redirectsVALUEInteger5Configure maximal number of redirects when redirecting to an OIDC provider within a single authentication attempt
optionalVALUEBooleanfalseWhether authentication is required
outboundLISTi.h.s.p.c.OutboundTarget Add a new target configuration
outbound-typeVALUEi.h.s.p.o.c.OidcOutboundTypeUSER_JWTType of the OIDC outbound
pkce-challenge-methodVALUEi.h.s.p.o.c.PkceChallengeMethodS256Proof Key Code Exchange (PKCE) challenge creation method
pkce-enabledVALUEBooleanfalseWhether this provider should support PKCE
propagateVALUEBooleanfalseWhether to propagate identity
proxy-portVALUEInteger80Proxy port
query-id-token-param-nameVALUEStringid_tokenName of a query parameter that contains the JWT id token when parameter is used
query-param-nameVALUEStringaccessTokenName of a query parameter that contains the JWT access token when parameter is used
query-param-tenant-nameVALUEStringh_tenantName of a query parameter that contains the tenant name when the parameter is used
query-param-useVALUEBooleanfalseWhether to use a query parameter to send JWT token from application to this server
redirectVALUEBooleanfalseBy default, the client should redirect to the identity server for the user to log in
redirect-attempt-paramVALUEStringh_raConfigure the parameter used to store the number of attempts in redirect
redirect-uriVALUEString/oidc/redirectURI to register web server component on, used by the OIDC server to redirect authorization requests to after a user logs in or approves scopes
tenantsVALUEi.h.s.p.o.c.TenantConfig Configurations of the tenants
token-signature-validationVALUEBooleantrueWhether access token signature check should be enabled
use-jwt-groupsVALUEBooleantrueClaim groups from JWT will be used to automatically add groups to current subject (may be used with jakarta.annotation.security.RolesAllowed annotation)
webclientVALUEi.h.w.a.WebClient WebClient configuration used for outbound requests to the identity server. This configuration sets the values to the OIDC WebClient default configuration
Deprecated Options
KeyKindTypeDefault ValueDescription
proxy-hostVALUEString Proxy host to use
proxy-protocolVALUEStringhttpProxy protocol to use when proxy is used
relative-urisVALUEBooleanfalseCan be set to true to force the use of relative URIs in all requests, regardless of the presence or absence of proxies or no-proxy lists

Example code

See the example on GitHub.

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"
Copied

How does it work?

At Helidon startup, if OIDC provider is configured, the following will happen:

  1. client-id, client-secret, and identityUri are validated - these must provide values
  2. Unless all resources are configured as local resources, the provider attempts to contact the oidc-metadata.resource endpoint to retrieve all endpoints

At runtime, depending on configuration…​

If a request comes without a token or with insufficient scopes:

  1. If redirect is set to true (default), request is redirected to the authorization endpoint of the identity server. If set to false, 401 is returned
  2. User authenticates against the identity server
  3. The identity server redirects back to Helidon service with a code
  4. Helidon service contacts the identity server’s token endpoint, to exchange the code for a JWT
  5. The JWT is stored in a cookie (if cookie support is enabled, which it is by default)
  6. Helidon service redirects to original endpoint (on itself)

Helidon obtains a token from request (from cookie, header, or query parameter):

  1. Token is parsed as a singed JWT
  2. We validate the JWT signature either against local JWK or against the identity server’s introspection endpoint depending on configuration
  3. We validate the issuer and audience of the token if it matches the configured values
  4. A subject is created from the JWT, including scopes from the token
  5. We validate that we have sufficient scopes to proceed, and return 403 if not
  6. Handling is returned to security to process other security providers

Multiple tenants

The OIDC provider also supports multiple tenants. To enable this feature, it is required to do several steps.

  1. To enable the default multi-tenant support, add the multi-tenant: true option to the OIDC provider configuration
  2. Specify the desired way to provide the tenant name. This step is done over adding the tenant-id-style configuration option. For more information, see the table below
  3. Add the tenants section to the OIDC provider configuration
tenants:
   - name: "example-tenant"
     # ... tenant configuration options
Copied

There are four ways to provide the required tenant information to Helidon by default.

Possible tenant-id-style configuration options
keydescriptionadditional 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 my.helidon.com → domain level 3 is my, domain level 2 is helidon and domain level 1 is com.

tenant-id-domain-level: <domain level>
Copied
token-handler

The tenant name information is expected to be provided through the configured custom header value.

tenant-id-handler:
  header: "my-custom-header"
Copied
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
KeyKindTypeDefault ValueDescription
audienceVALUEString Audience of issued tokens
authorization-endpoint-uriVALUEURI URI of an authorization endpoint used to redirect users to for logging-in
base-scopesVALUEStringopenidConfigure base scopes
check-audienceVALUEBooleantrueConfigure audience claim check
client-idVALUEString Client ID as generated by OIDC server
client-secretVALUEString Client secret as generated by OIDC server
client-timeout-millisVALUEDuration30000Timeout of calls using web client
decryption-keys.resourceVALUEi.h.c.c.Resource A resource pointing to JWK with private keys used for JWE content key decryption
identity-uriVALUEURI URI of the identity server, base used to retrieve OIDC metadata
introspect-endpoint-uriVALUEURI Endpoint to use to validate JWT
issuerVALUEString Issuer of issued tokens
nameVALUEString Name of the tenant
oidc-metadata-well-knownVALUEBooleantrueIf set to true, metadata will be loaded from default (well known) location, unless it is explicitly defined using oidc-metadata-resource
oidc-metadata.resourceVALUEi.h.c.c.Resource Resource configuration for OIDC Metadata containing endpoints to various identity services, as well as information about the identity server
optional-audienceVALUEBooleanfalseAllow audience claim to be optional
scope-audienceVALUEString Audience of the scope required by this application
server-typeVALUEString@defaultConfigure one of the supported types of identity servers
sign-jwk.resourceVALUEi.h.c.c.Resource A resource pointing to JWK with public keys of signing certificates used to validate JWT
token-endpoint-authVALUEi.h.s.p.o.c.O.ClientAuthenticationCLIENT_SECRET_BASICType of authentication to use when invoking the token endpoint
token-endpoint-uriVALUEURI URI of a token endpoint used to obtain a JWT based on the authentication code
validate-jwt-with-jwkVALUEBooleantrueUse 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 is having @default name specified.

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

Setup

Maven dependency
<dependency>
    <groupId>io.helidon.security.providers</groupId>
    <artifactId>helidon-security-providers-http-auth</artifactId>
</dependency>
Copied

Overview

Configuration options

KeyKindTypeDefault ValueDescription
optionalVALUEBooleanfalseWhether authentication is required
outboundLISTi.h.s.p.c.OutboundTarget Add a new outbound target to configure identity propagation or explicit username/password
principal-typeVALUEi.h.s.SubjectTypeUSERPrincipal type this provider extracts (and also propagates)
realmVALUEStringhelidonSet the realm to use when challenging users
usersLISTi.h.s.p.h.C.ConfigUser Set user store to validate users

Example code

See the example on GitHub.

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}"
Copied

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:

  1. We propagate the current username and password (inbound request must be authenticated using basic authentication).
  2. We use username and password from an explicitly configured property (See EndpointConfig.PROPERTY_OUTBOUND_ID and EndpointConfig.PROPERTY_OUTBOUND_SECRET)
  3. We use username and password associated with an outbound target (see example configuration above)

Identity is propagated only if:

  1. There is an outbound target configured for the endpoint
  2. 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

HTTP Digest authentication support

Setup

Maven dependency
<dependency>
    <groupId>io.helidon.security.providers</groupId>
    <artifactId>helidon-security-providers-http-auth</artifactId>
</dependency>
Copied

Overview

Configuration options

KeyKindTypeDefault ValueDescription
algorithmVALUEi.h.s.p.h.H.AlgorithmMD5Digest algorithm to use
nonce-timeout-millisVALUELong86400000How long will the nonce value be valid. When timed-out, browser will re-request username/password
optionalVALUEBooleanfalseWhether authentication is required
principal-typeVALUEi.h.s.SubjectTypeUSERPrincipal type this provider extracts (and also propagates)
qopVALUEi.h.s.p.h.H.QopNONEOnly `AUTH` supported. If left empty, uses the legacy approach (older RFC version). `AUTH-INT` is not supported
realmVALUEStringHelidonSet the realm to use when challenging users
server-secretLISTString 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
usersLISTi.h.s.p.h.C.ConfigUser Set user store to obtain passwords and roles based on logins

Example code

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"]
Copied

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

These authentication schemes should be obsolete, though they provide a very easy way to test a protected resource.

Header Authentication Provider

Asserts user or service identity based on a value of a header.

Setup

Maven dependency
<dependency>
    <groupId>io.helidon.security.providers</groupId>
    <artifactId>helidon-security-providers-header</artifactId>
</dependency>
Copied

Overview

Configuration options

KeyKindTypeDefault ValueDescription
atn-tokenVALUEi.h.s.u.TokenHandler Token handler to extract username from request
authenticateVALUEBooleantrueWhether to authenticate requests
optionalVALUEBooleanfalseWhether authentication is required
outboundLISTi.h.s.p.c.OutboundTarget Configure outbound target for identity propagation
outbound-tokenVALUEi.h.s.u.TokenHandler Token handler to create outbound headers to propagate identity
principal-typeVALUEi.h.s.SubjectTypeUSERPrincipal type this provider extracts (and also propagates)
propagateVALUEBooleanfalseWhether to propagate identity

Example code

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"
Copied

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.

Setup

Maven dependency
<dependency>
    <groupId>io.helidon.security.providers</groupId>
    <artifactId>helidon-security-providers-http-sign</artifactId>
</dependency>
Copied

Overview

Configuration options

KeyKindTypeDefault ValueDescription
backward-compatible-eolVALUEBooleanfalseEnable support for Helidon versions before 3.0.0 (exclusive)
headersLISTi.h.s.p.h.HttpSignHeader Add a header that is validated on inbound requests
inbound.keysLISTi.h.s.p.h.InboundClientDefinition Add inbound configuration
optionalVALUEBooleantrueSet whether the signature is optional
outboundVALUEi.h.s.p.c.OutboundConfig Add outbound targets to this builder
realmVALUEStringhelidonRealm to use for challenging inbound requests that do not have "Authorization" header in case header is HttpSignHeader#AUTHORIZATION and singatures are not optional
sign-headersLISTi.h.s.p.h.S.HeadersConfig Override the default inbound required headers (e.g

Example code

See the example on GitHub.

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"
Copied

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.

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

IDCS Role Mapper

A role mapper to retrieve roles from Oracle IDCS.

Setup

Maven dependency
<dependency>
    <groupId>io.helidon.security.providers</groupId>
    <artifactId>helidon-security-providers-idcs-mapper</artifactId>
</dependency>
Copied

Single-tenant IDCS Role Mapper

Configuration options

KeyKindTypeDefault ValueDescription
cache-configVALUEi.h.s.p.c.EvictableCache Use explicit io.helidon.security.providers.common.EvictableCache for role caching
default-idcs-subject-typeVALUEStringuserConfigure subject type to use when requesting roles from IDCS
oidc-configVALUEi.h.s.p.o.c.OidcConfig Use explicit io.helidon.security.providers.oidc.common.OidcConfig instance, e.g
subject-typesLISTi.h.s.SubjectTypeUSERAdd a supported subject type

Multi-tenant IDCS Role Mapper

Configuration options

KeyKindTypeDefault ValueDescription
cache-configVALUEi.h.s.p.c.EvictableCache Use explicit io.helidon.security.providers.common.EvictableCache for role caching
default-idcs-subject-typeVALUEStringuserConfigure subject type to use when requesting roles from IDCS
idcs-app-name-handlerVALUEi.h.s.u.TokenHandler Configure token handler for IDCS Application name
idcs-tenant-handlerVALUEi.h.s.u.TokenHandler Configure token handler for IDCS Tenant ID
oidc-configVALUEi.h.s.p.o.c.OidcConfig Use explicit io.helidon.security.providers.oidc.common.OidcConfig instance, e.g
subject-typesLISTi.h.s.SubjectTypeUSERAdd a supported subject type

Example code

See the example on GitHub.

Configuration example
security:
  providers:
    - idcs-role-mapper:
        multitenant: false
        oidc-config:
            client-id: "client-id"
            client-secret: "changeit"
            identity-uri: "IDCS identity server address"
Copied

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.

Setup

Maven dependency
<dependency>
    <groupId>io.helidon.security.providers</groupId>
    <artifactId>helidon-security-providers-abac</artifactId>
</dependency>
Copied

Overview

Configuration options

KeyKindTypeDefault ValueDescription
fail-if-none-validatedVALUEBooleantrueWhether to fail if NONE of the attributes is validated
fail-on-unvalidatedVALUEBooleantrueWhether to fail if any attribute is left unvalidated

Example code

See the example on GitHub.

Configuration example
security:
  providers:
    - abac:
Copied

Configuration options

The following table shows all configuration options of the provider and their default values

keydefault valuedescription
fail-on-unvalidatedtrue"Unvalidated" means: an attribute is defined, but there is no validator available for it
fail-if-none-validatedtrue"None validated" means: there was not a single attribute that was validated

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:

  1. true & true: Will fail if any attribute is not validated and if any has failed validation
  2. false & 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)
  3. 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();
        }
    }
}
Copied

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"]
Copied
JAX-RS example
@RolesAllowed("user")
@RoleValidator.Roles(value = "service_role", subjectType = SubjectType.SERVICE)
@Authenticated
@Path("/abac")
public class AbacResource {
}
Copied
Interaction with 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"]
Copied
JAX-RS example
@Scope("calendar_read")
@Scope("calendar_edit")
@Authenticated
@Path("/abac")
public class AbacResource {
}
Copied

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')"
Copied
JAX-RS example
@PolicyStatement("${env.time.year >= 2017}")
@Authenticated
@Path("/abac")
public class AbacResource {
}
Copied
Configuration example for JAX-RS over the configuration
server:
  features:
    security:
      endpoints:
        - path: "/somePath"
          config:
            abac.policy-validator.statement: "\\${env.time.year >= 2017}"
Copied

Google Login Provider

Authenticates a token from request against Google identity provider

This provider is deprecated and will be removed in a future version of Helidon. Please use our OpenID Connect security provider instead.

Setup

Maven dependency
<dependency>
    <groupId>io.helidon.security.providers</groupId>
    <artifactId>helidon-security-providers-google-login</artifactId>
</dependency>
Copied

Overview

Configuration options

KeyKindTypeDefault ValueDescription
client-idVALUEString Google application client id, to validate that the token was generated by Google for us
optionalVALUEBooleanfalseIf set to true, this provider will return io.helidon.security.SecurityResponse.SecurityStatus#ABSTAIN instead of failing in case of invalid request
outboundVALUEi.h.s.p.c.OutboundConfig Outbound configuration - a set of outbound targets that will have the token propagated
proxy-hostVALUEString Set proxy host when talking to Google
proxy-portVALUEInteger80Set proxy port when talking to Google
realmVALUEStringhelidonSet the authentication realm to build challenge, defaults to "helidon"
tokenVALUEi.h.s.u.TokenHandler`Authorization` header with `bearer` prefixToken provider to extract Google access token from request, defaults to "Authorization" header with a "bearer " prefix

Example code

See the example on GitHub.

Configuration example
security:
  providers:
    - provider:
        client-id: "Google client id"
Copied

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:

  1. Validate if it timed out locally
  2. Return a cached response (see EvictableCache with default values)
  3. Otherwise verify using Google API - GoogleIdTokenVerifier

We build a subject from the Google token with the following attributes filled (if in token):

  • userId

  • email

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

Setup

Maven dependency
<dependency>
    <groupId>io.helidon.security.providers</groupId>
    <artifactId>helidon-security-providers-jwt</artifactId>
</dependency>
Copied

Overview

Configuration options

KeyKindTypeDefault ValueDescription
allow-impersonationVALUEBooleanfalseWhether to allow impersonation by explicitly overriding username from outbound requests using io.helidon.security.EndpointConfig#PROPERTY_OUTBOUND_ID property
allow-unsignedVALUEBooleanfalseConfigure support for unsigned JWT
atn-token.handlerVALUEi.h.s.u.TokenHandler Token handler to extract username from request
atn-token.jwk.resourceVALUEi.h.c.c.Resource JWK resource used to verify JWTs created by other parties
atn-token.jwt-audienceVALUEString Audience expected in inbound JWTs
atn-token.jwt-issuerVALUEString Issuer expected in inbound JWTs
atn-token.verify-signatureVALUEBooleantrueConfigure whether to verify signatures
authenticateVALUEBooleantrueWhether to authenticate requests
optionalVALUEBooleanfalseWhether authentication is required
principal-typeVALUEi.h.s.SubjectTypeUSERPrincipal type this provider extracts (and also propagates)
propagateVALUEBooleantrueWhether to propagate identity
sign-tokenVALUEi.h.s.p.c.OutboundConfig Configuration of outbound rules
sign-token.jwk.resourceVALUEi.h.c.c.Resource JWK resource used to sign JWTs created by us
sign-token.jwt-issuerVALUEString Issuer used to create new JWTs
use-jwt-groupsVALUEBooleantrueClaim groups from JWT will be used to automatically add groups to current subject (may be used with jakarta.annotation.security.RolesAllowed annotation)

Example code

See the example on GitHub.

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"
Copied

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.