1   package org.mortbay.jetty.servlet;
2   
3   import java.security.NoSuchAlgorithmException;
4   import java.security.SecureRandom;
5   import java.util.Random;
6   
7   import javax.servlet.http.HttpServletRequest;
8   import javax.servlet.http.HttpSession;
9   
10  import org.mortbay.component.AbstractLifeCycle;
11  import org.mortbay.jetty.Server;
12  import org.mortbay.jetty.SessionIdManager;
13  import org.mortbay.log.Log;
14  
15  public abstract class AbstractSessionIdManager extends AbstractLifeCycle implements SessionIdManager
16  {
17      private final static String __NEW_SESSION_ID="org.mortbay.jetty.newSessionId";  
18      protected final static String SESSION_ID_RANDOM_ALGORITHM = "SHA1PRNG";
19      protected final static String SESSION_ID_RANDOM_ALGORITHM_ALT = "IBMSecureRandom";
20      
21      protected Random _random;
22      protected boolean _weakRandom;
23      protected String _workerName;
24      protected Server _server;
25      
26      
27      public AbstractSessionIdManager(Server server)
28      {
29          _server=server;
30      }
31      
32      
33      public AbstractSessionIdManager(Server server, Random random)
34      {
35          _random=random;
36          _server=server;
37      }
38  
39      public String getWorkerName()
40      {
41          return _workerName;
42      }
43      
44      public void setWorkerName (String name)
45      {
46          _workerName=name;
47      }
48  
49      /* ------------------------------------------------------------ */
50      public Random getRandom()
51      {
52          return _random;
53      }
54  
55      /* ------------------------------------------------------------ */
56      public void setRandom(Random random)
57      {
58          _random=random;
59          _weakRandom=false;
60      }
61      /** 
62       * Create a new session id if necessary.
63       * 
64       * @see org.mortbay.jetty.SessionIdManager#newSessionId(javax.servlet.http.HttpServletRequest, long)
65       */
66      public String newSessionId(HttpServletRequest request, long created)
67      {
68          synchronized (this)
69          {
70              // A requested session ID can only be used if it is in use already.
71              String requested_id=request.getRequestedSessionId();
72              if (requested_id!=null)
73              {
74                  String cluster_id=getClusterId(requested_id);
75                  if (idInUse(cluster_id))
76                      return cluster_id;
77              }
78            
79              // Else reuse any new session ID already defined for this request.
80              String new_id=(String)request.getAttribute(__NEW_SESSION_ID);
81              if (new_id!=null&&idInUse(new_id))
82                  return new_id;
83  
84              
85              
86              // pick a new unique ID!
87              String id=null;
88              while (id==null||id.length()==0||idInUse(id))
89              {
90                  long r=_weakRandom
91                  ?(hashCode()^Runtime.getRuntime().freeMemory()^_random.nextInt()^(((long)request.hashCode())<<32))
92                  :_random.nextLong();
93                  r^=created;
94                  if (request!=null && request.getRemoteAddr()!=null)
95                      r^=request.getRemoteAddr().hashCode();
96                  if (r<0)
97                      r=-r;
98                  id=Long.toString(r,36);
99                  
100                 //add in the id of the node to ensure unique id across cluster
101                 //NOTE this is different to the node suffix which denotes which node the request was received on
102                 id=_workerName + id;
103             }
104 
105             request.setAttribute(__NEW_SESSION_ID,id);
106             return id;
107         }
108     }
109 
110     
111     public void doStart()
112     {
113        initRandom();
114     }
115 
116     
117     
118     
119     /**
120      * Set up a random number generator for the sessionids.
121      * 
122      * By preference, use a SecureRandom but allow to be injected.
123      */
124     public void initRandom ()
125     {
126         if (_random==null)
127         {
128             try
129             {
130                 _random=SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM);
131             }
132             catch (NoSuchAlgorithmException e)
133             {
134                 try
135                 {
136                     _random=SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM_ALT);
137                     _weakRandom=false;
138                 }
139                 catch (NoSuchAlgorithmException e_alt)
140                 {
141                     Log.warn("Could not generate SecureRandom for session-id randomness",e);
142                     _random=new Random();
143                     _weakRandom=true;
144                 }
145             }
146         }
147         _random.setSeed(_random.nextLong()^System.currentTimeMillis()^hashCode()^Runtime.getRuntime().freeMemory()); 
148     }
149 }