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