Source for gnu.javax.net.ssl.AbstractSessionContext

   1: /* AbstractSessionContext -- stores SSL sessions, possibly persistently.
   2:    Copyright (C) 2006  Free Software Foundation, Inc.
   3: 
   4: This file is a part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2 of the License, or (at
   9: your option) any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; if not, write to the Free Software
  18: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  19: USA
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version.  */
  37: 
  38: 
  39: package gnu.javax.net.ssl;
  40: 
  41: import gnu.java.security.Requires;
  42: 
  43: import gnu.javax.net.ssl.provider.SimpleSessionContext;
  44: 
  45: import java.util.Enumeration;
  46: 
  47: import javax.net.ssl.SSLException;
  48: import javax.net.ssl.SSLPermission;
  49: import javax.net.ssl.SSLSession;
  50: import javax.net.ssl.SSLSessionContext;
  51: 
  52: /**
  53:  * A skeletal implementation of {@link SSLSessionContext}. This class may
  54:  * be subclassed to add extended functionality to session contexts, such
  55:  * as by storing sessions in files on disk, or by sharing contexts
  56:  * across different JVM instances.
  57:  *
  58:  * <p>In order to securely store sessions, along with private key data,
  59:  * the abstract methods {@lnk {@link #load(char[])} and {@link #store(char[])}
  60:  * come into play. When storing sessions, a session context implementation
  61:  * must pass this password to the {@link Session#prepare(char[])} method,
  62:  * before either writing the {@link java.io.Serializable} session to the
  63:  * underlying store, or getting the opaque {@link Session#privateData()}
  64:  * class from the session, and storing that.
  65:  *
  66:  * <p>As a simple example, that writes sessions to some object output
  67:  * stream:
  68:  *
  69:  * <pre>
  70:   char[] password = ...;
  71:   ObjectOutputStream out = ...;
  72:   ...
  73:   for (Session s : this)
  74:     {
  75:       s.prepare(password);
  76:       out.writeObject(s);
  77:     }</pre>
  78:  *
  79:  * <p>The reverse must be done when deserializing sessions, by using the
  80:  * {@link Session#repair(char[])} method, possibly by first calling
  81:  * {@link Session#setPrivateData(java.io.Serializable)} with the read,
  82:  * opaque private data type. Thus an example of reading may be:
  83:  *
  84:  * <pre>
  85:   char[] password = ...;
  86:   ObjectInputStream in = ...;
  87:   ...
  88:   while (hasMoreSessions(in))
  89:     {
  90:       Session s = (Session) in.readObject();
  91:       s.repair(password);
  92:       addToThisStore(s);
  93:     }</pre>
  94:  *
  95:  * @author Casey Marshall (csm@gnu.org)
  96:  */
  97: public abstract class AbstractSessionContext implements SSLSessionContext
  98: {
  99:   protected long timeout;
 100:   private static Class<? extends AbstractSessionContext>
 101:     implClass = SimpleSessionContext.class;
 102: 
 103:   /**
 104:    * Create a new instance of a session context, according to the configured
 105:    * implementation class.
 106:    *
 107:    * @return The new session context.
 108:    * @throws SSLException If an error occurs in creating the instance.
 109:    */
 110:   public static AbstractSessionContext newInstance () throws SSLException
 111:   {
 112:     try
 113:       {
 114:         return implClass.newInstance();
 115:       }
 116:     catch (IllegalAccessException iae)
 117:       {
 118:         throw new SSLException(iae);
 119:       }
 120:     catch (InstantiationException ie)
 121:       {
 122:         throw new SSLException(ie);
 123:       }
 124:   }
 125: 
 126:   /**
 127:    * Reconfigure this instance to use a different session context
 128:    * implementation.
 129:    *
 130:    * <p><strong>Note:</strong> this method requires that the caller have
 131:    * {@link SSLPermission} with target
 132:    * <code>gnu.javax.net.ssl.AbstractSessionContext</code> and action
 133:    * <code>setImplClass</code>.
 134:    *
 135:    * @param clazz The new implementation class.
 136:    * @throws SecurityException If the caller does not have permission to
 137:    *  change the session context.
 138:    */
 139:   @Requires(permissionClass = SSLPermission.class,
 140:             target = "gnu.javax.net.ssl.AbstractSessionContext",
 141:             action = "setImplClass")
 142:   public static synchronized void setImplClass
 143:     (Class<? extends AbstractSessionContext> clazz)
 144:     throws SecurityException
 145:   {
 146:     SecurityManager sm = System.getSecurityManager ();
 147:     if (sm != null)
 148:       sm.checkPermission(new SSLPermission("gnu.javax.net.ssl.AbstractSessionContext",
 149:                                            "setImplClass"));
 150:     implClass = clazz;
 151:   }
 152: 
 153:   /**
 154:    * @param timeout The initial session timeout.
 155:    */
 156:   protected AbstractSessionContext (final int timeout)
 157:   {
 158:     setSessionTimeout(timeout);
 159:   }
 160: 
 161:   /**
 162:    * Fetch a saved session by its ID. This method will (possibly)
 163:    * deserialize and return the SSL session with that ID, or null if
 164:    * the requested session does not exist, or has expired.
 165:    *
 166:    * <p>Subclasses implementing this class <strong>must not</strong>
 167:    * perform any blocking operations in this method. If any blocking
 168:    * behavior is required, it must be done in the {@link load(char[])}
 169:    * method.
 170:    *
 171:    * @param sessionId The ID of the session to get.
 172:    * @return The found session, or null if no such session was found,
 173:    * or if that session has expired.
 174:    */
 175:   public final SSLSession getSession (byte[] sessionId)
 176:   {
 177:     Session s = implGet (sessionId);
 178:     if (s != null
 179:         && System.currentTimeMillis () - s.getLastAccessedTime () > timeout)
 180:       {
 181:         remove (sessionId);
 182:         return null;
 183:       }
 184:     return s;
 185:   }
 186: 
 187:   public final SSLSession getSession(String host, int port)
 188:   {
 189:     for (Enumeration e = getIds(); e.hasMoreElements(); )
 190:       {
 191:         byte[] id = (byte[]) e.nextElement();
 192:         SSLSession s = getSession(id);
 193:         if (s == null) // session expired.
 194:           continue;
 195:         String host2 = s.getPeerHost();
 196:         if (host == null)
 197:           {
 198:             if (host2 != null)
 199:               continue;
 200:           }
 201:         else if (!host.equals(host2))
 202:           continue;
 203:         int port2 = s.getPeerPort();
 204:         if (port != port2)
 205:           continue;
 206: 
 207:         // Else, a match.
 208:         return s;
 209:       }
 210: 
 211:     return null;
 212:   }
 213: 
 214:   /**
 215:    * To be implemented by subclasses. Subclasses do not need to check
 216:    * timeouts in this method.
 217:    *
 218:    * @param sessionId The session ID.
 219:    * @return The session, or <code>null</code> if the requested session
 220:    *  was not found.
 221:    */
 222:   protected abstract Session implGet (byte[] sessionId);
 223: 
 224:   public int getSessionTimeout()
 225:   {
 226:     return (int) (timeout / 1000);
 227:   }
 228: 
 229:   /**
 230:    * Load this session store from the underlying media, if supported
 231:    * by the implementation.
 232:    *
 233:    * @param password The password that protects the sensitive data in
 234:    * this store.
 235:    * @throws SessionStoreException If reading this store fails, such
 236:    * as when an I/O exception occurs, or if the password is incorrect.
 237:    */
 238:   public abstract void load (char[] password) throws SessionStoreException;
 239: 
 240:   /**
 241:    * Add a new session to the store. The underlying implementation
 242:    * will add the session to its store, possibly overwriting any
 243:    * existing session with the same ID.
 244:    *
 245:    * <p>Subclasses implementing this class <strong>must not</strong>
 246:    * perform any blocking operations in this method. If any blocking
 247:    * behavior is required, it must be done in the {@link
 248:    * #store(char[])} method.
 249:    *
 250:    * @param session The session to add.
 251:    * @throws NullPointerException If the argument is null.
 252:    */
 253:   public abstract void put (Session session);
 254: 
 255:   /**
 256:    * Remove a session from this store.
 257:    *
 258:    * <p>Subclasses implementing this class <strong>must not</strong>
 259:    * perform any blocking operations in this method. If any blocking
 260:    * behavior is required, it must be done in the {@link
 261:    * #store(char[])} method.
 262:    *
 263:    * @param sessionId The ID of the session to remove.
 264:    */
 265:   public abstract void remove (byte[] sessionId);
 266: 
 267:   /**
 268:    *
 269:    */
 270:   public final void setSessionTimeout(int seconds)
 271:   {
 272:     if (timeout < 0)
 273:       throw new IllegalArgumentException("timeout may not be negative");
 274:     this.timeout = (long) seconds * 1000;
 275:   }
 276: 
 277:   /**
 278:    * Commit this session store to the underlying media. For session
 279:    * store implementations that support saving sessions across
 280:    * invocations of the JVM, this method will save any sessions that
 281:    * have not expired to some persistent media, so they may be loaded
 282:    * and used again later.
 283:    *
 284:    * @param password The password that will protect the sensitive data
 285:    * in this store.
 286:    */
 287:   public abstract void store (char[] password) throws SessionStoreException;
 288: }