Make security tests transport agnostic (#39411)
Currently there are two security tests that specifically target the netty security transport. This PR moves the client authentication tests into `AbstractSimpleSecurityTransportTestCase` so that the nio transport will also be tested. Additionally the work to build transport configurations is moved out of the netty transport and tested independently.
This commit is contained in:
parent
30687cbe7f
commit
f24dae302d
|
@ -1113,6 +1113,10 @@ public abstract class TcpTransport extends AbstractLifecycleComponent implements
|
|||
return handshaker.getNumHandshakes();
|
||||
}
|
||||
|
||||
final Set<TcpChannel> getAcceptedChannels() {
|
||||
return Collections.unmodifiableSet(acceptedChannels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures this transport is still started / open
|
||||
*
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.elasticsearch.Version;
|
|||
import org.elasticsearch.action.ActionListenerResponseHandler;
|
||||
import org.elasticsearch.action.support.PlainActionFuture;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||
|
@ -38,6 +39,7 @@ import org.elasticsearch.common.network.CloseableChannel;
|
|||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.network.NetworkUtils;
|
||||
import org.elasticsearch.common.settings.ClusterSettings;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.BoundTransportAddress;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
|
@ -105,10 +107,10 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
private static final Version CURRENT_VERSION = Version.fromString(String.valueOf(Version.CURRENT.major) + ".0.0");
|
||||
protected static final Version version0 = CURRENT_VERSION.minimumCompatibilityVersion();
|
||||
|
||||
private ClusterSettings clusterSettings;
|
||||
|
||||
protected volatile DiscoveryNode nodeA;
|
||||
protected volatile MockTransportService serviceA;
|
||||
protected ClusterSettings clusterSettingsA;
|
||||
|
||||
protected static final Version version1 = Version.fromId(CURRENT_VERSION.id + 1);
|
||||
protected volatile DiscoveryNode nodeB;
|
||||
|
@ -121,12 +123,16 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
return 6;
|
||||
}
|
||||
|
||||
protected Set<Setting<?>> getSupportedSettings() {
|
||||
return ClusterSettings.BUILT_IN_CLUSTER_SETTINGS;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
threadPool = new TestThreadPool(getClass().getName());
|
||||
clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
|
||||
clusterSettingsA = new ClusterSettings(Settings.EMPTY, getSupportedSettings());
|
||||
Settings connectionSettings = Settings.builder()
|
||||
.put(TransportSettings.CONNECTIONS_PER_NODE_RECOVERY.getKey(), 1)
|
||||
.put(TransportSettings.CONNECTIONS_PER_NODE_BULK.getKey(), 1)
|
||||
|
@ -135,7 +141,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
.put(TransportSettings.CONNECTIONS_PER_NODE_PING.getKey(), 1)
|
||||
.build();
|
||||
|
||||
serviceA = buildService("TS_A", version0, clusterSettings, connectionSettings); // this one supports dynamic tracer updates
|
||||
serviceA = buildService("TS_A", version0, clusterSettingsA, connectionSettings); // this one supports dynamic tracer updates
|
||||
nodeA = serviceA.getLocalNode();
|
||||
serviceB = buildService("TS_B", version1, null, connectionSettings); // this one doesn't support dynamic tracer updates
|
||||
nodeB = serviceB.getLocalNode();
|
||||
|
@ -166,25 +172,24 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
serviceB.removeConnectionListener(waitForConnection);
|
||||
}
|
||||
|
||||
private MockTransportService buildService(final String name, final Version version, ClusterSettings clusterSettings,
|
||||
private MockTransportService buildService(final String name, final Version version, @Nullable ClusterSettings clusterSettings,
|
||||
Settings settings, boolean acceptRequests, boolean doHandshake) {
|
||||
MockTransportService service = build(
|
||||
Settings.builder()
|
||||
.put(settings)
|
||||
.put(Node.NODE_NAME_SETTING.getKey(), name)
|
||||
.put(TransportSettings.TRACE_LOG_INCLUDE_SETTING.getKey(), "")
|
||||
.put(TransportSettings.TRACE_LOG_EXCLUDE_SETTING.getKey(), "NOTHING")
|
||||
.build(),
|
||||
version,
|
||||
clusterSettings, doHandshake);
|
||||
Settings updatedSettings = Settings.builder()
|
||||
.put(settings)
|
||||
.put(Node.NODE_NAME_SETTING.getKey(), name)
|
||||
.build();
|
||||
if (clusterSettings == null) {
|
||||
clusterSettings = new ClusterSettings(updatedSettings, getSupportedSettings());
|
||||
}
|
||||
MockTransportService service = build(updatedSettings, version, clusterSettings, doHandshake);
|
||||
if (acceptRequests) {
|
||||
service.acceptIncomingRequests();
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
protected MockTransportService buildService(final String name, final Version version, ClusterSettings clusterSettings) {
|
||||
return buildService(name, version, clusterSettings, Settings.EMPTY);
|
||||
protected MockTransportService buildService(final String name, final Version version, Settings settings) {
|
||||
return buildService(name, version, null, settings);
|
||||
}
|
||||
|
||||
protected MockTransportService buildService(final String name, final Version version, ClusterSettings clusterSettings,
|
||||
|
@ -500,7 +505,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testVoidMessageCompressed() {
|
||||
try (MockTransportService serviceC = build(Settings.EMPTY, CURRENT_VERSION, null, true)) {
|
||||
try (MockTransportService serviceC = buildService("TS_C", CURRENT_VERSION, Settings.EMPTY)) {
|
||||
serviceC.start();
|
||||
serviceC.acceptIncomingRequests();
|
||||
|
||||
|
@ -553,7 +558,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testHelloWorldCompressed() throws IOException {
|
||||
try (MockTransportService serviceC = build(Settings.EMPTY, CURRENT_VERSION, null, true)) {
|
||||
try (MockTransportService serviceC = buildService("TS_C", CURRENT_VERSION, Settings.EMPTY)) {
|
||||
serviceC.start();
|
||||
serviceC.acceptIncomingRequests();
|
||||
|
||||
|
@ -767,7 +772,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
if (i % 3 == 0) {
|
||||
// simulate restart of nodeB
|
||||
serviceB.close();
|
||||
MockTransportService newService = buildService("TS_B_" + i, version1, null);
|
||||
MockTransportService newService = buildService("TS_B_" + i, version1, Settings.EMPTY);
|
||||
newService.registerRequestHandler("internal:test", TestRequest::new, ThreadPool.Names.SAME, ignoringRequestHandler);
|
||||
serviceB = newService;
|
||||
nodeB = newService.getLocalDiscoNode();
|
||||
|
@ -1050,7 +1055,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
includeSettings = "internal:test";
|
||||
excludeSettings = "DOESN'T_MATCH";
|
||||
}
|
||||
clusterSettings.applySettings(Settings.builder()
|
||||
clusterSettingsA.applySettings(Settings.builder()
|
||||
.put(TransportSettings.TRACE_LOG_INCLUDE_SETTING.getKey(), includeSettings)
|
||||
.put(TransportSettings.TRACE_LOG_EXCLUDE_SETTING.getKey(), excludeSettings)
|
||||
.build());
|
||||
|
@ -1732,14 +1737,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testSendRandomRequests() throws InterruptedException {
|
||||
TransportService serviceC = build(
|
||||
Settings.builder()
|
||||
.put("name", "TS_TEST")
|
||||
.put(TransportSettings.TRACE_LOG_INCLUDE_SETTING.getKey(), "")
|
||||
.put(TransportSettings.TRACE_LOG_EXCLUDE_SETTING.getKey(), "NOTHING")
|
||||
.build(),
|
||||
version0,
|
||||
null, true);
|
||||
TransportService serviceC = buildService("TS_C", version0, Settings.EMPTY);
|
||||
DiscoveryNode nodeC = serviceC.getLocalNode();
|
||||
serviceC.acceptIncomingRequests();
|
||||
|
||||
|
@ -1970,7 +1968,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
public void testHandshakeWithIncompatVersion() {
|
||||
assumeTrue("only tcp transport has a handshake method", serviceA.getOriginalTransport() instanceof TcpTransport);
|
||||
Version version = Version.fromString("2.0.0");
|
||||
try (MockTransportService service = build(Settings.EMPTY, version, null, true)) {
|
||||
try (MockTransportService service = buildService("TS_C", version, Settings.EMPTY)) {
|
||||
service.start();
|
||||
service.acceptIncomingRequests();
|
||||
TransportAddress address = service.boundAddress().publishAddress();
|
||||
|
@ -1989,7 +1987,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
public void testHandshakeUpdatesVersion() throws IOException {
|
||||
assumeTrue("only tcp transport has a handshake method", serviceA.getOriginalTransport() instanceof TcpTransport);
|
||||
Version version = VersionUtils.randomVersionBetween(random(), Version.CURRENT.minimumCompatibilityVersion(), Version.CURRENT);
|
||||
try (MockTransportService service = build(Settings.EMPTY, version, null, true)) {
|
||||
try (MockTransportService service = buildService("TS_C", version, Settings.EMPTY)) {
|
||||
service.start();
|
||||
service.acceptIncomingRequests();
|
||||
TransportAddress address = service.boundAddress().publishAddress();
|
||||
|
@ -2015,7 +2013,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
ConnectionProfile connectionProfile = new ConnectionProfile.Builder(defaultProfile)
|
||||
.setPingInterval(TimeValue.timeValueMillis(50))
|
||||
.build();
|
||||
try (TransportService service = buildService("TS_TPC", Version.CURRENT, null)) {
|
||||
try (TransportService service = buildService("TS_TPC", Version.CURRENT, Settings.EMPTY)) {
|
||||
PlainActionFuture<Transport.Connection> future = PlainActionFuture.newFuture();
|
||||
DiscoveryNode node = new DiscoveryNode("TS_TPC", "TS_TPC", service.boundAddress().publishAddress(), emptyMap(), emptySet(),
|
||||
version0);
|
||||
|
@ -2062,7 +2060,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
}
|
||||
|
||||
ConnectionProfile connectionProfile = ConnectionProfile.buildDefaultConnectionProfile(Settings.EMPTY);
|
||||
try (TransportService service = buildService("TS_TPC", Version.CURRENT, null)) {
|
||||
try (TransportService service = buildService("TS_TPC", Version.CURRENT, Settings.EMPTY)) {
|
||||
DiscoveryNode node = new DiscoveryNode("TS_TPC", "TS_TPC", service.boundAddress().publishAddress(), emptyMap(), emptySet(),
|
||||
version0);
|
||||
PlainActionFuture<Transport.Connection> future = PlainActionFuture.newFuture();
|
||||
|
@ -2193,7 +2191,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
public void testHandlerIsInvokedOnConnectionClose() throws IOException, InterruptedException {
|
||||
List<String> executors = new ArrayList<>(ThreadPool.THREAD_POOL_TYPES.keySet());
|
||||
CollectionUtil.timSort(executors); // makes sure it's reproducible
|
||||
TransportService serviceC = build(Settings.builder().put("name", "TS_TEST").build(), version0, null, true);
|
||||
TransportService serviceC = buildService("TS_C", CURRENT_VERSION, Settings.EMPTY);
|
||||
serviceC.registerRequestHandler("internal:action", TestRequest::new, ThreadPool.Names.SAME,
|
||||
(request, channel, task) -> {
|
||||
// do nothing
|
||||
|
@ -2251,7 +2249,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testConcurrentDisconnectOnNonPublishedConnection() throws IOException, InterruptedException {
|
||||
MockTransportService serviceC = build(Settings.builder().put("name", "TS_TEST").build(), version0, null, true);
|
||||
MockTransportService serviceC = buildService("TS_C", version0, Settings.EMPTY);
|
||||
CountDownLatch receivedLatch = new CountDownLatch(1);
|
||||
CountDownLatch sendResponseLatch = new CountDownLatch(1);
|
||||
serviceC.registerRequestHandler("internal:action", TestRequest::new, ThreadPool.Names.SAME,
|
||||
|
@ -2319,7 +2317,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testTransportStats() throws Exception {
|
||||
MockTransportService serviceC = build(Settings.builder().put("name", "TS_TEST").build(), version0, null, true);
|
||||
MockTransportService serviceC = buildService("TS_C", version0, Settings.EMPTY);
|
||||
CountDownLatch receivedLatch = new CountDownLatch(1);
|
||||
CountDownLatch sendResponseLatch = new CountDownLatch(1);
|
||||
serviceB.registerRequestHandler("internal:action", TestRequest::new, ThreadPool.Names.SAME,
|
||||
|
@ -2430,7 +2428,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testTransportStatsWithException() throws Exception {
|
||||
MockTransportService serviceC = build(Settings.builder().put("name", "TS_TEST").build(), version0, null, true);
|
||||
MockTransportService serviceC = buildService("TS_C", version0, Settings.EMPTY);
|
||||
CountDownLatch receivedLatch = new CountDownLatch(1);
|
||||
CountDownLatch sendResponseLatch = new CountDownLatch(1);
|
||||
Exception ex = new RuntimeException("boom");
|
||||
|
@ -2541,15 +2539,14 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
} else {
|
||||
hosts = Arrays.asList("_local:ipv4_");
|
||||
}
|
||||
try (MockTransportService serviceC = build(Settings.builder()
|
||||
.put("name", "TS_TEST")
|
||||
try (MockTransportService serviceC = buildService("TS_C", version0, Settings.builder()
|
||||
.put("transport.profiles.default.bind_host", "_local:ipv4_")
|
||||
.put("transport.profiles.some_profile.port", "8900-9000")
|
||||
.put("transport.profiles.some_profile.bind_host", "_local:ipv4_")
|
||||
.put("transport.profiles.some_other_profile.port", "8700-8800")
|
||||
.putList("transport.profiles.some_other_profile.bind_host", hosts)
|
||||
.putList("transport.profiles.some_other_profile.publish_host", "_local:ipv4_")
|
||||
.build(), version0, null, true)) {
|
||||
.build())) {
|
||||
|
||||
serviceC.start();
|
||||
serviceC.acceptIncomingRequests();
|
||||
|
@ -2706,7 +2703,7 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testChannelCloseWhileConnecting() {
|
||||
try (MockTransportService service = build(Settings.builder().put("name", "close").build(), version0, null, true)) {
|
||||
try (MockTransportService service = buildService("TS_C", version0, Settings.EMPTY)) {
|
||||
AtomicBoolean connectionClosedListenerCalled = new AtomicBoolean(false);
|
||||
service.addConnectionListener(new TransportConnectionListener() {
|
||||
@Override
|
||||
|
@ -2748,4 +2745,8 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
|
|||
protected InetSocketAddress getLocalEphemeral() throws UnknownHostException {
|
||||
return new InetSocketAddress(InetAddress.getLocalHost(), 0);
|
||||
}
|
||||
|
||||
protected Set<TcpChannel> getAcceptedChannels(TcpTransport transport) {
|
||||
return transport.getAcceptedChannels();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ package org.elasticsearch.transport;
|
|||
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
||||
final class TestProfiles {
|
||||
public final class TestProfiles {
|
||||
|
||||
private TestProfiles() {}
|
||||
|
||||
|
@ -29,7 +29,7 @@ final class TestProfiles {
|
|||
* A pre-built light connection profile that shares a single connection across all
|
||||
* types.
|
||||
*/
|
||||
static final ConnectionProfile LIGHT_PROFILE;
|
||||
public static final ConnectionProfile LIGHT_PROFILE;
|
||||
|
||||
static {
|
||||
ConnectionProfile source = ConnectionProfile.buildDefaultConnectionProfile(Settings.EMPTY);
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.core.security.transport;
|
||||
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.xpack.core.security.SecurityField.setting;
|
||||
|
||||
public final class ProfileConfigurations {
|
||||
|
||||
private ProfileConfigurations() {}
|
||||
|
||||
public static Map<String, SSLConfiguration> get(Settings settings, SSLService sslService, SSLConfiguration defaultConfiguration) {
|
||||
Set<String> profileNames = settings.getGroups("transport.profiles.", true).keySet();
|
||||
Map<String, SSLConfiguration> profileConfiguration = new HashMap<>(profileNames.size() + 1);
|
||||
for (String profileName : profileNames) {
|
||||
if (profileName.equals(TransportSettings.DEFAULT_PROFILE)) {
|
||||
// don't attempt to parse ssl settings from the profile;
|
||||
// profiles need to be killed with fire
|
||||
if (settings.getByPrefix("transport.profiles.default.xpack.security.ssl.").isEmpty()) {
|
||||
continue;
|
||||
} else {
|
||||
throw new IllegalArgumentException("SSL settings should not be configured for the default profile. " +
|
||||
"Use the [xpack.security.transport.ssl] settings instead.");
|
||||
}
|
||||
}
|
||||
SSLConfiguration configuration = sslService.getSSLConfiguration("transport.profiles." + profileName + "." + setting("ssl"));
|
||||
profileConfiguration.put(profileName, configuration);
|
||||
}
|
||||
|
||||
assert profileConfiguration.containsKey(TransportSettings.DEFAULT_PROFILE) == false;
|
||||
profileConfiguration.put(TransportSettings.DEFAULT_PROFILE, defaultConfiguration);
|
||||
return profileConfiguration;
|
||||
}
|
||||
}
|
|
@ -25,9 +25,9 @@ import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
|||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.ConnectTransportException;
|
||||
import org.elasticsearch.transport.TcpChannel;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
import org.elasticsearch.transport.netty4.Netty4Transport;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.security.transport.ProfileConfigurations;
|
||||
import org.elasticsearch.xpack.core.security.transport.SSLExceptionHelper;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||
|
@ -39,9 +39,7 @@ import javax.net.ssl.SSLParameters;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.xpack.core.security.SecurityField.setting;
|
||||
|
||||
|
@ -70,7 +68,7 @@ public class SecurityNetty4Transport extends Netty4Transport {
|
|||
this.sslEnabled = XPackSettings.TRANSPORT_SSL_ENABLED.get(settings);
|
||||
if (sslEnabled) {
|
||||
this.sslConfiguration = sslService.getSSLConfiguration(setting("transport.ssl."));
|
||||
Map<String, SSLConfiguration> profileConfiguration = getTransportProfileConfigurations(settings, sslService, sslConfiguration);
|
||||
Map<String, SSLConfiguration> profileConfiguration = ProfileConfigurations.get(settings, sslService, sslConfiguration);
|
||||
this.profileConfiguration = Collections.unmodifiableMap(profileConfiguration);
|
||||
} else {
|
||||
this.profileConfiguration = Collections.emptyMap();
|
||||
|
@ -78,30 +76,6 @@ public class SecurityNetty4Transport extends Netty4Transport {
|
|||
}
|
||||
}
|
||||
|
||||
public static Map<String, SSLConfiguration> getTransportProfileConfigurations(Settings settings, SSLService sslService,
|
||||
SSLConfiguration defaultConfiguration) {
|
||||
Set<String> profileNames = settings.getGroups("transport.profiles.", true).keySet();
|
||||
Map<String, SSLConfiguration> profileConfiguration = new HashMap<>(profileNames.size() + 1);
|
||||
for (String profileName : profileNames) {
|
||||
if (profileName.equals(TransportSettings.DEFAULT_PROFILE)) {
|
||||
// don't attempt to parse ssl settings from the profile;
|
||||
// profiles need to be killed with fire
|
||||
if (settings.getByPrefix("transport.profiles.default.xpack.security.ssl.").isEmpty()) {
|
||||
continue;
|
||||
} else {
|
||||
throw new IllegalArgumentException("SSL settings should not be configured for the default profile. " +
|
||||
"Use the [xpack.security.transport.ssl] settings instead.");
|
||||
}
|
||||
}
|
||||
SSLConfiguration configuration = sslService.getSSLConfiguration("transport.profiles." + profileName + "." + setting("ssl"));
|
||||
profileConfiguration.put(profileName, configuration);
|
||||
}
|
||||
|
||||
assert profileConfiguration.containsKey(TransportSettings.DEFAULT_PROFILE) == false;
|
||||
profileConfiguration.put(TransportSettings.DEFAULT_PROFILE, defaultConfiguration);
|
||||
return profileConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
super.doStart();
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.xpack.core.security.transport.netty4;
|
||||
package org.elasticsearch.xpack.core.security.transport;
|
||||
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
@ -17,9 +17,7 @@ import org.hamcrest.Matchers;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.xpack.core.security.transport.netty4.SecurityNetty4Transport.getTransportProfileConfigurations;
|
||||
|
||||
public class SecurityNetty4TransportTests extends ESTestCase {
|
||||
public class ProfileConfigurationsTests extends ESTestCase {
|
||||
|
||||
public void testGetSecureTransportProfileConfigurations() {
|
||||
final Settings settings = Settings.builder()
|
||||
|
@ -31,7 +29,7 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
final Environment env = TestEnvironment.newEnvironment(settings);
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
final SSLConfiguration defaultConfig = sslService.getSSLConfiguration("xpack.security.transport.ssl");
|
||||
final Map<String, SSLConfiguration> profileConfigurations = getTransportProfileConfigurations(settings, sslService, defaultConfig);
|
||||
final Map<String, SSLConfiguration> profileConfigurations = ProfileConfigurations.get(settings, sslService, defaultConfig);
|
||||
assertThat(profileConfigurations.size(), Matchers.equalTo(3));
|
||||
assertThat(profileConfigurations.keySet(), Matchers.containsInAnyOrder("full", "cert", "default"));
|
||||
assertThat(profileConfigurations.get("full").verificationMode(), Matchers.equalTo(VerificationMode.FULL));
|
||||
|
@ -49,7 +47,7 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
final Environment env = TestEnvironment.newEnvironment(settings);
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
final SSLConfiguration defaultConfig = sslService.getSSLConfiguration("xpack.security.transport.ssl");
|
||||
final Map<String, SSLConfiguration> profileConfigurations = getTransportProfileConfigurations(settings, sslService, defaultConfig);
|
||||
final Map<String, SSLConfiguration> profileConfigurations = ProfileConfigurations.get(settings, sslService, defaultConfig);
|
||||
assertThat(profileConfigurations.size(), Matchers.equalTo(2));
|
||||
assertThat(profileConfigurations.keySet(), Matchers.containsInAnyOrder("none", "default"));
|
||||
assertThat(profileConfigurations.get("none").verificationMode(), Matchers.equalTo(VerificationMode.NONE));
|
|
@ -33,7 +33,7 @@ import org.elasticsearch.transport.TransportService;
|
|||
import org.elasticsearch.transport.TransportService.ContextRestoreResponseHandler;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.transport.netty4.SecurityNetty4Transport;
|
||||
import org.elasticsearch.xpack.core.security.transport.ProfileConfigurations;
|
||||
import org.elasticsearch.xpack.core.security.user.SystemUser;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||
|
@ -172,10 +172,9 @@ public class SecurityServerTransportInterceptor implements TransportInterceptor
|
|||
licenseState, threadPool);
|
||||
}
|
||||
|
||||
protected Map<String, ServerTransportFilter> initializeProfileFilters(DestructiveOperations destructiveOperations) {
|
||||
final SSLConfiguration transportSslConfiguration = sslService.getSSLConfiguration(setting("transport.ssl"));
|
||||
final Map<String, SSLConfiguration> profileConfigurations = SecurityNetty4Transport.getTransportProfileConfigurations(settings,
|
||||
sslService, transportSslConfiguration);
|
||||
private Map<String, ServerTransportFilter> initializeProfileFilters(DestructiveOperations destructiveOperations) {
|
||||
final SSLConfiguration sslConfiguration = sslService.getSSLConfiguration(setting("transport.ssl"));
|
||||
final Map<String, SSLConfiguration> profileConfigurations = ProfileConfigurations.get(settings, sslService, sslConfiguration);
|
||||
|
||||
Map<String, ServerTransportFilter> profileFilters = new HashMap<>(profileConfigurations.size() + 1);
|
||||
|
||||
|
|
|
@ -35,8 +35,8 @@ import org.elasticsearch.transport.nio.NioTcpServerChannel;
|
|||
import org.elasticsearch.transport.nio.NioTransport;
|
||||
import org.elasticsearch.transport.nio.TcpReadWriteHandler;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.security.transport.ProfileConfigurations;
|
||||
import org.elasticsearch.xpack.core.security.transport.SSLExceptionHelper;
|
||||
import org.elasticsearch.xpack.core.security.transport.netty4.SecurityNetty4Transport;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
|
@ -85,8 +85,7 @@ public class SecurityNioTransport extends NioTransport {
|
|||
this.sslEnabled = XPackSettings.TRANSPORT_SSL_ENABLED.get(settings);
|
||||
if (sslEnabled) {
|
||||
final SSLConfiguration transportConfiguration = sslService.getSSLConfiguration(setting("transport.ssl."));
|
||||
Map<String, SSLConfiguration> profileConfiguration = SecurityNetty4Transport.getTransportProfileConfigurations(settings,
|
||||
sslService, transportConfiguration);
|
||||
Map<String, SSLConfiguration> profileConfiguration = ProfileConfigurations.get(settings, sslService, transportConfiguration);
|
||||
this.profileConfiguration = Collections.unmodifiableMap(profileConfiguration);
|
||||
} else {
|
||||
profileConfiguration = Collections.emptyMap();
|
||||
|
|
|
@ -10,24 +10,27 @@ import org.elasticsearch.action.support.PlainActionFuture;
|
|||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.io.stream.OutputStreamStreamOutput;
|
||||
import org.elasticsearch.common.settings.ClusterSettings;
|
||||
import org.elasticsearch.common.settings.MockSecureSettings;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.core.internal.io.IOUtils;
|
||||
import org.elasticsearch.env.TestEnvironment;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.test.transport.MockTransportService;
|
||||
import org.elasticsearch.test.transport.StubbableTransport;
|
||||
import org.elasticsearch.transport.AbstractSimpleTransportTestCase;
|
||||
import org.elasticsearch.transport.BindTransportException;
|
||||
import org.elasticsearch.transport.ConnectTransportException;
|
||||
import org.elasticsearch.transport.ConnectionProfile;
|
||||
import org.elasticsearch.transport.TcpChannel;
|
||||
import org.elasticsearch.transport.TcpTransport;
|
||||
import org.elasticsearch.transport.TestProfiles;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.transport.TransportRequestOptions;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.common.socket.SocketAccess;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||
|
||||
|
@ -37,6 +40,7 @@ import javax.net.ssl.SNIHostName;
|
|||
import javax.net.ssl.SNIMatcher;
|
||||
import javax.net.ssl.SNIServerName;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.SSLServerSocket;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
|
@ -51,30 +55,24 @@ import java.nio.file.Path;
|
|||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
public abstract class AbstractSimpleSecurityTransportTestCase extends AbstractSimpleTransportTestCase {
|
||||
|
||||
private static final ConnectionProfile SINGLE_CHANNEL_PROFILE;
|
||||
|
||||
static {
|
||||
ConnectionProfile.Builder builder = new ConnectionProfile.Builder();
|
||||
builder.addConnections(1,
|
||||
TransportRequestOptions.Type.BULK,
|
||||
TransportRequestOptions.Type.PING,
|
||||
TransportRequestOptions.Type.RECOVERY,
|
||||
TransportRequestOptions.Type.REG,
|
||||
TransportRequestOptions.Type.STATE);
|
||||
SINGLE_CHANNEL_PROFILE = builder.build();
|
||||
}
|
||||
|
||||
protected SSLService createSSLService() {
|
||||
private SSLService createSSLService() {
|
||||
return createSSLService(Settings.EMPTY);
|
||||
}
|
||||
|
||||
|
@ -83,6 +81,8 @@ public abstract class AbstractSimpleSecurityTransportTestCase extends AbstractSi
|
|||
Path testnodeKey = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem");
|
||||
MockSecureSettings secureSettings = new MockSecureSettings();
|
||||
secureSettings.setString("xpack.security.transport.ssl.secure_key_passphrase", "testnode");
|
||||
// Some tests use a client profile. Put the passphrase in the secure settings for the profile (secure settings cannot be set twice)
|
||||
secureSettings.setString("transport.profiles.client.xpack.security.ssl.secure_key_passphrase", "testnode");
|
||||
Settings settings1 = Settings.builder()
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("xpack.security.transport.ssl.key", testnodeKey)
|
||||
|
@ -98,6 +98,13 @@ public abstract class AbstractSimpleSecurityTransportTestCase extends AbstractSi
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<Setting<?>> getSupportedSettings() {
|
||||
HashSet<Setting<?>> availableSettings = new HashSet<>(super.getSupportedSettings());
|
||||
availableSettings.addAll(XPackSettings.getAllSettings());
|
||||
return availableSettings;
|
||||
}
|
||||
|
||||
public void testConnectException() throws UnknownHostException {
|
||||
try {
|
||||
serviceA.connectToNode(new DiscoveryNode("C", new TransportAddress(InetAddress.getByName("localhost"), 9876),
|
||||
|
@ -115,14 +122,10 @@ public abstract class AbstractSimpleSecurityTransportTestCase extends AbstractSi
|
|||
// this is on a lower level since it needs access to the TransportService before it's started
|
||||
int port = serviceA.boundAddress().publishAddress().getPort();
|
||||
Settings settings = Settings.builder()
|
||||
.put(Node.NODE_NAME_SETTING.getKey(), "foobar")
|
||||
.put(TransportSettings.TRACE_LOG_INCLUDE_SETTING.getKey(), "")
|
||||
.put(TransportSettings.TRACE_LOG_EXCLUDE_SETTING.getKey(), "NOTHING")
|
||||
.put(TransportSettings.PORT.getKey(), port)
|
||||
.build();
|
||||
ClusterSettings clusterSettings = new ClusterSettings(settings, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
|
||||
BindTransportException bindTransportException = expectThrows(BindTransportException.class, () -> {
|
||||
MockTransportService transportService = build(settings, Version.CURRENT, clusterSettings, true);
|
||||
MockTransportService transportService = buildService("TS_C", Version.CURRENT, settings);
|
||||
try {
|
||||
transportService.start();
|
||||
} finally {
|
||||
|
@ -139,7 +142,7 @@ public abstract class AbstractSimpleSecurityTransportTestCase extends AbstractSi
|
|||
TcpTransport originalTransport = (TcpTransport) serviceA.getOriginalTransport();
|
||||
|
||||
ConnectionProfile connectionProfile = ConnectionProfile.buildDefaultConnectionProfile(Settings.EMPTY);
|
||||
try (TransportService service = buildService("TS_TPC", Version.CURRENT, null)) {
|
||||
try (TransportService service = buildService("TS_TPC", Version.CURRENT, Settings.EMPTY)) {
|
||||
DiscoveryNode node = new DiscoveryNode("TS_TPC", "TS_TPC", service.boundAddress().publishAddress(), emptyMap(), emptySet(),
|
||||
version0);
|
||||
PlainActionFuture<Transport.Connection> future = PlainActionFuture.newFuture();
|
||||
|
@ -245,10 +248,10 @@ public abstract class AbstractSimpleSecurityTransportTestCase extends AbstractSi
|
|||
|
||||
InetSocketAddress serverAddress = (InetSocketAddress) SocketAccess.doPrivileged(sslServerSocket::getLocalSocketAddress);
|
||||
|
||||
Settings settings = Settings.builder().put("name", "TS_TEST")
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.transport.ssl.verification_mode", "none")
|
||||
.build();
|
||||
try (MockTransportService serviceC = build(settings, version0, null, true)) {
|
||||
try (MockTransportService serviceC = buildService("TS_C", version0, settings)) {
|
||||
serviceC.acceptIncomingRequests();
|
||||
|
||||
HashMap<String, String> attributes = new HashMap<>();
|
||||
|
@ -258,7 +261,7 @@ public abstract class AbstractSimpleSecurityTransportTestCase extends AbstractSi
|
|||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
serviceC.connectToNode(node, SINGLE_CHANNEL_PROFILE);
|
||||
serviceC.connectToNode(node, TestProfiles.LIGHT_PROFILE);
|
||||
} catch (ConnectTransportException ex) {
|
||||
// Ignore. The other side is not setup to do the ES handshake. So this will fail.
|
||||
}
|
||||
|
@ -292,10 +295,10 @@ public abstract class AbstractSimpleSecurityTransportTestCase extends AbstractSi
|
|||
|
||||
InetSocketAddress serverAddress = (InetSocketAddress) SocketAccess.doPrivileged(sslServerSocket::getLocalSocketAddress);
|
||||
|
||||
Settings settings = Settings.builder().put("name", "TS_TEST")
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.transport.ssl.verification_mode", "none")
|
||||
.build();
|
||||
try (MockTransportService serviceC = build(settings, version0, null, true)) {
|
||||
try (MockTransportService serviceC = buildService("TS_C", version0, settings)) {
|
||||
serviceC.acceptIncomingRequests();
|
||||
|
||||
HashMap<String, String> attributes = new HashMap<>();
|
||||
|
@ -304,10 +307,147 @@ public abstract class AbstractSimpleSecurityTransportTestCase extends AbstractSi
|
|||
EnumSet.allOf(DiscoveryNode.Role.class), Version.CURRENT);
|
||||
|
||||
ConnectTransportException connectException = expectThrows(ConnectTransportException.class,
|
||||
() -> serviceC.connectToNode(node, SINGLE_CHANNEL_PROFILE));
|
||||
() -> serviceC.connectToNode(node, TestProfiles.LIGHT_PROFILE));
|
||||
|
||||
assertThat(connectException.getMessage(), containsString("invalid DiscoveryNode server_name [invalid_hostname]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testSecurityClientAuthenticationConfigs() throws Exception {
|
||||
Path testnodeCert = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt");
|
||||
Path testnodeKey = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem");
|
||||
|
||||
Transport.Connection connection1 = serviceA.getConnection(serviceB.getLocalNode());
|
||||
SSLEngine sslEngine = getSSLEngine(connection1);
|
||||
assertThat(sslEngine, notNullValue());
|
||||
// test client authentication is default
|
||||
assertThat(sslEngine.getNeedClientAuth(), is(true));
|
||||
assertThat(sslEngine.getWantClientAuth(), is(false));
|
||||
|
||||
// test required client authentication
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder().put("xpack.security.transport.ssl.client_authentication", value).build();
|
||||
try (MockTransportService service = buildService("TS_REQUIRED_CLIENT_AUTH", Version.CURRENT, settings)) {
|
||||
TcpTransport originalTransport = (TcpTransport) service.getOriginalTransport();
|
||||
try (Transport.Connection connection2 = serviceA.openConnection(service.getLocalNode(), TestProfiles.LIGHT_PROFILE)) {
|
||||
sslEngine = getEngineFromAcceptedChannel(originalTransport, connection2);
|
||||
assertThat(sslEngine.getNeedClientAuth(), is(true));
|
||||
assertThat(sslEngine.getWantClientAuth(), is(false));
|
||||
}
|
||||
}
|
||||
|
||||
// test no client authentication
|
||||
value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT));
|
||||
settings = Settings.builder().put("xpack.security.transport.ssl.client_authentication", value).build();
|
||||
try (MockTransportService service = buildService("TS_NO_CLIENT_AUTH", Version.CURRENT, settings)) {
|
||||
TcpTransport originalTransport = (TcpTransport) service.getOriginalTransport();
|
||||
try (Transport.Connection connection2 = serviceA.openConnection(service.getLocalNode(), TestProfiles.LIGHT_PROFILE)) {
|
||||
sslEngine = getEngineFromAcceptedChannel(originalTransport, connection2);
|
||||
assertThat(sslEngine.getNeedClientAuth(), is(false));
|
||||
assertThat(sslEngine.getWantClientAuth(), is(false));
|
||||
}
|
||||
}
|
||||
|
||||
// test optional client authentication
|
||||
value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
|
||||
settings = Settings.builder().put("xpack.security.transport.ssl.client_authentication", value).build();
|
||||
try (MockTransportService service = buildService("TS_OPTIONAL_CLIENT_AUTH", Version.CURRENT, settings)) {
|
||||
TcpTransport originalTransport = (TcpTransport) service.getOriginalTransport();
|
||||
try (Transport.Connection connection2 = serviceA.openConnection(service.getLocalNode(), TestProfiles.LIGHT_PROFILE)) {
|
||||
sslEngine = getEngineFromAcceptedChannel(originalTransport, connection2);
|
||||
assertThat(sslEngine.getNeedClientAuth(), is(false));
|
||||
assertThat(sslEngine.getWantClientAuth(), is(true));
|
||||
}
|
||||
}
|
||||
|
||||
// test profile required client authentication
|
||||
value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT));
|
||||
settings = Settings.builder()
|
||||
.put("transport.profiles.client.port", "8000-9000")
|
||||
.put("transport.profiles.client.xpack.security.ssl.enabled", true)
|
||||
.put("transport.profiles.client.xpack.security.ssl.certificate", testnodeCert)
|
||||
.put("transport.profiles.client.xpack.security.ssl.key", testnodeKey)
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
try (MockTransportService service = buildService("TS_PROFILE_REQUIRE_CLIENT_AUTH", Version.CURRENT, settings)) {
|
||||
TcpTransport originalTransport = (TcpTransport) service.getOriginalTransport();
|
||||
TransportAddress clientAddress = originalTransport.profileBoundAddresses().get("client").publishAddress();
|
||||
DiscoveryNode node = new DiscoveryNode(service.getLocalNode().getId(), clientAddress, service.getLocalNode().getVersion());
|
||||
try (Transport.Connection connection2 = serviceA.openConnection(node, TestProfiles.LIGHT_PROFILE)) {
|
||||
sslEngine = getEngineFromAcceptedChannel(originalTransport, connection2);
|
||||
assertEquals("client", getAcceptedChannel(originalTransport, connection2).getProfile());
|
||||
assertThat(sslEngine.getNeedClientAuth(), is(true));
|
||||
assertThat(sslEngine.getWantClientAuth(), is(false));
|
||||
}
|
||||
}
|
||||
|
||||
// test profile no client authentication
|
||||
value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT));
|
||||
settings = Settings.builder()
|
||||
.put("transport.profiles.client.port", "8000-9000")
|
||||
.put("transport.profiles.client.xpack.security.ssl.enabled", true)
|
||||
.put("transport.profiles.client.xpack.security.ssl.certificate", testnodeCert)
|
||||
.put("transport.profiles.client.xpack.security.ssl.key", testnodeKey)
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
try (MockTransportService service = buildService("TS_PROFILE_NO_CLIENT_AUTH", Version.CURRENT, settings)) {
|
||||
TcpTransport originalTransport = (TcpTransport) service.getOriginalTransport();
|
||||
TransportAddress clientAddress = originalTransport.profileBoundAddresses().get("client").publishAddress();
|
||||
DiscoveryNode node = new DiscoveryNode(service.getLocalNode().getId(), clientAddress, service.getLocalNode().getVersion());
|
||||
try (Transport.Connection connection2 = serviceA.openConnection(node, TestProfiles.LIGHT_PROFILE)) {
|
||||
sslEngine = getEngineFromAcceptedChannel(originalTransport, connection2);
|
||||
assertEquals("client", getAcceptedChannel(originalTransport, connection2).getProfile());
|
||||
assertThat(sslEngine.getNeedClientAuth(), is(false));
|
||||
assertThat(sslEngine.getWantClientAuth(), is(false));
|
||||
}
|
||||
}
|
||||
|
||||
// test profile optional client authentication
|
||||
value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
|
||||
settings = Settings.builder()
|
||||
.put("transport.profiles.client.port", "8000-9000")
|
||||
.put("transport.profiles.client.xpack.security.ssl.enabled", true)
|
||||
.put("transport.profiles.client.xpack.security.ssl.certificate", testnodeCert)
|
||||
.put("transport.profiles.client.xpack.security.ssl.key", testnodeKey)
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
try (MockTransportService service = buildService("TS_PROFILE_OPTIONAL_CLIENT_AUTH", Version.CURRENT, settings)) {
|
||||
TcpTransport originalTransport = (TcpTransport) service.getOriginalTransport();
|
||||
TransportAddress clientAddress = originalTransport.profileBoundAddresses().get("client").publishAddress();
|
||||
DiscoveryNode node = new DiscoveryNode(service.getLocalNode().getId(), clientAddress, service.getLocalNode().getVersion());
|
||||
try (Transport.Connection connection2 = serviceA.openConnection(node, TestProfiles.LIGHT_PROFILE)) {
|
||||
sslEngine = getEngineFromAcceptedChannel(originalTransport, connection2);
|
||||
assertEquals("client", getAcceptedChannel(originalTransport, connection2).getProfile());
|
||||
assertThat(sslEngine.getNeedClientAuth(), is(false));
|
||||
assertThat(sslEngine.getWantClientAuth(), is(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SSLEngine getEngineFromAcceptedChannel(TcpTransport transport, Transport.Connection connection) throws Exception {
|
||||
return SSLEngineUtils.getSSLEngine(getAcceptedChannel(transport, connection));
|
||||
}
|
||||
|
||||
private TcpChannel getAcceptedChannel(TcpTransport transport, Transport.Connection connection) throws Exception {
|
||||
InetSocketAddress localAddress = getSingleChannel(connection).getLocalAddress();
|
||||
AtomicReference<TcpChannel> accepted = new AtomicReference<>();
|
||||
assertBusy(() -> {
|
||||
Optional<TcpChannel> maybeAccepted = getAcceptedChannels(transport)
|
||||
.stream().filter(c -> c.getRemoteAddress().equals(localAddress)).findFirst();
|
||||
assertTrue(maybeAccepted.isPresent());
|
||||
accepted.set(maybeAccepted.get());
|
||||
});
|
||||
return accepted.get();
|
||||
}
|
||||
|
||||
private SSLEngine getSSLEngine(Transport.Connection connection) {
|
||||
return SSLEngineUtils.getSSLEngine(getSingleChannel(connection));
|
||||
}
|
||||
|
||||
private TcpChannel getSingleChannel(Transport.Connection connection) {
|
||||
StubbableTransport.WrappedConnection wrappedConnection = (StubbableTransport.WrappedConnection) connection;
|
||||
TcpTransport.NodeChannels nodeChannels = (TcpTransport.NodeChannels) wrappedConnection.getConnection();
|
||||
return nodeChannels.getChannels().get(0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,180 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.transport.netty4;
|
||||
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.settings.MockSecureSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.PageCacheRecycler;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.env.TestEnvironment;
|
||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.core.security.transport.netty4.SecurityNetty4Transport;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class SecurityNetty4ServerTransportTests extends ESTestCase {
|
||||
|
||||
private Environment env;
|
||||
private SSLService sslService;
|
||||
|
||||
@Before
|
||||
public void createSSLService() throws Exception {
|
||||
Path testnodeCert = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt");
|
||||
Path testnodeKey = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem");
|
||||
MockSecureSettings secureSettings = new MockSecureSettings();
|
||||
secureSettings.setString("xpack.security.transport.ssl.secure_key_passphrase", "testnode");
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("xpack.security.transport.ssl.key", testnodeKey)
|
||||
.put("xpack.security.transport.ssl.certificate", testnodeCert)
|
||||
.setSecureSettings(secureSettings)
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = TestEnvironment.newEnvironment(settings);
|
||||
sslService = new SSLService(settings, env);
|
||||
}
|
||||
|
||||
private SecurityNetty4Transport createTransport() {
|
||||
return createTransport(Settings.builder().put("xpack.security.transport.ssl.enabled", true).build());
|
||||
}
|
||||
|
||||
private SecurityNetty4Transport createTransport(Settings additionalSettings) {
|
||||
final Settings settings =
|
||||
Settings.builder()
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put(additionalSettings)
|
||||
.build();
|
||||
return new SecurityNetty4ServerTransport(
|
||||
settings,
|
||||
Version.CURRENT,
|
||||
mock(ThreadPool.class),
|
||||
new NetworkService(Collections.emptyList()),
|
||||
mock(PageCacheRecycler.class),
|
||||
mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class),
|
||||
null,
|
||||
sslService);
|
||||
}
|
||||
|
||||
public void testThatProfileTakesDefaultSSLSetting() throws Exception {
|
||||
SecurityNetty4Transport transport = createTransport();
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("default");
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine(), notNullValue());
|
||||
}
|
||||
|
||||
public void testDefaultClientAuth() throws Exception {
|
||||
SecurityNetty4Transport transport = createTransport();
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("default");
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(true));
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testRequiredClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(settings);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("default");
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(true));
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testNoClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(settings);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("default");
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false));
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testOptionalClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(settings);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("default");
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false));
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(true));
|
||||
}
|
||||
|
||||
public void testProfileRequiredClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("transport.profiles.client.port", "8000-9000")
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(settings);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client");
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(true));
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testProfileNoClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("transport.profiles.client.port", "8000-9000")
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(settings);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client");
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false));
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testProfileOptionalClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("transport.profiles.client.port", "8000-9000")
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(settings);
|
||||
final ChannelHandler handler = transport.getServerChannelInitializer("client");
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false));
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(true));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue