Merge branch 'cassandra-3.0' into trunk

This commit is contained in:
Aleksey Yeschenko 2016-02-29 17:20:13 +00:00
commit 84db205b41
7 changed files with 108 additions and 19 deletions

View File

@ -51,6 +51,7 @@ Merged from 3.0:
properly (CASSANDRA-11050)
* Fix NPE when using forceRepairRangeAsync without DC (CASSANDRA-11239)
Merged from 2.2:
* Preserve order for preferred SSL cipher suites (CASSANDRA-11164)
* Range.compareTo() violates the contract of Comparable (CASSANDRA-11216)
* Avoid NPE when serializing ErrorMessage with null message (CASSANDRA-11167)
* Replacing an aggregate with a new version doesn't reset INITCOND (CASSANDRA-10840)

View File

@ -24,9 +24,10 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.Set;
import java.util.List;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
@ -37,10 +38,12 @@ import javax.net.ssl.TrustManagerFactory;
import org.apache.cassandra.config.EncryptionOptions;
import org.apache.cassandra.io.util.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
/**
@ -58,8 +61,8 @@ public final class SSLFactory
SSLContext ctx = createSSLContext(options, true);
SSLServerSocket serverSocket = (SSLServerSocket)ctx.getServerSocketFactory().createServerSocket();
serverSocket.setReuseAddress(true);
String[] suits = filterCipherSuites(serverSocket.getSupportedCipherSuites(), options.cipher_suites);
serverSocket.setEnabledCipherSuites(suits);
String[] suites = filterCipherSuites(serverSocket.getSupportedCipherSuites(), options.cipher_suites);
serverSocket.setEnabledCipherSuites(suites);
serverSocket.setNeedClientAuth(options.require_client_auth);
serverSocket.setEnabledProtocols(ACCEPTED_PROTOCOLS);
serverSocket.bind(new InetSocketAddress(address, port), 500);
@ -71,8 +74,8 @@ public final class SSLFactory
{
SSLContext ctx = createSSLContext(options, true);
SSLSocket socket = (SSLSocket) ctx.getSocketFactory().createSocket(address, port, localAddress, localPort);
String[] suits = filterCipherSuites(socket.getSupportedCipherSuites(), options.cipher_suites);
socket.setEnabledCipherSuites(suits);
String[] suites = filterCipherSuites(socket.getSupportedCipherSuites(), options.cipher_suites);
socket.setEnabledCipherSuites(suites);
socket.setEnabledProtocols(ACCEPTED_PROTOCOLS);
return socket;
}
@ -82,8 +85,8 @@ public final class SSLFactory
{
SSLContext ctx = createSSLContext(options, true);
SSLSocket socket = (SSLSocket) ctx.getSocketFactory().createSocket(address, port);
String[] suits = filterCipherSuites(socket.getSupportedCipherSuites(), options.cipher_suites);
socket.setEnabledCipherSuites(suits);
String[] suites = filterCipherSuites(socket.getSupportedCipherSuites(), options.cipher_suites);
socket.setEnabledCipherSuites(suites);
socket.setEnabledProtocols(ACCEPTED_PROTOCOLS);
return socket;
}
@ -93,8 +96,8 @@ public final class SSLFactory
{
SSLContext ctx = createSSLContext(options, true);
SSLSocket socket = (SSLSocket) ctx.getSocketFactory().createSocket();
String[] suits = filterCipherSuites(socket.getSupportedCipherSuites(), options.cipher_suites);
socket.setEnabledCipherSuites(suits);
String[] suites = filterCipherSuites(socket.getSupportedCipherSuites(), options.cipher_suites);
socket.setEnabledCipherSuites(suites);
socket.setEnabledProtocols(ACCEPTED_PROTOCOLS);
return socket;
}
@ -155,12 +158,18 @@ public final class SSLFactory
return ctx;
}
private static String[] filterCipherSuites(String[] supported, String[] desired)
public static String[] filterCipherSuites(String[] supported, String[] desired)
{
Set<String> des = Sets.newHashSet(desired);
Set<String> toReturn = Sets.intersection(Sets.newHashSet(supported), des);
if (des.size() > toReturn.size())
logger.warn("Filtering out {} as it isnt supported by the socket", StringUtils.join(Sets.difference(des, toReturn), ","));
return toReturn.toArray(new String[toReturn.size()]);
if (Arrays.equals(supported, desired))
return desired;
List<String> ldesired = Arrays.asList(desired);
ImmutableSet<String> ssupported = ImmutableSet.copyOf(supported);
String[] ret = Iterables.toArray(Iterables.filter(ldesired, Predicates.in(ssupported)), String.class);
if (desired.length > ret.length && logger.isWarnEnabled())
{
Iterable<String> missing = Iterables.filter(ldesired, Predicates.not(Predicates.in(Sets.newHashSet(ret))));
logger.warn("Filtering out {} as it isn't supported by the socket", Iterables.toString(missing));
}
return ret;
}
}

View File

@ -245,7 +245,7 @@ public class CustomTThreadPoolServer extends TServer
if (clientEnc.enabled)
{
logger.info("enabling encrypted thrift connections between client and server");
TSSLTransportParameters params = new TSSLTransportParameters(clientEnc.protocol, clientEnc.cipher_suites);
TSSLTransportParameters params = new TSSLTransportParameters(clientEnc.protocol, new String[0]);
params.setKeyStore(clientEnc.keystore, clientEnc.keystore_password);
if (clientEnc.require_client_auth)
{
@ -254,6 +254,8 @@ public class CustomTThreadPoolServer extends TServer
}
TServerSocket sslServer = TSSLTransportFactory.getServerSocket(addr.getPort(), 0, addr.getAddress(), params);
SSLServerSocket sslServerSocket = (SSLServerSocket) sslServer.getServerSocket();
String[] suites = SSLFactory.filterCipherSuites(sslServerSocket.getSupportedCipherSuites(), clientEnc.cipher_suites);
sslServerSocket.setEnabledCipherSuites(suites);
sslServerSocket.setEnabledProtocols(SSLFactory.ACCEPTED_PROTOCOLS);
serverTransport = new TCustomServerSocket(sslServer.getServerSocket(), args.keepAlive, args.sendBufferSize, args.recvBufferSize);
}

View File

@ -358,7 +358,8 @@ public class Server implements CassandraDaemon.Server
protected final SslHandler createSslHandler() {
SSLEngine sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(false);
sslEngine.setEnabledCipherSuites(encryptionOptions.cipher_suites);
String[] suites = SSLFactory.filterCipherSuites(sslEngine.getSupportedCipherSuites(), encryptionOptions.cipher_suites);
sslEngine.setEnabledCipherSuites(suites);
sslEngine.setNeedClientAuth(encryptionOptions.require_client_auth);
sslEngine.setEnabledProtocols(SSLFactory.ACCEPTED_PROTOCOLS);
return new SslHandler(sslEngine);

View File

@ -291,7 +291,8 @@ public class SimpleClient implements Closeable
super.initChannel(channel);
SSLEngine sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(true);
sslEngine.setEnabledCipherSuites(encryptionOptions.cipher_suites);
String[] suites = SSLFactory.filterCipherSuites(sslEngine.getSupportedCipherSuites(), encryptionOptions.cipher_suites);
sslEngine.setEnabledCipherSuites(suites);
sslEngine.setEnabledProtocols(SSLFactory.ACCEPTED_PROTOCOLS);
channel.pipeline().addFirst("ssl", new SslHandler(sslEngine));
}

BIN
test/conf/keystore.jks Normal file

Binary file not shown.

View File

@ -0,0 +1,75 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cassandra.security;
import static org.junit.Assert.assertArrayEquals;
import java.io.IOException;
import java.net.InetAddress;
import javax.net.ssl.SSLServerSocket;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.apache.cassandra.config.EncryptionOptions;
import org.apache.cassandra.config.EncryptionOptions.ServerEncryptionOptions;
import org.junit.Test;
public class SSLFactoryTest
{
@Test
public void testFilterCipherSuites()
{
String[] supported = new String[] {"x", "b", "c", "f"};
String[] desired = new String[] { "k", "a", "b", "c" };
assertArrayEquals(new String[] { "b", "c" }, SSLFactory.filterCipherSuites(supported, desired));
desired = new String[] { "c", "b", "x" };
assertArrayEquals(desired, SSLFactory.filterCipherSuites(supported, desired));
}
@Test
public void testServerSocketCiphers() throws IOException
{
ServerEncryptionOptions options = new EncryptionOptions.ServerEncryptionOptions();
options.keystore = "test/conf/keystore.jks";
options.keystore_password = "cassandra";
options.truststore = options.keystore;
options.truststore_password = options.keystore_password;
options.cipher_suites = new String[] {
"TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"
};
// enabled ciphers must be a subset of configured ciphers with identical order
try (SSLServerSocket socket = SSLFactory.getServerSocket(options, InetAddress.getLocalHost(), 55123))
{
String[] enabled = socket.getEnabledCipherSuites();
String[] wanted = Iterables.toArray(Iterables.filter(Lists.newArrayList(options.cipher_suites),
Predicates.in(Lists.newArrayList(enabled))),
String.class);
assertArrayEquals(wanted, enabled);
}
}
}