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.util.LifecycleUtils;
32  import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
33  import org.apache.shiro.web.session.mgt.*;
34  import org.apache.shiro.web.subject.WebSubject;
35  import org.apache.shiro.web.subject.WebSubjectContext;
36  import org.apache.shiro.web.subject.support.DefaultWebSubjectContext;
37  import org.apache.shiro.web.util.WebUtils;
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  
41  import javax.servlet.ServletRequest;
42  import javax.servlet.ServletResponse;
43  import java.io.Serializable;
44  import java.util.Collection;
45  
46  
47  /**
48   * Default {@link WebSecurityManager WebSecurityManager} implementation used in web-based applications or any
49   * application that requires HTTP connectivity (SOAP, http remoting, etc).
50   *
51   * @since 0.2
52   */
53  public class DefaultWebSecurityManager extends DefaultSecurityManager implements WebSecurityManager {
54  
55      //TODO - complete JavaDoc
56  
57      private static final Logger log = LoggerFactory.getLogger(DefaultWebSecurityManager.class);
58  
59      @Deprecated
60      public static final String HTTP_SESSION_MODE = "http";
61      @Deprecated
62      public static final String NATIVE_SESSION_MODE = "native";
63  
64      /**
65       * @deprecated as of 1.2.  This should NOT be used for anything other than determining if the sessionMode has changed.
66       */
67      @Deprecated
68      private String sessionMode;
69  
70      public DefaultWebSecurityManager() {
71          super();
72          DefaultWebSessionStorageEvaluator webEvalutator = new DefaultWebSessionStorageEvaluator();  
73          ((DefaultSubjectDAO) this.subjectDAO).setSessionStorageEvaluator(webEvalutator);
74          this.sessionMode = HTTP_SESSION_MODE;
75          setSubjectFactory(new DefaultWebSubjectFactory());
76          setRememberMeManager(new CookieRememberMeManager());
77          setSessionManager(new ServletContainerSessionManager());
78          webEvalutator.setSessionManager(getSessionManager());
79      }
80  
81      @SuppressWarnings({"UnusedDeclaration"})
82      public DefaultWebSecurityManager(Realm singleRealm) {
83          this();
84          setRealm(singleRealm);
85      }
86  
87      @SuppressWarnings({"UnusedDeclaration"})
88      public DefaultWebSecurityManager(Collection<Realm> realms) {
89          this();
90          setRealms(realms);
91      }
92  
93      @Override
94      protected SubjectContext createSubjectContext() {
95          return new DefaultWebSubjectContext();
96      }
97  
98      @Override
99      //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 }