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 }