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.session;
020
021 import org.apache.shiro.session.InvalidSessionException;
022 import org.apache.shiro.session.Session;
023 import org.apache.shiro.util.StringUtils;
024 import org.apache.shiro.web.servlet.ShiroHttpSession;
025
026 import javax.servlet.http.HttpSession;
027 import java.io.Serializable;
028 import java.util.ArrayList;
029 import java.util.Collection;
030 import java.util.Date;
031 import java.util.Enumeration;
032
033 /**
034 * {@link Session Session} implementation that is backed entirely by a standard servlet container
035 * {@link HttpSession HttpSession} instance. It does not interact with any of Shiro's session-related components
036 * {@code SessionManager}, {@code SecurityManager}, etc, and instead satisfies all method implementations by interacting
037 * with a servlet container provided {@link HttpSession HttpSession} instance.
038 *
039 * @since 1.0
040 */
041 public class HttpServletSession implements Session {
042
043 private static final String HOST_SESSION_KEY = HttpServletSession.class.getName() + ".HOST_SESSION_KEY";
044 private static final String TOUCH_OBJECT_SESSION_KEY = HttpServletSession.class.getName() + ".TOUCH_OBJECT_SESSION_KEY";
045
046 private HttpSession httpSession = null;
047
048 public HttpServletSession(HttpSession httpSession, String host) {
049 if (httpSession == null) {
050 String msg = "HttpSession constructor argument cannot be null.";
051 throw new IllegalArgumentException(msg);
052 }
053 if (httpSession instanceof ShiroHttpSession) {
054 String msg = "HttpSession constructor argument cannot be an instance of ShiroHttpSession. This " +
055 "is enforced to prevent circular dependencies and infinite loops.";
056 throw new IllegalArgumentException(msg);
057 }
058 this.httpSession = httpSession;
059 if (StringUtils.hasText(host)) {
060 setHost(host);
061 }
062 }
063
064 public Serializable getId() {
065 return httpSession.getId();
066 }
067
068 public Date getStartTimestamp() {
069 return new Date(httpSession.getCreationTime());
070 }
071
072 public Date getLastAccessTime() {
073 return new Date(httpSession.getLastAccessedTime());
074 }
075
076 public long getTimeout() throws InvalidSessionException {
077 try {
078 return httpSession.getMaxInactiveInterval() * 1000;
079 } catch (Exception e) {
080 throw new InvalidSessionException(e);
081 }
082 }
083
084 public void setTimeout(long maxIdleTimeInMillis) throws InvalidSessionException {
085 try {
086 int timeout = Long.valueOf(maxIdleTimeInMillis / 1000).intValue();
087 httpSession.setMaxInactiveInterval(timeout);
088 } catch (Exception e) {
089 throw new InvalidSessionException(e);
090 }
091 }
092
093 protected void setHost(String host) {
094 setAttribute(HOST_SESSION_KEY, host);
095 }
096
097 public String getHost() {
098 return (String) getAttribute(HOST_SESSION_KEY);
099 }
100
101 public void touch() throws InvalidSessionException {
102 //just manipulate the session to update the access time:
103 try {
104 httpSession.setAttribute(TOUCH_OBJECT_SESSION_KEY, TOUCH_OBJECT_SESSION_KEY);
105 httpSession.removeAttribute(TOUCH_OBJECT_SESSION_KEY);
106 } catch (Exception e) {
107 throw new InvalidSessionException(e);
108 }
109 }
110
111 public void stop() throws InvalidSessionException {
112 try {
113 httpSession.invalidate();
114 } catch (Exception e) {
115 throw new InvalidSessionException(e);
116 }
117 }
118
119 public Collection<Object> getAttributeKeys() throws InvalidSessionException {
120 try {
121 Enumeration namesEnum = httpSession.getAttributeNames();
122 Collection<Object> keys = null;
123 if (namesEnum != null) {
124 keys = new ArrayList<Object>();
125 while (namesEnum.hasMoreElements()) {
126 keys.add(namesEnum.nextElement());
127 }
128 }
129 return keys;
130 } catch (Exception e) {
131 throw new InvalidSessionException(e);
132 }
133 }
134
135 private static String assertString(Object key) {
136 if (!(key instanceof String)) {
137 String msg = "HttpSession based implementations of the Shiro Session interface requires attribute keys " +
138 "to be String objects. The HttpSession class does not support anything other than String keys.";
139 throw new IllegalArgumentException(msg);
140 }
141 return (String) key;
142 }
143
144 public Object getAttribute(Object key) throws InvalidSessionException {
145 try {
146 return httpSession.getAttribute(assertString(key));
147 } catch (Exception e) {
148 throw new InvalidSessionException(e);
149 }
150 }
151
152 public void setAttribute(Object key, Object value) throws InvalidSessionException {
153 try {
154 httpSession.setAttribute(assertString(key), value);
155 } catch (Exception e) {
156 throw new InvalidSessionException(e);
157 }
158 }
159
160 public Object removeAttribute(Object key) throws InvalidSessionException {
161 try {
162 String sKey = assertString(key);
163 Object removed = httpSession.getAttribute(sKey);
164 httpSession.removeAttribute(sKey);
165 return removed;
166 } catch (Exception e) {
167 throw new InvalidSessionException(e);
168 }
169 }
170 }