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.SecureRandom;
17  import java.util.Random;
18  
19  import javax.servlet.http.HttpServletRequest;
20  
21  import org.eclipse.jetty.http.security.B64Code;
22  import org.eclipse.jetty.server.SessionIdManager;
23  import org.eclipse.jetty.util.component.AbstractLifeCycle;
24  import org.eclipse.jetty.util.log.Log;
25  
26  public abstract class AbstractSessionIdManager extends AbstractLifeCycle implements SessionIdManager
27  {
28      private final static String __NEW_SESSION_ID="org.eclipse.jetty.server.newSessionId";  
29      
30      protected Random _random;
31      protected boolean _weakRandom;
32      protected String _workerName;
33      
34      /* ------------------------------------------------------------ */
35      public AbstractSessionIdManager()
36      {
37      }
38      
39      /* ------------------------------------------------------------ */
40      public AbstractSessionIdManager(Random random)
41      {
42          _random=random;
43      }
44  
45  
46      /* ------------------------------------------------------------ */
47      /**
48       * Get the workname. If set, the workername is dot appended to the session
49       * ID and can be used to assist session affinity in a load balancer.
50       * 
51       * @return String or null
52       */
53      public String getWorkerName()
54      {
55          return _workerName;
56      }
57  
58      /* ------------------------------------------------------------ */
59      /**
60       * Set the workname. If set, the workername is dot appended to the session
61       * ID and can be used to assist session affinity in a load balancer.
62       * 
63       * @param workerName
64       */
65      public void setWorkerName(String workerName)
66      {
67          _workerName=workerName;
68      }
69  
70      /* ------------------------------------------------------------ */
71      public Random getRandom()
72      {
73          return _random;
74      }
75  
76      /* ------------------------------------------------------------ */
77      public void setRandom(Random random)
78      {
79          _random=random;
80          _weakRandom=false;
81      }
82      
83      /* ------------------------------------------------------------ */
84      /** 
85       * Create a new session id if necessary.
86       * 
87       * @see org.eclipse.jetty.server.SessionIdManager#newSessionId(javax.servlet.http.HttpServletRequest, long)
88       */
89      public String newSessionId(HttpServletRequest request, long created)
90      {
91          synchronized (this)
92          {
93              // A requested session ID can only be used if it is in use already.
94              String requested_id=request.getRequestedSessionId();
95              if (requested_id!=null)
96              {
97                  String cluster_id=getClusterId(requested_id);
98                  if (idInUse(cluster_id))
99                      return cluster_id;
100             }
101           
102             // Else reuse any new session ID already defined for this request.
103             String new_id=(String)request.getAttribute(__NEW_SESSION_ID);
104             if (new_id!=null&&idInUse(new_id))
105                 return new_id;
106 
107             // pick a new unique ID!
108             String id=null;
109             while (id==null||id.length()==0||idInUse(id))
110             {
111                 long r0=_weakRandom
112                 ?(hashCode()^Runtime.getRuntime().freeMemory()^_random.nextInt()^(((long)request.hashCode())<<32))
113                 :_random.nextLong();
114                 if (r0<0)
115                     r0=-r0;
116                 long r1=_weakRandom
117                 ?(hashCode()^Runtime.getRuntime().freeMemory()^_random.nextInt()^(((long)request.hashCode())<<32))
118                 :_random.nextLong();
119                 if (r1<0)
120                     r1=-r1;
121                 id=Long.toString(r0,36)+Long.toString(r1,36);
122                 
123                 //add in the id of the node to ensure unique id across cluster
124                 //NOTE this is different to the node suffix which denotes which node the request was received on
125                 if (_workerName!=null)
126                     id=_workerName + id;
127             }
128 
129             request.setAttribute(__NEW_SESSION_ID,id);
130             return id;
131         }
132     }
133 
134     /* ------------------------------------------------------------ */
135     @Override
136     protected void doStart() throws Exception
137     {
138        initRandom();
139     }
140     
141     /* ------------------------------------------------------------ */
142     @Override
143     protected void doStop() throws Exception
144     {
145     }
146     
147     /* ------------------------------------------------------------ */
148     /**
149      * Set up a random number generator for the sessionids.
150      * 
151      * By preference, use a SecureRandom but allow to be injected.
152      */
153     public void initRandom ()
154     {
155         if (_random==null)
156         {
157             try
158             {
159                 _random=new SecureRandom();
160             }
161             catch (Exception e)
162             {
163                 Log.warn("Could not generate SecureRandom for session-id randomness",e);
164                 _random=new Random();
165                 _weakRandom=true;
166             }
167         }
168         _random.setSeed(_random.nextLong()^System.currentTimeMillis()^hashCode()^Runtime.getRuntime().freeMemory()); 
169     }
170 }