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