Hello everyone.
We are migrating our raw Shiro code to using Pac4j and so far it has been great! Everything seems to work well with SpringBoot, Shiro, MongoDB, and JDK10. Our goal is to replace our old Shiro implementation with Pac4j (so, still using Shiro but Pac4j provides the filters, etc.)
We are trying to enable Shiro "authentication" caching from the Realm for a logged in user. Right now the back-end cache is Caffeine but when I switch it over to using Ignite Distributed Cache I see that it cannot find the element in the cache.
I have now run into an issue that I cannot seem to pinpoint. It does not appear to be in the caching itself as I see the put methods firing and elements in the cache. The results are it does not use the cache for authentication. In the case where Ignite is the back-end cache it throws an exception because the value cannot be found and hence fails to authenticate (which may be due to the way it is serialized but i can tell/or have started to fully debug yet).
It looks the have something to do with the way the key is created from the token. In all case i get back an "Optional" key which I do not believe is serializable.
I see when I try to login (using either the simple test authenticator or the mongo profile service):
[DEBUG] o.apache.shiro.realm.AuthenticatingRealm : Looked up AuthenticationInfo [#Pac4jPrincipal# | profiles: [#CommonProfile# | id: pwd | attributes: {username=pwd} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] |] from doGetAuthenticationInfo
[DEBUG] i.l.security.support.shiro.ShiroCache : PUT :
Optional[#CommonProfile# | id: pwd | attributes: {username=pwd} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] (Optional)
#Pac4jPrincipal# | profiles: [#CommonProfile# | id: pwd | attributes: {username=pwd} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] | (SimpleAuthenticationInfo)
null
[DEBUG] o.apache.shiro.realm.AuthenticatingRealm : Looked up AuthenticationInfo [#Pac4jPrincipal# | profiles: [#CommonProfile# | id: pwd | attributes: {username=pwd} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] |] from doGetAuthenticationInfo
[DEBUG] i.l.security.support.shiro.ShiroCache : PUT :
key --> Optional[#CommonProfile# | id: pwd | attributes: {username=pwd} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] (Optional)
value --> #Pac4jPrincipal# | profiles: [#CommonProfile# | id: pwd | attributes: {username=pwd} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] | (SimpleAuthenticationInfo)
null
[DEBUG] o.a.s.a.c.SimpleCredentialsMatcher : Performing credentials equality check for tokenCredentials of type [java.lang.Integer and accountCredentials of type [java.lang.Integer]
It looks to be putting the value into the cache but based on the key not looking it back up and retrieving it from the cache...
My Pac4jRealm looks like this (I extended the class but there are not changes it was just for some debugging):
@Bean
Realm pac4jStudioRealm()
{
final Pac4jStudioRealm realm = new Pac4jStudioRealm();
//Enable Authentication Caching
realm.setAuthenticationCachingEnabled(true);
realm.setAuthenticationCacheName(AUTHENTICATION_CACHE);
//Enable Authorization Caching
realm.setAuthorizationCachingEnabled(true);
realm.setAuthorizationCacheName(AUTHORIZATION_CACHE);
//Return realm
return realm;
}
My FormClient and MongoProfileService is configured (and injected into the Forms Client only) like this:
@Bean
FormClient pac4jFormsClient(final Authenticator<UsernamePasswordCredentials> authenticator)
{
final FormClient client = new FormClient();
client.setLoginUrl(properties.getLoginUrl());
client.setAuthenticator(authenticator);
return client;
}
@Bean
Authenticator<UsernamePasswordCredentials> pac4jMongoUsernamePasswordAuthenticator(final MongoClient mongo, final PasswordEncoder passwordEncoder)
{
final MongoProfileService profileService = new MongoProfileService(mongo, passwordEncoder);
profileService.setUsersDatabase(USERS_DATABASE);
profileService.setUsersCollection(USERS_COLLECTION);
profileService.setAttributes("firstname");
return profileService;
}
If I disable the authentication caching everything seems to work fine.