001: //========================================================================
002: //Copyright 2006 Mort Bay Consulting Pty. Ltd.
003: //------------------------------------------------------------------------
004: //Licensed under the Apache License, Version 2.0 (the "License");
005: //you may not use this file except in compliance with the License.
006: //You may obtain a copy of the License at
007: //http://www.apache.org/licenses/LICENSE-2.0
008: //Unless required by applicable law or agreed to in writing, software
009: //distributed under the License is distributed on an "AS IS" BASIS,
010: //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011: //See the License for the specific language governing permissions and
012: //limitations under the License.
013: //========================================================================
014:
015: package org.mortbay.jetty.servlet;
016:
017: import java.security.NoSuchAlgorithmException;
018: import java.security.SecureRandom;
019: import java.util.Random;
020:
021: import javax.servlet.http.HttpServletRequest;
022: import javax.servlet.http.HttpSession;
023:
024: import org.mortbay.component.AbstractLifeCycle;
025: import org.mortbay.jetty.SessionIdManager;
026: import org.mortbay.jetty.servlet.AbstractSessionManager.Session;
027: import org.mortbay.log.Log;
028: import org.mortbay.util.MultiMap;
029:
030: /* ------------------------------------------------------------ */
031: /**
032: * HashSessionIdManager. An in-memory implementation of the session ID manager.
033: */
034: public class HashSessionIdManager extends AbstractLifeCycle implements
035: SessionIdManager {
036: private final static String __NEW_SESSION_ID = "org.mortbay.jetty.newSessionId";
037: protected final static String SESSION_ID_RANDOM_ALGORITHM = "SHA1PRNG";
038: protected final static String SESSION_ID_RANDOM_ALGORITHM_ALT = "IBMSecureRandom";
039:
040: MultiMap _sessions;
041: protected Random _random;
042: private boolean _weakRandom;
043: private String _workerName;
044:
045: /* ------------------------------------------------------------ */
046: public HashSessionIdManager() {
047: }
048:
049: /* ------------------------------------------------------------ */
050: public HashSessionIdManager(Random random) {
051: _random = random;
052:
053: }
054:
055: /* ------------------------------------------------------------ */
056: /**
057: * Get the workname. If set, the workername is dot appended to the session
058: * ID and can be used to assist session affinity in a load balancer.
059: *
060: * @return String or null
061: */
062: public String getWorkerName() {
063: return _workerName;
064: }
065:
066: /* ------------------------------------------------------------ */
067: /**
068: * Set the workname. If set, the workername is dot appended to the session
069: * ID and can be used to assist session affinity in a load balancer.
070: *
071: * @param workerName
072: */
073: public void setWorkerName(String workerName) {
074: _workerName = workerName;
075: }
076:
077: /* ------------------------------------------------------------ */
078: protected void doStart() {
079: if (_random == null) {
080: try {
081: _random = SecureRandom
082: .getInstance(SESSION_ID_RANDOM_ALGORITHM);
083: } catch (NoSuchAlgorithmException e) {
084: try {
085: _random = SecureRandom
086: .getInstance(SESSION_ID_RANDOM_ALGORITHM_ALT);
087: _weakRandom = false;
088: } catch (NoSuchAlgorithmException e_alt) {
089: Log
090: .warn(
091: "Could not generate SecureRandom for session-id randomness",
092: e);
093: _random = new Random();
094: _weakRandom = true;
095: }
096: }
097: }
098: _random.setSeed(_random.nextLong() ^ System.currentTimeMillis()
099: ^ hashCode() ^ Runtime.getRuntime().freeMemory());
100: _sessions = new MultiMap();
101: }
102:
103: /* ------------------------------------------------------------ */
104: protected void doStop() {
105: if (_sessions != null)
106: _sessions.clear(); // Maybe invalidate?
107: _sessions = null;
108: }
109:
110: /* ------------------------------------------------------------ */
111: /*
112: * @see org.mortbay.jetty.SessionManager.MetaManager#idInUse(java.lang.String)
113: */
114: public boolean idInUse(String id) {
115: return _sessions.containsKey(id);
116: }
117:
118: /* ------------------------------------------------------------ */
119: /*
120: * @see org.mortbay.jetty.SessionManager.MetaManager#addSession(javax.servlet.http.HttpSession)
121: */
122: public void addSession(HttpSession session) {
123: synchronized (this ) {
124: _sessions.add(session.getId(), session);
125: }
126: }
127:
128: /* ------------------------------------------------------------ */
129: /*
130: * @see org.mortbay.jetty.SessionManager.MetaManager#addSession(javax.servlet.http.HttpSession)
131: */
132: public void removeSession(HttpSession session) {
133: synchronized (this ) {
134: _sessions.removeValue(session.getId(), session);
135: }
136: }
137:
138: /* ------------------------------------------------------------ */
139: /*
140: * @see org.mortbay.jetty.SessionManager.MetaManager#invalidateAll(java.lang.String)
141: */
142: public void invalidateAll(String id) {
143: synchronized (this ) {
144: // Do not use interators as this method tends to be called recursively
145: // by the invalidate calls.
146: while (_sessions.containsKey(id)) {
147: Session session = (Session) _sessions.getValue(id, 0);
148: if (session.isValid())
149: session.invalidate();
150: else
151: _sessions.removeValue(id, session);
152: }
153: }
154: }
155:
156: /* ------------------------------------------------------------ */
157: /*
158: * new Session ID. If the request has a requestedSessionID which is unique,
159: * that is used. The session ID is created as a unique random long XORed with
160: * connection specific information, base 36.
161: * @param request
162: * @param created
163: * @return Session ID.
164: */
165: public String newSessionId(HttpServletRequest request, long created) {
166: synchronized (this ) {
167: // A requested session ID can only be used if it is in use already.
168: String requested_id = request.getRequestedSessionId();
169: if (requested_id != null && idInUse(requested_id))
170: return requested_id;
171:
172: // Else reuse any new session ID already defined for this request.
173: String new_id = (String) request
174: .getAttribute(__NEW_SESSION_ID);
175: if (new_id != null && idInUse(new_id))
176: return new_id;
177:
178: // pick a new unique ID!
179: String id = null;
180: while (id == null || id.length() == 0 || idInUse(id)) {
181: long r = _weakRandom ? (hashCode()
182: ^ Runtime.getRuntime().freeMemory()
183: ^ _random.nextInt() ^ (((long) request
184: .hashCode()) << 32)) : _random.nextLong();
185: r ^= created;
186: if (request != null && request.getRemoteAddr() != null)
187: r ^= request.getRemoteAddr().hashCode();
188: if (r < 0)
189: r = -r;
190: id = Long.toString(r, 36);
191: }
192:
193: request.setAttribute(__NEW_SESSION_ID, id);
194: return id;
195: }
196: }
197:
198: /* ------------------------------------------------------------ */
199: public Random getRandom() {
200: return _random;
201: }
202:
203: /* ------------------------------------------------------------ */
204: public void setRandom(Random random) {
205: _random = random;
206: _weakRandom = false;
207: }
208:
209: }
|