Using Pac4j with Shiro "authentication" cache

124 views
Skip to first unread message

KimJohn Quinn

unread,
Sep 13, 2018, 1:26:06 PM9/13/18
to Pac4j users mailing list
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.

 

KimJohn Quinn

unread,
Sep 13, 2018, 1:39:20 PM9/13/18
to Pac4j users mailing list
Here is better log output showing the flow:

[TRACE] i.l.security.support.shiro.ShiroCache    : Getting object from cache [studioAuthcCache] for key [Optional[#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |]]
[TRACE] i.l.security.support.shiro.ShiroCache    : Element for [Optional[#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |]] is null.
[DEBUG] o.apache.shiro.realm.AuthenticatingRealm : Looked up AuthenticationInfo [#Pac4jPrincipal# | profiles: [#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] |] from doGetAuthenticationInfo
[TRACE] i.l.security.support.shiro.ShiroCache    : Putting object in cache [studioAuthcCache] for key [Optional[#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |]]
[TRACE] i.l.security.support.shiro.ShiroCache    : Getting object from cache [studioAuthcCache] for key [Optional[#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |]]
[TRACE] i.l.security.support.shiro.ShiroCache    : Element for [Optional[#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |]] is null.
[DEBUG] i.l.security.support.shiro.ShiroCache    : PUT :
Optional[#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] (Optional)
#Pac4jPrincipal# | profiles: [#MongoProfile# | id: test | attributes: {firstname=Test} | 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]
[DEBUG] o.a.shiro.authc.AbstractAuthenticator    : Authentication successful for token [io.buji.pac4j.token.Pac4jToken@59e6ef28].  Returned account [#Pac4jPrincipal# | profiles: [#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] |]

KimJohn Quinn

unread,
Sep 13, 2018, 1:50:34 PM9/13/18
to Pac4j users mailing list
One more quick test seems to show that I should not have any problems, at least with Caffeine, putting an "Optional" value as the key.


On Thursday, September 13, 2018 at 1:26:06 PM UTC-4, KimJohn Quinn wrote:

KimJohn Quinn

unread,
Sep 13, 2018, 2:17:55 PM9/13/18
to Pac4j users mailing list
Looking at the cache I see the following in the "Optional.Value()" which would cause the cache miss.

PUT Key Value = Pac4jPrincipal (what is in the cache)

GET Key Value = MongoProfile (Key being passed in)


On Thursday, September 13, 2018 at 1:26:06 PM UTC-4, KimJohn Quinn wrote:

KimJohn Quinn

unread,
Sep 13, 2018, 2:57:20 PM9/13/18
to Pac4j users mailing list
I think I found my problem.  Now I don't know how to fix it...

It looks like the lookup is being performed using a Pac4JPrincipal where as the key being put into the cache is a MongoProfile.

How do I coordinate this to use the same key so that I can use Mongo as my point of reference for all things user-related that I need to lookup?

Here is my debug output now, with more debugging, showing the lookup key vs. what has been put into the cache. 

[TRACE] i.l.security.support.shiro.ShiroCache    : Getting object from cache [studioAuthcCache] for key [Optional[#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |]]
[DEBUG] i.l.security.support.shiro.ShiroCache    : GET :
key: Optional[#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] (Optional)
  = #MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |
val: null (null)

[DEBUG] o.apache.shiro.realm.AuthenticatingRealm : Looked up AuthenticationInfo [#Pac4jPrincipal# | profiles: [#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] |] from doGetAuthenticationInfo
[TRACE] i.l.security.support.shiro.ShiroCache    : Putting object in cache [studioAuthcCache] for key [Optional[#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |]]
[TRACE] i.l.security.support.shiro.ShiroCache    : Getting object from cache [studioAuthcCache] for key [Optional[#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |]]
[DEBUG] i.l.security.support.shiro.ShiroCache    : GET :
key: Optional[#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] (Optional)
  = #MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |
val: null (null)
[DEBUG] i.l.security.support.shiro.ShiroCache    : PUT :
key: Optional[#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] (Optional)
  = #MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |
val: #Pac4jPrincipal# | profiles: [#MongoProfile# | id: test | attributes: {firstname=Test} | roles: [] | permissions: [] | isRemembered: false | clientName: FormClient | linkedId: null |] | (SimpleAuthenticationInfo)


On Thursday, September 13, 2018 at 1:26:06 PM UTC-4, KimJohn Quinn wrote:

KimJohn Quinn

unread,
Sep 13, 2018, 5:35:37 PM9/13/18
to Pac4j users mailing list
Looks to be a mistake on my part right now.  I was mis-interpreting my log output and my test was invalid.



On Thursday, September 13, 2018 at 1:26:06 PM UTC-4, KimJohn Quinn wrote:
Reply all
Reply to author
Forward
0 new messages