0

Is there any way, with springSecurityService, to log someone else out?

(For example, if a regular user leaves for the day and forgets to logout, and the manager wants to log their account out.)

Charles Wood
  • 864
  • 8
  • 23

3 Answers3

1

I have done in my application where , A admin User can logged-out forcefully any user from the list of all users currently logged-in into the system.

  1. I get all users those are currently logged-in into the system and send to the jsp where list of all logged-in users are shown to the Admin user.

    @PreAuthorize("hasRole('Currently_Logged-In_Users')")
     @RequestMapping(value = "/getLoggedInUsers", method = RequestMethod.POST)
     @ResponseBody
     public Map<String, List<?>> getLoggedInUsers(Map<String, Object> map ,Model model) {
      Authentication auth = SecurityContextHolder.getContext().getAuthentication();
           String userName = auth.getName(); 
          
     List<Object> principals = sessionRegistry.getAllPrincipals();
    
     List<UserInfo> usersInfoList = new ArrayList<UserInfo>();
    
     for (Object principal: principals) {
         if (principal instanceof UserInfo) {
          if(!((UserInfo) principal).getUsername().equals(userName)){
          for(SessionInformation sess :sessionRegistry.getAllSessions(principal, false)){
           if(!sess.isExpired()){
            usersInfoList.add((UserInfo) sess.getPrincipal());
           }
          }
          
          }
         }
     }
     
     Map<String, List<?>> loggedInUserMap = new HashMap<String, List<?>>();
    
     loggedInUserMap.put("loggenInUsers",
       usersInfoList);
    
    
     return loggedInUserMap;
     
     }
  2. Now Admin user can select any user or multiple user by clicking on check box against the users. and call forced Logged-out action.

    @PreAuthorize("hasRole('Currently_Logged-In_Users')")
     @RequestMapping(value = "/logoutSelectedUsers", method = RequestMethod.POST)
     @ResponseBody
     public Map<String, String> forcedLoggedOut(@RequestParam("userList[]")ArrayList<String> userList ,Model model ,HttpServletRequest request ) {
      
      Map<String,String> map= new HashMap<String,String>();
      try{
       
      String successMessage =null;
      List<String> userCodeList = new ArrayList<String>();
      
      for(String userCode :userList ){
       userCodeList.add(userCode);
      }
       
      List<Object> principals = sessionRegistry.getAllPrincipals();
      for (Object principal: principals) {
          if (principal instanceof UserInfo) {
           if(userCodeList.contains(((UserInfo) principal).getUsername())){
            for(SessionInformation sess :sessionRegistry.getAllSessions(principal, false)){
             sess.expireNow();
             successMessage = "msg.loggedOutSuccessfully";
             
            }
           }
          }
      }
      
     
      map.put("successmsg", successMessage);
      }
      catch(Exception e){
       map.put("failmsg", "msg.notLoggedOut");
       logger.error(e.toString(),e); 
       }
      return map;
      
     }
Sunil Khokhar
  • 370
  • 1
  • 5
0

The springSecurityService itself does not have this capability.

However, nothing is stopping you from creating your own ServletFilter to track session ids and security principals and expose a controller and pages to invalidate the associated session with a login.

Joshua Moore
  • 24,706
  • 6
  • 50
  • 73
  • Hmm. So I understand that I can use the built-in `session` object to obtain each user's session ID as they log in, but what class or object do I use to invalidate an arbitrary session by ID? – Charles Wood Sep 24 '14 at 13:35
  • 1
    This previous SO question and answer will help you understand what I mean by creating your won ServletFilter or SessionListener to track sessions and then target them to invalidate them. http://stackoverflow.com/questions/1499581/how-can-i-manually-load-a-java-session-using-a-jsessionid – Joshua Moore Sep 24 '14 at 15:33
0

Here's how I do it.

Edit: The example below uses the webxml plugin. You can also edit web.xml directly. See this answer for setting the timeout.

// src/groovy/com/example/ExpiringSessionEventListener.groovy:
package com.example

import grails.util.Holders
import javax.servlet.http.HttpSessionListener
import javax.servlet.http.HttpSessionEvent
import org.springframework.security.core.context.SecurityContext

public class ExpiringSessionEventListener implements  HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent event) {
        // Do some logging
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        SecurityContext securityContext = event.session.getAttribute("SPRING_SECURITY_CONTEXT")
        if (securityContext) {
            UserService userService = Holders.applicationContext.getBean("userService")
            String userName = securityContext.authentication.principal.username
            userService.userLoggedOut(userName, event.session.id, Boolean.TRUE)
        }
    }
}


//  grails-app/services/com/example/UserService.groovy:
package com.example

import grails.plugin.springsecurity.annotation.Secured

class UserService {

    @Secured(["ROLE_USER"])
    def userLoggedOut(String userName, String sessionId, Boolean expired) {
        User user = User.findByUsername(userName)
        if (expired) {
            // Do user cleanup stuff after expired session
        } else {
            // Do user cleanup stuff after clicking the logout button
        }
    }
}

Edit:

// grails-app/conf/WebXmlConfig.groovy:
webxml {
    sessionConfig.sessionTimeout = 10 // minutes
    listener.add = true
    listener.classNames = [
        "com.example.ExpiringSessionEventListener"
    ]
}
Community
  • 1
  • 1
Ken
  • 685
  • 2
  • 5
  • 11
  • When does `sessionDestroyed` get called? Is it something that I could just call to log an arbitrary user out? – Charles Wood Sep 24 '14 at 13:34
  • I'd left out a key piece of the puzzle. See my edits about ```web.xml``` and ```grails-app/conf/WebXmlConfig.groovy```. The ```sessionDestroyed``` method is called when the container times out the session, 10 minutes in my case. – Ken Sep 24 '14 at 13:56
  • I missed your second question. What do you mean by arbitrary user? – Ken Sep 24 '14 at 14:08
  • Neat! Well, my goal is for a manager to e.g. click a button in order to log out any other user. So, not quite the same as what we're looking at here. This isn't a bad idea, though. – Charles Wood Sep 24 '14 at 14:18
  • Using the approach above avoids a situation where an admin logs out an active user. However, you can use the bits in the service and listener methods and tie those to a GUI where the manager chooses a user and clicks a logout button. You might want to check out the [spring-security-ui plugin](http://grails.org/plugin/spring-security-ui) although I don't think it offers an arbitrary logout function. – Ken Sep 24 '14 at 15:48