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:
-
Use the default Elytron components for application and management authentication
-
Secure an application with a new identity store stored in a filesystem or database.
-
Set up one-way SSL/TLS for applications or the management interfaces.
-
Set up two-way SSL/TLS for applications or the management interfaces.
-
Create a credential store and use it with your SSL/TLS configuration.
-
Override an application’s authentication configuration with Elytron authentication.
-
Secure applications and the management interfaces with an LDAP-based identity store.
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. |
trust-managers |
A trust manager definition for creating the TrustManager list as used to create an SSL context. |
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 |
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-managers |
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. |
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. |
application-http-authentication |
The application-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 ApplicationDomain for authenticating principals. It accepts BASIC and FORM authentication mechanisms and exposes BASIC as Application Realm 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,
"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,
"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"
},
"application-http-authentication" => {
"http-server-mechanism-factory" => "global",
"mechanism-configurations" => [
{
"mechanism-name" => "BASIC",
"mechanism-realm-configurations" => [{"realm-name" => "Application Realm"}]
},
{"mechanism-name" => "FORM"}
],
"security-domain" => "ApplicationDomain"
}
},
"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,
"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" => {
"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"
},
"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"
}
},
"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=application-http-authentication)
3.4.2. Default Elytron Application HTTP Authentication Configuration
By default, the application-http-authentication http-authentication-factory is provided for application http authentication.
/subsystem=elytron/http-authentication-factory=application-http-authentication:read-resource()
{
"outcome" => "success",
"result" => {
"http-server-mechanism-factory" => "global",
"mechanism-configurations" => [
{
"mechanism-name" => "BASIC",
"mechanism-realm-configurations" => [{"realm-name" => "Application Realm"}]
},
{"mechanism-name" => "FORM"}
],
"security-domain" => "ApplicationDomain"
}
}
The application-http-authentication http-authentication-factory is 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",
"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,
"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"
}
}
}
3.5.3. Default Elytron Management CLI Authentication
By default, the management CLI ( jboss-cli.sh) is configured to connect over remotehttp.
Default jboss-cli.xml
<jboss-cli xmlns="urn:jboss:cli:3.1">
Â
<default-protocol use-legacy-override="true">remotehttp</default-protocol>
Â
<!-- The default controller to connect to when 'connect' command is executed w/o arguments -->
<default-controller>
<protocol>remotehttp</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 |
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/identity=user1:add()
/subsystem=elytron/filesystem-realm=exampleFsRealm/identity=user1:set-password( clear={password="password123"})
/subsystem=elytron/filesystem-realm=exampleFsRealm/identity=user1: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:
/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(uri="cr-store://exampleCS?create=true",credential-reference={clear-text=cs-secret})
Add a credential to a credential store.
/subsystem=elytron/credential-store=exampleCS/alias=keystorepw:add(secret-value="secret")
List all credentials in a credential store.
/subsystem=elytron/credential-store=exampleCS:read-children-names(child-type=alias)
{
"outcome" => "success",
"result" => ["keystorepw"]
}
Remove a credential from a credential store.
/subsystem=elytron/credential-store=exampleCS/alias=keystorepw:remove
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()
4.3.6. 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.7. 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.8. 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.9. 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.10. 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
When creating custom implementations of Elytron components, they must present the appropriate capabilities and requirements.
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-http-authentication by default which can be used to secure applications. For more details on how application-http-authentication is configured, see the Out of the Box Configuration section.
To configure applications to use application-http-authentication, see Configure Applications to Use Elytron or Legacy Security for Authentication. 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. |
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
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.
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-userinfo |
Matches against URIs with no userinfo. |
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-userinfo |
Takes a single name attribute specifying the userinfo 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-userinfo 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
Schema location: [https://github.com/wildfly/jboss-ejb-client/blob/4.0.2.Final/src/main/resources/schema/wildfly-client-ejb_3_0.xsd]
Example configuration:
<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
Schema location:[https://github.com/wildfly/wildfly-http-client/blob/1.0.2.Final/common/src/main/resources/schema/wildfly-http-client_1_0.xsd]
Example configuration:
<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
Schema location:[https://github.com/jboss-remoting/jboss-remoting/blob/5.0.1.Final/src/main/resources/schema/jboss-remoting_5_0.xsd]
Example configuration:
<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
Schema location:[https://github.com/xnio/xnio/blob/3.5.1.Final/api/src/main/resources/schema/xnio_3_5.xsd]
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)
8. Using KeyCloak with WildFly Elytron
TBD
9. OpenSSL
10. 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.
10.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
10.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}]
10.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.
10.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)
10.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.
10.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 ----
10.3. Deploy an Application
For the sake of simplicity, these are the minimum files you need in your application:
<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>
<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
11. Migrate Legacy Security to Elytron Security
11.1. Authentication Configuration
11.2. Properties Based Authentication / Authorization
11.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.
11.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>
11.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.
11.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>
11.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>
11.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>
11.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.
11.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.
11.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.
11.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.
11.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>
11.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.
11.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>
11.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>
11.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.
11.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.
11.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.
11.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>
11.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>
11.8. Clients
11.9. Application Client Migration
11.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);
11.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);
11.10. General Utilities
11.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.
11.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:
Output:
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.
11.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:
After each "keystore:" option new conversion starts. All options are mandatory except "salt:", "iteration:" and "properties:"
Execute following command:
Output:
The result is conversion of all vaults with proper CLI commands.
11.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>
11.13. SSL Migration
11.14. Simple SSL Migration
11.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:
-
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)
-
Create Elytron
key-manager
- specifying keystore, alias (usingalias-filter
) and password of key:/subsystem=elytron/key-manager=LocalhostKeyManager:add(key-store=LocalhostKeyStore,alias-filter=server,credential-reference={clear-text="key_password"})
-
Create Elytron
server-ssl-context
- specifying only reference tokey-manager
defined above:/subsystem=elytron/server-ssl-context=LocalhostSslContext:add(key-manager=LocalhostKeyManager)
-
Switch
https-listener
from legacysecurity-realm
to newly created Elytronssl-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)
-
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"/>
11.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:
-
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)
-
Create
trust-manager
- specifyingkey-store
of trustore, created above:/subsystem=elytron/trust-manager=TrustManager:add(key-store=TrustStore)
-
Modify
server-ssl-context
to use newly created trustmanager:/subsystem=elytron/server-ssl-context=LocalhostSslContext:write-attribute(name=trust-manager,value=TrustManager)
-
Enable client authentication for
server-ssl-context
:/subsystem=elytron/server-ssl-context=LocalhostSslContext:write-attribute(name=need-client-auth,value=true)
-
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>
11.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.
The WildFly Elytron project already contains a dummy certificate authority set up that we use for testing, the KeyStores within this documentation are from the dummy certificate authority although for anything other than testing these should be replaced with your own.
As a first step we define some paths that point to the wildfly-elytron project so we can use these in the subsequent 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={usersProperties=file://${jboss.server.config.dir}/example-users.properties, rolesProperties=file://${jboss.server.config.dir}/example-roles.properties}}])
This results in the following configuration.
<paths>
<path name="elytron.project" path="/home/darranl/src/wildfly10/wildfly-elytron"/>
<path name="elytron.project.jks" path="src/test/resources/ca/jks" relative-to="elytron.project"/>
<path name="elytron.project.properties" path="src/test/resources/org/wildfly/security/auth/realm" relative-to="elytron.project"/>
</paths>
11.15.1. KeyStores, KeyManagers, and TrustManagers.
The next step is to define the KeyStore resources, for this example three different keystores are used: -
- localhost.keystore
-
Contains the servers key and certificate for 'localhost'.
- beetles.keystore
-
Contains the individual client certificates.
- ca.keystore
-
Contains the certificate of the certificate authority.
When we define the overall configuration we will use the localhost keystore along with the ca keystore for the incoming connections so initially all client certificates signed by the certificate authority will be accepted and subsequently a security realm will check it against the actual certificates within beetles keystore.
./subsystem=elytron/key-store=localhost:add(type=jks, relative-to=elytron.project.jks, path=localhost.keystore, credential-reference={clear-text=Elytron})
./subsystem=elytron/key-store=beetles:add(type=jks, relative-to=elytron.project.jks, path=beetles.keystore, credential-reference={clear-text=Elytron})
./subsystem=elytron/key-store=ca:add(type=jks, relative-to=elytron.project.jks, path=ca.truststore, credential-reference={clear-text=Elytron})
This results in the following configuration.
<subsystem xmlns="urn:wildfly:elytron:1.1" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
...
<tls>
<key-stores>
<key-store name="localhost">
<credential-reference clear-text="Elytron"/>
<implementation type="jks"/>
<file path="localhost.keystore" relative-to="elytron.project.jks"/>
</key-store>
<key-store name="beetles">
<credential-reference clear-text="Elytron"/>
<implementation type="jks"/>
<file path="beetles.keystore" relative-to="elytron.project.jks"/>
</key-store>
<key-store name="ca">
<credential-reference clear-text="Elytron"/>
<implementation type="jks"/>
<file path="ca.truststore" relative-to="elytron.project.jks"/>
</key-store>
</key-stores>
</tls>
</subsystem>
Next the key and trust manager resources will be defined using these keystores.
./subsystem=elytron/key-manager=localhost-manager:add(algorithm=SunX509, key-store=localhost, credential-reference={clear-text=Elytron})
./subsystem=elytron/trust-manager=ca-manager:add(algorithm=SunX509, key-store=ca)
Resulting in:
<subsystem xmlns="urn:wildfly:elytron:1.1" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
...
<tls>
...
<key-managers>
<key-manager name="localhost-manager" algorithm="SunX509" key-store="localhost">
<credential-reference clear-text="Elytron"/>
</key-manager>
</key-managers>
<trust-managers>
<trust-manager name="ca-manager" algorithm="SunX509" key-store="ca"/>
</trust-managers>
</tls>
</subsystem>
11.15.2. Realms and Domains
Two security realms are now defined, one of these uses properties files from within the WildFly Elytron project to support username/password authentication and the other using the clients certificates for verification.
./subsystem=elytron/properties-realm=test-users:add(users-properties={relative-to=elytron.project.properties, path=clear.properties, plain-text=true, digest-realm-name=ManagementRealm}, groups-properties={relative-to=elytron.project.properties, path=groups.properties})
./subsystem=elytron/key-store-realm=key-store-realm:add(key-store=beetles)
Resulting in:
<subsystem xmlns="urn:wildfly:elytron:1.1" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
...
<security-realms>
...
<key-store-realm name="key-store-realm" key-store="beetles"/>
...
<properties-realm name="test-users">
<users-properties path="clear.properties" relative-to="elytron.project.properties" digest-realm-name="ManagementRealm" plain-text="true"/>
<groups-properties path="groups.properties" relative-to="elytron.project.properties"/>
</properties-realm>
</security-realms>
...
</subsystem>
These security realms can now be referenced from a security domain:
./subsystem=elytron/security-domain=client-cert-domain:add(realms=[{realm=test-users},{realm=key-store-realm}], \
default-realm=test-users, \
permission-mapper=default-permission-mapper)
Resulting in:
<subsystem xmlns="urn:wildfly:elytron:1.1" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
...
<security-domains>
...
<security-domain name="client-cert-domain" default-realm="test-users" permission-mapper="default-permission-mapper">
<realm name="test-users"/>
<realm name="key-store-realm"/>
</security-domain>
</security-domains>
...
</subsystem>
Before moving onto the individual authentication factories a couple of additional utility resources are also required: -
./subsystem=elytron/constant-realm-mapper=key-store-realm:add(realm-name=key-store-realm) ./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"/>
...
<constant-realm-mapper name="key-store-realm" realm-name="key-store-realm"/>
...
</mappers>
...
</subsystem>
11.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.
./subsystem=elytron/http-authentication-factory=client-cert-digest:add(http-server-mechanism-factory=global, \ security-domain=client-cert-domain, \ mechanism-configurations=[{ \ mechanism-name=CLIENT_CERT, \ realm-mapper=key-store-realm, \ 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="client-cert-domain"> <mechanism-configuration> <mechanism mechanism-name="CLIENT_CERT" pre-realm-principal-transformer="x500-decoder" realm-mapper="key-store-realm"/> <mechanism mechanism-name="DIGEST"> <mechanism-realm realm-name="ManagementRealm"/> </mechanism> </mechanism-configuration> </http-authentication-factory> ... </http> ... </subsystem>
Where DIGEST authentication is used we rely on the default configuration within the security domain to select the 'test-users' realm, however where CLIENT_CERT authentication is in use an alternative realm-mapper is referenced to ensure the 'key-store-realm' is used.
Additionally for CLIENT_CERT authentication a principal-transformer is referenced to extract the CN attribute from the distinguished name of the client certificate and use this when accessing the identity from the security realm.
11.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.
./subsystem=elytron/sasl-authentication-factory=client-cert-digest:add(sasl-server-factory=elytron, \ security-domain=client-cert-domain, \ mechanism-configurations=[{mechanism-name=EXTERNAL, \ realm-mapper=key-store-realm, \ 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="client-cert-domain">
<mechanism-configuration>
<mechanism mechanism-name="EXTERNAL" pre-realm-principal-transformer="x500-decoder" realm-mapper="key-store-realm"/>
<mechanism mechanism-name="DIGEST-MD5">
<mechanism-realm realm-name="ManagementRealm"/>
</mechanism>
</mechanism-configuration>
</sasl-authentication-factory>
...
</sasl>
...
</subsystem>
Realm mappers and principal transformers are defined in the same way as were defined for HTTP.
11.15.5. SSL Context
An SSL context is also defined for use by the server.
./subsystem=elytron/server-ssl-context=localhost:add(key-manager=localhost-manager, trust-manager=ca-manager, \ security-domain=client-cert-domain, \ authentication-optional=true, \ want-client-auth=true, \ need-client-auth=false)
Resulting in: -
<subsystem xmlns="urn:wildfly:elytron:1.1" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
...
<tls>
...
<server-ssl-contexts>
<server-ssl-context name="localhost" security-domain="client-cert-domain" want-client-auth="true" need-client-auth="false" authentication-optional="true" key-manager="localhost-manager" trust-manager="ca-manager"/>
</server-ssl-contexts>
</tls>
</subsystem>
As we will be supporting fallback to username/password authentication need-client-auth is set to false as well as authentication-optional being set to false, this allows connections to be established but an alternative form of authentication will be required.
11.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=localhost) ./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="localhost">
<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 the username elytron and password passwd12#$
For certificate based authentication the keys and certificates from the WildFly Elytron tests can be used, these are found in JKS keystores under 'src/test/resources/ca/jks', these keystores have a password of Elytron.
Web Browser Configuration
A PKCS#12 file can be created from the test keystores,this can then be imported into the web browser to use when connecting to the server.
keytool -importkeystore -srckeystore ladybird.keystore \ -destkeystore ladybird.pkcs12 \ -srcstoretype jks \ -deststoretype pkcs12 \ -deststorepass Elytron \ -srcalias ladybird \ -destalias ladybird
CLI Configuration
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.
For the purpose of this example copy the ladybird,keystore and ca.truststore from the Wildfly Elytron testsuite to the location the JBoss CLI is being started from, the following wildfly-config.xml can be created in this location as well: -
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<authentication-client xmlns="urn:elytron:1.0">
<key-stores>
<key-store name="ladybird" type="jks" >
<file name="ladybird.keystore"/>
<key-store-clear-password password="Elytron" />
</key-store>
<key-store name="ca" type="jks">
<file name="ca.truststore"/>
<key-store-clear-password password="Elytron" />
</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="ladybird" alias="ladybird">
<key-store-clear-password password="Elytron" />
</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" => "Ladybird"}, "mapped-roles" => ["SuperUser"] } }
11.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?