001/**
002 * Copyright 2014 Tampere University of Technology, Pori Department
003 * 
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * 
008 *   http://www.apache.org/licenses/LICENSE-2.0
009 * 
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package core.tut.pori.context;
017
018import org.apache.log4j.Logger;
019import org.springframework.security.core.session.SessionInformation;
020import org.springframework.security.core.session.SessionRegistry;
021
022import core.tut.pori.users.UserIdentity;
023
024/**
025 * Accessible interface to active Sessions within the web application (service) context.
026 * 
027 * This class can be used to register new sessions and retrieve information for a particular session. 
028 * The session information is provided for all services, though the session management is generally handled internally and modifying the active sessions may cause undefined behavior.
029 * 
030 * One should not initialize this handler directly, as an instantiated version is available from ServiceInitializer.
031 */
032public class SessionHandler {
033  private static final Logger LOGGER = Logger.getLogger(SessionHandler.class);
034  private static SessionHandler _handler = new SessionHandler();
035  private SessionHandlerPrivate _handlerPrivate = null;
036
037  /**
038   * 
039   * @param handler
040   */
041  private static synchronized void setHandler(SessionHandlerPrivate handler){
042    if(handler == null){
043      LOGGER.debug("Removing handler...");
044    }else if(_handler._handlerPrivate != null){
045      LOGGER.warn("Replacing previous handler...");
046    }
047    _handler.setHandlerPrivate(handler);
048  }
049
050  /**
051   * 
052   * @return the session handler
053   */
054  public static SessionHandler getSessionHandler(){
055    return _handler;
056  }
057
058  /**
059   * 
060   */
061  private SessionHandler(){
062    // nothing needed
063  }
064
065  /**
066   * @param sessionId
067   * @return session information
068   * @see org.springframework.security.core.session.SessionRegistry#getSessionInformation(java.lang.String)
069   */
070  public SessionInformation getSessionInformation(String sessionId) {
071    if(_handlerPrivate == null){
072      LOGGER.debug("Session registry not available.");
073      return null;
074    }else{
075      LOGGER.debug("Retrieving session information for sessionId: "+sessionId);
076      return _handlerPrivate.getSessionRegistry().getSessionInformation(sessionId); // in principle we should synchronize and check if registry is available, but in practice it will never NOT be available
077    }
078  }
079
080  /**
081   * @param sessionId
082   * @param userId
083   * @see org.springframework.security.core.session.SessionRegistry#registerNewSession(java.lang.String, java.lang.Object)
084   * @throws IllegalStateException if registry is not available
085   */
086  public void registerNewSession(String sessionId, UserIdentity userId) throws IllegalStateException{
087    if(_handlerPrivate == null){
088      throw new IllegalStateException("Session registry not available.");
089    }
090    LOGGER.debug("Registering new session for sessionId: "+sessionId+", userId: "+userId.getUserId());
091    _handlerPrivate.getSessionRegistry().registerNewSession(sessionId, userId); // in principle we should synchronize and check if registry is available, but in practice it will never NOT be available
092  }
093
094  /**
095   * This is essentially the same as calling LoginHandler.authentice() and registerNewSession()
096   * 
097   * @param sessionId
098   * @param userId
099   * @throws IllegalStateException
100   */
101  public void registerAndAuthenticate(String sessionId, UserIdentity userId) throws IllegalStateException{
102    LoginHandler.authenticate(userId);
103    registerNewSession(sessionId, userId);
104  }
105
106  /**
107   * @param sessionId
108   * @see org.springframework.security.core.session.SessionRegistry#removeSessionInformation(java.lang.String)
109   */
110  public void removeSessionInformation(String sessionId) {
111    if(_handlerPrivate == null){
112      LOGGER.debug("Session registry not available.");
113    }else{
114      LOGGER.debug("Removing session information for sessionId: "+sessionId);
115      _handlerPrivate.getSessionRegistry().removeSessionInformation(sessionId); // in principle we should synchronize and check if registry is available, but in practice it will never NOT be available
116    }
117  }
118
119  /**
120   * Note: this is NOT synchronized, which means that it may be possible for the user to re-login whilst the operation is in progress, if this is called for user account removal,
121   * remember to FIRST remove the account to make sure user cannot re-login
122   * 
123   * @param userId
124   */
125  public void removeSessionInformation(UserIdentity userId){
126    if(_handlerPrivate == null){ // in principle we should synchronize and check if registry is available, but in practice it will never NOT be available
127      LOGGER.debug("Session registry not available.");
128    }else{
129      LOGGER.debug("Removing session information for userId: "+userId.getUserId());
130      SessionRegistry registry = _handlerPrivate.getSessionRegistry();
131      for(Object principal : registry.getAllPrincipals()){ // check all principals, note that simply asking for all sessions for the given userId object (principal) may not work as there might be slight differences between the passed object and the one known by the system, which may fool the equals check
132        if(principal.getClass() != UserIdentity.class){
133          continue;
134        }
135        UserIdentity pIdentity = (UserIdentity) principal;
136        if(UserIdentity.equals(userId, (UserIdentity) principal)){
137          for(SessionInformation sessionInformation : registry.getAllSessions(pIdentity, true)){
138            _handlerPrivate.getSessionRegistry().removeSessionInformation(sessionInformation.getSessionId());
139          } // for session information
140        } // if equals
141      } // for
142    } // else
143  }
144
145  /**
146   * @param handlerPrivate the handlerPrivate to set
147   */
148  private void setHandlerPrivate(SessionHandlerPrivate handlerPrivate) {
149    _handlerPrivate = handlerPrivate;
150  }
151
152  /**
153   * Private instance of session handler.
154   * 
155   * Created as a bean.
156   */
157  private static class SessionHandlerPrivate{
158    private SessionRegistry _sessionRegistry = null;
159
160    /**
161     * 
162     * @param sessionRegistry
163     */
164    @SuppressWarnings("unused")
165    public SessionHandlerPrivate(SessionRegistry sessionRegistry){
166      _sessionRegistry = sessionRegistry;
167    }
168
169    /**
170     * Called by bean initialization
171     */
172    @SuppressWarnings("unused")
173    public void initialized(){
174      LOGGER.debug("Initialized.");
175      setHandler(this);
176    }
177
178    /**
179     * Called when bean is destroyed
180     */
181    @SuppressWarnings("unused")
182    public void destroyed(){
183      LOGGER.debug("Destroyed.");
184      setHandler(null);
185    }
186
187    /**
188     * @return the sessionRegistry
189     */
190    public SessionRegistry getSessionRegistry() {
191      return _sessionRegistry;
192    }
193  } // class SessionHandlerPrivate
194}