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.servlet;
20  
21  import org.apache.shiro.session.InvalidSessionException;
22  import org.apache.shiro.session.Session;
23  import org.apache.shiro.web.session.HttpServletSession;
24  
25  import javax.servlet.ServletContext;
26  import javax.servlet.http.HttpServletRequest;
27  import javax.servlet.http.HttpSession;
28  import javax.servlet.http.HttpSessionBindingEvent;
29  import javax.servlet.http.HttpSessionBindingListener;
30  import java.util.Collection;
31  import java.util.Enumeration;
32  import java.util.HashSet;
33  import java.util.Iterator;
34  import java.util.Set;
35  
36  /**
37   * Wrapper class that uses a Shiro {@link Session Session} under the hood for all session operations instead of the
38   * Servlet Container's session mechanism.  This is required in heterogeneous client environments where the Session
39   * is used on both the business tier as well as in multiple client technologies (web, swing, flash, etc.) since
40   * Servlet container sessions alone cannot support this feature.
41   *
42   * @since 0.2
43   */
44  @SuppressWarnings("checkstyle:MagicNumber")
45  public class ShiroHttpSession implements HttpSession {
46  
47      /**
48       * default session id name.
49       */
50      public static final String DEFAULT_SESSION_ID_NAME = "JSESSIONID";
51  
52      private static final Enumeration<String> EMPTY_ENUMERATION = new Enumeration<>() {
53          public boolean hasMoreElements() {
54              return false;
55          }
56  
57          public String nextElement() {
58              return null;
59          }
60      };
61  
62      @SuppressWarnings({"deprecation"})
63      private static final javax.servlet.http.HttpSessionContext HTTP_SESSION_CONTEXT =
64              new javax.servlet.http.HttpSessionContext() {
65                  public HttpSession getSession(String s) {
66                      return null;
67                  }
68  
69                  public Enumeration<String> getIds() {
70                      return EMPTY_ENUMERATION;
71                  }
72              };
73  
74      protected ServletContext servletContext;
75      protected HttpServletRequest currentRequest;
76      //'real' Shiro Session
77      protected Session session;
78  
79      public ShiroHttpSession(Session session, HttpServletRequest currentRequest, ServletContext servletContext) {
80          if (session instanceof HttpServletSession) {
81              String msg = "Session constructor argument cannot be an instance of HttpServletSession.  This is enforced to "
82                      + "prevent circular dependencies and infinite loops.";
83              throw new IllegalArgumentException(msg);
84          }
85          this.session = session;
86          this.currentRequest = currentRequest;
87          this.servletContext = servletContext;
88      }
89  
90      public Session getSession() {
91          return this.session;
92      }
93  
94      public long getCreationTime() {
95          try {
96              return getSession().getStartTimestamp().getTime();
97          } catch (Exception e) {
98              throw new IllegalStateException(e);
99          }
100     }
101 
102     public String getId() {
103         return getSession().getId().toString();
104     }
105 
106     public long getLastAccessedTime() {
107         return getSession().getLastAccessTime().getTime();
108     }
109 
110     public ServletContext getServletContext() {
111         return this.servletContext;
112     }
113 
114     public void setMaxInactiveInterval(int i) {
115         try {
116             getSession().setTimeout(i * 1000L);
117         } catch (InvalidSessionException e) {
118             throw new IllegalStateException(e);
119         }
120     }
121 
122     public int getMaxInactiveInterval() {
123         try {
124             return (Long.valueOf(getSession().getTimeout() / 1000)).intValue();
125         } catch (InvalidSessionException e) {
126             throw new IllegalStateException(e);
127         }
128     }
129 
130     @SuppressWarnings({"deprecation"})
131     public javax.servlet.http.HttpSessionContext getSessionContext() {
132         return HTTP_SESSION_CONTEXT;
133     }
134 
135     public Object getAttribute(String s) {
136         try {
137             return getSession().getAttribute(s);
138         } catch (InvalidSessionException e) {
139             throw new IllegalStateException(e);
140         }
141     }
142 
143     @Deprecated
144     @Override
145     public Object getValue(String s) {
146         return getAttribute(s);
147     }
148 
149     protected Set<String> getKeyNames() {
150         Collection<Object> keySet;
151         try {
152             keySet = getSession().getAttributeKeys();
153         } catch (InvalidSessionException e) {
154             throw new IllegalStateException(e);
155         }
156         Set<String> keyNames;
157         if (keySet != null && !keySet.isEmpty()) {
158             keyNames = new HashSet<String>(keySet.size());
159             for (Object o : keySet) {
160                 keyNames.add(o.toString());
161             }
162         } else {
163             keyNames = Set.of();
164         }
165         return keyNames;
166     }
167 
168     @Override
169     public Enumeration<String> getAttributeNames() {
170         Set<String> keyNames = getKeyNames();
171         final Iterator<String> iterator = keyNames.iterator();
172         return new Enumeration<>() {
173             public boolean hasMoreElements() {
174                 return iterator.hasNext();
175             }
176 
177             public String nextElement() {
178                 return iterator.next();
179             }
180         };
181     }
182 
183     @Deprecated
184     public String[] getValueNames() {
185         Set<String> keyNames = getKeyNames();
186         String[] array = new String[keyNames.size()];
187         if (keyNames.size() > 0) {
188             array = keyNames.toArray(array);
189         }
190         return array;
191     }
192 
193     protected void afterBound(String s, Object o) {
194         if (o instanceof HttpSessionBindingListener) {
195             HttpSessionBindingListener listener = (HttpSessionBindingListener) o;
196             HttpSessionBindingEvent event = new HttpSessionBindingEvent(this, s, o);
197             listener.valueBound(event);
198         }
199     }
200 
201     protected void afterUnbound(String s, Object o) {
202         if (o instanceof HttpSessionBindingListener) {
203             HttpSessionBindingListener listener = (HttpSessionBindingListener) o;
204             HttpSessionBindingEvent event = new HttpSessionBindingEvent(this, s, o);
205             listener.valueUnbound(event);
206         }
207     }
208 
209     public void setAttribute(String s, Object o) {
210         try {
211             getSession().setAttribute(s, o);
212             afterBound(s, o);
213         } catch (InvalidSessionException e) {
214             //noinspection finally
215             try {
216                 afterUnbound(s, o);
217             } finally {
218                 //noinspection ThrowFromFinallyBlock
219                 throw new IllegalStateException(e);
220             }
221         }
222     }
223 
224     @Deprecated
225     public void putValue(String s, Object o) {
226         setAttribute(s, o);
227     }
228 
229     public void removeAttribute(String s) {
230         try {
231             Object attribute = getSession().removeAttribute(s);
232             afterUnbound(s, attribute);
233         } catch (InvalidSessionException e) {
234             throw new IllegalStateException(e);
235         }
236     }
237 
238     @Deprecated
239     public void removeValue(String s) {
240         removeAttribute(s);
241     }
242 
243     public void invalidate() {
244         try {
245             getSession().stop();
246         } catch (InvalidSessionException e) {
247             throw new IllegalStateException(e);
248         }
249     }
250 
251     public boolean isNew() {
252         Boolean value = (Boolean) currentRequest.getAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW);
253         return value != null && value.equals(Boolean.TRUE);
254     }
255 }