Coverage Report - org.apache.shiro.web.session.mgt.DefaultWebSessionManager
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultWebSessionManager
82%
108/131
74%
37/50
2.667
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.shiro.web.session.mgt;
 20  
 
 21  
 import org.apache.shiro.session.ExpiredSessionException;
 22  
 import org.apache.shiro.session.InvalidSessionException;
 23  
 import org.apache.shiro.session.Session;
 24  
 import org.apache.shiro.session.mgt.DefaultSessionManager;
 25  
 import org.apache.shiro.session.mgt.DelegatingSession;
 26  
 import org.apache.shiro.session.mgt.SessionContext;
 27  
 import org.apache.shiro.session.mgt.SessionKey;
 28  
 import org.apache.shiro.web.servlet.Cookie;
 29  
 import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
 30  
 import org.apache.shiro.web.servlet.ShiroHttpSession;
 31  
 import org.apache.shiro.web.servlet.SimpleCookie;
 32  
 import org.apache.shiro.web.util.WebUtils;
 33  
 import org.slf4j.Logger;
 34  
 import org.slf4j.LoggerFactory;
 35  
 
 36  
 import javax.servlet.ServletRequest;
 37  
 import javax.servlet.ServletResponse;
 38  
 import javax.servlet.http.HttpServletRequest;
 39  
 import javax.servlet.http.HttpServletResponse;
 40  
 import java.io.Serializable;
 41  
 
 42  
 
 43  
 /**
 44  
  * Web-application capable {@link org.apache.shiro.session.mgt.SessionManager SessionManager} implementation.
 45  
  *
 46  
  * @since 0.9
 47  
  */
 48  
 public class DefaultWebSessionManager extends DefaultSessionManager implements WebSessionManager {
 49  
 
 50  2
     private static final Logger log = LoggerFactory.getLogger(DefaultWebSessionManager.class);
 51  
 
 52  
     private Cookie sessionIdCookie;
 53  
     private boolean sessionIdCookieEnabled;
 54  
 
 55  36
     public DefaultWebSessionManager() {
 56  36
         Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
 57  36
         cookie.setHttpOnly(true); //more secure, protects against XSS attacks
 58  36
         this.sessionIdCookie = cookie;
 59  36
         this.sessionIdCookieEnabled = true;
 60  36
     }
 61  
 
 62  
     public Cookie getSessionIdCookie() {
 63  22
         return sessionIdCookie;
 64  
     }
 65  
 
 66  
     @SuppressWarnings({"UnusedDeclaration"})
 67  
     public void setSessionIdCookie(Cookie sessionIdCookie) {
 68  10
         this.sessionIdCookie = sessionIdCookie;
 69  10
     }
 70  
 
 71  
     public boolean isSessionIdCookieEnabled() {
 72  28
         return sessionIdCookieEnabled;
 73  
     }
 74  
 
 75  
     @SuppressWarnings({"UnusedDeclaration"})
 76  
     public void setSessionIdCookieEnabled(boolean sessionIdCookieEnabled) {
 77  8
         this.sessionIdCookieEnabled = sessionIdCookieEnabled;
 78  8
     }
 79  
 
 80  
     private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {
 81  8
         if (currentId == null) {
 82  0
             String msg = "sessionId cannot be null when persisting for subsequent requests.";
 83  0
             throw new IllegalArgumentException(msg);
 84  
         }
 85  8
         Cookie template = getSessionIdCookie();
 86  8
         Cookie cookie = new SimpleCookie(template);
 87  8
         String idString = currentId.toString();
 88  8
         cookie.setValue(idString);
 89  8
         cookie.saveTo(request, response);
 90  8
         log.trace("Set session ID cookie for session with id {}", idString);
 91  8
     }
 92  
 
 93  
     private void removeSessionIdCookie(HttpServletRequest request, HttpServletResponse response) {
 94  2
         getSessionIdCookie().removeFrom(request, response);
 95  2
     }
 96  
 
 97  
     private String getSessionIdCookieValue(ServletRequest request, ServletResponse response) {
 98  18
         if (!isSessionIdCookieEnabled()) {
 99  6
             log.debug("Session ID cookie is disabled - session id will not be acquired from a request cookie.");
 100  6
             return null;
 101  
         }
 102  12
         if (!(request instanceof HttpServletRequest)) {
 103  0
             log.debug("Current request is not an HttpServletRequest - cannot get session ID cookie.  Returning null.");
 104  0
             return null;
 105  
         }
 106  12
         HttpServletRequest httpRequest = (HttpServletRequest) request;
 107  12
         return getSessionIdCookie().readValue(httpRequest, WebUtils.toHttp(response));
 108  
     }
 109  
 
 110  
     private Serializable getReferencedSessionId(ServletRequest request, ServletResponse response) {
 111  
 
 112  18
         String id = getSessionIdCookieValue(request, response);
 113  18
         if (id != null) {
 114  4
             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
 115  
                     ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
 116  
         } else {
 117  
             //not in a cookie, or cookie is disabled - try the request URI as a fallback (i.e. due to URL rewriting):
 118  
 
 119  
             //try the URI path segment parameters first:
 120  14
             id = getUriPathSegmentParamValue(request, ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
 121  
 
 122  14
             if (id == null) {
 123  
                 //not a URI path segment parameter, try the query parameters:
 124  12
                 String name = getSessionIdName();
 125  12
                 id = request.getParameter(name);
 126  12
                 if (id == null) {
 127  
                     //try lowercase:
 128  10
                     id = request.getParameter(name.toLowerCase());
 129  
                 }
 130  
             }
 131  14
             if (id != null) {
 132  6
                 request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
 133  
                         ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);
 134  
             }
 135  
         }
 136  18
         if (id != null) {
 137  10
             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
 138  
             //automatically mark it valid here.  If it is invalid, the
 139  
             //onUnknownSession method below will be invoked and we'll remove the attribute at that time.
 140  10
             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
 141  
         }
 142  18
         return id;
 143  
     }
 144  
 
 145  
     //SHIRO-351
 146  
     //also see http://cdivilly.wordpress.com/2011/04/22/java-servlets-uri-parameters/
 147  
     //since 1.2.2
 148  
     private String getUriPathSegmentParamValue(ServletRequest servletRequest, String paramName) {
 149  
 
 150  24
         if (!(servletRequest instanceof HttpServletRequest)) {
 151  2
             return null;
 152  
         }
 153  22
         HttpServletRequest request = (HttpServletRequest)servletRequest;
 154  22
         String uri = request.getRequestURI();
 155  22
         if (uri == null) {
 156  10
             return null;
 157  
         }
 158  
 
 159  12
         int queryStartIndex = uri.indexOf('?');
 160  12
         if (queryStartIndex >= 0) { //get rid of the query string
 161  8
             uri = uri.substring(0, queryStartIndex);
 162  
         }
 163  
 
 164  12
         int index = uri.indexOf(';'); //now check for path segment parameters:
 165  12
         if (index < 0) {
 166  
             //no path segment params - return:
 167  6
             return null;
 168  
         }
 169  
 
 170  
         //there are path segment params, let's get the last one that may exist:
 171  
 
 172  6
         final String TOKEN = paramName + "=";
 173  
 
 174  6
         uri = uri.substring(index+1); //uri now contains only the path segment params
 175  
 
 176  
         //we only care about the last JSESSIONID param:
 177  6
         index = uri.lastIndexOf(TOKEN);
 178  6
         if (index < 0) {
 179  
             //no segment param:
 180  2
             return null;
 181  
         }
 182  
 
 183  4
         uri = uri.substring(index + TOKEN.length());
 184  
 
 185  4
         index = uri.indexOf(';'); //strip off any remaining segment params:
 186  4
         if(index >= 0) {
 187  4
             uri = uri.substring(0, index);
 188  
         }
 189  
 
 190  4
         return uri; //what remains is the value
 191  
     }
 192  
 
 193  
     //since 1.2.1
 194  
     private String getSessionIdName() {
 195  12
         String name = this.sessionIdCookie != null ? this.sessionIdCookie.getName() : null;
 196  12
         if (name == null) {
 197  0
             name = ShiroHttpSession.DEFAULT_SESSION_ID_NAME;
 198  
         }
 199  12
         return name;
 200  
     }
 201  
 
 202  
     protected Session createExposedSession(Session session, SessionContext context) {
 203  6
         if (!WebUtils.isWeb(context)) {
 204  0
             return super.createExposedSession(session, context);
 205  
         }
 206  6
         ServletRequest request = WebUtils.getRequest(context);
 207  6
         ServletResponse response = WebUtils.getResponse(context);
 208  6
         SessionKey key = new WebSessionKey(session.getId(), request, response);
 209  6
         return new DelegatingSession(this, key);
 210  
     }
 211  
 
 212  
     protected Session createExposedSession(Session session, SessionKey key) {
 213  2
         if (!WebUtils.isWeb(key)) {
 214  0
             return super.createExposedSession(session, key);
 215  
         }
 216  
 
 217  2
         ServletRequest request = WebUtils.getRequest(key);
 218  2
         ServletResponse response = WebUtils.getResponse(key);
 219  2
         SessionKey sessionKey = new WebSessionKey(session.getId(), request, response);
 220  2
         return new DelegatingSession(this, sessionKey);
 221  
     }
 222  
 
 223  
     /**
 224  
      * Stores the Session's ID, usually as a Cookie, to associate with future requests.
 225  
      *
 226  
      * @param session the session that was just {@link #createSession created}.
 227  
      */
 228  
     @Override
 229  
     protected void onStart(Session session, SessionContext context) {
 230  10
         super.onStart(session, context);
 231  
 
 232  10
         if (!WebUtils.isHttp(context)) {
 233  0
             log.debug("SessionContext argument is not HTTP compatible or does not have an HTTP request/response " +
 234  
                     "pair. No session ID cookie will be set.");
 235  0
             return;
 236  
 
 237  
         }
 238  10
         HttpServletRequest request = WebUtils.getHttpRequest(context);
 239  10
         HttpServletResponse response = WebUtils.getHttpResponse(context);
 240  
 
 241  10
         if (isSessionIdCookieEnabled()) {
 242  8
             Serializable sessionId = session.getId();
 243  8
             storeSessionId(sessionId, request, response);
 244  8
         } else {
 245  2
             log.debug("Session ID cookie is disabled.  No cookie has been set for new session with id {}", session.getId());
 246  
         }
 247  
 
 248  10
         request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);
 249  10
         request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
 250  10
     }
 251  
 
 252  
     @Override
 253  
     public Serializable getSessionId(SessionKey key) {
 254  44
         Serializable id = super.getSessionId(key);
 255  44
         if (id == null && WebUtils.isWeb(key)) {
 256  10
             ServletRequest request = WebUtils.getRequest(key);
 257  10
             ServletResponse response = WebUtils.getResponse(key);
 258  10
             id = getSessionId(request, response);
 259  
         }
 260  44
         return id;
 261  
     }
 262  
 
 263  
     protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
 264  18
         return getReferencedSessionId(request, response);
 265  
     }
 266  
 
 267  
     @Override
 268  
     protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
 269  2
         super.onExpiration(s, ese, key);
 270  2
         onInvalidation(key);
 271  2
     }
 272  
 
 273  
     @Override
 274  
     protected void onInvalidation(Session session, InvalidSessionException ise, SessionKey key) {
 275  0
         super.onInvalidation(session, ise, key);
 276  0
         onInvalidation(key);
 277  0
     }
 278  
 
 279  
     private void onInvalidation(SessionKey key) {
 280  2
         ServletRequest request = WebUtils.getRequest(key);
 281  2
         if (request != null) {
 282  2
             request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID);
 283  
         }
 284  2
         if (WebUtils.isHttp(key)) {
 285  2
             log.debug("Referenced session was invalid.  Removing session ID cookie.");
 286  2
             removeSessionIdCookie(WebUtils.getHttpRequest(key), WebUtils.getHttpResponse(key));
 287  
         } else {
 288  0
             log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response " +
 289  
                     "pair. Session ID cookie will not be removed due to invalidated session.");
 290  
         }
 291  2
     }
 292  
 
 293  
     @Override
 294  
     protected void onStop(Session session, SessionKey key) {
 295  0
         super.onStop(session, key);
 296  0
         if (WebUtils.isHttp(key)) {
 297  0
             HttpServletRequest request = WebUtils.getHttpRequest(key);
 298  0
             HttpServletResponse response = WebUtils.getHttpResponse(key);
 299  0
             log.debug("Session has been stopped (subject logout or explicit stop).  Removing session ID cookie.");
 300  0
             removeSessionIdCookie(request, response);
 301  0
         } else {
 302  0
             log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response " +
 303  
                     "pair. Session ID cookie will not be removed due to stopped session.");
 304  
         }
 305  0
     }
 306  
 
 307  
     /**
 308  
      * This is a native session manager implementation, so this method returns {@code false} always.
 309  
      *
 310  
      * @return {@code false} always
 311  
      * @since 1.2
 312  
      */
 313  
     public boolean isServletContainerSessions() {
 314  0
         return false;
 315  
     }
 316  
 }