Saturday, July 23. 2022
Creating a custom credential store for wildfly


The first step is downloading, installing and starting the last wildfly server.
wget https://github.com/wildfly/wildfly/releases/download/26.1.1.Final/wildfly-26.1.1.Final.zip unzip wildfly-26.1.1.Final.zip cd wildfly-26.1.1.Final/bin ./add-user.sh -u admin -p admin ./standalone.sh
The credential stores are just provided by a standard JavaSE Provider. So in order to create a custom implementation two classes should be developed.
The one that extends the CredentialStoreSpi. This class is the real implementation of the store, with methods like store, retrieve or getAliases to manage the secret values. The standard implementations are placed in this folder and, for example, the MapCredentialStore is a simple Map implementation which is a useful starting point.
But the Provider is also needed to register the previous implementation. Inside elytron the provider class is WildFlyElytronCredentialStoreProvider. It adds the services for the standard stores with the correct types, algorithms and implementation classes.
For the entry a simple credential store that saves the secrets in a properties file is going to be developed. But to make it a bit more interesting the values in the file are going to be encrypted using a PBE algorithm. The PBE key will be derived from the password passed to the credential store. This point is a bit weak and maybe it was better to use a hardcoded key, but I think that this way the entry is more educational. As always, the implementation is just an example you can extend, improve and adapt to your needs. The full maven project can be downloaded from here and it is also in my personal github account.
For details in the implementation just check the store class but let's show the provider constructor.
public CustomCredentialStoreProvider() { super("CustomCredentialStoreProvider", "0.1", "Custom CredentialStore Provider"); putService(new Service(this, "CredentialStore", "CustomCredentialStoreProvider", "es.rickyepoderi.ccs.CustomCredentialStore", Collections.
emptyList(), Collections. emptyMap())); } The class registers the implementation putting the service with type CredentialStore (it should be this value), algorithm is CustomCredentialStoreProvider (this name will be used later to configure the store inside wildfly) and the implementation class is es.rickyepoderi.ccs.CustomCredentialStore. No aliases or attributes are defined.
The final part of the coding process is adding a META-INF/services/java.security.Provider file that will make the JDK automatically detect the provider (ServiceLoader technique).
cat src/main/resources/META-INF/services/java.security.Provider es.rickyepoderi.ccs.CustomCredentialStoreProvider
So we have our custom credential store implementation ready. Just compile it and create the jar.
cd custom-credential-store mvn clean package
The final file will be place in the target directory.
Now the interesting part, using CLI add the library as a module inside wildfly.
module add --name=es.rickyepoderi.ccs --resources=/path/to/custom-credential-store/target/custom-credential-store-0.0.1.jar --dependencies=org.wildfly.security.elytron
The provider should be loaded into elytron to make it available to the server (if you remember I did the same with the Bouncy Castle FIPS jars in a previous entry).
/subsystem=elytron/provider-loader=ccs:add(module=es.rickyepoderi.ccs)
As the provider was defined in the service file no more arguments are needed. The provider class will be located automatically.
The custom credential can be configured at this point.
/subsystem=elytron/credential-store=ccs:add(providers=ccs, credential-reference={clear-text=XXXXXX}, location=custom.properties, relative-to=jboss.server.config.dir, type=CustomCredentialStoreProvider, create=true)
The type should be CustomCredentialStoreProvider (the algorithm registered inside the provider). The store will use the provided password (please here it is provided in plain which is a nonsense, as I commented this is just an example) to create a PBE key and the values will be encrypted with it. The underlying file is specified using location and relative-to options and placed inside the configuration folder of the server. By default the implementation encrypts values using PBEWithHmacSHA512AndAES_256 algorithm but it can be changed using the implementation-properties option. In general that option can pass custom attributes to the implementation and the example manages several of them you can try and play with.
Finally a secret is created inside the store ready to be used.
/subsystem=elytron/credential-store=ccs:add-alias(alias=alias1, secret-value=sa)
And if you check the properties file the alias will be there with the value encrypted.
grep alias1 ../standalone/configuration/custom.properties alias1=oDaesxvoSWLkiwWo89sjzA\=\=\:MFkwOAYJKoZIhvcNAQUMMCsEFGTaNHH+6TJiT6PrGPC/tByEaGIWAgIQAAIBIDAMBggqhkiG9w0CCwUAMB0GCWCGSAFlAwQBKgQQDzqM6mftjvjqCg49J2td7Q\=\=
That secret will be used to connect to the default H2 datasource that is defined in the wildfly server (that is why the secret value was sa).
batch /subsystem=datasources/data-source=ExampleDS:undefine-attribute(name=password) /subsystem=datasources/data-source=ExampleDS:write-attribute(name=credential-reference, value={store=ccs, alias=alias1}) run-batch reload
The server should be reloaded OK and the datasource should be able to connect to the H2 database.
/subsystem=datasources/data-source=ExampleDS:test-connection-in-pool { "outcome" => "success", "result" => [true] }
It works successfully!
That is all. The entry is a simple example to develop your own credential store. This is usually not needed and standard stores provided by wildfly should be enough for you. But, if for whatever reason, there is a specific requirement that forces you to implement a custom credential store, here you have an example. Remember my implementation uses the password provided to the store to derive a PBE key and encrypt values with it (it was done to show how to recover that password but maybe using a hadcoded key was a better idea). It is just a proof of concept. The entry details the implementation and the configuration of the store inside the server. Links to the maven project were available before, please use it with care.
Best regards!
Comments