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