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