One of the things that took me more time to understand when starting to use Wildfly was how caching worked for authentication. Besides the functionality is quite different comparing it to the old JBoss-AS so I think that it is good to summarize my findings here. I know how I am, and I will forget part of the idea if I do not use it again in the next months, and I will have doubts that will make me test it again. So better if I spend some time writing the current entry.
In the pre-wildfly times the web part was based in the jbossweb subsystem, which was mainly Tomcat. In Tomcat (at least in its default functionality, I do not know if you can change that default behavior) when a login happens because of a security-constraint the information is stored in the session. Therefore, once the session is authenticated (no matter the mechanism used to do it -BASIC, FORM, KERBEROS,...-) there are no more login calls. The principal associated with the request is retrieved from the session and no more authentication processes are executed. This behavior has the consequence that the requests that use no session (for example static files that does not create a session) are authenticated in every request until the session is created and used as a cache for the authentication information (take this on mind).
But when Wildfly entered in the game, the web part was renewed with the undertow project and, to my surprise, the previous behavior was completely changed (and with no documentation about it). Now the basic idea is that undertow always, and always means always, performs a verification of the account. For that it uses the interface IdentityManager that is called every time to refresh the account. For example looking into the BasicAuthenticationMechanism, the class that manages the BASIC authentication, this line performs the verification of the header. Does it mean that now Wildfly always logs the user in at every request? Bombarding the LDAP or Database to check the password and obtaining the roles all the time? Well, in theory yes, but in the end there are other caches to avoid this.
I am going to focus the entry in the old security subsystem (although I think that elytron is more or less the same). If the final authentication uses a security-domain there is a JAAS stack of login modules that performs the real authentication of the user (LDAP, files, database or any module that is finally authenticating the user). The security domain has a cache-type property, there is a default value that has a static cache of entries using LIRS strategy (there is also a infinispan type that lets configure more specific cache settings). So, using this cache, although undertow performs the verification in every request, when the process finally enters in the security domain code this cache is in place and no real authentication is performed. But, important to remember, if the cache-type is removed in the security domain configuration, every request is authenticated again and again.
At this point the things seem to be clear, now Wildfly authenticates always the request (if security is needed) but there is a cache that can be configured to avoid flooding the user store. Using a more specific cache like infinispan the application can even realize about changes in the final user store (password changed or new roles associated). But I have been talking about Basic authentication until now, using Basic the username and password are sent by the browser in every request, but... What happens with other mechanisms? For example, when using a Form to login, the username and password are only available when the login page is displayed to the user. What does Wildfly do in those cases?
Looking the code undertow performs another trick for those mechanisms. The FormAuthenticationMechanism registers the account when the login is really executed and it is available from there for the subsequent requests (the last parameter true has the effect to cache the account). Once the account is registered by the form mechanism another CachedAuthenticatedSessionMechanism enters in the game and performs the verification of the previous account. So, in summary, if the application is using a mechanism that (by design) has no access to the account in every request (for example Basic can do that but not Form), the mechanism implementation itself should register the account (as the Form mechanism does) and the cached mechanism is the one in charge of getting the cached account and doing its verification. But, important again, even in Form the account is validated in every request (the previously commented cache in the security domain should be configured to avoid this).
So, in the end, the summary is just the following three points:
Wildfly starts the authentication process for every request that should be authenticated (information is not stored in session like in the pre-wildfly versions).
Even mechanisms that cannot naturally do that (because the username/password pair is not available in every request, Form for example) starts the login in every request.
In order to avoid this constant re-login you need to configure cache in the security domain (default or infinispan type).
As I said, the new elytron has not been considered, I do not have all the details but I think that it is more or less the same. You can check it if you are curious about how the new security subsystem works. In case of a security domain the cache is usually configured to the default type and, therefore, there is usually no problem (but better if we understand what is happening under the hood). Hope it helps to somebody else. I think that it is incredible that this kind of changes are not reflected in any documentation or specification paper.
Regards!
Comments