1. About

The WildFly Elytron project is a new security framework brought to WildFly to provide a single unified security framework across the whole of the application server. As a single framework it will be usable both for configuring management access to the server and for applications deployed to the server, it will also be usable across all process types so there will be no need to learn a different security framework for host controllers in a domain compared to configuring a standalone server.

The project covers these main areas: -

  • Authentication

  • Authorization

  • SSL / TLS

  • Secure Credential Storage

1.1. Authentication

One of the fundamental objectives of the project was to ensure that we can use stronger authentication mechanisms for both HTTP and SASL based authentication, in both cases the new framework also makes it possible to bring in new implementations opening up various integration opportunities with external solutions.

1.2. Authorization

The architecture of the project makes a very clear distinction between the raw representation of the identity as returned by a SecurityRealm from the repository of identities and the final representation as a SecurityIdentity after roles have been decoded and mapped and permissions have been mapped.

Custom implementations of the components to perform role decoding and mapping, and permission mapping can be provided allowing for further flexibility beyond the default set of components provided by the project.

1.3. SSL / TLS

The project becomes the centralised point within the application server for configuring SSL related resources meaning they can be configured in a central location and referenced by resources across the application server. The centralised configuration also covers advanced options such as configuration of enabled cipher suites and protocols without this information needing to be distributed across the management model.

The SSL / TLS implementation also includes an optimisation where it can be closely tied to authentication allowing for permissions checks to be performed on establishment of a connection before the first request is received and the eager construction of a SecurityIdentity eliminating the need for it to be constructed on a per-request basis.

1.4. Secure Credential Storage

The previous vault used for plain text String encryption is replaced with a newly designed credential store. in addition to the protection it offers for the credentials stored within it, the store currently supports storage of clear text credentials.

2. General Elytron Architecture

The overall architecture for WildFly Elytron is building up a full security policy from assembling smaller components together, by default we include various implementations of the components - in addition to this, custom implementations of many components can be provided in order to provide more specialised implementations.

Within WildFly the different Elytron components are handled as capabilities meaning that different implementations can be mixed and matched, however the different implementations are modelled using distinct resources. This section contains a number of diagrams to show the general relationships between different components to provide a high level view, however the different resource definitions may use different dependencies depending on their purpose.

2.1. Security Domains

Within WildFly Elytron a SecurityDomain can be considered as a security policy backed by one or more SecurityRealm instances. Resources that make authorization decisions will be associated with a SecurityDomain, from the SecurityDomain a SecurityIdentity can be obtained which is a representation of the current identity, from this the identities roles and permissions can be checked to make the authorization decision for the resource.

The SecurityDomain is the general wrapper around the policy describing a resulting SecurityIdentity and makes use of the following components to define this policy.

  • NameRewriter

NameRewriters are used in multiple places within the Elytron configuration, as their name implies, their purpose is to take a name and map it to another representation of the name or perform some normalisation or clean up of the name.

  • RealmMapper

As a SecurityDomain is able to reference multiple SecurityRealms the RealmMapper is responsible for identifying which SecurityRealm to use based on the supplied name for authentication.

  • SecurityRealm

One more more named SecurityRealms are associated with a SecurityDomain, the SecurityRealms are the access to the underlying repository of identities and are used for obtaining credentials to allow authentication mechanisms to perform verification, for validation of Evidence and for obtaining the raw AuthorizationIdentity performing the authentication.

Some SecurityRealm implementations are also modifiable so expose an API that allows for updates to be made to the repository containing the identities.

  • RoleDecoder

Along with the SecurityRealm association is also a reference to a RoleDecoder, the RoleDecoder takes the raw AuthorizationIdentity returned from the SecurityRealm and converts it’s attributes into roles.

  • RoleMapper

After the roles have been decoded for an identity further mapping can be applied, this could be as simple at normalising the format of the names through to adding or removing specific role names. If a RoleMapper is referenced by the SecurityRealm association that RoleMapper is applied first before applying the RoleMapper associated with the SecurityDomain.

  • PrincipalDecoder

A PrincipalDecoder converts from a Principal to a String representation of a name, one example for this is we have an X500PrincipalDecoder which is able to extract an attribute from a distinguished name.

  • PermissionMapper

In addition to having roles a SecurityIdentity can also have a set of permissions, the PermissionMapper assigns those permissions to the identity.

Different secured resources can be associated with different SecurityDomains for their authorization decisions, within WildFly Elytron we have the ability to configure inflow between different SecurityDomains. The inflow process means that a SecurityIdentity inflowed into a second SecurityDomain has the mappings of the new SecurityDomain applied to it so although a common identity may be calling different resources each of those resources could have a very different view.

2.2. SASL Authentication

The SaslAuthenticationFactory is an authentication policy for authentication using SASL authentication mechanisms, in addition to being a policy it is also a factory for configured authentication mechanisms backed by a SecurityDomain.

The SaslAuthenticationFactory references the following: -

  • SecurityDomain

This is the security domain that any mechanism authentication will be performed against.

  • SaslServerFactory

This is the general factory for server side SASL authentication mechanisms.

  • MechanismConfigurationSelector

Additional configuration can be supplied for the authentication mechanisms, the configuration will be described in more detail later but the purpose of the MechanismConfigurationSelector is to obtain configuration specific to the mechanism selected. This can include information about realm names a mechanism should present to a remote client plus additional NameRewriters and RealmMappers to use during the authentication process.

The reason some of the components referenced by the SecurityDomain are duplicated is so that mechanism specific mappings can be applied.

2.3. HTTP Authentication

The HttpAuthenticationFactory is an authentication policy for authentication using HTTP authentication mechanisms, in addition to being a policy it is also a factory for configured authentication mechanisms backed by a SecurityDomain.

The HttpAuthenticationFactory references the following: -

  • SecurityDomain

This is the security domain that any mechanism authentication will be performed against.

  • HttpServerAuthenticationMechanismFactory

This is the general factory for server side HTTP authentication mechanisms.

  • MechanismConfigurationSelector

Additional configuration can be supplied for the authentication mechanisms, the configuration will be described in more detail later but the purpose of the MechanismConfigurationSelector is to obtain configuration specific to the mechanism selected. This can include information about realm names a mechanism should present to a remote client plus additional NameRewriters and RealmMappers to use during the authentication process.

The reason some of the components referenced by the SecurityDomain are duplicated is so that mechanism specific mappings can be applied.

2.4. SSL / TLS

The SSLContext defined within Elytron is a javax.net.ssl.SSLContext meaning it can be used by anything that uses an SSLContext directly.

In addition to the usual configuration for an SSLContext it is possible to configure additional items such as cipher suites and protocols and the SSLContext returned will wrap any engines created to set these values.

The SSLContext within Elytron can also reference the following: -

  • KeyManagers

An array of KeyManager instances to be used by the SSLContext, this in turn can reference a KeyStore to load the keys.

  • TrustManagers

An array of TrustManager instances to be used by the SSLContext, this in turn can also reference a KeyStore to load the certificates.

  • SecurityDomain

This is optional, however if an SSLContext is configured to reference a SecurityDomain then verification of a clients certificate can be performed as an authentication ensuring the appropriate permissions to Logon are assigned before even allowing the connection to be fully opened, additionally the SecurityIdentity can be established at the time the connection is opened and used for any invocations over the connection.

3. Elytron Subsystem

WildFly Elytron is a security framework used to unify security across the entire application server. The elytron subsystem enables a single point of configuration for securing both applications and the management interfaces. WildFly Elytron also provides a set of APIs and SPIs for providing custom implementations of functionality and integrating with the elytron subsystem.

In addition, there are several other important features of the WildFly Elytron:

  • Stronger authentication mechanisms for HTTP and SASL authentication.

  • Improved architecture that allows for SecurityIdentities to be propagated across security domains and transparently transformed ready to be used for authorization. This transformation takes place using configurable role decoders, role mappers, and permission mappers.

  • Centralized point for SSL/TLS configuration including cipher suites and protocols.

  • SSL/TLS optimizations such as eager SecureIdentity construction and closely tying authorization to establishing an SSL/TLS connection. Eager SecureIdentity construction eliminates the need for a SecureIdentity to be constructed on a per-request basis. Closely tying authentication to establishing an SSL/TLS connection enables permission checks to happen BEFORE the first request is received.

  • A secure credential store that replaces the previous vault implementation to store clear text credentials.

The new elytron subsystem exists in parallel to the legacy security subsystem and legacy core management authentication. Both the legacy and Elytron methods may be used for securing the management interfaces as well as providing security for applications.

3.1. Get Started using the Elytron Subsystem

To get started using Elytron, refer to these topics:

3.2. Provided components

Wildfly Elytron provides a default set of implementations in the elytron subsystem.

3.2.1. Factories

Component Description

aggregate-http-server-mechanism-factory

An HTTP server factory definition where the HTTP server factory is an aggregation of other HTTP server factories.

aggregate-sasl-server-factory

A SASL server factory definition where the SASL server factory is an aggregation of other SASL server factories.

configurable-http-server-mechanism-factory

A SASL server factory definition where the SASL server factory is an aggregation of other SASL server factories.

configurable-sasl-server-factory

A SASL server factory definition where the SASL server factory is an aggregation of other SASL server factories.

custom-credential-security-factory

A custom credential SecurityFactory definition.

http-authentication-factory

Resource containing the association of a security domain with a HttpServerAuthenticationMechanismFactory.

kerberos-security-factory

A security factory for obtaining a GSSCredential for use during authentication.

mechanism-provider-filtering-sasl-server-factory

A SASL server factory definition that enables filtering by provider where the factory was loaded using a provider.

provider-http-server-mechanism-factory

An HTTP server factory definition where the HTTP server factory is an aggregation of factories from the provider list.

provider-sasl-server-factory

A SASL server factory definition where the SASL server factory is an aggregation of factories from the provider list.

sasl-authentication-factory

Resource containing the association of a security domain with a SaslServerFactory.

service-loader-http-server-mechanism-factory

An HTTP server factory definition where the HTTP server factory is an aggregation of factories identified using a ServiceLoader

service-loader-sasl-server-factory

A SASL server factory definition where the SASL server factory is an aggregation of factories identified using a ServiceLoader

3.2.2. Principal Transformers

Component Description

aggregate-principal-transformer

A principal transformer definition where the principal transformer is an aggregation of other principal transformers.

chained-principal-transformer

A principal transformer definition where the principal transformer is a chaining of other principal transformers.

constant-principal-transformer

A principal transformer definition where the principal transformer always returns the same constant.

custom-principal-transformer

A custom principal transformer definition.

regex-principal-transformer

A regular expression based principal transformer

regex-validating-principal-transformer

A regular expression based principal transformer which uses the regular expression to validate the name.

3.2.3. Principal Decoders

Component Description

aggregate-principal-decoder

A principal decoder definition where the principal decoder is an aggregation of other principal decoders.

concatenating-principal-decoder

A principal decoder definition where the principal decoder is a concatenation of other principal decoders.

constant-principal-decoder

Definition of a principal decoder that always returns the same constant.

custom-principal-decoder

Definition of a custom principal decoder.

x500-attribute-principal-decoder

Definition of a X500 attribute based principal decoder.

3.2.4. Realm Mappers

Component Description

constant-realm-mapper

Definition of a constant realm mapper that always returns the same value.

custom-realm-mapper

Definition of a custom realm mapper

mapped-regex-realm-mapper

Definition of a realm mapper implementation that first uses a regular expression to extract the realm name, this is then converted using the configured mapping of realm names.

simple-regex-realm-mapper

Definition of a simple realm mapper that attempts to extract the realm name using the capture group from the regular expression, if that does not provide a match then the delegate realm mapper is used instead.

3.2.5. Realms

Component Description

aggregate-realm

A realm definition that is an aggregation of two realms, one for the authentication steps and one for loading the identity for the authorization steps.

caching-realm

A realm definition that enables caching to another security realm. Caching strategy is Least Recently Used where least accessed entries are discarded when maximum number of entries is reached.

custom-modifiable-realm

Custom realm configured as being modifiable will be expected to implement the ModifiableSecurityRealm interface. By configuring a realm as being modifiable management operations will be made available to manipulate the realm.

custom-realm

A custom realm definitions can implement either the s SecurityRealm interface or the ModifiableSecurityRealm interface. Regardless of which interface is implemented management operations will not be exposed to manage the realm. However other services that depend on the realm will still be able to perform a type check and cast to gain access to the modification API.

filesystem-realm

A simple security realm definition backed by the filesystem.

identity-realm

A security realm definition where identities are represented in the management model.

jdbc-realm

A security realm definition backed by database using JDBC.

key-store-realm

A security realm definition backed by a keystore.

ldap-realm

A security realm definition backed by LDAP.

properties-realm

A security realm definition backed by properties files.

token-realm

A security realm definition capable of validating and extracting identities from security tokens.

3.2.6. Permission Mappers

Component Description

custom-permission-mapper

Definition of a custom permission mapper.

logical-permission-mapper

Definition of a logical permission mapper.

simple-permission-mapper

Definition of a simple configured permission mapper.

constant-permission-mapper

Definition of a permission mapper that always returns the same constant.

3.2.7. Role Decoders

Component Description

custom-role-decoder

Definition of a custom RoleDecoder

simple-role-decoder

Definition of a simple RoleDecoder that takes a single attribute and maps it directly to roles.

3.2.8. Role Mappers

Component Description

add-prefix-role-mapper

A role mapper definition for a role mapper that adds a prefix to each provided.

add-suffix-role-mapper

A role mapper definition for a role mapper that adds a suffix to each provided.

constant-role-mapper

A role mapper definition where a constant set of roles is always returned.

aggregate-role-mapper

A role mapper definition where the role mapper is an aggregation of other role mappers.

logical-role-mapper

A role mapper definition for a role mapper that performs a logical operation using two referenced role mappers.

custom-role-mapper

Definition of a custom role mapper

mapped-role-mapper

A role mapper definition for a role mapper that uses configured mapping of role names to map role names.

3.2.9. SSL Components

Component Description

client-ssl-context

An SSLContext for use on the client side of a connection.

filtering-key-store

A filtering keystore definition, which provides a keystore by filtering a key-store.

key-manager

A key manager definition for creating the key manager list as used to create an SSL context.

key-store

A keystore definition.

ldap-key-store

An LDAP keystore definition, which loads a keystore from an LDAP server.

server-ssl-context

An SSL context for use on the server side of a connection.

trust-manager

A trust manager definition for creating the TrustManager list as used to create an SSL context.

certificate-authority-account

A certificate authority account which can be used to obtain and revoke signed certificates.

3.2.10. Other

Component Description

aggregate-providers

An aggregation of two or more Provider[] resources.

authentication-configuration

An individual authentication configuration definition, which is used by clients deployed to Wildfly and other resources for authenticating when making a remote connection.

authentication-context

An individual authentication context definition, which is used to supply an ssl-context and authentication-configuration when clients deployed to Wildfly and other resources make a remoting connection.

credential-store

Credential store to keep alias for sensitive information such as passwords for external services.

dir-context

The configuration to connect to a directory (LDAP) server.

provider-loader

A definition for a provider loader.

security-domain

A security domain definition.

security-property

A definition of a security property to be set.

3.3. Out of the Box Configuration

WildFly provides a set of components configured by default. While these components are ready to use, the legacy security subsystem and legacy core management authentication is still used by default. To configure WildFly to use the these configured components as well as create new ones, see the Using the Elytron Subsystem section.

Default Component Description

ApplicationDomain

The ApplicationDomain security domain uses ApplicationRealm and groups-to-roles for authentication. It also uses default-permission-mapper to assign the login permission.

ManagementDomain

The ManagementDomain security domain uses two security realms for authentication: ManagementRealm with groups-to-roles and local with super-user-mapper. It also uses default-permission-mapper to assign the login permission.

local (security realm)

The local security realm does no authentication and sets the identity of principals to $local

ApplicationRealm

The ApplicationRealm security realm is a properties realm that authenticates principals using application-users.properties and assigns roles using application-roles.properties. These files are located under jboss.server.config.dir, which by default, maps to EAP_HOME/standalone/configuration. They are also the same files used by the legacy security default configuration.

ManagementRealm

The ManagementRealm security realm is a properties realm that authenticates principals using mgmt-users.properties and assigns roles using mgmt-groups.properties. These files are located under jboss.server.config.dir, which by default, maps to EAP_HOME/standalone/configuration. They are also the same files used by the legacy security default configuration.

default-permission-mapper

The default-permission-mapper mapper is a simple permission mapper that uses the default-permissions permission set to assign the full set of permissions that an identity would require to access any services on the server. For example, the default-permission-mapper mapper uses org.wildfly.extension.batch.jberet.deployment.BatchPermission specified by the default-permissions permission set to assign permission for batch jobs. The batch permissions are start, stop, restart, abandon, and read which aligns with javax.batch.operations.JobOperator. The default-permission-mapper mapper also uses org.wildfly.security.auth.permission.LoginPermission specified by the the login-permission permission set to assign the login permission.

local (mapper)

The local mapper is a constant role mapper that maps to the local security realm. This is used to map authentication to the local security realm.

groups-to-roles

The groups-to-roles mapper is a simple-role-decoder that will decode the groups information of a principal and use it for the role information.

super-user-mapper

The super-user-mapper mapper is a constant role mapper that maps the SuperUser role to a principal.

management-http-authentication

The management-http-authentication http-authentication-factory can be used for doing authentication over http. It uses the global provider-http-server-mechanism-factory to filter authentication mechanism and uses ManagementDomain for authenticating principals. It accepts the DIGEST authentication mechanisms and exposes it as ManagementRealm to applications.

global (provider-http-server-mechanism-factory)

This is the HTTP server factory mechanism definition used to list the provided authentication mechanisms when creating an http authentication factory.

management-sasl-authentication

The management-sasl-authentication sasl-authentication-factory can be used for authentication using SASL. It uses the configured sasl-server-factory to filter authentication mechanisms, which also uses the global provider-sasl-server-factory to filter by provider names. management-sasl-authentication uses the ManagementDomain security domain for authentication of principals. It also maps authentication using JBOSS-LOCAL-USER mechanisms using the local realm mapper and authentication using DIGEST-MD5 to ManagementRealm.

application-sasl-authentication

The application-sasl-authentication sasl-authentication-factory can be used for authentication using SASL. It uses the configured sasl-server-factory to filter authentication mechanisms, which also uses the global provider-sasl-server-factory to filter by provider names. application-sasl-authentication uses the ApplicationDomain security domain for authentication of principals.

global (provider-sasl-server-factory)

This is the SASL server factory definition used to create SASL authentication factories.

elytron (mechanism-provider-filtering-sasl-server-factor)

This is used to filter which sasl-authentication-factory is used based on the provider. In this case, elytron will match on the WildFlyElytron provider name.

configured (configurable-sasl-server-factory)

This is used to filter sasl-authentication-factory is used based on the mechanism name. In this case, configured will match on JBOSS-LOCAL-USER and DIGEST-MD5. It also sets the wildfly.sasl.local-user.default-user to $local.

combined-providers

Is an aggregate provider that aggreates the elytron and openssl provider loaders.

elytron

A provider loader

openssl

A provider loader

Default WildFly Configuration

/subsystem=elytron:read-resource(recursive=true)
{
    "outcome" => "success",
    "result" => {
        "default-authentication-context" => undefined,
        "disallowed-providers" => ["OracleUcrypto"],
        "final-providers" => "combined-providers",
        "initial-providers" => undefined,
        "security-properties" => undefined,
        "add-prefix-role-mapper" => undefined,
        "add-suffix-role-mapper" => undefined,
        "aggregate-http-server-mechanism-factory" => undefined,
        "aggregate-principal-decoder" => undefined,
        "aggregate-principal-transformer" => undefined,
        "aggregate-providers" => {"combined-providers" => {"providers" => [
            "elytron",
            "openssl"
        ]}},
        "aggregate-realm" => undefined,
        "aggregate-role-mapper" => undefined,
        "aggregate-sasl-server-factory" => undefined,
        "aggregate-security-event-listener" => undefined,
        "authentication-configuration" => undefined,
        "authentication-context" => undefined,
        "caching-realm" => undefined,
        "certificate-authority-account" => undefined,
        "chained-principal-transformer" => undefined,
        "client-ssl-context" => undefined,
        "concatenating-principal-decoder" => undefined,
        "configurable-http-server-mechanism-factory" => undefined,
        "configurable-sasl-server-factory" => {"configured" => {
            "filters" => undefined,
            "properties" => {"wildfly.sasl.local-user.default-user" => "$local"},
            "protocol" => undefined,
            "sasl-server-factory" => "elytron",
            "server-name" => undefined
        }},
        "constant-permission-mapper" => undefined,
        "constant-principal-decoder" => undefined,
        "constant-principal-transformer" => undefined,
        "constant-realm-mapper" => {"local" => {"realm-name" => "local"}},
        "constant-role-mapper" => {"super-user-mapper" => {"roles" => ["SuperUser"]}},
        "credential-store" => undefined,
        "custom-credential-security-factory" => undefined,
        "custom-modifiable-realm" => undefined,
        "custom-permission-mapper" => undefined,
        "custom-principal-decoder" => undefined,
        "custom-principal-transformer" => undefined,
        "custom-realm" => undefined,
        "custom-realm-mapper" => undefined,
        "custom-role-decoder" => undefined,
        "custom-role-mapper" => undefined,
        "custom-security-event-listener" => undefined,
        "dir-context" => undefined,
        "file-audit-log" => {"local-audit" => {
            "format" => "JSON",
            "path" => "audit.log",
            "relative-to" => "jboss.server.log.dir",
            "synchronized" => true
        }},
        "filesystem-realm" => undefined,
        "filtering-key-store" => undefined,
        "http-authentication-factory" => {
            "management-http-authentication" => {
                "http-server-mechanism-factory" => "global",
                "mechanism-configurations" => [{
                    "mechanism-name" => "DIGEST",
                    "mechanism-realm-configurations" => [{"realm-name" => "ManagementRealm"}]
                }],
                "security-domain" => "ManagementDomain"
            }
        },
        "identity-realm" => {"local" => {
            "attribute-name" => undefined,
            "attribute-values" => undefined,
            "identity" => "$local"
        }},
        "jdbc-realm" => undefined,
        "kerberos-security-factory" => undefined,
        "key-manager" => undefined,
        "key-store" => undefined,
        "key-store-realm" => undefined,
        "ldap-key-store" => undefined,
        "ldap-realm" => undefined,
        "logical-permission-mapper" => undefined,
        "logical-role-mapper" => undefined,
        "mapped-regex-realm-mapper" => undefined,
        "mapped-role-mapper" => undefined,
        "mechanism-provider-filtering-sasl-server-factory" => {"elytron" => {
            "enabling" => true,
            "filters" => [{"provider-name" => "WildFlyElytron"}],
            "sasl-server-factory" => "global"
        }},
        "periodic-rotating-file-audit-log" => undefined,
        "permission-set" => {
            "login-permission" => {"permissions" => [{"class-name" => "org.wildfly.security.auth.permission.LoginPermission"}]},
            "default-permissions" => {"permissions" => [
                {
                    "class-name" => "org.wildfly.extension.batch.jberet.deployment.BatchPermission",
                    "module" => "org.wildfly.extension.batch.jberet",
                    "target-name" => "*"
                },
                {
                    "class-name" => "org.wildfly.transaction.client.RemoteTransactionPermission",
                    "module" => "org.wildfly.transaction.client"
                },
                {
                    "class-name" => "org.jboss.ejb.client.RemoteEJBPermission",
                    "module" => "org.jboss.ejb-client"
                }
            ]}
        },
        "policy" => undefined,
        "properties-realm" => {
            "ApplicationRealm" => {
                "groups-attribute" => "groups",
                "groups-properties" => {
                    "path" => "application-roles.properties",
                    "relative-to" => "jboss.server.config.dir"
                },
                "users-properties" => {
                    "path" => "application-users.properties",
                    "relative-to" => "jboss.server.config.dir",
                    "digest-realm-name" => "ApplicationRealm"
                }
            },
            "ManagementRealm" => {
                "groups-attribute" => "groups",
                "groups-properties" => {
                    "path" => "mgmt-groups.properties",
                    "relative-to" => "jboss.server.config.dir"
                },
                "users-properties" => {
                    "path" => "mgmt-users.properties",
                    "relative-to" => "jboss.server.config.dir",
                    "digest-realm-name" => "ManagementRealm"
                }
            }
        },
        "provider-http-server-mechanism-factory" => {"global" => {"providers" => undefined}},
        "provider-loader" => {
            "elytron" => {
                "argument" => undefined,
                "class-names" => undefined,
                "configuration" => undefined,
                "module" => "org.wildfly.security.elytron",
                "path" => undefined,
                "relative-to" => undefined
            },
            "openssl" => {
                "argument" => undefined,
                "class-names" => undefined,
                "configuration" => undefined,
                "module" => "org.wildfly.openssl",
                "path" => undefined,
                "relative-to" => undefined
            }
        },
        "provider-sasl-server-factory" => {"global" => {"providers" => undefined}},
        "regex-principal-transformer" => undefined,
        "regex-validating-principal-transformer" => undefined,
        "sasl-authentication-factory" => {
            "application-sasl-authentication" => {
                "mechanism-configurations" => [
                    {
                        "mechanism-name" => "JBOSS-LOCAL-USER",
                        "realm-mapper" => "local"
                    },
                    {
                        "mechanism-name" => "DIGEST-MD5",
                        "mechanism-realm-configurations" => [{"realm-name" => "ApplicationRealm"}]
                    }
                ],
                "sasl-server-factory" => "configured",
                "security-domain" => "ApplicationDomain"
            },
            "management-sasl-authentication" => {
                "mechanism-configurations" => [
                    {
                        "mechanism-name" => "JBOSS-LOCAL-USER",
                        "realm-mapper" => "local"
                    },
                    {
                        "mechanism-name" => "DIGEST-MD5",
                        "mechanism-realm-configurations" => [{"realm-name" => "ManagementRealm"}]
                    }
                ],
                "sasl-server-factory" => "configured",
                "security-domain" => "ManagementDomain"
            }
        },
        "security-domain" => {
            "ApplicationDomain" => {
                "default-realm" => "ApplicationRealm",
                "outflow-anonymous" => false,
                "outflow-security-domains" => undefined,
                "permission-mapper" => "default-permission-mapper",
                "post-realm-principal-transformer" => undefined,
                "pre-realm-principal-transformer" => undefined,
                "principal-decoder" => undefined,
                "realm-mapper" => undefined,
                "realms" => [
                    {
                        "realm" => "ApplicationRealm",
                        "role-decoder" => "groups-to-roles"
                    },
                    {"realm" => "local"}
                ],
                "role-mapper" => undefined,
                "security-event-listener" => undefined,
                "trusted-security-domains" => undefined
            },
            "ManagementDomain" => {
                "default-realm" => "ManagementRealm",
                "outflow-anonymous" => false,
                "outflow-security-domains" => undefined,
                "permission-mapper" => "default-permission-mapper",
                "post-realm-principal-transformer" => undefined,
                "pre-realm-principal-transformer" => undefined,
                "principal-decoder" => undefined,
                "realm-mapper" => undefined,
                "realms" => [
                    {
                        "realm" => "ManagementRealm",
                        "role-decoder" => "groups-to-roles"
                    },
                    {
                        "realm" => "local",
                        "role-mapper" => "super-user-mapper"
                    }
                ],
                "role-mapper" => undefined,
                "security-event-listener" => undefined,
                "trusted-security-domains" => undefined
            }
        },
        "server-ssl-context" => undefined,
        "service-loader-http-server-mechanism-factory" => undefined,
        "service-loader-sasl-server-factory" => undefined,
        "simple-permission-mapper" => {"default-permission-mapper" => {
            "mapping-mode" => "first",
            "permission-mappings" => [
                {
                    "principals" => ["anonymous"],
                    "permission-sets" => [{"permission-set" => "default-permissions"}]
                },
                {
                    "match-all" => true,
                    "permission-sets" => [
                        {"permission-set" => "login-permission"},
                        {"permission-set" => "default-permissions"}
                    ]
                }
            ]
        }},
        "simple-regex-realm-mapper" => undefined,
        "simple-role-decoder" => {"groups-to-roles" => {"attribute" => "groups"}},
        "size-rotating-file-audit-log" => undefined,
        "syslog-audit-log" => undefined,
        "token-realm" => undefined,
        "trust-manager" => undefined,
        "x500-attribute-principal-decoder" => undefined
    }
}

3.4. Default Application Authentication Configuration

By default, applications are secured using legacy security domains. Applications must specify a security domain in their web.xml as well as the authentication method. If no security domain is specified by the application, WildFly will use the provided other legacy security domain.

3.4.1. Update WildFly to Use the Default Elytron Components for Application

Authentication

/subsystem=undertow/application-security-domain=exampleApplicationDomain:add(http-authentication-factory=example-http-auth)

For more information on configuring an http-authentication-factory, see configure an http-authentication-factory

3.4.2. Default Elytron ApplicationDomain Configuration

The http-authentication-factory can be configured to use the ApplicationDomain security domain.

/subsystem=elytron/security-domain=ApplicationDomain:read-resource()
{
    "outcome" => "success",
    "result" => {
        "default-realm" => "ApplicationRealm",
        "permission-mapper" => "default-permission-mapper",
        "post-realm-principal-transformer" => undefined,
        "pre-realm-principal-transformer" => undefined,
        "principal-decoder" => undefined,
        "realm-mapper" => undefined,
        "realms" => [{
            "realm" => "ApplicationRealm",
            "role-decoder" => "groups-to-roles"
        }],
        "role-mapper" => undefined,
        "trusted-security-domains" => undefined
    }
}

The ApplicationDomain security domain is backed by the ApplicationRealm Elytron security realm, which is a properties-based realm.

/subsystem=elytron/properties-realm=ApplicationRealm:read-resource()
{
    "outcome" => "success",
    "result" => {
        "groups-attribute" => "groups",
        "groups-properties" => {
            "path" => "application-roles.properties",
            "relative-to" => "jboss.server.config.dir"
        },
        "users-properties" => {
            "path" => "application-users.properties",
            "relative-to" => "jboss.server.config.dir",
            "digest-realm-name" => "ApplicationRealm"
        }
    }
}

3.5. Default Management Authentication Configuration

By default, the WildFly management interfaces are secured by the legacy core management authentication.

Default Configuration

/core-service=management/management-interface=http-interface:read-resource()
{
    "outcome" => "success",
    "result" => {
        "allowed-origins" => undefined,
        "console-enabled" => true,
        "http-authentication-factory" => undefined,
        "http-upgrade" => {"enabled" => true},
        "http-upgrade-enabled" => true,
        "sasl-protocol" => "remote",
        "secure-socket-binding" => undefined,
        "security-realm" => "ManagementRealm",
        "server-name" => undefined,
        "socket-binding" => "management-http",
        "ssl-context" => undefined
    }

WildFly does provide management-http-authentication and management-sasl-authentication in the elytron subsystem for securing the management interfaces as well.

3.5.1. Update WildFly to Use the Default Elytron Components for Management

Authentication

Set http-authentication-factory to use

management-http-authentication

/core-service=management/management-interface=http-interface:write-attribute( \
  name=http-authentication-factory, \
  value=management-http-authentication \
)
Set sasl-authentication-factory to use

management-sasl-authentication

/core-service=management/management-interface=http-interface:write-attribute( \
  name=http-upgrade.sasl-authentication-factory, \
  value=management-sasl-authentication \
)
Undefine security-realm
/core-service=management/management-interface=http-interface:undefine-attribute(name=security-realm)
Reload WildFly for the changes to take affect.
reload

The management interfaces are now secured using the default components provided by the 'elytron' subsystem.

3.5.2. Default Elytron Management HTTP Authentication Configuration

When you access the management interface over HTTP, for example when using the web-based management console, WildFly will use the management-http-authentication http-authentication-factory.

/subsystem=elytron/http-authentication-factory=management-http-authentication:read-resource()
{
    "outcome" => "success",
    "result" => {
        "http-server-mechanism-factory" => "global",
        "mechanism-configurations" => [{
            "mechanism-name" => "DIGEST",
            "mechanism-realm-configurations" => [{"realm-name" => "ManagementRealm"}]
        }],
        "security-domain" => "ManagementDomain"
    }
}

The management-http-authentication http-authentication-factory, is configured to use the ManagementDomain security domain.

/subsystem=elytron/security-domain=ManagementDomain:read-resource()
{
    "outcome" => "success",
    "result" => {
        "default-realm" => "ManagementRealm",
        "outflow-anonymous" => false,
        "outflow-security-domains" => undefined,
        "permission-mapper" => "default-permission-mapper",
        "post-realm-principal-transformer" => undefined,
        "pre-realm-principal-transformer" => undefined,
        "principal-decoder" => undefined,
        "realm-mapper" => undefined,
        "realms" => [
            {
                "realm" => "ManagementRealm",
                "role-decoder" => "groups-to-roles"
            },
            {
                "realm" => "local",
                "role-mapper" => "super-user-mapper"
            }
        ],
        "role-mapper" => undefined,
        "security-event-listener" => undefined,
        "trusted-security-domains" => undefined
    }
}

The ManagementDomain security domain is backed by the ManagementRealm Elytron security realm, which is a properties-based realm.

/subsystem=elytron/properties-realm=ManagementRealm:read-resource()
{
    "outcome" => "success",
    "result" => {
        "groups-attribute" => "groups",
        "groups-properties" => {
            "path" => "mgmt-groups.properties",
            "relative-to" => "jboss.server.config.dir"
        },
        "plain-text" => false,
        "users-properties" => {
            "path" => "mgmt-users.properties",
            "relative-to" => "jboss.server.config.dir",
            "digest-realm-name" => "ManagementRealm"
        }
    }
}

3.5.3. Default Elytron Management CLI Authentication

By default, the management CLI ( jboss-cli.sh) is configured to connect over remote+http.

Default jboss-cli.xml

<jboss-cli xmlns="urn:jboss:cli:3.3">
 
    <default-protocol use-legacy-override="true">remote+http</default-protocol>
 
    <!-- The default controller to connect to when 'connect' command is executed w/o arguments -->
    <default-controller>
        <protocol>remote+http</protocol>
        <host>localhost</host>
        <port>9990</port>
    </default-controller>

This will establish a connection over HTTP and use HTTP upgrade to change the communication protocol to native. The HTTP upgrade connection is secured in the http-upgrade section of the http-interface using a sasl-authentication-factory.

Example Configuration with Default Components

/core-service=management/management-interface=http-interface:read-resource()
{
    "outcome" => "success",
    "result" => {
        "allowed-origins" => undefined,
        "console-enabled" => true,
        "http-authentication-factory" => "management-http-authentication",
        "http-upgrade" => {
            "enabled" => true,
            "sasl-authentication-factory" => "management-sasl-authentication"
        },
        "http-upgrade-enabled" => true,
        "sasl-protocol" => "remote",
        "secure-socket-binding" => undefined,
        "security-realm" => undefined,
        "server-name" => undefined,
        "socket-binding" => "management-http",
        "ssl-context" => undefined
    }
}

The default sasl-authentication-factory is management-sasl-authentication.

/subsystem=elytron/sasl-authentication-factory=management-sasl-authentication:read-resource()
{
    "outcome" => "success",
    "result" => {
        "mechanism-configurations" => [
            {
                "mechanism-name" => "JBOSS-LOCAL-USER",
                "realm-mapper" => "local"
            },
            {
                "mechanism-name" => "DIGEST-MD5",
                "mechanism-realm-configurations" => [{"realm-name" => "ManagementRealm"}]
            }
        ],
        "sasl-server-factory" => "configured",
        "security-domain" => "ManagementDomain"
    }
}

The management-sasl-authentication sasl-authentication-factory specifies JBOSS-LOCAL-USER and DIGEST-MD5 mechanisms.

JBOSS-LOCAL-USER Realm

/subsystem=elytron/identity-realm=local:read-resource()
{
    "outcome" => "success",
    "result" => {
        "attribute-name" => undefined,
        "attribute-values" => undefined,
        "identity" => "$local"
    }
}

The local Elytron security realm is for handling silent authentication for local users.

The ManagementRealm Elytron security realm is the same realm used in the management-http-authentication http-authentication-factory.

3.6. Comparing Legacy Approaches to Elytron Approaches

Legacy Approach Elytron Approach

UsersRoles Login Module

Configure Authentication with a Properties File-Based Identity Store

Database Login Module

Configure Authentication with a Database Identity Store

Ldap, LdapExtended, AdvancedLdap, AdvancedADLdap Login Modules

Configure Authentication with an LDAP-Based Identity Store

Certificate, Certificate Roles Login Module

Configure Authentication with Certificates

Kerberos, SPNEGO Login Modules

Configure Authentication with a Kerberos-Based Identity Store

Kerberos, SPNEGO Login Modules with Fallback

Configure Authentication with a Form as a Fallback for Kerberos

RoleMapping Login Module

Configure Authentication with a Mapped Role Mapper

Vault

Create and Use a Credential Store

Legacy Security Realms

Secure the Management Interfaces with a New Identity Store, Silent Authentication

RBAC

Using RBAC with Elytron

Legacy Security Realms for One-way and Two-way SSL/TLS for Applications

Enable One-way SSL/TLS for Applications, Enable Two-way SSL/TLS in WildFly for Applications

Legacy Security Realms for One-way and Two-way SSL/TLS for Management Interfaces

Enable One-way for the Management Interfaces Using the Elytron Subsystem, Enable Two-way SSL/TLS for the Management Interfaces using the Elytron Subsystem

4. Using the Elytron Subsystem

4.1. Set Up and Configure Authentication for Applications

4.1.1. Configure Authentication with a Properties File-Based Identity Store

Create properties files:

You need to create two properties files: one that maps user to passwords and another that maps users to roles. Usually these files are located in the jboss.server.config.dir directory and follow the naming convention *-users.properties and *-roles.properties, but other locations and names may be used. The *-users.properties file must also contain a reference to the properties-realm, which you will create in the next step: #$REALM_NAME=YOUR_PROPERTIES_REALM_NAME$

Example user to password file: example-users.properties

#$REALM_NAME=examplePropRealm$
user1=password123
user2=password123

Example user to roles file: example-roles.properties

user1=Admin
user2=Guest
Configure a properties-realm in WildFly:
/subsystem=elytron/properties-realm=examplePropRealm:add(groups-attribute=groups,groups-properties={path=example-roles.properties,relative-to=jboss.server.config.dir},users-properties={path=example-users.properties,relative-to=jboss.server.config.dir,plain-text=true})

The name of the properties-realm is examplePropRealm, which is used in the previous step in the example-users.properties file. Also, if your properties files are located outside of jboss.server.config.dir, then you need to change the path and relative-to values appropriately.

Configure a security-domain:
/subsystem=elytron/security-domain=exampleSD:add(realms=[{realm=examplePropRealm,role-decoder=groups-to-roles}],default-realm=examplePropRealm,permission-mapper=default-permission-mapper)
Configure an http-authentication-factory:
/subsystem=elytron/http-authentication-factory=example-http-auth:add(http-server-mechanism-factory=global,security-domain=exampleSD,mechanism-configurations=[{mechanism-name=BASIC,mechanism-realm-configurations=[{realm-name=exampleApplicationDomain}]}])

This example shows creating an http-authentication-factory using BASIC authentication, but it could be updated to other mechanisms such as FORM.

Configure an application-security-domain in the Undertow subsystem:
/subsystem=undertow/application-security-domain=exampleApplicationDomain:add(http-authentication-factory=example-http-auth)
Configure your application’s web.xml and jboss-web.xml.

Your application’s web.xml and jboss-web.xml must be updated to use the application-security-domain you configured in WildFly. An example of this is available in the Configure Applications to Use Elytron or Legacy Security for Authentication section.

4.1.2. Configure Authentication with a Filesystem-Based Identity Store

Chose a directory for users:

You need a directory where your users will be stored. In this example, we are using a directory called fs-realm-users located in jboss.server.config.dir.

Configure a filesystem-realm in WildFly:
/subsystem=elytron/filesystem-realm=exampleFsRealm:add(path=fs-realm-users,relative-to=jboss.server.config.dir)

If your directory is located outside of jboss.server.config.dir, then you need to change the path and relative-to values appropriately.

Add a user:

When using the filesystem-realm, you can add users using the management CLI.

/subsystem=elytron/filesystem-realm=exampleFsRealm:add-identity(identity=user1)
/subsystem=elytron/filesystem-realm=exampleFsRealm:set-password(clear={password="password123"}, identity=user1)
/subsystem=elytron/filesystem-realm=exampleFsRealm:add-identity-attribute(identity=user1, name=Roles, value=["Admin","Guest"])
Add a simple-role-decoder:
/subsystem=elytron/simple-role-decoder=from-roles-attribute:add(attribute=Roles)

This simple-role-decoder decodes a principal’s roles from the Roles attribute. You can change this value if your roles are in a different attribute.

Configure a security-domain:
/subsystem=elytron/security-domain=exampleFsSD:add(realms=[{realm=exampleFsRealm,role-decoder=from-roles-attribute}],default-realm=exampleFsRealm,permission-mapper=default-permission-mapper)
Configure an http-authentication-factory:
/subsystem=elytron/http-authentication-factory=example-fs-http-auth:add(http-server-mechanism-factory=global,security-domain=exampleFsSD,mechanism-configurations=[{mechanism-name=BASIC,mechanism-realm-configurations=[{realm-name=exampleApplicationDomain}]}])

This example shows creating an http-authentication-factory using BASIC authentication, but it could be updated to other mechanisms such as FORM.

Configure an application-security-domain in the Undertow subsystem:
/subsystem=undertow/application-security-domain=exampleApplicationDomain:add(http-authentication-factory=example-fs-http-auth)
Configure your application’s web.xml and jboss-web.xml.

Your application’s web.xml and jboss-web.xml must be updated to use the application-security-domain you configured in WildFly. An example of this is available in the Configure Applications to Use Elytron or Legacy Security for Authentication section.

Your application is now using a filesystem-based identity store for authentication.

4.1.3. Configure Authentication with a Database Identity Store

Determine your database format for usernames, passwords, and roles:

To set up authentication using a database for an identity store, you need to determine how your usernames, passwords, and roles are stored in that database. In this example, we are using a single table with the following sample data:

username password roles

user1

password123

Admin

user2

password123

Guest

Configure a datasource:

To connect to a database from WildFly, you must have the appropriate database driver deployed as well as a datasource configured. This example shows deploying the driver for postgres and configuring a datasource in WildFly:

deploy /path/to/postgresql-9.4.1210.jar
 
data-source add --name=examplePostgresDS --jndi-name=java:jboss/examplePostgresDS --driver-name=postgresql-9.4.1210.jar  --connection-url=jdbc:postgresql://localhost:5432/postgresdb --user-name=postgresAdmin --password=mysecretpassword
Configure a jdbc-realm in WildFly:
/subsystem=elytron/jdbc-realm=exampleDbRealm:add(principal-query=[{sql="SELECT password,roles FROM wildfly_users WHERE username=?",data-source=examplePostgresDS,clear-password-mapper={password-index=1},attribute-mapping=[{index=2,to=groups}]}])

NOTE: The above example shows how to obtain passwords and roles from a single principal-query. You can also create additional principal-query with attribute-mapping attributes if you require multiple queries to obtain roles or additional authentication or authorization information.

Configure a security-domain:
/subsystem=elytron/security-domain=exampleDbSD:add(realms=[{realm=exampleDbRealm,role-decoder=groups-to-roles}],default-realm=exampleDbRealm,permission-mapper=default-permission-mapper)
Configure an http-authentication-factory:
/subsystem=elytron/http-authentication-factory=example-db-http-auth:add(http-server-mechanism-factory=global,security-domain=exampleDbSD,mechanism-configurations=[{mechanism-name=BASIC,mechanism-realm-configurations=[{realm-name=exampleDbSD}]}])

This example shows creating an http-authentication-factory using BASIC authentication, but it could be updated to other mechanisms such as FORM.

Configure an application-security-domain in the Undertow subsystem:
/subsystem=undertow/application-security-domain=exampleApplicationDomain:add(http-authentication-factory=example-db-http-auth)
Configure your application’s web.xml and jboss-web.xml.

Your application’s web.xml and jboss-web.xml must be updated to use the application-security-domain you configured in WildFly. An example of this is available in the Configure Applications to Use Elytron or Legacy Security for Authentication section.

4.1.4. Configure Authentication with an LDAP-Based Identity Store

Determine your LDAP format for usernames, passwords, and roles:

To set up authentication using an LDAP server for an identity store, you need to determine how your usernames, passwords, and roles are stored. In this example, we are using the following structure:

dn: dc=wildfly,dc=org
dc: wildfly
objectClass: top
objectClass: domain
 
dn: ou=Users,dc=wildfly,dc=org
objectClass: organizationalUnit
objectClass: top
ou: Users
 
dn: uid=jsmith,ou=Users,dc=wildfly,dc=org
objectClass: top
objectClass: person
objectClass: inetOrgPerson
cn: John Smith
sn: smith
uid: jsmith
userPassword: password123
 
dn: ou=Roles,dc=wildfly,dc=org
objectclass: top
objectclass: organizationalUnit
ou: Roles
 
dn: cn=Admin,ou=Roles,dc=wildfly,dc=org
objectClass: top
objectClass: groupOfNames
cn: Admin
member: uid=jsmith,ou=Users,dc=wildfly,dc=org
Configure a dir-context:

To connect to the LDAP server from WildFly, you need to configure a dir-context that provides the URL as well as the principal used to connect to the server.

/subsystem=elytron/dir-context=exampleDC:add(url="ldap://127.0.0.1:10389",principal="uid=admin,ou=system",credential-reference={clear-text="secret"})
Configure an ldap-realm in WildFly:
/subsystem=elytron/ldap-realm=exampleLR:add(dir-context=exampleDC,identity-mapping={search-base-dn="ou=Users,dc=wildfly,dc=org",rdn-identifier="uid",user-password-mapper={from="userPassword"},attribute-mapping=[{filter-base-dn="ou=Roles,dc=wildfly,dc=org",filter="(&(objectClass=groupOfNames)(member={1}))",from="cn",to="Roles"}]})
Add a simple-role-decoder:
/subsystem=elytron/simple-role-decoder=from-roles-attribute:add(attribute=Roles)
Configure a security-domain:
/subsystem=elytron/security-domain=exampleLdapSD:add(realms=[{realm=exampleLR,role-decoder=from-roles-attribute}],default-realm=exampleLR,permission-mapper=default-permission-mapper)
Configure an http-authentication-factory:
/subsystem=elytron/http-authentication-factory=example-ldap-http-auth:add(http-server-mechanism-factory=global,security-domain=exampleLdapSD,mechanism-configurations=[{mechanism-name=BASIC,mechanism-realm-configurations=[{realm-name=exampleApplicationDomain}]}])

This example shows creating an http-authentication-factory using BASIC authentication, but it could be updated to other mechanisms such as FORM.

Configure an application-security-domain in the Undertow subsystem:
/subsystem=undertow/application-security-domain=exampleApplicationDomain:add(http-authentication-factory=example-ldap-http-auth)
Configure your application’s web.xml and jboss-web.xml.

Your application’s web.xml and jboss-web.xml must be updated to use the application-security-domain you configured in WildFly. An example of this is available in the Configure Applications to Use Elytron or Legacy Security for Authentication section.

IMPORTANT: In cases where you configure an LDAP server in the elytron subsystem for authentication and that LDAP server then becomes unreachable, WildFly will return a 500, or internal server error, error code when attempting authentication using that unreachable LDAP server. This behavior differs from the legacy security subsystem, which will return a 401, or unauthorized, error code under the same conditions.

4.1.5. Configure Authentication with Certificates

IMPORTANT: Before you can set up certificate-based authentication, you must have two-way SSL configured.

Configure a key-store-realm.
/subsystem=elytron/key-store-realm=ksRealm:add(key-store=twoWayTS)

You must configure this realm with a truststore that contains the client’s certificate. The authentication process uses the same certificate presented by the client during the two-way SSL handshake.

Create a Decoder.

You need to create a x500-attribute-principal-decoder to decode the principal you get from your certificate. The below example will decode the principal based on the first CN value.

/subsystem=elytron/x500-attribute-principal-decoder=CNDecoder:add(oid="2.5.4.3",maximum-segments=1)

For example, if the full DN was CN=client,CN=client-certificate,DC=example,DC=jboss,DC=org, CNDecoder would decode the principal as client. This decoded principal is used as the alias value to lookup a certificate in the truststore configured in ksRealm.

IMPORTANT: The decoded principal * MUST* must be the alias value you set in your server’s truststore for the client’s certificate.

Add a constant-role-mapper for assigning roles.

This is example uses a constant-role-mapper to assign roles to a principal from ksRealm but other approaches may also be used.

/subsystem=elytron/constant-role-mapper=constantClientCertRole:add(roles=[Admin,Guest])
Configure a security-domain.
/subsystem=elytron/security-domain=exampleCertSD:add(realms=[{realm=ksRealm}],default-realm=ksRealm,permission-mapper=default-permission-mapper,principal-decoder=CNDecoder,role-mapper=constantClientCertRole)
Configure an http-authentication-factory.
/subsystem=elytron/http-authentication-factory=exampleCertHttpAuth:add(http-server-mechanism-factory=global,security-domain=exampleCertSD,mechanism-configurations=[{mechanism-name=CLIENT_CERT,mechanism-realm-configurations=[{realm-name=exampleApplicationDomain}]}])
Configure an application-security-domain in the Undertow subsystem.
/subsystem=undertow/application-security-domain=exampleApplicationDomain:add(http-authentication-factory=exampleCertHttpAuth)
Update server-ssl-context.
/subsystem=elytron/server-ssl-context=twoWaySSC:write-attribute(name=security-domain,value=exampleCertSD)
/subsystem=elytron/server-ssl-context=twoWaySSC:write-attribute(name=authentication-optional, value=true)
Configure your application’s web.xml and jboss-web.xml.

Your application’s web.xml and jboss-web.xml must be updated to use the application-security-domain you configured in WildFly. An example of this is available in the Configure Applications to Use Elytron or Legacy Security for Authentication section.

In addition, you need to update your web.xml to use CLIENT-CERT as its authentication method.

<login-config>
  <auth-method>CLIENT-CERT</auth-method>
  <realm-name>exampleApplicationDomain</realm-name>
</login-config>

4.1.6. Configure Authentication with a Kerberos-Based Identity Store

IMPORTANT: The following steps assume you have a working KDC and Kerberos domain as well as your client browsers configured.

Configure a kerberos-security-factory.
/subsystem=elytron/kerberos-security-factory=krbSF:add(principal="HTTP/host@REALM",path="/path/to/http.keytab",mechanism-oids=[1.2.840.113554.1.2.2,1.3.6.1.5.5.2])
Configure the system properties for Kerberos.

Depending on how your environment is configured, you will need to set some of the system properties below.

System Property Description

java.security.krb5.kdc

The host name of the KDC.

java.security.krb5.realm

The name of the realm.

java.security.krb5.conf

The path to the configuration krb5.conf file.

sun.security.krb5.debug

If true, debugging mode will be enabled.

To configure a system property in WildFly:

/system-property=java.security.krb5.conf:add(value="/path/to/krb5.conf")
Configure an Eltyron security realm for assigning roles.

The the client’s Kerberos token will provide the principal, but you need a way to map that principal to a role for your application. There are several ways to accomplish this, but this example creates a filesystem-realm, adds a user to the realm that matches the principal from the Kerberos token, and assigns roles to that user.

/subsystem=elytron/filesystem-realm=exampleFsRealm:add(path=fs-realm-users,relative-to=jboss.server.config.dir)
/subsystem=elytron/filesystem-realm=exampleFsRealm/identity=user1@REALM:add()
/subsystem=elytron/filesystem-realm=exampleFsRealm/identity=user1@REALM:add-attribute(name=Roles, value=["Admin","Guest"])
Add a simple-role-decoder.
/subsystem=elytron/simple-role-decoder=from-roles-attribute:add(attribute=Roles)

This simple-role-decoder decodes a principal’s roles from the Roles attribute. You can change this value if your roles are in a different attribute.

Configure a security-domain.
/subsystem=elytron/security-domain=exampleFsSD:add(realms=[{realm=exampleFsRealm,role-decoder=from-roles-attribute}],default-realm=exampleFsRealm,permission-mapper=default-permission-mapper)
Configure an http-authentication-factory that uses the

kerberos-security-factory.

/subsystem=elytron/http-authentication-factory=example-krb-http-auth:add(http-server-mechanism-factory=global,security-domain=exampleFsSD,mechanism-configurations=[{mechanism-name=SPNEGO,mechanism-realm-configurations=[{realm-name=exampleFsSD}],credential-security-factory=krbSF}])
Configure an application-security-domain in the Undertow subsystem:
/subsystem=undertow/application-security-domain=exampleApplicationDomain:add(http-authentication-factory=example-krb-http-auth)
Configure your application’s web.xml, jboss-web.xml and

jboss-deployment-structure.xml.

Your application’s web.xml and jboss-web.xml must be updated to use the application-security-domain you configured in WildFly. An example of this is available in the Configure Applications to Use Elytron or Legacy Security for Authentication section.

In addition, you need to update your web.xml to use SPNEGO as its authentication method.

<login-config>
  <auth-method>SPNEGO</auth-method>
  <realm-name>exampleApplicationDomain</realm-name>
</login-config>

4.1.7. Configure Authentication with a Form as a Fallback for Kerberos

Configure kerberos-based authentication.

Configuring kerberos-based authentication is covered in a previous section.

Add a mechanism for FORM authentication in the

http-authentication-factory.

You can use the existing http-authentication-factory you configured for kerberos-based authentication and and an additional mechanism for FORM authentication.

/subsystem=elytron/http-authentication-factory=example-krb-http-auth:list-add(name=mechanism-configurations, value={mechanism-name=FORM})
Add additional fallback principals.

The existing configuration for kerberos-based authentication should already have a security realm configured for mapping principals from kerberos token to roles for the application. You can add additional users for fallback authentication to that realm. For example if you used a filesystem-realm, you can simply create a new user with the appropriate roles:

/subsystem=elytron/filesystem-realm=exampleFsRealm/identity=fallbackUser1:add()
/subsystem=elytron/filesystem-realm=exampleFsRealm/identity=fallbackUser1:set-password(clear={password="password123"})
/subsystem=elytron/filesystem-realm=exampleFsRealm/identity=fallbackUser1:add-attribute(name=Roles, value=["Admin","Guest"])
Update the web.xml for FORM fallback.

You need to update the web.xml to use the value SPNEGO,FORM for the auth-method, which will use FORM as a fallback authentication method if SPNEGO fails. You also need to specify the location of your login and error pages.

<login-config>
  <auth-method>SPNEGO,FORM</auth-method>
  <realm-name>exampleApplicationDomain</realm-name>
  <form-login-config>
    <form-login-page>/login.jsp</form-login-page>
    <form-error-page>/error.jsp</form-error-page>
  </form-login-config>
</login-config>

4.1.8. Configure Applications to Use Elytron or Legacy Security for

Authentication

After you have configured the elytron or legacy security subsystems for authentication, you need to configure your application to use it.

Configure your application’s web.xml.

Your application’s web.xml needs to be configured to use the appropriate authentication method. When using elytron, this is defined in the http-authentication-factory you created. When using the legacy security subsystem, this depends on your login module and the type of authentication you want to configure.

Example web.xml with BASIC Authentication

<web-app>
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>secure</web-resource-name>
      <url-pattern>/secure/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>Admin</role-name>
    </auth-constraint>
  </security-constraint>
  <security-role>
    <description>The role that is required to log in to /secure/*</description>
    <role-name>Admin</role-name>
  </security-role>
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>exampleApplicationDomain</realm-name>
  </login-config>
</web-app>
Configure your application to use a security domain.

You can configure your application’s jboss-web.xml to specify the security domain you want to use for authentication. When using the elytron subsystem, this is defined when you created the application-security-domain. When using the legacy security subsystem, this is the name of the legacy security domain.

Example jboss-web.xml

<jboss-web>
  <security-domain>exampleApplicationDomain</security-domain>
</jboss-web>

Using jboss-web.xml allows you to configure the security domain for a single application only. Alternatively, you can specify a default security domain for all applications using the undertow subsystem. This allows you to omit using jboss-web.xml to configure a security domain for an individual application.

/subsystem=undertow:write-attribute(name=default-security-domain, value="exampleApplicationDomain")

IMPORTANT: Setting default-security-domain in the undertow subsystem will apply to ALL applications. If default-security-domain is set and an application specifies a security domain in a jboss-web.xml file, the configuration in jboss-web.xml will override the default-security-domain in the undertow subsystem.

Using Elytron and Legacy Security Subsystems in Parallel

You can define authentication in both the elytron and legacy security subsystems and use them in parallel. If you use both jboss-web.xml and default-security-domain in the undertow subsystem, WildFly will first try to match the configured security domain in the elytron subsystem. If a match is not found, then WildFly will attempt to match the security domain with one configured in the legacy security subsystem. If the elytron and legacy security subsystem each have a security domain with the same name, the elytron security domain is used.

4.1.9. Override an Application’s Authentication Configuration

You can override the authentication configuration of an application with one configured in WildFly. To do this, use the override-deployment-configuration property in the application-security-domain section of the undertow subsystem:

/subsystem=undertow/application-security-domain=exampleApplicationDomain:write-attribute(name=override-deployment-config,value=true)

For example, an application is configured to use FORM authentication with the exampleApplicationDomain in its jboss-web.xml.

Example jboss-web.xml

<login-config>
  <auth-method>FORM</auth-method>
  <realm-name>exampleApplicationDomain</realm-name>
</login-config>

By enabling override-deployment-configuration, you can create a new http-authentication-factory that specifies a different authentication mechanism such as BASIC.

Example http-authentication-factory

/subsystem=elytron/http-authentication-factory=exampleHttpAuth:read-resource()
{
    "outcome" => "success",
    "result" => {
        "http-server-mechanism-factory" => "global",
        "mechanism-configurations" => [{
            "mechanism-name" => "BASIC",
            "mechanism-realm-configurations" => [{"realm-name" => "exampleApplicationDomain"}]
        }],
        "security-domain" => "exampleSD"
    }
}

This will override the authentication mechanism defined in the application’s jboss-web.xml and attempt to authenticate a user using BASIC instead of FORM.

4.1.10. Create and Use a Credential Store

Create credential store.
/subsystem=elytron/credential-store=exampleCS:add(relative-to=jboss.server.data.dir, location=example.jceks,create=true,credential-reference={clear-text=cs-secret})
Add a credential to a credential store.
/subsystem=elytron/credential-store=exampleCS:add-alias(alias=keystorepw,secret-value=secret)
List all credentials in a credential store.
/subsystem=elytron/credential-store=exampleCS:read-aliases()
{
    "outcome" => "success",
    "result" => ["keystorepw"]
}
Remove a credential from a credential store.
/subsystem=elytron/credential-store=exampleCS:remove-alias(alias=keystorepw)
Use a credential store.
/subsystem=elytron/key-store=twoWayKS:write-attribute(name=credential-reference,value={store=exampleCS,alias=keystorepw})

4.2. Set up and Configure Authentication for the Management Interfaces

4.2.1. Secure the Management Interfaces with a New Identity Store

Create a security domain and any supporting security realms,

decoders, or mappers for your identity store.

This process is covered in a previous section. For example, if you wanted to secure the management interfaces using a filesystem-based identity store, you would follow the steps in Configure Authentication with a Filesystem-Based Identity Store.

Create an http-authentication-factory or

sasl-authentication-factory.

Example http-authentication-factory

/subsystem=elytron/http-authentication-factory=example-http-auth:add(http-server-mechanism-factory=global,security-domain=exampleSD,mechanism-configurations=[{mechanism-name=DIGEST,mechanism-realm-configurations=[{realm-name=exampleManagementRealm}]}])

Example sasl-authentication-factory

/subsystem=elytron/sasl-authentication-factory=example-sasl-auth:add(sasl-server-factory=configured,security-domain=exampleSD,mechanism-configurations=[{mechanism-name=DIGEST-MD5,mechanism-realm-configurations=[{realm-name=exampleManagementRealm}]}])
Update the management interfaces to use your

http-authentication-factory or sasl-authentication-factory.

Example update http-authentication-factory

/core-service=management/management-interface=http-interface:write-attribute(name=http-authentication-factory, value=example-http-auth)
{
   "outcome" => "success",
   "response-headers" => {
       "operation-requires-reload" => true,
       "process-state" => "reload-required"
   }
}
 
reload

Example update sasl-authentication-factory

/core-service=management/management-interface=http-interface:write-attribute(name=http-upgrade.sasl-authentication-factory, value=example-sasl-auth)
{
   "outcome" => "success",
   "response-headers" => {
       "operation-requires-reload" => true,
       "process-state" => "reload-required"
   }
}
 
reload

4.2.2. Silent Authentication

By default, WildFly provides an authentication mechanism for local users, also know as silent authentication, through the local security realm.

Silent authentication must be used via a sasl-authentication-factory.

IMPORTANT: When enabling silent authentication, you must ensure the security domain referenced by your sasl-authentication-factory references a security realm that contains the $local user. By default, WildFly provides the local identity realm that provides this user.

Add silent authentication to an existing

sasl-authentication-factory.

/subsystem=elytron/sasl-authentication-factory=example-sasl-auth:list-add(name=mechanism-configurations, value={mechanism-name=JBOSS-LOCAL-USER, realm-mapper=local})
 
reload
Create a new sasl-server-factory with silent authentication.
/subsystem=elytron/sasl-authentication-factory=example-sasl-auth:add(sasl-server-factory=configured,security-domain=exampleSD,mechanism-configurations=[{mechanism-name=DIGEST-MD5,mechanism-realm-configurations=[{realm-name=exampleManagementRealm}]},{mechanism-name=JBOSS-LOCAL-USER, realm-mapper=local}])
 
reload
Remove silent authentication from an existing sasl-server-factory:
/subsystem=elytron/sasl-authentication-factory=managenet-sasl-authentication:read-resource
{
    "outcome" => "success",
    "result" => {
        "mechanism-configurations" => [
            {
                "mechanism-name" => "JBOSS-LOCAL-USER",
                "realm-mapper" => "local"
            },
            {
                "mechanism-name" => "DIGEST-MD5",
                "mechanism-realm-configurations" => [{"realm-name" => "ManagementRealm"}]
            }
        ],
        "sasl-server-factory" => "configured",
        "security-domain" => "ManagementDomain"
    }
}
 
/subsystem=elytron/sasl-authentication-factory=temp-sasl-authentication:list-remove(name=mechanism-configurations,index=0)
 
reload

4.2.3. Using RBAC with Elytron

RBAC can be configured to automatically assign or exclude roles for users that are members of groups. This is configured in the access-control section of the core management. When the management interfaces are secured with the elytron subsystem, and users are assigned groups when they authenticate. You can also configure roles to be assigned to authenticated users in a variety of ways using the elytron subsystem, for example using a role mapper or a role decoder.

4.3. Configure SSL/TLS

4.3.1. Enable One-way SSL/TLS for Applications

There are a couple ways to enable one-way SSL/TLS for deployed applications.

Using a security command:

The security enable-ssl-http-server command can be used to enable one-way SSL/TLS for deployed applications. Example of wizard usage:

security enable-ssl-http-server --interactive
Please provide required pieces of information to enable SSL:
Key-store file name (default default-server.keystore): keystore.jks
Password (blank generated): secret
What is your first and last name? [Unknown]: localhost
What is the name of your organizational unit? [Unknown]:
What is the name of your organization? [Unknown]:
What is the name of your City or Locality? [Unknown]:
What is the name of your State or Province? [Unknown]:
What is the two-letter country code for this unit? [Unknown]:
Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct y/n [y]?
Validity (in days, blank default): 365
Alias (blank generated): localhost
Enable SSL Mutual Authentication y/n (blank n): n

SSL options:
key store file: keystore.jks
distinguished name: CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
password: secret
validity: 365
alias: localhost
Server keystore file keystore.jks, certificate file keystore.pem and keystore.csr file
will be generated in server configuration directory.
Do you confirm y/n: y

NB: Once the command is executed, the CLI will reload the server.

HTTPS is now enabled for applications.

Using Elytron subsystem commands:

You can also use the Elytron subsystem, along with the Undertow subsystem, to enable HTTPS for deployed applications.

Configure a key-store in WildFly:
/subsystem=elytron/key-store=httpsKS:add(path=/path/to/keystore.jks,credential-reference={clear-text=secret},type=JKS)

The previous command uses an absolute path to the keystore. Alternatively you can use the relative-to attribute to specify the base directory variable and path specify a relative path.

/subsystem=elytron/key-store=httpsKS:add(path=keystore.jks,relative-to=jboss.server.config.dir,credential-reference={clear-text=secret},type=JKS)

If the keystore file does not exist yet, the following commands can be used to generate an example key pair:

/subsystem=elytron/key-store=httpsKS:generate-key-pair(alias=localhost,algorithm=RSA,key-size=1024,validity=365,credential-reference={clear-text=secret},distinguished-name="CN=localhost")
/subsystem=elytron/key-store=httpsKS:store()
Configure a key-manager that references your key-store:
/subsystem=elytron/key-manager=httpsKM:add(key-store=httpsKS,credential-reference={clear-text=secret})
Configure a server-ssl-context that references your key-manager:
/subsystem=elytron/server-ssl-context=httpsSSC:add(key-manager=httpsKM,protocols=["TLSv1.2"])

IMPORTANT: You need to determine what SSL/TLS protocols you want to support. The example commands above uses TLSv1.2.

Check and see if the https-listener is configured to use a legacy security realm for its SSL configuration:
/subsystem=undertow/server=default-server/https-listener=https:read-attribute(name=security-realm)
{
    "outcome" => "success",
    "result" => "ApplicationRealm"
}

The above command shows that the https-listener is configured to use the ApplicationRealm legacy security realm for its SSL configuration. Undertow cannot reference both a legacy security realm and an ssl-context in Elytron at the same time so you must remove the reference to the legacy security realm. Also there has to be always configured either ssl-context or security-realm. Thus when changing between those, you have to use batch operation:

Remove the reference to the legacy security realm and update the https-listener to use the ssl-context from Elytron :

batch
/subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(name=security-realm)
/subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=ssl-context,value=httpsSSC)
run-batch
Reload the server:
reload

HTTPS is now enabled for applications.

4.3.2. Enable Two-way SSL/TLS in WildFly for Applications

First, obtain or generate your client keystore.

$ keytool -genkeypair -alias client -keyalg RSA -keysize 1024 -validity 365 -keystore client.keystore.jks -dname "CN=client" -keypass secret -storepass secret

Export the client certificate:

$ keytool -exportcert  -keystore client.keystore.jks -alias client -keypass secret -storepass secret -file /path/to/client.cer

There are a couple ways to enable two-way SSL/TLS for deployed applications.

Using a security command:

The security enable-ssl-http-server command can be used to enable two-way SSL/TLS for the deployed applications. Example of wizard usage:

security enable-ssl-http-server --interactive
Please provide required pieces of information to enable SSL:
Key-store file name (default default-server.keystore): server.keystore.jks
Password (blank generated): secret
What is your first and last name? [Unknown]: localhost
What is the name of your organizational unit? [Unknown]:
What is the name of your organization? [Unknown]:
What is the name of your City or Locality? [Unknown]:
What is the name of your State or Province? [Unknown]:
What is the two-letter country code for this unit? [Unknown]:
Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct y/n [y]?
Validity (in days, blank default): 365
Alias (blank generated): localhost
Enable SSL Mutual Authentication y/n (blank n): y
Client certificate (path to pem file): /path/to/client.cer
Validate certificate y/n (blank y):
Trust-store file name (management.truststore): server.truststore.jks
Password (blank generated): secret

SSL options:
key store file: server.keystore.jks
distinguished name: CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
password: secret
validity: 365
alias: localhost
client certificate: /path/to/client.cer
trust store file: server.trustore.jks
trust store password: secret
Server keystore file server.keystore.jks, certificate file server.pem and server.csr file will be generated in server configuration directory.
Server truststore file server.trustore.jks will be generated in server configuration directory.
Do you confirm y/n: y

NB: Once the command is executed, the CLI will reload the server. To complete the two-way SSL/TLS authentication, you need to import the server certificate into the client truststore and configure your client to present the client certificate.

Using Elytron subsystem commands:

You can also use the Elytron subsystem, along with the Undertow subsystem, to enable two-way SSL/TLS for deployed applications.

Obtain or generate your key stores:

Before enabling HTTPS in WildFly, you must obtain or generate the server key store and trust store you plan on using. To generate an example key store and trust store, use the following commands.

Create a server key-store:

/subsystem=elytron/key-store=twoWayKS:add(path=/path/to/server.keystore.jks,credential-reference={clear-text=secret},type=JKS)
/subsystem=elytron/key-store=twoWayKS:generate-key-pair(alias=localhost,algorithm=RSA,key-size=1024,validity=365,credential-reference={clear-text=secret},distinguished-name="CN=localhost")
/subsystem=elytron/key-store=twoWayKS:store()

NOTE
The first command above uses an absolute path to the keystore. Alternatively you can use the relative-to attribute to specify the base directory variable and path specify a relative path.

/subsystem=elytron/key-store=twoWayKS:add(path=server.keystore.jks,relative-to=jboss.server.config.dir,credential-reference={clear-text=secret},type=JKS)

Export the server certificate:

/subsystem=elytron/key-store=twoWayKS:export-certificate(alias=localhost,path=/path/to/server.cer,pem=true)

Create a key-store for the server truststore and import the client certificate into the server truststore:

/subsystem=elytron/key-store=twoWayTS:add(path=/path/to/server.truststore.jks,credential-reference={clear-text=secret},type=JKS)
/subsystem=elytron/key-store=twoWayTS:import-certificate(alias=client,path=/path/to/client.cer,credential-reference={clear-text=secret},trust-cacerts=true)
/subsystem=elytron/key-store=twoWayTS:store()
Configure a key-manager that references your key store key-store:
/subsystem=elytron/key-manager=twoWayKM:add(key-store=twoWayKS,credential-reference={clear-text=secret})
Configure a trust-manager that references your truststore key-store:
/subsystem=elytron/trust-manager=twoWayTM:add(key-store=twoWayTS)
Configure a server-ssl-context that references your key-manager, trust-manager, and enables client authentication:
/subsystem=elytron/server-ssl-context=twoWaySSC:add(key-manager=twoWayKM,protocols=["TLSv1.2"],trust-manager=twoWayTM,need-client-auth=true)

IMPORTANT
You need to determine what SSL/TLS protocols you want to support. The example commands above uses TLSv1.2.

Check and see if the https-listener is configured to use a legacy security realm for its SSL configuration:
/subsystem=undertow/server=default-server/https-listener=https:read-attribute(name=security-realm)
{
    "outcome" => "success",
    "result" => "ApplicationRealm"
}

The above command shows that the https-listener is configured to use the ApplicationRealm legacy security realm for its SSL configuration. Undertow cannot reference both a legacy security realm and an ssl-context in Elytron at the same time so you must remove the reference to the legacy security realm. Also there has to be always configured either ssl-context or security-realm. Thus when changing between those, you have to use batch operation:

Remove the reference to the legacy security realm and update the

https-listener to use the ssl-context from Elytron:

batch
/subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(name=security-realm)
/subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=ssl-context,value=twoWaySSC)
run-batch
Reload the server
reload

To complete the two-way SSL/TLS authentication, you need to import the server certificate into the client truststore and configure your client to present the client certificate.

Import the server certificate into the client truststore
$ keytool -importcert -keystore client.truststore.jks -storepass secret -alias localhost -trustcacerts -file /path/to/server.cer
Configure your client to use the client certificate

You need to configure your client to present the trusted client certificate to the server to complete the two-way SSL/TLS authentication. For example, if using a browser, you need to import the trusted certificate into the browser’s truststore.

Two-Way HTTPS is now enabled for applications.

4.3.3. Enable One-way SSL/TLS for the Management Interfaces

There are a couple ways to enable one-way SSL/TLS for the management interfaces.

Using a security command:

The security enable-ssl-management command can be used to enable one-way SSL/TLS for the management interfaces. Example of wizard usage:

security enable-ssl-management --interactive
Please provide required pieces of information to enable SSL:
Key-store file name (default management.keystore): keystore.jks
Password (blank generated): secret
What is your first and last name? [Unknown]: localhost
What is the name of your organizational unit? [Unknown]:
What is the name of your organization? [Unknown]:
What is the name of your City or Locality? [Unknown]:
What is the name of your State or Province? [Unknown]:
What is the two-letter country code for this unit? [Unknown]:
Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct y/n [y]?
Validity (in days, blank default): 365
Alias (blank generated): localhost
Enable SSL Mutual Authentication y/n (blank n): n

SSL options:
key store file: keystore.jks
distinguished name: CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
password: secret
validity: 365
alias: localhost
Server keystore file keystore.jks, certificate file keystore.pem and keystore.csr file
will be generated in server configuration directory.
Do you confirm y/n :y

NB: Once the command is executed, the CLI will reload the server and reconnect to it.

HTTPS is now enabled for the management interfaces.

Using Elytron subsystem commands:

Elytron subsystem commands can also be used to enable one-way SSL/TLS for the management interfaces.

Configure a key-store:
/subsystem=elytron/key-store=httpsKS:add(path=keystore.jks,relative-to=jboss.server.config.dir,credential-reference={clear-text=secret},type=JKS)

NOTE: The above command uses relative-to to reference the location of the keystore file. Alternatively, you can specify the full path to the keystore in path and omit relative-to.

If the keystore file does not exist yet, the following commands can be used to generate an example key pair:

/subsystem=elytron/key-store=httpsKS:generate-key-pair(alias=localhost,algorithm=RSA,key-size=1024,validity=365,credential-reference={clear-text=secret},distinguished-name="CN=localhost")
/subsystem=elytron/key-store=httpsKS:store()
Create a key-manager and server-ssl-context.
/subsystem=elytron/key-manager=httpsKM:add(key-store=httpsKS,credential-reference={clear-text=secret})
 
/subsystem=elytron/server-ssl-context=httpsSSC:add(key-manager=httpsKM,protocols=["TLSv1.2"])

IMPORTANT: You need to determine what SSL/TLS protocols you want to support. The example commands above uses TLSv1.2.

Enable HTTPS on the management interface.
/core-service=management/management-interface=http-interface:write-attribute(name=ssl-context, value=httpsSSC)
 
/core-service=management/management-interface=http-interface:write-attribute(name=secure-socket-binding, value=management-https)
Reload the WildFly instance.
reload

HTTPS is now enabled for the management interfaces.

4.3.4. Enable Two-way SSL/TLS for the Management Interfaces

First, obtain or generate your client keystore.

$ keytool -genkeypair -alias client -keyalg RSA -keysize 1024 -validity 365 -keystore client.keystore.jks -dname "CN=client" -keypass secret -storepass secret

Export your client certificate.

$ keytool -exportcert  -keystore client.keystore.jks -alias client -keypass secret -storepass secret -file /path/to/client.cer

There are a couple ways to enable two-way SSL/TLS for the management interfaces.

Using a security command:

The security enable-ssl-management command can be used to enable two-way SSL/TLS for the management interfaces. Example of wizard usage:

security enable-ssl-management --interactive
Please provide required pieces of information to enable SSL:
Key-store file name (default management.keystore): server.keystore.jks
Password (blank generated): secret
What is your first and last name? [Unknown]: localhost
What is the name of your organizational unit? [Unknown]:
What is the name of your organization? [Unknown]:
What is the name of your City or Locality? [Unknown]:
What is the name of your State or Province? [Unknown]:
What is the two-letter country code for this unit? [Unknown]:
Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct y/n [y]?
Validity (in days, blank default): 365
Alias (blank generated): localhost
Enable SSL Mutual Authentication y/n (blank n): y
Client certificate (path to pem file): /path/to/client.cer
Validate certificate y/n (blank y):
Trust-store file name (management.truststore): server.truststore.jks
Password (blank generated): secret

SSL options:
key store file: server.keystore.jks
distinguished name: CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
password: secret
validity: 365
alias: localhost
client certificate: /path/to/client.cer
trust store file: server.trustore.jks
trust store password: secret
Server keystore file server.keystore.jks, certificate file server.pem and server.csr file will be generated in server configuration directory.
Server truststore file server.trustore.jks will be generated in server configuration directory.
Do you confirm y/n: y

NB: Once the command is executed, the CLI will reload the server and attempt to reconnect to it. To complete the two-way SSL/TLS authentication, you need to import the server certificate into the client truststore and configure your client to present the client certificate.

Using Elytron subsystem commands:

Elytron subsystem commands can also be used to enable two-way SSL/TLS for the management interfaces.

Obtain or generate your key stores.

Before enabling HTTPS in WildFly, you must obtain or generate the server key store and trust store you plan on using. To generate an example key store and trust store, use the following commands.

Configure a key-store.

/subsystem=elytron/key-store=twoWayKS:add(path=server.keystore.jks,relative-to=jboss.server.config.dir,credential-reference={clear-text=secret},type=JKS)

/subsystem=elytron/key-store=twoWayKS:generate-key-pair(alias=localhost,algorithm=RSA,key-size=1024,validity=365,credential-reference={clear-text=secret},distinguished-name="CN=localhost")

/subsystem=elytron/key-store=twoWayKS:store()

NOTE: The above command uses relative-to to reference the location of the keystore file. Alternatively, you can specify the full path to the keystore in path and omit relative-to.

Export your server certificate.

/subsystem=elytron/key-store=twoWayKS:export-certificate(alias=localhost,path=/path/to/server.cer,pem=true)

Create a key-store for the server trust store and import the client certificate into the server trust store.

/subsystem=elytron/key-store=twoWayTS:add(path=server.truststore.jks,relative-to=jboss.server.config.dir,credential-reference={clear-text=secret},type=JKS)

/subsystem=elytron/key-store=twoWayTS:import-certificate(alias=client,path=/path/to/client.cer,credential-reference={clear-text=secret},trust-cacerts=true)

/subsystem=elytron/key-store=twoWayTS:store()
Configure a key-manager, trust-manager, and server-ssl-context for the server key store and trust store.
/subsystem=elytron/key-manager=twoWayKM:add(key-store=twoWayKS,credential-reference={clear-text=secret})
 
/subsystem=elytron/trust-manager=twoWayTM:add(key-store=twoWayTS)
 
/subsystem=elytron/server-ssl-context=twoWaySSC:add(key-manager=twoWayKM,protocols=["TLSv1.2"],trust-manager=twoWayTM,want-client-auth=true,need-client-auth=true)

IMPORTANT: You need to determine what SSL/TLS protocols you want to support. The example commands above uses TLSv1.2.

Enable HTTPS on the management interface.
/core-service=management/management-interface=http-interface:write-attribute(name=ssl-context, value=twoWaySSC)
 
/core-service=management/management-interface=http-interface:write-attribute(name=secure-socket-binding, value=management-https)
Reload the WildFly instance.
reload

To complete the two-way SSL/TLS authentication, you need to import the server certificate into the client truststore and configure your client to present the client certificate.

Import the server certificate into the client truststore.
$ keytool -importcert -keystore client.truststore.jks -storepass secret -alias localhost -trustcacerts -file /path/to/server.cer
Configure your client to use the client certificate.

You need to configure your client to present the trusted client certificate to the server to complete the two-way SSL/TLS authentication. For example, if using a browser, you need to import the trusted certificate into the browser’s trust store.

Two-way SSL/TLS is now enabled for the management interfaces.

4.3.5. KeyStore manipulation operations

It is possible to perform various KeyStore manipulation operations on an Elytron key-store resource using the management CLI.

Generate a key pair

The generate-key-pair command generates a key pair and wraps the resulting public key in a self-signed X.509 certificate. The generated private key and self-signed certificate will be added to the KeyStore.

/subsystem=elytron/key-store=httpsKS:generate-key-pair(alias=example,algorithm=RSA,key-size=1024,validity=365,credential-reference={clear-text=secret},distinguished-name="CN=www.example.com")
Generate a certificate signing request

The generate-certificate-signing-request command generates a PKCS #10 certificate signing request using a PrivateKeyEntry from the KeyStore. The generated certificate signing request will be output to a file.

/subsystem=elytron/key-store=httpsKS:generate-certificate-signing-request(alias=example,path=server.csr,relative-to=jboss.server.config.dir,distinguished-name="CN=www.example.com",extensions=[{critical=false,name=KeyUsage,value=digitalSignature}],credential-reference={clear-text=secret})
Import a certificate or certificate chain

The import-certificate command imports a certificate or certificate chain from a file into an entry in the KeyStore.

/subsystem=elytron/key-store=httpsKS:import-certificate(alias=example,path=/path/to/certificate_or_chain/file,relative-to=jboss.server.config.dir,credential-reference={clear-text=secret},trust-cacerts=true)
Export a certificate

The export-certificate command exports a certificate from an entry in the KeyStore to a file.

/subsystem=elytron/key-store=httpsKS:export-certificate(alias=example,path=serverCert.cer,relative-to=jboss.server.config.dir,pem=true)
Change an alias

The change-alias command moves an existing KeyStore entry to a new alias.

/subsystem=elytron/key-store=httpsKS:change-alias(alias=example,new-alias=newExample,credential-reference={clear-text=secret})
Store changes made to key-stores

The store command persists any changes that have been made to the file that backs the KeyStore.

/subsystem=elytron/key-store=httpsKS:store()
Obtain a signed certificate from Let’s Encrypt

Before obtaining a signed certificate from Let’s Encrypt, you must configure a Let’s Encrypt account using the following commands.

Create a key-store to hold your Let’s Encrypt account key.
/subsystem=elytron/key-store=accountsKS:add(path=accounts.keystore.jks,relative-to=jboss.server.config.dir,credential-reference={clear-text=secret},type=JKS)
Configure a Let’s Encrypt account
/subsystem=elytron/certificate-authority-account=myLEAccount:add(alias=example,key-store=accountsKS,contact-urls=[mailto:admin@example.org])
Obtain a signed certificate from Let’s Encrypt

The obtain-certificate command creates an account with Let’s Encrypt, if such an account does not already exist, obtains a signed certificate from Let’s Encrypt, and stores it in the KeyStore.

/subsystem=elytron/key-store=httpsKS:obtain-certificate(alias=server,domain-names=[www.example.org],certificate-authority-account=myLEAccount,agree-to-terms-of-service=true,algorithm=RSA,key-size=1024,credential-reference={clear-text=secret})
Revoke a signed certificate

The revoke-certificate command revokes a certificate that was issued by Let’s Encrypt.

/subsystem=elytron/key-store=httpsKS:revoke-certificate(alias=server,reason=keyCompromise,certificate-authority-account=myLEAccount)
Check if a certificate is due for renewal

The should-renew-certificate command checks if a certificate is due for renewal. In particular, it will return true if the certificate expires in less than the given number of days and false otherwise.

/subsystem=elytron/key-store=httpsKS:should-renew-certificate(alias=server,expiration=7)

4.3.6. Certificate authority account operations

It is possible to perform various operations on an Elytron certificate-authority-account resource using the management CLI.

Create an account with the certificate authority

The create-account command creates an account with the certificate authority if one does not already exist.

/subsystem=elytron/certificate-authority-account=myLEAccount:create-account(agree-to-terms-of-service=true)
Update an account with the certificate authority

The update-account command updates an account with the certificate authority.

/subsystem=elytron/certificate-authority-account=myLEAccount:update-account(agree-to-terms-of-service=true)
Change the account key

The change-account-key command changes the key associated with the certificate authority account.

/subsystem=elytron/certificate-authority-account=myLEAccount:change-account-key()
Deactivate the account

The deactivate-account command deactivates the certificate authority account.

/subsystem=elytron/certificate-authority-account=myLEAccount:deactivate-account()
Get metadata

The get-metadata command retrieves the metadata (e.g., terms of service URL, website URL, CAA identities, and whether or not an external account is required), if any, associated with the certificate authority.

/subsystem=elytron/certificate-authority-account=myLEAccount:get-metadata()

4.3.7. Using an ldap-key-store

An ldap-key-store allows you to use a keystore stored in an LDAP server. You can use an ldap-key-store in same way you can use a key-store.

To create and use an ldap-key-store:

Configure a dir-context.

To connect to the LDAP server from WildFly, you need to configure a dir-context that provides the URL as well as the principal used to connect to the server.

Example dir-context

/subsystem=elytron/dir-context=exampleDC:add( \
  url="ldap://127.0.0.1:10389", \
  principal="uid=admin,ou=system", \
  credential-reference={clear-text=secret} \
)
Configure an ldap-key-store.

When configure an ldap-key-store, you need to specify both the dir-context used to connect to the LDAP server as well as how to locate the keystore stored in the LDAP server. At a minimum, this requires you specify a search-path.

Example ldap-key-store

/subsystem=elytron/ldap-key-store=ldapKS:add( \
  dir-context=exampleDC, \
  search-path="ou=Keystores,dc=wildfly,dc=org" \
)
Use the ldap-key-store.

Once you have defined your ldap-key-store, you can use it in the same places where a key-store could be used. For example, you could use an ldap-key-store when configuring HTTPS and Two-Way HTTPS for applications.

4.3.8. Using a filtering-key-store

A filtering-key-store allows you to expose a subset of aliases from an existing key-store, and use it in the same places you could use a key-store. For example, if a keystore contained alias1, alias2, and alias3, but you only wanted to expose alias1 and alias3, a filtering-key-store provides you several ways to do that.

To create a filtering-key-store:

Configure a key-store.
/subsystem=elytron/key-store=myKS:add( \
  path=keystore.jks, \
  relative-to=jboss.server.config.dir, \
  credential-reference={ \
    clear-text=secret \
  }, \
  type=JKS \
)
Configure a filtering-key-store.

When you configure a filtering-key-store, you specify which key-store you want to filter and the alias-filter for filtering aliases from the key-store. The filter can be specified in one of the following formats:

  • alias1,alias3, which is a comma-delimited list of aliases to expose.

  • ALL:-alias2, which exposes all aliases in the keystore except the ones listed.

  • NONE:+alias1:+alias3, which exposes no aliases in the keystore except the ones listed.

This example uses a comma-delimted list to expose alias1 and alias3.

/subsystem=elytron/filtering-key-store=filterKS:add( \
  key-store=myKS, \
  alias-filter="alias1,alias3" \
)
Use the filtering-key-store.

Once you have defined your filtering-key-store, you can use it in the same places where a key-store could be used. For example, you could use a filtering-key-store when configuring HTTPS and Two-Way HTTPS for applications.

4.3.9. Reload a Keystore

You can reload a keystore configured in WildFly from the management CLI. This is useful in cases where you have made changes to certificates referenced by a keystore.

To reload a keystore.

/subsystem=elytron/key-store=httpsKS:load

4.3.10. Reinitialize a Key Manager

You can reinitialize a key-manager configured in WildFly from the management CLI. This is useful in cases where you have made changes in certificates provided by keystore resource and you want to apply this change to new SSL connections without restarting the server.

If the key-store is file based then it must be loaded first.

/subsystem=elytron/key-store=httpsKS:load()

To reinitialize a key-manager.

/subsystem=elytron/key-manager=httpsKM:init()

4.3.11. Reinitialize a Trust Manager

You can reinitialize a trust-manager configured in WildFly from the management CLI. This is useful in cases where you have made changes to certificates provided by keystore resource and you want to apply this change to new SSL connections without restarting the server.

If the key-store is file based then it must be loaded first.

/subsystem=elytron/key-store=httpsKS:load()

To reinitialize a trust-manager.

/subsystem=elytron/trust-manager=httpsTM:init()

4.3.12. Check the Content of a Keystore by Alias

If you add a keystore to the elytron subsystem using the key-store component, you can check the keystore’s contents using the alias child element and reading its attributes.

For example:

/subsystem=elytron/key-store=httpsKS/alias=localhost:read-attribute(name=certificate-chain)
{
    "outcome" => "success",
    "result" => [{
        "type" => "X.509",
        "algorithm" => "RSA",
        "format" => "X.509",
        "public-key" => "30:81:9f:30:0d:06:09:2a:8......

The following attributes can be read:

Attribute Description

certificate

The certificate associated with the alias. If the alias has a certificate chain this will always be undefined.

certificate-chain

The certificate chain associated with the alias.

creation-date

The creation date of the entry represented by this alias.

entry-type

The type of the entry for this alias. Available types: PasswordEntry, PrivateKeyEntry, SecretKeyEntry, TrustedCertificateEntry, and Other. Unrecognized types will be reported as Other.

4.3.13. Custom Components

When configuring SSL/TLS in the elytron subsystem, you can provide and use custom implementations of the following components:

  • key-store

  • key-manager

  • trust-manager

  • client-ssl-context

  • server-ssl-context

  • certificate-authority-account

When creating custom implementations of Elytron components, they must present the appropriate capabilities and requirements.

4.3.14. Default SSLContext

Many libraries that can be used within deployments may require SSL configuration for any connections they establish, these libraries tend to be configurable by the caller or if no configuration is provided fall back to using the default SSLContext for the process available from: -

javax.net.ssl.SSLContext.getDefault();

By default this SSLContext is configured using system properties, however within the WildFly Elytron subsystem it is possible to specify that one of the configured contexts should be associated and used as the default.

To make use of this feature configure your SSLContext as normal, the following command can then be used to specify which SSLContext should be used as the default.

/subsystem=elytron:write-attribute(name=default-ssl-context, value=client-context)

As existing services and deployments could have cached the default SSLContext prior to this being set a reload is required to ensure the default gets set before the deployments are activated.

:reload

Note: If the default-ssl-context attribute is subsequently 'undefined' the standard APIs do not provide us with a mechanism to revert the default so in this situation the Java process would need be restarted.

/subsystem=elytron:undefine-attribute(name=default-ssl-context)
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-restart" => true,
        "process-state" => "restart-required"
    }
}

4.3.15. Configuring SNI

Using the WildFly Elytron subsystem it is possible to configure an SSL context which supports SNI. By supporting SNI if an SNI host name is available whilst the SSLSession is being negotiated a host specific SSLContext will be selected. If no host specific SSLContext is identified either because no host name was received or because there is no match a default SSLContext will be used instead. By identifying a host specific SSLContext it means that a certificate appropriate for that host can be used.

The following command demonstrates how an SNI aware SSLContext can be added: -

[standalone@localhost:9990 /] ./subsystem=elytron/server-ssl-sni-context=test-sni:add(default-ssl-context=jboss,host-context-map={localhost=localhost, wildfly.org=wildfly})
{"outcome" => "success"}

This example assumes that three SSLContexts have been previously defined following the steps available previously in this document, those contexts are jboss, localhost, and wildfly.

During negotiation of the SSLSession if the SNI host name received is localhost then the localhost SSLContext will be used, if the SNI host name is wildfly.org then the wildfly SSLContext will be used. If no SNI host name is received or if we receive a name that does not match this will fallback and use the jboss SSLContext.

The resulting resource looks like: -

[standalone@localhost:9990 /] ./subsystem=elytron/server-ssl-sni-context=test-sni:read-resource
{
    "outcome" => "success",
    "result" => {
        "default-ssl-context" => "jboss",
        "host-context-map" => {
            "localhost" => "localhost",
            "wildfly.org" => "wildfly"
        }
    }
}

Within the host-context-map it is also possible to define wildcard mappings such as * and *.wildfly.org.

4.4. Configuring the Elytron and Security Subsystems

4.4.1. Enable and Disable the Elytron Subsystem

To add the elytron extension required for the elytron subsystem:
/extension=org.wildfly.extension.elytron:add()
To enable the Elytron subsystem in WildFly:
/subsystem=elytron:add
 
reload
To disable the Elytron subsystem in WildFly:
/subsystem=elytron:remove
 
reload

IMPORTANT: Other subsystems within WildFly may have dependencies on the elytron subsystem. If these dependencies are not resolved before disabling it, you will see errors when starting WildFly.

4.4.2. Enable and Disable the Security Subsystem

To disable the security subsystem in WildFly:
/subsystem=security:remove
 
reload

IMPORTANT: Other subsystems within WildFly may have dependencies on the security subsystem. If these dependencies are not resolved before disabling it, you will see errors when starting WildFly.

To enable the security subsystem in WildFly:
/subsystem=security:add
 
reload

4.4.3. Use the Elytron and Security Subsystems in Parallel

By default the elytron and security subsystems will run in parallel if both are enabled. For authentication in applications, you can use the application-security-domain property in the undertow subsystem to configure a security domain in the elytron subsystem.

/subsystem=undertow/application-security-domain=exampleApplicationDomain:add(http-authentication-factory=example-http-auth)

NOTE: This must match the security-domain configured in the jboss-web.xml of your application.

If the application-security-domain is not set, WildFly will look for a security domain configured in the security subsystem that matches the security-domain configured in the jboss-web.xml of your application.

For enabling HTTPS using a legacy security realm, you can use the security-realm attribute in the https-listener section of the undertow subsystem:

/subsystem=undertow/server=default-server/https-listener=https:read-attribute(name=security-realm)
{
    "outcome" => "success",
    "result" => "ApplicationRealm"
}

For enabling HTTPS using elytron, you need to undefine the security-realm attribute and set the ssl-context attribute. As there has to be always configured either ssl-context or security-realm you have to use batch operation when changing between those:

batch
/subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(name=security-realm)
/subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=ssl-context,value=httpsSSC)
run-batch

4.5. Creating Elytron Subsystem Components

4.5.1. Create an Elytron Security Realm

Security realms in the Elytron subsystem, when used in conjunction with security domains, are use for both core management authentication as well as for authentication with applications. Security realms are also specifically typed based on their identity store, for example jdbc-realm, filesystem-realm, properties-realm, etc.

Adding a security realm takes the general form:

/subsystem=elytron/type-of-realm=realmName:add(....)

Examples of adding specific realms, such as jdbc-realm, filesystem-realm, and properties-realm can be found in previous sections.

4.5.2. Create an Elytron Role Decoder

A role decoder converts attributes from the identity provided by the security realm into roles. Role decoders are also specifically typed based on their functionality, for example empty-role-decoder, simple-role-decoder, and custom-role-decoder.

Adding a role decoder takes the general form:

/subsystem=elytron/ROLE-DECODER-TYPE=roleDeoderName:add(....)

4.5.3. Create an Elytron Permission Set

Permission sets can be used to assign permissions to an identity.

Adding a permission set takes the general form:

/subsystem=elytron/permission-set=PermissionSetName:add(permissions=[{class-name="...", module="...", target-name="...", action="..."}...])

where permissions consists of a set of permissions, where each permission has the following attributes:

  • class-name is the fully qualified class name of the permission. This is the only permission attribute that is required.

  • module is the optional module to use to load the permission.

  • target-name is the optional target name to pass to the permission as it is constructed.

  • action is the optional action to pass to the permission as it is constructed.

4.5.4. Create an Elytron Permission Mapper

In addition to roles being assigned to a identity, permissions may also be assigned. A permission mapper assigns permissions to an identity. Permission mappers are also specifically typed based on their functionality, for example logical-permission-mapper, simple-permission-mapper, and custom-permission-mapper.

Adding a permission mapper takes the general form:

/subsystem=elytron/simple-permission-mapper=PermissionMapperName:add(...)

4.5.5. Create an Elytron Role Mapper

A role mapper maps roles after they have been decoded to other roles. Examples include normalizing role names or adding and removing specific roles from principals after they have been decoded. Role mappers are also specifically typed based on their functionality, for example add-prefix-role-mapper, add-suffix-role-mapper, and constant-role-mapper.

Adding a role mapper takes the general form:

/subsystem=elytron/ROLEM-MAPPER-TYPE=roleMapperName:add(...)

4.5.6. Create an Elytron Security Domain

Security domains in the Elytron subsystem, when used in conjunction with security realms, are use for both core management authentication as well as for authentication with applications.

Adding a security domain takes the general form:

/subsystem=elytron/security-domain=domainName:add(realms=[{realm=realmName,role-decoder=roleDecoderName}],default-realm=realmName,permission-mapper=permissionMapperName,role-mapper=roleMapperName,...)

4.5.7. Create an Elytron Authentication Factory

An authentication factory is an authentication policy used for specific authentication mechanisms. Authenticaion factories are specifically based on the authentication mechanism, for example http-authentication-factory and
sasl-authentication-factory and kerberos-security-factory.

Adding an authentication factory takes the general form:

/subsystem=elytron/AUTH-FACTORY-TYPE=authFactoryName:add(....)

4.5.8. Create an Elytron Policy Provider

Elytron subsystem provides a specific resource definition that can be used to configure a default ruby Policy provider. The subsystem allows you to define multiple policy providers but select a single one as the default:

/subsystem=elytron/policy=policy-provider-a:add(custom-policy=\[{name=policy-provider-a, class-name=MyPolicyProviderA, module=x.y.z}\])

5. Using Elytron within WildFly

5.1. Using the Out of the Box Elytron Components

5.1.1. Securing Management Interfaces

You can find more details on the enabling WildFly to use the out of the box Elytron components for securing the management interfaces in the Default Management Authentication Configuration section.

5.1.2. Securing Applications

The elytron subsystem provides application-security-domain by default which can be used to secure applications. For more details on how application-security-domain is configured, see the Default Application Authentication Configuration section.

To configure applications to use application-security-domain, see Set Up and Configure Authentication for Applications. You can also override the default behavior of all applications using the steps in Override an Application’s Authentication Configuration.

5.1.3. Using SSL/TLS

WildFly does provide a default one-way SSL/TLS configuration using the legacy core management authentication but does not provide one in the elytron subsystem. You can find more details on configuring SSL/TLS using the elytron subsystem for both the management interfaces as well as for applications in Configure SSL/TLS

5.1.4. Using Elytron with Other Subsystems

In addition to securing applications and management interfaces, Elytron also integrates with other subsystems in WildFly.

Subsystem Details

batch-jberet

You can configure the batch-jberet to run batch jobs using an Elytron security domain.

datasources

You can use a credential store or an Elytron security domain to provide authentication information in a datasource definition.

messaging-activemq

You can secure remote connections to the remote connections used by the messaging-activemq subsystem.

iiop-openjdk

You can use the elytron subsystem to configure SSL/TLS between clients and servers using the iiop-openjdk subsystem.

mail

You can use a credential store to provide authentication information in a server definition in the mail subsystem.

undertow

You can use the elytron subsystem to configure both SSL/TLS and application authentication.

5.2. Undertow Subsystem

As a web application is deployed the name of the security domain required by that application will be identified, this will either be from within the deployment or if the deployment does not have a security domain the default-security-domain as defined on the Undertow subsystem will be assumed. By default it is assumed that the security domain maps to a PicketBox domain defined in the legacy security subsystem, however an application-security-domain resource can be added to the Undertow subsystem which maps from the name of the security domain required by the application to the appropriate WildFly Elytron configuration.

As an example in it’s simplest form a mapping can be added as: -

/subsystem=undertow/application-security-domain=MyAppSecurity:add(security-domain=ApplicationDomain)

Which results in: -

<subsystem xmlns="urn:jboss:domain:undertow:7.0" ... default-security-domain="other">
...
    <application-security-domains>
        <application-security-domain name="MyAppSecurity" security-domain="ApplicationDomain"/>
    </application-security-domains>
...
</subsystem>

Note: If the deployment was already deployed at this point the application server should be reloaded or the deployment redeployed for the application security domain mapping to take effect.

Here we are mapping from the applications security domain MyAppSecurity to the WildFly Elytron defined domain ApplicationDomain.

This simple form is suitable where a deployment is using the standard HTTP mechanisms as defined within the Servlet specification i.e. BASIC, CLIENT_CERT, DIGEST, FORM and authentication will be performed against the ApplicationDomain security domain. This form is also suitable where an application is not using any authentication mechanisms and instead is using programatic authentication or even wishes to obtain the SecurityDomain associated with the deployment and use it directly.

An advanced form of the mapping can be added as: -

/subsystem=undertow/application-security-domain=MyAppSecurity:add(http-authentication-factory=application-http-authentication)

Which results in: -

<subsystem xmlns="urn:jboss:domain:undertow:7.0" ... default-security-domain="other">
...
    <application-security-domains>
        <application-security-domain name="MyAppSecurity" http-authentication-factory="application-http-authentication"/>
    </application-security-domains>
...
</subsystem>

In this form of the configuration instead of referencing a security domain a http-authentication-factory is referenced instead, this is the factory that will be used to obtain the instances of the authentication mechansisms and is in turn associated with the security domain. The standard mechanisms as defined in the Servlet specification can be used in this way but this approach also allows for other mechanisms to be used such as SPNEGO which requires additional configuration or even plug-in custom mechanism implementations.

When the advanced form of the mapping is used a further configuration option is available: -

  • override-deployment-config

The referenced http-authentication-factory can return a complete set of authentication mechanisms, by default these are filtered to just match the mechanisms requested by the application - if this option is set to true then the mechanisms offered by the factory will override the mechanisms requested by the application. One example of where this could be useful is say an application has been developed to support FORM authentication, by overriding the mechanisms the application could be updated to support SPNEGO, and FORM authentication without any modifications to the deployment.

The application-security-domain resource also has one additional option enable-jacc, if this is set to true JACC will be enabled for any deployments matching against this mapping.

5.2.1. Runtime Information

Where an application-security-domain mapping is in use it can be useful to double check that deployments did match against it as expected, if the resource is read with include-runtime=true the deployments that are associated with the mapping will also be shown: -

[standalone@localhost:9990 /] /subsystem=undertow/application-security-domain=MyAppSecurity:read-resource(include-runtime=true)
{
    "outcome" => "success",
    "result" => {
        "enable-jacc" => false,
        "http-authentication-factory" => undefined,
        "override-deployment-config" => false,
        "referencing-deployments" => ["simple-webapp.war"],
        "security-domain" => "ApplicationDomain",
        "setting" => undefined
    }
}

In this output the referencing-deployments attribute shows that the deployment simple-webapp.war has been deployed using this mapping.

5.3. EJB Subsystem

Configuration can be added to the EJB subsystem to map a security domain name referenced in a deployment to an Elytron security domain:

/subsystem=ejb3/application-security-domain=MyAppSecurity:add(security-domain=ApplicationDomain)

Which results in:

<subsystem xmlns="urn:jboss:domain:ejb3:5.0">
...
    <application-security-domains>
        <application-security-domain name="MyAppSecurity" security-domain="ApplicationDomain"/>
    </application-security-domains>
...
</subsystem>

Note: If the deployment was already deployed at this point the application server should be reloaded or the deployment redeployed for the application security domain mapping to take effect.

An application-security-domain has two main attributes:

  • name - the name of the security domain as specified in a deployment

  • security-domain - a reference to the Elytron security domain that should be used

When an application security domain mapping is configured for a bean in a deployment, this indicates that security should be handled by Elytron.

5.4. WebServices Subsystem

There is adapter in webservices subsystem to make authentication works for elytron security domain automatically. Like configure with legacy security domain, you can configure elytron security domain in deployment descriptor or annotation to secure webservice endpoint.

When Elytron security is enabled, JAAS subject or principal can be pushed to jbossws-cxf endpoint’s SecurityContext to propagate authenticated identity to EJB container. Here is a CXF interceptor example to propagate authenticated information to EJB container :

public class PropagateSecurityInterceptor extends WSS4JInInterceptor {

   public PropagateSecurityInterceptor() {
      super();
      getAfter().add(PolicyBasedWSS4JInInterceptor.class.getName());
   }

   @Override
   public void handleMessage(SoapMessage message) throws Fault {
      ...
      final Endpoint endpoint = message.getExchange().get(Endpoint.class);
      final SecurityDomainContext securityDomainContext = endpoint.getSecurityDomainContext();
      //push subject principal retrieved from CXF to ElytronSecurityDomainContext
      securityDomainContext.pushSubjectContext(subject, principal, null)
   }

}

5.5. Legacy Security Subsystem

As previously described, Elytron based security is configured by chaining together different capability references to form a complete security policy. To allow an incremental migration from the legacy Security subsystem some of the major components of this subsystem can be mapped to Elytron capabilities and used within an Elytron based set up.

6. Client Authentication with Elytron Client

WildFly Elytron uses the Elytron Client project to enable remote clients to authenticate using Elytron. Elytron Client has the following components:

Component Description

Authentication Configuration

Contains authentication information such as usernames, passwords, allowed SASL mechanisms, and the security realm to use during digest authentication.

MatchRule

Rule used for deciding which authentication configuration to use.

Authentication Context

Set of rules and authentication configurations to use with a client for establishing a connection.

When a connection is established, the client makes use of an authentication context, which gives rules that match which authentication configuration is used with an outbound connection. For example, you could have a rules that use one authentication configuration when connecting to server1 and another authentication configuration when connecting with server2. The authentication context is comprised of a set of authentication configurations and a set of rules that define how they are selected when establishing a connection. An authentication context can also reference ssl-context and can be matched with rules.

To create a client that uses security information when establishing a connection:

  • Create one or more authentication configurations.

  • Create an authentication context by creating rule and authentication configuration pairs.

  • Create a runnable for establishing your connection.

  • Use your authentication context to run your runnable.

When you establish your connection, Elytron Client will use the set of rules provided by the authentication context to match the correct authentication configuration to use during authentication.

You can use one of the following approaches to use security information when establishing a client connection.

IMPORTANT: When using Elytron Client to make EJB calls, any hard-coded programatic authentication information, such as setting Context.SECURITY_PRINCIPAL in the javax.naming.InitialContext, will override the Elytron Client configuration.

6.1. The Configuration File Approach

The configuration file approach involves creating an XML file with your authentication configuration, authentication context, and match rules.

custom-config.xml

<configuration>
    <authentication-client xmlns="urn:elytron:1.0">
        <authentication-rules>
            <rule use-configuration="monitor">
                <match-host name="127.0.0.1" />
            </rule>
            <rule use-configuration="administrator">
                <match-host name="localhost" />
            </rule>
        </authentication-rules>
        <authentication-configurations>
            <configuration name="monitor">
                <allow-sasl-mechanisms names="DIGEST-MD5" />
                 <use-service-loader-providers />
                 <set-user-name name="monitor" />
                 <credentials>
                     <clear-password password="password1!" />
                 </credentials>
                 <set-mechanism-realm name="ManagementRealm" />
             </configuration>

             <configuration name="administrator">
                <allow-sasl-mechanisms names="DIGEST-MD5" />
                 <use-service-loader-providers />
                 <set-user-name name="administrator" />
                 <credentials>
                     <clear-password password="password1!" />
                 </credentials>
                 <set-mechanism-realm name="ManagementRealm" />
             </configuration>
        </authentication-configurations>
    </authentication-client>
</configuration>

You can then reference that file in your client’s code by setting a system property when running your client.

$ java -Dwildfly.config.url=/path/to/the.xml .....

IMPORTANT: If you use the The Programmatic Approach, it will override any provided configuration files even if the wildfly.config.url system property is set.

When creating rules, you can look for matches on various parameters such as hostname, port, protocol, or username. A full list of options for MatchRule are available in the Javadocs. Rules are evaluated in the order in which they are configured.

Common Rules

Rule Description

match-domain

Takes a single name attribute specifying the security domain to match against.

match-host

Takes a single name attribute specifying the hostname to match against. For example, the host 127.0.0.1 would match on http://127.0.0.1:9990/my/path .

match-no-user

Matches against URIs with no user.

match-path

Takes a single name attribute specifying the path to match against. For example, the path /my/path/ would match on http://127.0.0.1:9990/my/path .

match-port

Takes a single name attribute specifying the port to match against. For example, the port 9990 would match on http://127.0.0.1:9990/my/path .

match-protocol

Takes a single name attribute specifying the protocol to match against. For example, the protocol http would match on http://127.0.0.1:9990/my/path .

match-purpose

Takes a names attribute specifying the list of purposes to match against.

match-urn

Takes a single name attribute specifying the URN to match against.

match-user

Takes a single name attribute specifying the user to match against.

6.2. The Programmatic Approach

The programatic approach configures all the Elytron Client configuration in the client’s code:

//create your authentication configuration
AuthenticationConfiguration adminConfig =
    AuthenticationConfiguration.EMPTY
      .useProviders(() -> new Provider[] { new WildFlyElytronProvider() })
      .allowSaslMechanisms("DIGEST-MD5")
      .useRealm("ManagementRealm")
      .useName("administrator")
      .usePassword("password1!");
 
//create your authentication context
AuthenticationContext context = AuthenticationContext.empty();
context = context.with(MatchRule.ALL.matchHost("127.0.0.1"), adminConfig);
 
 
//create your runnable for establishing a connection
Runnable runnable =
    new Runnable() {
      public void run() {
        try {
           //Establish your connection and do some work
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    };
 
//use your authentication context to run your client
context.run(runnable);

When adding configuration details to AuthenticationConfiguration and AuthenticationContext, each method call returns a new instance of that object. For example, if you wanted separate configurations when connecting over different hostnames, you could do the following:

//create your authentication configuration
AuthenticationConfiguration commonConfig =
    AuthenticationConfiguration.EMPTY
      .useProviders(() -> new Provider[] { new WildFlyElytronProvider() })
      .allowSaslMechanisms("DIGEST-MD5")
      .useRealm("ManagementRealm");
 
AuthenticationConfiguration administrator =
    commonConfig
      .useName("administrator")
      .usePassword("password1!");


AuthenticationConfiguration monitor =
    commonConfig
      .useName("monitor")
      .usePassword("password1!");
 
 
//create your authentication context
AuthenticationContext context = AuthenticationContext.empty();
context = context.with(MatchRule.ALL.matchHost("127.0.0.1"), administrator);
context = context.with(MatchRule.ALL.matchHost("localhost"), monitor);

Common Rules

Rule Description

matchLocalSecurityDomain(String name)

This is the same as match-domain in the configuration file approach.

matchNoUser()

This is the same as match-no-user in the configuration file approach.

matchPath(String pathSpec)

This is the same as match-path in the configuration file approach.

matchPort(int port)

This is the same as match-port in the configuration file approach.

matchProtocol(String protoName)

This is the same as match-port in the configuration file approach.

matchPurpose(String purpose)

Create a new rule which is the same as this rule, but also matches the given purpose name.

matchPurposes(String…​ purposes)

This is the same as match-purpose in the configuration file approach.

matchUrnName(String name)

This is the same as match-urn in the configuration file approach.

matchUser(String userSpec)

This is the same as match-user in the configuration file approach.

Also, instead of starting with an empty authentication configuration, you can start with the current configured one by using captureCurrent().

//create your authentication configuration
AuthenticationConfiguration commonConfig = AuthenticationConfiguration.captureCurrent();

Using captureCurrent() will capture any previously established authentication context and use it as your new base configuration. A authentication context is established once its been activated by calling run(). If captureCurrent() is called and no context is currently active, it will try and use the default authentication if available. You can find more details about this in The Configuration File Approach, The Default Configuration Approach, and Using Elytron Client with Clients Deployed to WildFly sections.

Using AuthenticationConfiguration.EMPTY should only be used as a base to build a configuration on top of and should not be used on its own. It provides a configuration that uses the JVM-wide registered providers and enables anonymous authentication.

When specifying the providers on top of the AuthenticationConfiguration.EMPTY configuration, you can specify a custom list, but most users should use WildFlyElytronProvider() providers.

When creating an authentication context, using the context.with(…​) will create a new context that merges the rules and authentication configuration from the current context with the provided rule and authentication configuration. The provided rule and authentication configuration will appear after the ones in the current context.

6.3. The Default Configuration Approach

The default configuration approach relies completely on the configuration provided by Elytron Client:

//create your runnable for establishing a connection
Runnable runnable =
    new Runnable() {
      public void run() {
        try {
           //Establish your connection and do some work
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    };
 
// run runnable directly
runnable.run();

To provide a default configuration, Elytron Client tries to auto-discover a wildfly-config.xml file on the filesystem. It looks in the following locations:

  • Location specified by the wildfly.config.url system property set outside of the client code.

  • The classpath root directory.

  • The META-INF directory on the classpath.

If it does not find one, it will try and use the default wildfly-config.xml provided in the $WILDFLY_HOME/bin/client/jboss-client.jar.

default wildfly-config.xml

<configuration>
  <authentication-client xmlns="urn:elytron:1.0">
    <authentication-rules>
      <rule use-configuration="default" />
    </authentication-rules>
    <authentication-configurations>
      <configuration name="default">
        <allow-all-sasl-mechanisms />
        <set-mechanism-properties>
          <property key="wildfly.sasl.local-user.quiet-auth" value="true" />
        </set-mechanism-properties>
        <use-service-loader-providers />
      </configuration>
    </authentication-configurations>
  </authentication-client>
</configuration>

6.4. Using Elytron Client with Clients Deployed to WildFly

Clients deployed to WildFly can also make use of Elytron Client. In cases where you have included a wildfly-config.xml with your deployment or the system property has been set, an AuthenticationContext is automatically parsed and created from that file.

To load a configuration file outside of the deployment, you can use the parseAuthenticationClientConfiguration(URI) method. This method will return an AuthentcationContext which you can then use in your client’s code using the The Programmatic Approach.

Additionally, clients will also automatically parse and create an AuthenticationContext from the client configuration provided by the elytron subsystem. The client configuration in the elytron subsystem can also take advantage of other components defined in the elytron subsystem such as credential stores. If client configuration is provided by BOTH the deployment and the elytron subsystem, the elytron subsystem’s configuration is used.

6.5. Client configuration using wildfly-config.xml

Prior to WildFly 11, many WildFly client libraries used different configuration strategies. WildFly 11 introduces a new wildfly-config.xml file which unifies all client configuration in a single place. In addition to being able to configure authentication using Elytron as described in the previous section, a wildfly-config.xml file can also be used to:

6.5.1. Configure EJB client connections, global interceptors, and invocation timeout

Example configuration:

wildfly-config.xml
<configuration>
...
    <jboss-ejb-client xmlns="urn:jboss:wildfly-client-ejb:3.0">
        <invocation-timeout seconds="10"/>
        <connections>
            <connection uri="remote+http://10.20.30.40:8080"/>
        </connections>
        <global-interceptors>
            <interceptor class="org.jboss.example.ExampleInterceptor"/>
        </global-interceptors>
    </jboss-ejb-client>
...
</configuration>

6.5.2. Configure HTTP client

Example configuration:

wildfly-config.xml
<configuration>
...
    <http-client xmlns="urn:wildfly-http-client:1.0">
        <defaults>
            <eagerly-acquire-session value="true" />
            <buffer-pool buffer-size="2000" max-size="10" direct="true" thread-local-size="1" />
        </defaults>
    </http-client>
...
</configuration>

6.5.3. Configure a remoting endpoint

Example configuration:

wildfly-config.xml
<configuration>
...
    <endpoint xmlns="urn:jboss-remoting:5.0">
        <connections>
            <connection destination="remote+http://10.20.30.40:8080" read-timeout="50" write-timeout="50" heartbeat-interval="10000"/>
        </connections>
    </endpoint>
...
</configuration>

6.5.4. Configure the default XNIO worker

Example configuration:

wildfly-config.xml

<configuration>
...
    <worker xmlns="urn:xnio:3.5">
        <io-threads value="10"/>
        <task-keepalive value="100"/>
        <stack-size value="5000"/>
    </worker>
...
</configuration>
Note that WildFly client libraries do have reasonable default configuration. Thus, adding configuration for these clients to wildfly-config.xml isn’t mandatory.

7. Elytron and Java Authorization Contract for Containers (JACC)

This document will guide you on how to enable JACC using Elytron Subsystem.

7.1. Disabling JACC in Legacy Security Subsystem (PicketBox)

By default, the application server uses the legacy security subsystem (PicketBox) to configure the JACC policy provider and factory. The default configuration maps to implementations from PicketBox.

In order to use Elytron to manage JACC configuration (or any other policy you want to install to the application server) you must first disable JACC in legacy security subsystem. For that, please execute the following CLI command:

/subsystem=security:write-attribute(name=initialize-jacc, value=false)

The command above tells the legacy security subsystem to not initialize any JACC related configuration, but rely on the policies defined via Elytron subsystem as we’ll see in the next sections.

7.2. Defining a JACC Policy Provider

Elytron subsystem provides a built-in policy provider based on JACC specification. To create the policy provider you can execute a CLI command as follows:

[standalone@localhost:9990 /] /subsystem=elytron/policy=jacc:add(jacc-policy={})

After executing the command above, please reload the server configuration as follows:

[standalone@localhost:9990 /] reload

7.3. Enabling JACC to a Web Deployment

Once JACC Policy Provider is defined you can enable JACC to web deployments by executing the following command:

[standalone@localhost:9990 /] /subsystem=undertow/application-security-domain=other:add(http-authentication-factory=application-http-authentication,enable-jacc=true)

The command above defines a default security domain for applications if none is provided in jboss-web.xml. In case you already have a application-security-domain defined and just want to enable JACC you can execute a command as follows:

[standalone@localhost:9990 /] /subsystem=undertow/application-security-domain=my-security-domain:write-attribute(name=enable-jacc,value=true)

7.4. Enabling JACC to a EJB Deployment

Once JACC Policy Provider is defined you can enable JACC to EJB deployments by executing the following command:

[standalone@localhost:9990 /] /subsystem=ejb3/application-security-domain=other:add(security-domain=ApplicationDomain,enable-jacc=true)

The command above defines a default security domain for EJBs. In case you already have a *application-security-domain *defined and just want to enable JACC you can execute a command as follows:

[standalone@localhost:9990 /] /subsystem=ejb3/application-security-domain=my-security-domain:write-attribute(name=enable-jacc,value=true)

9. Elytron and Java Authentication SPI for Containers (JASPI)

8. Introduction

Starting from WildFly 15 an implementation of the Servlet profile from the Java Authentication SPI for Containers (JSR-196 / JASPI) is also provided by the WildFly Elytron subsystem allowing tighter integration with the security features provided by WildFly Elytron. This JASPI implementation is available out of the box with minimal steps required to use it for deployments, this section of the documentation describes how to make use of it and the features it provides.

8.1. Activation

Presently it is the Servlet profile from the JASPI specification which is supported by this integration, the following information applies to web applications deployed to WildFly.

For the JASPI integration to be enabled for a web application that web application needs to be associated with either an Elytron http-authentication-factory or a security-domain - by doing this the WildFly Elytron security handlers will be installed for the deployment and the WildFly Elytron security framework activated for the deployment. This is all that is required for a deployment to be 'securable' using a JASPI configuration.

Once the WildFly Elytron security framework is activate for a deployment at the time requests are being handled the globally registered AuthConfigFactory will be queried to identify if an AuthConfigProvider has been registered which should be used for that deployment - if an AuthConfigProvider is found then JASPI authentication will be used instead of the deployments authentication configuration. If no AuthConfigProvider is found then the authentication configuration for the deployment will be used instead, this could mean authentication mechanisms from a http-authentication-factory are used or mechanisms specified in the web.xml are used or it could even mean no authentication is performed if the application does not have any mechanisms defined.

Any updates made to the AuthConfigFactory are immediately available, this means that if an AuthConfigProvider is registered which is a match for an existing application it will start to be used immediately without requiring redeployment of the application.

All web applications deployed to WildFly have a security domain which will be resolved in the following order: - . From the deployment descriptors / annotations of the deployment being deployed. . The value defined on the default-security-domain attribute on the Undertow subsystem. . Default to 'other'.

We assume that this security domain is a reference to a PicketBox security domain so the final step in activation is ensuring this is mapped to WildFly Elytron using an application-security-domain resource in the Undertow subsystem. This mapping can either reference a WildFly Elytron security domain directly or it can reference a http-authentication-factory resource to obtain instances of authentication mechanisms.

e.g.

/subsystem=undertow/application-security-domain=MyAppSecurity:add(security-domain=ApplicationDomain)

or

/subsystem=undertow/application-security-domain=MyAppSecurity:add(http-authentication-factory=application-http-authentication)

Although this latter form references a http-authentication-factory that in turn will reference a security domain - for both examples the referenced security domain is associated with the deployment.

The minimal steps to enable the JASPI integration are: - . Leave the default-security-domain attribute on the Undertow subsystem undefined so it defaults to 'other'. . Add an application-security-domain mapping from 'other' to a WildFly Elytron security domain.

All deployments that do not specify their own security domain will be assigned this default mapping automatically which will activate the WildFly Elytron handlers and subsequently make JASPI available for that deployment.

The security domain associated with a deployment in these steps is the security domain that will be wrapped in a CallbackHandler to be passed into the ServerAuthModule instances used for authentication.

8.1.1. Additional Options

On the application-security-domain resource two additional attributes have been added to allow some further control of the JASPI behaviour.

  • enable-jaspi - Can be set to false to disable JASPI support for all deployments using this mapping.

  • integrated-jaspi - By default all identities are loaded from the security domain, if set to false ad-hoc identities will be created instead.

8.2. Subsystem Configuration

One way to register a configuration which will result in an AuthConfigProvider being returned for a deployment is to register a jaspi-configuration in the Elytron subsystem.

The following command demonstrates how to add a configuration containing two ServerAuthModule definitions: -

./subsystem=elytron/jaspi-configuration=simple-configuration:add(layer=HttpServlet, application-context="default-host /webctx", \
        description="Elytron Test Configuration", \
        server-auth-modules=[{class-name=org.wildfly.security.examples.jaspi.SimpleServerAuthModule, module=org.wildfly.security.examples.jaspi, flag=OPTIONAL, options={a=b, c=d}}, \
            {class-name=org.wildfly.security.examples.jaspi.SecondServerAuthModule, module=org.wildfly.security.examples.jaspi}])

This results in the following configuration being persisted: -

<jaspi>
    <jaspi-configuration name="simple-configuration" layer="HttpServlet" application-context="default-host /webctx" description="Elytron Test Configuration">
        <server-auth-modules>
            <server-auth-module class-name="org.wildfly.security.examples.jaspi.SimpleServerAuthModule" module="org.wildfly.security.examples.jaspi" flag="OPTIONAL">
                <options>
                    <property name="a" value="b"/>
                    <property name="c" value="d"/>
                </options>
            </server-auth-module>
            <server-auth-module class-name="org.wildfly.security.examples.jaspi.SecondServerAuthModule" module="org.wildfly.security.examples.jaspi"/>
        </server-auth-modules>
    </jaspi-configuration>
</jaspi>

The name attribute is just a name that allows the resource to be referenced in the management model.

The layer and application-context attributes are used when registering this configuration with the AuthConfigFactory - both of these attributes can be omitted allowing wildcard matching. The description attribute is also optional and is used to provide a description to the AuthConfigFactory.

Within the configuration one or more server-auth-module instances can be defined with the following attributes. * class-name - The fully qualified class name of the ServerAuthModule. * module - The module to load the ServerAuthModule from. * flag - The control flag to indicate how this module operates in relation to the other modules. * options - Configuration options to be passed into the ServerAuthModule on initialisation.

Configuration defined in this way is immediately registered with the AuthConfigFactory so any existing deployments using the WildFly Elytron security framework that match against the layer and application-context will immediately start to make use of the configuration.

8.3. Programatic Configuration

The APIs defined within the JASPI specification allow for applications to dynamically register custom AuthConfigProvider instances, however the specification does not provide the actual implementations to use or a standard way to create instances of the implementations, the WildFly Elytron project contains a simple utility that can be used by deployments to help with this: -

org.wildfly.security.auth.jaspi.JaspiConfigurationBuilder

The following piece of code illustrates how this API can be used to register a similar configuration to the one illustrated in the subsystem.

String registraionId = JaspiConfigurationBuilder.builder("HttpServlet", servletContext.getVirtualServerName() + " " + servletContext.getContextPath())
    .addAuthModuleFactory(SimpleServerAuthModule::new, Flag.OPTIONAL, Collections.singletonMap("a", "b"))
    .addAuthModuleFactory(SecondServerAuthModule::new)
.register();

As an example this code could be executed within the init() method of a Servlet to register the AuthConfigProvider specific for that deployment, in this code example the application context has also been assembled by consulting the ServletContext.

The register method returns the resulting registration ID that can also be used to subsequently remove this registration directly from the AuthConfigFactory.

As with the subsystem configuration this call has an immediate effect and will be live for all web applications using the WildFly Elytron security framework immediately.

8.4. Authentication Process

8.4.1. CallbackHandler

Based on the configuration on the application-security-domain resource in the Undertow subsystem the CallbackHandler passed to the ServerAuthModule in an integrated or non-integrated mode.

8.4.2. Integrated

When operating in integrated mode although the ServerAuthModule instances will be handling the actual authentication the resulting identity will be loaded from the referenced SecurityDomain using the SecurityRealms referenced by that SecurityDomain, it is still possible in this mode to override the roles that will be assigned within the Servlet container.

The advantage of this mode is that ServerAuthModules are able to take advantage of the WildFly Elytron configuration for the loading of identities so identities stored in usual locations such as databases and LDAP can be loaded without the ServerAuthModule needing to be aware of these locations, additionally other WildFly Elytron configuration can be applied such as role and permission mapping. The referenced SecurityDomain can also be referenced in other places such as for SASL authentication or other non JASPI applications all backed by a common repository of identities.

In this mode the CallbackHandlers operate as follows: -

  • PasswordValidationCallback

    The username and password will be used with the SecurityDomain to perform an authentication, if successful there is now an authenticated identity.
  • CallerPrincipalCallback

    This Callback is used to establish the authorized identity / the identity that will be seen once the request reached the web application.
    If an authenticated identity has already been established via the PasswordValidationCallback this Callback is interpreted as a run-as request and authorization checks are performed to ensure the authenticated identity is authorized to run as the identity specified in this Callback.  If no authenticated identity has been established by a PasswordValidationCallback it is assumed the ServerAuthModule has handled the authentication step so this Callback will cause the specified identity to be loaded from the SecurityDomain and an authorization check to verify this identity has the LoginPermission.
    If a Callback is received with a null Principal and name then if an authenticated identity has already been established authorization will be performed as that identity, if no identity has been established then authorization of the anonymous identity will be performed.  Where authorization of the anonymous identity is performed the SecurityDomain must have been configured to grant the anonymous identity the LoginPermission otherwise authorization will fail.
  • GroupPrincipalCallback

    By default in this mode the attribute loading, role decoding, and role mapping configured on the security domain will be used to establish the identity - if this Callback is received the groups specified will be taken as the roles that will be assigned to the identity whilst the request is in the servlet container.  These roles will be visible in the servlet container only.

8.4.3. Non Integrated

When operating in non-integrated mode the ServerAuthModules are completely responsible for all authentication AND identity management, the Callbacks specified in the specification can be used to establish an identity. The resulting identity will be created on the SecurityDomain but it will be independent of any identities stored in referenced SecurityRealms.

The advantage of this mode is that JASPI configurations that are able to 100% handle the identities can be deployed to the application server without requiring anything beyond a simple SecurityDomain definitions, there is no need for this SecurityDomain to actually contain the identities that will be used at runtime. The disadvantage of this mode is that the ServerAuthModule is now reposible for all identity handling potenitally making the implementation much more complex.

In this mode the CallbackHandlers operate as follows: -

  • PasswordValidationCallback

    The Callback is not supported in this mode, the purpose of this mode is for the ServerAuthModule to operate independently of the referenced SecurityDomain so requesting a password to be validated would not be suitable.
  • CallerPrincipalCallback

    This Callback is used to establish the Principal for the resulting identity, as the ServerAuthModule is handling all of the identity checking requirements no checks are performed to verify if the identity exists in the security domain and no authorization checks are performed.
    If a Callback is received with a null Principal and name then then the identity will be established as the anonymous identity, as the ServerAuthModule is making the decisions no authorizaton check will be performed with the SecurityDomain.
  • GroupPrincipalCallback

    As the identity is created in this mode without loading from the SecurityDomain it will by default have no roles assigned, if this Callback is received the groups will be taken and assigned to the resulting identity whilst the request is in the servlet container. These roles will be visible in the servlet container only.

8.4.4. validateRequest

During the call to validateRequest on the ServerAuthContext the individual ServerAuthModule instances will be called in the order they are defined. A control flag can also be specified for each module, this defines how the response should be interpreted and if processing should continue to the next auth module or return immediately.

Control Flags

Where the configuration was provided either within the WildFly Elytron subsystem or using the JaspiConfigurationBuilder API it is possible to associate a control flag with each ServerAuthModule - if one is not specified we assume REQUIRED. The flags have the following meanings depending on their result.

Flag

AuthStatus.SEND_SUCCESS

AuthStatus.SEND_FAILURE, AuthStatus.SEND_CONTINUE

Required

Validation will continue to the remaining modules, provided the requirements of the remaining modules are satisfied the request will be allowed to proceed to authorization.

Validation will continue to the remaining modules, however regardless of their outcome the validation is not successful so control will return to the client.

Requisite

Validation will continue to the remaining modules, provided the requirements of the remaining modules are satisfied the request will be allowed to proceed to authorization.

The request will return immediately to the client.

Sufficient

Validation is deemed successful and complete, provided no previous Required or Requisite module has returned an AuthStatus other than AuthStatus.SUCCESS the request will proceed to authorization of the secured resource.

Validation will continue down the list of remaining modules, this status will only affect the decision if there are no REQUIRED or REQUISITE modules.

Optional

Validation will continue to the remaining modules, provided no 'Required' or 'Requisite' modules have not returned SUCCESS this will be sufficient for validation to be deemed successful and for the request to proceed to the authorization stage and the secured resource.

Validation will continue down the list of remaining modules, this status will only affect the decision if there are no REQUIRED or REQUISITE modules.

For all ServerAuthModule instances if they throw an AuthException an error will be immediately reported to the client without further modules being called.

8.4.5. secureResponse

During the call to secureResponse each ServerAuthMdoule is called but this time in reverse order. Where a module only undertakes an action in secureResponse if it undertook an action in validateResponse it is the responsibility of the module to track this.

The control flag has no effect on secureResponse processing, processing ends when one of the following is true: - . All of the ServerAuthModule instances have been called. . A module returns AuthStatus.SEND_FAILURE. . A module throws an AuthException.

8.4.6. SecurityIdentity

Once the authentication process has completed a org.wildfly.security.auth.server.SecurityIdentity for the deployments SecurityDomain will have been created as a result of the Callbacks to the CallbackHandler, depending on the Callbacks this will either be an identity loaded directly from the SecurityDomain or will be an ad-hoc identity described by the callbacks. This SecurityIdentity will be associated with the request as we do for other authentication mechanisms

10. Using KeyCloak with WildFly Elytron

TBD

11. Bearer Token Authorization

Bearer Token Authorization is the process of authorizing HTTP requests based on the existence and validity of a bearer token representing a subject and his access context, where the token provides valuable information to determine the subject of the call as well whether or not a HTTP resource can be accessed.

Elytron supports bearer token authorization by providing a BEARER_TOKEN HTTP authentication mechanism based on RFC-6750 and an specific realm implementation, the token-realm, to validate tokens using the JWT format (for instance, OpenID Connect ID Tokens) or opaque tokens issued by any OAuth2 compliant authorization server.

11.1. How it Works

When a HTTP request arrives to your application, the BEARER_TOKEN mechanism will check if a bearer token was provided by checking the existence of an Authorization HTTP header with the following format:

GET /resource HTTP/1.1
Host: server.example.com
Authorization: Bearer mF_9.B5f-4.1JqM

If no bearer token was provided, the mechanism will respond with a 401 HTTP status code as follows:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example"

When a bearer token is provided, the mechanism will extract the token from the request (in the example above, the token is represented by the string mF_9.B5f-4.1JqM) and pass it over to the token-realm in order to check if the token is valid and can be used to build a security context based on its information. Note that the BEARER_TOKEN mechanism is only responsible to check and extract bearer tokens from an HTTP request, whereas the token-realm is the one responsible for validating the token.

If validation succeeds, a security context will be created based on the information represented by the token and the application can use the newly created security context to obtain information about the subject making the request as well decide whether or not the request should be full filled. In case the validation fails, the mechanism will respond with a 403 HTTP status code as follows:

HTTP/1.1 403 Forbidden

11.2. Validating JWT Tokens

Elytron provides built-in support for JWT tokens, which can be enabled by defining a realm in the Elytron subsystem as follows:

 <token-realm name="JwtRealm" principal-claim="sub">
    <jwt issuer="as.example.com"
         audience="api.example.com"
         public-key="-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQAB-----END PUBLIC KEY-----"/>
 </token-realm>

In the example above, the token-realm is defined with a principal-claim attribute. This attribute specifies which claim within the token should be used to identity the principal. If you have a token as follows:

 {
   "iss": "as.example.com",
   "sub": "24400320",
   "aud": "s6BhdRkqt3",
   "exp": 1311281970,
   "nbf": 1311280970,
  }

Elytron will use the value associated with the sub claim as the identifier of the subject represented by the token.

The jwt element within the token-realm specifies that tokens should be validated as JWT and provides different configuration options on how they should be validated:

  • issuer

    A list of strings representing the issuers supported by this configuration. During validation JWT tokens must have an "iss" claim that contains one of the values defined here

  • audience

    A list of strings representing the audiences supported by this configuration. During validation JWT tokens must have an "aud" claim that contains one of the values defined here

  • public-key

    A public key in PEM Format. During validation, if a public key is provided, signature will be verified based on the key you provided here. Alternatively, you can define a key-store and certificate attributes to configure the public key. This key will be used to verify tokens without "kid" claim.

  • key-store

    As an alternative to public-key, you can also define a key store from where the certificate with a public key should be loaded from

  • certificate

    The name of the certificate with a public key to load from the key store in case you defined the key-store attribute

  • client-ssl-context

    The SSL context to be used if if you want to use remote JSON Web Keys. This enables you to use url from "jku" token claim to fetch public keys for token verification.

  • host-name-verification-policy

    A policy that defines how host names should be verified when using remote JSON Web Keys. Allowed values: "ANY", "DEFAULT".

For being able to use different key pairs for signing / verification and for easier key rotation you can define key map. This will take the "kid" claim from the token and use corresponding public key for verification.

 <token-realm name="JwtRealm" principal-claim="sub">
    <jwt issuer="as.example.com" audience="api.example.com">
        <key kid="1" public-key="-----BEGIN PUBLIC KEY-----MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANc4VlnN6oZwe1PoQQeJsTwu7LGS+eEbgYMNYXahidga4+BhdGKwzMZU54ABFQ11tUMJSENQ6o3n1YKVgMnxvcMCAwEAAQ==-----END PUBLIC KEY-----"/>
        <key kid="2" public-key="-----BEGIN PUBLIC KEY-----MFswDQYJKoZIhvcNAQEBBQADSgAwRwJAcNpXy6psxC21DdnTtAdlgsEwEuJh/earH3q7xJPjmsygmrlpC66MG4/A/J9Gai2Hp+QdCSEVpBWkIoVff3sIlwIDAQAB-----END PUBLIC KEY-----"/>
    </jwt>
 </token-realm>

This token-realm will verify tokens with "kid" claims of value "1" or "2" using corresponding key.

Tokens without "kid" claim will be verified using the 'public-key' attribute of 'jwt', or in this case invalidated, as there is no key specified.

The jwt validator performs different checks in order to determine the validity of a JWT:

  • Expiration checks based on the values of the exp and nbf claims

  • Signature checks based on the public key provided via public-key or certificate attributes, key map with named public keys, or by fetching remote JSON Web Key Set using provided client-ssl-context. You can skip token signature verification by not defining any of these.

It is strongly recommended that you use signed JWTs in order to guarantee authenticity of tokens and make sure they were not tampered.

11.3. Validating OAuth2 Bearer Tokens

Elytron provides built-in support for tokens issued by an OAuth2 compliant authorization server, where these tokens are validated using a token introspection endpoint as defined by OAuth2 specification.

<token-realm name="OAuth2Realm" principal-claim="sub">
    <oauth2-introspection client-id="my-client-id"
                          client-secret="keep_it_secret"
                          introspection-url="https://as.example.com/token/introspect"
                          client-ssl-context="user-defined-ssl-context"
                          host-name-verification-policy="ANY" />
</token-realm>

The auth2-introspection element within the token-realm specifies that tokens should be validated using an OAuth2 Token Introspection Endpoint and provides different configuration options on how they should be validated:

  • client-id

    The identifier of the client on the OAuth2 Authorization Server

  • client-secret

    The secret of the client

  • introspection-url

    The URL of token introspection endpoint

  • client-ssl-context

    The SSL context to be used if the introspection endpoint is using HTTPS.

  • host-name-verification-policy

    A policy that defines how host names should be verified when using HTTPS. Allowed values: "ANY", "DEFAULT".

11.5. CLI Examples on How to Create a Token Realm

Create a Token Realm to validate JWT tokens using a key store to retrieve the public key
# Create a Key Store
/subsystem=elytron/key-store=my-keystore:add(path=/path/to/keystore.jks,credential-reference={clear-text=secret},type=JKS)

# Create the realm
/subsystem=elytron/token-realm=jwt-realm:add(principal-claim=sub, jwt={issuer=["as.example.com"], audience=["api.example.com"], key-store=my-keystore, certificate=as.example.com})
Create a Token Realm to validate OAuth2 tokens
# Create a Client SSLContext
/subsystem=elytron/key-store=default-trust-store:add(path=/path/to/keystore.jks,credential-reference={clear-text=secret},type=JKS)
/subsystem=elytron/trust-manager=default-trust-manager:add(algorithm=PKIX, key-store=default-trust-store)
/subsystem=elytron/client-ssl-context=default-client-ssl-context:add(trust-manager=default-trust-manager)

# Create the realm
/subsystem=elytron/token-realm=oauth2-realm:add(principal-claim=preferred_username, oauth2-introspection={client-id=my-client-id, client-secret=keep_it_secret, client-ssl-context=default-client-ssl-context, introspection-url=https://as.example.com/token/introspect})

12. OpenSSL

13. Web Single Sign-On

This document will guide on how to enable single sign-on across different applications deployed into different servers, where these applications belong to same security domain.

13.1. Create a Server Configuration Template

For this document, you’ll need to run at least two server instances in order to check single sign-on and how it affect usability in your applications. Users should be able to log in once and have access to any application using the same security domain.

All configuration described in the next sections should be done with a server instance using standalone-ha.xml (or standalone-full-ha.xml).

Run a server instance using the following command:

bin/standalone.sh -c standalone-ha.xml

13.1.1. Create a HTTP Authentication Factory

If you already have a http-authentication-factory defined in Elytron subsystem and just want to use it to enable single sign-on to your applications, please skip this section.{info} First, you need a security-domain which we’ll use to authenticate users. Please, execute the following CLI commands:
# Creates a FileSystem Realm, an identity store where users are stored in the local filesystem
/subsystem=elytron/filesystem-realm=example-realm:add(path=/tmp/example-realm)

# Creates a Security Domain
/subsystem=elytron/security-domain=example-domain:add(default-realm=example-realm, permission-mapper=default-permission-mapper,realms=[{realm=example-realm, role-decoder=groups-to-roles}]

# Creates an user that you can use to access your applications
/subsystem=elytron/filesystem-realm=example-realm:add-identity(identity=alice)
/subsystem=elytron/filesystem-realm=example-realm:add-identity-attribute(identity=alice, name=groups, value=["user"])
/subsystem=elytron/filesystem-realm=example-realm:set-password(identity=alice, clear={password=alice})

Now you can create a http-authentication-factory that you’ll use to actually protect your web applications using Undertow:

# Create a Http Authentication Factory
/subsystem=elytron/http-authentication-factory=example-http-authentication:add(security-domain=example-domain, http-server-mechanism-factory=global, mechanism-configurations=[{mechanism-name=FORM}]

13.1.2. Create a Application Security Domain in Undertow

If you already have a _application-security-domain_ defined in Undertow subsystem and just want to use it to enable single sign-on to your applications, please skip this section.

In order to protect applications using the configuration defined in Elytron subsystem, you should create a application-security-domain definition in Undertow subsystem as follows:

/subsystem=undertow/application-security-domain=other:add(http-authentication-factory=example-http-authentication)

By default, if your application does not define any specific security-domain in jboss-web.xml, the application server will choose one with a name other.

13.1.3. Create a Key Store

In order to create a key-store in Elytron subsystem, first create a Java Key Store as follows:

keytool -genkeypair -alias localhost -keyalg RSA -keysize 1024 -validity 365 -keystore keystore.jks -dname "CN=localhost" -keypass secret -storepass secret

Once the keystore.jks file is created, execute the following CLI commands to create a key-store definition in Elytron:

/subsystem=elytron/key-store=example-keystore:add(path=keystore.jks, relative-to=jboss.server.config.dir, credential-reference={clear-text=secret}, type=JKS)

13.1.4. Enable Single Sign-On

Single Sign-On is enabled to a specific application-security-domain definition in Undertow subsystem. It is important that the servers you will be using to deploy applications are using the same configuration.

To enable single-sign on, just change an existing application-security-domain in Undertow subsystem as follows:

/subsystem=undertow/application-security-domain=other/setting=single-sign-on:add(key-store=example-keystore, key-alias=localhost, domain=localhost, credential-reference={clear-text=secret})

After restarting the servers, users should be able to log in once and have access to any application using the same application-security-domain.

13.2. Create Two Server Instances

All configuration you did so far should be reflect in $JBOSS_HOME/standalone/standalone-ha.xml. You can now create two distinct server configuration directories_:\_

cp -r standalone standalone-a
cp -r standalone standalone-b

And you can run the two instances using the command below:

$JBOSS_HOME/bin/standalone.sh -c standalone-ha.xml -Djboss.node.name=node-a -Djboss.socket.binding.port-offset=200 -Djboss.server.base.dir=$JBOSS_HOME/standalone-a
$JBOSS_HOME/bin/standalone.sh -c standalone-ha.xml -Djboss.node.name=node-b -Djboss.socket.binding.port-offset=300 -Djboss.server.base.dir=$JBOSS_HOME/standalone-b ----

13.3. Deploy an Application

For the sake of simplicity, these are the minimum files you need in your application:

WEB-INF/web.xml
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">

    <security-constraint>
        <display-name>SecurityConstraint</display-name>
        <web-resource-collection>
            <web-resource-name>All Resources</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>user</role-name>
        </auth-constraint>
    </security-constraint>

    <login-config>
        <auth-method>FORM</auth-method>
        <form-login-config>
            <form-login-page>/login.html</form-login-page>
            <form-error-page>/login.html</form-error-page>
        </form-login-config>
    </login-config>

    <security-role>
        <role-name>user</role-name>
    </security-role>
</web-app>
login.html
<html>
    <body>
        <form method="post" action="j_security_check">
            <input type="text" name="j_username">
            <input type="password" name="j_password">
            <input type="submit" value="Log In">
        </form>
    </body>
</html>
Make sure you have at least a welcome file (e.g.: index.html\|jsp).

Deploy your application into both server instances and try to log in using the user you created at the beginning of this document:

  • Username: alice

  • Password: alice

14. Audit

WildFly Elytron supports audit using security event listeners - components which captures security events, like successful or unsucceful login attempts.

14.1. File audit log

File audit log logs security events into a local file. It requires to define path to the log file, which can be relative-to a system property. It also allows to set the file format - human readable SIMPLE or JSON. While in WildFly 14 there was only one attribute synchronized, which had influence on data reliability, now there is possible more fine grained performance and reliability tunning: * autoflush defines whether should be output stream flushed after every audit event (guarantees that the log message is passed to the operating system immediately) * synchonized defines whether should be file descriptor synchronized after every audit event (guarantees that all system buffers are synchronized with the underlying device)

15. Custom Components

WildFly Elytron subsystem allows to add custom implementation of different components in form of WildFly modules into the WildFly instance and use them by the same way as built-in Elytron subsystem components. For example, you can create custom security event listener to develop custom audit mechanisms and store information about user authentication attempts in custom storage structure. Or you can create custom security realm to authenticate users against your own identities storage.

To find what types of custom components you can implement you can use Tab completion:

[standalone@localhost:9990 /] /subsystem=elytron/custom-
custom-credential-security-factory  custom-realm
custom-modifiable-realm             custom-realm-mapper
custom-permission-mapper            custom-role-decoder
custom-principal-decoder            custom-role-mapper
custom-principal-transformer        custom-security-event-listener

15.1. Security event listener

To create custom security event listener you need to implement java.util.function.Consumer<org.wildfly.security.auth.server.event.SecurityEvent> interface. Resulting class needs to be packed into JAR and WildFly module created. You can create appropriate directory structure and module descriptor manually, or you can use following command of WildFly CLI:

bin/jboss-cli.sh
module add --name=my.module --resources=my-listener.jar --dependencies=org.wildfly.security.elytron

Check Class loading doc for more information how to create WildFly module.

When appropriate module is on place, you can start using it by adding Elytron subsystem resource:

/subsystem=elytron/custom-security-event-listener=myListener:add(
        module=my.module, class-name=my.module.MyAuditListener)

Now you can start to use it as any other security event listener - typically to set it as listener of ApplicationDomain:

/subsystem=elytron/security-domain=ApplicationDomain:write-attribute(name=security-event-listener, value=myListener)

After server reload the listener will receive all security events from given security domain.

15.2. Configurable custom components

You can also provide some component configuration from the subsystem, if class of your component will implement following method:

public void initialize(Map<String, String> configuration)

Afterwards you can provide configuration into your component from the subsystem using attribute configuration:

/subsystem=elytron/custom-...=my-component:add(module=..., class-name=..., configuration={myAttribute="myValue"})

After the component construction, the initialize method will be called with the configuration.

16. Migrate Legacy Security to Elytron Security

16.1. Authentication Configuration

16.2. Properties Based Authentication / Authorization

16.2.1. PicketBox Based Configuration

This migration example assumes a deployed web application is configured to require authentication using FORM based authentication and is referencing a PicketBox based security domain using the UsersRolesLoginModule to load user information from a pair or properties files.

Original Configuration

A security domain can be defined in the legacy security subsystem using the following management operations: -

./subsystem=security/security-domain=application-security:add
./subsystem=security/security-domain=application-security/authentication=classic:add(login-modules=[{code=UsersRoles, flag=Required, module-options={usersProperties=file://${jboss.server.config.dir}/example-users.properties, rolesProperties=file://${jboss.server.config.dir}/example-roles.properties}}])

This would result in a security domain definition: -

  <security-domain name="application-security">
    <authentication>
      <login-module code="UsersRoles" flag="required">
        <module-option name="usersProperties" value="file://${jboss.server.config.dir}/example-users.properties"/>
        <module-option name="rolesProperties" value="file://${jboss.server.config.dir}/example-roles.properties"/>
      </login-module>
    </authentication>
  </security-domain>
Intermediate Configuration

It is possible to take a previously defined PicketBox security domain and expose it as an Elytron security realm so it can be wired into a complete Elytron based configuration, if only properties based authentication was to be migrated it would be recommended to jump to the fully migration configuration and avoid the unnecessary dependency on the legacy security subsystem but for situations where that is not immediately possible these commands illustrate an intermediate solution.

These steps assume the original configuration is already in place.

The first step is to add a mapping to an Elytron security realm within the legacy security subsystem.

./subsystem=security/elytron-realm=application-security:add(legacy-jaas-config=application-security)

This results in the following configuration.

  <subsystem xmlns="urn:jboss:domain:security:2.0">
    ...
    <elytron-integration>
      <security-realms>
        <elytron-realm name="application-security" legacy-jaas-config="application-security"/>
      </security-realms>
    </elytron-integration>
    ...
  </subsystem>

Within the Elytron subsystem a security domain can be defined which references the exported security realm and also a http authentication factory which supports FORM based authentication.

./subsystem=elytron/security-domain=application-security:add(realms=[{realm=application-security}], default-realm=application-security, permission-mapper=default-permission-mapper)
./subsystem=elytron/http-authentication-factory=application-security-http:add(http-server-mechanism-factory=global, security-domain=application-security, mechanism-configurations=[{mechanism-name=FORM}])

And the resulting configuration: -

  <subsystem xmlns="urn:wildfly:elytron:1.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
    ...
    <security-domains>
      ...
      <security-domain name="application-security" default-realm="application-security" permission-mapper="default-permission-mapper">
        <realm name="application-security"/>
      </security-domain>
    </security-domains>
    ...
    <http>
      ...
      <http-authentication-factory name="application-security-http" http-server-mechanism-factory="global" security-domain="application-security">
        <mechanism-configuration>
          <mechanism mechanism-name="FORM"/>
        </mechanism-configuration>
      </http-authentication-factory>
      ...
    </http>
    ...
  </subsystem>

Finally configuration needs to be added to the Undertow subsystem to map the security domain referenced by the deployment to the newly defined http authentication factory.

./subsystem=undertow/application-security-domain=application-security:add(http-authentication-factory=application-security-http)

Which results in: -

  <subsystem xmlns="urn:jboss:domain:undertow:4.0">
    ...
    <application-security-domains>
      <application-security-domain name="application-security" http-authentication-factory="application-security-http"/>
    </application-security-domains>
    ...
  </subsystem>

Note: If the deployment was already deployed at this point the application server should be reloaded or the deployment redeployed for the application security domain mapping to take effect.

The following command can then be used to verify the mapping was applied to the deployment.

[standalone@localhost:9990 /] ./subsystem=undertow/application-security-domain=application-security:read-resource(include-runtime=true)
{
    "outcome" => "success",
    "result" => {
        "enable-jacc" => false,
        "http-authentication-factory" => "application-security-http",
        "override-deployment-config" => false,
        "referencing-deployments" => ["HelloWorld.war"],
        "setting" => undefined
    }
}

The deployment being tested here is 'HelloWorld.war' and the output from the previous command shows this deployment is referencing the mapping.

At this stage the previously defined security domain is used for it’s LoginModule configuration but this is wrapped by Elytron components which take over authentication.

Fully Migrated Configuration

Alternatively the configuration can be completely defined within the Elytron subsystem, in this case it is assumed none of the previous commands have been executed and this is started from a clean configuration - however if the security domain definition does exist in the legacy security subsystem that will remain completely independent.

First a new security realm can be defined within the Elytron subsystem referencing the files referenced previously: -

./subsystem=elytron/properties-realm=application-properties:add(users-properties={path=example-users.properties, relative-to=jboss.server.config.dir, plain-text=true, digest-realm-name="Application Security"}, groups-properties={path=example-roles.properties, relative-to=jboss.server.config.dir}, groups-attribute=Roles)

As before a security domain and http authentication factory can be defined.

./subsystem=elytron/security-domain=application-security:add(realms=[{realm=application-properties}], default-realm=application-properties, permission-mapper=default-permission-mapper)
./subsystem=elytron/http-authentication-factory=application-security-http:add(http-server-mechanism-factory=global, security-domain=application-security, mechanism-configurations=[{mechanism-name=FORM}])

This results in the following overall configuration.

  <subsystem xmlns="urn:wildfly:elytron:1.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
    ...
    <security-domains>
      ...
      <security-domain name="application-security" default-realm="application-properties" permission-mapper="default-permission-mapper">
        <realm name="application-properties"/>
      </security-domain>
    </security-domains>
    <security-realms>
      ...
      <properties-realm name="application-properties" groups-attribute="Roles">
        <users-properties path="example-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="Application Security" plain-text="true"/>
        <groups-properties path="example-roles.properties" relative-to="jboss.server.config.dir"/>
      </properties-realm>
    </security-realms>
    ...
    <http>
      ...
      <http-authentication-factory name="application-security-http" http-server-mechanism-factory="global" security-domain="application-security">
        <mechanism-configuration>
          <mechanism mechanism-name="FORM"/>
        </mechanism-configuration>
      </http-authentication-factory>
      ...
    </http>
    ...
  </subsystem>

As before the application-security-domain mapping should be added to the Undertow subsystem and the server reloaded or the deployment redeployed as required.

./subsystem=undertow/application-security-domain=application-security:add(http-authentication-factory=application-security-http)

Which results in: -

  <subsystem xmlns="urn:jboss:domain:undertow:4.0">
    ...
    <application-security-domains>
      <application-security-domain name="application-security" http-authentication-factory="application-security-http"/>
    </application-security-domains>
    ...
  </subsystem>

At this stage the authentication is the equivalent of the original configuration however now Elytron components are used exclusively.

16.2.2. Legacy Security Realm

Original Configuration

A legacy security realm can be defined using the following commands to load users passwords and group information from properties files.

./core-service=management/security-realm=ApplicationSecurity:add
./core-service=management/security-realm=ApplicationSecurity/authentication=properties:add(relative-to=jboss.server.config.dir, path=example-users.properties, plain-text=true)
./core-service=management/security-realm=ApplicationSecurity/authorization=properties:add(relative-to=jboss.server.config.dir, path=example-roles.properties)

This results in the following realm definition.

  <security-realm name="ApplicationSecurity">
    <authentication>
      <properties path="example-users.properties" relative-to="jboss.server.config.dir" plain-text="true"/>
    </authentication>
    <authorization>
      <properties path="example-roles.properties" relative-to="jboss.server.config.dir"/>
    </authorization>
  </security-realm>

A legacy security realm would typically be used to secure either the management interfaces or remoting connectors.

Migrated Configuration

One of the motivations for adding the Elytron based security to the application server is to allow a consistent security solution to be used across the server, to replace the security realm the same steps as described in the previous 'Fully Migrated' section can be followed again up until the http-authentication-factory is defined.

A legacy security realm can also be used for SASL based authentication so a sasl-authentication-factory should also be defined.

./subsystem=elytron/sasl-authentication-factory=application-security-sasl:add(sasl-server-factory=elytron, security-domain=application-security, mechanism-configurations=[{mechanism-name=PLAIN}])
  <subsystem xmlns="urn:wildfly:elytron:1.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
    ...
    <sasl>
      ...
      <sasl-authentication-factory name="application-security-sasl" sasl-server-factory="elytron" security-domain="application-security">
        <mechanism-configuration>
          <mechanism mechanism-name="PLAIN"/>
        </mechanism-configuration>
      </sasl-authentication-factory>
      ...
    </sasl>
  </subsystem>

This can be associated with a Remoting connector to use for authentication and the existing security realm reference cleared.

./subsystem=remoting/http-connector=http-remoting-connector:write-attribute(name=sasl-authentication-factory, value=application-security-sasl)
./subsystem=remoting/http-connector=http-remoting-connector:undefine-attribute(name=security-realm)
  <subsystem xmlns="urn:jboss:domain:remoting:4.0">
    ...
    <http-connector name="http-remoting-connector" connector-ref="default" sasl-authentication-factory="application-security-sasl"/>
  </subsystem>

If this new configuration was to be used to secure the management interfaces more suitable names should be chosen but the following commands illustrate how to set the two authentication factories and clear the existing security realm reference.

./core-service=management/management-interface=http-interface:write-attribute(name=http-authentication-factory, value=application-security-http)
./core-service=management/management-interface=http-interface:write-attribute(name=http-upgrade.sasl-authentication-factory, value=application-security-sasl)
./core-service=management/management-interface=http-interface:undefine-attribute(name=security-realm)
  <management-interfaces>
    <http-interface http-authentication-factory="application-security-http">
      <http-upgrade enabled="true" sasl-authentication-factory="application-security-sasl"/>
      <socket-binding http="management-http"/>
    </http-interface>
  </management-interfaces>

16.3. LDAP Authentication Migration

The section describing how to migrate from properties based authentication using either PicketBox or legacy security realms to Elytron also contained a lot of additional information regarding defining security domains, authentication factories, and how these are mapped to be used for authentication. This section will illustrate some equivalent LDAP configuration using legacy security realms and PicketBox security domains and show the equivalent configuration using Elytron but will not repeat the steps to wire it all together covered in the previous section.

These configuration examples are developed against a test LDAP sever with user entries like: -

dn: uid=TestUserOne,ou=users,dc=group-to-principal,dc=wildfly,dc=org
objectClass: top
objectClass: inetOrgPerson
objectClass: uidObject
objectClass: person
objectClass: organizationalPerson
cn: Test User One
sn: Test User One
uid: TestUserOne
userPassword: {SSHA}UG8ov2rnrnBKakcARVvraZHqTa7mFWJZlWt2HA==

The group entries then look like: -

dn: uid=GroupOne,ou=groups,dc=group-to-principal,dc=wildfly,dc=org
objectClass: top
objectClass: groupOfUniqueNames
objectClass: uidObject
cn: Group One
uid: GroupOne
uniqueMember: uid=TestUserOne,ou=users,dc=group-to-principal,dc=wildfly,dc=org

For authentication purposes the username will be matched against the 'uid' attribute, also the resulting group name will be taken from the 'uid' attribute of the group entry.

16.3.1. Legacy Security Realm

A connection to the LDAP server and related security realm can be created with the following commands: -

batch
./core-service=management/ldap-connection=MyLdapConnection:add(url="ldap://localhost:10389", search-dn="uid=admin,ou=system", search-credential="secret")
 
./core-service=management/security-realm=LDAPRealm:add
./core-service=management/security-realm=LDAPRealm/authentication=ldap:add(connection="MyLdapConnection", username-attribute=uid, base-dn="ou=users,dc=group-to-principal,dc=wildfly,dc=org")
 
 
./core-service=management/security-realm=LDAPRealm/authorization=ldap:add(connection=MyLdapConnection)
./core-service=management/security-realm=LDAPRealm/authorization=ldap/username-to-dn=username-filter:add(attribute=uid, base-dn="ou=users,dc=group-to-principal,dc=wildfly,dc=org")
./core-service=management/security-realm=LDAPRealm/authorization=ldap/group-search=group-to-principal:add(base-dn="ou=groups,dc=group-to-principal,dc=wildfly,dc=org", iterative=true, prefer-original-connection=true, principal-attribute=uniqueMember, search-by=DISTINGUISHED_NAME, group-name=SIMPLE, group-name-attribute=uid)
run-batch

This results in the following configuration.

  <management>
    <security-realms>
      ...
      <security-realm name="LDAPRealm">
        <authentication>
          <ldap connection="MyLdapConnection" base-dn="ou=users,dc=group-to-principal,dc=wildfly,dc=org">
            <username-filter attribute="uid"/>
          </ldap>
        </authentication>
        <authorization>
          <ldap connection="MyLdapConnection">
            <username-to-dn>
              <username-filter base-dn="ou=users,dc=group-to-principal,dc=wildfly,dc=org" attribute="uid"/>
            </username-to-dn>
            <group-search group-name="SIMPLE" iterative="true" group-name-attribute="uid">
              <group-to-principal search-by="DISTINGUISHED_NAME" base-dn="ou=groups,dc=group-to-principal,dc=wildfly,dc=org" prefer-original-connection="true">
                <membership-filter principal-attribute="uniqueMember"/>
              </group-to-principal>
            </group-search>
          </ldap>
        </authorization>
      </security-realm>
    </security-realms>
    <outbound-connections>
      <ldap name="MyLdapConnection" url="ldap://localhost:10389" search-dn="uid=admin,ou=system" search-credential="secret"/>
    </outbound-connections>
    ...
  </management>

16.3.2. PicketBox LdapExtLoginModule

The following commands can create a PicketBox security domain configured to use the LdapExtLoginModule to verify a username and password.

./subsystem=security/security-domain=application-security:add
./subsystem=security/security-domain=application-security/authentication=classic:add(login-modules=[{code=LdapExtended, flag=Required, module-options={ \
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, \
java.naming.provider.url=ldap://localhost:10389, \
java.naming.security.authentication=simple, \
bindDN="uid=admin,ou=system", \
bindCredential=secret, \
baseCtxDN="ou=users,dc=group-to-principal,dc=wildfly,dc=org", \
baseFilter="(uid={0})", \
rolesCtxDN="ou=groups,dc=group-to-principal,dc=wildfly,dc=org",\
roleFilter="(uniqueMember={1})", \
roleAttributeID="uid" \
}}])

This results in the following configuration.

  <subsystem xmlns="urn:jboss:domain:security:2.0">
    ...
    <security-domains>
      ...
      <security-domain name="application-security">
        <authentication>
          <login-module code="LdapExtended" flag="required">
            <module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
            <module-option name="java.naming.provider.url" value="ldap://localhost:10389"/>
            <module-option name="java.naming.security.authentication" value="simple"/>
            <module-option name="bindDN" value="uid=admin,ou=system"/>
            <module-option name="bindCredential" value="secret"/>
            <module-option name="baseCtxDN" value="ou=users,dc=group-to-principal,dc=wildfly,dc=org"/>
            <module-option name="baseFilter" value="(uid={0})"/>
            <module-option name="rolesCtxDN" value="ou=groups,dc=group-to-principal,dc=wildfly,dc=org"/>
            <module-option name="roleFilter" value="(uniqueMember={1})"/>
            <module-option name="roleAttributeID" value="uid"/>
          </login-module>
        </authentication>
      </security-domain>
    </security-domains>
  </subsystem>

16.3.3. Migrated

Within the Elytron subsystem a directory context can be defined for the connection to LDAP: -

./subsystem=elytron/dir-context=ldap-connection:add(url=ldap://localhost:10389, principal="uid=admin,ou=system", credential-reference={clear-text=secret})

Then a security realm can be created to search LDAP and verify the supplied password: -

./subsystem=elytron/ldap-realm=ldap-realm:add(dir-context=ldap-connection, \
direct-verification=true, \
identity-mapping={search-base-dn="ou=users,dc=group-to-principal,dc=wildfly,dc=org", \
rdn-identifier="uid", \
attribute-mapping=[{filter-base-dn="ou=groups,dc=group-to-principal,dc=wildfly,dc=org",filter="(uniqueMember={1})",from="uid",to="Roles"}]})

In the prior two examples information is loaded from LDAP to use directly as groups or roles, in the Elytron case information can be loaded from LDAP to associate with the identity as attributes - these can subsequently be mapped to roles but attributes can be loaded for other purposes as well.

By default, if no role-decoder is defined for given security-domain, identity attribute " `Roles`" is mapped to the identity roles.

This leads to the following configuration.

  <subsystem xmlns="urn:wildfly:elytron:1.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
    ...
    <security-realms>
      ...
      <ldap-realm name="ldap-realm" dir-context="ldap-connection" direct-verification="true">
        <identity-mapping rdn-identifier="uid" search-base-dn="ou=users,dc=group-to-principal,dc=wildfly,dc=org">
          <attribute-mapping>
            <attribute from="uid" to="Roles" filter="(uniqueMember={1})" filter-base-dn="ou=groups,dc=group-to-principal,dc=wildfly,dc=org"/>
          </attribute-mapping>
        </identity-mapping>
      </ldap-realm>
    </security-realms>
    ...
    <dir-contexts>
      <dir-context name="ldap-connection" url="ldap://localhost:10389" principal="uid=admin,ou=system">
        <credential-reference clear-text="secret"/>
      </dir-context>
    </dir-contexts>
  </subsystem>

16.4. Composite Stores Migration

When using either PicketBox or the legacy security realms it is possible to define a configuration where authentication is performed against one identity store whilst the information used for authorization is loaded from a different store, when using WildFly Elytron this can be achieved by using an aggregate security realm.

The example here makes use of a properties file for authentication and then searches LDAP to load group / role information. Both of these are based on the previous examples within this document so the environmental information is not repeated here.

16.4.1. PicketBox Based Configuration

./subsystem=security/security-domain=application-security:add
./subsystem=security/security-domain=application-security/authentication=classic:add(login-modules=[ \
{code=UsersRoles, flag=Required, module-options={ \
password-stacking=useFirstPass, \
usersProperties=file://${jboss.server.config.dir}/example-users.properties, \
rolesProperties=file://${jboss.server.config.dir}/example-roles.properties}} \
{code=LdapExtended, flag=Required, module-options={ \
password-stacking=useFirstPass, \
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, \
java.naming.provider.url=ldap://localhost:10389, \
java.naming.security.authentication=simple, \
bindDN="uid=admin,ou=system", \
bindCredential=secret, \
baseCtxDN="ou=users,dc=group-to-principal,dc=wildfly,dc=org", \
baseFilter="(uid={0})", \
rolesCtxDN="ou=groups,dc=group-to-principal,dc=wildfly,dc=org",\
roleFilter="(uniqueMember={1})", \
roleAttributeID="uid" \
}}])

This results in the following domain definition

<security-domain name="application-security">
  <authentication>
    <login-module code="UsersRoles" flag="required">
      <module-option name="password-stacking" value="useFirstPass"/>
      <module-option name="usersProperties" value="file://${jboss.server.config.dir}/example-users.properties"/>
      <module-option name="rolesProperties" value="file://${jboss.server.config.dir}/example-roles.properties"/>
    </login-module>
    <login-module code="LdapExtended" flag="required">
      <module-option name="password-stacking" value="useFirstPass"/>
      <module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
      <module-option name="java.naming.provider.url" value="ldap://localhost:10389"/>
      <module-option name="java.naming.security.authentication" value="simple"/>
      <module-option name="bindDN" value="uid=admin,ou=system"/>
      <module-option name="bindCredential" value="secret"/>
      <module-option name="baseCtxDN" value="ou=users,dc=group-to-principal,dc=wildfly,dc=org"/>
      <module-option name="baseFilter" value="(uid={0})"/>
      <module-option name="rolesCtxDN" value="ou=groups,dc=group-to-principal,dc=wildfly,dc=org"/>
      <module-option name="roleFilter" value="(uniqueMember={1})"/>
      <module-option name="roleAttributeID" value="uid"/>
    </login-module>
  </authentication>
</security-domain>

During an authentication attempt the 'UsersRoles' login module will first be called to perform authentication based on the supplied credential, then the 'LdapExtLoginModule' will be called which will proceed to query LDAP to load the roles for the identity.

./core-service=management/ldap-connection=MyLdapConnection:add(url="ldap://localhost:10389", search-dn="uid=admin,ou=system", search-credential="secret")

./core-service=management/security-realm=ApplicationSecurity:add
./core-service=management/security-realm=ApplicationSecurity/authentication=properties:add(path=example-users.properties, relative-to=jboss.server.config.dir, plain-text=true)

batch
./core-service=management/security-realm=ApplicationSecurity/authorization=ldap:add(connection=MyLdapConnection)
./core-service=management/security-realm=ApplicationSecurity/authorization=ldap/username-to-dn=username-filter:add(attribute=uid, base-dn="ou=users,dc=group-to-principal,dc=wildfly,dc=org")
./core-service=management/security-realm=ApplicationSecurity/authorization=ldap/group-search=group-to-principal:add(base-dn="ou=groups,dc=group-to-principal,dc=wildfly,dc=org", iterative=true, prefer-original-connection=true, principal-attribute=uniqueMember, search-by=DISTINGUISHED_NAME, group-name=SIMPLE, group-name-attribute=uid)
run-batch

This results in the following realm definition:

<security-realm name="ApplicationSecurity">
  <authentication>
    <properties path="example-users.properties" relative-to="jboss.server.config.dir" plain-text="true"/>
  </authentication>
  <authorization>
    <ldap connection="MyLdapConnection">
      <username-to-dn>
        <username-filter base-dn="ou=users,dc=group-to-principal,dc=wildfly,dc=org" attribute="uid"/>
      </username-to-dn>
      <group-search group-name="SIMPLE" iterative="true" group-name-attribute="uid">
        <group-to-principal search-by="DISTINGUISHED_NAME" base-dn="ou=groups,dc=group-to-principal,dc=wildfly,dc=org" prefer-original-connection="true">
          <membership-filter principal-attribute="uniqueMember"/>
        </group-to-principal>
      </group-search>
    </ldap>
  </authorization>
</security-realm>

<outbound-connections>
  <ldap name="MyLdapConnection" url="ldap://localhost:10389" search-dn="uid=admin,ou=system" search-credential="secret"/>
</outbound-connections>

As with the PicketBox example, authentication is first performed using the properties file - then group searching is performed against LDAP.

16.4.2. Migrated WildFly Elytron Configuration

The equivalent WildFly Elytron configuration can be defined with the following commands:

./subsystem=elytron/dir-context=ldap-connection:add(url=ldap://localhost:10389, principal="uid=admin,ou=system", credential-reference={clear-text=secret})

./subsystem=elytron/ldap-realm=ldap-realm:add(dir-context=ldap-connection, \
direct-verification=true, \
identity-mapping={search-base-dn="ou=users,dc=group-to-principal,dc=wildfly,dc=org", \
rdn-identifier="uid", \
attribute-mapping=[{filter-base-dn="ou=groups,dc=group-to-principal,dc=wildfly,dc=org",filter="(uniqueMember={1})",from="uid",to="Roles"}]})

./subsystem=elytron/properties-realm=application-properties:add(users-properties={path=example-users.properties, relative-to=jboss.server.config.dir, plain-text=true, digest-realm-name="Application Security"}, groups-properties={path=example-roles.properties, relative-to=jboss.server.config.dir}, groups-attribute=Roles)

./subsystem=elytron/aggregate-realm=combined-realm:add(authentication-realm=application-properties, authorization-realm=ldap-realm)

./subsystem=elytron/security-domain=application-security:add(realms=[{realm=combined-realm}], default-realm=combined-realm, permission-mapper=default-permission-mapper)
./subsystem=elytron/http-authentication-factory=application-security-http:add(http-server-mechanism-factory=global, security-domain=application-security, mechanism-configurations=[{mechanism-name=BASIC}])

This results in the following realm definition:

<subsystem xmlns="urn:wildfly:elytron:1.1" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
  ...
  <security-domains>
    ...
    <security-domain name="application-security" default-realm="combined-realm" permission-mapper="default-permission-mapper">
      <realm name="combined-realm"/>
    </security-domain>
  </security-domains>
  <security-realms>
    <aggregate-realm name="combined-realm" authentication-realm="application-properties" authorization-realm="ldap-realm"/>
      ...
      <properties-realm name="application-properties" groups-attribute="Roles">
        <users-properties path="example-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="Application Security" plain-text="true"/>
        <groups-properties path="example-roles.properties" relative-to="jboss.server.config.dir"/>
      </properties-realm>
      <ldap-realm name="ldap-realm" dir-context="ldap-connection" direct-verification="true">
        <identity-mapping rdn-identifier="uid" search-base-dn="ou=users,dc=group-to-principal,dc=wildfly,dc=org">
          <attribute-mapping>
            <attribute from="uid" to="Roles" filter="(uniqueMember={1})" filter-base-dn="ou=groups,dc=group-to-principal,dc=wildfly,dc=org"/>
          </attribute-mapping>
        </identity-mapping>
      </ldap-realm>
  </security-realms>
  ...
  <http>
    ...
    <http-authentication-factory name="application-security-http" http-server-mechanism-factory="global" security-domain="application-security">
      <mechanism-configuration>
        <mechanism mechanism-name="BASIC"/>
      </mechanism-configuration>
    </http-authentication-factory>
    ...
  </http>
  ...
  <dir-contexts>
    <dir-context name="ldap-connection" url="ldap://localhost:10389" principal="uid=admin,ou=system">
      <credential-reference clear-text="secret"/>
    </dir-context>
  </dir-contexts>
</subsystem>

Within the WildFly Elytron example a new security realm 'aggregate-realm' has been defined, this definition specifies which of the defined security realms should be used for the authentication step and which of the security realms should be used for the loading of the identity used for subsequent authorization decisions.

16.5. Database Authentication

The section describing how to migrate from database accessible via JDBC datasource based authentication using PicketBox to Elytron. This section will illustrate some equivalent configuration using PicketBox security domains and show the equivalent configuration using Elytron but will not repeat the steps to wire it all together covered in the previous sections.

These configuration examples are developed against a test database with users table like:

CREATE TABLE User (
    id BIGINT NOT NULL,
    username VARCHAR(255),
    password VARCHAR(255),
    role ENUM('admin', 'manager', 'user'),
    PRIMARY KEY (id),
    UNIQUE (username)
)

For authentication purposes the username will be matched against the ' `username’ column, password will be expected in hex-encoded MD5 hash in ' `password’ column. User role for authorization purposes will be taken from ' `role’ column.

16.5.1. PicketBox Database LoginModule

The following commands can create a PicketBox security domain configured to use database accessible via JDBC datasource to verify a username and password and to assign roles.

./subsystem=security/security-domain=application-security/:add
./subsystem=security/security-domain=application-security/authentication=classic:add(login-modules=[{code=Database, flag=Required, module-options={ \
    dsJndiName="java:jboss/datasources/ExampleDS", \
    principalsQuery="SELECT password FROM User WHERE username = ?", \
    rolesQuery="SELECT role, 'Roles' FROM User WHERE username = ?", \
    hashAlgorithm=MD5, \
    hashEncoding=base64 \
}}])

This results in the following configuration.

        <subsystem xmlns="urn:jboss:domain:security:2.0">
            <security-domains>
                ...
                <security-domain name="application-security">
                    <authentication>
                        <login-module code="Database" flag="required">
                            <module-option name="dsJndiName" value="java:jboss/datasources/ExampleDS"/>
                            <module-option name="principalsQuery" value="SELECT password FROM User WHERE username = ?"/>
                            <module-option name="rolesQuery" value="SELECT role, 'Roles' FROM User WHERE username = ?"/>
                            <module-option name="hashAlgorithm" value="MD5"/>
                            <module-option name="hashEncoding" value="base64"/>
                        </login-module>
                    </authentication>
                </security-domain>
            </security-domains>
        </subsystem>

16.5.2. Migrated

Within the Elytron subsystem to use database accesible via JDBC you need to define jdbc-realm:

./subsystem=elytron/jdbc-realm=jdbc-realm:add(principal-query=[{ \
    data-source=ExampleDS, \
    sql="SELECT role, password FROM User WHERE username = ?", \
    attribute-mapping=[{index=1, to=Roles}] \
    simple-digest-mapper={algorithm=simple-digest-md5, password-index=2}, \
}])

This results in the following overall configuration:

        <subsystem xmlns="urn:wildfly:elytron:1.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
            ...
            <security-realms>
                ...
                <jdbc-realm name="jdbc-realm">
                    <principal-query sql="SELECT role, password FROM User WHERE username = ?" data-source="ExampleDS">
                        <attribute-mapping>
                            <attribute to="Roles" index="1"/>
                        </attribute-mapping>
                        <simple-digest-mapper password-index="2"/>
                    </principal-query>
                </jdbc-realm>
                ...
            </security-realms>
            ...
        </subsystem>

In comparison with PicketBox solution, Elytron jdbc-realm use one SQL query to obtain all user attributes and credentials. Their extraction from SQL result specifies mappers.

16.5.3. N-M relation beetween user and roles

When using a n:m-relation beetween user and roles (which means: the user has multiple roles), the previous configuration does not work.

The database:

CREATE TABLE User (
id BIGINT NOT NULL,
username VARCHAR(255),
password VARCHAR(255),
PRIMARY KEY (id),
UNIQUE (username)
)

CREATE TABLE Role(
id BIGINT NOT NULL,
rolename VARCHAR(255),
PRIMARY KEY (id),
UNIQUE (rolename)
)

CREATE TABLE Userrole(
userid BIGINT not null,
roleid BIGINT not null,
PRIMARY KEY (userid, roleid),
FOREIGN KEY (userid) references User(id,
FOREIGN KEY (roleid) references Role(id)
)

Here you need two configure two principal queries:

<jdbc-realm name="jdbc-realm">
    <principal-query sql="SELECT PASSWORD FROM USER WHERE USERNAME = ?" data-source="ExampleDS">
        <clear-password-mapper password-index="1"/>
    </principal-query>
    <principal-query sql="SELECT R.ROLENAME from ROLE AS R, USERROLE AS UR, USER AS U WHERE U.USERNAME=? AND UR.ROLEID = R.ID AND UR.USERID = U.ID" data-source="ExampleDS">
        <attribute-mapping>
            <attribute to="roles" index="1"/>
        </attribute-mapping>
    </principal-query>
</jdbc-realm>

The second query needs an attribute mapping to decode the selected rolename column (index 1):

<mappers>
...
<simple-role-decoder name="from-roles-attribute" attribute="roles"/>
...
</mappers>

The role decoder is referenced by the security domain:

<security-domain name="MyDomain" default-realm="jdbc-realm" permission-mapper="default-permission-mapper">
<realm name="MyDbRealm" role-decoder="from-roles-attribute"/>
</security-domain>

16.6. Kerberos Authentication Migration

When working with Kerberos configuration it is possible for the application server to rely on configuration from the environment or the key configuration can be specified using system properties, for the purpose of these examples I define system properties - these properties are applicable to both the legacy configuration and the migrated Elytron configuration.

./system-property=sun.security.krb5.debug:add(value=true)
./system-property=java.security.krb5.realm:add(value=ELYTRON.ORG)
./system-property=java.security.krb5.kdc:add(value=kdc.elytron.org)

The first line makes debugging easier but the last two lines specify the Kerberos realm in use and the address of the KDC.

  <system-properties>
    <property name="sun.security.krb5.debug" value="true"/>
    <property name="java.security.krb5.realm" value="ELYTRON.ORG"/>
    <property name="java.security.krb5.kdc" value="kdc.elytron.org"/>
  </system-properties>

16.6.1. HTTP Authentication

Legacy Security Realm

A legacy security realm can be define so that SPNEGO authentication can be enabled for the HTTP management interface.

./core-service=management/security-realm=Kerberos:add
./core-service=management/security-realm=Kerberos/server-identity=kerberos:add
./core-service=management/security-realm=Kerberos/server-identity=kerberos/keytab=HTTP\/test-server.elytron.org@ELYTRON.ORG:add(path=/home/darranl/src/kerberos/test-server.keytab, debug=true)
./core-service=management/security-realm=Kerberos/authentication=kerberos:add(remove-realm=true)

This results in the following configuration: -

  <security-realms>
    ...
    <security-realm name="Kerberos">
      <server-identities>
        <kerberos>
          <keytab principal="HTTP/test-server.elytron.org@ELYTRON.ORG" path="/home/darranl/src/kerberos/test-server.keytab" debug="true"/>
        </kerberos>
      </server-identities>
      <authentication>
        <kerberos remove-realm="true"/>
      </authentication>
    </security-realm>
  </security-realms>
Application SPNEGO

Alternatively deployed applications would make use of a pair of security domains.

./subsystem=security/security-domain=host:add
./subsystem=security/security-domain=host/authentication=classic:add
./subsystem=security/security-domain=host/authentication=classic/login-module=1:add(code=Kerberos, flag=Required, module-options={storeKey=true, useKeyTab=true, principal=HTTP/test-server.elytron.org@ELYTRON.ORG, keyTab=/home/darranl/src/kerberos/test-server.keytab, debug=true}
./subsystem=security/security-domain=SPNEGO:add
./subsystem=security/security-domain=SPNEGO/authentication=classic:add
./subsystem=security/security-domain=SPNEGO/authentication=classic/login-module=1:add(code=SPNEGO, flag=requisite,  module-options={password-stacking=useFirstPass, serverSecurityDomain=host})
./subsystem=security/security-domain=SPNEGO/authentication=classic/login-module=1:write-attribute(name=module, value=org.jboss.security.negotiation)
./subsystem=security/security-domain=SPNEGO/authentication=classic/login-module=2:add(code=UsersRoles, flag=required, module-options={password-stacking=useFirstPass, usersProperties=file:///home/darranl/src/kerberos/spnego-users.properties, rolesProperties=file:///home/darranl/src/kerberos/spnego-roles.properties, defaultUsersProperties=file:///home/darranl/src/kerberos/spnego-users.properties, defaultRolesProperties=file:///home/darranl/src/kerberos/spnego-roles.properties})

This results in: -

  <subsystem xmlns="urn:jboss:domain:security:2.0">
    <security-domains>
      ...
      <security-domain name="host">
        <authentication>
          <login-module name="1" code="Kerberos" flag="required">
            <module-option name="storeKey" value="true"/>
            <module-option name="useKeyTab" value="true"/>
            <module-option name="principal" value="HTTP/test-server.elytron.org@ELYTRON.ORG"/>
            <module-option name="keyTab" value="/home/darranl/src/kerberos/test-server.keytab"/>
            <module-option name="debug" value="true"/>
          </login-module>
        </authentication>
      </security-domain>
      <security-domain name="SPNEGO">
        <authentication>
          <login-module name="1" code="SPNEGO" flag="requisite" module="org.jboss.security.negotiation">
            <module-option name="password-stacking" value="useFirstPass"/>
            <module-option name="serverSecurityDomain" value="host"/>
          </login-module>
          <login-module name="2" code="UsersRoles" flag="required">
            <module-option name="password-stacking" value="useFirstPass"/>
            <module-option name="usersProperties" value="file:///home/darranl/src/kerberos/spnego-users.properties"/>
            <module-option name="rolesProperties" value="file:///home/darranl/src/kerberos/spnego-roles.properties"/>
            <module-option name="defaultUsersProperties" value="file:///home/darranl/src/kerberos/spnego-users.properties"/>
            <module-option name="defaultRolesProperties" value="file:///home/darranl/src/kerberos/spnego-roles.properties"/>
          </login-module>
        </authentication>
      </security-domain>
    </security-domains>
  </subsystem>

An application can now be deployed referencing the SPNEGO security domain and secured with SPNEGO mechanism.

Migrated SPNEGO

The equivalent configuration can be achieved with WildFly Elytron by first defining a security realm which will be used to load identity information.

./subsystem=elytron/properties-realm=spnego-properties:add(users-properties={path=/home/darranl/src/kerberos/spnego-users.properties, plain-text=true, digest-realm-name=ELYTRON.ORG}, groups-properties={path=/home/darranl/src/kerberos/spnego-roles.properties})

Next a Kerberos security factory is defined which allows the server to load it’s own Kerberos identity.

./subsystem=elytron/kerberos-security-factory=test-server:add(path=/home/darranl/src/kerberos/test-server.keytab, principal=HTTP/test-server.elytron.org@ELYTRON.ORG, debug=true)

As with the previous examples we define a security realm to pull together the policy as well as a HTTP authentication factory for the authentication policy.

./subsystem=elytron/security-domain=SPNEGODomain:add(default-realm=spnego-properties, realms=[{realm=spnego-properties, role-decoder=groups-to-roles}], permission-mapper=default-permission-mapper)
./subsystem=elytron/http-authentication-factory=spnego-http-authentication:add(security-domain=SPNEGODomain, http-server-mechanism-factory=global,mechanism-configurations=[{mechanism-name=SPNEGO, credential-security-factory=test-server}])

Overall this results in the following configuration: -

  <subsystem xmlns="urn:wildfly:elytron:1.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
    ...
    <security-domains>
    ...
      <security-domain name="SPNEGODomain" default-realm="spnego-properties" permission-mapper="default-permission-mapper">
        <realm name="spnego-properties" role-decoder="groups-to-roles"/>
      </security-domain>
    </security-domains>
    <security-realms>
      ...
      <properties-realm name="spnego-properties">
        <users-properties path="/home/darranl/src/kerberos/spnego-users.properties" digest-realm-name="ELYTRON.ORG" plain-text="true"/>
        <groups-properties path="/home/darranl/src/kerberos/spnego-roles.properties"/>
      </properties-realm>
    </security-realms>
    <credential-security-factories>
      <kerberos-security-factory name="test-server" principal="HTTP/test-server.elytron.org@ELYTRON.ORG" path="/home/darranl/src/kerberos/test-server.keytab" debug="true"/>
    </credential-security-factories>
    ...
    <http>
      ...
      <http-authentication-factory name="spnego-http-authentication" http-server-mechanism-factory="global" security-domain="SPNEGODomain">
        <mechanism-configuration>
          <mechanism mechanism-name="SPNEGO" credential-security-factory="test-server"/>
        </mechanism-configuration>
      </http-authentication-factory>
      ...
    </http>
    ...
  </subsystem>

Now, to enable SPNEGO authentication for the HTTP management interface, update this interface to reference the http-authentication-factory defined above, as described in the properties authentication section.

Alternatively, to secure an application using SPNEGO authentication, an application security domain can be defined in the Undertow subsystem to map security domains to the http-authentication-factory defined above, as described in the properties authentication section.

16.6.2. Remoting / SASL Authentication

Legacy Security Realm

It is also possible to define a legacy security realm for Kerberos / GSSAPI SASL authenticatio for Remoting authentication such as the native management interface.

./core-service=management/security-realm=Kerberos:add
./core-service=management/security-realm=Kerberos/server-identity=kerberos:add
./core-service=management/security-realm=Kerberos/server-identity=kerberos/keytab=remote\/test-server.elytron.org@ELYTRON.ORG:add(path=/home/darranl/src/kerberos/remote-test-server.keytab, debug=true)
./core-service=management/security-realm=Kerberos/authentication=kerberos:add(remove-realm=true)
  <management>
    <security-realms>
      ...
      <security-realm name="Kerberos">
        <server-identities>
          <kerberos>
            <keytab principal="remote/test-server.elytron.org@ELYTRON.ORG" path="/home/darranl/src/kerberos/remote-test-server.keytab" debug="true"/>
          </kerberos>
        </server-identities>
        <authentication>
          <kerberos remove-realm="true"/>
        </authentication>
      </security-realm>
    </security-realms>
    ...
  </management>
Migrated GSSAPI

The steps to define the equivalent Elytron configuration are very similar to the HTTP example.

First define the security realm to load the identity from: -

./path=kerberos:add(relative-to=user.home, path=src/kerberos)
./subsystem=elytron/properties-realm=kerberos-properties:add(users-properties={path=kerberos-users.properties, relative-to=kerberos, digest-realm-name=ELYTRON.ORG}, groups-properties={path=kerberos-groups.properties, relative-to=kerberos})

Then define the Kerberos security factory for the server’s identity.

./subsystem=elytron/kerberos-security-factory=test-server:add(relative-to=kerberos, path=remote-test-server.keytab, principal=remote/test-server.elytron.org@ELYTRON.ORG)

Finally define the security domain and this time a SASL authentication factory.

./subsystem=elytron/security-domain=KerberosDomain:add(default-realm=kerberos-properties, realms=[{realm=kerberos-properties, role-decoder=groups-to-roles}], permission-mapper=default-permission-mapper)
./subsystem=elytron/sasl-authentication-factory=gssapi-authentication-factory:add(security-domain=KerberosDomain, sasl-server-factory=elytron, mechanism-configurations=[{mechanism-name=GSSAPI, credential-security-factory=test-server}])

This results in the following subsystem configuration: -

  <subsystem xmlns="urn:wildfly:elytron:1.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
    ...
    <security-domains>
      ...
      <security-domain name="KerberosDomain" default-realm="kerberos-properties" permission-mapper="default-permission-mapper">
        <realm name="kerberos-properties" role-decoder="groups-to-roles"/>
      </security-domain>
    </security-domains>
    <security-realms>
     ...
       <properties-realm name="kerberos-properties">
         <users-properties path="kerberos-users.properties" relative-to="kerberos" digest-realm-name="ELYTRON.ORG"/>
         <groups-properties path="kerberos-groups.properties" relative-to="kerberos"/>
       </properties-realm>
     </security-realms>
     <credential-security-factories>
       <kerberos-security-factory name="test-server" principal="remote/test-server.elytron.org@ELYTRON.ORG" path="remote-test-server.keytab" relative-to="kerberos"/>
     </credential-security-factories>
     ...
     <sasl>
       ...
       <sasl-authentication-factory name="gssapi-authentication-factory" sasl-server-factory="elytron" security-domain="KerberosDomain">
         <mechanism-configuration>
           <mechanism mechanism-name="GSSAPI" credential-security-factory="test-server"/>
         </mechanism-configuration>
       </sasl-authentication-factory>
       ...
     </sasl>
   </subsystem>

The management interface or Remoting connectors can now be updated to reference the SASL authentication factory.

The two Elytron examples defined here could also be combined into one to use a shared security domain and security realm and just use protocol specific authentication factories each referencing their own Kerberos security factory.

16.7. Caching Migration

Where a PicketBox based security domain is defined it is possible to enable caching for that security domain, this enables subsequent hits to the identity store to be avoided as an in memory cache can be used instead, this example demonstrates how caching can be used with a WildFly Elytron based configuration.

The purpose of this chapter is to highlight the migration of a configuration with caching enabled, this example is based in the previous LDAP example but with caching enabled.

16.7.1. PicketBox Example

A PicketBox based security domain can be defined with the following commands.

./subsystem=security/security-domain=application-security:add(cache-type=default)
./subsystem=security/security-domain=application-security/authentication=classic:add(login-modules=[{code=LdapExtended, flag=Required, module-options={ \
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, \
java.naming.provider.url=ldap://localhost:10389, \
java.naming.security.authentication=simple, \
bindDN="uid=admin,ou=system", \
bindCredential=secret, \
baseCtxDN="ou=users,dc=group-to-principal,dc=wildfly,dc=org", \
baseFilter="(uid={0})", \
rolesCtxDN="ou=groups,dc=group-to-principal,dc=wildfly,dc=org",\
roleFilter="(uniqueMember={1})", \
roleAttributeID="uid" \
}}])

Resulting in the following security domain definition:

<subsystem xmlns="urn:jboss:domain:security:2.0">
  <security-domains>
    ...
    <security-domain name="application-security" cache-type="default">
      <authentication>
        <login-module code="LdapExtended" flag="required">
          <module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
          <module-option name="java.naming.provider.url" value="ldap://localhost:10389"/>
          <module-option name="java.naming.security.authentication" value="simple"/>
          <module-option name="bindDN" value="uid=admin,ou=system"/>
          <module-option name="bindCredential" value="secret"/>
          <module-option name="baseCtxDN" value="ou=users,dc=group-to-principal,dc=wildfly,dc=org"/>
          <module-option name="baseFilter" value="(uid={0})"/>
          <module-option name="rolesCtxDN" value="ou=groups,dc=group-to-principal,dc=wildfly,dc=org"/>
          <module-option name="roleFilter" value="(uniqueMember={1})"/>
          <module-option name="roleAttributeID" value="uid"/>
        </login-module>
      </authentication>
    </security-domain>
  </security-domains>
</subsystem>

16.7.2. Migrated Example

When using WildFly Elytron where caching is required the individual security realm is wrapped using a cache, a migrated configuration can be defined with the following commands:

./subsystem=elytron/dir-context=ldap-connection:add(url=ldap://localhost:10389, principal="uid=admin,ou=system", credential-reference={clear-text=secret})
./subsystem=elytron/ldap-realm=ldap-realm:add(dir-context=ldap-connection, \
direct-verification=true, \
identity-mapping={search-base-dn="ou=users,dc=group-to-principal,dc=wildfly,dc=org", \
rdn-identifier="uid", \
attribute-mapping=[{filter-base-dn="ou=groups,dc=group-to-principal,dc=wildfly,dc=org",filter="(uniqueMember={1})",from="uid",to="Roles"}]})
./subsystem=elytron/caching-realm=cached-ldap:add(realm=ldap-realm)

These can then be used in a security domain and subsequently an authentication factory.

./subsystem=elytron/security-domain=application-security:add(realms=[{realm=cached-ldap}], default-realm=cached-ldap, permission-mapper=default-permission-mapper)
./subsystem=elytron/http-authentication-factory=application-security-http:add(http-server-mechanism-factory=global, security-domain=application-security, mechanism-configurations=[{mechanism-name=BASIC}])

In this final step it is very important that the caching-realm is referenced rather than the original realm otherwise caching will be bypassed.

This results in the following definitions:

<subsystem xmlns="urn:wildfly:elytron:1.1" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
  ...
  <security-domains>
    ...
    <security-domain name="application-security" default-realm="cached-ldap" permission-mapper="default-permission-mapper">
      <realm name="cached-ldap"/>
    </security-domain>
  </security-domains>
  <security-realms>
    ...
    <ldap-realm name="ldap-realm" dir-context="ldap-connection" direct-verification="true">
      <identity-mapping rdn-identifier="uid" search-base-dn="ou=users,dc=group-to-principal,dc=wildfly,dc=org">
        <attribute-mapping>
          <attribute from="uid" to="Roles" filter="(uniqueMember={1})" filter-base-dn="ou=groups,dc=group-to-principal,dc=wildfly,dc=org"/>
        </attribute-mapping>
      </identity-mapping>
    </ldap-realm>
    <caching-realm name="cached-ldap" realm="ldap-realm"/>
  </security-realms>
  ...
  <http>
    ...
    <http-authentication-factory name="application-security-http" http-server-mechanism-factory="global" security-domain="application-security">
      <mechanism-configuration>
        <mechanism mechanism-name="BASIC"/>
      </mechanism-configuration>
    </http-authentication-factory>
    ...
  </http>
  ...
  <dir-contexts>
    <dir-context name="ldap-connection" url="ldap://localhost:10389" principal="uid=admin,ou=system">
      <credential-reference clear-text="secret"/>
    </dir-context>
  </dir-contexts>
</subsystem>

16.8. Clients

16.9. Application Client Migration

16.9.1. Naming Client

This migration example assumes a client application performs a remote JNDI lookup using an  InitialContext backed by the org.jboss.naming.remote.client.InitialContextFactory class.

Original Configuration

An InitialContext backed by the org.jboss.naming.remote.client.InitialContextFactory class can be created by specifying properties that contain the URL of the naming provider to connect to along with appropriate user credentials:

Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
properties.put(Context.PROVIDER_URL, "http-remoting://127.0.0.1:8080");
properties.put(Context.SECURITY_PRINCIPAL, "bob");
properties.put(Context.SECURITY_CREDENTIALS, "secret");
InitialContext context = new InitialContext(properties);
Bar bar = (Bar) context.lookup("foo/bar");
...
Migrated Configuration

An InitialContext backed by the org.wildfly.naming.client.WildFlyInitialContextFactory class can be created by specifying a property that contains the URL of the naming provider to connect to. The user credentials can be specified using a WildFly client configuration file or programmatically.

Configuration File Approach

A wildfly-config.xml file that contains the user credentials to use when establishing a connection to the naming provider can be added to the client application’s META-INF directory:

wildfly-config.xml

<configuration>
    <authentication-client xmlns="urn:elytron:1.0">
        <authentication-rules>
            <rule use-configuration="namingConfig">
                <match-host name="127.0.0.1"/>
            </rule>
        </authentication-rules>
        <authentication-configurations>
            <configuration name="namingConfig">
                <set-user-name name="bob"/>
                <credentials>
                    <clear-password password="secret"/>
                </credentials>
            </configuration>
        </authentication-configurations>
    </authentication-client>
</configuration>

An InitialContext can then be created as follows:

Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
properties.put(Context.PROVIDER_URL, "remote+http://127.0.0.1:8080");
InitialContext context = new InitialContext(properties);
Bar bar = (Bar) context.lookup("foo/bar");
...
Programmatic Approach

The user credentials to use when establishing a connection to the naming provider can be specified directly in the client application’s code:

// create your authentication configuration
AuthenticationConfiguration namingConfig = AuthenticationConfiguration.empty().useName("bob").usePassword("secret");
 
// create your authentication context
AuthenticationContext context = AuthenticationContext.empty().with(MatchRule.ALL.matchHost("127.0.0.1"), namingConfig);
 
// create a callable that creates and uses an InitialContext
Callable<Void> callable = () -> {
    Properties properties = new Properties();
    properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
    properties.put(Context.PROVIDER_URL, "remote+http://127.0.0.1:8080");
    InitialContext context = new InitialContext(properties);
    Bar bar = (Bar) context.lookup("foo/bar");
    ...
    return null;
};
 
// use your authentication context to run your callable
context.runCallable(callable);

16.9.2. EJB Client

This migration example assumes a client application is configured to invoke an EJB deployed on a remote server using a jboss-ejb-client.properties file.

Original Configuration

A jboss-ejb-client.properties file that contains the information needed to connect to the remote server can be specified in a client application’s META-INF directory:

jboss-ejb-client.properties

remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=127.0.0.1
remote.connection.default.port = 8080
remote.connection.default.username=bob
remote.connection.default.password=secret

An EJB can then be looked up and a method can be invoked on it as follows:

// create an InitialContext
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
properties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
InitialContext context = new InitialContext(properties);
 
// look up an EJB and invoke one of its methods
RemoteCalculator statelessRemoteCalculator = (RemoteCalculator) context.lookup(
    "ejb:/ejb-remote-server-side//CalculatorBean!" + RemoteCalculator.class.getName());
int sum = statelessRemoteCalculator.add(101, 202);
Migrated Configuration

The information needed to connect to the remote server can be specified using a WildFly client configuration file or programmatically.

Configuration File Approach

A wildfly-config.xml file that contains the information needed to connect to the remote server can be added to the client application’s META-INF directory:

wildfly-config.xml

<configuration>
    <authentication-client xmlns="urn:elytron:1.0">
        <authentication-rules>
            <rule use-configuration="ejbConfig">
                <match-host name="127.0.0.1"/>
            </rule>
        </authentication-rules>
        <authentication-configurations>
            <configuration name="ejbConfig">
                <set-user-name name="bob"/>
                <credentials>
                    <clear-password password="secret"/>
                </credentials>
            </configuration>
        </authentication-configurations>
    </authentication-client>
    <jboss-ejb-client xmlns="urn:jboss:wildfly-client-ejb:3.0">
        <connections>
            <connection uri="remote+http://127.0.0.1:8080" />
        </connections>
    </jboss-ejb-client>
</configuration>

An EJB can then be looked up and a method can be invoked on it as follows:

// create an InitialContext
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
InitialContext context = new InitialContext(properties);
 
// look up an EJB and invoke one of its methods (same as before)
RemoteCalculator statelessRemoteCalculator = (RemoteCalculator) context.lookup(
    "ejb:/ejb-remote-server-side//CalculatorBean!" + RemoteCalculator.class.getName());
int sum = statelessRemoteCalculator.add(101, 202);
Programmatic Approach

The information needed to connect to the remote server can be specified directly in the client application’s code:

// create your authentication configuration
AuthenticationConfiguration ejbConfig = AuthenticationConfiguration.empty().useName("bob").usePassword("secret");
 
// create your authentication context
AuthenticationContext context = AuthenticationContext.empty().with(MatchRule.ALL.matchHost("127.0.0.1"), ejbConfig);
 
// create a callable that invokes an EJB
Callable<Void> callable = () -> {
 
    // create an InitialContext
    Properties properties = new Properties();
    properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
    properties.put(Context.PROVIDER_URL, "remote+http://127.0.0.1:8080");
    InitialContext context = new InitialContext(properties);
 
    // look up an EJB and invoke one of its methods (same as before)
    RemoteCalculator statelessRemoteCalculator = (RemoteCalculator) context.lookup(
        "ejb:/ejb-remote-server-side//CalculatorBean!" + RemoteCalculator.class.getName());
    int sum = statelessRemoteCalculator.add(101, 202);
    ...
    return null;
};
 
// use your authentication context to run your callable
context.runCallable(callable);

16.10. General Utilities

16.11. Security Vault Migration

Security Vault is primarily used in legacy configurations, a vault is used to store sensitive strings outside of the configuration files. WildFly server may only contain a single security vault.

Credential Store introduced in WildFly 11 is meant to expand Security Vault in terms of storing different credential types and introduce easy to implemnent SPI which allows to deploy custom implemenations of CredentialStore SPI. Credentials are stored safely encrypted in storage file outside WildFly configuration files. Each WildFly server may contain multiple credential stores.

To easily migrate vault content into credential store we have added "vault" command into WildFly Elytron Tool. The tool could be found at $JBOSS_HOME/bin directory. It has several scripts named "elytron-tool.*" dependent on your platform of choice. One can use also simple form "java -jar $JBOSS_HOME/bin/wildfly-elytron-tool.jar <command> <arguments>" if it better suites ones needs.

16.11.1. Single Security Vault Conversion

To convert single security vault credential store use following example:

  • to get sample vault use testing resources of Elytron Tool project from GitHub

Command to run actual conversion:

./bin/elytron-tool.sh vault --enc-dir vault_data/ --keystore vault-jceks.keystore --keystore-password MASK-2hKo56F1a3jYGnJwhPmiF5 --iteration 34 --salt 12345678 --alias test --location cs-v1.store --summary

Output:

Vault (enc-dir="vault_data/";keystore="vault-jceks.keystore") converted to credential store "cs-v1.store"
Vault Conversion summary:
--------------------------------------
Vault Conversion Successful
CLI command to add new credential store:
/subsystem=elytron/credential-store=test:add(relative-to=jboss.server.data.dir,create=true,modifiable=true,location="cs-v1.store",implementation-properties={"keyStoreType"⇒"JCEKS"},credential-reference={clear-text="MASK-2hKo56F1a3jYGnJwhPmiF5;12345678;34"})

Use elytron-tool.sh vault --help to get description of all parameters.

Notes:
  • Elytron Tool cannot handle very first version of Security Vault data file.

  • --keystore-password can come in two forms (1) masked as shown in the example or (2) clear text. Parameter --salt and --iteration are there to supply information to decrypt the masked password or to generate masked password in output. In case --salt and --iteration are omitted default values are used.

  • When --summary parameter is specified, one can see nice output with CLI command to be used in WildFly console to add converted credential store to the configuration.

16.11.2. Bulk Security Vault Conversion

There is possibility to convert multiple vaults to credential store using --bulk-convert parameter with description file.
Example of description file from our tests:

# Bulk conversion descriptor
keystore:target/test-classes/vault-v1/vault-jceks.keystore
keystore-password:MASK-2hKo56F1a3jYGnJwhPmiF5
enc-dir:target/test-classes/vault-v1/vault_data/
salt:12345678
iteration:34
location:target/v1-cs-1.store
alias:test

keystore:target/test-classes/vault-v1/vault-jceks.keystore
keystore-password:secretsecret
enc-dir:target/test-classes/vault-v1/vault_data/
location:target/v1-cs-2.store
alias:test

# different vault vault-v1-more
keystore:target/test-classes/vault-v1-more/vault-jceks.keystore
keystore-password:MASK-2hKo56F1a3jYGnJwhPmiF5
enc-dir:target/test-classes/vault-v1-more/vault_data/
salt:12345678
iteration:34
location:target/v1-cs-more.store
alias:test

After each "keystore:" option new conversion starts. All options are mandatory except "salt:", "iteration:" and "properties:"

Execute following command:

./bin/elytron-tool.sh vault --bulk-convert bulk-vault-conversion-desc --summary

Output:

Vault (enc-dir="vault-v1/vault_data/";keystore="vault-v1/vault-jceks.keystore") converted to credential store "v1-cs-1.store"
Vault Conversion summary:
--------------------------------------
Vault Conversion Successful
CLI command to add new credential store:
/subsystem=elytron/credential-store=test:add(relative-to=jboss.server.data.dir,create=true,modifiable=true,location="v1-cs-1.store",implementation-properties={"keyStoreType"⇒"JCEKS"},credential-reference={clear-text="MASK-2hKo56F1a3jYGnJwhPmiF5;12345678;34"})
--------------------------------------

Vault (enc-dir="vault-v1/vault_data/";keystore="vault-v1/vault-jceks.keystore") converted to credential store "v1-cs-2.store"
Vault Conversion summary:
--------------------------------------
Vault Conversion Successful
CLI command to add new credential store:
/subsystem=elytron/credential-store=test:add(relative-to=jboss.server.data.dir,create=true,modifiable=true,location="v1-cs-2.store",implementation-properties={"keyStoreType"⇒"JCEKS"},credential-reference={clear-text="secretsecret"})
--------------------------------------

Vault (enc-dir="vault-v1-more/vault_data/";keystore="vault-v1-more/vault-jceks.keystore") converted to credential store "v1-cs-more.store"
Vault Conversion summary:
--------------------------------------
Vault Conversion Successful
CLI command to add new credential store:
/subsystem=elytron/credential-store=test:add(relative-to=jboss.server.data.dir,create=true,modifiable=true,location="v1-cs-more.store",implementation-properties={"keyStoreType"⇒"JCEKS"},credential-reference={clear-text="MASK-2hKo56F1a3jYGnJwhPmiF5;12345678;34"})
--------------------------------------

The result is conversion of all vaults with proper CLI commands.

16.12. Security Properties

Lets suppose security properties "a" and "c" defined in legacy security:

        <subsystem xmlns="urn:jboss:domain:security:2.0">
            ...
            <security-properties>
                <property name="a" value="b" />
                <property name="c" value="d" />
            </security-properties>
        </subsystem>

To define security properties in Elytron subsystem you need to set attribute security-properties of the subsystem:

./subsystem=elytron:write-attribute(name=security-properties, value={ \
    a = "b", \
    c = "d" \
})

You can also add or change one another property without modification of others using map operations. Following command will set property "e":

./subsystem=elytron:map-put(name=security-properties, key=e, value=f)

By the same way you can also remove one of properties - in example newly created property "e":

./subsystem=elytron:map-remove(name=security-properties, key=e)

Output XML configuration will be:

        <subsystem xmlns="urn:wildfly:elytron:1.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
            <security-properties>
                <security-property name="a" value="b"/>
                <security-property name="c" value="d"/>
            </security-properties>
            ...
        </subsystem>

16.13. SSL Migration

16.14. Simple SSL Migration

16.14.1. Simple SSL Migration

This section describe securing HTTP connections to the server using SSL using Elytron.
It suppose you have already configured SSL using legacy security-realm, for example by Admin Guide#Enable SSL, and your configuration looks like:

<security-realm name="ApplicationRealm">
  <server-identities>
    <ssl>
      <keystore path="server.keystore" relative-to="jboss.server.config.dir" keystore-password="keystore_password" alias="server" key-password="key_password" />
    </ssl>
  </server-identities>
</security-realm>

To switch to Elytron you need to:

  1. Create Elytron key-store - specifying where is the keystore file stored and password by which it is encrypted. Default type of keystore generated using keytool is JKS:

    /subsystem=elytron/key-store=LocalhostKeyStore:add(path=server.keystore,relative-to=jboss.server.config.dir,credential-reference={clear-text="keystore_password"},type=JKS)
  2. Create Elytron key-manager - specifying keystore, alias (using alias-filter) and password of key:

    /subsystem=elytron/key-manager=LocalhostKeyManager:add(key-store=LocalhostKeyStore,alias-filter=server,credential-reference={clear-text="key_password"})
  3. Create Elytron server-ssl-context - specifying only reference to key-manager defined above:

    /subsystem=elytron/server-ssl-context=LocalhostSslContext:add(key-manager=LocalhostKeyManager)
  4. Switch https-listener from legacy security-realm to newly created Elytron ssl-context:

    /subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(name=security-realm)
    /subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=ssl-context,value=LocalhostSslContext)
  5. And reload the server:

    reload

Output XML configuration of Elytron subsystem should look like:

        <subsystem xmlns="urn:wildfly:elytron:1.0" ...>
            ...
            <tls>
                <key-stores>
                    <key-store name="LocalhostKeyStore">
                        <credential-reference clear-text="keystore_password"/>
                        <implementation type="JKS"/>
                        <file path="server.keystore" relative-to="jboss.server.config.dir"/>
                    </key-store>
                </key-stores>
                <key-managers>
                    <key-manager name="LocalhostKeyManager" key-store="LocalhostKeyStore">
                        <credential-reference clear-text="key_password"/>
                    </key-manager>
                </key-managers>
                <server-ssl-contexts>
                    <server-ssl-context name="LocalhostSslContext" key-manager="LocalhostKeyManager"/>
                </server-ssl-contexts>
            </tls>
        </subsystem>

Output https-listener in Undertow subsystem should be:

<https-listener name="https" socket-binding="https" ssl-context="LocalhostSslContext" enable-http2="true"/>

16.14.2. Client-Cert SSL Authentication Migration

This suppose you have already configured Client-Cert SSL authentication using truststore in legacy security-realm, for example by Admin Guide#Add Client-Cert to SSL, and your configuration looks like:

<security-realm name="ApplicationRealm">
  <server-identities>
    <ssl>
      <keystore path="server.keystore" relative-to="jboss.server.config.dir" keystore-password="keystore_password" alias="server" key-password="key_password" />
    </ssl>
  </server-identities>
  <authentication>
    <truststore path="server.truststore" relative-to="jboss.server.config.dir" keystore-password="truststore_password" />
    <local default-user="$local"/>
    <properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
  </authentication>
</security-realm>
Following configuration is sufficient to prevent users without valid certificate and private key to access the server, but it does not provide user identity to the application. That require to define CLIENT_CERT HTTP mechanism / EXTERNAL SASL mechanism, which will be described later.)

At first use steps above to migrate basic part of the configuration. Then continue by following:

  1. Create key-store of truststore - like for keystore above:

    /subsystem=elytron/key-store=TrustStore:add(path=server.truststore,relative-to=jboss.server.config.dir,credential-reference={clear-text="truststore_password"},type=JKS)
  2. Create trust-manager - specifying key-store of trustore, created above:

    /subsystem=elytron/trust-manager=TrustManager:add(key-store=TrustStore)
  3. Modify server-ssl-context to use newly created trustmanager:

    /subsystem=elytron/server-ssl-context=LocalhostSslContext:write-attribute(name=trust-manager,value=TrustManager)
  4. Enable client authentication for server-ssl-context:

    /subsystem=elytron/server-ssl-context=LocalhostSslContext:write-attribute(name=need-client-auth,value=true)
  5. And reload the server:

    reload

Output XML configuration of Elytron subsystem should look like:

<subsystem xmlns="urn:wildfly:elytron:1.0" ...>
    ...
    <tls>
        <key-stores>
            <key-store name="LocalhostKeyStore">
                <credential-reference clear-text="keystore_password"/>
                <implementation type="JKS"/>
                <file path="server.keystore" relative-to="jboss.server.config.dir"/>
            </key-store>
            <key-store name="TrustStore">
                <credential-reference clear-text="truststore_password"/>
                <implementation type="JKS"/>
                <file path="server.truststore" relative-to="jboss.server.config.dir"/>
            </key-store>
        </key-stores>
        <key-managers>
            <key-manager name="LocalhostKeyManager" key-store="LocalhostKeyStore" alias-filter="server">
                <credential-reference clear-text="key_password"/>
            </key-manager>
        </key-managers>
        <trust-managers>
            <trust-manager name="TrustManager" key-store="TrustStore"/>
        </trust-managers>
        <server-ssl-contexts>
            <server-ssl-context name="LocalhostSslContext" need-client-auth="true" key-manager="LocalhostKeyManager" trust-manager="TrustManager"/>
        </server-ssl-contexts>
    </tls>
</subsystem>

16.15. SSL with Client Cert Migration

As this documentation is primarily intended for users migrating to WildFly Elytron I am going to jump straight into the configuration required with WildFly Elytron.

This section will cover how to create the various resources required to achieve CLIENT_CERT authentication with fallback to username / password authentication for both HTTP and SASL (i.e. Remoting) - both are being covered at the same time as predominantly they require the same core configuration, it is not until the definition of the authentication factories that the configuration becomes really specific.

This suppose you have configured legacy Client-Cert SSL authentication using truststore in legacy security-realm, for example by Admin Guide#Add Client-Cert to SSL, and your configuration looks like:

<security-realm name="ManagementRealm">
  <server-identities>
    <ssl>
      <keystore path="server.keystore" relative-to="jboss.server.config.dir" keystore-password="keystore_password" alias="server" key-password="key_password" />
    </ssl>
  </server-identities>
  <authentication>
    <truststore path="server.truststore" relative-to="jboss.server.config.dir" keystore-password="truststore_password" />
    <local default-user="$local"/>
    <properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
  </authentication>
</security-realm>

This also suppose you have already followed Simple SSL Migration section, so your partialy migrated configuration looks like:

<subsystem xmlns="urn:wildfly:elytron:1.0" ...>
    ...
    <tls>
        <key-stores>
            <key-store name="LocalhostKeyStore">
                <credential-reference clear-text="keystore_password"/>
                <implementation type="JKS"/>
                <file path="server.keystore" relative-to="jboss.server.config.dir"/>
            </key-store>
            <key-store name="TrustStore">
                <credential-reference clear-text="truststore_password"/>
                <implementation type="JKS"/>
                <file path="server.truststore" relative-to="jboss.server.config.dir"/>
            </key-store>
        </key-stores>
        <key-managers>
            <key-manager name="LocalhostKeyManager" key-store="LocalhostKeyStore" alias-filter="server">
                <credential-reference clear-text="key_password"/>
            </key-manager>
        </key-managers>
        <trust-managers>
            <trust-manager name="TrustManager" key-store="TrustStore"/>
        </trust-managers>
        <server-ssl-contexts>
            <server-ssl-context name="LocalhostSslContext" need-client-auth="true" key-manager="LocalhostKeyManager" trust-manager="TrustManager"/>
        </server-ssl-contexts>
    </tls>
</subsystem>

However following steps are needed to be user identity provided to your applications or management console.

16.15.1. Realms and Domains

We use users stored in standard properties files, so we can predefined Elytron security domain ManagementDomain and realm ManagementRealm:

    <security-domains>
        <security-domain name="ManagementDomain" default-realm="ManagementRealm" permission-mapper="default-permission-mapper">
            <realm name="ManagementRealm" role-decoder="groups-to-roles"/>
            <realm name="local"/>
        </security-domain>
    </security-domains>
    <security-realms>
        <properties-realm name="ManagementRealm">
            <users-properties path="mgmt-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ManagementRealm"/>
            <groups-properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
        </properties-realm>
    </security-realms>

The security realm will be used in two situations: * Authentication in password fallback case, when certificate authentication fails * Authorization in both - password and certificate auth - cases - the realm will provide roles of individual users

This mean, for any client certificate there have to exists user in the security realm.

16.15.2. Principal decoder

When certificate authentication is used and the security realm accepts usernames to resolve an identity, there have to be defined way to obtain username from a client certificate. In this case we will use first CN attribute in certificate subject:

./subsystem=elytron/x500-attribute-principal-decoder=x500-decoder:add(attribute-name=CN, maximum-segments=1)

Resulting in: -

<subsystem xmlns="urn:wildfly:elytron:1.1" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
  ...
  <mappers>
    ...
    <x500-attribute-principal-decoder name="x500-decoder" attribute-name="CN" maximum-segments="1"/>
    ...
  </mappers>
  ...
</subsystem>

16.15.3. HTTP Authentication Factory

For the HTTP connections we now define a HTTP authentication factory using the previously defined resources and it is configured to support CLIENT_CERT and DIGEST authentication.

Because our security realm is not able to verify client certificates (properties realm verifies passwords only), we need to add configuring mechanism factory first, which will disable certificate verification against the security realm:

/subsystem=elytron/configurable-http-server-mechanism-factory=configured-cert:add(http-server-mechanism-factory=global, properties={org.wildfly.security.http.skip-certificate-verification=true})

As following, we can create HTTP authentication alone:

./subsystem=elytron/http-authentication-factory=client-cert-digest:add(http-server-mechanism-factory=configured-cert, \
  security-domain=ManagementDomain, \
 mechanism-configurations=[{ \
  mechanism-name=CLIENT_CERT, \
  pre-realm-principal-transformer=x500-decoder}, \
 {mechanism-name=DIGEST, mechanism-realm-configurations=[{realm-name=ManagementRealm}]}])

Resulting in: -

<subsystem xmlns="urn:wildfly:elytron:1.1" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
  ...
  <http>
    ...
    <http-authentication-factory name="client-cert-digest" http-server-mechanism-factory="global" security-domain="ManagementDomain">
      <mechanism-configuration>
        <mechanism mechanism-name="CLIENT_CERT" pre-realm-principal-transformer="x500-decoder"/>
        <mechanism mechanism-name="DIGEST">
          <mechanism-realm realm-name="ManagementRealm"/>
        </mechanism>
      </mechanism-configuration>
    </http-authentication-factory>
    ...
    <configurable-http-server-mechanism-factory name="configured-cert" http-server-mechanism-factory="global">
        <properties>
            <property name="org.wildfly.security.http.skip-certificate-verification" value="true"/>
        </properties>
    </configurable-http-server-mechanism-factory>
    ...
  </http>
  ...
</subsystem>

16.15.4. SASL Authentication Factory

The architecture of the two authentication factories if very similar so a SASL authentication factory can be defined in the same way as the HTTP equivalent. However, as EXTERNAL SASL mechanism does not do any certificate verification, there is no need for configuring SASL server factory.

./subsystem=elytron/sasl-authentication-factory=client-cert-digest:add(sasl-server-factory=elytron, \
  security-domain=ManagementDomain, \
  mechanism-configurations=[{mechanism-name=EXTERNAL, \
  pre-realm-principal-transformer=x500-decoder}, \
  {mechanism-name=DIGEST-MD5, mechanism-realm-configurations=[{realm-name=ManagementRealm}]}])

This results in: -

<subsystem xmlns="urn:wildfly:elytron:1.1" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
  ...
  <sasl>
    ...
    <sasl-authentication-factory name="client-cert-digest" sasl-server-factory="elytron" security-domain="ManagementDomain">
      <mechanism-configuration>
        <mechanism mechanism-name="EXTERNAL" pre-realm-principal-transformer="x500-decoder"/>
        <mechanism mechanism-name="DIGEST-MD5">
          <mechanism-realm realm-name="ManagementRealm"/>
        </mechanism>
      </mechanism-configuration>
    </sasl-authentication-factory>
    ...
  </sasl>
  ...
</subsystem>

There is used the same principal transformer as defined for HTTP.

16.15.5. SSL Context

The SSL context was already defined, but we need to modify it to not fail on client certificate authentication failure, but to fallback to password authentication.

./subsystem=elytron/server-ssl-context=LocalhostSslContext:write-attribute(name=need-client-auth, value=false)
./subsystem=elytron/server-ssl-context=LocalhostSslContext:write-attribute(name=want-client-auth, value=true)

Resulting in: -

<subsystem xmlns="urn:wildfly:elytron:1.1" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
  ...
  <tls>
    ...
    <server-ssl-contexts>
      <server-ssl-context name="LocalhostSslContext" want-client-auth="true" need-client-auth="false" key-manager="LocalhostKeyManager" trust-manager="TrustManager"/>
    </server-ssl-contexts>
  </tls>
</subsystem>

As we will be supporting fallback to username/password authentication need-client-auth is set to false. This allows connections to be established but an alternative form of authentication will be required.

16.15.6. Using for Management

At this point the management interfaces can be updated to use the newly defined resources, we need to add references to the two new authentication factories and the SSL context, we can also remove the existing reference to the legacy security realm. As this is modifying existing interfaces a server reload will also be required.

./core-service=management/management-interface=http-interface:write-attribute(name=ssl-context, value=LocalhostSslContext)
./core-service=management/management-interface=http-interface:write-attribute(name=secure-socket-binding, value=management-https)
./core-service=management/management-interface=http-interface:write-attribute(name=http-authentication-factory, value=client-cert-digest)
./core-service=management/management-interface=http-interface:write-attribute(name=http-upgrade.sasl-authentication-factory, value=client-cert-digest)
./core-service=management/management-interface=http-interface:undefine-attribute(name=security-realm)
:reload

The management interface configuration then becomes: -

<management>
  ...
  <management-interfaces>
    <http-interface http-authentication-factory="client-cert-digest" ssl-context="LocalhostSslContext">
      <http-upgrade enabled="true" sasl-authentication-factory="client-cert-digest"/>
      <socket-binding http="management-http" https="management-https"/>
    </http-interface>
  </management-interfaces>
  ...
</management>
Admin Clients

At this stage assuming the same files have been used as in this example it should be possible to connect to the management interface of the server either using a web browser or the JBoss CLI with username and password from your original mgmt-users.properties file.

For certificate based authentication certificates signed by your CA, whose subject DN resolves to username existing in properties realm will be accepted.

CLI Client Configuration

This suppose you have used following configuration in bin/jboss-cli.xml:

<ssl>
  <alias>adminalias</alias>
  <key-store>admin.keystore</key-store>
  <key-store-password>keystore_password</key-store-password>
  <trust-store>ca.truststore</trust-store>
  <trust-store-password>truststore_password</trust-store-password>
</ssl>

You can stay using this configuration, but since the integration of WildFly Elytron it is possible with the CLI to use a configuration file wildfly-config.xml to define the security settings including the settings for the client side SSL context.

In such case, following wildfly-config.xml can be created in the location the JBoss CLI is being started from: -

<?xml version="1.0" encoding="UTF-8"?>

<configuration>
    <authentication-client xmlns="urn:elytron:1.0">
        <key-stores>
            <key-store name="admin" type="jks" >
                <file name="admin.keystore"/>
                <key-store-clear-password password="keystore_password" />
            </key-store>
            <key-store name="ca" type="jks">
                <file name="ca.truststore"/>
                <key-store-clear-password password="truststore_password" />
            </key-store>
        </key-stores>
        <ssl-context-rules>
            <rule use-ssl-context="default" />
        </ssl-context-rules>
        <ssl-contexts>
            <ssl-context name="default">
                <key-store-ssl-certificate key-store-name="admin" alias="adminalias">
                    <key-store-clear-password password="key_password" />
                </key-store-ssl-certificate>
                <trust-store key-store-name="ca" />
            </ssl-context>
        </ssl-contexts>
    </authentication-client>
</configuration>

The CLI can now be started using the following command: -

./jboss-cli.sh -c -Dwildfly.config.url=wildfly-config.xml

The :whoami command can be used within the CLI to double check the current identity.

[standalone@localhost:9993 /] :whoami(verbose=true)
{
    "outcome" => "success",
    "result" => {
        "identity" => {"username" => "admin"},
        "mapped-roles" => ["SuperUser"]
    }
}

16.16. Documentation Still Needed

  • How to migrate application which uses different identity store for authentication and authorization (migration to Elytron aggregate-realm).

  • How migrate to using cache (migration to caching-realm)

  • Limitations for migration from PicketBox/legacy security to Elytron, for example, Infinispan cache cannot be used, any others?