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 }