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