View Javadoc

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