0

In my web app I am trying to achieve the functionality, that an admin is able to logout other currently logged in users.

What I have done so far:

  • I created a POJO to store significant user information, including a referrence to the users HTTP session.
  • This POJO is implementing HttpSessionBindingListener
  • During the login process I put an instance of this POJO into the SessionMap. Via the valueBound method I am putting into a static Map, which stores all such logged-in-userinformation (on the unbound-Event I am removing it again
  • In a seperated admin section I am now able to access the HttpSession of a specific user and invalidate it
  • the logged-out user gets informed via websocket that he has been logged-out

Invalidating the HttpSession works fine and the mentioned unbound method is called. However, the problem is that if a in that way logged out user is still able to do AJAX requests. A new instance of hte ViewScoped Bean is created and assigned to the client and the request goes against this new instance.

What I would expect (or what I would like to achieve) is that sth like a ViewExpiredException is thrown instead and redirecting the user to the login page instead.
Or am I missing an important part in my concept?

Would it be enough to set up proper security-constraints in web.xml or would it just hide the conceptual problem?

(If it's important, the Bean is not a JSF Bean but a CDI ViewScoped bean.)

Application is running on Glassfish 4.1,, Mojarra 2.2.12


SessionBindingListener:

@RequiredArgsConstructor
@EqualsAndHashCode(of = {"user"})
public class UserSessionInfo implements HttpSessionBindingListener {

    @Getter private static final Map<UserSessionInfo, UserSessionInfo> sessions 
         = new HashMap<>(10);

    @Getter private final String user;
    @Getter private HttpSession session;

    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        UserSessionInfo usi = sessions.remove(this);
        if (usi != null) {
            HttpSession hs = usi.session;
            if (hs != null) {
                hs.invalidate();
            }
        }
        this.session = event.getSession();
        sessions.put(this, this);
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        sessions.remove(this);
    }

}

Login-method

public String login() {
        FacesContext context = FacesContext.getCurrentInstance();        
        HttpServletRequest request = 
           (HttpServletRequest) context.getExternalContext().getRequest();
        try {
            request.login(username, password);
            context
                .getExternalContext()
                .getSessionMap().put(username, new UserSessionInfo(/* ...*/)));
            // ..
        } 
        // ....
        return "/index?faces-redirect=true";
    }

Admin-Method for logging out some other user:

public void logoff(UserSessionInfo usr) {
    EventBus eventBus = EventBusFactory.getDefault().eventBus();        
    eventBus.publish(CHANNEL, new DialogMessage(/*...*/));        
    usr.getSession().invalidate();           
}
stg
  • 2,757
  • 2
  • 28
  • 55

1 Answers1

0

If the session of your user is really invalidated, all requests should fail, ajax or not.

In one of my app, I have :

  • security restrictions, through roles in web.xml
  • session tracking with a HttpSessionListener and a Filter (the filter is the way I detect new sessions created by tomcat on login, to avoid session fixation)
  • the possibility to "kill" another session, using session.invalidate

If a session is recreated "in your back", it must be because you have an unrestricted area being access. Require auth for all your all, with a rule such as :

<security-constraint>
    <display-name>Authenticated users</display-name>
    <web-resource-collection>
        <web-resource-name>Authenticated users</web-resource-name>
        <url-pattern>/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
        <role-name>*</role-name>
    </auth-constraint>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

in web.xml, and it should be ok.

Ludovic Pénet
  • 1,136
  • 1
  • 16
  • 32