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