AbstractSessionContext.java 9.3 KB

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