JAAS & JACC: How do I kick a user out?

456 Views Asked by At

We're currently adopting JAAS and JACC using JBoss EAP 6.4/7.0. Just a brief explanation on how we are applying things:

  • we use HttpServletRequest.login(...) to authenticate
  • subsequently, we use HttpServletRequest.logout() to log out.
  • we have a LoginModule which validates the credentials and preps up the Roles.

All is well and good, however, part of my application must allow a certain set of users to be able to:

  • revoke someone else's Role to log into the system, and
  • kick out them out of any currently-active sessions.

The first part is easy, but I am having a hard time trying to figure out how I could invalidate someone's session. Is there a way I could somehow get hold of some other user's Subject/Session and invalidate it?

Much appreciated

1

There are 1 best solutions below

0
On

Note on terminology:

  • Authentication Mechanism (AM) herein refers to any component responsible for making authentication statements pertaining to, and registering / establishing, as a result, the identity of, authenticated caller entities with / in a Java EE runtime. Such components may be specific to the Application Server (AS) or Java EE-standard; AS implementation details or types destined for extension by the Java EE application developer; deployed as part of a Java EE application or as part of the AS. One such component is your JAAS LoginModule (LM). While Identity Store (IS) appears to be the (semi-)normative term used for referring to (among other things) LMs nowadays, I wanted to reserve it for your application-specific, persistence layer (e.g. JPA @Entity) types representing your users, and thus had to establish this (ill-defined) distinction. "Why are you being vague?", you might ask, "Can't you just call an LM an LM?". Because I know nothing about JBoss LMs! In fact, I am neither a JBoss user, nor someone using JAAS in Java EE. Still, I felt like I could contribute an answer applying to the general case, hence the inevitable vagueness.
  • Deactivated user refers, for lack of a better term, to your "to-be-kicked-out-user", i.e., the user whose rights (groups, roles, permissions--whatever they are called in there) have been revoked in some way at the IS level.


First of all, there is no standard Java EE API that will expose the Subject or HttpSession of an arbitrary user to your code. You could theoretically record that information yourself, e.g. during authentication, but I will assume that this is not quite what you want. Furthermore, regarding the Subject specifically, while no standard explicitly forbids its (Principal / credential collection's) modification during servicing of a request on the Subject's behalf, none state that it has to be either. It is in fact not even clear whether the current authenticated caller's Subject--the one populated during authentication and retrievable via JACC's "javax.security.auth.Subject.container" PolicyContextHandler--must coincide with the data structure the runtime queries the Policy with when making authorization decisions; that is, the runtime might only provide you with a copy, use an entirely different representation of the authenticated caller internally, or anything in between. Therefore, even if you were able to modify the Subject, doing so would not necessarily affect the security context in effect.

Moving on to what can be done. Your need can be addressed either on the authentication and/or on the authorization side, with the former approach being considerably easier to employ than the later. Since you did not answer my comment, I will briefly cover both of its possible answers.

Prohibiting caller re-authentication

Once the application has deactivated the user, it must somehow instruct the AM to cease re-authenticating them on subsequent requests they issue. In order to reduce coupling, the application will typically not communicate with the AM directly, but satisfy some condition evaluated by the later instead. For instance, the application might assign some special "locked_out" right to the user, or set an HttpSession attribute. When asked to re-authenticate the deactivated user, the AM would acknowledge deactivation and refuse to re-authenticate them. Subsequently it would invalidate the user's session. How exactly it would accomplish that depends on its kind and implementation. Your LM would probably have to leverage the "javax.servlet.http.HttpServletRequest" JACC PolicyContextHandler for that purpose. A JASPIC ServerAuthModule would have immediate access to the request instance, having received it as a validateRequest argument. Some other component would perhaps have to resort to use of AS internals, or burden the application with the responsibility of session invalidation (some call-intercepting component, such as a Servlet Filter, would have to query the IS a second time and act accordingly).

The aforementioned approach obviously requires the ability to modify the functionality of the AM. Additionally, a caching AM needs to evaluate said deactivation condition before reusing its previously established authentication outcome. Lastly, as mentioned in the comment, if, at the time of a user's IS access revocation, a request on that user's behalf is in the process of being serviced (having arrived / having been authenticated prior to the occurrence of the access revocation event), servicing of that request will complete normally (unless the application requests re-authentication of that user, e.g. via HttpServletRequest#(login|authenticate).

Prohibiting caller re-authorization

While, as I mentioned in the begining, users' Subjects are not readily retrievable / modifiable, the backing Policy, against which, on JACC-compliant Java EE runtimes those get authorized, actually is. Unfortunately, the default AS-provided JACC provider (PolicyConfiguration + Policy) has a serious limitation: it only allows you to operate on Java EE roles, not on the caller Principals mapped to, i.e., "having", those roles. For example, the default provider allows you to extend the Permissions that Principals mapped to the "admin" role have; it allows you to remove the "admin" role along with all its Permissions; but it does not allow you to decide who gets to be an "admin"--at least not in a standard way.

This limitation basically leaves you with two alternatives, as far as JACC is concerned: Either have the AM add a "dummy" group Principal to each caller's Subject, with the same name as that of the respective caller Principal. Then, upon user deactivation, add (via PolicyConfiguration#addToRole) a custon Permission pertaining to the "dummy" group. Finally, check (e.g. via AccessController#checkPermission) from "application-space" code whether the user has the Permission and if so kick them out. But wait, this is utterly meaningless--why even bother using the Policy in the first place, if it is incapable of handling authorization on its own? The alternative is to author and install your own JACC provider. Doing so would give you full control over Principal-/group-to-role mappings and enable you to act pretty much however you please, authorization-wise, with that information from that point on. Writing a new provider is nontrivial though, particularly because it would have to accommodate for the authorization needs JRE-wide, not just in the scope of a single application. I doubt that your requirement justifies an amount of work that high. If you still feel like going down that path, the JACC-related articles on Arjan Tijms' blog are a great starting point.