001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.shiro.web.mgt; 020 021import org.apache.shiro.mgt.DefaultSecurityManager; 022import org.apache.shiro.mgt.DefaultSubjectDAO; 023import org.apache.shiro.mgt.SessionStorageEvaluator; 024import org.apache.shiro.mgt.SubjectDAO; 025import org.apache.shiro.realm.Realm; 026import org.apache.shiro.session.Session; 027import org.apache.shiro.session.mgt.SessionContext; 028import org.apache.shiro.session.mgt.SessionKey; 029import org.apache.shiro.session.mgt.SessionManager; 030import org.apache.shiro.subject.Subject; 031import org.apache.shiro.subject.SubjectContext; 032import org.apache.shiro.lang.util.LifecycleUtils; 033import org.apache.shiro.web.servlet.ShiroHttpServletRequest; 034import org.apache.shiro.web.session.mgt.DefaultWebSessionContext; 035import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; 036import org.apache.shiro.web.session.mgt.ServletContainerSessionManager; 037import org.apache.shiro.web.session.mgt.WebSessionKey; 038import org.apache.shiro.web.session.mgt.WebSessionManager; 039import org.apache.shiro.web.subject.WebSubject; 040import org.apache.shiro.web.subject.WebSubjectContext; 041import org.apache.shiro.web.subject.support.DefaultWebSubjectContext; 042import org.apache.shiro.web.subject.support.WebDelegatingSubject; 043import org.apache.shiro.web.util.WebUtils; 044import org.slf4j.Logger; 045import org.slf4j.LoggerFactory; 046 047import javax.servlet.ServletRequest; 048import javax.servlet.ServletResponse; 049import java.io.Serializable; 050import java.util.Collection; 051import java.util.function.Supplier; 052 053 054/** 055 * Default {@link WebSecurityManager WebSecurityManager} implementation used in web-based applications or any 056 * application that requires HTTP connectivity (SOAP, http remoting, etc.). 057 * 058 * @since 0.2 059 */ 060public class DefaultWebSecurityManager extends DefaultSecurityManager implements WebSecurityManager { 061 062 @SuppressWarnings("checkstyle:JavadocVariable") 063 @Deprecated 064 public static final String HTTP_SESSION_MODE = "http"; 065 @SuppressWarnings("checkstyle:JavadocVariable") 066 @Deprecated 067 public static final String NATIVE_SESSION_MODE = "native"; 068 069 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultWebSecurityManager.class); 070 071 /** 072 * @deprecated as of 1.2. This should NOT be used for anything other than determining if the sessionMode has changed. 073 */ 074 @Deprecated 075 private String sessionMode; 076 077 public DefaultWebSecurityManager() { 078 super(); 079 init(null); 080 } 081 082 public DefaultWebSecurityManager(Supplier<byte[]> keySupplier) { 083 super(); 084 init(keySupplier); 085 } 086 087 @SuppressWarnings({"UnusedDeclaration"}) 088 public DefaultWebSecurityManager(Realm singleRealm) { 089 this(); 090 setRealm(singleRealm); 091 } 092 093 @SuppressWarnings({"UnusedDeclaration"}) 094 public DefaultWebSecurityManager(Collection<Realm> realms) { 095 this(); 096 setRealms(realms); 097 } 098 099 @Override 100 protected SubjectContext createSubjectContext() { 101 return new DefaultWebSubjectContext(); 102 } 103 104 private void init(Supplier<byte[]> keySupplier) { 105 DefaultWebSessionStorageEvaluator webEvaluator = new DefaultWebSessionStorageEvaluator(); 106 ((DefaultSubjectDAO) this.subjectDAO).setSessionStorageEvaluator(webEvaluator); 107 this.sessionMode = HTTP_SESSION_MODE; 108 setSubjectFactory(new DefaultWebSubjectFactory()); 109 setRememberMeManager(keySupplier == null ? new CookieRememberMeManager() 110 : new CookieRememberMeManager(keySupplier)); 111 setSessionManager(new ServletContainerSessionManager()); 112 webEvaluator.setSessionManager(getSessionManager()); 113 } 114 115 @Override 116 //since 1.2.1 for fixing SHIRO-350 117 public void setSubjectDAO(SubjectDAO subjectDAO) { 118 super.setSubjectDAO(subjectDAO); 119 applySessionManagerToSessionStorageEvaluatorIfPossible(); 120 } 121 122 //since 1.2.1 for fixing SHIRO-350 123 @Override 124 protected void afterSessionManagerSet() { 125 super.afterSessionManagerSet(); 126 applySessionManagerToSessionStorageEvaluatorIfPossible(); 127 } 128 129 //since 1.2.1 for fixing SHIRO-350: 130 private void applySessionManagerToSessionStorageEvaluatorIfPossible() { 131 SubjectDAO subjectDAO = getSubjectDAO(); 132 if (subjectDAO instanceof DefaultSubjectDAO) { 133 SessionStorageEvaluator evaluator = ((DefaultSubjectDAO) subjectDAO).getSessionStorageEvaluator(); 134 if (evaluator instanceof DefaultWebSessionStorageEvaluator) { 135 ((DefaultWebSessionStorageEvaluator) evaluator).setSessionManager(getSessionManager()); 136 } 137 } 138 } 139 140 @Override 141 protected SubjectContext copy(SubjectContext subjectContext) { 142 if (subjectContext instanceof WebSubjectContext) { 143 return new DefaultWebSubjectContext((WebSubjectContext) subjectContext); 144 } 145 return super.copy(subjectContext); 146 } 147 148 @SuppressWarnings({"UnusedDeclaration"}) 149 @Deprecated 150 public String getSessionMode() { 151 return sessionMode; 152 } 153 154 /** 155 * @param sessionMode 156 * @deprecated since 1.2 157 */ 158 @Deprecated 159 public void setSessionMode(String sessionMode) { 160 LOGGER.warn("The 'sessionMode' property has been deprecated. Please configure an appropriate WebSessionManager " 161 + "instance instead of using this property. This property/method will be removed in a later version."); 162 String mode = sessionMode; 163 if (mode == null) { 164 throw new IllegalArgumentException("sessionMode argument cannot be null."); 165 } 166 mode = sessionMode.toLowerCase(); 167 if (!HTTP_SESSION_MODE.equals(mode) && !NATIVE_SESSION_MODE.equals(mode)) { 168 String msg = "Invalid sessionMode [" + sessionMode + "]. Allowed values are " 169 + "public static final String constants in the " + getClass().getName() + " class: '" 170 + HTTP_SESSION_MODE + "' or '" + NATIVE_SESSION_MODE + "', with '" 171 + HTTP_SESSION_MODE + "' being the default."; 172 throw new IllegalArgumentException(msg); 173 } 174 boolean recreate = this.sessionMode == null || !this.sessionMode.equals(mode); 175 this.sessionMode = mode; 176 if (recreate) { 177 LifecycleUtils.destroy(getSessionManager()); 178 SessionManager sessionManager = createSessionManager(mode); 179 this.setInternalSessionManager(sessionManager); 180 } 181 } 182 183 @Override 184 public void setSessionManager(SessionManager sessionManager) { 185 this.sessionMode = null; 186 if (sessionManager != null && !(sessionManager instanceof WebSessionManager)) { 187 if (LOGGER.isWarnEnabled()) { 188 String msg = "The " + getClass().getName() + " implementation expects SessionManager instances " 189 + "that implement the " + WebSessionManager.class.getName() + " interface. The " 190 + "configured instance is of type [" + sessionManager.getClass().getName() + "] which does not " 191 + "implement this interface.. This may cause unexpected behavior."; 192 LOGGER.warn(msg); 193 } 194 } 195 setInternalSessionManager(sessionManager); 196 } 197 198 /** 199 * @param sessionManager 200 * @since 1.2 201 */ 202 private void setInternalSessionManager(SessionManager sessionManager) { 203 super.setSessionManager(sessionManager); 204 } 205 206 /** 207 * @since 1.0 208 */ 209 public boolean isHttpSessionMode() { 210 SessionManager sessionManager = getSessionManager(); 211 return sessionManager instanceof WebSessionManager && ((WebSessionManager) sessionManager).isServletContainerSessions(); 212 } 213 214 protected SessionManager createSessionManager(String sessionMode) { 215 if (sessionMode == null || !sessionMode.equalsIgnoreCase(NATIVE_SESSION_MODE)) { 216 LOGGER.info("{} mode - enabling ServletContainerSessionManager (HTTP-only Sessions)", HTTP_SESSION_MODE); 217 return new ServletContainerSessionManager(); 218 } else { 219 LOGGER.info("{} mode - enabling DefaultWebSessionManager (non-HTTP and HTTP Sessions)", NATIVE_SESSION_MODE); 220 return new DefaultWebSessionManager(); 221 } 222 } 223 224 @Override 225 protected SessionContext createSessionContext(SubjectContext subjectContext) { 226 SessionContext sessionContext = super.createSessionContext(subjectContext); 227 if (subjectContext instanceof WebSubjectContext) { 228 WebSubjectContext wsc = (WebSubjectContext) subjectContext; 229 ServletRequest request = wsc.resolveServletRequest(); 230 ServletResponse response = wsc.resolveServletResponse(); 231 DefaultWebSessionContext webSessionContext = new DefaultWebSessionContext(sessionContext); 232 if (request != null) { 233 webSessionContext.setServletRequest(request); 234 } 235 if (response != null) { 236 webSessionContext.setServletResponse(response); 237 } 238 239 sessionContext = webSessionContext; 240 } 241 return sessionContext; 242 } 243 244 @Override 245 protected SessionKey getSessionKey(SubjectContext context) { 246 if (WebUtils.isWeb(context)) { 247 Serializable sessionId = context.getSessionId(); 248 ServletRequest request = WebUtils.getRequest(context); 249 ServletResponse response = WebUtils.getResponse(context); 250 return new WebSessionKey(sessionId, request, response); 251 } else { 252 return super.getSessionKey(context); 253 254 } 255 } 256 257 @Override 258 protected void beforeSuccessfulLogin(Subject subject) { 259 if (isHttpSessionMode()) { 260 Session session = subject.getSession(false); 261 if (session != null) { 262 WebUtils.toHttp(((WebDelegatingSubject) subject).getServletRequest()).changeSessionId(); 263 } 264 } else { 265 super.beforeSuccessfulLogin(subject); 266 } 267 } 268 269 @Override 270 protected void beforeLogout(Subject subject) { 271 super.beforeLogout(subject); 272 removeRequestIdentity(subject); 273 } 274 275 protected void removeRequestIdentity(Subject subject) { 276 if (subject instanceof WebSubject) { 277 WebSubject webSubject = (WebSubject) subject; 278 ServletRequest request = webSubject.getServletRequest(); 279 if (request != null) { 280 request.setAttribute(ShiroHttpServletRequest.IDENTITY_REMOVED_KEY, Boolean.TRUE); 281 } 282 } 283 } 284}