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  1
     private static final Logger log = LoggerFactory.getLogger(DefaultWebSessionManager.class);
 51  
 
 52  
     private Cookie sessionIdCookie;
 53  
     private boolean sessionIdCookieEnabled;
 54  
 
 55  18
     public DefaultWebSessionManager() {
 56  18
         Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
 57  18
         cookie.setHttpOnly(true); //more secure, protects against XSS attacks
 58  18
         this.sessionIdCookie = cookie;
 59  18
         this.sessionIdCookieEnabled = true;
 60  18
     }
 61  
 
 62  
     public Cookie getSessionIdCookie() {
 63  11
         return sessionIdCookie;
 64  
     }
 65  
 
 66  
     @SuppressWarnings({"UnusedDeclaration"})
 67  
     public void setSessionIdCookie(Cookie sessionIdCookie) {
 68  5
         this.sessionIdCookie = sessionIdCookie;
 69  5
     }
 70  
 
 71  
     public boolean isSessionIdCookieEnabled() {
 72  14
         return sessionIdCookieEnabled;
 73  
     }
 74  
 
 75  
     @SuppressWarnings({"UnusedDeclaration"})
 76  
     public void setSessionIdCookieEnabled(boolean sessionIdCookieEnabled) {
 77  4
         this.sessionIdCookieEnabled = sessionIdCookieEnabled;
 78  4
     }
 79  
 
 80  
     private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {
 81  4
         if (currentId == null) {
 82  0
             String msg = "sessionId cannot be null when persisting for subsequent requests.";
 83  0
             throw new IllegalArgumentException(msg);
 84  
         }
 85  4
         Cookie template = getSessionIdCookie();
 86  4
         Cookie cookie = new SimpleCookie(template);
 87  4
         String idString = currentId.toString();
 88  4
         cookie.setValue(idString);
 89  4
         cookie.saveTo(request, response);
 90  4
         log.trace("Set session ID cookie for session with id {}", idString);
 91  4
     }
 92  
 
 93  
     private void removeSessionIdCookie(HttpServletRequest request, HttpServletResponse response) {
 94  1
         getSessionIdCookie().removeFrom(request, response);
 95  1
     }
 96  
 
 97  
     private String getSessionIdCookieValue(ServletRequest request, ServletResponse response) {
 98  9
         if (!isSessionIdCookieEnabled()) {
 99  3
             log.debug("Session ID cookie is disabled - session id will not be acquired from a request cookie.");
 100  3
             return null;
 101  
         }
 102  6
         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  6
         HttpServletRequest httpRequest = (HttpServletRequest) request;
 107  6
         return getSessionIdCookie().readValue(httpRequest, WebUtils.toHttp(response));
 108  
     }
 109  
 
 110  
     private Serializable getReferencedSessionId(ServletRequest request, ServletResponse response) {
 111  
 
 112  9
         String id = getSessionIdCookieValue(request, response);
 113  9
         if (id != null) {
 114  2
             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  7
             id = getUriPathSegmentParamValue(request, ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
 121  
 
 122  7
             if (id == null) {
 123  
                 //not a URI path segment parameter, try the query parameters:
 124  6
                 String name = getSessionIdName();
 125  6
                 id = request.getParameter(name);
 126  6
                 if (id == null) {
 127  
                     //try lowercase:
 128  5
                     id = request.getParameter(name.toLowerCase());
 129  
                 }
 130  
             }
 131  7
             if (id != null) {
 132  3
                 request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
 133  
                         ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);
 134  
             }
 135  
         }
 136  9
         if (id != null) {
 137  5
             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  5
             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
 141  
         }
 142  9
         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  12
         if (!(servletRequest instanceof HttpServletRequest)) {
 151  1
             return null;
 152  
         }
 153  11
         HttpServletRequest request = (HttpServletRequest)servletRequest;
 154  11
         String uri = request.getRequestURI();
 155  11
         if (uri == null) {
 156  5
             return null;
 157  
         }
 158  
 
 159  6
         int queryStartIndex = uri.indexOf('?');
 160  6
         if (queryStartIndex >= 0) { //get rid of the query string
 161  4
             uri = uri.substring(0, queryStartIndex);
 162  
         }
 163  
 
 164  6
         int index = uri.indexOf(';'); //now check for path segment parameters:
 165  6
         if (index < 0) {
 166  
             //no path segment params - return:
 167  3
             return null;
 168  
         }
 169  
 
 170  
         //there are path segment params, let's get the last one that may exist:
 171  
 
 172  3
         final String TOKEN = paramName + "=";
 173  
 
 174  3
         uri = uri.substring(index+1); //uri now contains only the path segment params
 175  
 
 176  
         //we only care about the last JSESSIONID param:
 177  3
         index = uri.lastIndexOf(TOKEN);
 178  3
         if (index < 0) {
 179  
             //no segment param:
 180  1
             return null;
 181  
         }
 182  
 
 183  2
         uri = uri.substring(index + TOKEN.length());
 184  
 
 185  2
         index = uri.indexOf(';'); //strip off any remaining segment params:
 186  2
         if(index >= 0) {
 187  2
             uri = uri.substring(0, index);
 188  
         }
 189  
 
 190  2
         return uri; //what remains is the value
 191  
     }
 192  
 
 193  
     //since 1.2.1
 194  
     private String getSessionIdName() {
 195  6
         String name = this.sessionIdCookie != null ? this.sessionIdCookie.getName() : null;
 196  6
         if (name == null) {
 197  0
             name = ShiroHttpSession.DEFAULT_SESSION_ID_NAME;
 198  
         }
 199  6
         return name;
 200  
     }
 201  
 
 202  
     protected Session createExposedSession(Session session, SessionContext context) {
 203  3
         if (!WebUtils.isWeb(context)) {
 204  0
             return super.createExposedSession(session, context);
 205  
         }
 206  3
         ServletRequest request = WebUtils.getRequest(context);
 207  3
         ServletResponse response = WebUtils.getResponse(context);
 208  3
         SessionKey key = new WebSessionKey(session.getId(), request, response);
 209  3
         return new DelegatingSession(this, key);
 210  
     }
 211  
 
 212  
     protected Session createExposedSession(Session session, SessionKey key) {
 213  1
         if (!WebUtils.isWeb(key)) {
 214  0
             return super.createExposedSession(session, key);
 215  
         }
 216  
 
 217  1
         ServletRequest request = WebUtils.getRequest(key);
 218  1
         ServletResponse response = WebUtils.getResponse(key);
 219  1
         SessionKey sessionKey = new WebSessionKey(session.getId(), request, response);
 220  1
         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  5
         super.onStart(session, context);
 231  
 
 232  5
         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  5
         HttpServletRequest request = WebUtils.getHttpRequest(context);
 239  5
         HttpServletResponse response = WebUtils.getHttpResponse(context);
 240  
 
 241  5
         if (isSessionIdCookieEnabled()) {
 242  4
             Serializable sessionId = session.getId();
 243  4
             storeSessionId(sessionId, request, response);
 244  4
         } else {
 245  1
             log.debug("Session ID cookie is disabled.  No cookie has been set for new session with id {}", session.getId());
 246  
         }
 247  
 
 248  5
         request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);
 249  5
         request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
 250  5
     }
 251  
 
 252  
     @Override
 253  
     public Serializable getSessionId(SessionKey key) {
 254  22
         Serializable id = super.getSessionId(key);
 255  22
         if (id == null && WebUtils.isWeb(key)) {
 256  5
             ServletRequest request = WebUtils.getRequest(key);
 257  5
             ServletResponse response = WebUtils.getResponse(key);
 258  5
             id = getSessionId(request, response);
 259  
         }
 260  22
         return id;
 261  
     }
 262  
 
 263  
     protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
 264  9
         return getReferencedSessionId(request, response);
 265  
     }
 266  
 
 267  
     @Override
 268  
     protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
 269  1
         super.onExpiration(s, ese, key);
 270  1
         onInvalidation(key);
 271  1
     }
 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  1
         ServletRequest request = WebUtils.getRequest(key);
 281  1
         if (request != null) {
 282  1
             request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID);
 283  
         }
 284  1
         if (WebUtils.isHttp(key)) {
 285  1
             log.debug("Referenced session was invalid.  Removing session ID cookie.");
 286  1
             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  1
     }
 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  
 }