View Javadoc

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