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