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    }