1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.terracotta.servlet;
16
17 import java.security.NoSuchAlgorithmException;
18 import java.security.SecureRandom;
19 import java.util.Hashtable;
20 import java.util.Map;
21 import java.util.Random;
22
23 import javax.servlet.http.HttpServletRequest;
24 import javax.servlet.http.HttpSession;
25
26 import org.mortbay.component.AbstractLifeCycle;
27 import org.mortbay.jetty.Handler;
28 import org.mortbay.jetty.Server;
29 import org.mortbay.jetty.SessionIdManager;
30 import org.mortbay.jetty.SessionManager;
31 import org.mortbay.jetty.servlet.AbstractSessionManager;
32 import org.mortbay.jetty.servlet.AbstractSessionManager.Session;
33 import org.mortbay.jetty.webapp.WebAppContext;
34 import org.mortbay.log.Log;
35
36
37
38
39
40
41
42 public class TerracottaSessionIdManager extends AbstractLifeCycle implements SessionIdManager
43 {
44 private final static String __NEW_SESSION_ID = "org.mortbay.jetty.newSessionId";
45 private final static String SESSION_ID_RANDOM_ALGORITHM = "SHA1PRNG";
46 private final static String SESSION_ID_RANDOM_ALGORITHM_ALT = "IBMSecureRandom";
47 private static final Object PRESENT = new Object();
48
49 private final Server _server;
50 private String _workerName;
51 private Random _random;
52 private boolean _weakRandom;
53 private Map<String, Object> _sessionIds;
54
55 public TerracottaSessionIdManager(Server server)
56 {
57 _server = server;
58 }
59
60 public void doStart()
61 {
62 if (_random == null)
63 {
64 try
65 {
66 _random = SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM);
67 }
68 catch (NoSuchAlgorithmException e)
69 {
70 try
71 {
72 _random = SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM_ALT);
73 _weakRandom = false;
74 }
75 catch (NoSuchAlgorithmException e_alt)
76 {
77 Log.warn("Could not generate SecureRandom for session-id randomness", e);
78 _random = new Random();
79 _weakRandom = true;
80 }
81 }
82 }
83 _random.setSeed(_random.nextLong() ^ System.currentTimeMillis() ^ hashCode() ^ Runtime.getRuntime().freeMemory());
84 _sessionIds = newSessionIdsSet();
85 }
86
87 private Map<String, Object> newSessionIdsSet()
88 {
89
90
91
92 return new Hashtable();
93 }
94
95 public void doStop()
96 {
97 }
98
99 public void addSession(HttpSession session)
100 {
101 String clusterId = ((TerracottaSessionManager.Session)session).getClusterId();
102
103
104 _sessionIds.put(clusterId, PRESENT);
105 }
106
107 public String getWorkerName()
108 {
109 return _workerName;
110 }
111
112 public void setWorkerName(String workerName)
113 {
114 _workerName = workerName;
115 }
116
117 public boolean idInUse(String clusterId)
118 {
119 return _sessionIds.containsKey(clusterId);
120 }
121
122
123
124
125
126
127 public void invalidateAll(String clusterId)
128 {
129 Handler[] contexts = _server.getChildHandlersByClass(WebAppContext.class);
130 for (int i = 0; contexts != null && i < contexts.length; i++)
131 {
132 WebAppContext webAppContext = (WebAppContext)contexts[i];
133 SessionManager sessionManager = webAppContext.getSessionHandler().getSessionManager();
134 if (sessionManager instanceof AbstractSessionManager)
135 {
136 Session session = ((AbstractSessionManager)sessionManager).getSession(clusterId);
137 if (session != null) session.invalidate();
138 }
139 }
140 }
141
142 public String newSessionId(HttpServletRequest request, long created)
143 {
144
145
146
147
148 String requested_id = request.getRequestedSessionId();
149 if (requested_id != null && idInUse(requested_id))
150 return requested_id;
151
152
153 String new_id = (String)request.getAttribute(__NEW_SESSION_ID);
154 if (new_id != null && idInUse(new_id))
155 return new_id;
156
157
158 String id = null;
159 while (id == null || id.length() == 0 || idInUse(id))
160 {
161 long r = _weakRandom
162 ? (hashCode() ^ Runtime.getRuntime().freeMemory() ^ _random.nextInt() ^ (((long)request.hashCode()) << 32))
163 : _random.nextLong();
164 r ^= created;
165 if (request.getRemoteAddr() != null) r ^= request.getRemoteAddr().hashCode();
166 if (r < 0) r = -r;
167 id = Long.toString(r, 36);
168 }
169
170 request.setAttribute(__NEW_SESSION_ID, id);
171 return id;
172 }
173
174 public void removeSession(HttpSession session)
175 {
176 String clusterId = ((TerracottaSessionManager.Session)session).getClusterId();
177 _sessionIds.remove(clusterId);
178 }
179
180 public String getClusterId(String nodeId)
181 {
182 int dot = nodeId.lastIndexOf('.');
183 return (dot > 0) ? nodeId.substring(0, dot) : nodeId;
184 }
185
186 public String getNodeId(String clusterId, HttpServletRequest request)
187 {
188 if (_workerName != null) return clusterId + '.' + _workerName;
189 return clusterId;
190 }
191 }