Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to built-in security transports from core #4119

Merged
merged 4 commits into from
Mar 26, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
@@ -114,6 +115,8 @@
import org.opensearch.plugins.ExtensionAwarePlugin;
import org.opensearch.plugins.IdentityPlugin;
import org.opensearch.plugins.MapperPlugin;
import org.opensearch.plugins.SecureSettingsFactory;
import org.opensearch.plugins.SecureTransportSettingsProvider;
import org.opensearch.repositories.RepositoriesService;
import org.opensearch.rest.RestController;
import org.opensearch.rest.RestHandler;
@@ -150,8 +153,8 @@
import org.opensearch.security.dlic.rest.validation.PasswordValidator;
import org.opensearch.security.filter.SecurityFilter;
import org.opensearch.security.filter.SecurityRestFilter;
import org.opensearch.security.http.SecurityHttpServerTransport;
import org.opensearch.security.http.SecurityNonSslHttpServerTransport;
import org.opensearch.security.http.NonSslHttpServerTransport;
import org.opensearch.security.http.SecureHttpServerTransport;
import org.opensearch.security.http.XFFResolver;
import org.opensearch.security.identity.SecurityTokenManager;
import org.opensearch.security.privileges.PrivilegesEvaluator;
@@ -167,11 +170,11 @@
import org.opensearch.security.securityconf.DynamicConfigFactory;
import org.opensearch.security.setting.OpensearchDynamicSetting;
import org.opensearch.security.setting.TransportPassiveAuthSetting;
import org.opensearch.security.ssl.OpenSearchSecureSettingsFactory;
import org.opensearch.security.ssl.OpenSearchSecuritySSLPlugin;
import org.opensearch.security.ssl.SslExceptionHandler;
import org.opensearch.security.ssl.http.netty.ValidatingDispatcher;
import org.opensearch.security.ssl.transport.DefaultPrincipalExtractor;
import org.opensearch.security.ssl.transport.SecuritySSLNettyTransport;
import org.opensearch.security.ssl.util.SSLConfigConstants;
import org.opensearch.security.support.ConfigConstants;
import org.opensearch.security.support.GuardedSearchOperationWrapper;
@@ -199,6 +202,7 @@
import org.opensearch.transport.TransportRequestOptions;
import org.opensearch.transport.TransportResponseHandler;
import org.opensearch.transport.TransportService;
import org.opensearch.transport.netty4.ssl.SecureNetty4Transport;
import org.opensearch.watcher.ResourceWatcherService;

import static org.opensearch.security.dlic.rest.api.RestApiAdminPrivilegesEvaluator.ENDPOINTS_WITH_PERMISSIONS;
@@ -858,44 +862,44 @@ public <T extends TransportResponse> void sendRequest(
}

@Override
public Map<String, Supplier<Transport>> getTransports(
public Map<String, Supplier<Transport>> getSecureTransports(
Settings settings,
ThreadPool threadPool,
PageCacheRecycler pageCacheRecycler,
CircuitBreakerService circuitBreakerService,
NamedWriteableRegistry namedWriteableRegistry,
NetworkService networkService,
SecureTransportSettingsProvider secureTransportSettingsProvider,
Tracer tracer
) {
Map<String, Supplier<Transport>> transports = new HashMap<String, Supplier<Transport>>();

if (SSLConfig.isSslOnlyMode()) {
return super.getTransports(
return super.getSecureTransports(
settings,
threadPool,
pageCacheRecycler,
circuitBreakerService,
namedWriteableRegistry,
networkService,
secureTransportSettingsProvider,
tracer
);
}

if (transportSSLEnabled) {
transports.put(
"org.opensearch.security.ssl.http.netty.SecuritySSLNettyTransport",
() -> new SecuritySSLNettyTransport(
settings,
() -> new SecureNetty4Transport(
migrateSettings(settings),
Version.CURRENT,
threadPool,
networkService,
pageCacheRecycler,
namedWriteableRegistry,
circuitBreakerService,
sks,
evaluateSslExceptionHandler(),
sharedGroupFactory,
SSLConfig,
secureTransportSettingsProvider,
tracer
)
);
@@ -904,7 +908,7 @@ public Map<String, Supplier<Transport>> getTransports(
}

@Override
public Map<String, Supplier<HttpServerTransport>> getHttpTransports(
public Map<String, Supplier<HttpServerTransport>> getSecureHttpTransports(
Settings settings,
ThreadPool threadPool,
BigArrays bigArrays,
@@ -914,11 +918,12 @@ public Map<String, Supplier<HttpServerTransport>> getHttpTransports(
NetworkService networkService,
Dispatcher dispatcher,
ClusterSettings clusterSettings,
SecureTransportSettingsProvider secureTransportSettingsProvider,
Tracer tracer
) {

if (SSLConfig.isSslOnlyMode()) {
return super.getHttpTransports(
return super.getSecureHttpTransports(
settings,
threadPool,
bigArrays,
@@ -928,6 +933,7 @@ public Map<String, Supplier<HttpServerTransport>> getHttpTransports(
networkService,
dispatcher,
clusterSettings,
secureTransportSettingsProvider,
tracer
);
}
@@ -943,17 +949,16 @@ public Map<String, Supplier<HttpServerTransport>> getHttpTransports(
evaluateSslExceptionHandler()
);
// TODO close odshst
final SecurityHttpServerTransport odshst = new SecurityHttpServerTransport(
settings,
final SecureHttpServerTransport odshst = new SecureHttpServerTransport(
migrateSettings(settings),
networkService,
bigArrays,
threadPool,
sks,
evaluateSslExceptionHandler(),
xContentRegistry,
validatingDispatcher,
clusterSettings,
sharedGroupFactory,
secureTransportSettingsProvider,
tracer,
securityRestHandler
);
@@ -962,15 +967,16 @@ public Map<String, Supplier<HttpServerTransport>> getHttpTransports(
} else if (!client) {
return Collections.singletonMap(
"org.opensearch.security.http.SecurityHttpServerTransport",
() -> new SecurityNonSslHttpServerTransport(
settings,
() -> new NonSslHttpServerTransport(
migrateSettings(settings),
networkService,
bigArrays,
threadPool,
xContentRegistry,
dispatcher,
clusterSettings,
sharedGroupFactory,
secureTransportSettingsProvider,
tracer,
securityRestHandler
)
@@ -2005,6 +2011,11 @@ public SecurityTokenManager getTokenManager() {
return tokenManager;
}

@Override
public Optional<SecureSettingsFactory> getSecureSettingFactory(Settings settings) {
return Optional.of(new OpenSearchSecureSettingsFactory(settings, sks, sslExceptionHandler));
}

public static class GuiceHolder implements LifecycleComponent {

private static RepositoriesService repositoriesService;
Original file line number Diff line number Diff line change
@@ -69,10 +69,10 @@

import static org.opensearch.security.OpenSearchSecurityPlugin.LEGACY_OPENDISTRO_PREFIX;
import static org.opensearch.security.OpenSearchSecurityPlugin.PLUGINS_PREFIX;
import static org.opensearch.security.http.SecurityHttpServerTransport.CONTEXT_TO_RESTORE;
import static org.opensearch.security.http.SecurityHttpServerTransport.EARLY_RESPONSE;
import static org.opensearch.security.http.SecurityHttpServerTransport.IS_AUTHENTICATED;
import static org.opensearch.security.http.SecurityHttpServerTransport.UNCONSUMED_PARAMS;
import static org.opensearch.security.http.SecureHttpServerTransport.CONTEXT_TO_RESTORE;
import static org.opensearch.security.http.SecureHttpServerTransport.EARLY_RESPONSE;
import static org.opensearch.security.http.SecureHttpServerTransport.IS_AUTHENTICATED;
import static org.opensearch.security.http.SecureHttpServerTransport.UNCONSUMED_PARAMS;

public class SecurityRestFilter {

Original file line number Diff line number Diff line change
@@ -33,6 +33,8 @@
import org.opensearch.core.xcontent.NamedXContentRegistry;
import org.opensearch.http.HttpHandlingSettings;
import org.opensearch.http.netty4.Netty4HttpServerTransport;
import org.opensearch.http.netty4.ssl.SecureNetty4HttpServerTransport;
import org.opensearch.plugins.SecureTransportSettingsProvider;
import org.opensearch.security.filter.SecurityRestFilter;
import org.opensearch.security.ssl.http.netty.Netty4ConditionalDecompressor;
import org.opensearch.security.ssl.http.netty.Netty4HttpRequestHeaderVerifier;
@@ -44,11 +46,11 @@
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class SecurityNonSslHttpServerTransport extends Netty4HttpServerTransport {
public class NonSslHttpServerTransport extends SecureNetty4HttpServerTransport {

private final ChannelInboundHandlerAdapter headerVerifier;

public SecurityNonSslHttpServerTransport(
public NonSslHttpServerTransport(
final Settings settings,
final NetworkService networkService,
final BigArrays bigArrays,
@@ -57,6 +59,7 @@ public SecurityNonSslHttpServerTransport(
final Dispatcher dispatcher,
final ClusterSettings clusterSettings,
final SharedGroupFactory sharedGroupFactory,
final SecureTransportSettingsProvider secureTransportSettingsProvider,
final Tracer tracer,
final SecurityRestFilter restFilter
) {
@@ -69,6 +72,7 @@ public SecurityNonSslHttpServerTransport(
dispatcher,
clusterSettings,
sharedGroupFactory,
secureTransportSettingsProvider,
tracer
);
headerVerifier = new Netty4HttpRequestHeaderVerifier(restFilter, threadPool, settings);
Original file line number Diff line number Diff line change
@@ -34,19 +34,21 @@
import org.opensearch.common.util.BigArrays;
import org.opensearch.common.util.concurrent.ThreadContext;
import org.opensearch.core.xcontent.NamedXContentRegistry;
import org.opensearch.http.netty4.ssl.SecureNetty4HttpServerTransport;
import org.opensearch.plugins.SecureTransportSettingsProvider;
import org.opensearch.security.filter.SecurityResponse;
import org.opensearch.security.filter.SecurityRestFilter;
import org.opensearch.security.ssl.SecurityKeyStore;
import org.opensearch.security.ssl.SslExceptionHandler;
import org.opensearch.security.ssl.http.netty.SecuritySSLNettyHttpServerTransport;
import org.opensearch.security.ssl.http.netty.Netty4ConditionalDecompressor;
import org.opensearch.security.ssl.http.netty.Netty4HttpRequestHeaderVerifier;
import org.opensearch.security.ssl.http.netty.ValidatingDispatcher;
import org.opensearch.telemetry.tracing.Tracer;
import org.opensearch.threadpool.ThreadPool;
import org.opensearch.transport.SharedGroupFactory;

import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.AttributeKey;

public class SecurityHttpServerTransport extends SecuritySSLNettyHttpServerTransport {
public class SecureHttpServerTransport extends SecureNetty4HttpServerTransport {

public static final AttributeKey<SecurityResponse> EARLY_RESPONSE = AttributeKey.newInstance("opensearch-http-early-response");
public static final AttributeKey<Set<String>> UNCONSUMED_PARAMS = AttributeKey.newInstance("opensearch-http-request-consumed-params");
@@ -56,17 +58,18 @@ public class SecurityHttpServerTransport extends SecuritySSLNettyHttpServerTrans
public static final AttributeKey<Boolean> SHOULD_DECOMPRESS = AttributeKey.newInstance("opensearch-http-should-decompress");
public static final AttributeKey<Boolean> IS_AUTHENTICATED = AttributeKey.newInstance("opensearch-http-is-authenticated");

public SecurityHttpServerTransport(
private final ChannelInboundHandlerAdapter headerVerifier;

public SecureHttpServerTransport(
final Settings settings,
final NetworkService networkService,
final BigArrays bigArrays,
final ThreadPool threadPool,
final SecurityKeyStore odsks,
final SslExceptionHandler sslExceptionHandler,
final NamedXContentRegistry namedXContentRegistry,
final ValidatingDispatcher dispatcher,
final ClusterSettings clusterSettings,
SharedGroupFactory sharedGroupFactory,
final SecureTransportSettingsProvider secureTransportSettingsProvider,
Tracer tracer,
SecurityRestFilter restFilter
) {
@@ -75,14 +78,24 @@ public SecurityHttpServerTransport(
networkService,
bigArrays,
threadPool,
odsks,
namedXContentRegistry,
dispatcher,
sslExceptionHandler,
clusterSettings,
sharedGroupFactory,
tracer,
restFilter
secureTransportSettingsProvider,
tracer
);

headerVerifier = new Netty4HttpRequestHeaderVerifier(restFilter, threadPool, settings);
}

@Override
protected ChannelInboundHandlerAdapter createHeaderVerifier() {
return headerVerifier;
}

@Override
protected ChannelInboundHandlerAdapter createDecompressor() {
return new Netty4ConditionalDecompressor();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

package org.opensearch.security.ssl;

import java.util.Optional;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;

import org.opensearch.common.settings.Settings;
import org.opensearch.http.HttpServerTransport;
import org.opensearch.plugins.SecureSettingsFactory;
import org.opensearch.plugins.SecureTransportSettingsProvider;
import org.opensearch.transport.TcpTransport;

public class OpenSearchSecureSettingsFactory implements SecureSettingsFactory {
private final Settings settings;
private final SecurityKeyStore sks;
private final SslExceptionHandler sslExceptionHandler;

public OpenSearchSecureSettingsFactory(Settings settings, SecurityKeyStore sks, SslExceptionHandler sslExceptionHandler) {
this.settings = settings;
this.sks = sks;
this.sslExceptionHandler = sslExceptionHandler;
}

@Override
public Optional<SecureTransportSettingsProvider> getSecureTransportSettingsProvider(Settings settings) {
return Optional.of(new SecureTransportSettingsProvider() {
@Override
public Optional<ServerExceptionHandler> buildHttpServerExceptionHandler(Settings settings, HttpServerTransport transport) {
return Optional.of(new ServerExceptionHandler() {
@Override
public void onError(Throwable t) {
sslExceptionHandler.logError(t, true);
}
});
}

@Override
public Optional<ServerExceptionHandler> buildServerTransportExceptionHandler(Settings settings, TcpTransport transport) {
return Optional.of(new ServerExceptionHandler() {
@Override
public void onError(Throwable t) {
sslExceptionHandler.logError(t, false);
}
});
}

@Override
public Optional<SSLEngine> buildSecureHttpServerEngine(Settings settings, HttpServerTransport transport) throws SSLException {
return Optional.of(sks.createHTTPSSLEngine());
}

@Override
public Optional<SSLEngine> buildSecureServerTransportEngine(Settings settings, TcpTransport transport) throws SSLException {
return Optional.of(sks.createServerTransportSSLEngine());
}

@Override
public Optional<SSLEngine> buildSecureClientTransportEngine(Settings settings, String hostname, int port) throws SSLException {
return Optional.of(sks.createClientTransportSSLEngine(hostname, port));
}
});
}
}
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;

@@ -62,6 +63,8 @@
import org.opensearch.http.HttpServerTransport.Dispatcher;
import org.opensearch.plugins.NetworkPlugin;
import org.opensearch.plugins.Plugin;
import org.opensearch.plugins.SecureSettingsFactory;
import org.opensearch.plugins.SecureTransportSettingsProvider;
import org.opensearch.plugins.SystemIndexPlugin;
import org.opensearch.repositories.RepositoriesService;
import org.opensearch.rest.RestController;
@@ -70,27 +73,43 @@
import org.opensearch.security.DefaultObjectMapper;
import org.opensearch.security.NonValidatingObjectMapper;
import org.opensearch.security.filter.SecurityRestFilter;
import org.opensearch.security.ssl.http.netty.SecuritySSLNettyHttpServerTransport;
import org.opensearch.security.http.SecureHttpServerTransport;
import org.opensearch.security.ssl.http.netty.ValidatingDispatcher;
import org.opensearch.security.ssl.rest.SecuritySSLInfoAction;
import org.opensearch.security.ssl.transport.DefaultPrincipalExtractor;
import org.opensearch.security.ssl.transport.PrincipalExtractor;
import org.opensearch.security.ssl.transport.SSLConfig;
import org.opensearch.security.ssl.transport.SecuritySSLNettyTransport;
import org.opensearch.security.ssl.transport.SecuritySSLTransportInterceptor;
import org.opensearch.security.ssl.util.SSLConfigConstants;
import org.opensearch.security.support.SecuritySettings;
import org.opensearch.telemetry.tracing.Tracer;
import org.opensearch.threadpool.ThreadPool;
import org.opensearch.transport.SharedGroupFactory;
import org.opensearch.transport.Transport;
import org.opensearch.transport.TransportInterceptor;
import org.opensearch.transport.netty4.ssl.SecureNetty4Transport;
import org.opensearch.watcher.ResourceWatcherService;

import io.netty.handler.ssl.OpenSsl;
import io.netty.util.internal.PlatformDependent;

//For ES5 this class has only effect when SSL only plugin is installed
public class OpenSearchSecuritySSLPlugin extends Plugin implements SystemIndexPlugin, NetworkPlugin {
private static final Setting<Boolean> SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION = Setting.boolSetting(
SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION,
true,
Property.NodeScope,
Property.Filtered,
Property.Deprecated
);

private static final Setting<Boolean> SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME = Setting.boolSetting(
SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME,
true,
Property.NodeScope,
Property.Filtered,
Property.Deprecated
);

private static boolean USE_NETTY_DEFAULT_ALLOCATOR = Booleans.parseBoolean(
System.getProperty("opensearch.unsafe.use_netty_default_allocator"),
@@ -237,7 +256,7 @@
}

@Override
public Map<String, Supplier<HttpServerTransport>> getHttpTransports(
public Map<String, Supplier<HttpServerTransport>> getSecureHttpTransports(
Settings settings,
ThreadPool threadPool,
BigArrays bigArrays,
@@ -247,6 +266,7 @@
NetworkService networkService,
Dispatcher dispatcher,
ClusterSettings clusterSettings,
SecureTransportSettingsProvider secureTransportSettingsProvider,
Tracer tracer
) {

@@ -259,17 +279,16 @@
configPath,
NOOP_SSL_EXCEPTION_HANDLER
);
final SecuritySSLNettyHttpServerTransport sgsnht = new SecuritySSLNettyHttpServerTransport(
settings,
final SecureHttpServerTransport sgsnht = new SecureHttpServerTransport(
migrateSettings(settings),
networkService,
bigArrays,
threadPool,
sks,
xContentRegistry,
validatingDispatcher,
NOOP_SSL_EXCEPTION_HANDLER,
clusterSettings,
sharedGroupFactory,
secureTransportSettingsProvider,
tracer,
securityRestHandler
);
@@ -313,32 +332,31 @@
}

@Override
public Map<String, Supplier<Transport>> getTransports(
public Map<String, Supplier<Transport>> getSecureTransports(
Settings settings,
ThreadPool threadPool,
PageCacheRecycler pageCacheRecycler,
CircuitBreakerService circuitBreakerService,
NamedWriteableRegistry namedWriteableRegistry,
NetworkService networkService,
SecureTransportSettingsProvider secureTransportSettingsProvider,
Tracer tracer
) {

Map<String, Supplier<Transport>> transports = new HashMap<String, Supplier<Transport>>();
if (transportSSLEnabled) {
transports.put(
"org.opensearch.security.ssl.http.netty.SecuritySSLNettyTransport",
() -> new SecuritySSLNettyTransport(
settings,
() -> new SecureNetty4Transport(
migrateSettings(settings),
Version.CURRENT,
threadPool,
networkService,
pageCacheRecycler,
namedWriteableRegistry,
circuitBreakerService,
sks,
NOOP_SSL_EXCEPTION_HANDLER,
sharedGroupFactory,
SSLConfig,
secureTransportSettingsProvider,
tracer
)
);
@@ -436,22 +454,13 @@
Property.Filtered
)
);
settings.add(
Setting.boolSetting(
SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION,
true,
Property.NodeScope,
Property.Filtered
)
);
settings.add(
Setting.boolSetting(
SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME,
true,
Property.NodeScope,
Property.Filtered
)
);
if (!settings.stream().anyMatch(s -> s.getKey().equalsIgnoreCase(NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION_KEY))) {
settings.add(SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION);
}
if (!settings.stream()
.anyMatch(s -> s.getKey().equalsIgnoreCase(NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME_KEY))) {
settings.add(SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME);
}
settings.add(
Setting.simpleString(SSLConfigConstants.SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH, Property.NodeScope, Property.Filtered)
);
@@ -664,4 +673,63 @@
settingsFilter.add("plugins.security.*");
return settingsFilter;
}

@Override
public Optional<SecureSettingsFactory> getSecureSettingFactory(Settings settings) {
return Optional.of(new OpenSearchSecureSettingsFactory(settings, sks, NOOP_SSL_EXCEPTION_HANDLER));

Check warning on line 679 in src/main/java/org/opensearch/security/ssl/OpenSearchSecuritySSLPlugin.java

Codecov / codecov/patch

src/main/java/org/opensearch/security/ssl/OpenSearchSecuritySSLPlugin.java#L679

Added line #L679 was not covered by tests
}

protected Settings migrateSettings(Settings settings) {
final Settings.Builder builder = Settings.builder().put(settings);

if (!NetworkModule.TRANSPORT_SSL_DUAL_MODE_ENABLED.exists(settings)) {
builder.put(NetworkModule.TRANSPORT_SSL_DUAL_MODE_ENABLED_KEY, SecuritySettings.SSL_DUAL_MODE_SETTING.get(settings));
} else {
if (SecuritySettings.SSL_DUAL_MODE_SETTING.exists(settings)) {
throw new OpenSearchException(
"Only one of the settings ["
+ NetworkModule.TRANSPORT_SSL_DUAL_MODE_ENABLED_KEY
+ ", "
+ SecuritySettings.SSL_DUAL_MODE_SETTING.getKey()
+ " (deprecated)] could be specified but not both"
);
}
}

if (!NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME.exists(settings)) {
builder.put(
NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME_KEY,
SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME.get(settings)
);
} else {
if (SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME.exists(settings)) {
throw new OpenSearchException(
"Only one of the settings ["
+ NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME_KEY
+ ", "
+ SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME.getKey()
+ " (deprecated)] could be specified but not both"
);
}
}

if (!NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION.exists(settings)) {
builder.put(
NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION_KEY,
SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION.get(settings)
);
} else {
if (SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION.exists(settings)) {
throw new OpenSearchException(
"Only one of the settings ["
+ NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION_KEY
+ ", "
+ SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION.getKey()
+ " (deprecated)] could be specified but not both"
);
}
}

return builder.build();
}
}
Original file line number Diff line number Diff line change
@@ -13,8 +13,8 @@
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.HttpContentDecompressor;

import static org.opensearch.security.http.SecurityHttpServerTransport.EARLY_RESPONSE;
import static org.opensearch.security.http.SecurityHttpServerTransport.SHOULD_DECOMPRESS;
import static org.opensearch.security.http.SecureHttpServerTransport.EARLY_RESPONSE;
import static org.opensearch.security.http.SecureHttpServerTransport.SHOULD_DECOMPRESS;

public class Netty4ConditionalDecompressor extends HttpContentDecompressor {

Original file line number Diff line number Diff line change
@@ -32,11 +32,11 @@
import io.netty.handler.codec.http.HttpRequest;
import io.netty.util.ReferenceCountUtil;

import static org.opensearch.security.http.SecurityHttpServerTransport.CONTEXT_TO_RESTORE;
import static org.opensearch.security.http.SecurityHttpServerTransport.EARLY_RESPONSE;
import static org.opensearch.security.http.SecurityHttpServerTransport.IS_AUTHENTICATED;
import static org.opensearch.security.http.SecurityHttpServerTransport.SHOULD_DECOMPRESS;
import static org.opensearch.security.http.SecurityHttpServerTransport.UNCONSUMED_PARAMS;
import static org.opensearch.security.http.SecureHttpServerTransport.CONTEXT_TO_RESTORE;
import static org.opensearch.security.http.SecureHttpServerTransport.EARLY_RESPONSE;
import static org.opensearch.security.http.SecureHttpServerTransport.IS_AUTHENTICATED;
import static org.opensearch.security.http.SecureHttpServerTransport.SHOULD_DECOMPRESS;
import static org.opensearch.security.http.SecureHttpServerTransport.UNCONSUMED_PARAMS;

@Sharable
public class Netty4HttpRequestHeaderVerifier extends SimpleChannelInboundHandler<DefaultHttpRequest> {

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.security.ssl;

import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;

import org.junit.Before;
import org.junit.Test;

import org.opensearch.OpenSearchException;
import org.opensearch.common.collect.Tuple;
import org.opensearch.common.network.NetworkModule;
import org.opensearch.common.settings.ClusterSettings;
import org.opensearch.common.settings.Settings;
import org.opensearch.http.HttpServerTransport;
import org.opensearch.plugins.SecureTransportSettingsProvider;
import org.opensearch.security.ssl.util.SSLConfigConstants;
import org.opensearch.security.support.SecuritySettings;
import org.opensearch.security.test.AbstractSecurityUnitTest;
import org.opensearch.security.test.helper.file.FileHelper;
import org.opensearch.telemetry.tracing.noop.NoopTracer;
import org.opensearch.transport.TcpTransport;
import org.opensearch.transport.Transport;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsMapContaining.hasKey;
import static org.junit.Assert.assertThrows;

public class OpenSearchSecuritySSLPluginTest extends AbstractSecurityUnitTest {
private Settings settings;
private SecureTransportSettingsProvider secureTransportSettingsProvider;
private ClusterSettings clusterSettings;

@Before
public void setUp() {
settings = Settings.builder()
.put(
SSLConfigConstants.SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH,
FileHelper.getAbsoluteFilePathFromClassPath("ssl/kirk-keystore.jks")
)
.put(
SSLConfigConstants.SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH,
FileHelper.getAbsoluteFilePathFromClassPath("ssl/root-ca.pem")
)
.put(
SSLConfigConstants.SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH,
FileHelper.getAbsoluteFilePathFromClassPath("ssl/truststore.jks")
)
.put(
SSLConfigConstants.SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH,
FileHelper.getAbsoluteFilePathFromClassPath("ssl/kirk-keystore.jks")
)
.put(
SSLConfigConstants.SECURITY_SSL_HTTP_KEYSTORE_FILEPATH,
FileHelper.getAbsoluteFilePathFromClassPath("ssl/node-0-keystore.jks")
)
.put(SSLConfigConstants.SECURITY_SSL_HTTP_ENABLED, true)
.put(OpenSearchSecuritySSLPlugin.CLIENT_TYPE, "node")
.build();

secureTransportSettingsProvider = new SecureTransportSettingsProvider() {
@Override
public Optional<ServerExceptionHandler> buildHttpServerExceptionHandler(Settings settings, HttpServerTransport transport) {
return Optional.empty();
}

@Override
public Optional<ServerExceptionHandler> buildServerTransportExceptionHandler(Settings settings, TcpTransport transport) {
return Optional.empty();
}

@Override
public Optional<SSLEngine> buildSecureHttpServerEngine(Settings settings, HttpServerTransport transport) throws SSLException {
return Optional.empty();
}

@Override
public Optional<SSLEngine> buildSecureServerTransportEngine(Settings settings, TcpTransport transport) throws SSLException {
return Optional.empty();
}

@Override
public Optional<SSLEngine> buildSecureClientTransportEngine(Settings settings, String hostname, int port) throws SSLException {
return Optional.empty();
}
};

clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
}

@Test
public void testRegisterSecureHttpTransport() throws IOException {
try (OpenSearchSecuritySSLPlugin plugin = new OpenSearchSecuritySSLPlugin(settings, null, false)) {
final Map<String, Supplier<HttpServerTransport>> transports = plugin.getSecureHttpTransports(
settings,
MOCK_POOL,
null,
null,
null,
null,
null,
null,
clusterSettings,
secureTransportSettingsProvider,
NoopTracer.INSTANCE
);
assertThat(transports, hasKey("org.opensearch.security.ssl.http.netty.SecuritySSLNettyHttpServerTransport"));
}
}

@Test
public void testRegisterSecureTransport() throws IOException {
try (OpenSearchSecuritySSLPlugin plugin = new OpenSearchSecuritySSLPlugin(settings, null, false)) {
final Map<String, Supplier<Transport>> transports = plugin.getSecureTransports(
settings,
MOCK_POOL,
null,
null,
null,
null,
secureTransportSettingsProvider,
NoopTracer.INSTANCE
);
assertThat(transports, hasKey("org.opensearch.security.ssl.http.netty.SecuritySSLNettyTransport"));
}
}

@Test
public void testRegisterSecureTransportWithDeprecatedSecuirtyPluginSettings() throws IOException {
final Settings deprecated = Settings.builder()
.put(settings)
.put(SecuritySettings.SSL_DUAL_MODE_SETTING.getKey(), true)
.put(SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME, false)
.put(SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION, false)
.build();

try (OpenSearchSecuritySSLPlugin plugin = new OpenSearchSecuritySSLPlugin(deprecated, null, false)) {
final Map<String, Supplier<Transport>> transports = plugin.getSecureTransports(
deprecated,
MOCK_POOL,
null,
null,
null,
null,
secureTransportSettingsProvider,
NoopTracer.INSTANCE
);
assertThat(transports, hasKey("org.opensearch.security.ssl.http.netty.SecuritySSLNettyTransport"));
assertThat(transports.get("org.opensearch.security.ssl.http.netty.SecuritySSLNettyTransport").get(), not(nullValue()));
}
}

@Test
public void testRegisterSecureTransportWithNetworkModuleSettings() throws IOException {
final Settings migrated = Settings.builder()
.put(settings)
.put(NetworkModule.TRANSPORT_SSL_DUAL_MODE_ENABLED_KEY, true)
.put(NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME_KEY, false)
.put(NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION_KEY, false)
.build();

try (OpenSearchSecuritySSLPlugin plugin = new OpenSearchSecuritySSLPlugin(migrated, null, false)) {
final Map<String, Supplier<Transport>> transports = plugin.getSecureTransports(
migrated,
MOCK_POOL,
null,
null,
null,
null,
secureTransportSettingsProvider,
NoopTracer.INSTANCE
);
assertThat(transports, hasKey("org.opensearch.security.ssl.http.netty.SecuritySSLNettyTransport"));
assertThat(transports.get("org.opensearch.security.ssl.http.netty.SecuritySSLNettyTransport").get(), not(nullValue()));
}
}

@Test
public void testRegisterSecureTransportWithDuplicateSettings() throws IOException {
final Collection<Tuple<String, String>> duplicates = List.of(
Tuple.tuple(SecuritySettings.SSL_DUAL_MODE_SETTING.getKey(), NetworkModule.TRANSPORT_SSL_DUAL_MODE_ENABLED_KEY),
Tuple.tuple(
SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME,
NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME_KEY
),
Tuple.tuple(
SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION,
NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION_KEY
)
);

for (final Tuple<String, String> duplicate : duplicates) {
final Settings migrated = Settings.builder()
.put(settings)
.put(duplicate.v1(), true)
.put(NetworkModule.TRANSPORT_SSL_DUAL_MODE_ENABLED_KEY, true)
.put(NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME_KEY, false)
.put(NetworkModule.TRANSPORT_SSL_ENFORCE_HOSTNAME_VERIFICATION_KEY, false)
.build();

try (OpenSearchSecuritySSLPlugin plugin = new OpenSearchSecuritySSLPlugin(migrated, null, false)) {
final Map<String, Supplier<Transport>> transports = plugin.getSecureTransports(
migrated,
MOCK_POOL,
null,
null,
null,
null,
secureTransportSettingsProvider,
NoopTracer.INSTANCE
);
assertThat(transports, hasKey("org.opensearch.security.ssl.http.netty.SecuritySSLNettyTransport"));
final OpenSearchException ex = assertThrows(
OpenSearchException.class,
transports.get("org.opensearch.security.ssl.http.netty.SecuritySSLNettyTransport")::get
);
assertThat(
ex.getMessage(),
containsString(
"Only one of the settings ["
+ duplicate.v2()
+ ", "
+ duplicate.v1()
+ " (deprecated)] could be specified but not both"
)
);
}
}
}
}

This file was deleted.

This file was deleted.