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 legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2008 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027package org.opends.server.protocols.jmx; 028 029import org.forgerock.i18n.slf4j.LocalizedLogger; 030 031import java.io.IOException; 032import java.net.InetAddress; 033import java.net.ServerSocket; 034import java.net.Socket; 035import java.rmi.server.RMIServerSocketFactory; 036 037import javax.net.ssl.SSLSocket; 038import javax.net.ssl.SSLSocketFactory; 039 040/** 041 * A <code>DirectoryRMIServerSocketFactory</code> instance is used by the RMI 042 * runtime in order to obtain server sockets for RMI calls via SSL. 043 * 044 * <p> 045 * This class implements <code>RMIServerSocketFactory</code> over the Secure 046 * Sockets Layer (SSL) or Transport Layer Security (TLS) protocols. 047 * </p> 048 */ 049public class DirectoryRMIServerSocketFactory implements 050 RMIServerSocketFactory 051{ 052 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 053 054 /** 055 * The SSL socket factory associated with the connector. 056 */ 057 private SSLSocketFactory sslSocketFactory; 058 059 /** 060 * Indicate if we required the client authentication via SSL. 061 */ 062 private final boolean needClientCertificate; 063 064 065 /** 066 * Constructs a new <code>DirectoryRMIServerSocketFactory</code> with the 067 * specified SSL socket configuration. 068 * 069 * @param sslSocketFactory 070 * the SSL socket factory to be used by this factory 071 * 072 * @param needClientCertificate 073 * <code>true</code> to require client authentication on SSL 074 * connections accepted by server sockets created by this 075 * factory; <code>false</code> to not require client 076 * authentication. 077 */ 078 public DirectoryRMIServerSocketFactory(SSLSocketFactory sslSocketFactory, 079 boolean needClientCertificate) 080 { 081 // Initialize the configuration parameters. 082 this.needClientCertificate = needClientCertificate; 083 this.sslSocketFactory = sslSocketFactory; 084 } 085 086 /** 087 * <p> 088 * Returns <code>true</code> if client authentication is required on SSL 089 * connections accepted by server sockets created by this factory. 090 * </p> 091 * 092 * @return <code>true</code> if client authentication is required 093 * 094 * @see SSLSocket#setNeedClientAuth 095 */ 096 public final boolean getNeedClientCertificate() 097 { 098 return needClientCertificate; 099 } 100 101 /** 102 * Creates a server socket that accepts SSL connections configured according 103 * to this factory's SSL socket configuration parameters. 104 * 105 * @param port 106 * the port number the socket listens to 107 * 108 * @return a server socket 109 * 110 * @throws IOException 111 * if the socket cannot be created 112 */ 113 public ServerSocket createServerSocket(int port) throws IOException 114 { 115 return new ServerSocket(port, 0, InetAddress.getByName("0.0.0.0")) 116 { 117 @Override 118 public Socket accept() throws IOException 119 { 120 Socket socket = super.accept(); 121 if (logger.isTraceEnabled()) 122 { 123 logger.trace("host/port: %s/%d", 124 socket.getInetAddress().getHostName(), socket.getPort()); 125 } 126 SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket( 127 socket, 128 socket.getInetAddress().getHostName(), 129 socket.getPort(), 130 true); 131 132 sslSocket.setUseClientMode(false); 133 sslSocket.setNeedClientAuth(needClientCertificate); 134 return sslSocket; 135 } 136 }; 137 138 } 139 140 /** 141 * <p> 142 * Indicates whether some other object is "equal to" this one. 143 * </p> 144 * 145 * <p> 146 * Two <code>CacaoRMIServerSocketFactory</code> objects are equal if they 147 * have been constructed with the same SSL socket configuration parameters. 148 * </p> 149 * 150 * <p> 151 * A subclass should override this method (as well as {@link #hashCode()}) 152 * if it adds instance state that affects equality. 153 * </p> 154 * 155 * @param obj the reference object with which to compare. 156 * 157 * @return <code>true</code> if this object is the same as the obj 158 * argument <code>false</code> otherwise. 159 */ 160 public boolean equals(Object obj) 161 { 162 if (obj == this) 163 { 164 return true; 165 } 166 if (!(obj instanceof DirectoryRMIServerSocketFactory)) 167 { 168 return false; 169 } 170 DirectoryRMIServerSocketFactory that = 171 (DirectoryRMIServerSocketFactory) obj; 172 return getClass().equals(that.getClass()) && checkParameters(that); 173 } 174 175 /** 176 * Checks if inputs parameters are OK. 177 * @param that the input parameter 178 * @return true or false. 179 */ 180 private boolean checkParameters(DirectoryRMIServerSocketFactory that) 181 { 182 return needClientCertificate == that.needClientCertificate 183 && sslSocketFactory.equals(that.sslSocketFactory); 184 } 185 186 /** 187 * <p>Returns a hash code value for this 188 * <code>CacaoRMIServerSocketFactory</code>.</p> 189 * 190 * @return a hash code value for this 191 * <code>CacaoRMIServerSocketFactory</code>. 192 */ 193 public int hashCode() 194 { 195 return getClass().hashCode() 196 + Boolean.valueOf(needClientCertificate).hashCode() 197 + sslSocketFactory.hashCode(); 198 } 199}