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.servlet;
020    
021    import org.apache.shiro.SecurityUtils;
022    import org.apache.shiro.session.Session;
023    import org.apache.shiro.subject.Subject;
024    import org.apache.shiro.subject.support.DisabledSessionException;
025    import org.apache.shiro.web.util.WebUtils;
026    
027    import javax.servlet.ServletContext;
028    import javax.servlet.http.HttpServletRequest;
029    import javax.servlet.http.HttpServletRequestWrapper;
030    import javax.servlet.http.HttpSession;
031    import java.security.Principal;
032    
033    
034    /**
035     * A {@code ShiroHttpServletRequest} wraps the Servlet container's original {@code ServletRequest} instance, but ensures
036     * that all {@link HttpServletRequest} invocations that require Shiro's support ({@link #getRemoteUser getRemoteUser},
037     * {@link #getSession getSession}, etc) can be executed first by Shiro as necessary before allowing the underlying
038     * Servlet container instance's method to be invoked.
039     *
040     * @since 0.2
041     */
042    public class ShiroHttpServletRequest extends HttpServletRequestWrapper {
043    
044        //TODO - complete JavaDoc
045    
046        //The following 7 constants support the Shiro's implementation of the Servlet Specification
047        public static final String COOKIE_SESSION_ID_SOURCE = "cookie";
048        public static final String URL_SESSION_ID_SOURCE = "url";
049        public static final String REFERENCED_SESSION_ID = ShiroHttpServletRequest.class.getName() + "_REQUESTED_SESSION_ID";
050        public static final String REFERENCED_SESSION_ID_IS_VALID = ShiroHttpServletRequest.class.getName() + "_REQUESTED_SESSION_ID_VALID";
051        public static final String REFERENCED_SESSION_IS_NEW = ShiroHttpServletRequest.class.getName() + "_REFERENCED_SESSION_IS_NEW";
052        public static final String REFERENCED_SESSION_ID_SOURCE = ShiroHttpServletRequest.class.getName() + "REFERENCED_SESSION_ID_SOURCE";
053        public static final String IDENTITY_REMOVED_KEY = ShiroHttpServletRequest.class.getName() + "_IDENTITY_REMOVED_KEY";
054    
055        protected ServletContext servletContext = null;
056    
057        protected HttpSession session = null;
058        protected boolean httpSessions = true;
059    
060        public ShiroHttpServletRequest(HttpServletRequest wrapped, ServletContext servletContext, boolean httpSessions) {
061            super(wrapped);
062            this.servletContext = servletContext;
063            this.httpSessions = httpSessions;
064        }
065    
066        public boolean isHttpSessions() {
067            return httpSessions;
068        }
069    
070        public String getRemoteUser() {
071            String remoteUser;
072            Object scPrincipal = getSubjectPrincipal();
073            if (scPrincipal != null) {
074                if (scPrincipal instanceof String) {
075                    return (String) scPrincipal;
076                } else if (scPrincipal instanceof Principal) {
077                    remoteUser = ((Principal) scPrincipal).getName();
078                } else {
079                    remoteUser = scPrincipal.toString();
080                }
081            } else {
082                remoteUser = super.getRemoteUser();
083            }
084            return remoteUser;
085        }
086    
087        protected Subject getSubject() {
088            return SecurityUtils.getSubject();
089        }
090    
091        protected Object getSubjectPrincipal() {
092            Object userPrincipal = null;
093            Subject subject = getSubject();
094            if (subject != null) {
095                userPrincipal = subject.getPrincipal();
096            }
097            return userPrincipal;
098        }
099    
100        public boolean isUserInRole(String s) {
101            Subject subject = getSubject();
102            boolean inRole = (subject != null && subject.hasRole(s));
103            if (!inRole) {
104                inRole = super.isUserInRole(s);
105            }
106            return inRole;
107        }
108    
109        public Principal getUserPrincipal() {
110            Principal userPrincipal;
111            Object scPrincipal = getSubjectPrincipal();
112            if (scPrincipal != null) {
113                if (scPrincipal instanceof Principal) {
114                    userPrincipal = (Principal) scPrincipal;
115                } else {
116                    userPrincipal = new ObjectPrincipal(scPrincipal);
117                }
118            } else {
119                userPrincipal = super.getUserPrincipal();
120            }
121            return userPrincipal;
122        }
123    
124        public String getRequestedSessionId() {
125            String requestedSessionId = null;
126            if (isHttpSessions()) {
127                requestedSessionId = super.getRequestedSessionId();
128            } else {
129                Object sessionId = getAttribute(REFERENCED_SESSION_ID);
130                if (sessionId != null) {
131                    requestedSessionId = sessionId.toString();
132                }
133            }
134    
135            return requestedSessionId;
136        }
137    
138        public HttpSession getSession(boolean create) {
139    
140            HttpSession httpSession;
141    
142            if (isHttpSessions()) {
143                httpSession = super.getSession(false);
144                if (httpSession == null && create) {
145                    //Shiro 1.2: assert that creation is enabled (SHIRO-266):
146                    if (WebUtils._isSessionCreationEnabled(this)) {
147                        httpSession = super.getSession(create);
148                    } else {
149                        throw newNoSessionCreationException();
150                    }
151                }
152            } else {
153                if (this.session == null) {
154    
155                    boolean existing = getSubject().getSession(false) != null;
156    
157                    Session shiroSession = getSubject().getSession(create);
158                    if (shiroSession != null) {
159                        this.session = new ShiroHttpSession(shiroSession, this, this.servletContext);
160                        if (!existing) {
161                            setAttribute(REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
162                        }
163                    }
164                }
165                httpSession = this.session;
166            }
167    
168            return httpSession;
169        }
170    
171        /**
172         * Constructs and returns a {@link DisabledSessionException} with an appropriate message explaining why
173         * session creation has been disabled.
174         *
175         * @return a new DisabledSessionException with appropriate no creation message
176         * @since 1.2
177         */
178        private DisabledSessionException newNoSessionCreationException() {
179            String msg = "Session creation has been disabled for the current request.  This exception indicates " +
180                    "that there is either a programming error (using a session when it should never be " +
181                    "used) or that Shiro's configuration needs to be adjusted to allow Sessions to be created " +
182                    "for the current request.  See the " + DisabledSessionException.class.getName() + " JavaDoc " +
183                    "for more.";
184            return new DisabledSessionException(msg);
185        }
186    
187        public HttpSession getSession() {
188            return getSession(true);
189        }
190    
191        public boolean isRequestedSessionIdValid() {
192            if (isHttpSessions()) {
193                return super.isRequestedSessionIdValid();
194            } else {
195                Boolean value = (Boolean) getAttribute(REFERENCED_SESSION_ID_IS_VALID);
196                return (value != null && value.equals(Boolean.TRUE));
197            }
198        }
199    
200        public boolean isRequestedSessionIdFromCookie() {
201            if (isHttpSessions()) {
202                return super.isRequestedSessionIdFromCookie();
203            } else {
204                String value = (String) getAttribute(REFERENCED_SESSION_ID_SOURCE);
205                return value != null && value.equals(COOKIE_SESSION_ID_SOURCE);
206            }
207        }
208    
209        public boolean isRequestedSessionIdFromURL() {
210            if (isHttpSessions()) {
211                return super.isRequestedSessionIdFromURL();
212            } else {
213                String value = (String) getAttribute(REFERENCED_SESSION_ID_SOURCE);
214                return value != null && value.equals(URL_SESSION_ID_SOURCE);
215            }
216        }
217    
218        public boolean isRequestedSessionIdFromUrl() {
219            return isRequestedSessionIdFromURL();
220        }
221    
222        private class ObjectPrincipal implements java.security.Principal {
223            private Object object = null;
224    
225            public ObjectPrincipal(Object object) {
226                this.object = object;
227            }
228    
229            public Object getObject() {
230                return object;
231            }
232    
233            public String getName() {
234                return getObject().toString();
235            }
236    
237            public int hashCode() {
238                return object.hashCode();
239            }
240    
241            public boolean equals(Object o) {
242                if (o instanceof ObjectPrincipal) {
243                    ObjectPrincipal op = (ObjectPrincipal) o;
244                    return getObject().equals(op.getObject());
245                }
246                return false;
247            }
248    
249            public String toString() {
250                return object.toString();
251            }
252        }
253    }