Imported GNU Classpath 0.90
[official-gcc.git] / libjava / classpath / gnu / javax / net / ssl / provider / JDBCSessionContext.java
blob2b9b14034252710a02e90a7bebdc753fc169667b
1 /* JDBCSessionContext.java -- database persistent sessions.
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is a part of GNU Classpath.
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.
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.
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
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.
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. */
39 package gnu.javax.net.ssl.provider;
41 import java.io.ByteArrayOutputStream;
42 import java.io.InputStream;
44 import java.security.SecureRandom;
45 import java.security.cert.Certificate;
46 import java.security.cert.CertificateFactory;
48 import java.sql.Connection;
49 import java.sql.DriverManager;
50 import java.sql.PreparedStatement;
51 import java.sql.ResultSet;
52 import java.sql.SQLException;
53 import java.sql.Statement;
54 import java.sql.Timestamp;
55 import java.sql.Types;
57 import java.util.ArrayList;
58 import java.util.Iterator;
59 import java.util.Enumeration;
60 import java.util.TreeSet;
61 import java.util.Vector;
63 import javax.net.ssl.SSLSession;
65 /**
66 * The SQL table this class stores sessions in, called <tt>SESSIONS</tt>,
67 * looks like this:
69 * <blockquote><pre>
70 * TABLE SESSIONS (
71 * ID VARBINARY(32) PRIMARY KEY UNIQUE NOT NULL,
72 * CREATED TIMESTAMP NOT NULL,
73 * LAST_ACCESSED TIMESTAMP NOT NULL,
74 * PROTOCOL VARCHAR(7) NOT NULL,
75 * SUITE VARCHAR(255) NOT NULL,
76 * PEER_HOST TEXT NOT NULL,
77 * PEER_CERT_TYPE VARCHAR(32),
78 * PEER_CERTS BLOB,
79 * CERT_TYPE VARCHAR(32),
80 * CERTS BLOB,
81 * SECRET VARBINARY(48) NOT NULL
82 * )
83 * </pre></blockquote>
85 * <p>Note that the master secret for sessions is not protected before
86 * being inserted into the database; it is up to the system to protect
87 * the stored data from unauthorized access.
89 class JDBCSessionContext extends SessionContext
92 // Fields.
93 // -------------------------------------------------------------------------
95 protected Connection connection;
96 protected PreparedStatement selectById;
97 protected PreparedStatement insert;
98 protected PreparedStatement selectTimestamp;
99 protected PreparedStatement updateTimestamp;
100 protected PreparedStatement deleteSession;
102 // Constructor.
103 // -------------------------------------------------------------------------
105 JDBCSessionContext() throws SQLException
107 String url = Util.getSecurityProperty("jessie.SessionContext.jdbc.url");
108 String user = Util.getSecurityProperty("jessie.SessionContext.jdbc.user");
109 String passwd = Util.getSecurityProperty("jessie.SessionContext.jdbc.password");
110 if (url == null)
112 throw new IllegalArgumentException("no JDBC URL");
114 if (user == null || passwd == null)
116 connection = DriverManager.getConnection(url);
118 else
120 connection = DriverManager.getConnection(url, user, passwd);
122 selectById =
123 connection.prepareStatement("SELECT * FROM SESSIONS WHERE ID = ?");
124 insert = connection.prepareStatement("INSERT INTO SESSIONS VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
125 selectTimestamp =
126 connection.prepareStatement("SELECT CREATED FROM SESSIONS WHERE ID = ?");
127 updateTimestamp =
128 connection.prepareStatement("UPDATE SESSIONS SET LAST_ACCESSED = ? WHERE ID = ?");
129 deleteSession =
130 connection.prepareStatement("DELETE FROM SESSIONS WHERE ID = ?");
133 // Instance methods.
134 // -------------------------------------------------------------------------
136 public synchronized Enumeration getIds()
138 Vector ids = new Vector();
141 Statement stmt = connection.createStatement();
142 ResultSet rs = stmt.executeQuery("SELECT ID FROM SESSIONS");
143 while (rs.next())
145 byte[] id = rs.getBytes("ID");
146 ids.add(id);
149 catch (SQLException sqle)
152 return ids.elements();
155 public synchronized SSLSession getSession(byte[] sessionId)
157 Session session = (Session) super.getSession(sessionId);
158 if (session == null)
162 selectById.setBytes(1, sessionId);
163 ResultSet rs = selectById.executeQuery();
164 if (rs.next())
166 session = new Session(rs.getTimestamp("CREATED").getTime());
167 session.enabledSuites = new ArrayList(SSLSocket.supportedSuites);
168 session.enabledProtocols = new TreeSet(SSLSocket.supportedProtocols);
169 session.random = new SecureRandom();
170 session.context = this;
171 session.sessionId = new Session.ID(rs.getBytes("ID"));
172 session.setLastAccessedTime(rs.getTimestamp("LAST_ACCESSED").getTime());
173 long elapsed = System.currentTimeMillis() - session.getLastAccessedTime();
174 if ((int) (elapsed / 1000L) > timeout)
176 removeSession(session.sessionId);
177 return null;
179 session.peerHost = rs.getString("PEER_HOST");
180 String protocol = rs.getString("PROTOCOL");
181 if (protocol.equals("SSLv3"))
183 session.protocol = ProtocolVersion.SSL_3;
185 else if (protocol.equals("TLSv1"))
187 session.protocol = ProtocolVersion.TLS_1;
189 else if (protocol.equals("TLSv1.1"))
191 session.protocol = ProtocolVersion.TLS_1_1;
193 else
195 return null;
197 session.cipherSuite = CipherSuite.forName(rs.getString("SUITE"));
198 String type = rs.getString("PEER_CERT_TYPE");
199 boolean wasNull = rs.wasNull();
200 InputStream certs = null;
201 if (!wasNull)
203 certs = rs.getBinaryStream("PEER_CERTS");
204 wasNull = rs.wasNull();
206 if (!wasNull)
208 CertificateFactory cf = CertificateFactory.getInstance(type);
209 session.peerCerts = (Certificate[])
210 cf.generateCertificates(certs).toArray(new Certificate[0]);
211 session.peerVerified = true;
213 type = rs.getString("CERT_TYPE");
214 wasNull = rs.wasNull();
215 if (!wasNull)
217 certs = rs.getBinaryStream("CERTS");
218 wasNull = rs.wasNull();
220 if (!wasNull)
222 CertificateFactory cf = CertificateFactory.getInstance(type);
223 session.localCerts = (Certificate[])
224 cf.generateCertificates(certs).toArray(new Certificate[0]);
226 session.masterSecret = rs.getBytes("SECRET");
227 if (cacheSize == 0 || sessions.size() < cacheSize)
229 sessions.put(session.sessionId, session);
233 catch (Exception ex)
237 return session;
240 synchronized boolean addSession(Session.ID id, Session s)
242 if (containsSessionID(id))
244 return false;
248 insert.setBytes(1, id.getId());
249 insert.setTimestamp(2, new Timestamp(s.getCreationTime()));
250 insert.setTimestamp(3, new Timestamp(s.getLastAccessedTime()));
251 insert.setString(4, s.getProtocol());
252 insert.setString(5, s.getCipherSuite());
253 insert.setString(6, s.peerHost);
254 if (s.peerCerts != null && s.peerCerts.length > 0)
256 insert.setString(7, s.peerCerts[0].getType());
257 insert.setBytes(8, certs(s.peerCerts));
259 else
261 insert.setNull(7, Types.VARCHAR);
262 insert.setNull(8, Types.LONGVARBINARY);
264 if (s.localCerts != null && s.localCerts.length > 0)
266 insert.setString(9, s.localCerts[0].getType());
267 insert.setBytes(10, certs(s.localCerts));
269 else
271 insert.setNull(9, Types.VARCHAR);
272 insert.setNull(10, Types.LONGVARBINARY);
274 insert.setBytes(11, s.masterSecret);
275 insert.executeUpdate();
276 super.addSession(id, s);
278 catch (SQLException sqle)
280 return false;
282 return true;
285 synchronized boolean containsSessionID(Session.ID sessionId)
289 selectTimestamp.setBytes(1, sessionId.getId());
290 ResultSet rs = selectTimestamp.executeQuery();
291 if (!rs.next())
293 return false;
295 Timestamp ts = rs.getTimestamp("CREATED");
296 if (rs.wasNull())
298 return false;
300 long elapsed = System.currentTimeMillis() - ts.getTime();
301 if ((int) (elapsed / 1000) > timeout)
303 removeSession(sessionId);
304 return false;
306 return true;
308 catch (SQLException sqle)
310 return false;
314 protected boolean removeSession(Session.ID sessionId)
316 super.removeSession(sessionId);
319 deleteSession.setBytes(1, sessionId.getId());
320 return deleteSession.executeUpdate() > 0;
322 catch (SQLException sqle)
325 return false;
328 synchronized void notifyAccess(Session session)
332 updateTimestamp.setTimestamp(1, new Timestamp(session.getLastAccessedTime()));
333 updateTimestamp.setBytes(2, session.getId());
334 updateTimestamp.executeUpdate();
336 catch (SQLException sqle)
341 private byte[] certs(Certificate[] certs)
343 ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
344 for (int i = 0; i < certs.length; i++)
348 out.write(certs[i].getEncoded());
350 catch (Exception x)
354 return out.toByteArray();