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 }