001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2008 Sun Microsystems, Inc.
026 */
027
028 package org.opends.server.replication.protocol;
029
030 import static org.opends.server.loggers.ErrorLogger.logError;
031 import static org.opends.messages.ReplicationMessages.*;
032
033 import org.opends.messages.Message;
034 import org.opends.server.admin.std.server.ReplicationServerCfg;
035 import org.opends.server.admin.std.server.ReplicationDomainCfg;
036 import org.opends.server.types.DirectoryConfig;
037 import org.opends.server.types.CryptoManager;
038 import org.opends.server.config.ConfigException;
039
040 import javax.net.ssl.SSLException;
041 import javax.net.ssl.SSLSocket;
042 import javax.net.ssl.SSLContext;
043 import javax.net.ssl.SSLSocketFactory;
044 import java.util.SortedSet;
045 import java.net.Socket;
046 import java.net.InetAddress;
047 import java.io.IOException;
048
049 /**
050 * This class represents the security configuration for replication protocol
051 * sessions. It contains all the configuration required to use SSL, and it
052 * determines whether encryption should be enabled for a session to a given
053 * replication server.
054 *
055 */
056 public class ReplSessionSecurity
057 {
058 /**
059 * Whether the replication server should listen on a secure port.
060 * Set false for test purposes only.
061 */
062 private static boolean useSSL = true;
063
064 /**
065 * Whether replication sessions use SSL encryption.
066 */
067 private boolean sslEncryption;
068
069 /**
070 * The name of the local certificate to use, or null if none is specified.
071 */
072 private String sslCertNickname;
073
074 /**
075 * The set of enabled SSL protocols, or null for the default set.
076 */
077 private String sslProtocols[];
078
079 /**
080 * The set of enabled SSL cipher suites, or null for the default set.
081 */
082 private String sslCipherSuites[];
083
084 /**
085 * Create a ReplSessionSecurity instance from the supplied configuration
086 * values.
087 *
088 * @param sslCertNickname The name of the local certificate to use, or null
089 * if none is specified.
090 * @param sslProtocols The protocols that should be enabled, or null if
091 * the default protocols should be used.
092 * @param sslCipherSuites The cipher suites that should be enabled, or null
093 * if the default cipher suites should be used.
094 * @param sslEncryption Whether replication sessions use SSL encryption.
095 *
096 * @throws ConfigException If the supplied configuration was not valid.
097 */
098 public ReplSessionSecurity(String sslCertNickname,
099 SortedSet<String> sslProtocols,
100 SortedSet<String> sslCipherSuites,
101 boolean sslEncryption)
102 throws ConfigException
103 {
104 if (sslProtocols == null || sslProtocols.size() == 0)
105 {
106 this.sslProtocols = null;
107 }
108 else
109 {
110 this.sslProtocols = new String[sslProtocols.size()];
111 sslProtocols.toArray(this.sslProtocols);
112 }
113
114 if (sslCipherSuites == null || sslCipherSuites.size() == 0)
115 {
116 this.sslCipherSuites = null;
117 }
118 else
119 {
120 this.sslCipherSuites = new String[sslProtocols.size()];
121 sslProtocols.toArray(this.sslCipherSuites);
122 }
123
124 this.sslEncryption = sslEncryption;
125 this.sslCertNickname = sslCertNickname;
126 }
127
128 /**
129 * Create a ReplSessionSecurity instance from a provided replication server
130 * configuration.
131 *
132 * @param replServerCfg The replication server configuration.
133 *
134 * @throws ConfigException If the supplied configuration was not valid.
135 */
136 public ReplSessionSecurity(ReplicationServerCfg replServerCfg)
137 throws ConfigException
138 {
139 // Currently use global settings from the crypto manager.
140 this(DirectoryConfig.getCryptoManager().getSslCertNickname(),
141 DirectoryConfig.getCryptoManager().getSslProtocols(),
142 DirectoryConfig.getCryptoManager().getSslCipherSuites(),
143 DirectoryConfig.getCryptoManager().isSslEncryption());
144 }
145
146 /**
147 * Create a ReplSessionSecurity instance from a provided multimaster domain
148 * configuration.
149 *
150 * @param multimasterDomainCfg The multimaster domain configuration.
151 *
152 * @throws ConfigException If the supplied configuration was not valid.
153 */
154 public ReplSessionSecurity(ReplicationDomainCfg multimasterDomainCfg)
155 throws ConfigException
156 {
157 // Currently use global settings from the crypto manager.
158 this(DirectoryConfig.getCryptoManager().getSslCertNickname(),
159 DirectoryConfig.getCryptoManager().getSslProtocols(),
160 DirectoryConfig.getCryptoManager().getSslCipherSuites(),
161 DirectoryConfig.getCryptoManager().isSslEncryption());
162 }
163
164 /**
165 * Determine whether a given replication server is listening on a secure
166 * port.
167 * @param serverURL The replication server URL.
168 * @return true if the given replication server is listening on a secure
169 * port, or false if it is listening on a non-secure port.
170 */
171 private boolean isSecurePort(String serverURL)
172 {
173 // Always true unless changed for test purposes.
174 return useSSL;
175 }
176
177 /**
178 * Determine whether sessions to a given replication server should be
179 * encrypted.
180 * @param serverURL The replication server URL.
181 * @return true if sessions to the given replication server should be
182 * encrypted, or false if they should not be encrypted.
183 */
184 public boolean isSslEncryption(String serverURL)
185 {
186 // Currently use global settings from the crypto manager.
187 return sslEncryption;
188 }
189
190 /**
191 * Create a new protocol session in the client role on the provided socket.
192 * @param serverURL The remote replication server to which the socket is
193 * connected.
194 * @param socket The connected socket.
195 * @return The new protocol session.
196 * @throws ConfigException If the protocol session could not be established
197 * due to a configuration problem.
198 * @throws IOException If the protocol session could not be established
199 * for some other reason.
200 */
201 public ProtocolSession createClientSession(String serverURL, Socket socket)
202 throws ConfigException, IOException
203 {
204 boolean useSSL = isSecurePort(serverURL);
205 if (useSSL)
206 {
207 // Create a new SSL context every time to make sure we pick up the
208 // latest contents of the trust store.
209 CryptoManager cryptoManager = DirectoryConfig.getCryptoManager();
210 SSLContext sslContext = cryptoManager.getSslContext(sslCertNickname);
211 SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
212
213 SSLSocket secureSocket = (SSLSocket) sslSocketFactory.createSocket(socket,
214 socket.getInetAddress().getHostName(),
215 socket.getPort(), false);
216 secureSocket.setUseClientMode(true);
217
218 if (sslProtocols != null)
219 {
220 secureSocket.setEnabledProtocols(sslProtocols);
221 }
222
223 if (sslCipherSuites != null)
224 {
225 secureSocket.setEnabledCipherSuites(sslCipherSuites);
226 }
227
228 // Force TLS negotiation now.
229 secureSocket.startHandshake();
230
231 return new TLSSocketSession(socket, secureSocket);
232 }
233 else
234 {
235 return new SocketSession(socket);
236 }
237 }
238
239 /**
240 * Create a new protocol session in the server role on the provided socket.
241 * @param socket The connected socket.
242 * @return The new protocol session.
243 * @throws ConfigException If the protocol session could not be established
244 * due to a configuration problem.
245 * @throws IOException If the protocol session could not be established
246 * for some other reason.
247 */
248 public ProtocolSession createServerSession(Socket socket)
249 throws ConfigException, IOException
250 {
251 if (useSSL)
252 {
253 try
254 {
255 // Create a new SSL context every time to make sure we pick up the
256 // latest contents of the trust store.
257 CryptoManager cryptoManager = DirectoryConfig.getCryptoManager();
258 SSLContext sslContext = cryptoManager.getSslContext(sslCertNickname);
259 SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
260
261 SSLSocket secureSocket = (SSLSocket)
262 sslSocketFactory.createSocket(socket,
263 socket.getInetAddress().getHostName(),
264 socket.getPort(), false);
265 secureSocket.setUseClientMode(false);
266 secureSocket.setNeedClientAuth(true);
267
268 if (sslProtocols != null)
269 {
270 secureSocket.setEnabledProtocols(sslProtocols);
271 }
272
273 if (sslCipherSuites != null)
274 {
275 secureSocket.setEnabledCipherSuites(sslCipherSuites);
276 }
277
278 // Force TLS negotiation now.
279 secureSocket.startHandshake();
280
281 // SSLSession sslSession = secureSocket.getSession();
282 // System.out.println("Peer = " + sslSession.getPeerHost() + ":" +
283 // sslSession.getPeerPort());
284 // System.out.println("Principal = " + sslSession.getPeerPrincipal());
285
286 return new TLSSocketSession(socket, secureSocket);
287 } catch (SSLException e)
288 {
289 // This is probably a connection attempt from an unexpected client
290 // log that to warn the administrator.
291 InetAddress remHost = socket.getInetAddress();
292 Message message = NOTE_SSL_SERVER_CON_ATTEMPT_ERROR.get(remHost.
293 getHostName(), remHost.getHostAddress(), e.getLocalizedMessage());
294 logError(message);
295 return null;
296 }
297 } else
298 {
299 return new SocketSession(socket);
300 }
301 }
302
303 }