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