Hello,
I’m looking for information on how to programmatically interact with the cache in a cacheable security realm so that individual Principals can be ejected from the cache as desired. Some background information: I’m attempting to move from Wildfly 17 to Wildfly 21. We currently have a cached credentials service that is intended to synchronize the evicting, flushing, and searching of user credentials between two caches: the underlying Wildfly cache, and a separate application-wide cache maintained by a separate user service.
For wildfly 17, we created a cacheable security domain as follows:
/subsystem=security/security-domain=datawave:add(cache-type=infinispan)
/subsystem=security/security-domain=datawave/authentication=classic:add
/subsystem=security/security-domain=datawave/authentication=classic/login-module=Remoting:add( \
code=Remoting, \
flag=optional, \
module-options={password-stacking=useFirstPass})
/subsystem=security/security-domain=datawave/authentication=classic/login-module=RunAs:add( \
code=RunAs, \
flag=required, \
module-options={roleName=InternalUser})
/subsystem=security/security-domain=datawave/authentication=classic/login-module=Datawave:add( \
code=datawave.security.login.DatawavePrincipalLoginModule, \
flag=required, \
module-options={ \
principalClass=datawave.security.authorization.DatawavePrincipal, \
verifier=datawave.security.login.DatawaveCertVerifier, \
ocspLevel=off, \
allowUserProxying=false, \
trustedHeaderLogin="${dw.trusted.header.authentication:false}"})
/subsystem=security/security-domain=datawave/jsse=classic:add( \
keystore={type="${KEYSTORE_TYPE}", \
password="${KEYSTORE_PASSWORD}", \
url="file://${KEYSTORE}"}, \
truststore={type="${TRUSTSTORE_TYPE}", \
password="${TRUSTSTORE_PASSWORD}", \
url="file://${TRUSTSTORE}"})
We then have a method that produces the underlying cache (as a CacheableManager from picketbox) so it can be injected in other EJBs:
@Resource(name = "java:jboss/jaas/datawave")
private AuthenticationManager authenticationManager;
@Produces
@AuthorizationCache
@SuppressWarnings("unchecked")
public CacheableManager<Object,Principal> produceAuthManager() {
return (authenticationManager instanceof CacheableManager) ? (CacheableManager<Object,Principal>) authenticationManager : null;
}
This then gets injected into our credentials cache service where we can evict Principals as needed.
@Inject
@AuthorizationCache
private CacheableManager<?,Principal> authManager;
@Inject
private Instance<CachedDatawaveUserService> cachedDatawaveUserServiceInstance;
/**
* Removes all cached {@link DatawaveUser}s. There are potentially two caches in use. First, Wildfly uses a security cache that stores {@link Principal}s
* under the incoming credential key. This is normally a very short-lived cache (5-30 minutes). Second, a {@link CachedDatawaveUserService} may be in use,
* which means that it caches according to its own rules. This method attempts to clear both caches.
*
* @return a string indicating cache flush was successful
*/
@GET
@Path("/flushAll")
@JmxManaged
public String flushAll() {
try {
// Remove principals from the Wildfly cached authentication manager, if we have one in use.
authManager.flushCache();
if (!cachedDatawaveUserServiceInstance.isUnsatisfied()) {
cachedDatawaveUserServiceInstance.get().evictAll();
}
return "All credentials caches cleared.";
} catch (Exception e) {
GenericResponse<String> response = new GenericResponse<>();
response.addException(new QueryException(UNKNOWN_SERVER_ERROR, e));
throw new DatawaveWebApplicationException(e, response);
}
}
Our authentication will need to be migrated over to a custom security realm in Wildfly 26, and from my understanding, it will need to be embedded into a caching-realm if we want to continue to have a cache of the Principals via Wildfly. Something that will probably look similar to the following:
/subsystem=elytron/custom-realm=datawaveRealm:add( \
class-name=datawave.security.realm.DatawavePrincipalSecurityRealm, \
module="datawave.elytron", \
configuration={ \
verifier="datawave.security.realm.DatawaveCertVerifier", \
ocspLevel="off", \
allowUserProxying="false", \
trustedHeaderLogin="${trusted.header.login}"})
/subsystem=elytron/caching-realm=cachedDatawaveRealm:add( \
realm=datawaveRealm)
/subsystem=elytron/security-domain=datawave:add(default-realm=cachedDatawaveRealm,realms=[{realm=cachedDatawaveRealm}])
What would be the best way to inject the cache in use by the SecurityRealm elsewhere so that we can evict Principals as needed? I assume I need to access and inject the realm’s RealmIdentityCache instance. If this isn’t supported, what is the recommended way to programmatically interact with a security realm’s cache?