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