View Javadoc
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.mgt;
20  
21  import org.apache.shiro.mgt.DefaultSecurityManager;
22  import org.apache.shiro.mgt.DefaultSubjectDAO;
23  import org.apache.shiro.mgt.SessionStorageEvaluator;
24  import org.apache.shiro.mgt.SubjectDAO;
25  import org.apache.shiro.realm.Realm;
26  import org.apache.shiro.session.mgt.SessionContext;
27  import org.apache.shiro.session.mgt.SessionKey;
28  import org.apache.shiro.session.mgt.SessionManager;
29  import org.apache.shiro.subject.Subject;
30  import org.apache.shiro.subject.SubjectContext;
31  import org.apache.shiro.lang.util.LifecycleUtils;
32  import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
33  import org.apache.shiro.web.session.mgt.DefaultWebSessionContext;
34  import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
35  import org.apache.shiro.web.session.mgt.ServletContainerSessionManager;
36  import org.apache.shiro.web.session.mgt.WebSessionKey;
37  import org.apache.shiro.web.session.mgt.WebSessionManager;
38  import org.apache.shiro.web.subject.WebSubject;
39  import org.apache.shiro.web.subject.WebSubjectContext;
40  import org.apache.shiro.web.subject.support.DefaultWebSubjectContext;
41  import org.apache.shiro.web.util.WebUtils;
42  import org.slf4j.Logger;
43  import org.slf4j.LoggerFactory;
44  
45  import javax.servlet.ServletRequest;
46  import javax.servlet.ServletResponse;
47  import java.io.Serializable;
48  import java.util.Collection;
49  import java.util.function.Supplier;
50  
51  
52  /**
53   * Default {@link WebSecurityManager WebSecurityManager} implementation used in web-based applications or any
54   * application that requires HTTP connectivity (SOAP, http remoting, etc.).
55   *
56   * @since 0.2
57   */
58  public class DefaultWebSecurityManager extends DefaultSecurityManager implements WebSecurityManager {
59  
60      @SuppressWarnings("checkstyle:JavadocVariable")
61      @Deprecated
62      public static final String HTTP_SESSION_MODE = "http";
63      @SuppressWarnings("checkstyle:JavadocVariable")
64      @Deprecated
65      public static final String NATIVE_SESSION_MODE = "native";
66  
67      private static final Logger LOGGER = LoggerFactory.getLogger(DefaultWebSecurityManager.class);
68  
69      /**
70       * @deprecated as of 1.2.  This should NOT be used for anything other than determining if the sessionMode has changed.
71       */
72      @Deprecated
73      private String sessionMode;
74  
75      public DefaultWebSecurityManager() {
76          super();
77          init(null);
78      }
79  
80      public DefaultWebSecurityManager(Supplier<byte[]> keySupplier) {
81          super();
82          init(keySupplier);
83      }
84  
85      @SuppressWarnings({"UnusedDeclaration"})
86      public DefaultWebSecurityManager(Realm singleRealm) {
87          this();
88          setRealm(singleRealm);
89      }
90  
91      @SuppressWarnings({"UnusedDeclaration"})
92      public DefaultWebSecurityManager(Collection<Realm> realms) {
93          this();
94          setRealms(realms);
95      }
96  
97      @Override
98      protected SubjectContext createSubjectContext() {
99          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 }