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
Note on terminology:
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.First of all, there is no standard Java EE API that will expose the
Subject
orHttpSession
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 theSubject
specifically, while no standard explicitly forbids its (Principal
/ credential collection's) modification during servicing of a request on theSubject
's behalf, none state that it has to be either. It is in fact not even clear whether the current authenticated caller'sSubject
--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 thePolicy
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 theSubject
, 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"
JACCPolicyContextHandler
for that purpose. A JASPICServerAuthModule
would have immediate access to the request instance, having received it as avalidateRequest
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 ServletFilter
, 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'
Subject
s are not readily retrievable / modifiable, the backingPolicy
, 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 callerPrincipal
s mapped to, i.e., "having", those roles. For example, the default provider allows you to extend thePermission
s thatPrincipal
s mapped to the "admin" role have; it allows you to remove the "admin" role along with all itsPermission
s; 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'sSubject
, with the same name as that of the respective callerPrincipal
. Then, upon user deactivation, add (viaPolicyConfiguration#addToRole
) a custonPermission
pertaining to the "dummy" group. Finally, check (e.g. via AccessController#checkPermission) from "application-space" code whether the user has thePermission
and if so kick them out. But wait, this is utterly meaningless--why even bother using thePolicy
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 overPrincipal
-/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.