Since the Elytron project now has a new site, all of our blog posts on Elytron will be hosted there. Keep an eye on https://wildfly-security.github.io/wildfly-elytron/blog/ for new posts.
Since the feature development phase for WildFly 19 has now started, we wanted to highlight the security features that we are planning to work on for this release.
Details on what is being planned for this feature can be found here.
Instead of needing to first add a credential to a credential store in order to reference it from a credential-reference, WildFly 19 will add the ability to automatically add a credential to a previously defined credential store. Check out this blog post for an introduction to this new feature.
The WildFly Elytron integration added a new API and configuration file to configure client side security for outgoing calls. This feature request is to increase the integration for web services clients. For an introduction to this new feature, take a look at this blog post.
This feature request looks at integration for RESTEasy clients. More information about this feature can be found here.
This new feature will make it possible to use SSH authentication via Elytron when using Git to manage and persist your WildFly configuration file. More details are available here.
This feature request looks at allowing users to configure how much output should appear when invoking certain operations on Elytron key-stores.
As usual, please keep in mind that this blog post is a summary of our general plans and not a guarantee that each of these features will be merged. However, this blog post does give an indication of our team’s current priorities. If any of these features are a priority for you, please let us know. Please also let us know if there are any security features that are missing that you would like to see prioritized as we can take this kind of feedback into account for future releases.
This blog post highlights the new security features included in WildFly 18.
Since WildFly 14, it's possible to obtain and manage certificates from Let’s Encrypt using the WildFly CLI. WildFly 18 now adds the ability to make use of any certificate authority that implements the Automatic Certificate Management Environment (ACME) protocol. More details can be found in this blog post.
It is now possible to use the ssl enable-ssl-management and enable-ssl-http-server commands to easily enable one-way and two-way SSL using certificates obtained automatically from Let’s Encrypt. Details on how to get started with these commands can be found here.
Certificate revocation checks can now be performed using the Online Certificate Status Protocol (OCSP) in addition to certificate revocation lists (CRL). Details on how to configure an Elytron trust manager to perform certificate revocation checks can be found here.
Prior to WildFly 18, the mapping of an X.509 certificate chain to an identity was done by taking the subject distinguished name from the first certificate in the X.509 certificate chain as an X.500 principal. It is now possible to map an X.509 certificate chain to an identity by using a subject alternative name from the first certificate in the X.509 certificate chain. For a complete overview of this feature, take a look at this blog post.
Elytron already had a very flexible approach for assigning roles and permissions to an identity based on arbitrary attributes loaded by a security realm. This feature adds support for loading the attributes from multiple security realms and aggregating the results together. Check out this blog post for more details on this feature.
It is now possible to configure a principal transformer for an aggregate realm that will be used to transform the principal after the authentication identity is obtained but before the authorization identity is obtained. A complete example on how to configure and make use of this principal transformer can be found here.
Support for both RFC 5424 and RFC 3164 have now been added to Elytron’s audit logging capabilities as well as the ability to configure how many times Elytron should attempt to send messages to a syslog server when an error is encountered during sending. More details on this feature can be found here.
It is now possible to specify masked passwords when using the Elytron Authentication Client. Check out this blog post for examples on how to make use of masked passwords.
As always, be sure to check out our blog posts page, where we collect references to all our blog posts on Elytron features. If there is an Elytron topic you’d like to see a blog post on, feel free to leave a comment on that page to ask for it. Questions on Elytron are also welcome on WildFly’s user forums.
To learn more about the Elytron subsystem, take a look at the Elytron documentation.
One of the new security features that we have been working on is adding support for automatic updates of credential stores. The plan is to have it included in WildFly 20. This blog post will give an introduction to this new feature.
A credential store allows for secure storage of credentials. It is possible to populate and manipulate a credential store using the WildFly CLI. Once a credential has been added to a credential store, it is possible to reference the stored credential. In particular, many resources across WildFly’s management model support a credential-reference attribute that can be used either to specify a clear-text password or to cross-reference a credential from a configured credential store. As an example, when configuring a key-store in the Elytron subsystem, a credential-reference is used to specify the credential that should be used to access the keystore. This can be configured as follows:
First, let's configure a credential-store (note that the mycredstore.cs file doesn’t need to exist yet):
/subsystem=elytron/credential-store=myCredStore:add(location=mycredstore.cs, relative-to=jboss.server.config.dir, credential-reference={clear-text=StorePassword}, create=true)
Next, we'll add a credential to our credential-store:
/subsystem=elytron/credential-store=myCredStore:add-alias(alias=example, secret-value=mySecretPassword)
Finally, we can configure a key-store and reference this newly added credential:
/subsystem=elytron/key-store=myKS:add(relative-to=jboss.server.config.dir, path=my.keystore, type=JCEKS, credential-reference={store=myCredStore, alias=example})
Notice that the credential-reference has two attributes, store and alias. The store attribute indicates the credential store. The alias attribute indicates the entry in the credential store that holds our credential.
Instead of needing to first add a credential to a configured credential store in order to reference it from a credential-reference, WildFly 19 will add the ability to automatically add a credential to a previously defined credential store by specifying both the store and clear-text attributes for a credential-reference. In particular, when configuring a new credential-reference with both the store and clear-text attributes specified, the following will happen:
As an example, let’s configure another credential-store in the Elytron subsystem:
/subsystem=elytron/credential-store=myNewCredStore:add(location=mynewcredstore.cs, relative-to=jboss.server.config.dir, credential-reference={clear-text=StorePassword}, create=true)
Now, going back to our keystore example, from WildFly 19, it will be possible to configure a key-store with a credential-reference that specifies the store, alias, and clear-text attributes as follows:
/subsystem=elytron/key-store=newKS:add(relative-to=jboss.server.config.dir, path=new.keystore, type=JCEKS, credential-reference={store=myNewCredStore, alias=myNewAlias, clear-text=myNewPassword}) { "outcome" => "success", "result" => {"credential-store-update" => { "status" => "new-entry-added", "new-alias" => "myNewAlias" }} }
The above command will result in a new entry being added to our credential store, myNewCredStore, with alias myNewAlias and credential myNewPassword.
When updating an existing credential-reference attribute that contains both the alias and store attributes to also specify the clear-text attribute, the existing credential in the configured credential store will be replaced with the clear text password that was specified. The clear-text attribute will then be removed from the management model. As an example, the following command will result in updating the credential for the myNewAlias entry that was just added to our credential store:
/subsystem=elytron/key-store=newKS:write-attribute(name=credential-reference.clear-text,value=myUpdatedPassword) { "outcome" => "success", "result" => {"credential-store-update" => {"status" => "existing-entry-updated"}}, "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } }
This blog post has given an introduction to the upcoming support for automatic updates of credential stores.
For more details on this feature and updates on the status of this feature, keep an eye on WFCORE-4150.
For certificate-based authentication, the client presents its X.509 certificate chain to the server. The server then verifies this certificate chain using its truststore. The truststore only needs to contain certificates for root certificate authorities or intermediate certificate authorities, it doesn’t need to contain the individual client certificates. Once a server has successfully verified a client’s certificate chain, it checks if the corresponding identity is authorized to access a particular resource. This authorization check is done using a security realm that contains the roles that are associated with identities. This security realm also does not need to contain individual client certificates. Instead, it can contain principals that can be derived from a portion of the client’s certificate. As mentioned in a previous blog post, we are enhancing the way an X.509 certificate can be mapped to an underlying identity using Elytron.
In this blog post, we’ll take a look at how to secure a web application deployed to WildFly using the CLIENT_CERT HTTP authentication mechanism with two-way SSL and authorization. The server’s truststore will only contain an example CA certificate, it won’t contain any client certificates. Similarly, the security realm used for authorization in this example won’t contain any client certificates. It will contain principals that are derived from a portion of the CN value from the subject name from a client’s X.509 certificate.
First, clone the elytron-examples repo locally:
git clone https://github.com/wildfly-security-incubator/elytron-examples cd elytron-examples
Next, let's generate some client and server certificates that will be used in this example to set up two-way SSL:
cd dynamic-certificates mvn clean install exec:java -Dexec.mainClass="org.wildfly.security.examples.CertificateGenerationExample" -Dexec.args="CN=Bob.Smith.123456 CN=Alice.Smith.456789"
Notice that the above command generates the following keystores and truststores in the dynamic-certificates/target directory:
client1.keystore
client2.keystore
server.keystore
server.truststore
Next, convert the client keystores into PKCS12 format and import them into your browser so you can pick which one to present to the server later on:
keytool -importkeystore -srckeystore client1.keystore -srcstoretype jks -destkeystore client1.keystore.pkcs12 -deststoretype pkcs12 -srcstorepass keystorepass -deststorepass keystorepass
keytool -importkeystore -srckeystore client2.keystore -srcstoretype jks -destkeystore client2.keystore.pkcs12 -deststoretype pkcs12 -srcstorepass keystorepass -deststorepass keystorepass
Finally, copy the server.keystore and server.truststore files to your WildFly server instance:
cp /PATH/TO/ELYTRON/EXAMPLES/dynamic-certificates/target/server.* $WILDFLY_HOME/standalone/configuration
A WildFly CLI script that contains all of the commands that are used in this example can be found in the client-cert-with-authorization project in elytron-examples repository:
We’re going to configure a security domain such that only the client with ID "123456" will be able to access our secured web application.
First, create a principal decoder that can be used to obtain the CN value from the subject name from an X.509 client certificate:
/subsystem=elytron/x500-attribute-principal-decoder=cnDecoder:add(attribute-name=CN, maximum-segments=1)
Next, create a principal transformer that can be used to extract the ID portion from the CN value:
/subsystem=elytron/regex-principal-transformer=myRegexTransformer:add(pattern=".*\\.([0-9]+)",replacement="$1")
Now, let’s combine these two principal transformers into a chained principal transformer:
/subsystem=elytron/chained-principal-transformer=myChainedTransformer:add(principal-transformers=[cnDecoder, myRegexTransformer])
As an example, for client1’s certificate, the above chained-principal-transformer would map the subject name "CN=Bob.Smith.123456" to just the ID portion: "123456".
Next, create a file-system based security realm that will be used to store the client IDs and their roles:
/subsystem=elytron/filesystem-realm=idsRealm:add(path=ids,relative-to=jboss.server.config.dir)
Now, let’s add the two IDs from the client certificates to our filesystem-realm. Notice that the user with ID "123546" has “Users” role but the second user with ID "456879" does not have any roles.
/subsystem=elytron/filesystem-realm=idsRealm:add-identity(identity=123456) /subsystem=elytron/filesystem-realm=idsRealm:add-identity-attribute(identity=123456,name=Roles,value=[Users]) /subsystem=elytron/filesystem-realm=idsRealm:add-identity(identity=456789)
Finally, we’ll configure a security domain that references our security realm and makes use of our chained principal transformer:
/subsystem=elytron/security-domain=clientCertDomain:add(realms=[{realm=idsRealm}], default-realm=idsRealm, pre-realm-principal-transformer=myChainedTransformer, permission-mapper=default-permission-mapper)
We’re now going to enable two-way SSL for web applications deployed to the server.
First, configure a key-store using our server.truststore file. Remember this only contains the example certificate authority’s certificate, it doesn’t contain the individual client certificates:
/subsystem=elytron/key-store=serverTS:add(path=server.truststore,relative-to=jboss.server.config.dir,credential-reference={clear-text=truststorepass},type=JKS)
Next, enable two-way SSL:
security enable-ssl-http-server --key-store-path=server.keystore --key-store-path-relative-to=jboss.server.config.dir --key-store-password=keystorepass --trust-store-name=serverTS
We’re now going to configure the CLIENT_CERT HTTP authentication mechanism so we can secure our web application using this mechanism.
The CLIENT_CERT HTTP authentication mechanism makes use of the verified X.509 client certificate chain that is established on the SSL connection. By default, this authentication mechanism will attempt to use the configured security realm to validate this certificate chain using client certificates that are stored in the configured security realm. Since our security realm does not contain client certificates and only contains role information, there won’t be a way for the realm itself to verify the client certificate. This is fine since we know the certificate chain was already verified when establishing the SSL connection so we’re going to set the org.wildfly.security.http.skip-certificate-verification property to true for the CLIENT_CERT mechanism, as shown below. Our security realm will still be used for the authorization check.
/subsystem=elytron/configurable-http-server-mechanism-factory=configuredCert:add(http-server-mechanism-factory=global, properties={org.wildfly.security.http.skip-certificate-verification=true})
Now let’s finish configuring the CLIENT_CERT mechanism:
/subsystem=elytron/http-authentication-factory=clientCertAuth:add(http-server-mechanism-factory=configuredCert, security-domain=clientCertDomain, mechanism-configurations=[{mechanism-name=CLIENT_CERT}]) /subsystem=undertow/application-security-domain=other:add(http-authentication-factory=clientCertAuth,override-deployment-config=true)
Finally, reload the server:
reload
We’re going to make use of the simple-webapp project in the elytron-examples repository. It can be deployed using the following commands:
cd /PATH/TO/ELYTRON/EXAMPLES/simple-webapp mvn clean install wildfly:deploy
Then try accessing the application using https://localhost:8443/simple-webapp
Note that since the server's certificate won't be trusted by your browser, you'll need to manually confirm that this certificate is trusted or configure your browser to trust it.
First, select the certificate for "Alice.Smith.456789". Then try clicking on “Access Secured Servlet”. Notice that a Forbidden message occurs. This is because accessing the secured servlet requires “Users” role but the “456789” identity that we configured has no roles.
Now, try accessing the application again. This time, select the certificate for "Bob.Smith.123456" and then click on “Access Secured Servlet”. This time, this succeeds since the “123456” identity that we configured has “Users” role.
This example has shown to secure a web application deployed to WildFly using the CLIENT_CERT HTTP authentication mechanism with two-way SSL with authorization. It has also demonstrated that individual client certificates do not need to be stored in either the server’s truststore or in its security realm.
Since the feature development phase for WildFly 18 has now started, we wanted to highlight the security features that we are planning to work on for this release.
The features in this first set are ones that were actively developed during the WildFly 17 feature development phase. Many of these are now close to being merged:
Currently, WildFly only supports integration with the Let’s Encrypt certificate authority. Once the certificate authority is configurable, it will be possible to use this integration with other certificate authorities that implement the ACME protocol.
The ssl enable-ssl-management and enable-ssl-http-server already make it possible to enable one-way and two-way SSL easily. These commands will soon be able to obtain certificates from Let’s Encrypt.
Currently, the mapping of an X.509 certificate chain to an identity is done by taking the subject distinguished name from the first certificate in the X.509 certificate chain as an X.500 principal. It will soon be possible to map an X.509 certificate chain to an identity by using a subject alternative name from the first certificate in the X.509 certificate chain.
Elytron already provides a very flexible approach to assigning roles and permissions to an identity based on arbitrary attributes loaded by a security realm. This enhancement will add support for loading the attributes from multiple security realms and aggregating the results together.
This feature request looks at adding support for RFC 5424 and RFC 3164 as well as some other enhancements related to reliability vs. speed.
The features in this second set are new ones that we are planning to work on:
This feature request looks at adding support for additional audit events as well as support for a new @Audit annotation.
The previous Vault implementation was basically a repository of encrypted clear text strings that could be referenced using expressions in the management model. The new CredentialStore is a repository of credentials. This feature request will look into how the CredentialStore could be used to support encrypted values within the overall model.
The WildFly Elytron integration added a new API and configuration file to configure the client side security for outgoing calls. This feature request is to increase the integration for web services clients.
This one will look at adding adding some remaining items needed to support the MicroProfile JWT RBAC security specification.
This feature request looks at allowing users to configure how much output should appear when invoking certain operations on Elytron key-stores.
Please keep in mind that this blog post is a summary of our general plans and not a guarantee that each of these features will be merged. However, this blog post does give an indication of our team’s current priorities. If any of these features are a priority for you, please let us know. Please also let us know if there are any security features that are missing that you would like to see prioritized as we can take this kind of feedback into account for future releases.
A new security feature that we have been working on is enhancing the way an X.509 certificate chain gets mapped to an underlying identity. This feature will be included in WildFly 18. This blog post gives an overview of this new feature.
For certificate-based authentication, the client presents its X.509 certificate chain to the server. The server then verifies this certificate chain. Elytron’s security realm APIs support using this type of X.509 certificate chain evidence to locate and load an identity. For example, after verifying a certificate chain, a server may need to check if the corresponding identity is authorized to access a particular resource. This would involve interacting with the security realm to locate and load an identity based on the X.509 certificate chain in order to determine the roles that are associated with that identity.
Currently, the mapping of an X.509 certificate chain to an identity is done by taking the subject distinguished name from the first certificate in the X.509 certificate chain as an X.500 principal. This principal then gets rewritten using any principal decoders or principal transformers that have been configured, as shown below:
The X.509 v3 Subject Alternative Name extension provides the ability to specify one or more alternative names that can be used in addition to or instead of the subject distinguished name in an X.509 certificate. From WildFly 18, it will also be possible to map an X.509 certificate chain to an identity by using a subject alternative name from the first certificate in the X.509 certificate chain. This principal will then get rewritten using any principal decoders or principal transformers that have been configured, as shown below:
In particular, to specify that a subject alternative name from a certificate should be used as the principal associated with that certificate, it will be possible to configure an x509-subject-alt-name-evidence-decoder in the mappers configuration in the Elytron subsystem. This element will have two attributes:
For example, to associate the X.509 certificate in the diagram above with the principal "bob.smith@example.com", it will be possible to configure the following x509-subject-alt-name-evidence-decoder:
/subsystem=elytron/x509-subject-alt-name-evidence-decoder=emailDecoder:add(alt-name-type=rfc822Name)
This evidence decoder can then be referenced when creating an Elytron security-domain:
/subsystem=elytron/security-domain=exampleSD:add(...,evidence-decoder=emailDecoder)
It will also be possible to configure an x500-subject-evidence-decoder that will just extract the subject from the first certificate in the certificate chain, as an X.500 principal, as shown below:
/subsystem=elytron/x500-subject-evidence-decoder=subjectDecoder:add()
Finally, it will also be possible to configure an aggregate-evidence-decoder that is made up of two or more evidence decoders, as shown in the following example:
/subsystem=elytron/x509-subject-alt-name-evidence-decoder=emailDecoder:add(alt-name-type=rfc822Name) /subsystem=elytron/x509-subject-alt-name-evidence-decoder=dnsDecoder:add(alt-name-type=dNSName) /subsystem=elytron/x500-subject-evidence-decoder=subjectDecoder:add() /subsystem=elytron/aggregate-evidence-decoder=aggregateDecoder:add(evidence-decoders=[emailDecoder,subjectDecoder,dnsDecoder])
The evidence decoders that make up an aggregate-evidence-decoder will be attempted in order until one returns a non-null principal or until there are no more evidence decoders left to try.
This blog post has described how we are enhancing the mapping of an X.509 certificate to an underlying identity in WildFly 18.
One of the new security features that we have been working on is adding support for TLS 1.3 to WildFly. Although this feature didn’t make it into WildFly 17, the plan is to have it included in WildFly 18. This blog post will give a quick introduction to this feature.
Within the Elytron subsystem in WildFly, the server-ssl-context and client-ssl-context are used to configure a server and client SSL context, respectively. Note that a client SSL context is used when a WildFly instance creates an SSL connection as a client. Both the server-ssl-context and client-ssl-context have a protocols attribute which contains a list of the protocols to be supported by WildFly. From WildFly 18, this attribute will also allow TLSv1.3 to be specified.
Since the TLS 1.3 specification introduced a few new cipher suites, both the server-ssl-context and client-ssl-context will also have a new cipher-suite-names attribute that will be used to specify the TLS 1.3 cipher suites to enable. The format will be a colon separated list of cipher suite names that will default to:
“TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256”
It is important to note the new TLS 1.3 cipher suites cannot be used with TLS 1.2 and below. Similarly, the old cipher suites cannot be used with TLS 1.3.
Within the Elytron authentication client, similar changes will be made to the ssl-context. In particular, from WildFly 18, the ssl-context’s protocol element will also allow TLSv1.3 to be specified in the list of protocol names to be supported.
The ssl-context’s cipher-suite element will also have a new names attribute to specify the TLS 1.3 cipher suites to enable. As on the server side, this will default to:
“TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256”
This blog post has given a quick introduction to the upcoming support for TLS 1.3 in WildFly. Since the TLS 1.3 implementation was introduced in JDK 11, this new feature will only be available when running WildFly against JDK 11 or higher.
For more details on this feature and updates on the status of this feature, keep an eye on WFCORE-4172.
WildFly Elytron 1.8.0.Final has been released and is included with WildFly 16 Final, which is now available for download. In this blog post, we’ll take a look at what’s new in Elytron in WildFly 16.
Setting a simple property for the HTTP Basic authentication mechanism in your application’s deployment descriptor enables silent mode. This is useful when paired with HTTP Form authentication, allowing human users to log in using the Form authentication mechanism and programmatic clients to log in using the Basic authentication mechanism. More details can be found in this blog post.
When adding a file-based key-store in the Elytron subsystem, the type attribute no longer needs to be specified. Instead, the Elytron subsystem will now automatically detect the type.
It is now easy to migrate legacy properties files to an Elytron filesystem-realm using the WildFly Elytron Tool. Take a look at this blog post for the migration steps.
It is possible to make use of the new Security API in Java EE 8 defined under JSR-375 with Elytron. Details on how to get started with EE security can now be found here.
Since WildFly 14, it is possible to obtain and manage certificates from Let’s Encrypt using the WildFly CLI. WildFly 16 now adds the ability to also make use of the web-based WildFly Management Console to do this. The details, including screenshots, can be found here.
Elytron’s APIs allow identities to be modified, making it possible for users to update their credentials and/or other information about themselves. This two-part blog post shows how to create a web application for user self-service.
Although there are a few different principal transformers that can be used out of the box with WildFly, it is also possible to implement custom principal transformers that can be registered using the Elytron subsystem. This blog post describes how to create and make use of a custom Elytron principal transformer.
The full list of issues resolved is available here.
As always, be sure to check out our blog posts page, where we collect references to all our blog posts on Elytron features. If there is an Elytron topic you’d like to see a blog post on, feel free to leave a comment on that page to ask for it. Questions on Elytron are also welcome on WildFly’s user forums.
To learn more about the Elytron subsystem, take a look at the Elytron documentation.
An Elytron principal transformer can be used to map a principal from one form to another. Although there are a few different principal transformers that can be used out of the box with WildFly, it is also possible to implement custom principal transformers that can be registered using the Elytron subsystem. In this blog post, we’ll see how to create a custom principal transformer that can be used to convert usernames to all upper case characters. This can be useful if your identity store contains upper case usernames but you want to ignore the case when a username is being specified during the authentication process.
This blog post will make use of the custom-principal-transformer project in the elytron-examples repository:
Let’s first add a management user for the server - this is the user that we’re going to use later on when attempting to connect to the CLI. For this example, we’re going to create a filesystem-based identity store and add a user named “BOBSMITH” with password “bob123+” using the following CLI commands:
/subsystem=elytron/filesystem-realm=exampleRealm:add(path=fs-realm-users,relative-to=jboss.server.config.dir) /subsystem=elytron/filesystem-realm=exampleRealm:add-identity(identity=BOBSMITH) /subsystem=elytron/filesystem-realm=exampleRealm:set-password(identity=BOBSMITH,clear={password=bob123+}) /subsystem=elytron/filesystem-realm=exampleRealm:add-identity-attribute(identity=BOBSMITH,name=Roles,value=[SuperUser])
Next, we’re going to add the filesystem-realm that we just created to the “ManagementDomain” security domain that is already defined in the default Elytron subsystem configuration and we’re going to make this the default security realm for this security domain:
/subsystem=elytron/security-domain=ManagementDomain:list-add(name=realms, value={realm=exampleRealm}) /subsystem=elytron/security-domain=ManagementDomain:write-attribute(name=default-realm, value=exampleRealm)
Now, use the following commands to secure the management interface using Elytron:
/core-service=management/management-interface=http-interface:write-attribute(name=http-upgrade,value={enabled=true, sasl-authentication-factory=management-sasl-authentication}) /core-service=management/management-interface=http-interface:undefine-attribute(name=security-realm)
For this example, we’re also going to use RBAC to secure the management interface using our filesystem-based identity store. However, please note that this step is optional:
/core-service=management/access=authorization:write-attribute(name=provider, value=rbac) /core-service=management/access=authorization:write-attribute(name=use-identity-roles,value=true)
Finally, reload the server:
:reload
At this point, let’s try to connect to the CLI specifying “BobSmith” as the username:
$WILDFLY_HOME/bin/jboss-cli.sh -c --controller=remote+http://127.0.0.1:9990 --user=BobSmith --password=bob123+
Notice that authentication fails since the username in our identity store is “BOBSMITH” not “BobSmith”. In the next few sections, we’ll see how to create and make use of a custom principal transformer that can be used to convert the given principal name to all upper case characters.
To create a custom principal transformer, we need to create a class that implements the PrincipalTransformer interface. In particular, we need to provide an implementation for the apply method which will be used to map the given principal from one form to another. Our custom implementation, CasePrincipalTransformer, that converts the given principal name to all upper case characters can be found here.
Now that we’ve created our custom principal transformer, the next thing we need to do is install it in WildFly so we can make use of it in the Elytron subsystem. First, let’s build our custom-principal-transformer project:
mvn clean install
The above command produces a JAR that contains our custom implementation. Next, we can add a module that contains this JAR to WildFly using the CLI:
module add --name=org.wildfly.security.examples.custom-principal-transformer --resources=/PATH_TO_ELYTRON_EXAMPLES/elytron-examples/custom-principal-transformer/target/custom-principal-transformer-1.0.0.Alpha1-SNAPSHOT.jar --dependencies=org.wildfly.security.elytron,org.wildfly.extension.elytron
Finally, we can create a custom-principal-transformer in the Elytron subsystem that references both this new module and our custom principal transformer class that is contained in this module:
/subsystem=elytron/custom-principal-transformer=myPrincipalTransformer:add(module=org.wildfly.security.examples.custom-principal-transformer, class-name=org.wildfly.security.examples.CasePrincipalTransformer)
We’re now ready to make use of our custom-principal-transformer. Let’s update our "ManagementDomain" to specify that our newly created custom-principal-transformer should be used as the pre-realm-principal-transformer - this is a principal transformer that gets applied before the realm is selected:
/subsystem=elytron/security-domain=ManagementDomain:write-attribute(name=pre-realm-principal-transformer,value=myPrincipalTransformer)
Next, reload the server using the :reload command.
Now, try connecting to the CLI again, specifying “BobSmith” as the username:
$WILDFLY_HOME/bin/jboss-cli.sh -c --controller=remote+http://127.0.0.1:9990 --user=BobSmith --password=bob123+
This time, authentication succeeds since our custom-principal-transformer gets used to convert the given username to all upper case characters, matching the username in our identity store.
This blog post has shown how to create and make use of a custom Elytron principal transformer.
Although Elytron was developed for the WildFly application server, it is possible to use Elytron outside of WildFly. This blog post is going to give an overview of how to secure an embedded Jetty server using Elytron. In particular, we’re going to take a look at an example embedded Jetty application that makes use of HTTP Basic authentication and we’re going to modify it so that it’s backed by Elytron for its security.
Let’s take a look at a simple embedded Jetty server application:
public static void main(String[] args) throws Exception { // Create the Jetty server instance Server server = new Server(8080); ConstraintSecurityHandler security = new ConstraintSecurityHandler(); server.setHandler(security); // Create a constraint that specifies that accessing "/secured" requires authentication // and the authenticated user must have "admin" role Constraint constraint = new Constraint(); constraint.setName("auth"); constraint.setAuthenticate(true); constraint.setRoles(new String[]{"admin"}); ConstraintMapping mapping = new ConstraintMapping(); mapping.setPathSpec("/secured"); mapping.setConstraint(constraint); security.setConstraintMappings(Collections.singletonList(mapping)); // Security realm configuration // alice: alice123+,admin,employee // bob: bob123+,employee LoginService loginService = new HashLoginService("MyRealm", "src/test/resources/realm.properties"); server.addBean(loginService); security.setLoginService(loginService); // Use Jetty's BasicAuthenticator security.setAuthenticator(new BasicAuthenticator()); // Configure the handler we are securing ServletHandler servletHandler = new ServletHandler(); servletHandler.addServletWithMapping(SecuredServlet.class, "/secured"); security.setHandler(servletHandler); server.start(); }
The above example first creates a Jetty server instance. It then creates a constraint that specifies that accessing the /secured page requires authentication and that the authenticated user must have admin role. Next, it configures a Jetty security realm that’s backed by a properties file. It then specifies that Jetty’s BasicAuthenticator should be used to handle authentication. It also specifies the ServletHandler that’s being secured. This handler is configured with a simple servlet that just outputs the username of the authenticated user. Finally, the Jetty server instance is started.
Let’s modify our simple Jetty application so that it’s backed by Elytron for its security. To do this, we're going to focus on the security related parts of the example, namely the security realm configuration, the Authenticator configuration, and the ServletHandler configuration. The code used in this example can be found here.
There are two key dependencies that are needed:
The first thing we’re going to do is create an Elytron security domain. We’re going to use a simple map backed security realm for this example but any type of Elytron security realm could be used here instead:
private static SecurityDomain createSecurityDomain() throws Exception { // Create an Elytron map-backed security realm SimpleMapBackedSecurityRealm simpleRealm = new SimpleMapBackedSecurityRealm(() -> new Provider[] { elytronProvider }); Map<string, simplerealmentry=""> identityMap = new HashMap<>(); // Add user alice identityMap.put("alice", new SimpleRealmEntry(getCredentialsForClearPassword("alice123+"), getAttributesForRoles("employee", "admin"))); // Add user bob identityMap.put("bob", new SimpleRealmEntry(getCredentialsForClearPassword("bob123+"), getAttributesForRoles("employee"))); simpleRealm.setIdentityMap(identityMap); // Add the map-backed security realm to a new security domain's list of realms SecurityDomain.Builder builder = SecurityDomain.builder() .addRealm("ExampleRealm", simpleRealm).build() .setPermissionMapper((principal, roles) -> PermissionVerifier.from(new LoginPermission())) .setDefaultRealmName("ExampleRealm"); return builder.build(); }
Notice that our security domain has two users, alice and bob, with passwords alice123+ and bob123+, respectively. Note that alice has both employee and admin role and bob only has employee role.
The next thing we’re going to do is create an ElytronAuthenticator instance. ElytronAuthenticator is a class from the elytron-web-jetty project that implements Jetty’s Authenticator interface. It is the class that will be used for validating a request. In particular, ElytronAuthenticator’s validateRequest method uses Elytron APIs to perform authentication for a request by making use of an Elytron SecurityDomain and an Elytron HttpAuthenticationFactory.
We’re first going to create an Elytron HttpServerAuthenticationMechanismFactory which provides the Elytron HTTP Basic authentication mechanism:
HttpServerAuthenticationMechanismFactory providerFactory = new SecurityProviderServerMechanismFactory(() -> new Provider[] {new WildFlyElytronProvider()}); HttpServerAuthenticationMechanismFactory httpServerMechanismFactory = new FilterServerMechanismFactory(providerFactory, true, "BASIC");
We can now create an ElytronAuthenticator instance using our createSecurityDomain() method and our newly created httpServerMechanismFactory:
private static ElytronAuthenticator createElytronAuthenticator() { SecurityDomain securityDomain = createSecurityDomain(); return ElytronAuthenticator.builder() .setSecurityDomain(securityDomain) .setMechanismConfigurationSelector(MechanismConfigurationSelector.constantSelector(MechanismConfiguration.builder() .addMechanismRealm(MechanismRealmConfiguration.builder().setRealmName("Elytron Realm").build()) .build())) .setFactory(httpServerMechanismFactory) .build(); }
We can then tweak the example application to specify that authentication should be handled by our ElytronAuthenticator instance:
ElytronAuthenticator elytronAuthenticator = createElytronAuthenticator(); security.setAuthenticator(elytronAuthenticator);
Recall that the ServletHandler in the example was configured with a simple secured servlet that just outputs the username of the authenticated user. We’re now going to wrap that handler with an ElytronRunAsHandler, as shown below. This class is also from the elytron-web-jetty project and is used to associate the security identity that was produced after successfully validating a request with the current thread.
ServletHandler servletHandler = new ServletHandler(); ElytronRunAsHandler elytronRunAsHandler = new ElytronRunAsHandler(servletHandler); servletHandler.addServletWithMapping(SecuredServlet.class, "/secured"); security.setHandler(elytronRunAsHandler);
Now, in our secured servlet, we can use securityDomain.getCurrentSecurityIdentity() to get the current user and then we can use getPrincipal().getName() to output the username of that authenticated user:
public static class SecuredServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); PrintWriter writer = response.getWriter(); writer.println("Hello " + securityDomain.getCurrentSecurityIdentity().getPrincipal().getName() + "! You've authenticated successfully using Elytron!"); } }
These are all the changes that are needed to modify our example embedded Jetty application so that it’s backed by Elytron for its security. The complete code for this example can be found here.
To build and run the modified example application, the following command can be used:
mvn clean install exec:exec
This will start the embedded Jetty server instance and it will be listening for requests on port 8080.
Now try accessing the example application using http://localhost:8080/secured.
First, try to log in as bob using password bob123+. Since accessing the /secured page requires admin role and since bob is not an admin, you'll see an HTTP 403 error.
Next, try to log in as alice using password alice123+. Since alice has admin role, you'll be able to successfully log in and will see the following message:
Hello alice! You've authenticated successfully using Elytron!
This blog post has shown how to secure an embedded Jetty server using Elytron. The classes for integrating Elytron based HTTP authentication with Jetty can be found in the elytron-web-jetty project.
Since WildFly 14, it is possible to obtain and manage certificates from the Let’s Encrypt certificate authority using the WildFly CLI. In particular, it is possible to get a certificate from Let’s Encrypt, revoke it if necessary, and check if it’s due for renewal. This blog post is going to give an overview of these new operations.
First, configure a key-store in the Elytron subsystem that will be used to hold your server certificates. Note that the path to the keystore file doesn’t need to exist yet.
/subsystem=elytron/key-store=serverKS:add(path=server.keystore.jks, relative-to=jboss.server.config.dir, credential-reference={clear-text=secret}, type=JKS)
Next, make sure your WildFly server instance is publicly accessible using the domain name(s) you will be obtaining a certificate for from Let’s Encrypt. For example, if you are requesting a certificate for the domain name “www.example.org”, then “www.example.org” needs to be publicly accessible. This is because Let’s Encrypt will attempt to access this URL when attempting to validate that you really do own this domain name. WildFly itself will handle proving that you really do own this domain name.
Obtaining and managing certificates from Let’s Encrypt using the CLI requires a couple one-time configuration steps. After that, the new obtain-certificate, revoke-certificate, and should-renew-certificate commands can simply be used. These commands are shown below. We’re going to go through each of these commands in more detail in the rest of this post.
### One-time configuration # Configure a Let’s Encrypt account /subsystem=elytron/key-store=accountsKS:add(path=accounts.keystore.jks,relative-to=jboss.server.config.dir,credential-reference={clear-text=secret},type=JKS) /subsystem=elytron/certificate-authority-account=myLetsEncryptAccount:add(alias=letsEncrypt,key-store=accountsKS,contact-urls=[mailto:admin@admin.org]) ### Now you’re ready to start obtaining and managing certificates # Obtain a certificate from Let’s Encrypt /subsystem=elytron/key-store=serverKS:obtain-certificate(alias=server,domain-names=[www.example.org],certificate-authority-account=myLetsEncryptAccount,agree-to-terms-of-service) # Revoke a certificate that was issued by Let’s Encrypt /subsystem=elytron/key-store=serverKS:revoke-certificate(alias=server,reason=keyCompromise,certificate-authority-account=myLetsEncryptAccount) # Check if a certificate is due for renewal in less than 30 days /subsystem=elytron/key-store=serverKS:should-renew-certificate(alias=server)
Before obtaining your first certificate from Let’s Encrypt, a Let’s Encrypt account needs to be configured.
First, configure a key-store in the Elytron subsystem that will be used to hold your Let’s Encrypt account key. The path to the keystore file doesn’t need to exist yet.
/subsystem=elytron/key-store=accountsKS:add(path=accounts.keystore.jks,relative-to=jboss.server.config.dir,credential-reference={clear-text=secret},type=JKS)
Now we can configure a Let’s Encrypt account that we will reference when obtaining and revoking certificates:
/subsystem=elytron/certificate-authority-account=myLetsEncryptAccount:add(alias=letsEncrypt,key-store=accountsKS,contact-urls=[mailto:admin@admin.org])
The above command results in the following configuration in the Elytron subsystem:
<subsystem xmlns="urn:wildfly:elytron:4.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto"> ... <tls> ... <certificate-authority-accounts> <certificate-authority-account name="myLetsEncryptAccount" contact-urls="mailto:admin@admin.org"> <account-key key-store="accountsKS" alias="letsEncrypt"/> </certificate-authority-account> </certificate-authority-accounts> ... </tls> ... </subsystem>
Notice that a certificate-authority-account has the following attributes and element:
To obtain a certificate from Let’s Encrypt, the key-store obtain-certificate command can be used. Its syntax is as follows:
obtain-certificate --alias= --domain-names= --certificate-authority-account= [--agree-to-terms-of-service=<true,false>] [--staging=<true,false>] [--algorithm=] [--key-size=] [--credential-reference=]
Let’s take a closer look at the obtain-certificate operation’s parameters:
The obtain-certificate command will use the referenced certificate-authority-account to create an account with Let’s Encrypt if one does not already exist. It will then request a certificate from Let’s Encrypt for the specified domain-names. In particular, the obtain-certificate operation will prove ownership of the requested domain names, generate a key pair, generate a certificate signing request (CSR) using the generated key pair and the requested domain names, and submit this CSR to Let’s Encrypt. If successful, the obtain-certificate operation will retrieve the resulting certificate chain from Let’s Encrypt and store it along with the generated PrivateKey under the given alias in the key-store. These changes will also be persisted to the file that backs the key-store.
For example, to request a certificate from Let’s Encrypt for the domain name “www.example.org” using the “myLetsEncryptAccount” certificate-authority-account, the following command could be used. The resulting certificate will be stored in the file that backs the "serverKS" key-store under the alias “server”.
/subsystem=elytron/key-store=serverKS:obtain-certificate(alias=server,domain-names=[www.example.org],certificate-authority-account=myLetsEncryptAccount,agree-to-terms-of-service)
You can now check the alias names in the key-store and confirm the new alias, “server”, is listed:
/subsystem=elytron/key-store=serverKS:read-aliases() { "outcome" => "success", "result" => ["server"] }
To make use of this server certificate that’s been issued by Let’s Encrypt for one-way or two-way SSL, this server key-store can be used to create a key-manager in the Elytron subsystem and an ssl-context that references this key-manager can then be created. More details about setting up one-way and two-way SSL can be found in the Elytron documentation.
If you need to revoke a certificate that was issued by Let’s Encrypt, the revoke-certificate command can be used:
/subsystem=elytron/key-store=serverKS:revoke-certificate(alias=server,reason=keyCompromise,certificate-authority-account=myLetsEncryptAccount)
In the above example, alias identifies the certificate that should be revoked. The certificate-authority-account is a reference to the certificate authority account information that should be used to revoke the certificate. The reason is optional and indicates the reason for revocation. If provided, it must be a valid revocation string.
Once the certificate has been successfully revoked, it will be deleted from the key-store. This change will also be persisted to the file that backs the key-store.
The should-renew-certificate command can be used to check if a certificate is due for renewal. It returns true if the certificate expires in less than the given number of days and false otherwise. Its output also indicates the number of days to expiry. In the following example, should-renew-certificate checks if the certificate stored under the alias “server” expires in less than 15 days.
/subsystem=elytron/key-store=serverKS:should-renew-certificate(alias=server,expiration=15) { "outcome" => "success", "result" => { "should-renew-certificate" => false, "days-to-expiry" => 89L } }
If the expiration parameter is not provided, it will default to 30 days, i.e., should-renew-certificate will return true if the certificate expires in less than 30 days and false otherwise.
Certificates issued by Let’s Encrypt are valid for 90 days. Let’s Encrypt recommends renewing certificates every 60 days. You can automate renewal by first creating a CLI script that checks if a certificate is due for renewal and if so, uses the obtain-certificate command to renew it. You could then create a cron job that runs say, twice daily, and executes the CLI script. A simple example of such a CLI script can be found below:
if (result.should-renew-certificate == true) of /subsystem=elytron/key-store=serverKS:should-renew-certificate(alias=server) # certificate is due for renewal in less than 30 days, obtain a new certificate to replace the existing one in the key-store /subsystem=elytron/key-store=serverKS:obtain-certificate(alias=server,domain-names=[www.example.org],certificate-authority-account=myLetsEncryptAccount,agree-to-terms-of-service) # re-initialize your key-manager to ensure your new certificate will be used without needing to restart the server /subsystem=elytron/key-manager=httpsKM:init() end-if
Notice that in the above script, after renewing the certificate, we can simply execute the key-manager init command in order to ensure that the new certificate will be used by the key-manager from now on without needing to restart WildFly.
To update the contact URLs that are associated with your Let’s Encrypt, the following commands can be used:
/subsystem=elytron/certificate-authority-account=myLetsEncryptAccount:write-attribute(name=contact-urls,value=[mailto:newadmin@admin.org]) reload /subsystem=elytron/certificate-authority-account=myLetsEncryptAccount:update-account()
If you ever want to change the key that is associated with your Let’s Encrypt account (e.g., in the event of a key compromise), the change-account-key command can be used:
/subsystem=elytron/certificate-authority-account=myLetsEncryptAccount:change-account-key()
If you ever need to deactivate your Let’s Encrypt account, the deactivate-account command can be used:
/subsystem=elytron/certificate-authority-account=myLetsEncryptAccount:deactivate-account()
This blog post has given an overview on how to obtain and manage certificates from the Let’s Encrypt certificate authority using the WildFly CLI. For more information on the Elytron subsystem, check out the Elytron documentation.
With WildFly 13, there’s a new way to configure permissions in the Elytron subsystem. In particular, it is now possible to configure permissions using a new permission-set resource.
Adding a permission-set takes the following general form:
/subsystem=elytron/permission-set=MyPermissionSetName:add(permissions=[{class-name="...", module="...", target-name="...", action="..."}...])
In the above command, permissions consists of a set of permissions, where each permission can have the following attributes:
After a permission-set has been created, it can be referenced when creating a permission mapper in order to assign permissions to an identity.
As an example, the following command can be used to add a new permission-set that contains the org.wildfly.security.auth.permission.RunAsPrincipalPermission:
/subsystem=elytron/permission-set=run-as-principal-permission:add(permissions=[{class-name="org.wildfly.security.auth.permission.RunAsPrincipalPermission", target-name="*"}])
This results in the following configuration in the Elytron subsystem (note that the login-permission and default-permissions permission sets are already present in the default Elytron subsystem configuration):
<subsystem xmlns="urn:wildfly:elytron:3.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto"> ... <permission-sets> <permission-set name="login-permission"> <permission class-name="org.wildfly.security.auth.permission.LoginPermission"/> </permission-set> <permission-set name="default-permissions"> <permission class-name="org.wildfly.extension.batch.jberet.deployment.BatchPermission" module="org.wildfly.extension.batch.jberet" target-name="*"/> <permission class-name="org.wildfly.transaction.client.RemoteTransactionPermission" module="org.wildfly.transaction.client"/> <permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/> </permission-set> <permission-set name="run-as-principal-permission"> <permission class-name="org.wildfly.security.auth.permission.RunAsPrincipalPermission" target-name="*"/> </permission-set> </permission-sets> ... </subsystem>
Next, create a simple permission mapper that references the newly created run-as-principal-permission permission set:
/subsystem=elytron/simple-permission-mapper=my-simple-permission-mapper:add(permission-mappings=[{principals=["anonymous"]}, \ {principals=["server1"], permission-sets=[{permission-set=login-permission}, {permission-set=default-permissions}, {permission-set=run-as-principal-permission}]}, \ {match-all=true,permission-sets=[{permission-set=login-permission}, {permission-set=default-permissions}]}])
This results in the following configuration in the Elytron subsystem:
<subsystem xmlns="urn:wildfly:elytron:3.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto"> ... <mappers> ... <simple-permission-mapper name="my-simple-permission-mapper"> <permission-mapping> <principal name="anonymous"/> </permission-mapping> <permission-mapping> <principal name="server1"/> <permission-set name="login-permission"/> <permission-set name="default-permissions"/> <permission-set name="run-as-principal-permission"/> </permission-mapping> <permission-mapping match-all="true"> <permission-set name="login-permission"/> <permission-set name="default-permissions"/> </permission-mapping> </simple-permission-mapper> ... </mappers> ... </subsystem>
The above command creates a simple permission mapper that:
This blog post has given an overview of Elytron permission sets. For more information about the Elytron subsystem, check out the Elytron documentation.
With WildFly 12, it is now possible to perform various KeyStore manipulation operations on a key-store resource in the Elytron subsystem using the JBoss CLI. In particular, the new operations make it possible to:
With these new operations, it is now possible to set up one-way and two-way SSL for applications and management interfaces using only the CLI - going back and forth between the CLI and keytool is no longer necessary. This blog post is going to give an overview of these new operations.
To start the server, use the following command:
$WILDFLY_HOME/bin/standalone.sh
To connect to the running server to execute CLI commands, use:
$WILDFLY_HOME/bin/jboss-cli.sh --connect
First, configure a key-store in the Elytron subsystem. Note that the path to the keystore file doesn’t actually have to exist yet.
/subsystem=elytron/key-store=exampleKS:add(path=server.keystore.jks, relative-to=jboss.server.config.dir, credential-reference={clear-text=secret}, type=JKS)
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 a new PrivateKeyEntry in the KeyStore.
/subsystem=elytron/key-store=exampleKS:generate-key-pair(alias=example, algorithm=RSA, key-size=1024, validity=365, credential-reference={clear-text=secret}, distinguished-name="CN=www.example.com")
After performing the above command, you can check the alias names in the KeyStore and confirm the new alias, "example", is listed:
/subsystem=elytron/key-store=exampleKS:read-aliases() { "outcome" => "success", "result" => ["example"] }
The generate-certificate-signing-request command generates a PKCS #10 CSR using a PrivateKeyEntry from the KeyStore. The generated CSR will be output to a file (in the example below, the CSR is output to server.csr).
/subsystem=elytron/key-store=exampleKS: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})
Notice that in the above command, alias=example refers to the PrivateKeyEntry that was created using the generate-key-pair command.
The import-certificate command imports a certificate or certificate chain from a file into an entry in the KeyStore. This can be used to either import a trusted certificate or to import a certificate reply that’s received after submitting a CSR to a certificate authority.
/subsystem=elytron/key-store=exampleKS:import-certificate(alias=example, path=/path/to/certificate/chain/file, relative-to=jboss.server.config.dir, credential-reference={clear-text=secret}, trust-cacerts=true)
The export-certificate command exports a certificate from an entry in the KeyStore to a file (in the example below, the certificate is exported to serverCert.cer).
/subsystem=elytron/key-store=exampleKS:export-certificate(alias=example, path=serverCert.cer, relative-to=jboss.server.config.dir, pem=true)
The change-alias command moves an existing KeyStore entry to a new alias.
/subsystem=elytron/key-store=exampleKS:change-alias(alias=example, new-alias=new-example, credential-reference={clear-text=secret})
After performing the above command, you can check the alias names in the KeyStore and confirm the new alias name, "new-example", is listed:
/subsystem=elytron/key-store=exampleKS:read-aliases() { "outcome" => "success", "result" => ["new-example"] }
The store command persists any changes that you have made using the above commands to the file that backs the KeyStore.
/subsystem=elytron/key-store=exampleKS:store()
This blog post has given an overview of the new KeyStore manipulation operations that are available via the CLI in WildFly 12. For information on how to set up one-way and two-way SSL for applications and management interfaces, check out the Elytron documentation.
Some SASL mechanisms support channel binding to external secure channels like TLS. The name of a SASL mechanism tells us if channel binding is supported. In particular, SASL mechanisms that support the optional use of channel binding have two SASL mechanism names - one name that includes the “-PLUS” suffix, which implies that channel binding is supported, and one name without the “-PLUS” suffix, which implies that channel binding is not supported (e.g., GS2-KRB5 and GS2-KRB5-PLUS, SCRAM-SHA-256 and SCRAM-SHA-256-PLUS, etc.). Whether or not channel binding is used is determined during SASL mechanism negotiation.
This blog post is going to show the server and client configuration needed to connect to the JBoss CLI using the SCRAM-SHA-256-PLUS mechanism, one of the SASL PLUS mechanisms provided by Elytron.
First, add a management user for the server - this is the user that we’re going to use later on when attempting to connect to the CLI. For this example, we’re going to create a filesystem-based identity store and add a user named “bob” with password “pAssw0rd” using the following CLI commands:
/subsystem=elytron/filesystem-realm=exampleRealm:add(path=fs-realm-users,relative-to=jboss.server.config.dir) /subsystem=elytron/filesystem-realm=exampleRealm:add-identity(identity=bob) /subsystem=elytron/filesystem-realm=exampleRealm:set-password(identity=bob,clear={password=pAssw0rd})
Now, we’re going to add the filesystem-realm that we just created to the “ManagementDomain” security domain that is already defined in the default Elytron subsystem configuration and we’re going to make this the default security realm for this security domain:
/subsystem=elytron/security-domain=ManagementDomain:list-add(name=realms, value={realm=exampleRealm}) /subsystem=elytron/security-domain=ManagementDomain:write-attribute(name=default-realm, value=exampleRealm)
Next, use the following commands to secure the management interface using Elytron:
/core-service=management/management-interface=http-interface:write-attribute(name=http-upgrade,value={enabled=true, sasl-authentication-factory=management-sasl-authentication}) /core-service=management/management-interface=http-interface:write-attribute(name=http-authentication-factory,value=management-http-authentication) /core-service=management/management-interface=http-interface:undefine-attribute(name=security-realm)
Finally, generate a server keystore and a client truststore using the keytool command, as shown below. We’re going to use these to enable one-way SSL/TLS for the management interface.
Generate the server keystore:
keytool -genkeypair -alias localhost -keyalg RSA -keysize 1024 -validity 365 -keystore server.keystore.jks -dname "CN=localhost" -keypass secret -storepass secret
Export the server certificate:
keytool -exportcert -keystore server.keystore.jks -alias localhost -keypass secret -storepass secret -file server.cer
Import the server certificate into the client’s truststore:
keytool -importcert -keystore client.truststore.jks -storepass secret -alias localhost -trustcacerts -file server.cer
Now we’re ready to proceed with the server and client configuration needed to use the SCRAM-SHA-256-PLUS mechanism.
First, configure a key-store, key-manager, and server-ssl-context in the Elytron subsystem using the server keystore that we just created (the following commands assume the server.keystore.jks file is located in the $WILDFLY_HOME/standalone/configuration directory):
/subsystem=elytron/key-store=exampleKS:add(path=server.keystore.jks, relative-to=jboss.server.config.dir, credential-reference={clear-text=secret}, type=JKS) /subsystem=elytron/key-manager=exampleKM:add(key-store=exampleKS, credential-reference={clear-text=secret}) /subsystem=elytron/server-ssl-context=exampleSSC:add(key-manager=exampleKM, protocols=["TLSv1.2"])
Next, enable HTTPS on the management interface using the newly created server-ssl-context:
/core-service=management/management-interface=http-interface:write-attribute(name=ssl-context, value=exampleSSC) /core-service=management/management-interface=http-interface:write-attribute(name=secure-socket-binding, value=management-https)
Now, update the “management-sasl-authentication” SASL authentication factory to also offer the SCRAM-SHA-256-PLUS mechanism:
/subsystem=elytron/sasl-authentication-factory=management-sasl-authentication:list-add(name=mechanism-configurations, value={mechanism-name=SCRAM-SHA-256-PLUS})
Finally, reload the server using the :reload command.
We can use a wildfly-config.xml file to provide the information that’s needed to connect to the CLI:
<configuration> <authentication-client xmlns="urn:elytron:1.0"> <authentication-rules> <rule use-configuration="auth-config"/> </authentication-rules> <authentication-configurations> <configuration name="auth-config"> <sasl-mechanism-selector selector="SCRAM-SHA-256-PLUS"/> <set-user-name name="bob"/> <credentials> <clear-password password="pAssw0rd"/> </credentials> </configuration> </authentication-configurations> <key-stores> <key-store name="truststore" type="JKS"> <file name="/path/to/client.truststore.jks" /> <key-store-clear-password password="secret" /> </key-store> </key-stores> <ssl-contexts> <ssl-context name="client-cli-context"> <trust-store key-store-name="truststore" /> </ssl-context> </ssl-contexts> <ssl-context-rules> <rule use-ssl-context="client-cli-context" /> </ssl-context-rules> </authentication-client> </configuration>
Notice that the wildfly-config.xml file specifies that the SCRAM-SHA-256-PLUS mechanism should be used and the username and password that should be used when attempting to connect to the CLI. It also configures an ssl-context using the client truststore that we created earlier.
Now, we just need to specify this wildfly-config.xml file when connecting to the CLI. The following command connects to the CLI and executes the :whoami command.
$WILDFLY_HOME/jboss-cli.sh -c --controller=remote+https://127.0.0.1:9993 -Dwildfly.config.url=/path/to/wildfly-config.xml :whoami
You should see the following output, which indicates that we’ve successfully connected to the CLI using the SCRAM-SHA-256-PLUS mechanism.
{ "outcome" => "success", "result" => {"identity" => {"username" => "bob"}} }
This blog post has shown how to set up one-way SSL/TLS for the management interface and how to then use a SASL mechanism that supports channel binding to connect to the CLI.