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-2015 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 /** 045 * The SSL socket factory associated with the connector. 046 */ 047 private SSLSocketFactory sslSocketFactory; 048 049 /** 050 * Indicate if we required the client authentication via SSL. 051 */ 052 private final boolean needClientCertificate; 053 054 055 /** 056 * Constructs a new <code>DirectoryRMIServerSocketFactory</code> with the 057 * specified SSL socket configuration. 058 * 059 * @param sslSocketFactory 060 * the SSL socket factory to be used by this factory 061 * 062 * @param needClientCertificate 063 * <code>true</code> to require client authentication on SSL 064 * connections accepted by server sockets created by this 065 * factory; <code>false</code> to not require client 066 * authentication. 067 */ 068 public DirectoryRMIServerSocketFactory(SSLSocketFactory sslSocketFactory, 069 boolean needClientCertificate) 070 { 071 // Initialize the configuration parameters. 072 this.needClientCertificate = needClientCertificate; 073 this.sslSocketFactory = sslSocketFactory; 074 } 075 076 /** 077 * <p> 078 * Returns <code>true</code> if client authentication is required on SSL 079 * connections accepted by server sockets created by this factory. 080 * </p> 081 * 082 * @return <code>true</code> if client authentication is required 083 * 084 * @see SSLSocket#setNeedClientAuth 085 */ 086 public final boolean getNeedClientCertificate() 087 { 088 return needClientCertificate; 089 } 090 091 /** 092 * Creates a server socket that accepts SSL connections configured according 093 * to this factory's SSL socket configuration parameters. 094 * 095 * @param port 096 * the port number the socket listens to 097 * 098 * @return a server socket 099 * 100 * @throws IOException 101 * if the socket cannot be created 102 */ 103 public ServerSocket createServerSocket(int port) throws IOException 104 { 105 return new ServerSocket(port, 0, InetAddress.getByName("0.0.0.0")) 106 { 107 @Override 108 public Socket accept() throws IOException 109 { 110 Socket socket = super.accept(); 111 if (logger.isTraceEnabled()) 112 { 113 logger.trace("host/port: %s/%d", 114 socket.getInetAddress().getHostName(), socket.getPort()); 115 } 116 SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket( 117 socket, 118 socket.getInetAddress().getHostName(), 119 socket.getPort(), 120 true); 121 122 sslSocket.setUseClientMode(false); 123 sslSocket.setNeedClientAuth(needClientCertificate); 124 return sslSocket; 125 } 126 }; 127 128 } 129 130 /** 131 * <p> 132 * Indicates whether some other object is "equal to" this one. 133 * </p> 134 * 135 * <p> 136 * Two <code>CacaoRMIServerSocketFactory</code> objects are equal if they 137 * have been constructed with the same SSL socket configuration parameters. 138 * </p> 139 * 140 * <p> 141 * A subclass should override this method (as well as {@link #hashCode()}) 142 * if it adds instance state that affects equality. 143 * </p> 144 * 145 * @param obj the reference object with which to compare. 146 * 147 * @return <code>true</code> if this object is the same as the obj 148 * argument <code>false</code> otherwise. 149 */ 150 public boolean equals(Object obj) 151 { 152 if (obj == this) 153 { 154 return true; 155 } 156 if (!(obj instanceof DirectoryRMIServerSocketFactory)) 157 { 158 return false; 159 } 160 DirectoryRMIServerSocketFactory that = 161 (DirectoryRMIServerSocketFactory) obj; 162 return getClass().equals(that.getClass()) && checkParameters(that); 163 } 164 165 /** 166 * Checks if inputs parameters are OK. 167 * @param that the input parameter 168 * @return true or false. 169 */ 170 private boolean checkParameters(DirectoryRMIServerSocketFactory that) 171 { 172 return needClientCertificate == that.needClientCertificate 173 && sslSocketFactory.equals(that.sslSocketFactory); 174 } 175 176 /** 177 * <p>Returns a hash code value for this 178 * <code>CacaoRMIServerSocketFactory</code>.</p> 179 * 180 * @return a hash code value for this 181 * <code>CacaoRMIServerSocketFactory</code>. 182 */ 183 public int hashCode() 184 { 185 return getClass().hashCode() 186 + Boolean.valueOf(needClientCertificate).hashCode() 187 + sslSocketFactory.hashCode(); 188 } 189}