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 */ 019package org.apache.shiro.web.session; 020 021import org.apache.shiro.session.InvalidSessionException; 022import org.apache.shiro.session.Session; 023import org.apache.shiro.lang.util.StringUtils; 024import org.apache.shiro.web.servlet.ShiroHttpSession; 025 026import javax.servlet.http.HttpSession; 027import java.io.Serializable; 028import java.util.ArrayList; 029import java.util.Collection; 030import java.util.Date; 031import 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 */ 041public 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; 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 @SuppressWarnings("checkstyle:MagicNumber") 077 public long getTimeout() throws InvalidSessionException { 078 try { 079 return httpSession.getMaxInactiveInterval() * 1000L; 080 } catch (Exception e) { 081 throw new InvalidSessionException(e); 082 } 083 } 084 085 @SuppressWarnings("checkstyle:MagicNumber") 086 public void setTimeout(long maxIdleTimeInMillis) throws InvalidSessionException { 087 try { 088 int timeout = (int) (maxIdleTimeInMillis / 1000); 089 httpSession.setMaxInactiveInterval(timeout); 090 } catch (Exception e) { 091 throw new InvalidSessionException(e); 092 } 093 } 094 095 protected void setHost(String host) { 096 setAttribute(HOST_SESSION_KEY, host); 097 } 098 099 public String getHost() { 100 return (String) getAttribute(HOST_SESSION_KEY); 101 } 102 103 public void touch() throws InvalidSessionException { 104 //just manipulate the session to update the access time: 105 try { 106 httpSession.setAttribute(TOUCH_OBJECT_SESSION_KEY, TOUCH_OBJECT_SESSION_KEY); 107 httpSession.removeAttribute(TOUCH_OBJECT_SESSION_KEY); 108 } catch (Exception e) { 109 throw new InvalidSessionException(e); 110 } 111 } 112 113 public void stop() throws InvalidSessionException { 114 try { 115 httpSession.invalidate(); 116 } catch (Exception e) { 117 throw new InvalidSessionException(e); 118 } 119 } 120 121 public Collection<Object> getAttributeKeys() throws InvalidSessionException { 122 try { 123 Enumeration namesEnum = httpSession.getAttributeNames(); 124 Collection<Object> keys = null; 125 if (namesEnum != null) { 126 keys = new ArrayList<Object>(); 127 while (namesEnum.hasMoreElements()) { 128 keys.add(namesEnum.nextElement()); 129 } 130 } 131 return keys; 132 } catch (Exception e) { 133 throw new InvalidSessionException(e); 134 } 135 } 136 137 private static String assertString(Object key) { 138 if (!(key instanceof String)) { 139 String msg = "HttpSession based implementations of the Shiro Session interface requires attribute keys " 140 + "to be String objects. The HttpSession class does not support anything other than String keys."; 141 throw new IllegalArgumentException(msg); 142 } 143 return (String) key; 144 } 145 146 public Object getAttribute(Object key) throws InvalidSessionException { 147 try { 148 return httpSession.getAttribute(assertString(key)); 149 } catch (Exception e) { 150 throw new InvalidSessionException(e); 151 } 152 } 153 154 public void setAttribute(Object key, Object value) throws InvalidSessionException { 155 try { 156 httpSession.setAttribute(assertString(key), value); 157 } catch (Exception e) { 158 throw new InvalidSessionException(e); 159 } 160 } 161 162 public Object removeAttribute(Object key) throws InvalidSessionException { 163 try { 164 String sKey = assertString(key); 165 Object removed = httpSession.getAttribute(sKey); 166 httpSession.removeAttribute(sKey); 167 return removed; 168 } catch (Exception e) { 169 throw new InvalidSessionException(e); 170 } 171 } 172}