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.
















No comments:

Post a Comment