Path: blob/master/src/java.rmi/share/classes/javax/rmi/ssl/SslRMIServerSocketFactory.java
41171 views
/*1* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.rmi.ssl;2627import java.io.IOException;28import java.net.ServerSocket;29import java.net.Socket;30import java.rmi.server.RMIServerSocketFactory;31import java.util.Arrays;32import java.util.List;33import javax.net.ssl.SSLContext;34import javax.net.ssl.SSLServerSocketFactory;35import javax.net.ssl.SSLSocket;36import javax.net.ssl.SSLSocketFactory;3738/**39* <p>An <code>SslRMIServerSocketFactory</code> instance is used by the RMI40* runtime in order to obtain server sockets for RMI calls via SSL.</p>41*42* <p>This class implements <code>RMIServerSocketFactory</code> over43* the Secure Sockets Layer (SSL) or Transport Layer Security (TLS)44* protocols.</p>45*46* <p>This class creates SSL sockets using the default47* <code>SSLSocketFactory</code> (see {@link48* SSLSocketFactory#getDefault}) or the default49* <code>SSLServerSocketFactory</code> (see {@link50* SSLServerSocketFactory#getDefault}) unless the51* constructor taking an <code>SSLContext</code> is52* used in which case the SSL sockets are created using53* the <code>SSLSocketFactory</code> returned by54* {@link SSLContext#getSocketFactory} or the55* <code>SSLServerSocketFactory</code> returned by56* {@link SSLContext#getServerSocketFactory}.57*58* When an <code>SSLContext</code> is not supplied all the instances of this59* class share the same keystore, and the same truststore (when client60* authentication is required by the server). This behavior can be modified61* by supplying an already initialized <code>SSLContext</code> instance.62*63* @see javax.net.ssl.SSLSocketFactory64* @see javax.net.ssl.SSLServerSocketFactory65* @see javax.rmi.ssl.SslRMIClientSocketFactory66* @since 1.567*/68public class SslRMIServerSocketFactory implements RMIServerSocketFactory {6970/**71* <p>Creates a new <code>SslRMIServerSocketFactory</code> with72* the default SSL socket configuration.</p>73*74* <p>SSL connections accepted by server sockets created by this75* factory have the default cipher suites and protocol versions76* enabled and do not require client authentication.</p>77*/78public SslRMIServerSocketFactory() {79this(null, null, false);80}8182/**83* <p>Creates a new <code>SslRMIServerSocketFactory</code> with84* the specified SSL socket configuration.</p>85*86* @param enabledCipherSuites names of all the cipher suites to87* enable on SSL connections accepted by server sockets created by88* this factory, or <code>null</code> to use the cipher suites89* that are enabled by default90*91* @param enabledProtocols names of all the protocol versions to92* enable on SSL connections accepted by server sockets created by93* this factory, or <code>null</code> to use the protocol versions94* that are enabled by default95*96* @param needClientAuth <code>true</code> to require client97* authentication on SSL connections accepted by server sockets98* created by this factory; <code>false</code> to not require99* client authentication100*101* @exception IllegalArgumentException when one or more of the cipher102* suites named by the <code>enabledCipherSuites</code> parameter is103* not supported, when one or more of the protocols named by the104* <code>enabledProtocols</code> parameter is not supported or when105* a problem is encountered while trying to check if the supplied106* cipher suites and protocols to be enabled are supported.107*108* @see SSLSocket#setEnabledCipherSuites109* @see SSLSocket#setEnabledProtocols110* @see SSLSocket#setNeedClientAuth111*/112public SslRMIServerSocketFactory(113String[] enabledCipherSuites,114String[] enabledProtocols,115boolean needClientAuth)116throws IllegalArgumentException {117this(null, enabledCipherSuites, enabledProtocols, needClientAuth);118}119120/**121* <p>Creates a new <code>SslRMIServerSocketFactory</code> with the122* specified <code>SSLContext</code> and SSL socket configuration.</p>123*124* @param context the SSL context to be used for creating SSL sockets.125* If <code>context</code> is null the default <code>SSLSocketFactory</code>126* or the default <code>SSLServerSocketFactory</code> will be used to127* create SSL sockets. Otherwise, the socket factory returned by128* <code>SSLContext.getSocketFactory()</code> or129* <code>SSLContext.getServerSocketFactory()</code> will be used instead.130*131* @param enabledCipherSuites names of all the cipher suites to132* enable on SSL connections accepted by server sockets created by133* this factory, or <code>null</code> to use the cipher suites134* that are enabled by default135*136* @param enabledProtocols names of all the protocol versions to137* enable on SSL connections accepted by server sockets created by138* this factory, or <code>null</code> to use the protocol versions139* that are enabled by default140*141* @param needClientAuth <code>true</code> to require client142* authentication on SSL connections accepted by server sockets143* created by this factory; <code>false</code> to not require144* client authentication145*146* @exception IllegalArgumentException when one or more of the cipher147* suites named by the <code>enabledCipherSuites</code> parameter is148* not supported, when one or more of the protocols named by the149* <code>enabledProtocols</code> parameter is not supported or when150* a problem is encountered while trying to check if the supplied151* cipher suites and protocols to be enabled are supported.152*153* @see SSLSocket#setEnabledCipherSuites154* @see SSLSocket#setEnabledProtocols155* @see SSLSocket#setNeedClientAuth156* @since 1.7157*/158public SslRMIServerSocketFactory(159SSLContext context,160String[] enabledCipherSuites,161String[] enabledProtocols,162boolean needClientAuth)163throws IllegalArgumentException {164// Initialize the configuration parameters.165//166this.enabledCipherSuites = enabledCipherSuites == null ?167null : enabledCipherSuites.clone();168this.enabledProtocols = enabledProtocols == null ?169null : enabledProtocols.clone();170this.needClientAuth = needClientAuth;171172// Force the initialization of the default at construction time,173// rather than delaying it to the first time createServerSocket()174// is called.175//176this.context = context;177final SSLSocketFactory sslSocketFactory =178context == null ?179getDefaultSSLSocketFactory() : context.getSocketFactory();180SSLSocket sslSocket = null;181if (this.enabledCipherSuites != null || this.enabledProtocols != null) {182try {183sslSocket = (SSLSocket) sslSocketFactory.createSocket();184} catch (Exception e) {185final String msg = "Unable to check if the cipher suites " +186"and protocols to enable are supported";187throw (IllegalArgumentException)188new IllegalArgumentException(msg).initCause(e);189}190}191192// Check if all the cipher suites and protocol versions to enable193// are supported by the underlying SSL/TLS implementation and if194// true create lists from arrays.195//196if (this.enabledCipherSuites != null) {197sslSocket.setEnabledCipherSuites(this.enabledCipherSuites);198enabledCipherSuitesList = Arrays.asList(this.enabledCipherSuites);199}200if (this.enabledProtocols != null) {201sslSocket.setEnabledProtocols(this.enabledProtocols);202enabledProtocolsList = Arrays.asList(this.enabledProtocols);203}204}205206/**207* <p>Returns the names of the cipher suites enabled on SSL208* connections accepted by server sockets created by this factory,209* or <code>null</code> if this factory uses the cipher suites210* that are enabled by default.</p>211*212* @return an array of cipher suites enabled, or <code>null</code>213*214* @see SSLSocket#setEnabledCipherSuites215*/216public final String[] getEnabledCipherSuites() {217return enabledCipherSuites == null ?218null : enabledCipherSuites.clone();219}220221/**222* <p>Returns the names of the protocol versions enabled on SSL223* connections accepted by server sockets created by this factory,224* or <code>null</code> if this factory uses the protocol versions225* that are enabled by default.</p>226*227* @return an array of protocol versions enabled, or228* <code>null</code>229*230* @see SSLSocket#setEnabledProtocols231*/232public final String[] getEnabledProtocols() {233return enabledProtocols == null ?234null : enabledProtocols.clone();235}236237/**238* <p>Returns <code>true</code> if client authentication is239* required on SSL connections accepted by server sockets created240* by this factory.</p>241*242* @return <code>true</code> if client authentication is required243*244* @see SSLSocket#setNeedClientAuth245*/246public final boolean getNeedClientAuth() {247return needClientAuth;248}249250/**251* <p>Creates a server socket that accepts SSL connections252* configured according to this factory's SSL socket configuration253* parameters.</p>254*/255public ServerSocket createServerSocket(int port) throws IOException {256final SSLSocketFactory sslSocketFactory =257context == null ?258getDefaultSSLSocketFactory() : context.getSocketFactory();259return new ServerSocket(port) {260public Socket accept() throws IOException {261Socket socket = super.accept();262SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(263socket, socket.getInetAddress().getHostName(),264socket.getPort(), true);265sslSocket.setUseClientMode(false);266if (enabledCipherSuites != null) {267sslSocket.setEnabledCipherSuites(enabledCipherSuites);268}269if (enabledProtocols != null) {270sslSocket.setEnabledProtocols(enabledProtocols);271}272sslSocket.setNeedClientAuth(needClientAuth);273return sslSocket;274}275};276}277278/**279* <p>Indicates whether some other object is "equal to" this one.</p>280*281* <p>Two <code>SslRMIServerSocketFactory</code> objects are equal282* if they have been constructed with the same SSL context and283* SSL socket configuration parameters.</p>284*285* <p>A subclass should override this method (as well as286* {@link #hashCode()}) if it adds instance state that affects287* equality.</p>288*/289public boolean equals(Object obj) {290if (obj == null) return false;291if (obj == this) return true;292if (!(obj instanceof SslRMIServerSocketFactory))293return false;294SslRMIServerSocketFactory that = (SslRMIServerSocketFactory) obj;295return (getClass().equals(that.getClass()) && checkParameters(that));296}297298private boolean checkParameters(SslRMIServerSocketFactory that) {299// SSL context300//301if (context == null ? that.context != null : !context.equals(that.context))302return false;303304// needClientAuth flag305//306if (needClientAuth != that.needClientAuth)307return false;308309// enabledCipherSuites310//311if ((enabledCipherSuites == null && that.enabledCipherSuites != null) ||312(enabledCipherSuites != null && that.enabledCipherSuites == null))313return false;314if (enabledCipherSuites != null && that.enabledCipherSuites != null) {315List<String> thatEnabledCipherSuitesList =316Arrays.asList(that.enabledCipherSuites);317if (!enabledCipherSuitesList.equals(thatEnabledCipherSuitesList))318return false;319}320321// enabledProtocols322//323if ((enabledProtocols == null && that.enabledProtocols != null) ||324(enabledProtocols != null && that.enabledProtocols == null))325return false;326if (enabledProtocols != null && that.enabledProtocols != null) {327List<String> thatEnabledProtocolsList =328Arrays.asList(that.enabledProtocols);329if (!enabledProtocolsList.equals(thatEnabledProtocolsList))330return false;331}332333return true;334}335336/**337* <p>Returns a hash code value for this338* <code>SslRMIServerSocketFactory</code>.</p>339*340* @return a hash code value for this341* <code>SslRMIServerSocketFactory</code>.342*/343public int hashCode() {344return getClass().hashCode() +345(context == null ? 0 : context.hashCode()) +346(needClientAuth ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode()) +347(enabledCipherSuites == null ? 0 : enabledCipherSuitesList.hashCode()) +348(enabledProtocols == null ? 0 : enabledProtocolsList.hashCode());349}350351// We use a static field because:352//353// SSLSocketFactory.getDefault() always returns the same object354// (at least on Sun's implementation), and we want to make sure355// that the Javadoc & the implementation stay in sync.356//357// If someone needs to have different SslRMIServerSocketFactory358// factories with different underlying SSLSocketFactory objects359// using different keystores and truststores, he/she can always360// use the constructor that takes an SSLContext as input.361//362private static SSLSocketFactory defaultSSLSocketFactory = null;363364private static synchronized SSLSocketFactory getDefaultSSLSocketFactory() {365if (defaultSSLSocketFactory == null)366defaultSSLSocketFactory =367(SSLSocketFactory) SSLSocketFactory.getDefault();368return defaultSSLSocketFactory;369}370371private final String[] enabledCipherSuites;372private final String[] enabledProtocols;373private final boolean needClientAuth;374private List<String> enabledCipherSuitesList;375private List<String> enabledProtocolsList;376private SSLContext context;377}378379380