Wednesday 26 June 2019

WildFly Elytron Credential Store APIs

WildFly Elytron contains a CredentialStore API/SPI along with a default implementation that allows for the secure storage of various credential types.  This blog post is to introduce some of the APIs available to make use of the credential store from directly within your code.

The full example is available at elytron-examples/credential-store but this blog post will highlight the different steps in the code.

Before the credential store is accesses a ProtectionParameter is needed for the store, the following two lines: -

Password storePassword = ClearPassword.createRaw(
    ClearPassword.ALGORITHM_CLEAR, 
    "StorePassword".toCharArray());
ProtectionParameter protectionParameter = new CredentialSourceProtectionParameter(
    IdentityCredentials.NONE.withCredential(
    new PasswordCredential(storePassword)));

Credential store implementations can be registered using java.security.Provider instances and follow a similar pattern used elsewhere: -

  • getInstance
  • initialise
  • use
An instance of the credential store we want to use can be obtained from: -

CredentialStore credentialStore = CredentialStore.getInstance(
    "KeyStoreCredentialStore", CREDENTIAL_STORE_PROVIDER);


In this example an instance of java.security.Provider has been passed in, if this parameter was omitted the registered providers would be used instead.

The credential store implementation provided with WildFly Elytron is "KeyStoreCredentialStore" which is a credential store implementation which makes use of a KeyStore for persistence.

The credential store instance is now initialised using a Map and the previously created ProtectionParameter.  The values supported in the Map are specific to the credential store implementation.

Map<String, String> configuration = new HashMap<>();
configuration.put("location", "mystore.cs");
configuration.put("create", "true");

credentialStore.initialize(configuration, protectionParameter);

The "location" value is used to specify the full path to the file which represents the credential store.  The second option "create" specifies that the credential store should be created if it does not already exist, whilst tooling can be used to create and populate a store in advance this does mean that a store can be created entirely within the application that is using it.

With those few lines we now have a credential store ready for use.  The first thing to do is to add some entries to this store.  Within the application server we do presently predominantly use this for storing passwords, however many alternative credential types can be stored using the credential store so here are a few examples of the types that can be stored.

Storage of a clear text password: -

Password clearPassword = ClearPassword.createRaw(
    ClearPassword.ALGORITHM_CLEAR, "ExamplePassword".toCharArray());
credentialStore.store("clearPassword", 
    new PasswordCredential(clearPassword));

Generation and storage of a SecretKey: -

KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
SecretKey secretKey = keyGenerator.generateKey();
credentialStore.store("secretKey", 
    new SecretKeyCredential(secretKey));

Generation and storage of a KeyPair: -

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048, SecureRandom.getInstanceStrong());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
credentialStore.store("keyPair", new KeyPairCredential(keyPair));

Storage of just the public key from the KeyPair: -

credentialStore.store("publicKey", 
    new PublicKeyCredential(keyPair.getPublic()));

Various credential types are supported within WildFly Elytron and can be seen here: -

http://wildfly-security.github.io/wildfly-elytron/1.9.x/api-javadoc/org/wildfly/security/credential/package-summary.html

For custom credential store implementation different credential types may be supported including custom ones not listed here.

Once we have a populated credential store it is possible to list the aliases similar to how you would for a KeyStore: -

System.out.println("************************************");
System.out.println("Current Aliases: -");
for (String alias : credentialStore.getAliases()) {
    System.out.print(" - ");
    System.out.println(alias);
}
System.out.println("************************************");

Finally the purpose of storing credentials in a credential store is so that they can subsequently be retrieved, the following shows how each of the credentials added above can be retrieved: -

Password password = credentialStore.retrieve(
    "clearPassword", PasswordCredential.class).getPassword();
SecretKey secretKey = credentialStore.retrieve(
    "secretKey", SecretKeyCredential.class).getSecretKey();
KeyPair keyPair = credentialStore.retrieve(
    "keyPair", KeyPairCredential.class).getKeyPair();
PublicKey publicKey = credentialStore.retrieve(
    "publicKey", PublicKeyCredential.class).getPublicKey();

In the above command the expected credential type is passed into the retrieve method, using the credential store APIs it is possible for multiple credentials to be stored under the same alias.  This could be useful in situations where a single alias can represent say a password AND a secret key.
















Wednesday 12 June 2019

Security Feature Development for WildFly 17

At the beginning of development for WildFly 17 I published the following blog post identifying the features we were planning to work on during the feature development phase: -

https://darranl.blogspot.com/2019/03/security-features-for-wildfly-17.html

Now that WildFly 17 is complete this blog post is to provide some further information on the progress of these features.

Reviewing release notes provides a very coarse list of the changes that were actually merged during the development of Wildfly 17 this blog post provides further information in relation to the progress of features actively being developed.

JDBC Security Realm - Hex and Modular Crypt Encoding.


One of the planned features was to add support for hex encoding of passwords and support for modular crypt with the JDBC security realm, this feature has been merged and is available from WildFly 17 Final.

WFCORE-3832 Support hex encoding in jdbc-realm for elytron.

A blog post is available here showing some examples using this feature: -

https://developer.jboss.org/people/aabdelsa/blog/2019/06/11/configuring-a-jdbc-security-realm-with-bcrypt-and-modular-crypt-password-mappers

Additionally additional documentation has been published describing both the PasswordFactory APIs and the JDBC security realm.

https://docs.wildfly.org/17/WildFly_Elytron_Security.html#Passwords
https://docs.wildfly.org/17/WildFly_Elytron_Security.html#jdbc-security-realm

TLS 1.3

WFCORE-4172 Add support for TLS 1.3

Support for TLS 1.3 was developed during the development of WildFly 17, the changes were not quite ready during before the feature freeze however we hope these can be merged soon for WildFly 18.  In the meantime some further background to the changes can be found here: -

https://developer.jboss.org/people/fjuma/blog/2019/06/11/upcoming-support-for-tls-13-with-wildfly

X509Certification Mapping

WFCORE-4361 Enhanced mapping of X509Certificate to the underlying identity.

This feature is also close to be ready to be merged with information available at: -

https://developer.jboss.org/people/fjuma/blog/2019/06/11/mapping-an-x509-cert-to-an-identity-using-a-subject-alt-name

Audit Logging RFC Support and Performance Enhancements

More information can be found in the following blog post on enhancements presently being prepared in relation to enhanced RFC support and performance enhancements for audit logging: -

https://justinwildfly.blogspot.com/2019/06/enhanced-audit-logging-in-wildfly.html

Web Services and RESTEasy Client Integration

This is a pair of tasks involving collaboration between the WildFly Elytron engineering team and the respective engineers working on these projects.

WFLY-11697 WS integration with WildFly Elytron - AuthenticationClient for Authentication / SSL

The following blog contains information on the progress so far: -

https://dvilkola.wordpress.com/2019/06/11/web-services-client-and-resteasy-client-integration-with-wildfly-elytron/

Identity Attribute Aggregation

The aggregation of an identity's attributes from multiple security realms is being handled under WFCORE-4447, more information on the progress of this feature can be seen under the following blog post: -

https://darranl.blogspot.com/2019/06/wildfly-elytron-aggregation-of.html

Certificate Authority Account Configuration

Previous work has added support for LetsEncrypt within the application server WFCORE-4362 is a follow on task to make it possible to configure alternative certificate authority accounts enabling support for alternative certificate authorities which support the ACME protocol.

More information about this development can be found in the following blog post: -

https://dvilkola.wordpress.com/2019/06/11/obtain-and-manage-certificates-from-any-server-instance-that-implements-acme-specification-using-the-wildfly-cli/

OCSP

Finally development has been progressing WFCORE-3947 and we are hoping this one will be merged shortly, more information on this development can be seen in the proposal: -

https://github.com/wildfly/wildfly-proposals/pull/188













WildFly Elytron Aggregation of Attributes

One of the features developed during the development phase of Wildfly 17 was the addition of support for aggregating security realms to allow an identity's attributes to be aggregated from multiple realms.

https://issues.jboss.org/browse/WFCORE-4447

This feature was not quite ready as the code freeze for WildFly 17 arrived however the feature is now complete and is planned to be merged into WildFly 18 so will be available for use as soon as Wildfly 18 is released.

This enhancement has made use of the existing aggregate-security-realm resource, presently this resource supports two different attributes: -

  • authentication-realm - The realm to load credentials from and perform evidence verification against.
  • authorization-realm - The realm to use to load the identities attributes from for authorization decisions.

This enhancement is adding a new attribute authorization-realms to the resource which allows for multiple realms to be referenced.

A realm can then be defined with a CLI command: -

/subsystem=elytron/aggregate-realm=example:add(
    authentication-realm=ApplicationRealm, 
    authorization-realms=[RealmA, RealmB])

Attributes are aggregated on a 'first defined wins' basis, so as an example say an identity was assigned the following attributes from RealmA: -

  • groups = User, Supervisor
  • city = London
And from RealmB the following attributes were assigned: -
  • groups = Manager
  • telephone = 0000 0000 0000
After aggregation the identity would have the following attributes: -

  • groups = User, Supervisor
  • city = London
  • telephone = 0000 0000 0000



Tuesday 5 March 2019

Security Features for WildFly 17

The development for WildFly 17 has now commenced, here are some of the features we are planning to be looking into developing for WildFly 17.

WFCORE-4360 Support encrypted expression resolution using a CredentialStore

The previous Vault implementation was effectively 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.  WFCORE-4360 is to look into how the CredentialStore could be used to support encrypted values within the overall model.

WFCORE-3947 Support SSL Certificate revocation using OCSP

ELY-1712 Enhanced Audit Logging

As the WildFly Elytron project was integrated with WildFly 11 an initial set of events were made available with a couple of options for logging these events, this feature request is to look into how we can enhance this further.

WFCORE-4361 Enhanced mapping of X509Certificate to the underlying identity.

Presently WildFly Elytron provides a variety of options to configure certificate based authentication, this feature request is to enhance how the certificate is mapped to the underlying identity.

WFLY-11697 Web Services Integration with WildFly Elytron

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.

WFCORE-4172 Add support for TLS 1.3

WFCORE-4362 Make the certificate authority used by a certificate-authority-account configurable.

At the moment integration with Lets Encrypt is supported, once the certificate authority account is configurable it will be possible to use this integration with other certificate authorities that implement the ACME protocol.

WFCORE-3832 Support hex encoding in jdbc-realm for elytron.

Using multiple security realms.
WildFly Elytron already supports the use of multiple security realms where a realm can be selected either from the authentication mechanism in use or by some recognisable pattern in the username. 

Where LoginModules were used in the previous PicketBox solution it was possible to stack the LoginModules for a few additional scenarios: -

  • Failover in the event of unavailability.
  • Aggregation of multiple identity stores into one.
    • Allowing identities to be located in different stores.
    • Allowing attributes to be loaded from multiple locations.

Issues will be created as needed to track these different scenarios but the aim is during WildFly 17 to begin to address these as they have been identified as making it difficult to migrate from PicketBox.


Also in preparation to develop WildFly Elytron 1.9 the project has been broken up into smaller modules to allow dependencies to be defined on specific modules without depending on the whole project - WildFly 17 will be switching to use the new modules.

Please keep in mind this blog post is a summary of our general plans and not a guarantee that all will be merged but it should give an indication as to the teams current priorities.  If any of these features are a priority to you please let us know, also let us know if there are missing security features you would like prioritising - we can take this into account for future releases.

Saturday 19 January 2019

Using WildFly Elytron with the Netty HttpServerCodec

The WildFly Elytron project was developed to meet the needs if the WildFly application server, however the APIs and SPIs within this project also allow us to use the project in other environments.

A couple of previous blogs from Farah Juma and myself have highlighted a couple of these environments already: -
 Using WildFly Elytron with Undertow Standalone
 Securing an embedded Jetty server using Elytron

Also I have previously published a blog describing how to implement a custom HTTP authentication mechanism using the WildFly Elytron SPIs.
WildFly Elytron - Implementing a Custom HTTP Authentication Mechanism

Being able to take a single security project and use it in multiple environments has numerous benefits, some of which are: -

  • Only needing to learn one framework instead of one framework per server type.
  • Portability of custom implementation such as authentication mechanisms or security realms which can be used in all environments.
  • The ability to combine multiple servers into a single process whilst using common security SPIs.
This blog post is to introduce the integration of WildFly Elytron with the Netty HttpServerCodec for HTTP authentication.

It is worth noting this integration is specifically making use of Netty's HttpServerCodec for integration, if an alternative HTTP server was developed on Netty then an alternative integration with WildFly Elytron would also be required.

The project containing the Netty integration code can be found on GitHub at elytron-web-netty

As an integration project this project only exposes once class as public API 'org.wildfly.elytron.web.netty.server.ElytronHandlers'  - the purpose this class is to take configured WildFly Elytron components and use them to insert a set of handlers into a Netty ChannelPipeline, once inserted they will perform authentication kaing use of Wildfly Elytron.

The example project can be found on GitHub at netty-standalone.

After checking out the example project it can be built using maven: -

    mvn clean instal

And then once build can also be executed using maven: -

    mvn exec:exec

Once running you can navigate to http://localhost:7776/ and access the application using the username 'alice' with the password 'alice123+', if successful you should see the following response: -

Current identity 'alice'

Now that the example project is running we can look into the details as to how WildFly Elytron was activated.

Activation

Within Netty a ChannelInitializer is required to add the handlers to the ChannelPipeline, within the example project this is within the class 'org.wildfly.security.examples.TestInitialiser' and is implemented as: -


protected void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();
    pipeline.addLast(new HttpServerCodec());
    pipeline.addLast(new HttpServerExpectContinueHandler());
    securityHandler.apply(pipeline);
    pipeline.addLast(new TestContentHandler());
}

The 'securityHandler' within the example block of code is actually an instance of the ElytronHandlers class, it is worth noting that it can be cached and re-used potentially performing many initialisations concurrently.

As the example projects starts up the ElytronHandlers is initialised as follows: -

ElytronHandlers securityHandlers = ElytronHandlers.newInstance()
        .setSecurityDomain(securityDomain)
        .setFactory(createHttpAuthenticationFactory())
        .setMechanismConfigurationSelector(MechanismConfigurationSelector.constantSelector(
                MechanismConfiguration.builder()
                        .addMechanismRealm(MechanismRealmConfiguration.builder().setRealmName("Elytron Realm").build())
                        .build()));

This initialisation takes a pre-configured SecurityDomain and HttpAuthenticationFactory and adds a MechanismConfigurationSelector, these have been covered on prior blogs so I am not going to cover the details of these again here although they can all be seen within the org.wildfly.security.examples.HelloWorld class to see how these are initialised.

One further method not used in this example is: -

public ElytronHandlers setAuthenticationRequired(final Predicate<HttpRequest> authenticationRequired)

This can be used to add a Predicate to decide on a request by request basis if authentication is required after inspecting the HttpRequest.

Outcome

After the initialisation described above the channel end up with the following handlers defined on it's pipeline: -

For a request after being handled by the HttpServerCodec handler it will pass so the ElytronInboundHandler, this is where the authentication by WildFly Elytron takes place and a SecurityIdentity is established.

If authentication fails the request can be turned around at this stage and sent back to the client.

Our next inbound handler is the ElytronRunAsHandler, this handler is responsible for taking any established SecurityIdentity and ensuring it is associated with the current thread.

In this set up we have one outbound handler which is the ElytronOutboundHandler, this handler is called for all messages being sent back to the client is responsible for setting any security related HTTP headers that need to be set on the respone message.


Contribution

The Netty integration project is currently tagged as a Beta as a number of areas still need to be developed, if anyone is interested in contributing their contributions will be welcome.

Completing the implementation of the ElytronHttpExchange class: -
  • Support for all Scope types.
  • Parsing of request parameters.
  • Cookie support.
Request InputStream handling.

Improved response OutputStream handling.

Adding support for authorization, either role based checks or Java permission checks.

Further enhancement of the test cases including adding more mechanisms to be tested.

Outside of the Netty integration there are other projects out there still possible options for integration, some of these are: -
  • Tomcat
  • Pure servlet integration.
  • EE Security integration.

For all integrations some form of common testsuite to verify the full permutation of authentication mechanisms available within WildFly Elytron.