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 LoginAuthenticationAuthenticates 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.security.providers</groupId>
    <artifactId>helidon-security-providers-oidc</artifactId>
</dependency>
Copied

In Helidon SE, we need to register the redirection support with routing (in addition to WebSecurity that integrates with WebServer). This is not required when redirect is set to false.

Adding support for OIDC redirects
Routing routing = Routing.builder()
        .register(WebSecurity.create(config.get("security")))
        .register(OidcSupport.create(config))
        ...
        .build();
Copied
Provider class name
io.helidon.security.providers.oidc.OidcProvider
Copied
Provider configuration key
oidc
Copied

Example code

https://github.com/oracle/helidon/tree/master/examples/security/idcs-login

Configuration example
security:
  config.require-encryption: false
security:
  providers:
  - oidc:
      client-id: "client-id-of-this-service"
      client-secret: "${CLEAR=client-secret-of-this-service}"
      identity-uri: "http://your-tenant.identity-server.com"
      frontend-uri: "http://my-service:8080"
      audience: "http://my-service"
      cors:
        allow-origins: ["http://foo.com", "http://there.com"]
        allow-methods: ["PUT", "DELETE"]
      outbound:
        - name: "internal-services"
          hosts: ["*.example.org"]
          outbound-token:
            header: "X-Internal-Auth"
Copied

Configuration options

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

keydefault valuedescription
optionalfalseIf set to true, failure to authenticate will return ABSTAIN result instead of FAILURE. This is an important distinction when more than one provider is used
client-id Client ID as generated by identity server
client-secret Client secret as generated by identity server
identity-uri URI of the identity server, base used to retrieve OIDC metadata
frontend-uri Full URI of this service for redirects back from OIDC server
issuerissuer from OIDC metadataIssuer of token - each JWT is validated to check the issuer
audience Audience of a token - each JWT is validated to check the audience
cors Cross-origin resource sharing settings (see below)
proxy-protocolhttpProxy protocol to use when proxy is used
proxy-hostnullProxy host to use. When defined, triggers usage of proxy for HTTP requests
proxy-port80Port of the proxy server to use
relative-urisfalseCan 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. By default, requests that use the Proxy will have absolute URIs. Set this flag to true if the receiving host is unable to accept absolute URIs.
redirect-uri/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. Note that usually the redirect URI configured here must be the same one as configured on OIDC server.
scope-audienceempty stringAudience of the scope required by this application. This is prefixed to the scope name when requesting scopes from the identity server.
cookie-usetrueWhether to use cookie to store JWT. If used, redirects happen only in case the user is not authenticated or has insufficient scopes
cookie-nameJSESSIONIDName of the cookie
cookie-domain Domain the cookie is valid for. Not used by default
cookie-path/Path the cookie is valid for.
cookie-max-age-seconds{nsbp}When using cookie, used to set MaxAge attribute of the cookie, defining how long the cookie is valid.
cookie-http-onlytrueWhen using cookie, if set to true, the HttpOnly attribute will be configured.
cookie-securefalseWhen using cookie, if set to true, the Secure attribute will be configured.
cookie-same-siteLaxWhen using cookie, used to set the SameSite cookie value. Can be "Strict" or "Lax". Setting this to "Strict" will result in infinite redirects when calling OIDC on a different host.
query-param-usefalseWhether to expect JWT in a query parameter
query-param-nameaccessTokenName of a query parameter that contains the JWT token when parameter is used.
header-usefalseWhether to expect JWT in a header field.
header-tokenAuthorization header with prefix bearerA TokenHandler configuration to process header containing a JWT
oidc-metadata-well-knowntrueIf set to true, metadata will be loaded from default (well known) location, unless it is explicitly defined using oidc-metadata-resource. If set to false, it would not be loaded even if oidc-metadata-resource is not defined. In such a case all URIs must be explicitly defined (e.g. token-endpoint-uri).
oidc-metadata.resourceidentity-uri/.well-known/openid-configurationResource configuration for OIDC Metadata containing endpoints to various identity services, as well as information about the identity server. See Resource.create(io.helidon.config.Config)
token-endpoint-uritoken_endpoint in OIDC metadata, or identity-url/oauth2/v1/token if not availableURI of a token endpoint used to obtain a JWT based on the authentication code.
authorization-endpoint-uri"authorization_endpoint" in OIDC metadata, or identity-uri/oauth2/v1/authorize if not availableURI of an authorization endpoint used to redirect users to for logging-in.
validate-with-jwktrueWhen true - validate against jwk defined by "sign-jwk", when false validate JWT through OIDC Server endpoint "validation-endpoint-uri"
sign-jwk.resource"jwks-uri" in OIDC metadata, or identity-uri/admin/v1/SigningCert/jwk if not available, only needed when jwt validation is done by usA resource pointing to JWK with public keys of signing certificates used to validate JWT. See Resource.create(io.helidon.config.Config)
introspect-endpoint-uri"introspection_endpoint" in OIDC metadata, or identity-uri/oauth2/v1/introspectWhen validate-with-jwk is set to "false", this is the endpoint used
base-scopesopenidConfigure scopes to be requested by default. If the scope has a qualifier, it must be included here
redirecttrueWhether to redirect to identity server when authentication failed.
realmhelidonRealm returned in HTTP response if redirect is not enabled or possible.
redirect-attempt-paramh_raQuery parameter holding the number of times we redirected to an identity server. Customizable to prevent conflicts with application parameters
max-redirects5Maximal number of times we can redirect to an identity server. When the number is reached, no further redirects happen and the request finishes with an error (status 401)
server-type Type of identity server. Currently supported is idcs or not configured (for default).
propagate Whether to propagate the token we have. Defaults to false unless an outbound configuration is defined
outbound A list of outbound configurations
outbound.*.name Required name of outbound configuration
outbound.*.transportsany transportAn array of transports this outbound configuration should be used for
outbound.*.hostsany hostAn array of hosts this outbound configuration should be used for, can be a regular expression
outbound.*.pathsany pathAn array of paths this outbound configuration should be used for (such as /greet), can be a regular expression
outbound.*.methodsany methodAn array of HTTP methods this outbound configuration should be used for
outbound.*.outbound-tokenAuthorization header with bearer prefixConfiguration of outbound header used to propagate
outbound.*.outbound-token.header Name of the header used to propagate the token
outbound.*.outbound-token.prefix Prefix for the header value, such as "bearer" (only one of prefix, regexp and format should be defined, regexp wins over prefix, format wins over regexp)
outbound.*.outbound-token.format String format with a single parameter to create the header value, such as "bearer %1s"
outbound.*.outbound-token.regexp Regular expression to create the header value, such as "bearer (.*)"

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
CORS Settings

As an experimental feature, you can set up cross-origin handling for the redirect and logout endpoints in an optional cors block inside the oidc configuration.

The table below lists the configuration keys that identify the CORS characteristics.

Configuration KeyDefaultCORS Header Name
allow-credentialsfalseAccess-Control-Allow-Credentials
allow-headers["*"]Access-Control-Allow-Headers
allow-methods["*"]Access-Control-Allow-Methods
allow-origins["*"]Access-Control-Allow-Origins
expose-headersnoneAccess-Control-Expose-Headers
max-age3600Access-Control-Max-Age
enabledtruen/a

If the cross-origin configuration is disabled (enabled = false), then the Helidon CORS implementation ignores the cross-origin configuration entry.

The following example of basic cross-origin configuration limits cross-origin resource sharing for PUT and DELETE operations to only foo.com and there.com:

...
  allow-origins: ["http://foo.com", "http://there.com"]
  allow-methods: ["PUT", "DELETE"]
...
Copied

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
Provider class name
io.helidon.security.providers.httpauth.HttpBasicAuthProvider
Copied
Provider configuration key
http-basic-auth
Copied

Example code

https://github.com/oracle/helidon/tree/master/examples/security/outbound-override

Configuration example
security:
  config.require-encryption: false
security:
  providers:
  - http-basic-auth:
      realm: "helidon"
      users:
      - login: "john"
        password: "${CLEAR=password}"
        roles: ["admin"]
      - login: "jack"
        password: "password"
        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=password}"
Copied

Configuration options

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

keydefault valuedescription
optionalfalseIf set to true, failure to authenticate will return ABSTAIN result instead of FAILURE. This is an important distinction when more than one provider is used
realmhelidonThe realm shown in challenge when user accesses a service without authentication
principal-typeUSERType of authenticated entity - either USER or SERVICE, can be used in combination with other authentication mechanism to authenticate both the user (as in person sitting in front of a computer) and a service (as in the application requesting this service on user’s behalf)
users List of users when using configuration based approach. As an alternative, you can implement a java service (see below).
outbound A list of outbound configurations
outbound.*.name Required name of outbound configuration
outbound.*.username Optional username used for outbound security; if not provided, current identity is propagated
outbound.*.password Optional password used for outbound security
outbound.*.transportsany transportAn array of transports this outbound configuration should be used for
outbound.*.hostsany hostAn array of hosts this outbound configuration should be used for, can be a regular expression
outbound.*.pathsany pathAn array of paths this outbound configuration should be used for (such as /greet), can be a regular expression
outbound.*.methodsany methodAn array of HTTP methods this outbound configuration should be used for
outbound.*.outbound-tokenAuthorization header with basic prefixConfiguration of outbound header used to propagate
outbound.*.outbound-token.header Name of the header used to propagate the token
outbound.*.outbound-token.prefix Prefix for the header value, such as "basic " (only one of prefix, regexp and format should be defined, regexp wins over prefix, format wins over regexp)
outbound.*.outbound-token.format String format with a single parameter to create the header value, such as "basic %1s"
outbound.*.outbound-token.regexp Regular expression to create the header value, such as "basic (.*)"

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 HttpBasicAuthProvider.EP_PROPERTY_OUTBOUND_USER and HttpBasicAuthProvider.EP_PROPERTY_OUTBOUND_PASSWORD)
  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 Authenticaton (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
Provider class name
io.helidon.security.providers.httpauth.HttpDigestAuthProvider
Copied
Provider configuration key
http-digest-auth
Copied

Example code

Configuration example
security:
  config.require-encryption: false
security:
  providers:
  - http-digest-auth:
      realm: "helidon"
      server-secret: "${CLEAR=service-wide-secret-not-known-outside}"
      users:
      - login: "john"
        password: "${CLEAR=password}"
        roles: ["admin"]
      - login: "jack"
        password: "password"
        roles: ["user", "admin"]
Copied

Configuration options

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

keydefault valuedescription
optionalfalseIf set to true, failure to authenticate will return ABSTAIN result instead of FAILURE. This is an important distinction when more than one provider is used
realmhelidonThe realm shown in challenge when user accesses a service without authentication
principal-typeUSERType of authenticated entity - either USER or SERVICE, can be used in combination with other authentication mechanism to authenticate both the user (as in person sitting in front of a computer) and a service (as in the application requesting this service on user’s behalf)
users List of users when using configuration based approach. As an alternative, you can implement a java service (see below).
algorithmMD5Only MD5 supported
nonce-timeout-millis1 dayNumber of milliseconds for the nonce timeout
server-secretrandomA string to use as a server secret - this is to use digest auth between multiple servers (e.g. when in a cluster). Used to encrypt nonce. This must not be known outside of this app, as others may create digest requests we would trust.
qopNONEonly AUTH supported. If left empty, uses the legacy approach (older RFC version). AUTH-INT is not supported.

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 Authenticaton

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
Provider class name
io.helidon.security.providers.header.HeaderAtnProvider
Copied
Provider configuration key
header-atn
Copied

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

Configuration options

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

keydefault valuedescription
optionalfalseIf set to true, failure to authenticate will return ABSTAIN result instead of FAILURE. This is an important distinction when more than one provider is used
authenticatetrueIf set to false, authentication will not be attempted (outbound security can still be used)
propagatefalseIf explicitly set to false, identity propagation will not be done. Otherwise it is done if an outbound section is configured
principal-typeUSERCan be USER or SERVICE
atn-tokennoneToken extraction and propagation, you can define which header to use and how to extract it
outbound A list of outbound configurations
outbound.*.name Required name of outbound configuration
outbound.*.username Optional username used for outbound security; if not provided, current identity is propagated
outbound.*.transportsany transportAn array of transports this outbound configuration should be used for
outbound.*.hostsany hostAn array of hosts this outbound configuration should be used for, can be a regular expression
outbound.*.pathsany pathAn array of paths this outbound configuration should be used for (such as /greet), can be a regular expression
outbound.*.methodsany methodAn array of HTTP methods this outbound configuration should be used for
outbound.*.outbound-tokensame as atn-tokenConfiguration of outbound header used to propagate
outbound.*.outbound-token.header Name of the header used to propagate the token
outbound.*.outbound-token.prefix Prefix for the header value, such as "username " (only one of prefix, regexp and format should be defined, regexp wins over prefix, format wins over regexp)
outbound.*.outbound-token.format String format with a single parameter to create the header value, such as "username %1s"
outbound.*.outbound-token.regexp Regular expression to create the header value, such as "username (.*)"

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
Provider class name
io.helidon.security.providers.httpsign.HttpSignProvider
Copied
Provider configuration key
http-signatures
Copied

Example code

https://github.com/oracle/helidon/tree/master/examples/security/webserver-signatures

Configuration example
security:
  config.require-encryption: false
security:
  providers:
    - http-signatures:
        inbound:
          keys:
            - key-id: "service1-hmac"
              principal-name: "Service1 - HMAC signature"
              hmac.secret: "${CLEAR=somePasswordForHmacShouldBeEncrypted}"
            - key-id: "service1-rsa"
              principal-name: "Service1 - RSA signature"
              public-key:
                keystore:
                  resource.path: "src/main/resources/keystore.p12"
                  passphrase: "password"
                  cert.alias: "service_cert"
        outbound:
          - name: "service2-hmac"
            hosts: ["localhost"]
            paths: ["/service2"]
            signature:
              key-id: "service1-hmac"
              hmac.secret: "${CLEAR=somePasswordForHmacShouldBeEncrypted}"
          - name: "service2-rsa"
            hosts: ["localhost"]
            paths: ["/service2-rsa.*"]
            signature:
              key-id: "service1-rsa"
              private-key:
                keystore:
                  resource.path: "src/main/resources/keystore.p12"
                  passphrase: "password"
                  key.alias: "myPrivateKey"
Copied

Configuration options

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

keydefault valuedescription
optionalfalseIf set to true, failure to authenticate will return ABSTAIN result instead of FAILURE. This is an important distinction when more than one provider is used
realmhelidonRealm used for challenge when request does not have a signature
headers[SIGNATURE,AUTHORIZATION,CUSTOM]Headers to look for inbound signatures and to store outbound signatures. CUSTOM is provided using io.helidon.security.util.TokenHandler
sign-headersalways = ["date"]Headers to be signed
sign-headers.*.methoddefault for all methodsMethod this configuration is valid for
sign-headers.*.always Array of headers to be always required in the request signature
sign-headers.*.if-present Array of headers to be part of the signatures if present in the request
inbound Configuration of inbound traffic for authenticating incoming requests
inbound.keys Configuration of signature keys to verify incoming requests
inbound.keys.*.key-id Key id as used in inbound signature to find the correct certificate/hmac configuration to verify the signature
inbound.keys.*.principal-name The principal name (or user name) asserted when the signature is valid
inbound.keys.*.principal-typeSERVICEThe type of principal to assert (can be USER)
inbound.keys.*.algorithmaccording to other configurationhmac-sha256 or rsa-sha256 is assumed if other configuration options for that type are set
inbound.keys.*.hmac.secret Secret shared by the service that signed the request and this service for hmac-sha256 algorithm
inbound.keys.*.public-key Public key configuration, implies rsa-sha256 algorithm
inbound.keys.*.public-key.keystore Keystore configuration for public key - full configuration as defined by KeyStore class
outbound A list of outbound configurations
outbound.*.name Required name of outbound configuration
outbound.*.username Optional username used for outbound security; if not provided, current identity is propagated
outbound.*.password Optional password used for outbound security
outbound.*.transportsany transportAn array of transports this outbound configuration should be used for
outbound.*.hostsany hostAn array of hosts this outbound configuration should be used for, can be a regular expression
outbound.*.pathsany pathAn array of paths this outbound configuration should be used for (such as /greet), can be a regular expression
outbound.*.methodsany methodAn array of HTTP methods this outbound configuration should be used for
outbound.*.signature Configuration related to outbound signature configuration
outbound.*.signature.key-id Key id to use in the outbound signature (to map to appropriate public key in target service’s configuration)
outbound.*.signature.header[SIGNATURE,AUTHORIZATION,CUSTOM]Headers supported by HTTP Signature. CUSTOM is provided using io.helidon.security.util.TokenHandler
outbound.*.signature.hmac.secret Shared secret for hmac
outbound.*.signature.private-key Private key configuration for rsa based signatures
outbound.*.signature.private-key.keystore Keystore configuration for private key - full configuration as defined by KeyStore class

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
Provider class name
io.helidon.security.providers.idcs.mapper.IdcsRoleMapperProvider
Copied
Provider configuration key
idcs-role-mapper
Copied

Example code

https://github.com/oracle/helidon/tree/master/examples/security/idcs-login/

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

Configuration options

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

keydefault valuedescription
multitenanttrueWhether to support multi-tenancy with this provider
idcs-tenant-handlerHeader X-USER-IDENTITY-SERVICE-GUIDMulti-tenant specific TokenHandler configuration to retrieve the tenant id
idcs-app-name-handlerHeader X-RESOURCE-SERVICE-INSTANCE-IDENTITY-APPNAMEMulti-tenant specific TokenHandler configuration to retrieve the application name
cache-config Configuration of cache of roles for subjects
cache-config.cache-enabledtruePossibility to disable the cache altogether
cache-config.max-size100_000Maximal number of records in the cache
cache-config.cache-timeout-millis1 hourCache timeout in milliseconds
cache-config.cache-evict-delay-millis1 minuteHow long to wait before starting the first eviction process
cache-config.cache-evict-period-millis5 minutesPeriod of running the eviction process
cache-config.parallelism-threshold10_000Threshold as used by ConcurrentHashMap.forEachKey
cache-config.evictor-class Implementation of BiFunction that receives key and value, and returns true for records that should be removed from the cache. Eviction mechanism should be fast, as it is called within methods of ConcurrentHashMap
subject-typesUSERCan use USER and/or SERVICE
default-idcs-subject-typeuserDefault subject type to use when requesting roles, can be user or client
oidc-config OidcConfig configuration, except validate-with-jwk is set to false, and server-type is set to idcs

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
Provider class name
io.helidon.security.providers.abac.AbacProvider
Copied
Provider configuration key
abac
Copied

Example code

https://github.com/oracle/helidon/tree/master/examples/security/attribute-based-access-control

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.getDescription().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

Google Login Provider

Authenticates a token from request against Google identity provider

Setup

Maven dependency
<dependency>
    <groupId>io.helidon.security.providers</groupId>
    <artifactId>helidon-security-providers-google-login</artifactId>
</dependency>
Copied
Provider class name
io.helidon.security.providers.google.login.GoogleTokenProvider
Copied
Provider configuration key
google-login
Copied

Example code

https://github.com/oracle/helidon/tree/master/examples/security/google-login

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

Configuration options

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

keydefault valuedescription
client-id Client id of an application. To create an application, use the Google developer console (https://developers.google.com/identity/sign-in/web/sign-in)
optionalfalseIf set to true, failure to authenticate will return ABSTAIN result instead of FAILURE. This is an important distinction when more than one provider is used
realmhelidonRealm used in the challenge when authentication is not provided and it is required
proxy-hostnoneConfiguration of a proxy host to use when authenticating the user
proxy-port80Proxy port
tokenAuthorization header with bearer prefixConfiguration of the location of the token (see TokenHandler)
outbound A list of outbound configurations
outbound.*.name Required name of outbound configuration
outbound.*.username Optional username used for outbound security; if not provided, current identity is propagated
outbound.*.password Optional password used for outbound security
outbound.*.transportsany transportAn array of transports this outbound configuration should be used for
outbound.*.hostsany hostAn array of hosts this outbound configuration should be used for, can be a regular expression
outbound.*.pathsany pathAn array of paths this outbound configuration should be used for (such as /greet), can be a regular expression
outbound.*.methodsany methodAn array of HTTP methods this outbound configuration should be used for

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
Provider class name
io.helidon.security.providers.jwt.JwtProvider
Copied
Provider configuration key
jwt
Copied

Example code

https://github.com/oracle/helidon/tree/master/examples/security/outbound-override

Configuration example
security:
  providers:
    - provider:
        atn-token:
          jwk.resource.resource-path: "verifying-jwk.json"
          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

Configuration options

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

keydefault valuedescription
optionalfalseIf set to true, failure to authenticate will return ABSTAIN result instead of FAILURE. This is an important distinction when more than one provider is used
authenticatetrueWhether to attempt authentication
propagatetrueWhether to attempt identity propagation/JWT creation
principal-typeUSERWhether we authenticate a user or a service (other option is SERVICE)
atn-tokenA group for configuring authentication of the request
atn-token.verify-signaturetrueWhether to verify signature in incoming JWT. If disabled, ANY JWT will be accepted
atn-token.jwt-audience Expected audience of the JWT. If not defined, any audience is accepted (and we may accept JWT not inteded for us)
atn-token.jwk.resource.* Configuration of the JWK to obtain key(s) to validate signatures of inbound token. The JWK should contain public keys. This may be: jwk.resource.path, jwk.resource.resource-path, jwk.resource.url, jwk.resource.content-plain (actual JSON string), jwk.resource.content (base64)
atn-token.handlerAuthorization header with `bearer ` prefixA handler configuration for inbound token - e.g. how to extract it
atn-token.handler.header Name of a header the token is expected in
atn-token.handler.prefix Prefix before the token value (optional)
atn-token.handler.regexp Regular expression to obtain the token, first matching group is used (optional)
sign-token A group for configuring outbound security
sign-token.jwk.resource.* Configuration of the JWK to use when generating tokens (follows same rules as atn-token.jwk above), this JWK must contain private keys when using asymmetric ciphers
sign-token.jwt-issuer When we issue a new token, this is the issuer to be placed into it (validated by target service)
sign-token.outbound A group for configuring outbound rules (based on transport, host and.or path)
sign-token.outbound.*.name A short descriptive name for configured target service(s)
sign-token.outbound.*.transportsanyAn array of transports this outbound matches (e.g. https)
sign-token.outbound.*.hostsanyAn array of hosts this outbound matches, may use * as a wild-card (e.g. *.oracle.com)
sign-token.outbound.*.pathsanyAn array of paths on the host this outbound matches, may use * as a wild-card (e.g. /some/path/*)
sign-token.outbound.*.outbound-tokenAuthorization header with `bearer ` prefixConfiguration of outbound token handler (same as atn-token.handler)
sign-token.outbound.*.outbound-token.format Java text format for generating the value of outbound token header (e.g. "bearer %1$s")
sign-token.outbound.*.jwk-kid If this key is defined, we are generating a new token, otherwise we propagate existing. Defines the key id of a key definition in the JWK file to use for signing the outbound token
sign-token.outbound.*.jwt-kid A key to use in the generated JWT - this is for the other service to locate the verification key in their JWK
sign-token.outbound.*.jwt-audience Audience this key is generated for (e.g. http://www.example.org/api/myService) - validated by the other service
sign-token.outbound.*.jwt-not-before-seconds5Makes this key valid this amount of seconds into the past. Allows a certain time-skew for the generated token to be valid before current time (e.g. when we expect a certain misalignment of clocks)
sign-token.outbound.*.jwt-validity-seconds1 dayToken validity in seconds

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.