Frames | No Frames |
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: }