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     */
019    package org.apache.shiro.web.mgt;
020    
021    import org.apache.shiro.mgt.DefaultSecurityManager;
022    import org.apache.shiro.realm.Realm;
023    import org.apache.shiro.session.mgt.SessionContext;
024    import org.apache.shiro.session.mgt.SessionKey;
025    import org.apache.shiro.session.mgt.SessionManager;
026    import org.apache.shiro.subject.Subject;
027    import org.apache.shiro.subject.SubjectContext;
028    import org.apache.shiro.util.LifecycleUtils;
029    import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
030    import org.apache.shiro.web.session.mgt.DefaultWebSessionContext;
031    import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
032    import org.apache.shiro.web.session.mgt.ServletContainerSessionManager;
033    import org.apache.shiro.web.session.mgt.WebSessionKey;
034    import org.apache.shiro.web.subject.WebSubject;
035    import org.apache.shiro.web.subject.WebSubjectContext;
036    import org.apache.shiro.web.subject.support.DefaultWebSubjectContext;
037    import org.apache.shiro.web.util.WebUtils;
038    import org.slf4j.Logger;
039    import org.slf4j.LoggerFactory;
040    
041    import javax.servlet.ServletRequest;
042    import javax.servlet.ServletResponse;
043    import java.io.Serializable;
044    import 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     */
053    public class DefaultWebSecurityManager extends DefaultSecurityManager implements WebSecurityManager {
054    
055        //TODO - complete JavaDoc
056    
057        private static final Logger log = LoggerFactory.getLogger(DefaultWebSecurityManager.class);
058    
059        public static final String HTTP_SESSION_MODE = "http";
060        public static final String NATIVE_SESSION_MODE = "native";
061    
062        private String sessionMode;
063    
064        public DefaultWebSecurityManager() {
065            super();
066            this.sessionMode = HTTP_SESSION_MODE;
067            setSubjectFactory(new DefaultWebSubjectFactory());
068            setRememberMeManager(new CookieRememberMeManager());
069            setSessionManager(new ServletContainerSessionManager());
070        }
071    
072        @SuppressWarnings({"UnusedDeclaration"})
073        public DefaultWebSecurityManager(Realm singleRealm) {
074            this();
075            setRealm(singleRealm);
076        }
077    
078        @SuppressWarnings({"UnusedDeclaration"})
079        public DefaultWebSecurityManager(Collection<Realm> realms) {
080            this();
081            setRealms(realms);
082        }
083    
084        @Override
085        protected SubjectContext createSubjectContext() {
086            return new DefaultWebSubjectContext();
087        }
088    
089        @Override
090        protected SubjectContext copy(SubjectContext subjectContext) {
091            if (subjectContext instanceof WebSubjectContext) {
092                return new DefaultWebSubjectContext((WebSubjectContext) subjectContext);
093            }
094            return super.copy(subjectContext);
095        }
096    
097        @SuppressWarnings({"UnusedDeclaration"})
098        public String getSessionMode() {
099            return sessionMode;
100        }
101    
102        public void setSessionMode(String sessionMode) {
103            String mode = sessionMode;
104            if (mode == null) {
105                throw new IllegalArgumentException("sessionMode argument cannot be null.");
106            }
107            mode = sessionMode.toLowerCase();
108            if (!HTTP_SESSION_MODE.equals(mode) && !NATIVE_SESSION_MODE.equals(mode)) {
109                String msg = "Invalid sessionMode [" + sessionMode + "].  Allowed values are " +
110                        "public static final String constants in the " + getClass().getName() + " class: '"
111                        + HTTP_SESSION_MODE + "' or '" + NATIVE_SESSION_MODE + "', with '" +
112                        HTTP_SESSION_MODE + "' being the default.";
113                throw new IllegalArgumentException(msg);
114            }
115            boolean recreate = this.sessionMode == null || !this.sessionMode.equals(mode);
116            this.sessionMode = mode;
117            if (recreate) {
118                LifecycleUtils.destroy(getSessionManager());
119                SessionManager sessionManager = createSessionManager(mode);
120                setSessionManager(sessionManager);
121            }
122        }
123    
124        /**
125         * @since 1.0
126         */
127        public boolean isHttpSessionMode() {
128            return this.sessionMode == null || this.sessionMode.equals(HTTP_SESSION_MODE);
129        }
130    
131        protected SessionManager createSessionManager(String sessionMode) {
132            if (sessionMode == null || sessionMode.equalsIgnoreCase(HTTP_SESSION_MODE)) {
133                if (log.isInfoEnabled()) {
134                    log.info(HTTP_SESSION_MODE + " mode - enabling ServletContainerSessionManager (HTTP-only Sessions)");
135                }
136                return new ServletContainerSessionManager();
137            } else {
138                if (log.isInfoEnabled()) {
139                    log.info(NATIVE_SESSION_MODE + " mode - enabling DefaultWebSessionManager (HTTP + heterogeneous-client sessions)");
140                }
141                return new DefaultWebSessionManager();
142            }
143        }
144    
145        @Override
146        protected SessionContext createSessionContext(SubjectContext subjectContext) {
147            SessionContext sessionContext = super.createSessionContext(subjectContext);
148            if (subjectContext instanceof WebSubjectContext) {
149                WebSubjectContext wsc = (WebSubjectContext) subjectContext;
150                ServletRequest request = wsc.resolveServletRequest();
151                ServletResponse response = wsc.resolveServletResponse();
152                DefaultWebSessionContext webSessionContext = new DefaultWebSessionContext(sessionContext);
153                if (request != null) {
154                    webSessionContext.setServletRequest(request);
155                }
156                if (response != null) {
157                    webSessionContext.setServletResponse(response);
158                }
159    
160                sessionContext = webSessionContext;
161            }
162            return sessionContext;
163        }
164    
165        @Override
166        protected SessionKey getSessionKey(SubjectContext context) {
167            if (WebUtils.isWeb(context)) {
168                Serializable sessionId = context.getSessionId();
169                ServletRequest request = WebUtils.getRequest(context);
170                ServletResponse response = WebUtils.getResponse(context);
171                return new WebSessionKey(sessionId, request, response);
172            } else {
173                return super.getSessionKey(context);
174    
175            }
176        }
177    
178        @Override
179        protected void beforeLogout(Subject subject) {
180            super.beforeLogout(subject);
181            removeRequestIdentity(subject);
182        }
183    
184        protected void removeRequestIdentity(Subject subject) {
185            if (subject instanceof WebSubject) {
186                WebSubject webSubject = (WebSubject) subject;
187                ServletRequest request = webSubject.getServletRequest();
188                if (request != null) {
189                    request.setAttribute(ShiroHttpServletRequest.IDENTITY_REMOVED_KEY, Boolean.TRUE);
190                }
191            }
192        }
193    }