From 15d1b904a1a053c3d26072c604fa2ff0026bc87e Mon Sep 17 00:00:00 2001 From: Hendrik Muhs Date: Wed, 16 Jan 2019 08:10:13 +0100 Subject: [PATCH 01/16] =?UTF-8?q?[ML]=20log=20minimum=20diskspace=20settin?= =?UTF-8?q?g=20if=20forecast=20fails=20due=20to=20insufficient=20d?= =?UTF-8?q?=E2=80=A6=20(#37486)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit log minimum disk space setting if forecast fails due to insufficient disk space --- .../xpack/ml/action/TransportForecastJobAction.java | 9 ++++++++- .../job/process/autodetect/AutodetectProcessManager.java | 4 ++++ .../xpack/ml/process/NativeStorageProvider.java | 4 ++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/action/TransportForecastJobAction.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/action/TransportForecastJobAction.java index 6bcadf1ddb06f..3a26f9f863cdb 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/action/TransportForecastJobAction.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/action/TransportForecastJobAction.java @@ -97,8 +97,15 @@ private void getForecastRequestStats(String jobId, String forecastId, ActionList } else if (forecastRequestStats.getStatus() == ForecastRequestStats.ForecastRequestStatus.FAILED) { List messages = forecastRequestStats.getMessages(); if (messages.size() > 0) { + String message = messages.get(0); + + // special case: if forecast failed due to insufficient disk space, log the setting + if (message.contains("disk space is insufficient")) { + message += " Minimum disk space required: [" + processManager.getMinLocalStorageAvailable() + "]"; + } + listener.onFailure(ExceptionsHelper.badRequestException("Cannot run forecast: " - + messages.get(0))); + + message)); } else { // paranoia case, it should not be possible to have an empty message list listener.onFailure( diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/job/process/autodetect/AutodetectProcessManager.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/job/process/autodetect/AutodetectProcessManager.java index ef03b4f9e7160..fb6e9d46f4064 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/job/process/autodetect/AutodetectProcessManager.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/job/process/autodetect/AutodetectProcessManager.java @@ -749,6 +749,10 @@ ExecutorService createAutodetectExecutorService(ExecutorService executorService) return autoDetectWorkerExecutor; } + public ByteSizeValue getMinLocalStorageAvailable() { + return nativeStorageProvider.getMinLocalStorageAvailable(); + } + /* * The autodetect native process can only handle a single operation at a time. In order to guarantee that, all * operations are initially added to a queue and a worker thread from ml autodetect threadpool will process each diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/process/NativeStorageProvider.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/process/NativeStorageProvider.java index 1f9aee7bbeea3..9f366ab11312e 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/process/NativeStorageProvider.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/process/NativeStorageProvider.java @@ -111,6 +111,10 @@ public void cleanupLocalTmpStorage(Path path) throws IOException { } } + public ByteSizeValue getMinLocalStorageAvailable() { + return minLocalStorageAvailable; + } + long getUsableSpace(Path path) throws IOException { long freeSpaceInBytes = Environment.getFileStore(path).getUsableSpace(); From 5e94f384c41fecc94c412c3162863c93895dfe4c Mon Sep 17 00:00:00 2001 From: Przemyslaw Gomulka Date: Wed, 16 Jan 2019 09:05:30 +0100 Subject: [PATCH 02/16] Remove the use of AbstracLifecycleComponent constructor #37488 (#37488) The AbstracLifecycleComponent used to extend AbstractComponent, so it had to pass settings to the constractor of its supper class. It no longer extends the AbstractComponent so there is no need for this constructor There is also no need for AbstracLifecycleComponent subclasses to have Settings in their constructors if they were only passing it over to super constructor. This is part 1. which will be backported to 6.x with a migration guide/deprecation log. part 2 will have this constructor removed in 7 relates #35560 relates #34488 --- .../azure/classic/management/AzureComputeServiceImpl.java | 1 - .../org/elasticsearch/cloud/gce/GceMetadataService.java | 1 - .../org/elasticsearch/cluster/NodeConnectionsService.java | 1 - .../elasticsearch/cluster/coordination/Coordinator.java | 1 - .../cluster/routing/DelayedAllocationService.java | 4 +--- .../org/elasticsearch/cluster/routing/RoutingService.java | 4 +--- .../cluster/service/ClusterApplierService.java | 1 - .../org/elasticsearch/cluster/service/ClusterService.java | 1 - .../org/elasticsearch/cluster/service/MasterService.java | 1 - .../common/component/AbstractLifecycleComponent.java | 3 +++ .../discovery/UnicastConfiguredHostsResolver.java | 1 - .../discovery/single/SingleNodeDiscovery.java | 1 - .../org/elasticsearch/discovery/zen/ZenDiscovery.java | 1 - .../java/org/elasticsearch/gateway/GatewayService.java | 1 - .../elasticsearch/http/AbstractHttpServerTransport.java | 1 - .../java/org/elasticsearch/indices/IndicesService.java | 1 - .../indices/breaker/CircuitBreakerService.java | 4 +--- .../indices/breaker/HierarchyCircuitBreakerService.java | 2 +- .../indices/breaker/NoneCircuitBreakerService.java | 3 +-- .../indices/cluster/IndicesClusterStateService.java | 1 - .../java/org/elasticsearch/monitor/MonitorService.java | 1 - .../elasticsearch/monitor/jvm/JvmGcMonitorService.java | 1 - .../repositories/blobstore/BlobStoreRepository.java | 1 - .../main/java/org/elasticsearch/search/SearchService.java | 1 - .../elasticsearch/snapshots/SnapshotShardsService.java | 1 - .../org/elasticsearch/snapshots/SnapshotsService.java | 1 - .../java/org/elasticsearch/transport/TcpTransport.java | 1 - .../org/elasticsearch/transport/TransportService.java | 1 - .../org/elasticsearch/watcher/ResourceWatcherService.java | 1 - .../cluster/routing/DelayedAllocationServiceTests.java | 8 ++++---- .../cluster/routing/RoutingServiceTests.java | 3 +-- .../elasticsearch/common/network/NetworkModuleTests.java | 3 --- .../org/elasticsearch/index/shard/IndexShardTests.java | 1 - .../java/org/elasticsearch/rest/RestControllerTests.java | 1 - .../elasticsearch/snapshots/SnapshotsServiceTests.java | 2 +- .../java/org/elasticsearch/test/MockHttpTransport.java | 5 ----- .../src/main/java/org/elasticsearch/xpack/ccr/Ccr.java | 2 +- .../org/elasticsearch/xpack/ccr/CcrRepositoryManager.java | 1 - .../elasticsearch/xpack/ccr/repository/CcrRepository.java | 1 - .../xpack/ccr/repository/CcrRestoreSourceService.java | 4 ---- .../ccr/repository/CcrRestoreSourceServiceTests.java | 2 +- .../java/org/elasticsearch/license/LicenseService.java | 1 - .../elasticsearch/xpack/monitoring/MonitoringService.java | 1 - .../xpack/monitoring/cleaner/CleanerService.java | 1 - .../xpack/monitoring/exporter/Exporters.java | 1 - .../xpack/monitoring/MonitoringServiceTests.java | 1 - 46 files changed, 16 insertions(+), 65 deletions(-) diff --git a/plugins/discovery-azure-classic/src/main/java/org/elasticsearch/cloud/azure/classic/management/AzureComputeServiceImpl.java b/plugins/discovery-azure-classic/src/main/java/org/elasticsearch/cloud/azure/classic/management/AzureComputeServiceImpl.java index 710dfa7e71df7..b8e885b947006 100644 --- a/plugins/discovery-azure-classic/src/main/java/org/elasticsearch/cloud/azure/classic/management/AzureComputeServiceImpl.java +++ b/plugins/discovery-azure-classic/src/main/java/org/elasticsearch/cloud/azure/classic/management/AzureComputeServiceImpl.java @@ -52,7 +52,6 @@ public class AzureComputeServiceImpl extends AbstractLifecycleComponent private final String serviceName; public AzureComputeServiceImpl(Settings settings) { - super(settings); String subscriptionId = getRequiredSetting(settings, Management.SUBSCRIPTION_ID_SETTING); serviceName = getRequiredSetting(settings, Management.SERVICE_NAME_SETTING); diff --git a/plugins/discovery-gce/src/main/java/org/elasticsearch/cloud/gce/GceMetadataService.java b/plugins/discovery-gce/src/main/java/org/elasticsearch/cloud/gce/GceMetadataService.java index 248d9a0447915..1fae7e63854c1 100644 --- a/plugins/discovery-gce/src/main/java/org/elasticsearch/cloud/gce/GceMetadataService.java +++ b/plugins/discovery-gce/src/main/java/org/elasticsearch/cloud/gce/GceMetadataService.java @@ -53,7 +53,6 @@ public class GceMetadataService extends AbstractLifecycleComponent { private HttpTransport gceHttpTransport; public GceMetadataService(Settings settings) { - super(settings); this.settings = settings; } diff --git a/server/src/main/java/org/elasticsearch/cluster/NodeConnectionsService.java b/server/src/main/java/org/elasticsearch/cluster/NodeConnectionsService.java index 8010765854016..90526aaa9fd21 100644 --- a/server/src/main/java/org/elasticsearch/cluster/NodeConnectionsService.java +++ b/server/src/main/java/org/elasticsearch/cluster/NodeConnectionsService.java @@ -75,7 +75,6 @@ public class NodeConnectionsService extends AbstractLifecycleComponent { @Inject public NodeConnectionsService(Settings settings, ThreadPool threadPool, TransportService transportService) { - super(settings); this.threadPool = threadPool; this.transportService = transportService; this.reconnectInterval = NodeConnectionsService.CLUSTER_NODE_RECONNECT_INTERVAL_SETTING.get(settings); diff --git a/server/src/main/java/org/elasticsearch/cluster/coordination/Coordinator.java b/server/src/main/java/org/elasticsearch/cluster/coordination/Coordinator.java index 805eef9a89c06..72fe2e081de74 100644 --- a/server/src/main/java/org/elasticsearch/cluster/coordination/Coordinator.java +++ b/server/src/main/java/org/elasticsearch/cluster/coordination/Coordinator.java @@ -145,7 +145,6 @@ public Coordinator(String nodeName, Settings settings, ClusterSettings clusterSe NamedWriteableRegistry namedWriteableRegistry, AllocationService allocationService, MasterService masterService, Supplier persistedStateSupplier, UnicastHostsProvider unicastHostsProvider, ClusterApplier clusterApplier, Collection> onJoinValidators, Random random) { - super(settings); this.settings = settings; this.transportService = transportService; this.masterService = masterService; diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/DelayedAllocationService.java b/server/src/main/java/org/elasticsearch/cluster/routing/DelayedAllocationService.java index b8fb432f311ce..9349de94a66e2 100644 --- a/server/src/main/java/org/elasticsearch/cluster/routing/DelayedAllocationService.java +++ b/server/src/main/java/org/elasticsearch/cluster/routing/DelayedAllocationService.java @@ -30,7 +30,6 @@ import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.AbstractRunnable; import org.elasticsearch.common.util.concurrent.FutureUtils; @@ -130,9 +129,8 @@ public void onFailure(String source, Exception e) { } @Inject - public DelayedAllocationService(Settings settings, ThreadPool threadPool, ClusterService clusterService, + public DelayedAllocationService(ThreadPool threadPool, ClusterService clusterService, AllocationService allocationService) { - super(settings); this.threadPool = threadPool; this.clusterService = clusterService; this.allocationService = allocationService; diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/RoutingService.java b/server/src/main/java/org/elasticsearch/cluster/routing/RoutingService.java index 5d711cabce763..57f7a313942bb 100644 --- a/server/src/main/java/org/elasticsearch/cluster/routing/RoutingService.java +++ b/server/src/main/java/org/elasticsearch/cluster/routing/RoutingService.java @@ -30,7 +30,6 @@ import org.elasticsearch.common.Priority; import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; import java.util.concurrent.atomic.AtomicBoolean; @@ -57,8 +56,7 @@ public class RoutingService extends AbstractLifecycleComponent { private AtomicBoolean rerouting = new AtomicBoolean(); @Inject - public RoutingService(Settings settings, ClusterService clusterService, AllocationService allocationService) { - super(settings); + public RoutingService(ClusterService clusterService, AllocationService allocationService) { this.clusterService = clusterService; this.allocationService = allocationService; } diff --git a/server/src/main/java/org/elasticsearch/cluster/service/ClusterApplierService.java b/server/src/main/java/org/elasticsearch/cluster/service/ClusterApplierService.java index 5bd441419d136..fa3d4997efb4b 100644 --- a/server/src/main/java/org/elasticsearch/cluster/service/ClusterApplierService.java +++ b/server/src/main/java/org/elasticsearch/cluster/service/ClusterApplierService.java @@ -102,7 +102,6 @@ public class ClusterApplierService extends AbstractLifecycleComponent implements private NodeConnectionsService nodeConnectionsService; public ClusterApplierService(String nodeName, Settings settings, ClusterSettings clusterSettings, ThreadPool threadPool) { - super(settings); this.clusterSettings = clusterSettings; this.threadPool = threadPool; this.state = new AtomicReference<>(); diff --git a/server/src/main/java/org/elasticsearch/cluster/service/ClusterService.java b/server/src/main/java/org/elasticsearch/cluster/service/ClusterService.java index 12d45c4fb88f4..f66ca0738954b 100644 --- a/server/src/main/java/org/elasticsearch/cluster/service/ClusterService.java +++ b/server/src/main/java/org/elasticsearch/cluster/service/ClusterService.java @@ -78,7 +78,6 @@ public ClusterService(Settings settings, ClusterSettings clusterSettings, Thread public ClusterService(Settings settings, ClusterSettings clusterSettings, MasterService masterService, ClusterApplierService clusterApplierService) { - super(settings); this.settings = settings; this.nodeName = Node.NODE_NAME_SETTING.get(settings); this.masterService = masterService; diff --git a/server/src/main/java/org/elasticsearch/cluster/service/MasterService.java b/server/src/main/java/org/elasticsearch/cluster/service/MasterService.java index 472ffcd73effd..50cf4ffe9de8a 100644 --- a/server/src/main/java/org/elasticsearch/cluster/service/MasterService.java +++ b/server/src/main/java/org/elasticsearch/cluster/service/MasterService.java @@ -87,7 +87,6 @@ public class MasterService extends AbstractLifecycleComponent { private volatile Batcher taskBatcher; public MasterService(String nodeName, Settings settings, ThreadPool threadPool) { - super(settings); this.nodeName = nodeName; // TODO: introduce a dedicated setting for master service this.slowTaskLoggingThreshold = CLUSTER_SERVICE_SLOW_TASK_LOGGING_THRESHOLD_SETTING.get(settings); diff --git a/server/src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java b/server/src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java index f7dc6c55506f1..2caaa43fbcd05 100644 --- a/server/src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java +++ b/server/src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java @@ -34,6 +34,9 @@ public abstract class AbstractLifecycleComponent implements LifecycleComponent { private final List listeners = new CopyOnWriteArrayList<>(); + protected AbstractLifecycleComponent() {} + + @Deprecated protected AbstractLifecycleComponent(Settings settings) { // TODO drop settings from ctor } diff --git a/server/src/main/java/org/elasticsearch/discovery/UnicastConfiguredHostsResolver.java b/server/src/main/java/org/elasticsearch/discovery/UnicastConfiguredHostsResolver.java index 5200d9d36f60e..fcc716a7785a4 100644 --- a/server/src/main/java/org/elasticsearch/discovery/UnicastConfiguredHostsResolver.java +++ b/server/src/main/java/org/elasticsearch/discovery/UnicastConfiguredHostsResolver.java @@ -56,7 +56,6 @@ public class UnicastConfiguredHostsResolver extends AbstractLifecycleComponent i public UnicastConfiguredHostsResolver(String nodeName, Settings settings, TransportService transportService, UnicastHostsProvider hostsProvider) { - super(settings); this.settings = settings; this.nodeName = nodeName; this.transportService = transportService; diff --git a/server/src/main/java/org/elasticsearch/discovery/single/SingleNodeDiscovery.java b/server/src/main/java/org/elasticsearch/discovery/single/SingleNodeDiscovery.java index 238f72f72f464..2a415a74cd0cc 100644 --- a/server/src/main/java/org/elasticsearch/discovery/single/SingleNodeDiscovery.java +++ b/server/src/main/java/org/elasticsearch/discovery/single/SingleNodeDiscovery.java @@ -59,7 +59,6 @@ public class SingleNodeDiscovery extends AbstractLifecycleComponent implements D public SingleNodeDiscovery(final Settings settings, final TransportService transportService, final MasterService masterService, final ClusterApplier clusterApplier, final GatewayMetaState gatewayMetaState) { - super(Objects.requireNonNull(settings)); this.clusterName = ClusterName.CLUSTER_NAME_SETTING.get(settings); this.transportService = Objects.requireNonNull(transportService); masterService.setClusterStateSupplier(() -> clusterState); diff --git a/server/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java b/server/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java index 05d0bfa27188a..0ee69bbfeec93 100644 --- a/server/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java +++ b/server/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java @@ -161,7 +161,6 @@ public ZenDiscovery(Settings settings, ThreadPool threadPool, TransportService t NamedWriteableRegistry namedWriteableRegistry, MasterService masterService, ClusterApplier clusterApplier, ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider, AllocationService allocationService, Collection> onJoinValidators, GatewayMetaState gatewayMetaState) { - super(settings); this.onJoinValidators = JoinTaskExecutor.addBuiltInJoinValidators(onJoinValidators); this.masterService = masterService; this.clusterApplier = clusterApplier; diff --git a/server/src/main/java/org/elasticsearch/gateway/GatewayService.java b/server/src/main/java/org/elasticsearch/gateway/GatewayService.java index 1574874634cf5..c71ae40235056 100644 --- a/server/src/main/java/org/elasticsearch/gateway/GatewayService.java +++ b/server/src/main/java/org/elasticsearch/gateway/GatewayService.java @@ -95,7 +95,6 @@ public GatewayService(final Settings settings, final AllocationService allocatio final ThreadPool threadPool, final TransportNodesListGatewayMetaState listGatewayMetaState, final IndicesService indicesService, final Discovery discovery) { - super(settings); this.allocationService = allocationService; this.clusterService = clusterService; this.threadPool = threadPool; diff --git a/server/src/main/java/org/elasticsearch/http/AbstractHttpServerTransport.java b/server/src/main/java/org/elasticsearch/http/AbstractHttpServerTransport.java index 4b53ac902d96c..92f305cb67a1f 100644 --- a/server/src/main/java/org/elasticsearch/http/AbstractHttpServerTransport.java +++ b/server/src/main/java/org/elasticsearch/http/AbstractHttpServerTransport.java @@ -87,7 +87,6 @@ public abstract class AbstractHttpServerTransport extends AbstractLifecycleCompo protected AbstractHttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, ThreadPool threadPool, NamedXContentRegistry xContentRegistry, Dispatcher dispatcher) { - super(settings); this.settings = settings; this.networkService = networkService; this.bigArrays = bigArrays; diff --git a/server/src/main/java/org/elasticsearch/indices/IndicesService.java b/server/src/main/java/org/elasticsearch/indices/IndicesService.java index e3c1a77b84300..b881ba73a28e6 100644 --- a/server/src/main/java/org/elasticsearch/indices/IndicesService.java +++ b/server/src/main/java/org/elasticsearch/indices/IndicesService.java @@ -205,7 +205,6 @@ public IndicesService(Settings settings, PluginsService pluginsService, NodeEnvi ScriptService scriptService, Client client, MetaStateService metaStateService, Collection>> engineFactoryProviders, Map> indexStoreFactories) { - super(settings); this.settings = settings; this.threadPool = threadPool; this.pluginsService = pluginsService; diff --git a/server/src/main/java/org/elasticsearch/indices/breaker/CircuitBreakerService.java b/server/src/main/java/org/elasticsearch/indices/breaker/CircuitBreakerService.java index cc6b7d5ef85bc..90a814b29b3c5 100644 --- a/server/src/main/java/org/elasticsearch/indices/breaker/CircuitBreakerService.java +++ b/server/src/main/java/org/elasticsearch/indices/breaker/CircuitBreakerService.java @@ -23,7 +23,6 @@ import org.apache.logging.log4j.Logger; import org.elasticsearch.common.breaker.CircuitBreaker; import org.elasticsearch.common.component.AbstractLifecycleComponent; -import org.elasticsearch.common.settings.Settings; /** * Interface for Circuit Breaker services, which provide breakers to classes @@ -32,8 +31,7 @@ public abstract class CircuitBreakerService extends AbstractLifecycleComponent { private static final Logger logger = LogManager.getLogger(CircuitBreakerService.class); - protected CircuitBreakerService(Settings settings) { - super(settings); + protected CircuitBreakerService() { } /** diff --git a/server/src/main/java/org/elasticsearch/indices/breaker/HierarchyCircuitBreakerService.java b/server/src/main/java/org/elasticsearch/indices/breaker/HierarchyCircuitBreakerService.java index 31ee4b8286918..48045e219252a 100644 --- a/server/src/main/java/org/elasticsearch/indices/breaker/HierarchyCircuitBreakerService.java +++ b/server/src/main/java/org/elasticsearch/indices/breaker/HierarchyCircuitBreakerService.java @@ -104,7 +104,7 @@ public class HierarchyCircuitBreakerService extends CircuitBreakerService { private final AtomicLong parentTripCount = new AtomicLong(0); public HierarchyCircuitBreakerService(Settings settings, ClusterSettings clusterSettings) { - super(settings); + super(); this.fielddataSettings = new BreakerSettings(CircuitBreaker.FIELDDATA, FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING.get(settings).getBytes(), FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING.get(settings), diff --git a/server/src/main/java/org/elasticsearch/indices/breaker/NoneCircuitBreakerService.java b/server/src/main/java/org/elasticsearch/indices/breaker/NoneCircuitBreakerService.java index c686412bc29b2..69de18e380b63 100644 --- a/server/src/main/java/org/elasticsearch/indices/breaker/NoneCircuitBreakerService.java +++ b/server/src/main/java/org/elasticsearch/indices/breaker/NoneCircuitBreakerService.java @@ -21,7 +21,6 @@ import org.elasticsearch.common.breaker.CircuitBreaker; import org.elasticsearch.common.breaker.NoopCircuitBreaker; -import org.elasticsearch.common.settings.Settings; /** * Class that returns a breaker that never breaks @@ -31,7 +30,7 @@ public class NoneCircuitBreakerService extends CircuitBreakerService { private final CircuitBreaker breaker = new NoopCircuitBreaker(CircuitBreaker.FIELDDATA); public NoneCircuitBreakerService() { - super(Settings.EMPTY); + super(); } @Override diff --git a/server/src/main/java/org/elasticsearch/indices/cluster/IndicesClusterStateService.java b/server/src/main/java/org/elasticsearch/indices/cluster/IndicesClusterStateService.java index 41050d7d47486..c8afe92be8d37 100644 --- a/server/src/main/java/org/elasticsearch/indices/cluster/IndicesClusterStateService.java +++ b/server/src/main/java/org/elasticsearch/indices/cluster/IndicesClusterStateService.java @@ -171,7 +171,6 @@ public IndicesClusterStateService( final SnapshotShardsService snapshotShardsService, final PrimaryReplicaSyncer primaryReplicaSyncer, final Consumer globalCheckpointSyncer) { - super(settings); this.settings = settings; this.buildInIndexListener = Arrays.asList( diff --git a/server/src/main/java/org/elasticsearch/monitor/MonitorService.java b/server/src/main/java/org/elasticsearch/monitor/MonitorService.java index 9467bf29923d8..df91487332435 100644 --- a/server/src/main/java/org/elasticsearch/monitor/MonitorService.java +++ b/server/src/main/java/org/elasticsearch/monitor/MonitorService.java @@ -42,7 +42,6 @@ public class MonitorService extends AbstractLifecycleComponent { public MonitorService(Settings settings, NodeEnvironment nodeEnvironment, ThreadPool threadPool, ClusterInfoService clusterInfoService) throws IOException { - super(settings); this.jvmGcMonitorService = new JvmGcMonitorService(settings, threadPool); this.osService = new OsService(settings); this.processService = new ProcessService(settings); diff --git a/server/src/main/java/org/elasticsearch/monitor/jvm/JvmGcMonitorService.java b/server/src/main/java/org/elasticsearch/monitor/jvm/JvmGcMonitorService.java index 94c66c79d2ee7..70de50710c999 100644 --- a/server/src/main/java/org/elasticsearch/monitor/jvm/JvmGcMonitorService.java +++ b/server/src/main/java/org/elasticsearch/monitor/jvm/JvmGcMonitorService.java @@ -107,7 +107,6 @@ public String toString() { } public JvmGcMonitorService(Settings settings, ThreadPool threadPool) { - super(settings); this.threadPool = threadPool; this.enabled = ENABLED_SETTING.get(settings); diff --git a/server/src/main/java/org/elasticsearch/repositories/blobstore/BlobStoreRepository.java b/server/src/main/java/org/elasticsearch/repositories/blobstore/BlobStoreRepository.java index 9f2297b48775b..c8cdf0d4e0308 100644 --- a/server/src/main/java/org/elasticsearch/repositories/blobstore/BlobStoreRepository.java +++ b/server/src/main/java/org/elasticsearch/repositories/blobstore/BlobStoreRepository.java @@ -228,7 +228,6 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent imp * @param settings Settings for the node this repository object is created on */ protected BlobStoreRepository(RepositoryMetaData metadata, Settings settings, NamedXContentRegistry namedXContentRegistry) { - super(settings); this.settings = settings; this.metadata = metadata; this.namedXContentRegistry = namedXContentRegistry; diff --git a/server/src/main/java/org/elasticsearch/search/SearchService.java b/server/src/main/java/org/elasticsearch/search/SearchService.java index f6e91c03af6e1..4fee684276288 100644 --- a/server/src/main/java/org/elasticsearch/search/SearchService.java +++ b/server/src/main/java/org/elasticsearch/search/SearchService.java @@ -193,7 +193,6 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv public SearchService(ClusterService clusterService, IndicesService indicesService, ThreadPool threadPool, ScriptService scriptService, BigArrays bigArrays, FetchPhase fetchPhase, ResponseCollectorService responseCollectorService) { - super(clusterService.getSettings()); Settings settings = clusterService.getSettings(); this.threadPool = threadPool; this.clusterService = clusterService; diff --git a/server/src/main/java/org/elasticsearch/snapshots/SnapshotShardsService.java b/server/src/main/java/org/elasticsearch/snapshots/SnapshotShardsService.java index c0e196f1f4eb3..6b7b506114361 100644 --- a/server/src/main/java/org/elasticsearch/snapshots/SnapshotShardsService.java +++ b/server/src/main/java/org/elasticsearch/snapshots/SnapshotShardsService.java @@ -119,7 +119,6 @@ public class SnapshotShardsService extends AbstractLifecycleComponent implements public SnapshotShardsService(Settings settings, ClusterService clusterService, SnapshotsService snapshotsService, ThreadPool threadPool, TransportService transportService, IndicesService indicesService, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) { - super(settings); this.indicesService = indicesService; this.snapshotsService = snapshotsService; this.transportService = transportService; diff --git a/server/src/main/java/org/elasticsearch/snapshots/SnapshotsService.java b/server/src/main/java/org/elasticsearch/snapshots/SnapshotsService.java index 65802377be032..e76dde274557c 100644 --- a/server/src/main/java/org/elasticsearch/snapshots/SnapshotsService.java +++ b/server/src/main/java/org/elasticsearch/snapshots/SnapshotsService.java @@ -124,7 +124,6 @@ public class SnapshotsService extends AbstractLifecycleComponent implements Clus @Inject public SnapshotsService(Settings settings, ClusterService clusterService, IndexNameExpressionResolver indexNameExpressionResolver, RepositoriesService repositoriesService, ThreadPool threadPool) { - super(settings); this.clusterService = clusterService; this.indexNameExpressionResolver = indexNameExpressionResolver; this.repositoriesService = repositoriesService; diff --git a/server/src/main/java/org/elasticsearch/transport/TcpTransport.java b/server/src/main/java/org/elasticsearch/transport/TcpTransport.java index a10bad9e88b69..dd6a21acc8fbd 100644 --- a/server/src/main/java/org/elasticsearch/transport/TcpTransport.java +++ b/server/src/main/java/org/elasticsearch/transport/TcpTransport.java @@ -156,7 +156,6 @@ public abstract class TcpTransport extends AbstractLifecycleComponent implements public TcpTransport(String transportName, Settings settings, Version version, ThreadPool threadPool, PageCacheRecycler pageCacheRecycler, CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, NetworkService networkService) { - super(settings); this.settings = settings; this.profileSettings = getProfileSettings(settings); this.version = version; diff --git a/server/src/main/java/org/elasticsearch/transport/TransportService.java b/server/src/main/java/org/elasticsearch/transport/TransportService.java index b5e97ac3ae6cb..57aaba671518e 100644 --- a/server/src/main/java/org/elasticsearch/transport/TransportService.java +++ b/server/src/main/java/org/elasticsearch/transport/TransportService.java @@ -155,7 +155,6 @@ public TransportService(Settings settings, Transport transport, ThreadPool threa public TransportService(Settings settings, Transport transport, ThreadPool threadPool, TransportInterceptor transportInterceptor, Function localNodeFactory, @Nullable ClusterSettings clusterSettings, Set taskHeaders, ConnectionManager connectionManager) { - super(settings); // The only time we do not want to validate node connections is when this is a transport client using the simple node sampler this.validateConnections = TransportClient.CLIENT_TYPE.equals(settings.get(Client.CLIENT_TYPE_SETTING_S.getKey())) == false || TransportClient.CLIENT_TRANSPORT_SNIFF.get(settings); diff --git a/server/src/main/java/org/elasticsearch/watcher/ResourceWatcherService.java b/server/src/main/java/org/elasticsearch/watcher/ResourceWatcherService.java index 3edab68e1580f..4216bd817b68c 100644 --- a/server/src/main/java/org/elasticsearch/watcher/ResourceWatcherService.java +++ b/server/src/main/java/org/elasticsearch/watcher/ResourceWatcherService.java @@ -90,7 +90,6 @@ public enum Frequency { @Inject public ResourceWatcherService(Settings settings, ThreadPool threadPool) { - super(settings); this.enabled = ENABLED.get(settings); this.threadPool = threadPool; diff --git a/server/src/test/java/org/elasticsearch/cluster/routing/DelayedAllocationServiceTests.java b/server/src/test/java/org/elasticsearch/cluster/routing/DelayedAllocationServiceTests.java index e38f09e567a39..b168bae87de41 100644 --- a/server/src/test/java/org/elasticsearch/cluster/routing/DelayedAllocationServiceTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/routing/DelayedAllocationServiceTests.java @@ -69,7 +69,7 @@ public void createDelayedAllocationService() { threadPool = new TestThreadPool(getTestName()); clusterService = mock(ClusterService.class); allocationService = createAllocationService(Settings.EMPTY, new DelayedShardsMockGatewayAllocator()); - delayedAllocationService = new TestDelayAllocationService(Settings.EMPTY, threadPool, clusterService, allocationService); + delayedAllocationService = new TestDelayAllocationService(threadPool, clusterService, allocationService); verify(clusterService).addListener(delayedAllocationService); } @@ -464,9 +464,9 @@ public void testDelayedUnassignedScheduleRerouteRescheduledOnShorterDelay() thro private static class TestDelayAllocationService extends DelayedAllocationService { private volatile long nanoTimeOverride = -1L; - TestDelayAllocationService(Settings settings, ThreadPool threadPool, ClusterService clusterService, - AllocationService allocationService) { - super(settings, threadPool, clusterService, allocationService); + private TestDelayAllocationService(ThreadPool threadPool, ClusterService clusterService, + AllocationService allocationService) { + super(threadPool, clusterService, allocationService); } @Override diff --git a/server/src/test/java/org/elasticsearch/cluster/routing/RoutingServiceTests.java b/server/src/test/java/org/elasticsearch/cluster/routing/RoutingServiceTests.java index 09b957069a624..f9d3e0ab95c01 100644 --- a/server/src/test/java/org/elasticsearch/cluster/routing/RoutingServiceTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/routing/RoutingServiceTests.java @@ -19,7 +19,6 @@ package org.elasticsearch.cluster.routing; -import org.elasticsearch.common.settings.Settings; import org.elasticsearch.cluster.ESAllocationTestCase; import org.junit.Before; @@ -47,7 +46,7 @@ private class TestRoutingService extends RoutingService { private AtomicBoolean rerouted = new AtomicBoolean(); TestRoutingService() { - super(Settings.EMPTY, null, null); + super(null, null); } public boolean hasReroutedAndClear() { diff --git a/server/src/test/java/org/elasticsearch/common/network/NetworkModuleTests.java b/server/src/test/java/org/elasticsearch/common/network/NetworkModuleTests.java index 0dbc3efe0750e..32cc6785d57a2 100644 --- a/server/src/test/java/org/elasticsearch/common/network/NetworkModuleTests.java +++ b/server/src/test/java/org/elasticsearch/common/network/NetworkModuleTests.java @@ -72,9 +72,6 @@ public void tearDown() throws Exception { } static class FakeHttpTransport extends AbstractLifecycleComponent implements HttpServerTransport { - FakeHttpTransport() { - super(null); - } @Override protected void doStart() {} @Override diff --git a/server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java b/server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java index d2a73caa32d3a..0d58239fd4a56 100644 --- a/server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java +++ b/server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java @@ -3126,7 +3126,6 @@ private abstract static class RestoreOnlyRepository extends AbstractLifecycleCom private final String indexName; RestoreOnlyRepository(String indexName) { - super(Settings.EMPTY); this.indexName = indexName; } diff --git a/server/src/test/java/org/elasticsearch/rest/RestControllerTests.java b/server/src/test/java/org/elasticsearch/rest/RestControllerTests.java index 29cbb8f48ec9f..c04dc7be026b9 100644 --- a/server/src/test/java/org/elasticsearch/rest/RestControllerTests.java +++ b/server/src/test/java/org/elasticsearch/rest/RestControllerTests.java @@ -474,7 +474,6 @@ private static final class TestHttpServerTransport extends AbstractLifecycleComp HttpServerTransport { TestHttpServerTransport() { - super(Settings.EMPTY); } @Override diff --git a/server/src/test/java/org/elasticsearch/snapshots/SnapshotsServiceTests.java b/server/src/test/java/org/elasticsearch/snapshots/SnapshotsServiceTests.java index 5cd75df22a48a..1531744a13cac 100644 --- a/server/src/test/java/org/elasticsearch/snapshots/SnapshotsServiceTests.java +++ b/server/src/test/java/org/elasticsearch/snapshots/SnapshotsServiceTests.java @@ -463,7 +463,7 @@ protected void assertSnapshotOrGenericThread() { transportService, indicesService, actionFilters, indexNameExpressionResolver); final ShardStateAction shardStateAction = new ShardStateAction( clusterService, transportService, allocationService, - new RoutingService(settings, clusterService, allocationService), + new RoutingService(clusterService, allocationService), deterministicTaskQueue.getThreadPool() ); indicesClusterStateService = new IndicesClusterStateService( diff --git a/test/framework/src/main/java/org/elasticsearch/test/MockHttpTransport.java b/test/framework/src/main/java/org/elasticsearch/test/MockHttpTransport.java index 5955bcead67eb..f9dec4ee1ec5f 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/MockHttpTransport.java +++ b/test/framework/src/main/java/org/elasticsearch/test/MockHttpTransport.java @@ -20,7 +20,6 @@ package org.elasticsearch.test; import org.elasticsearch.common.component.AbstractLifecycleComponent; -import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.BoundTransportAddress; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.http.HttpInfo; @@ -46,10 +45,6 @@ public static class TestPlugin extends Plugin {} private static final HttpInfo DUMMY_HTTP_INFO = new HttpInfo(DUMMY_BOUND_ADDRESS, 0); private static final HttpStats DUMMY_HTTP_STATS = new HttpStats(0, 0); - public MockHttpTransport() { - super(Settings.EMPTY); - } - @Override protected void doStart() {} diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/Ccr.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/Ccr.java index 370d017a4bde7..8bbacac3d8054 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/Ccr.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/Ccr.java @@ -157,7 +157,7 @@ public Collection createComponents( return emptyList(); } - CcrRestoreSourceService restoreSourceService = new CcrRestoreSourceService(settings); + CcrRestoreSourceService restoreSourceService = new CcrRestoreSourceService(); this.restoreSourceService.set(restoreSourceService); return Arrays.asList( ccrLicenseChecker, diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/CcrRepositoryManager.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/CcrRepositoryManager.java index 54403df367809..c1a28b72cf8fe 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/CcrRepositoryManager.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/CcrRepositoryManager.java @@ -29,7 +29,6 @@ class CcrRepositoryManager extends AbstractLifecycleComponent { private final RemoteSettingsUpdateListener updateListener; CcrRepositoryManager(Settings settings, ClusterService clusterService, Client client) { - super(settings); this.client = client; updateListener = new RemoteSettingsUpdateListener(settings); updateListener.listenForUpdates(clusterService.getClusterSettings()); diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/repository/CcrRepository.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/repository/CcrRepository.java index 025892f80d834..5c3e0edda6177 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/repository/CcrRepository.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/repository/CcrRepository.java @@ -84,7 +84,6 @@ public class CcrRepository extends AbstractLifecycleComponent implements Reposit private final CcrLicenseChecker ccrLicenseChecker; public CcrRepository(RepositoryMetaData metadata, Client client, CcrLicenseChecker ccrLicenseChecker, Settings settings) { - super(settings); this.metadata = metadata; assert metadata.name().startsWith(NAME_PREFIX) : "CcrRepository metadata.name() must start with: " + NAME_PREFIX; this.remoteClusterAlias = Strings.split(metadata.name(), NAME_PREFIX)[1]; diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/repository/CcrRestoreSourceService.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/repository/CcrRestoreSourceService.java index 197d5ddbf38ff..785600dd5f8fc 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/repository/CcrRestoreSourceService.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/repository/CcrRestoreSourceService.java @@ -48,10 +48,6 @@ public class CcrRestoreSourceService extends AbstractLifecycleComponent implemen private final CopyOnWriteArrayList> openSessionListeners = new CopyOnWriteArrayList<>(); private final CopyOnWriteArrayList> closeSessionListeners = new CopyOnWriteArrayList<>(); - public CcrRestoreSourceService(Settings settings) { - super(settings); - } - @Override public synchronized void afterIndexShardClosed(ShardId shardId, @Nullable IndexShard indexShard, Settings indexSettings) { if (indexShard != null) { diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/repository/CcrRestoreSourceServiceTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/repository/CcrRestoreSourceServiceTests.java index efcd93e90fd07..c0b7863edf25a 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/repository/CcrRestoreSourceServiceTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/repository/CcrRestoreSourceServiceTests.java @@ -29,7 +29,7 @@ public class CcrRestoreSourceServiceTests extends IndexShardTestCase { @Before public void setUp() throws Exception { super.setUp(); - restoreSourceService = new CcrRestoreSourceService(Settings.EMPTY); + restoreSourceService = new CcrRestoreSourceService(); } public void testOpenSession() throws IOException { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicenseService.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicenseService.java index dbf11026f4709..68e094511a3e8 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicenseService.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicenseService.java @@ -121,7 +121,6 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste public LicenseService(Settings settings, ClusterService clusterService, Clock clock, Environment env, ResourceWatcherService resourceWatcherService, XPackLicenseState licenseState) { - super(settings); this.settings = settings; this.clusterService = clusterService; this.clock = clock; diff --git a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringService.java b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringService.java index 8759d493c8b97..1aa7ef230a390 100644 --- a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringService.java +++ b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringService.java @@ -91,7 +91,6 @@ public class MonitoringService extends AbstractLifecycleComponent { MonitoringService(Settings settings, ClusterService clusterService, ThreadPool threadPool, Set collectors, Exporters exporters) { - super(settings); this.clusterService = Objects.requireNonNull(clusterService); this.threadPool = Objects.requireNonNull(threadPool); this.collectors = Objects.requireNonNull(collectors); diff --git a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/cleaner/CleanerService.java b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/cleaner/CleanerService.java index f9f41974402b1..e6af45ee2bca0 100644 --- a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/cleaner/CleanerService.java +++ b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/cleaner/CleanerService.java @@ -40,7 +40,6 @@ public class CleanerService extends AbstractLifecycleComponent { CleanerService(Settings settings, ClusterSettings clusterSettings, XPackLicenseState licenseState, ThreadPool threadPool, ExecutionScheduler executionScheduler) { - super(settings); this.licenseState = licenseState; this.threadPool = threadPool; this.executionScheduler = executionScheduler; diff --git a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/exporter/Exporters.java b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/exporter/Exporters.java index 54d4fde4fbbdf..484361ddc542e 100644 --- a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/exporter/Exporters.java +++ b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/exporter/Exporters.java @@ -51,7 +51,6 @@ public class Exporters extends AbstractLifecycleComponent { public Exporters(Settings settings, Map factories, ClusterService clusterService, XPackLicenseState licenseState, ThreadContext threadContext) { - super(settings); this.settings = settings; this.factories = factories; this.exporters = new AtomicReference<>(emptyMap()); diff --git a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/MonitoringServiceTests.java b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/MonitoringServiceTests.java index 3d23933f8dcc0..f67b828606d07 100644 --- a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/MonitoringServiceTests.java +++ b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/MonitoringServiceTests.java @@ -173,7 +173,6 @@ class BlockingExporter extends CountingExporter { private final CountDownLatch latch; BlockingExporter(CountDownLatch latch) { - super(); this.latch = latch; } From 5a5e44d1de98f79ae19a6b86af0b0fdf12f0ef72 Mon Sep 17 00:00:00 2001 From: Armin Braun Date: Wed, 16 Jan 2019 11:08:48 +0100 Subject: [PATCH 03/16] Simplify Snapshot Create Request Handling (#37464) * The internal create request is absolutely redundant, the only difference to the transport request is that we resolved the snapshot name when moving from the transport to the internal version * Removed it and passed the transport request into the snapshot service instead * nicer way of resolve snapshot name in callback --- .../create/TransportCreateSnapshotAction.java | 19 +- .../snapshots/SnapshotsService.java | 219 ++---------------- 2 files changed, 23 insertions(+), 215 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/TransportCreateSnapshotAction.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/TransportCreateSnapshotAction.java index b4320f5b4f72e..abd50f0785a83 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/TransportCreateSnapshotAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/TransportCreateSnapshotAction.java @@ -73,24 +73,14 @@ protected ClusterBlockException checkBlock(CreateSnapshotRequest request, Cluste @Override protected void masterOperation(final CreateSnapshotRequest request, ClusterState state, final ActionListener listener) { - final String snapshotName = indexNameExpressionResolver.resolveDateMathExpression(request.snapshot()); - SnapshotsService.SnapshotRequest snapshotRequest = - new SnapshotsService.SnapshotRequest(request.repository(), snapshotName, "create_snapshot [" + snapshotName + "]") - .indices(request.indices()) - .indicesOptions(request.indicesOptions()) - .partial(request.partial()) - .settings(request.settings()) - .includeGlobalState(request.includeGlobalState()) - .masterNodeTimeout(request.masterNodeTimeout()); - snapshotsService.createSnapshot(snapshotRequest, new SnapshotsService.CreateSnapshotListener() { + snapshotsService.createSnapshot(request, new SnapshotsService.CreateSnapshotListener() { @Override - public void onResponse() { + public void onResponse(Snapshot snapshotCreated) { if (request.waitForCompletion()) { snapshotsService.addListener(new SnapshotsService.SnapshotCompletionListener() { @Override public void onSnapshotCompletion(Snapshot snapshot, SnapshotInfo snapshotInfo) { - if (snapshot.getRepository().equals(request.repository()) && - snapshot.getSnapshotId().getName().equals(snapshotName)) { + if (snapshotCreated.equals(snapshot)) { listener.onResponse(new CreateSnapshotResponse(snapshotInfo)); snapshotsService.removeListener(this); } @@ -98,8 +88,7 @@ public void onSnapshotCompletion(Snapshot snapshot, SnapshotInfo snapshotInfo) { @Override public void onSnapshotFailure(Snapshot snapshot, Exception e) { - if (snapshot.getRepository().equals(request.repository()) && - snapshot.getSnapshotId().getName().equals(snapshotName)) { + if (snapshotCreated.equals(snapshot)) { listener.onFailure(e); snapshotsService.removeListener(this); } diff --git a/server/src/main/java/org/elasticsearch/snapshots/SnapshotsService.java b/server/src/main/java/org/elasticsearch/snapshots/SnapshotsService.java index e76dde274557c..153bb1fbf2fcf 100644 --- a/server/src/main/java/org/elasticsearch/snapshots/SnapshotsService.java +++ b/server/src/main/java/org/elasticsearch/snapshots/SnapshotsService.java @@ -27,7 +27,7 @@ import org.apache.lucene.util.CollectionUtil; import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotRequest; import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterStateApplier; @@ -78,7 +78,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; @@ -92,8 +91,8 @@ *

* A typical snapshot creating process looks like this: *

    - *
  • On the master node the {@link #createSnapshot(SnapshotRequest, CreateSnapshotListener)} is called and makes sure that no snapshots - * is currently running and registers the new snapshot in cluster state
  • + *
  • On the master node the {@link #createSnapshot(CreateSnapshotRequest, CreateSnapshotListener)} is called and makes sure that + * no snapshot is currently running and registers the new snapshot in cluster state
  • *
  • When cluster state is updated * the {@link #beginSnapshot(ClusterState, SnapshotsInProgress.Entry, boolean, CreateSnapshotListener)} method kicks in and initializes * the snapshot in the repository and then populates list of shards that needs to be snapshotted in cluster state
  • @@ -235,20 +234,20 @@ public List currentSnapshots(final String repositoryName) { * @param request snapshot request * @param listener snapshot creation listener */ - public void createSnapshot(final SnapshotRequest request, final CreateSnapshotListener listener) { - final String repositoryName = request.repositoryName; - final String snapshotName = request.snapshotName; + public void createSnapshot(final CreateSnapshotRequest request, final CreateSnapshotListener listener) { + final String repositoryName = request.repository(); + final String snapshotName = indexNameExpressionResolver.resolveDateMathExpression(request.snapshot()); validate(repositoryName, snapshotName); final SnapshotId snapshotId = new SnapshotId(snapshotName, UUIDs.randomBase64UUID()); // new UUID for the snapshot final RepositoryData repositoryData = repositoriesService.repository(repositoryName).getRepositoryData(); - clusterService.submitStateUpdateTask(request.cause(), new ClusterStateUpdateTask() { + clusterService.submitStateUpdateTask("create_snapshot [" + snapshotName + ']', new ClusterStateUpdateTask() { private SnapshotsInProgress.Entry newSnapshot = null; @Override public ClusterState execute(ClusterState currentState) { - validate(request, currentState); + validate(repositoryName, snapshotName, currentState); SnapshotDeletionsInProgress deletionsInProgress = currentState.custom(SnapshotDeletionsInProgress.TYPE); if (deletionsInProgress != null && deletionsInProgress.hasDeletionsInProgress()) { throw new ConcurrentSnapshotExecutionException(repositoryName, snapshotName, @@ -301,16 +300,16 @@ public TimeValue timeout() { /** * Validates snapshot request * - * @param request snapshot request + * @param repositoryName repository name + * @param snapshotName snapshot name * @param state current cluster state */ - private void validate(SnapshotRequest request, ClusterState state) { + private void validate(String repositoryName, String snapshotName, ClusterState state) { RepositoriesMetaData repositoriesMetaData = state.getMetaData().custom(RepositoriesMetaData.TYPE); - final String repository = request.repositoryName; - if (repositoriesMetaData == null || repositoriesMetaData.repository(repository) == null) { - throw new RepositoryMissingException(repository); + if (repositoriesMetaData == null || repositoriesMetaData.repository(repositoryName) == null) { + throw new RepositoryMissingException(repositoryName); } - validate(repository, request.snapshotName); + validate(repositoryName, snapshotName); } private static void validate(final String repositoryName, final String snapshotName) { @@ -377,7 +376,7 @@ protected void doRun() { logger.info("snapshot [{}] started", snapshot.snapshot()); if (snapshot.indices().isEmpty()) { // No indices in this snapshot - we are done - userCreateSnapshotListener.onResponse(); + userCreateSnapshotListener.onResponse(snapshot.snapshot()); endSnapshot(snapshot); return; } @@ -465,7 +464,7 @@ public void clusterStateProcessed(String source, ClusterState oldState, ClusterS // for processing. If client wants to wait for the snapshot completion, it can register snapshot // completion listener in this method. For the snapshot completion to work properly, the snapshot // should still exist when listener is registered. - userCreateSnapshotListener.onResponse(); + userCreateSnapshotListener.onResponse(snapshot.snapshot()); // Now that snapshot completion listener is registered we can end the snapshot if needed // We should end snapshot only if 1) we didn't accept it for processing (which happens when there @@ -1544,8 +1543,10 @@ public interface CreateSnapshotListener { /** * Called when snapshot has successfully started + * + * @param snapshot snapshot that was created */ - void onResponse(); + void onResponse(Snapshot snapshot); /** * Called if a snapshot operation couldn't start @@ -1575,186 +1576,4 @@ public interface SnapshotCompletionListener { void onSnapshotFailure(Snapshot snapshot, Exception e); } - - /** - * Snapshot creation request - */ - public static class SnapshotRequest { - - private final String cause; - - private final String repositoryName; - - private final String snapshotName; - - private String[] indices; - - private IndicesOptions indicesOptions = IndicesOptions.strictExpandOpen(); - - private boolean partial; - - private Settings settings; - - private boolean includeGlobalState; - - private TimeValue masterNodeTimeout; - - /** - * Constructs new snapshot creation request - * - * @param repositoryName repository name - * @param snapshotName snapshot name - * @param cause cause for snapshot operation - */ - public SnapshotRequest(final String repositoryName, final String snapshotName, final String cause) { - this.repositoryName = Objects.requireNonNull(repositoryName); - this.snapshotName = Objects.requireNonNull(snapshotName); - this.cause = Objects.requireNonNull(cause); - } - - /** - * Sets the list of indices to be snapshotted - * - * @param indices list of indices - * @return this request - */ - public SnapshotRequest indices(String[] indices) { - this.indices = indices; - return this; - } - - /** - * Sets repository-specific snapshot settings - * - * @param settings snapshot settings - * @return this request - */ - public SnapshotRequest settings(Settings settings) { - this.settings = settings; - return this; - } - - /** - * Set to true if global state should be stored as part of the snapshot - * - * @param includeGlobalState true if global state should be stored as part of the snapshot - * @return this request - */ - public SnapshotRequest includeGlobalState(boolean includeGlobalState) { - this.includeGlobalState = includeGlobalState; - return this; - } - - /** - * Sets master node timeout - * - * @param masterNodeTimeout master node timeout - * @return this request - */ - public SnapshotRequest masterNodeTimeout(TimeValue masterNodeTimeout) { - this.masterNodeTimeout = masterNodeTimeout; - return this; - } - - /** - * Sets the indices options - * - * @param indicesOptions indices options - * @return this request - */ - public SnapshotRequest indicesOptions(IndicesOptions indicesOptions) { - this.indicesOptions = indicesOptions; - return this; - } - - /** - * Set to true if partial snapshot should be allowed - * - * @param partial true if partial snapshots should be allowed - * @return this request - */ - public SnapshotRequest partial(boolean partial) { - this.partial = partial; - return this; - } - - /** - * Returns cause for snapshot operation - * - * @return cause for snapshot operation - */ - public String cause() { - return cause; - } - - /** - * Returns the repository name - */ - public String repositoryName() { - return repositoryName; - } - - /** - * Returns the snapshot name - */ - public String snapshotName() { - return snapshotName; - } - - /** - * Returns the list of indices to be snapshotted - * - * @return the list of indices - */ - public String[] indices() { - return indices; - } - - /** - * Returns indices options - * - * @return indices options - */ - public IndicesOptions indicesOptions() { - return indicesOptions; - } - - /** - * Returns repository-specific settings for the snapshot operation - * - * @return repository-specific settings - */ - public Settings settings() { - return settings; - } - - /** - * Returns true if global state should be stored as part of the snapshot - * - * @return true if global state should be stored as part of the snapshot - */ - public boolean includeGlobalState() { - return includeGlobalState; - } - - /** - * Returns true if partial snapshot should be allowed - * - * @return true if partial snapshot should be allowed - */ - public boolean partial() { - return partial; - } - - /** - * Returns master node timeout - * - * @return master node timeout - */ - public TimeValue masterNodeTimeout() { - return masterNodeTimeout; - } - - } } - From 023bb2f1e473f4ad009e22c1947faf844d39dbad Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Wed, 16 Jan 2019 12:36:35 +0200 Subject: [PATCH 04/16] SQL: Remove slightly used meta commands (#37506) Remove SYS CATALOGS and SYS TABLE TYPES as they are a subset of SYS TABLES (and thus somewhat redundant) and used only by JDBC. Close #37409 --- .../xpack/sql/jdbc/JdbcDatabaseMetaData.java | 32 +- .../sql/qa/jdbc/DatabaseMetaDataTestCase.java | 21 +- .../sql/qa/rest/RestSqlUsageTestCase.java | 4 +- .../setup_mock_metadata_get_table_types.sql | 12 +- ...setup_mock_metadata_get_types_of_table.sql | 15 + x-pack/plugin/sql/src/main/antlr/SqlBase.g4 | 2 - .../xpack/sql/parser/CommandBuilder.java | 14 - .../xpack/sql/parser/SqlBaseBaseListener.java | 24 - .../xpack/sql/parser/SqlBaseBaseVisitor.java | 14 - .../xpack/sql/parser/SqlBaseListener.java | 24 - .../xpack/sql/parser/SqlBaseParser.java | 1503 ++++++++--------- .../xpack/sql/parser/SqlBaseVisitor.java | 14 - .../plan/logical/command/sys/SysCatalogs.java | 64 - .../logical/command/sys/SysTableTypes.java | 70 - .../logical/command/sys/SysCatalogsTests.java | 61 - .../command/sys/SysTableTypesTests.java | 52 - .../xpack/sql/stats/VerifierMetricsTests.java | 3 +- 17 files changed, 788 insertions(+), 1141 deletions(-) create mode 100644 x-pack/plugin/sql/qa/src/main/resources/setup_mock_metadata_get_types_of_table.sql delete mode 100644 x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysCatalogs.java delete mode 100644 x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTableTypes.java delete mode 100644 x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysCatalogsTests.java delete mode 100644 x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTableTypesTests.java diff --git a/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcDatabaseMetaData.java b/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcDatabaseMetaData.java index 2650e5892d59b..5697453730455 100644 --- a/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcDatabaseMetaData.java +++ b/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcDatabaseMetaData.java @@ -773,12 +773,16 @@ public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLExce @Override public ResultSet getCatalogs() throws SQLException { - return con.createStatement().executeQuery("SYS CATALOGS"); + // TABLE_CAT is the first column + Object[][] data = queryColumn(con, "SYS TABLES CATALOG LIKE '%'", 1); + return memorySet(con.cfg, columnInfo("", "TABLE_CAT"), data); } @Override public ResultSet getTableTypes() throws SQLException { - return con.createStatement().executeQuery("SYS TABLE TYPES"); + // TABLE_TYPE (4) + Object[][] data = queryColumn(con, "SYS TABLES TYPE '%'", 4); + return memorySet(con.cfg, columnInfo("", "TABLE_TYPE"), data); } @Override @@ -1114,6 +1118,26 @@ public boolean generatedKeyAlwaysReturned() throws SQLException { return false; } + // + // Utility methods + // + + private static Object[][] queryColumn(JdbcConnection con, String query, int... cols) throws SQLException { + List data = new ArrayList<>(); + try (ResultSet rs = con.createStatement().executeQuery(query)) { + while (rs.next()) { + Object[] row = new Object[cols.length]; + for (int i = 0; i < cols.length; i++) { + row[i] = rs.getObject(cols[i]); + } + data.add(row); + } + } + + return data.toArray(new Object[][] {}); + } + + private static List columnInfo(String tableName, Object... cols) throws JdbcSQLException { List columns = new ArrayList<>(); @@ -1156,7 +1180,7 @@ private static ResultSet memorySet(JdbcConfiguration cfg, List c return new JdbcResultSet(cfg, null, new InMemoryCursor(columns, data)); } - static class InMemoryCursor implements Cursor { + private static class InMemoryCursor implements Cursor { private final List columns; private final Object[][] data; @@ -1197,4 +1221,4 @@ public void close() throws SQLException { // this cursor doesn't hold any resource - no need to clean up } } -} +} \ No newline at end of file diff --git a/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/DatabaseMetaDataTestCase.java b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/DatabaseMetaDataTestCase.java index 9e4252cc27391..08f56b0058244 100644 --- a/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/DatabaseMetaDataTestCase.java +++ b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/DatabaseMetaDataTestCase.java @@ -71,12 +71,12 @@ public void testGetTables() throws Exception { } } - public void testGetTableTypes() throws Exception { + public void testGetTypeOfTables() throws Exception { index("test1", body -> body.field("name", "bob")); index("test2", body -> body.field("name", "bob")); try (Connection h2 = LocalH2.anonymousDb(); Connection es = esJdbc()) { - h2.createStatement().executeUpdate("RUNSCRIPT FROM 'classpath:/setup_mock_metadata_get_table_types.sql'"); + h2.createStatement().executeUpdate("RUNSCRIPT FROM 'classpath:/setup_mock_metadata_get_types_of_table.sql'"); CheckedSupplier all = () -> h2.createStatement() .executeQuery("SELECT '" + clusterName() + "' AS TABLE_CAT, * FROM mock"); @@ -88,6 +88,23 @@ public void testGetTableTypes() throws Exception { } } + public void testGetTableTypes() throws Exception { + index("test1", body -> body.field("name", "bob")); + index("test2", body -> body.field("name", "bob")); + + try (Connection h2 = LocalH2.anonymousDb(); Connection es = esJdbc()) { + h2.createStatement().executeUpdate("RUNSCRIPT FROM 'classpath:/setup_mock_metadata_get_table_types.sql'"); + assertResultSets(h2.createStatement().executeQuery("SELECT * FROM mock"), es.getMetaData().getTableTypes()); + } + } + + public void testGetCatalogs() throws Exception { + try (Connection h2 = LocalH2.anonymousDb(); Connection es = esJdbc()) { + assertResultSets(h2.createStatement().executeQuery("SELECT '" + clusterName() + "' AS TABLE_CAT"), + es.getMetaData().getCatalogs()); + } + } + public void testColumns() throws Exception { index("test1", body -> body.field("name", "bob")); index("test2", body -> { diff --git a/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/rest/RestSqlUsageTestCase.java b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/rest/RestSqlUsageTestCase.java index 7573fe8abaa0b..42f9e59840f86 100644 --- a/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/rest/RestSqlUsageTestCase.java +++ b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/rest/RestSqlUsageTestCase.java @@ -160,8 +160,8 @@ public void testSqlRestUsage() throws IOException { allTotalQueries += randomCommandExecutions; for (int i = 0; i < randomCommandExecutions; i++) { runSql(randomFrom("SHOW FUNCTIONS", "SHOW COLUMNS FROM library", "SHOW SCHEMAS", - "SHOW TABLES", "SYS CATALOGS", "SYS COLUMNS LIKE '%name'", - "SYS TABLES", "SYS TYPES")); + "SHOW TABLES", "SYS TABLES", "SYS COLUMNS LIKE '%name'", + "SYS TABLES TYPE '%'", "SYS TYPES")); } responseAsMap = getStats(); assertFeatureMetric(baseMetrics.get("command") + randomCommandExecutions, responseAsMap, "command"); diff --git a/x-pack/plugin/sql/qa/src/main/resources/setup_mock_metadata_get_table_types.sql b/x-pack/plugin/sql/qa/src/main/resources/setup_mock_metadata_get_table_types.sql index db40c6b90865f..52c767cb73485 100644 --- a/x-pack/plugin/sql/qa/src/main/resources/setup_mock_metadata_get_table_types.sql +++ b/x-pack/plugin/sql/qa/src/main/resources/setup_mock_metadata_get_table_types.sql @@ -1,15 +1,7 @@ CREATE TABLE mock ( - TABLE_SCHEM VARCHAR, - TABLE_NAME VARCHAR, TABLE_TYPE VARCHAR, - REMARKS VARCHAR, - TYPE_CAT VARCHAR, - TYPE_SCHEM VARCHAR, - TYPE_NAME VARCHAR, - SELF_REFERENCING_COL_NAME VARCHAR, - REF_GENERATION VARCHAR ) AS -SELECT '', 'test1', 'BASE TABLE', '', null, null, null, null, null FROM DUAL +SELECT 'ALIAS' FROM DUAL UNION ALL -SELECT '', 'test2', 'BASE TABLE', '', null, null, null, null, null FROM DUAL +SELECT 'BASE TABLE' FROM DUAL ; diff --git a/x-pack/plugin/sql/qa/src/main/resources/setup_mock_metadata_get_types_of_table.sql b/x-pack/plugin/sql/qa/src/main/resources/setup_mock_metadata_get_types_of_table.sql new file mode 100644 index 0000000000000..db40c6b90865f --- /dev/null +++ b/x-pack/plugin/sql/qa/src/main/resources/setup_mock_metadata_get_types_of_table.sql @@ -0,0 +1,15 @@ +CREATE TABLE mock ( + TABLE_SCHEM VARCHAR, + TABLE_NAME VARCHAR, + TABLE_TYPE VARCHAR, + REMARKS VARCHAR, + TYPE_CAT VARCHAR, + TYPE_SCHEM VARCHAR, + TYPE_NAME VARCHAR, + SELF_REFERENCING_COL_NAME VARCHAR, + REF_GENERATION VARCHAR +) AS +SELECT '', 'test1', 'BASE TABLE', '', null, null, null, null, null FROM DUAL +UNION ALL +SELECT '', 'test2', 'BASE TABLE', '', null, null, null, null, null FROM DUAL +; diff --git a/x-pack/plugin/sql/src/main/antlr/SqlBase.g4 b/x-pack/plugin/sql/src/main/antlr/SqlBase.g4 index 6435d80d04073..e7cb2e2b1b258 100644 --- a/x-pack/plugin/sql/src/main/antlr/SqlBase.g4 +++ b/x-pack/plugin/sql/src/main/antlr/SqlBase.g4 @@ -55,7 +55,6 @@ statement | (DESCRIBE | DESC) (tableLike=likePattern | tableIdent=tableIdentifier) #showColumns | SHOW FUNCTIONS (likePattern)? #showFunctions | SHOW SCHEMAS #showSchemas - | SYS CATALOGS #sysCatalogs | SYS TABLES (CATALOG clusterLike=likePattern)? (tableLike=likePattern | tableIdent=tableIdentifier)? (TYPE string (',' string)* )? #sysTables @@ -63,7 +62,6 @@ statement (TABLE tableLike=likePattern | tableIdent=tableIdentifier)? (columnPattern=likePattern)? #sysColumns | SYS TYPES ((PLUS | MINUS)? type=number)? #sysTypes - | SYS TABLE TYPES #sysTableTypes ; query diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CommandBuilder.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CommandBuilder.java index 532cef01f555e..87709ac104e08 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CommandBuilder.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CommandBuilder.java @@ -16,9 +16,7 @@ import org.elasticsearch.xpack.sql.parser.SqlBaseParser.ShowSchemasContext; import org.elasticsearch.xpack.sql.parser.SqlBaseParser.ShowTablesContext; import org.elasticsearch.xpack.sql.parser.SqlBaseParser.StringContext; -import org.elasticsearch.xpack.sql.parser.SqlBaseParser.SysCatalogsContext; import org.elasticsearch.xpack.sql.parser.SqlBaseParser.SysColumnsContext; -import org.elasticsearch.xpack.sql.parser.SqlBaseParser.SysTableTypesContext; import org.elasticsearch.xpack.sql.parser.SqlBaseParser.SysTablesContext; import org.elasticsearch.xpack.sql.parser.SqlBaseParser.SysTypesContext; import org.elasticsearch.xpack.sql.plan.TableIdentifier; @@ -29,9 +27,7 @@ import org.elasticsearch.xpack.sql.plan.logical.command.ShowFunctions; import org.elasticsearch.xpack.sql.plan.logical.command.ShowSchemas; import org.elasticsearch.xpack.sql.plan.logical.command.ShowTables; -import org.elasticsearch.xpack.sql.plan.logical.command.sys.SysCatalogs; import org.elasticsearch.xpack.sql.plan.logical.command.sys.SysColumns; -import org.elasticsearch.xpack.sql.plan.logical.command.sys.SysTableTypes; import org.elasticsearch.xpack.sql.plan.logical.command.sys.SysTables; import org.elasticsearch.xpack.sql.plan.logical.command.sys.SysTypes; import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue; @@ -144,11 +140,6 @@ public Object visitShowColumns(ShowColumnsContext ctx) { return new ShowColumns(source(ctx), index, visitLikePattern(ctx.likePattern())); } - @Override - public Object visitSysCatalogs(SysCatalogsContext ctx) { - return new SysCatalogs(source(ctx)); - } - @Override public SysTables visitSysTables(SysTablesContext ctx) { List types = new ArrayList<>(); @@ -199,9 +190,4 @@ public SysTypes visitSysTypes(SysTypesContext ctx) { return new SysTypes(source(ctx), Integer.valueOf(type)); } - - @Override - public Object visitSysTableTypes(SysTableTypesContext ctx) { - return new SysTableTypes(source(ctx)); - } } \ No newline at end of file diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseBaseListener.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseBaseListener.java index af7243cbe984a..a62c5b4083fa3 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseBaseListener.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseBaseListener.java @@ -119,18 +119,6 @@ class SqlBaseBaseListener implements SqlBaseListener { *

    The default implementation does nothing.

    */ @Override public void exitShowSchemas(SqlBaseParser.ShowSchemasContext ctx) { } - /** - * {@inheritDoc} - * - *

    The default implementation does nothing.

    - */ - @Override public void enterSysCatalogs(SqlBaseParser.SysCatalogsContext ctx) { } - /** - * {@inheritDoc} - * - *

    The default implementation does nothing.

    - */ - @Override public void exitSysCatalogs(SqlBaseParser.SysCatalogsContext ctx) { } /** * {@inheritDoc} * @@ -167,18 +155,6 @@ class SqlBaseBaseListener implements SqlBaseListener { *

    The default implementation does nothing.

    */ @Override public void exitSysTypes(SqlBaseParser.SysTypesContext ctx) { } - /** - * {@inheritDoc} - * - *

    The default implementation does nothing.

    - */ - @Override public void enterSysTableTypes(SqlBaseParser.SysTableTypesContext ctx) { } - /** - * {@inheritDoc} - * - *

    The default implementation does nothing.

    - */ - @Override public void exitSysTableTypes(SqlBaseParser.SysTableTypesContext ctx) { } /** * {@inheritDoc} * diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseBaseVisitor.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseBaseVisitor.java index 72f517cab8d40..13722407570a7 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseBaseVisitor.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseBaseVisitor.java @@ -74,13 +74,6 @@ class SqlBaseBaseVisitor extends AbstractParseTreeVisitor implements SqlBa * {@link #visitChildren} on {@code ctx}.

    */ @Override public T visitShowSchemas(SqlBaseParser.ShowSchemasContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

    The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

    - */ - @Override public T visitSysCatalogs(SqlBaseParser.SysCatalogsContext ctx) { return visitChildren(ctx); } /** * {@inheritDoc} * @@ -102,13 +95,6 @@ class SqlBaseBaseVisitor extends AbstractParseTreeVisitor implements SqlBa * {@link #visitChildren} on {@code ctx}.

    */ @Override public T visitSysTypes(SqlBaseParser.SysTypesContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

    The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

    - */ - @Override public T visitSysTableTypes(SqlBaseParser.SysTableTypesContext ctx) { return visitChildren(ctx); } /** * {@inheritDoc} * diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseListener.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseListener.java index 67180685c8cbe..7b5a8ea5fbad9 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseListener.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseListener.java @@ -111,18 +111,6 @@ interface SqlBaseListener extends ParseTreeListener { * @param ctx the parse tree */ void exitShowSchemas(SqlBaseParser.ShowSchemasContext ctx); - /** - * Enter a parse tree produced by the {@code sysCatalogs} - * labeled alternative in {@link SqlBaseParser#statement}. - * @param ctx the parse tree - */ - void enterSysCatalogs(SqlBaseParser.SysCatalogsContext ctx); - /** - * Exit a parse tree produced by the {@code sysCatalogs} - * labeled alternative in {@link SqlBaseParser#statement}. - * @param ctx the parse tree - */ - void exitSysCatalogs(SqlBaseParser.SysCatalogsContext ctx); /** * Enter a parse tree produced by the {@code sysTables} * labeled alternative in {@link SqlBaseParser#statement}. @@ -159,18 +147,6 @@ interface SqlBaseListener extends ParseTreeListener { * @param ctx the parse tree */ void exitSysTypes(SqlBaseParser.SysTypesContext ctx); - /** - * Enter a parse tree produced by the {@code sysTableTypes} - * labeled alternative in {@link SqlBaseParser#statement}. - * @param ctx the parse tree - */ - void enterSysTableTypes(SqlBaseParser.SysTableTypesContext ctx); - /** - * Exit a parse tree produced by the {@code sysTableTypes} - * labeled alternative in {@link SqlBaseParser#statement}. - * @param ctx the parse tree - */ - void exitSysTableTypes(SqlBaseParser.SysTableTypesContext ctx); /** * Enter a parse tree produced by {@link SqlBaseParser#query}. * @param ctx the parse tree diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseParser.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseParser.java index 8ba886404536b..7549bfab8320a 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseParser.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseParser.java @@ -334,24 +334,6 @@ public T accept(ParseTreeVisitor visitor) { else return visitor.visitChildren(this); } } - public static class SysCatalogsContext extends StatementContext { - public TerminalNode SYS() { return getToken(SqlBaseParser.SYS, 0); } - public TerminalNode CATALOGS() { return getToken(SqlBaseParser.CATALOGS, 0); } - public SysCatalogsContext(StatementContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof SqlBaseListener ) ((SqlBaseListener)listener).enterSysCatalogs(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof SqlBaseListener ) ((SqlBaseListener)listener).exitSysCatalogs(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof SqlBaseVisitor ) return ((SqlBaseVisitor)visitor).visitSysCatalogs(this); - else return visitor.visitChildren(this); - } - } public static class SysColumnsContext extends StatementContext { public StringContext cluster; public LikePatternContext tableLike; @@ -458,25 +440,6 @@ public T accept(ParseTreeVisitor visitor) { else return visitor.visitChildren(this); } } - public static class SysTableTypesContext extends StatementContext { - public TerminalNode SYS() { return getToken(SqlBaseParser.SYS, 0); } - public TerminalNode TABLE() { return getToken(SqlBaseParser.TABLE, 0); } - public TerminalNode TYPES() { return getToken(SqlBaseParser.TYPES, 0); } - public SysTableTypesContext(StatementContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof SqlBaseListener ) ((SqlBaseListener)listener).enterSysTableTypes(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof SqlBaseListener ) ((SqlBaseListener)listener).exitSysTableTypes(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof SqlBaseVisitor ) return ((SqlBaseVisitor)visitor).visitSysTableTypes(this); - else return visitor.visitChildren(this); - } - } public static class StatementDefaultContext extends StatementContext { public QueryContext query() { return getRuleContext(QueryContext.class,0); @@ -635,7 +598,7 @@ public final StatementContext statement() throws RecognitionException { enterRule(_localctx, 4, RULE_statement); int _la; try { - setState(220); + setState(215); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,19,_ctx) ) { case 1: @@ -1030,71 +993,61 @@ public final StatementContext statement() throws RecognitionException { } break; case 9: - _localctx = new SysCatalogsContext(_localctx); + _localctx = new SysTablesContext(_localctx); enterOuterAlt(_localctx, 9); { setState(172); match(SYS); setState(173); - match(CATALOGS); - } - break; - case 10: - _localctx = new SysTablesContext(_localctx); - enterOuterAlt(_localctx, 10); - { - setState(174); - match(SYS); - setState(175); match(TABLES); - setState(178); + setState(176); _la = _input.LA(1); if (_la==CATALOG) { { - setState(176); + setState(174); match(CATALOG); - setState(177); + setState(175); ((SysTablesContext)_localctx).clusterLike = likePattern(); } } - setState(182); + setState(180); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,11,_ctx) ) { case 1: { - setState(180); + setState(178); ((SysTablesContext)_localctx).tableLike = likePattern(); } break; case 2: { - setState(181); + setState(179); ((SysTablesContext)_localctx).tableIdent = tableIdentifier(); } break; } - setState(193); + setState(191); _la = _input.LA(1); if (_la==TYPE) { { - setState(184); + setState(182); match(TYPE); - setState(185); + setState(183); string(); - setState(190); + setState(188); _errHandler.sync(this); _la = _input.LA(1); while (_la==T__2) { { { - setState(186); + setState(184); match(T__2); - setState(187); + setState(185); string(); } } - setState(192); + setState(190); _errHandler.sync(this); _la = _input.LA(1); } @@ -1103,32 +1056,32 @@ public final StatementContext statement() throws RecognitionException { } break; - case 11: + case 10: _localctx = new SysColumnsContext(_localctx); - enterOuterAlt(_localctx, 11); + enterOuterAlt(_localctx, 10); { - setState(195); + setState(193); match(SYS); - setState(196); + setState(194); match(COLUMNS); - setState(199); + setState(197); _la = _input.LA(1); if (_la==CATALOG) { { - setState(197); + setState(195); match(CATALOG); - setState(198); + setState(196); ((SysColumnsContext)_localctx).cluster = string(); } } - setState(204); + setState(202); switch (_input.LA(1)) { case TABLE: { - setState(201); + setState(199); match(TABLE); - setState(202); + setState(200); ((SysColumnsContext)_localctx).tableLike = likePattern(); } break; @@ -1175,7 +1128,7 @@ public final StatementContext statement() throws RecognitionException { case QUOTED_IDENTIFIER: case BACKQUOTED_IDENTIFIER: { - setState(203); + setState(201); ((SysColumnsContext)_localctx).tableIdent = tableIdentifier(); } break; @@ -1185,34 +1138,34 @@ public final StatementContext statement() throws RecognitionException { default: throw new NoViableAltException(this); } - setState(207); + setState(205); _la = _input.LA(1); if (_la==LIKE) { { - setState(206); + setState(204); ((SysColumnsContext)_localctx).columnPattern = likePattern(); } } } break; - case 12: + case 11: _localctx = new SysTypesContext(_localctx); - enterOuterAlt(_localctx, 12); + enterOuterAlt(_localctx, 11); { - setState(209); + setState(207); match(SYS); - setState(210); + setState(208); match(TYPES); - setState(215); + setState(213); _la = _input.LA(1); if (((((_la - 107)) & ~0x3f) == 0 && ((1L << (_la - 107)) & ((1L << (PLUS - 107)) | (1L << (MINUS - 107)) | (1L << (INTEGER_VALUE - 107)) | (1L << (DECIMAL_VALUE - 107)))) != 0)) { { - setState(212); + setState(210); _la = _input.LA(1); if (_la==PLUS || _la==MINUS) { { - setState(211); + setState(209); _la = _input.LA(1); if ( !(_la==PLUS || _la==MINUS) ) { _errHandler.recoverInline(this); @@ -1222,23 +1175,11 @@ public final StatementContext statement() throws RecognitionException { } } - setState(214); + setState(212); ((SysTypesContext)_localctx).type = number(); } } - } - break; - case 13: - _localctx = new SysTableTypesContext(_localctx); - enterOuterAlt(_localctx, 13); - { - setState(217); - match(SYS); - setState(218); - match(TABLE); - setState(219); - match(TYPES); } break; } @@ -1291,34 +1232,34 @@ public final QueryContext query() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(231); + setState(226); _la = _input.LA(1); if (_la==WITH) { { - setState(222); + setState(217); match(WITH); - setState(223); + setState(218); namedQuery(); - setState(228); + setState(223); _errHandler.sync(this); _la = _input.LA(1); while (_la==T__2) { { { - setState(224); + setState(219); match(T__2); - setState(225); + setState(220); namedQuery(); } } - setState(230); + setState(225); _errHandler.sync(this); _la = _input.LA(1); } } } - setState(233); + setState(228); queryNoWith(); } } @@ -1374,42 +1315,42 @@ public final QueryNoWithContext queryNoWith() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(235); + setState(230); queryTerm(); - setState(246); + setState(241); _la = _input.LA(1); if (_la==ORDER) { { - setState(236); + setState(231); match(ORDER); - setState(237); + setState(232); match(BY); - setState(238); + setState(233); orderBy(); - setState(243); + setState(238); _errHandler.sync(this); _la = _input.LA(1); while (_la==T__2) { { { - setState(239); + setState(234); match(T__2); - setState(240); + setState(235); orderBy(); } } - setState(245); + setState(240); _errHandler.sync(this); _la = _input.LA(1); } } } - setState(249); + setState(244); _la = _input.LA(1); if (_la==LIMIT || _la==LIMIT_ESC) { { - setState(248); + setState(243); limitClause(); } } @@ -1458,14 +1399,14 @@ public final LimitClauseContext limitClause() throws RecognitionException { enterRule(_localctx, 10, RULE_limitClause); int _la; try { - setState(256); + setState(251); switch (_input.LA(1)) { case LIMIT: enterOuterAlt(_localctx, 1); { - setState(251); + setState(246); match(LIMIT); - setState(252); + setState(247); ((LimitClauseContext)_localctx).limit = _input.LT(1); _la = _input.LA(1); if ( !(_la==ALL || _la==INTEGER_VALUE) ) { @@ -1478,9 +1419,9 @@ public final LimitClauseContext limitClause() throws RecognitionException { case LIMIT_ESC: enterOuterAlt(_localctx, 2); { - setState(253); + setState(248); match(LIMIT_ESC); - setState(254); + setState(249); ((LimitClauseContext)_localctx).limit = _input.LT(1); _la = _input.LA(1); if ( !(_la==ALL || _la==INTEGER_VALUE) ) { @@ -1488,7 +1429,7 @@ public final LimitClauseContext limitClause() throws RecognitionException { } else { consume(); } - setState(255); + setState(250); match(ESC_END); } break; @@ -1561,13 +1502,13 @@ public final QueryTermContext queryTerm() throws RecognitionException { QueryTermContext _localctx = new QueryTermContext(_ctx, getState()); enterRule(_localctx, 12, RULE_queryTerm); try { - setState(263); + setState(258); switch (_input.LA(1)) { case SELECT: _localctx = new QueryPrimaryDefaultContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(258); + setState(253); querySpecification(); } break; @@ -1575,11 +1516,11 @@ public final QueryTermContext queryTerm() throws RecognitionException { _localctx = new SubqueryContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(259); + setState(254); match(T__0); - setState(260); + setState(255); queryNoWith(); - setState(261); + setState(256); match(T__1); } break; @@ -1635,13 +1576,13 @@ public final OrderByContext orderBy() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(265); + setState(260); expression(); - setState(267); + setState(262); _la = _input.LA(1); if (_la==ASC || _la==DESC) { { - setState(266); + setState(261); ((OrderByContext)_localctx).ordering = _input.LT(1); _la = _input.LA(1); if ( !(_la==ASC || _la==DESC) ) { @@ -1652,13 +1593,13 @@ public final OrderByContext orderBy() throws RecognitionException { } } - setState(271); + setState(266); _la = _input.LA(1); if (_la==NULLS) { { - setState(269); + setState(264); match(NULLS); - setState(270); + setState(265); ((OrderByContext)_localctx).nullOrdering = _input.LT(1); _la = _input.LA(1); if ( !(_la==FIRST || _la==LAST) ) { @@ -1737,75 +1678,75 @@ public final QuerySpecificationContext querySpecification() throws RecognitionEx try { enterOuterAlt(_localctx, 1); { - setState(273); + setState(268); match(SELECT); - setState(275); + setState(270); _la = _input.LA(1); if (_la==ALL || _la==DISTINCT) { { - setState(274); + setState(269); setQuantifier(); } } - setState(277); + setState(272); selectItem(); - setState(282); + setState(277); _errHandler.sync(this); _la = _input.LA(1); while (_la==T__2) { { { - setState(278); + setState(273); match(T__2); - setState(279); + setState(274); selectItem(); } } - setState(284); + setState(279); _errHandler.sync(this); _la = _input.LA(1); } - setState(286); + setState(281); _la = _input.LA(1); if (_la==FROM) { { - setState(285); + setState(280); fromClause(); } } - setState(290); + setState(285); _la = _input.LA(1); if (_la==WHERE) { { - setState(288); + setState(283); match(WHERE); - setState(289); + setState(284); ((QuerySpecificationContext)_localctx).where = booleanExpression(0); } } - setState(295); + setState(290); _la = _input.LA(1); if (_la==GROUP) { { - setState(292); + setState(287); match(GROUP); - setState(293); + setState(288); match(BY); - setState(294); + setState(289); groupBy(); } } - setState(299); + setState(294); _la = _input.LA(1); if (_la==HAVING) { { - setState(297); + setState(292); match(HAVING); - setState(298); + setState(293); ((QuerySpecificationContext)_localctx).having = booleanExpression(0); } } @@ -1857,23 +1798,23 @@ public final FromClauseContext fromClause() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(301); + setState(296); match(FROM); - setState(302); + setState(297); relation(); - setState(307); + setState(302); _errHandler.sync(this); _la = _input.LA(1); while (_la==T__2) { { { - setState(303); + setState(298); match(T__2); - setState(304); + setState(299); relation(); } } - setState(309); + setState(304); _errHandler.sync(this); _la = _input.LA(1); } @@ -1926,30 +1867,30 @@ public final GroupByContext groupBy() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(311); + setState(306); _la = _input.LA(1); if (_la==ALL || _la==DISTINCT) { { - setState(310); + setState(305); setQuantifier(); } } - setState(313); + setState(308); groupingElement(); - setState(318); + setState(313); _errHandler.sync(this); _la = _input.LA(1); while (_la==T__2) { { { - setState(314); + setState(309); match(T__2); - setState(315); + setState(310); groupingElement(); } } - setState(320); + setState(315); _errHandler.sync(this); _la = _input.LA(1); } @@ -2004,7 +1945,7 @@ public final GroupingElementContext groupingElement() throws RecognitionExceptio _localctx = new SingleGroupingSetContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(321); + setState(316); groupingExpressions(); } } @@ -2050,47 +1991,47 @@ public final GroupingExpressionsContext groupingExpressions() throws Recognition enterRule(_localctx, 24, RULE_groupingExpressions); int _la; try { - setState(336); + setState(331); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,40,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(323); + setState(318); match(T__0); - setState(332); + setState(327); _la = _input.LA(1); if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__0) | (1L << ANALYZE) | (1L << ANALYZED) | (1L << CAST) | (1L << CATALOGS) | (1L << COLUMNS) | (1L << CONVERT) | (1L << CURRENT) | (1L << CURRENT_TIMESTAMP) | (1L << DAY) | (1L << DEBUG) | (1L << EXECUTABLE) | (1L << EXISTS) | (1L << EXPLAIN) | (1L << EXTRACT) | (1L << FALSE) | (1L << FIRST) | (1L << FORMAT) | (1L << FULL) | (1L << FUNCTIONS) | (1L << GRAPHVIZ) | (1L << HOUR) | (1L << INTERVAL) | (1L << LAST) | (1L << LEFT) | (1L << LIMIT) | (1L << MAPPED) | (1L << MATCH) | (1L << MINUTE) | (1L << MONTH) | (1L << NOT) | (1L << NULL) | (1L << OPTIMIZED))) != 0) || ((((_la - 67)) & ~0x3f) == 0 && ((1L << (_la - 67)) & ((1L << (PARSED - 67)) | (1L << (PHYSICAL - 67)) | (1L << (PLAN - 67)) | (1L << (RIGHT - 67)) | (1L << (RLIKE - 67)) | (1L << (QUERY - 67)) | (1L << (SCHEMAS - 67)) | (1L << (SECOND - 67)) | (1L << (SHOW - 67)) | (1L << (SYS - 67)) | (1L << (TABLES - 67)) | (1L << (TEXT - 67)) | (1L << (TRUE - 67)) | (1L << (TYPE - 67)) | (1L << (TYPES - 67)) | (1L << (VERIFY - 67)) | (1L << (YEAR - 67)) | (1L << (FUNCTION_ESC - 67)) | (1L << (DATE_ESC - 67)) | (1L << (TIME_ESC - 67)) | (1L << (TIMESTAMP_ESC - 67)) | (1L << (GUID_ESC - 67)) | (1L << (PLUS - 67)) | (1L << (MINUS - 67)) | (1L << (ASTERISK - 67)) | (1L << (PARAM - 67)) | (1L << (STRING - 67)) | (1L << (INTEGER_VALUE - 67)) | (1L << (DECIMAL_VALUE - 67)) | (1L << (IDENTIFIER - 67)) | (1L << (DIGIT_IDENTIFIER - 67)) | (1L << (QUOTED_IDENTIFIER - 67)) | (1L << (BACKQUOTED_IDENTIFIER - 67)))) != 0)) { { - setState(324); + setState(319); expression(); - setState(329); + setState(324); _errHandler.sync(this); _la = _input.LA(1); while (_la==T__2) { { { - setState(325); + setState(320); match(T__2); - setState(326); + setState(321); expression(); } } - setState(331); + setState(326); _errHandler.sync(this); _la = _input.LA(1); } } } - setState(334); + setState(329); match(T__1); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(335); + setState(330); expression(); } break; @@ -2141,15 +2082,15 @@ public final NamedQueryContext namedQuery() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(338); + setState(333); ((NamedQueryContext)_localctx).name = identifier(); - setState(339); + setState(334); match(AS); - setState(340); + setState(335); match(T__0); - setState(341); + setState(336); queryNoWith(); - setState(342); + setState(337); match(T__1); } } @@ -2193,7 +2134,7 @@ public final SetQuantifierContext setQuantifier() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(344); + setState(339); _la = _input.LA(1); if ( !(_la==ALL || _la==DISTINCT) ) { _errHandler.recoverInline(this); @@ -2256,23 +2197,23 @@ public final SelectItemContext selectItem() throws RecognitionException { _localctx = new SelectExpressionContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(346); + setState(341); expression(); - setState(351); + setState(346); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,42,_ctx) ) { case 1: { - setState(348); + setState(343); _la = _input.LA(1); if (_la==AS) { { - setState(347); + setState(342); match(AS); } } - setState(350); + setState(345); identifier(); } break; @@ -2326,19 +2267,19 @@ public final RelationContext relation() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(353); + setState(348); relationPrimary(); - setState(357); + setState(352); _errHandler.sync(this); _la = _input.LA(1); while (((((_la - 36)) & ~0x3f) == 0 && ((1L << (_la - 36)) & ((1L << (FULL - 36)) | (1L << (INNER - 36)) | (1L << (JOIN - 36)) | (1L << (LEFT - 36)) | (1L << (NATURAL - 36)) | (1L << (RIGHT - 36)))) != 0)) { { { - setState(354); + setState(349); joinRelation(); } } - setState(359); + setState(354); _errHandler.sync(this); _la = _input.LA(1); } @@ -2392,7 +2333,7 @@ public final JoinRelationContext joinRelation() throws RecognitionException { enterRule(_localctx, 34, RULE_joinRelation); int _la; try { - setState(371); + setState(366); switch (_input.LA(1)) { case FULL: case INNER: @@ -2402,18 +2343,18 @@ public final JoinRelationContext joinRelation() throws RecognitionException { enterOuterAlt(_localctx, 1); { { - setState(360); + setState(355); joinType(); } - setState(361); + setState(356); match(JOIN); - setState(362); + setState(357); ((JoinRelationContext)_localctx).right = relationPrimary(); - setState(364); + setState(359); _la = _input.LA(1); if (_la==ON || _la==USING) { { - setState(363); + setState(358); joinCriteria(); } } @@ -2423,13 +2364,13 @@ public final JoinRelationContext joinRelation() throws RecognitionException { case NATURAL: enterOuterAlt(_localctx, 2); { - setState(366); + setState(361); match(NATURAL); - setState(367); + setState(362); joinType(); - setState(368); + setState(363); match(JOIN); - setState(369); + setState(364); ((JoinRelationContext)_localctx).right = relationPrimary(); } break; @@ -2478,17 +2419,17 @@ public final JoinTypeContext joinType() throws RecognitionException { enterRule(_localctx, 36, RULE_joinType); int _la; try { - setState(388); + setState(383); switch (_input.LA(1)) { case INNER: case JOIN: enterOuterAlt(_localctx, 1); { - setState(374); + setState(369); _la = _input.LA(1); if (_la==INNER) { { - setState(373); + setState(368); match(INNER); } } @@ -2498,13 +2439,13 @@ public final JoinTypeContext joinType() throws RecognitionException { case LEFT: enterOuterAlt(_localctx, 2); { - setState(376); + setState(371); match(LEFT); - setState(378); + setState(373); _la = _input.LA(1); if (_la==OUTER) { { - setState(377); + setState(372); match(OUTER); } } @@ -2514,13 +2455,13 @@ public final JoinTypeContext joinType() throws RecognitionException { case RIGHT: enterOuterAlt(_localctx, 3); { - setState(380); + setState(375); match(RIGHT); - setState(382); + setState(377); _la = _input.LA(1); if (_la==OUTER) { { - setState(381); + setState(376); match(OUTER); } } @@ -2530,13 +2471,13 @@ public final JoinTypeContext joinType() throws RecognitionException { case FULL: enterOuterAlt(_localctx, 4); { - setState(384); + setState(379); match(FULL); - setState(386); + setState(381); _la = _input.LA(1); if (_la==OUTER) { { - setState(385); + setState(380); match(OUTER); } } @@ -2594,43 +2535,43 @@ public final JoinCriteriaContext joinCriteria() throws RecognitionException { enterRule(_localctx, 38, RULE_joinCriteria); int _la; try { - setState(404); + setState(399); switch (_input.LA(1)) { case ON: enterOuterAlt(_localctx, 1); { - setState(390); + setState(385); match(ON); - setState(391); + setState(386); booleanExpression(0); } break; case USING: enterOuterAlt(_localctx, 2); { - setState(392); + setState(387); match(USING); - setState(393); + setState(388); match(T__0); - setState(394); + setState(389); identifier(); - setState(399); + setState(394); _errHandler.sync(this); _la = _input.LA(1); while (_la==T__2) { { { - setState(395); + setState(390); match(T__2); - setState(396); + setState(391); identifier(); } } - setState(401); + setState(396); _errHandler.sync(this); _la = _input.LA(1); } - setState(402); + setState(397); match(T__1); } break; @@ -2735,30 +2676,30 @@ public final RelationPrimaryContext relationPrimary() throws RecognitionExceptio enterRule(_localctx, 40, RULE_relationPrimary); int _la; try { - setState(431); + setState(426); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,59,_ctx) ) { case 1: _localctx = new TableNameContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(406); + setState(401); tableIdentifier(); - setState(411); + setState(406); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,54,_ctx) ) { case 1: { - setState(408); + setState(403); _la = _input.LA(1); if (_la==AS) { { - setState(407); + setState(402); match(AS); } } - setState(410); + setState(405); qualifiedName(); } break; @@ -2769,27 +2710,27 @@ public final RelationPrimaryContext relationPrimary() throws RecognitionExceptio _localctx = new AliasedQueryContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(413); + setState(408); match(T__0); - setState(414); + setState(409); queryNoWith(); - setState(415); + setState(410); match(T__1); - setState(420); + setState(415); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,56,_ctx) ) { case 1: { - setState(417); + setState(412); _la = _input.LA(1); if (_la==AS) { { - setState(416); + setState(411); match(AS); } } - setState(419); + setState(414); qualifiedName(); } break; @@ -2800,27 +2741,27 @@ public final RelationPrimaryContext relationPrimary() throws RecognitionExceptio _localctx = new AliasedRelationContext(_localctx); enterOuterAlt(_localctx, 3); { - setState(422); + setState(417); match(T__0); - setState(423); + setState(418); relation(); - setState(424); + setState(419); match(T__1); - setState(429); + setState(424); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,58,_ctx) ) { case 1: { - setState(426); + setState(421); _la = _input.LA(1); if (_la==AS) { { - setState(425); + setState(420); match(AS); } } - setState(428); + setState(423); qualifiedName(); } break; @@ -2869,7 +2810,7 @@ public final ExpressionContext expression() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(433); + setState(428); booleanExpression(0); } } @@ -3077,7 +3018,7 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc int _alt; enterOuterAlt(_localctx, 1); { - setState(466); + setState(461); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,60,_ctx) ) { case 1: @@ -3086,9 +3027,9 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _ctx = _localctx; _prevctx = _localctx; - setState(436); + setState(431); match(NOT); - setState(437); + setState(432); booleanExpression(8); } break; @@ -3097,13 +3038,13 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _localctx = new ExistsContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(438); + setState(433); match(EXISTS); - setState(439); + setState(434); match(T__0); - setState(440); + setState(435); query(); - setState(441); + setState(436); match(T__1); } break; @@ -3112,15 +3053,15 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _localctx = new StringQueryContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(443); + setState(438); match(QUERY); - setState(444); + setState(439); match(T__0); - setState(445); + setState(440); ((StringQueryContext)_localctx).queryString = string(); - setState(446); + setState(441); matchQueryOptions(); - setState(447); + setState(442); match(T__1); } break; @@ -3129,19 +3070,19 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _localctx = new MatchQueryContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(449); + setState(444); match(MATCH); - setState(450); + setState(445); match(T__0); - setState(451); + setState(446); ((MatchQueryContext)_localctx).singleField = qualifiedName(); - setState(452); + setState(447); match(T__2); - setState(453); + setState(448); ((MatchQueryContext)_localctx).queryString = string(); - setState(454); + setState(449); matchQueryOptions(); - setState(455); + setState(450); match(T__1); } break; @@ -3150,19 +3091,19 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _localctx = new MultiMatchQueryContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(457); + setState(452); match(MATCH); - setState(458); + setState(453); match(T__0); - setState(459); + setState(454); ((MultiMatchQueryContext)_localctx).multiFields = string(); - setState(460); + setState(455); match(T__2); - setState(461); + setState(456); ((MultiMatchQueryContext)_localctx).queryString = string(); - setState(462); + setState(457); matchQueryOptions(); - setState(463); + setState(458); match(T__1); } break; @@ -3171,13 +3112,13 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _localctx = new BooleanDefaultContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(465); + setState(460); predicated(); } break; } _ctx.stop = _input.LT(-1); - setState(476); + setState(471); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,62,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { @@ -3185,7 +3126,7 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc if ( _parseListeners!=null ) triggerExitRuleEvent(); _prevctx = _localctx; { - setState(474); + setState(469); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,61,_ctx) ) { case 1: @@ -3193,11 +3134,11 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _localctx = new LogicalBinaryContext(new BooleanExpressionContext(_parentctx, _parentState)); ((LogicalBinaryContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_booleanExpression); - setState(468); + setState(463); if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)"); - setState(469); + setState(464); ((LogicalBinaryContext)_localctx).operator = match(AND); - setState(470); + setState(465); ((LogicalBinaryContext)_localctx).right = booleanExpression(3); } break; @@ -3206,18 +3147,18 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _localctx = new LogicalBinaryContext(new BooleanExpressionContext(_parentctx, _parentState)); ((LogicalBinaryContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_booleanExpression); - setState(471); + setState(466); if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)"); - setState(472); + setState(467); ((LogicalBinaryContext)_localctx).operator = match(OR); - setState(473); + setState(468); ((LogicalBinaryContext)_localctx).right = booleanExpression(2); } break; } } } - setState(478); + setState(473); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,62,_ctx); } @@ -3267,19 +3208,19 @@ public final MatchQueryOptionsContext matchQueryOptions() throws RecognitionExce try { enterOuterAlt(_localctx, 1); { - setState(483); + setState(478); _errHandler.sync(this); _la = _input.LA(1); while (_la==T__2) { { { - setState(479); + setState(474); match(T__2); - setState(480); + setState(475); string(); } } - setState(485); + setState(480); _errHandler.sync(this); _la = _input.LA(1); } @@ -3328,14 +3269,14 @@ public final PredicatedContext predicated() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(486); + setState(481); valueExpression(0); - setState(488); + setState(483); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,64,_ctx) ) { case 1: { - setState(487); + setState(482); predicate(); } break; @@ -3405,142 +3346,142 @@ public final PredicateContext predicate() throws RecognitionException { enterRule(_localctx, 50, RULE_predicate); int _la; try { - setState(536); + setState(531); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,72,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(491); + setState(486); _la = _input.LA(1); if (_la==NOT) { { - setState(490); + setState(485); match(NOT); } } - setState(493); + setState(488); ((PredicateContext)_localctx).kind = match(BETWEEN); - setState(494); + setState(489); ((PredicateContext)_localctx).lower = valueExpression(0); - setState(495); + setState(490); match(AND); - setState(496); + setState(491); ((PredicateContext)_localctx).upper = valueExpression(0); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(499); + setState(494); _la = _input.LA(1); if (_la==NOT) { { - setState(498); + setState(493); match(NOT); } } - setState(501); + setState(496); ((PredicateContext)_localctx).kind = match(IN); - setState(502); + setState(497); match(T__0); - setState(503); + setState(498); valueExpression(0); - setState(508); + setState(503); _errHandler.sync(this); _la = _input.LA(1); while (_la==T__2) { { { - setState(504); + setState(499); match(T__2); - setState(505); + setState(500); valueExpression(0); } } - setState(510); + setState(505); _errHandler.sync(this); _la = _input.LA(1); } - setState(511); + setState(506); match(T__1); } break; case 3: enterOuterAlt(_localctx, 3); { - setState(514); + setState(509); _la = _input.LA(1); if (_la==NOT) { { - setState(513); + setState(508); match(NOT); } } - setState(516); + setState(511); ((PredicateContext)_localctx).kind = match(IN); - setState(517); + setState(512); match(T__0); - setState(518); + setState(513); query(); - setState(519); + setState(514); match(T__1); } break; case 4: enterOuterAlt(_localctx, 4); { - setState(522); + setState(517); _la = _input.LA(1); if (_la==NOT) { { - setState(521); + setState(516); match(NOT); } } - setState(524); + setState(519); ((PredicateContext)_localctx).kind = match(LIKE); - setState(525); + setState(520); pattern(); } break; case 5: enterOuterAlt(_localctx, 5); { - setState(527); + setState(522); _la = _input.LA(1); if (_la==NOT) { { - setState(526); + setState(521); match(NOT); } } - setState(529); + setState(524); ((PredicateContext)_localctx).kind = match(RLIKE); - setState(530); + setState(525); ((PredicateContext)_localctx).regex = string(); } break; case 6: enterOuterAlt(_localctx, 6); { - setState(531); + setState(526); match(IS); - setState(533); + setState(528); _la = _input.LA(1); if (_la==NOT) { { - setState(532); + setState(527); match(NOT); } } - setState(535); + setState(530); ((PredicateContext)_localctx).kind = match(NULL); } break; @@ -3587,9 +3528,9 @@ public final LikePatternContext likePattern() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(538); + setState(533); match(LIKE); - setState(539); + setState(534); pattern(); } } @@ -3637,14 +3578,14 @@ public final PatternContext pattern() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(541); + setState(536); ((PatternContext)_localctx).value = string(); - setState(543); + setState(538); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,73,_ctx) ) { case 1: { - setState(542); + setState(537); patternEscape(); } break; @@ -3692,25 +3633,25 @@ public final PatternEscapeContext patternEscape() throws RecognitionException { PatternEscapeContext _localctx = new PatternEscapeContext(_ctx, getState()); enterRule(_localctx, 56, RULE_patternEscape); try { - setState(551); + setState(546); switch (_input.LA(1)) { case ESCAPE: enterOuterAlt(_localctx, 1); { - setState(545); + setState(540); match(ESCAPE); - setState(546); + setState(541); ((PatternEscapeContext)_localctx).escape = string(); } break; case ESCAPE_ESC: enterOuterAlt(_localctx, 2); { - setState(547); + setState(542); match(ESCAPE_ESC); - setState(548); + setState(543); ((PatternEscapeContext)_localctx).escape = string(); - setState(549); + setState(544); match(ESC_END); } break; @@ -3855,7 +3796,7 @@ private ValueExpressionContext valueExpression(int _p) throws RecognitionExcepti int _alt; enterOuterAlt(_localctx, 1); { - setState(557); + setState(552); switch (_input.LA(1)) { case T__0: case ANALYZE: @@ -3923,7 +3864,7 @@ private ValueExpressionContext valueExpression(int _p) throws RecognitionExcepti _ctx = _localctx; _prevctx = _localctx; - setState(554); + setState(549); primaryExpression(); } break; @@ -3933,7 +3874,7 @@ private ValueExpressionContext valueExpression(int _p) throws RecognitionExcepti _localctx = new ArithmeticUnaryContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(555); + setState(550); ((ArithmeticUnaryContext)_localctx).operator = _input.LT(1); _la = _input.LA(1); if ( !(_la==PLUS || _la==MINUS) ) { @@ -3941,7 +3882,7 @@ private ValueExpressionContext valueExpression(int _p) throws RecognitionExcepti } else { consume(); } - setState(556); + setState(551); valueExpression(4); } break; @@ -3949,7 +3890,7 @@ private ValueExpressionContext valueExpression(int _p) throws RecognitionExcepti throw new NoViableAltException(this); } _ctx.stop = _input.LT(-1); - setState(571); + setState(566); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,77,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { @@ -3957,7 +3898,7 @@ private ValueExpressionContext valueExpression(int _p) throws RecognitionExcepti if ( _parseListeners!=null ) triggerExitRuleEvent(); _prevctx = _localctx; { - setState(569); + setState(564); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,76,_ctx) ) { case 1: @@ -3965,9 +3906,9 @@ private ValueExpressionContext valueExpression(int _p) throws RecognitionExcepti _localctx = new ArithmeticBinaryContext(new ValueExpressionContext(_parentctx, _parentState)); ((ArithmeticBinaryContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_valueExpression); - setState(559); + setState(554); if (!(precpred(_ctx, 3))) throw new FailedPredicateException(this, "precpred(_ctx, 3)"); - setState(560); + setState(555); ((ArithmeticBinaryContext)_localctx).operator = _input.LT(1); _la = _input.LA(1); if ( !(((((_la - 109)) & ~0x3f) == 0 && ((1L << (_la - 109)) & ((1L << (ASTERISK - 109)) | (1L << (SLASH - 109)) | (1L << (PERCENT - 109)))) != 0)) ) { @@ -3975,7 +3916,7 @@ private ValueExpressionContext valueExpression(int _p) throws RecognitionExcepti } else { consume(); } - setState(561); + setState(556); ((ArithmeticBinaryContext)_localctx).right = valueExpression(4); } break; @@ -3984,9 +3925,9 @@ private ValueExpressionContext valueExpression(int _p) throws RecognitionExcepti _localctx = new ArithmeticBinaryContext(new ValueExpressionContext(_parentctx, _parentState)); ((ArithmeticBinaryContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_valueExpression); - setState(562); + setState(557); if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)"); - setState(563); + setState(558); ((ArithmeticBinaryContext)_localctx).operator = _input.LT(1); _la = _input.LA(1); if ( !(_la==PLUS || _la==MINUS) ) { @@ -3994,7 +3935,7 @@ private ValueExpressionContext valueExpression(int _p) throws RecognitionExcepti } else { consume(); } - setState(564); + setState(559); ((ArithmeticBinaryContext)_localctx).right = valueExpression(3); } break; @@ -4003,18 +3944,18 @@ private ValueExpressionContext valueExpression(int _p) throws RecognitionExcepti _localctx = new ComparisonContext(new ValueExpressionContext(_parentctx, _parentState)); ((ComparisonContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_valueExpression); - setState(565); + setState(560); if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)"); - setState(566); + setState(561); comparisonOperator(); - setState(567); + setState(562); ((ComparisonContext)_localctx).right = valueExpression(2); } break; } } } - setState(573); + setState(568); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,77,_ctx); } @@ -4221,14 +4162,14 @@ public final PrimaryExpressionContext primaryExpression() throws RecognitionExce enterRule(_localctx, 60, RULE_primaryExpression); int _la; try { - setState(594); + setState(589); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,79,_ctx) ) { case 1: _localctx = new CastContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(574); + setState(569); castExpression(); } break; @@ -4236,7 +4177,7 @@ public final PrimaryExpressionContext primaryExpression() throws RecognitionExce _localctx = new ExtractContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(575); + setState(570); extractExpression(); } break; @@ -4244,7 +4185,7 @@ public final PrimaryExpressionContext primaryExpression() throws RecognitionExce _localctx = new CurrentDateTimeFunctionContext(_localctx); enterOuterAlt(_localctx, 3); { - setState(576); + setState(571); builtinDateTimeFunction(); } break; @@ -4252,7 +4193,7 @@ public final PrimaryExpressionContext primaryExpression() throws RecognitionExce _localctx = new ConstantDefaultContext(_localctx); enterOuterAlt(_localctx, 4); { - setState(577); + setState(572); constant(); } break; @@ -4260,18 +4201,18 @@ public final PrimaryExpressionContext primaryExpression() throws RecognitionExce _localctx = new StarContext(_localctx); enterOuterAlt(_localctx, 5); { - setState(581); + setState(576); _la = _input.LA(1); if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << ANALYZE) | (1L << ANALYZED) | (1L << CATALOGS) | (1L << COLUMNS) | (1L << CURRENT) | (1L << DAY) | (1L << DEBUG) | (1L << EXECUTABLE) | (1L << EXPLAIN) | (1L << FIRST) | (1L << FORMAT) | (1L << FULL) | (1L << FUNCTIONS) | (1L << GRAPHVIZ) | (1L << HOUR) | (1L << INTERVAL) | (1L << LAST) | (1L << LIMIT) | (1L << MAPPED) | (1L << MINUTE) | (1L << MONTH) | (1L << OPTIMIZED))) != 0) || ((((_la - 67)) & ~0x3f) == 0 && ((1L << (_la - 67)) & ((1L << (PARSED - 67)) | (1L << (PHYSICAL - 67)) | (1L << (PLAN - 67)) | (1L << (RLIKE - 67)) | (1L << (QUERY - 67)) | (1L << (SCHEMAS - 67)) | (1L << (SECOND - 67)) | (1L << (SHOW - 67)) | (1L << (SYS - 67)) | (1L << (TABLES - 67)) | (1L << (TEXT - 67)) | (1L << (TYPE - 67)) | (1L << (TYPES - 67)) | (1L << (VERIFY - 67)) | (1L << (YEAR - 67)) | (1L << (IDENTIFIER - 67)) | (1L << (DIGIT_IDENTIFIER - 67)) | (1L << (QUOTED_IDENTIFIER - 67)) | (1L << (BACKQUOTED_IDENTIFIER - 67)))) != 0)) { { - setState(578); + setState(573); qualifiedName(); - setState(579); + setState(574); match(DOT); } } - setState(583); + setState(578); match(ASTERISK); } break; @@ -4279,7 +4220,7 @@ public final PrimaryExpressionContext primaryExpression() throws RecognitionExce _localctx = new FunctionContext(_localctx); enterOuterAlt(_localctx, 6); { - setState(584); + setState(579); functionExpression(); } break; @@ -4287,11 +4228,11 @@ public final PrimaryExpressionContext primaryExpression() throws RecognitionExce _localctx = new SubqueryExpressionContext(_localctx); enterOuterAlt(_localctx, 7); { - setState(585); + setState(580); match(T__0); - setState(586); + setState(581); query(); - setState(587); + setState(582); match(T__1); } break; @@ -4299,7 +4240,7 @@ public final PrimaryExpressionContext primaryExpression() throws RecognitionExce _localctx = new DereferenceContext(_localctx); enterOuterAlt(_localctx, 8); { - setState(589); + setState(584); qualifiedName(); } break; @@ -4307,11 +4248,11 @@ public final PrimaryExpressionContext primaryExpression() throws RecognitionExce _localctx = new ParenthesizedExpressionContext(_localctx); enterOuterAlt(_localctx, 9); { - setState(590); + setState(585); match(T__0); - setState(591); + setState(586); expression(); - setState(592); + setState(587); match(T__1); } break; @@ -4360,42 +4301,42 @@ public final CastExpressionContext castExpression() throws RecognitionException CastExpressionContext _localctx = new CastExpressionContext(_ctx, getState()); enterRule(_localctx, 62, RULE_castExpression); try { - setState(606); + setState(601); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,80,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(596); + setState(591); castTemplate(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(597); + setState(592); match(FUNCTION_ESC); - setState(598); + setState(593); castTemplate(); - setState(599); + setState(594); match(ESC_END); } break; case 3: enterOuterAlt(_localctx, 3); { - setState(601); + setState(596); convertTemplate(); } break; case 4: enterOuterAlt(_localctx, 4); { - setState(602); + setState(597); match(FUNCTION_ESC); - setState(603); + setState(598); convertTemplate(); - setState(604); + setState(599); match(ESC_END); } break; @@ -4446,17 +4387,17 @@ public final CastTemplateContext castTemplate() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(608); + setState(603); match(CAST); - setState(609); + setState(604); match(T__0); - setState(610); + setState(605); expression(); - setState(611); + setState(606); match(AS); - setState(612); + setState(607); dataType(); - setState(613); + setState(608); match(T__1); } } @@ -4502,25 +4443,25 @@ public final BuiltinDateTimeFunctionContext builtinDateTimeFunction() throws Rec try { enterOuterAlt(_localctx, 1); { - setState(615); + setState(610); ((BuiltinDateTimeFunctionContext)_localctx).name = match(CURRENT_TIMESTAMP); - setState(621); + setState(616); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,82,_ctx) ) { case 1: { - setState(616); + setState(611); match(T__0); - setState(618); + setState(613); _la = _input.LA(1); if (_la==INTEGER_VALUE) { { - setState(617); + setState(612); ((BuiltinDateTimeFunctionContext)_localctx).precision = match(INTEGER_VALUE); } } - setState(620); + setState(615); match(T__1); } break; @@ -4571,17 +4512,17 @@ public final ConvertTemplateContext convertTemplate() throws RecognitionExceptio try { enterOuterAlt(_localctx, 1); { - setState(623); + setState(618); match(CONVERT); - setState(624); + setState(619); match(T__0); - setState(625); + setState(620); expression(); - setState(626); + setState(621); match(T__2); - setState(627); + setState(622); dataType(); - setState(628); + setState(623); match(T__1); } } @@ -4625,23 +4566,23 @@ public final ExtractExpressionContext extractExpression() throws RecognitionExce ExtractExpressionContext _localctx = new ExtractExpressionContext(_ctx, getState()); enterRule(_localctx, 70, RULE_extractExpression); try { - setState(635); + setState(630); switch (_input.LA(1)) { case EXTRACT: enterOuterAlt(_localctx, 1); { - setState(630); + setState(625); extractTemplate(); } break; case FUNCTION_ESC: enterOuterAlt(_localctx, 2); { - setState(631); + setState(626); match(FUNCTION_ESC); - setState(632); + setState(627); extractTemplate(); - setState(633); + setState(628); match(ESC_END); } break; @@ -4695,17 +4636,17 @@ public final ExtractTemplateContext extractTemplate() throws RecognitionExceptio try { enterOuterAlt(_localctx, 1); { - setState(637); + setState(632); match(EXTRACT); - setState(638); + setState(633); match(T__0); - setState(639); + setState(634); ((ExtractTemplateContext)_localctx).field = identifier(); - setState(640); + setState(635); match(FROM); - setState(641); + setState(636); valueExpression(0); - setState(642); + setState(637); match(T__1); } } @@ -4748,7 +4689,7 @@ public final FunctionExpressionContext functionExpression() throws RecognitionEx FunctionExpressionContext _localctx = new FunctionExpressionContext(_ctx, getState()); enterRule(_localctx, 74, RULE_functionExpression); try { - setState(649); + setState(644); switch (_input.LA(1)) { case ANALYZE: case ANALYZED: @@ -4795,18 +4736,18 @@ public final FunctionExpressionContext functionExpression() throws RecognitionEx case BACKQUOTED_IDENTIFIER: enterOuterAlt(_localctx, 1); { - setState(644); + setState(639); functionTemplate(); } break; case FUNCTION_ESC: enterOuterAlt(_localctx, 2); { - setState(645); + setState(640); match(FUNCTION_ESC); - setState(646); + setState(641); functionTemplate(); - setState(647); + setState(642); match(ESC_END); } break; @@ -4864,45 +4805,45 @@ public final FunctionTemplateContext functionTemplate() throws RecognitionExcept try { enterOuterAlt(_localctx, 1); { - setState(651); + setState(646); functionName(); - setState(652); + setState(647); match(T__0); - setState(664); + setState(659); _la = _input.LA(1); if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__0) | (1L << ALL) | (1L << ANALYZE) | (1L << ANALYZED) | (1L << CAST) | (1L << CATALOGS) | (1L << COLUMNS) | (1L << CONVERT) | (1L << CURRENT) | (1L << CURRENT_TIMESTAMP) | (1L << DAY) | (1L << DEBUG) | (1L << DISTINCT) | (1L << EXECUTABLE) | (1L << EXISTS) | (1L << EXPLAIN) | (1L << EXTRACT) | (1L << FALSE) | (1L << FIRST) | (1L << FORMAT) | (1L << FULL) | (1L << FUNCTIONS) | (1L << GRAPHVIZ) | (1L << HOUR) | (1L << INTERVAL) | (1L << LAST) | (1L << LEFT) | (1L << LIMIT) | (1L << MAPPED) | (1L << MATCH) | (1L << MINUTE) | (1L << MONTH) | (1L << NOT) | (1L << NULL) | (1L << OPTIMIZED))) != 0) || ((((_la - 67)) & ~0x3f) == 0 && ((1L << (_la - 67)) & ((1L << (PARSED - 67)) | (1L << (PHYSICAL - 67)) | (1L << (PLAN - 67)) | (1L << (RIGHT - 67)) | (1L << (RLIKE - 67)) | (1L << (QUERY - 67)) | (1L << (SCHEMAS - 67)) | (1L << (SECOND - 67)) | (1L << (SHOW - 67)) | (1L << (SYS - 67)) | (1L << (TABLES - 67)) | (1L << (TEXT - 67)) | (1L << (TRUE - 67)) | (1L << (TYPE - 67)) | (1L << (TYPES - 67)) | (1L << (VERIFY - 67)) | (1L << (YEAR - 67)) | (1L << (FUNCTION_ESC - 67)) | (1L << (DATE_ESC - 67)) | (1L << (TIME_ESC - 67)) | (1L << (TIMESTAMP_ESC - 67)) | (1L << (GUID_ESC - 67)) | (1L << (PLUS - 67)) | (1L << (MINUS - 67)) | (1L << (ASTERISK - 67)) | (1L << (PARAM - 67)) | (1L << (STRING - 67)) | (1L << (INTEGER_VALUE - 67)) | (1L << (DECIMAL_VALUE - 67)) | (1L << (IDENTIFIER - 67)) | (1L << (DIGIT_IDENTIFIER - 67)) | (1L << (QUOTED_IDENTIFIER - 67)) | (1L << (BACKQUOTED_IDENTIFIER - 67)))) != 0)) { { - setState(654); + setState(649); _la = _input.LA(1); if (_la==ALL || _la==DISTINCT) { { - setState(653); + setState(648); setQuantifier(); } } - setState(656); + setState(651); expression(); - setState(661); + setState(656); _errHandler.sync(this); _la = _input.LA(1); while (_la==T__2) { { { - setState(657); + setState(652); match(T__2); - setState(658); + setState(653); expression(); } } - setState(663); + setState(658); _errHandler.sync(this); _la = _input.LA(1); } } } - setState(666); + setState(661); match(T__1); } } @@ -4946,19 +4887,19 @@ public final FunctionNameContext functionName() throws RecognitionException { FunctionNameContext _localctx = new FunctionNameContext(_ctx, getState()); enterRule(_localctx, 78, RULE_functionName); try { - setState(671); + setState(666); switch (_input.LA(1)) { case LEFT: enterOuterAlt(_localctx, 1); { - setState(668); + setState(663); match(LEFT); } break; case RIGHT: enterOuterAlt(_localctx, 2); { - setState(669); + setState(664); match(RIGHT); } break; @@ -5005,7 +4946,7 @@ public final FunctionNameContext functionName() throws RecognitionException { case BACKQUOTED_IDENTIFIER: enterOuterAlt(_localctx, 3); { - setState(670); + setState(665); identifier(); } break; @@ -5236,13 +5177,13 @@ public final ConstantContext constant() throws RecognitionException { enterRule(_localctx, 80, RULE_constant); try { int _alt; - setState(699); + setState(694); switch (_input.LA(1)) { case NULL: _localctx = new NullLiteralContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(673); + setState(668); match(NULL); } break; @@ -5250,7 +5191,7 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new IntervalLiteralContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(674); + setState(669); interval(); } break; @@ -5259,7 +5200,7 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new NumericLiteralContext(_localctx); enterOuterAlt(_localctx, 3); { - setState(675); + setState(670); number(); } break; @@ -5268,7 +5209,7 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new BooleanLiteralContext(_localctx); enterOuterAlt(_localctx, 4); { - setState(676); + setState(671); booleanValue(); } break; @@ -5276,7 +5217,7 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new StringLiteralContext(_localctx); enterOuterAlt(_localctx, 5); { - setState(678); + setState(673); _errHandler.sync(this); _alt = 1; do { @@ -5284,7 +5225,7 @@ public final ConstantContext constant() throws RecognitionException { case 1: { { - setState(677); + setState(672); match(STRING); } } @@ -5292,7 +5233,7 @@ public final ConstantContext constant() throws RecognitionException { default: throw new NoViableAltException(this); } - setState(680); + setState(675); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,89,_ctx); } while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ); @@ -5302,7 +5243,7 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new ParamLiteralContext(_localctx); enterOuterAlt(_localctx, 6); { - setState(682); + setState(677); match(PARAM); } break; @@ -5310,11 +5251,11 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new DateEscapedLiteralContext(_localctx); enterOuterAlt(_localctx, 7); { - setState(683); + setState(678); match(DATE_ESC); - setState(684); + setState(679); string(); - setState(685); + setState(680); match(ESC_END); } break; @@ -5322,11 +5263,11 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new TimeEscapedLiteralContext(_localctx); enterOuterAlt(_localctx, 8); { - setState(687); + setState(682); match(TIME_ESC); - setState(688); + setState(683); string(); - setState(689); + setState(684); match(ESC_END); } break; @@ -5334,11 +5275,11 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new TimestampEscapedLiteralContext(_localctx); enterOuterAlt(_localctx, 9); { - setState(691); + setState(686); match(TIMESTAMP_ESC); - setState(692); + setState(687); string(); - setState(693); + setState(688); match(ESC_END); } break; @@ -5346,11 +5287,11 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new GuidEscapedLiteralContext(_localctx); enterOuterAlt(_localctx, 10); { - setState(695); + setState(690); match(GUID_ESC); - setState(696); + setState(691); string(); - setState(697); + setState(692); match(ESC_END); } break; @@ -5403,7 +5344,7 @@ public final ComparisonOperatorContext comparisonOperator() throws RecognitionEx try { enterOuterAlt(_localctx, 1); { - setState(701); + setState(696); _la = _input.LA(1); if ( !(((((_la - 100)) & ~0x3f) == 0 && ((1L << (_la - 100)) & ((1L << (EQ - 100)) | (1L << (NULLEQ - 100)) | (1L << (NEQ - 100)) | (1L << (LT - 100)) | (1L << (LTE - 100)) | (1L << (GT - 100)) | (1L << (GTE - 100)))) != 0)) ) { _errHandler.recoverInline(this); @@ -5452,7 +5393,7 @@ public final BooleanValueContext booleanValue() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(703); + setState(698); _la = _input.LA(1); if ( !(_la==FALSE || _la==TRUE) ) { _errHandler.recoverInline(this); @@ -5520,13 +5461,13 @@ public final IntervalContext interval() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(705); + setState(700); match(INTERVAL); - setState(707); + setState(702); _la = _input.LA(1); if (_la==PLUS || _la==MINUS) { { - setState(706); + setState(701); ((IntervalContext)_localctx).sign = _input.LT(1); _la = _input.LA(1); if ( !(_la==PLUS || _la==MINUS) ) { @@ -5537,35 +5478,35 @@ public final IntervalContext interval() throws RecognitionException { } } - setState(711); + setState(706); switch (_input.LA(1)) { case INTEGER_VALUE: case DECIMAL_VALUE: { - setState(709); + setState(704); ((IntervalContext)_localctx).valueNumeric = number(); } break; case PARAM: case STRING: { - setState(710); + setState(705); ((IntervalContext)_localctx).valuePattern = string(); } break; default: throw new NoViableAltException(this); } - setState(713); + setState(708); ((IntervalContext)_localctx).leading = intervalField(); - setState(716); + setState(711); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,93,_ctx) ) { case 1: { - setState(714); + setState(709); match(TO); - setState(715); + setState(710); ((IntervalContext)_localctx).trailing = intervalField(); } break; @@ -5622,7 +5563,7 @@ public final IntervalFieldContext intervalField() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(718); + setState(713); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << DAY) | (1L << DAYS) | (1L << HOUR) | (1L << HOURS) | (1L << MINUTE) | (1L << MINUTES) | (1L << MONTH) | (1L << MONTHS))) != 0) || ((((_la - 74)) & ~0x3f) == 0 && ((1L << (_la - 74)) & ((1L << (SECOND - 74)) | (1L << (SECONDS - 74)) | (1L << (YEAR - 74)) | (1L << (YEARS - 74)))) != 0)) ) { _errHandler.recoverInline(this); @@ -5680,7 +5621,7 @@ public final DataTypeContext dataType() throws RecognitionException { _localctx = new PrimitiveDataTypeContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(720); + setState(715); identifier(); } } @@ -5732,25 +5673,25 @@ public final QualifiedNameContext qualifiedName() throws RecognitionException { int _alt; enterOuterAlt(_localctx, 1); { - setState(727); + setState(722); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,94,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(722); + setState(717); identifier(); - setState(723); + setState(718); match(DOT); } } } - setState(729); + setState(724); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,94,_ctx); } - setState(730); + setState(725); identifier(); } } @@ -5795,13 +5736,13 @@ public final IdentifierContext identifier() throws RecognitionException { IdentifierContext _localctx = new IdentifierContext(_ctx, getState()); enterRule(_localctx, 94, RULE_identifier); try { - setState(734); + setState(729); switch (_input.LA(1)) { case QUOTED_IDENTIFIER: case BACKQUOTED_IDENTIFIER: enterOuterAlt(_localctx, 1); { - setState(732); + setState(727); quoteIdentifier(); } break; @@ -5846,7 +5787,7 @@ public final IdentifierContext identifier() throws RecognitionException { case DIGIT_IDENTIFIER: enterOuterAlt(_localctx, 2); { - setState(733); + setState(728); unquoteIdentifier(); } break; @@ -5899,43 +5840,43 @@ public final TableIdentifierContext tableIdentifier() throws RecognitionExceptio enterRule(_localctx, 96, RULE_tableIdentifier); int _la; try { - setState(748); + setState(743); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,98,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(739); + setState(734); _la = _input.LA(1); if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << ANALYZE) | (1L << ANALYZED) | (1L << CATALOGS) | (1L << COLUMNS) | (1L << CURRENT) | (1L << DAY) | (1L << DEBUG) | (1L << EXECUTABLE) | (1L << EXPLAIN) | (1L << FIRST) | (1L << FORMAT) | (1L << FULL) | (1L << FUNCTIONS) | (1L << GRAPHVIZ) | (1L << HOUR) | (1L << INTERVAL) | (1L << LAST) | (1L << LIMIT) | (1L << MAPPED) | (1L << MINUTE) | (1L << MONTH) | (1L << OPTIMIZED))) != 0) || ((((_la - 67)) & ~0x3f) == 0 && ((1L << (_la - 67)) & ((1L << (PARSED - 67)) | (1L << (PHYSICAL - 67)) | (1L << (PLAN - 67)) | (1L << (RLIKE - 67)) | (1L << (QUERY - 67)) | (1L << (SCHEMAS - 67)) | (1L << (SECOND - 67)) | (1L << (SHOW - 67)) | (1L << (SYS - 67)) | (1L << (TABLES - 67)) | (1L << (TEXT - 67)) | (1L << (TYPE - 67)) | (1L << (TYPES - 67)) | (1L << (VERIFY - 67)) | (1L << (YEAR - 67)) | (1L << (IDENTIFIER - 67)) | (1L << (DIGIT_IDENTIFIER - 67)) | (1L << (QUOTED_IDENTIFIER - 67)) | (1L << (BACKQUOTED_IDENTIFIER - 67)))) != 0)) { { - setState(736); + setState(731); ((TableIdentifierContext)_localctx).catalog = identifier(); - setState(737); + setState(732); match(T__3); } } - setState(741); + setState(736); match(TABLE_IDENTIFIER); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(745); + setState(740); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,97,_ctx) ) { case 1: { - setState(742); + setState(737); ((TableIdentifierContext)_localctx).catalog = identifier(); - setState(743); + setState(738); match(T__3); } break; } - setState(747); + setState(742); ((TableIdentifierContext)_localctx).name = identifier(); } break; @@ -6002,13 +5943,13 @@ public final QuoteIdentifierContext quoteIdentifier() throws RecognitionExceptio QuoteIdentifierContext _localctx = new QuoteIdentifierContext(_ctx, getState()); enterRule(_localctx, 98, RULE_quoteIdentifier); try { - setState(752); + setState(747); switch (_input.LA(1)) { case QUOTED_IDENTIFIER: _localctx = new QuotedIdentifierContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(750); + setState(745); match(QUOTED_IDENTIFIER); } break; @@ -6016,7 +5957,7 @@ public final QuoteIdentifierContext quoteIdentifier() throws RecognitionExceptio _localctx = new BackQuotedIdentifierContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(751); + setState(746); match(BACKQUOTED_IDENTIFIER); } break; @@ -6088,13 +6029,13 @@ public final UnquoteIdentifierContext unquoteIdentifier() throws RecognitionExce UnquoteIdentifierContext _localctx = new UnquoteIdentifierContext(_ctx, getState()); enterRule(_localctx, 100, RULE_unquoteIdentifier); try { - setState(757); + setState(752); switch (_input.LA(1)) { case IDENTIFIER: _localctx = new UnquotedIdentifierContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(754); + setState(749); match(IDENTIFIER); } break; @@ -6138,7 +6079,7 @@ public final UnquoteIdentifierContext unquoteIdentifier() throws RecognitionExce _localctx = new UnquotedIdentifierContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(755); + setState(750); nonReserved(); } break; @@ -6146,7 +6087,7 @@ public final UnquoteIdentifierContext unquoteIdentifier() throws RecognitionExce _localctx = new DigitIdentifierContext(_localctx); enterOuterAlt(_localctx, 3); { - setState(756); + setState(751); match(DIGIT_IDENTIFIER); } break; @@ -6215,13 +6156,13 @@ public final NumberContext number() throws RecognitionException { NumberContext _localctx = new NumberContext(_ctx, getState()); enterRule(_localctx, 102, RULE_number); try { - setState(761); + setState(756); switch (_input.LA(1)) { case DECIMAL_VALUE: _localctx = new DecimalLiteralContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(759); + setState(754); match(DECIMAL_VALUE); } break; @@ -6229,7 +6170,7 @@ public final NumberContext number() throws RecognitionException { _localctx = new IntegerLiteralContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(760); + setState(755); match(INTEGER_VALUE); } break; @@ -6277,7 +6218,7 @@ public final StringContext string() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(763); + setState(758); _la = _input.LA(1); if ( !(_la==PARAM || _la==STRING) ) { _errHandler.recoverInline(this); @@ -6361,7 +6302,7 @@ public final NonReservedContext nonReserved() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(765); + setState(760); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << ANALYZE) | (1L << ANALYZED) | (1L << CATALOGS) | (1L << COLUMNS) | (1L << CURRENT) | (1L << DAY) | (1L << DEBUG) | (1L << EXECUTABLE) | (1L << EXPLAIN) | (1L << FIRST) | (1L << FORMAT) | (1L << FULL) | (1L << FUNCTIONS) | (1L << GRAPHVIZ) | (1L << HOUR) | (1L << INTERVAL) | (1L << LAST) | (1L << LIMIT) | (1L << MAPPED) | (1L << MINUTE) | (1L << MONTH) | (1L << OPTIMIZED))) != 0) || ((((_la - 67)) & ~0x3f) == 0 && ((1L << (_la - 67)) & ((1L << (PARSED - 67)) | (1L << (PHYSICAL - 67)) | (1L << (PLAN - 67)) | (1L << (RLIKE - 67)) | (1L << (QUERY - 67)) | (1L << (SCHEMAS - 67)) | (1L << (SECOND - 67)) | (1L << (SHOW - 67)) | (1L << (SYS - 67)) | (1L << (TABLES - 67)) | (1L << (TEXT - 67)) | (1L << (TYPE - 67)) | (1L << (TYPES - 67)) | (1L << (VERIFY - 67)) | (1L << (YEAR - 67)))) != 0)) ) { _errHandler.recoverInline(this); @@ -6412,7 +6353,7 @@ private boolean valueExpression_sempred(ValueExpressionContext _localctx, int pr } public static final String _serializedATN = - "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3\u0081\u0302\4\2\t"+ + "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3\u0081\u02fd\4\2\t"+ "\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+ "\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+ "\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+ @@ -6424,300 +6365,298 @@ private boolean valueExpression_sempred(ValueExpressionContext _localctx, int pr "\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\7\4\u008d\n\4\f\4\16\4\u0090\13\4\3\4\5"+ "\4\u0093\n\4\3\4\3\4\3\4\3\4\3\4\5\4\u009a\n\4\3\4\3\4\3\4\3\4\3\4\5\4"+ "\u00a1\n\4\3\4\3\4\3\4\5\4\u00a6\n\4\3\4\3\4\3\4\5\4\u00ab\n\4\3\4\3\4"+ - "\3\4\3\4\3\4\3\4\3\4\3\4\5\4\u00b5\n\4\3\4\3\4\5\4\u00b9\n\4\3\4\3\4\3"+ - "\4\3\4\7\4\u00bf\n\4\f\4\16\4\u00c2\13\4\5\4\u00c4\n\4\3\4\3\4\3\4\3\4"+ - "\5\4\u00ca\n\4\3\4\3\4\3\4\5\4\u00cf\n\4\3\4\5\4\u00d2\n\4\3\4\3\4\3\4"+ - "\5\4\u00d7\n\4\3\4\5\4\u00da\n\4\3\4\3\4\3\4\5\4\u00df\n\4\3\5\3\5\3\5"+ - "\3\5\7\5\u00e5\n\5\f\5\16\5\u00e8\13\5\5\5\u00ea\n\5\3\5\3\5\3\6\3\6\3"+ - "\6\3\6\3\6\3\6\7\6\u00f4\n\6\f\6\16\6\u00f7\13\6\5\6\u00f9\n\6\3\6\5\6"+ - "\u00fc\n\6\3\7\3\7\3\7\3\7\3\7\5\7\u0103\n\7\3\b\3\b\3\b\3\b\3\b\5\b\u010a"+ - "\n\b\3\t\3\t\5\t\u010e\n\t\3\t\3\t\5\t\u0112\n\t\3\n\3\n\5\n\u0116\n\n"+ - "\3\n\3\n\3\n\7\n\u011b\n\n\f\n\16\n\u011e\13\n\3\n\5\n\u0121\n\n\3\n\3"+ - "\n\5\n\u0125\n\n\3\n\3\n\3\n\5\n\u012a\n\n\3\n\3\n\5\n\u012e\n\n\3\13"+ - "\3\13\3\13\3\13\7\13\u0134\n\13\f\13\16\13\u0137\13\13\3\f\5\f\u013a\n"+ - "\f\3\f\3\f\3\f\7\f\u013f\n\f\f\f\16\f\u0142\13\f\3\r\3\r\3\16\3\16\3\16"+ - "\3\16\7\16\u014a\n\16\f\16\16\16\u014d\13\16\5\16\u014f\n\16\3\16\3\16"+ - "\5\16\u0153\n\16\3\17\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\21\3\21\5\21"+ - "\u015f\n\21\3\21\5\21\u0162\n\21\3\22\3\22\7\22\u0166\n\22\f\22\16\22"+ - "\u0169\13\22\3\23\3\23\3\23\3\23\5\23\u016f\n\23\3\23\3\23\3\23\3\23\3"+ - "\23\5\23\u0176\n\23\3\24\5\24\u0179\n\24\3\24\3\24\5\24\u017d\n\24\3\24"+ - "\3\24\5\24\u0181\n\24\3\24\3\24\5\24\u0185\n\24\5\24\u0187\n\24\3\25\3"+ - "\25\3\25\3\25\3\25\3\25\3\25\7\25\u0190\n\25\f\25\16\25\u0193\13\25\3"+ - "\25\3\25\5\25\u0197\n\25\3\26\3\26\5\26\u019b\n\26\3\26\5\26\u019e\n\26"+ - "\3\26\3\26\3\26\3\26\5\26\u01a4\n\26\3\26\5\26\u01a7\n\26\3\26\3\26\3"+ - "\26\3\26\5\26\u01ad\n\26\3\26\5\26\u01b0\n\26\5\26\u01b2\n\26\3\27\3\27"+ - "\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30"+ + "\3\4\3\4\3\4\3\4\5\4\u00b3\n\4\3\4\3\4\5\4\u00b7\n\4\3\4\3\4\3\4\3\4\7"+ + "\4\u00bd\n\4\f\4\16\4\u00c0\13\4\5\4\u00c2\n\4\3\4\3\4\3\4\3\4\5\4\u00c8"+ + "\n\4\3\4\3\4\3\4\5\4\u00cd\n\4\3\4\5\4\u00d0\n\4\3\4\3\4\3\4\5\4\u00d5"+ + "\n\4\3\4\5\4\u00d8\n\4\5\4\u00da\n\4\3\5\3\5\3\5\3\5\7\5\u00e0\n\5\f\5"+ + "\16\5\u00e3\13\5\5\5\u00e5\n\5\3\5\3\5\3\6\3\6\3\6\3\6\3\6\3\6\7\6\u00ef"+ + "\n\6\f\6\16\6\u00f2\13\6\5\6\u00f4\n\6\3\6\5\6\u00f7\n\6\3\7\3\7\3\7\3"+ + "\7\3\7\5\7\u00fe\n\7\3\b\3\b\3\b\3\b\3\b\5\b\u0105\n\b\3\t\3\t\5\t\u0109"+ + "\n\t\3\t\3\t\5\t\u010d\n\t\3\n\3\n\5\n\u0111\n\n\3\n\3\n\3\n\7\n\u0116"+ + "\n\n\f\n\16\n\u0119\13\n\3\n\5\n\u011c\n\n\3\n\3\n\5\n\u0120\n\n\3\n\3"+ + "\n\3\n\5\n\u0125\n\n\3\n\3\n\5\n\u0129\n\n\3\13\3\13\3\13\3\13\7\13\u012f"+ + "\n\13\f\13\16\13\u0132\13\13\3\f\5\f\u0135\n\f\3\f\3\f\3\f\7\f\u013a\n"+ + "\f\f\f\16\f\u013d\13\f\3\r\3\r\3\16\3\16\3\16\3\16\7\16\u0145\n\16\f\16"+ + "\16\16\u0148\13\16\5\16\u014a\n\16\3\16\3\16\5\16\u014e\n\16\3\17\3\17"+ + "\3\17\3\17\3\17\3\17\3\20\3\20\3\21\3\21\5\21\u015a\n\21\3\21\5\21\u015d"+ + "\n\21\3\22\3\22\7\22\u0161\n\22\f\22\16\22\u0164\13\22\3\23\3\23\3\23"+ + "\3\23\5\23\u016a\n\23\3\23\3\23\3\23\3\23\3\23\5\23\u0171\n\23\3\24\5"+ + "\24\u0174\n\24\3\24\3\24\5\24\u0178\n\24\3\24\3\24\5\24\u017c\n\24\3\24"+ + "\3\24\5\24\u0180\n\24\5\24\u0182\n\24\3\25\3\25\3\25\3\25\3\25\3\25\3"+ + "\25\7\25\u018b\n\25\f\25\16\25\u018e\13\25\3\25\3\25\5\25\u0192\n\25\3"+ + "\26\3\26\5\26\u0196\n\26\3\26\5\26\u0199\n\26\3\26\3\26\3\26\3\26\5\26"+ + "\u019f\n\26\3\26\5\26\u01a2\n\26\3\26\3\26\3\26\3\26\5\26\u01a8\n\26\3"+ + "\26\5\26\u01ab\n\26\5\26\u01ad\n\26\3\27\3\27\3\30\3\30\3\30\3\30\3\30"+ "\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30"+ - "\3\30\3\30\3\30\5\30\u01d5\n\30\3\30\3\30\3\30\3\30\3\30\3\30\7\30\u01dd"+ - "\n\30\f\30\16\30\u01e0\13\30\3\31\3\31\7\31\u01e4\n\31\f\31\16\31\u01e7"+ - "\13\31\3\32\3\32\5\32\u01eb\n\32\3\33\5\33\u01ee\n\33\3\33\3\33\3\33\3"+ - "\33\3\33\3\33\5\33\u01f6\n\33\3\33\3\33\3\33\3\33\3\33\7\33\u01fd\n\33"+ - "\f\33\16\33\u0200\13\33\3\33\3\33\3\33\5\33\u0205\n\33\3\33\3\33\3\33"+ - "\3\33\3\33\3\33\5\33\u020d\n\33\3\33\3\33\3\33\5\33\u0212\n\33\3\33\3"+ - "\33\3\33\3\33\5\33\u0218\n\33\3\33\5\33\u021b\n\33\3\34\3\34\3\34\3\35"+ - "\3\35\5\35\u0222\n\35\3\36\3\36\3\36\3\36\3\36\3\36\5\36\u022a\n\36\3"+ - "\37\3\37\3\37\3\37\5\37\u0230\n\37\3\37\3\37\3\37\3\37\3\37\3\37\3\37"+ - "\3\37\3\37\3\37\7\37\u023c\n\37\f\37\16\37\u023f\13\37\3 \3 \3 \3 \3 "+ - "\3 \3 \5 \u0248\n \3 \3 \3 \3 \3 \3 \3 \3 \3 \3 \3 \5 \u0255\n \3!\3!"+ - "\3!\3!\3!\3!\3!\3!\3!\3!\5!\u0261\n!\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3#\3"+ - "#\3#\5#\u026d\n#\3#\5#\u0270\n#\3$\3$\3$\3$\3$\3$\3$\3%\3%\3%\3%\3%\5"+ - "%\u027e\n%\3&\3&\3&\3&\3&\3&\3&\3\'\3\'\3\'\3\'\3\'\5\'\u028c\n\'\3(\3"+ - "(\3(\5(\u0291\n(\3(\3(\3(\7(\u0296\n(\f(\16(\u0299\13(\5(\u029b\n(\3("+ - "\3(\3)\3)\3)\5)\u02a2\n)\3*\3*\3*\3*\3*\6*\u02a9\n*\r*\16*\u02aa\3*\3"+ - "*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3*\5*\u02be\n*\3+\3+\3,\3"+ - ",\3-\3-\5-\u02c6\n-\3-\3-\5-\u02ca\n-\3-\3-\3-\5-\u02cf\n-\3.\3.\3/\3"+ - "/\3\60\3\60\3\60\7\60\u02d8\n\60\f\60\16\60\u02db\13\60\3\60\3\60\3\61"+ - "\3\61\5\61\u02e1\n\61\3\62\3\62\3\62\5\62\u02e6\n\62\3\62\3\62\3\62\3"+ - "\62\5\62\u02ec\n\62\3\62\5\62\u02ef\n\62\3\63\3\63\5\63\u02f3\n\63\3\64"+ - "\3\64\3\64\5\64\u02f8\n\64\3\65\3\65\5\65\u02fc\n\65\3\66\3\66\3\67\3"+ - "\67\3\67\2\4.<8\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&(*,.\60\62"+ - "\64\668:<>@BDFHJLNPRTVXZ\\^`bdfhjl\2\22\b\2\7\7\t\t\36\36\66\66AAEE\4"+ - "\2((SS\4\2\t\tAA\4\2%%--\3\2\32\33\3\2mn\4\2\7\7vv\4\2\r\r\32\32\4\2#"+ - "#\62\62\4\2\7\7\34\34\3\2oq\3\2fl\4\2\"\"TT\7\2\27\30+,8;LM\\]\3\2tu\31"+ - "\2\b\t\22\23\25\25\27\27\31\31\36\36 #$&(++//\62\62\65\6688::AAEGILO"+ - "PRSVWYY\\\\\u035f\2n\3\2\2\2\4q\3\2\2\2\6\u00de\3\2\2\2\b\u00e9\3\2\2"+ - "\2\n\u00ed\3\2\2\2\f\u0102\3\2\2\2\16\u0109\3\2\2\2\20\u010b\3\2\2\2\22"+ - "\u0113\3\2\2\2\24\u012f\3\2\2\2\26\u0139\3\2\2\2\30\u0143\3\2\2\2\32\u0152"+ - "\3\2\2\2\34\u0154\3\2\2\2\36\u015a\3\2\2\2 \u015c\3\2\2\2\"\u0163\3\2"+ - "\2\2$\u0175\3\2\2\2&\u0186\3\2\2\2(\u0196\3\2\2\2*\u01b1\3\2\2\2,\u01b3"+ - "\3\2\2\2.\u01d4\3\2\2\2\60\u01e5\3\2\2\2\62\u01e8\3\2\2\2\64\u021a\3\2"+ - "\2\2\66\u021c\3\2\2\28\u021f\3\2\2\2:\u0229\3\2\2\2<\u022f\3\2\2\2>\u0254"+ - "\3\2\2\2@\u0260\3\2\2\2B\u0262\3\2\2\2D\u0269\3\2\2\2F\u0271\3\2\2\2H"+ - "\u027d\3\2\2\2J\u027f\3\2\2\2L\u028b\3\2\2\2N\u028d\3\2\2\2P\u02a1\3\2"+ - "\2\2R\u02bd\3\2\2\2T\u02bf\3\2\2\2V\u02c1\3\2\2\2X\u02c3\3\2\2\2Z\u02d0"+ - "\3\2\2\2\\\u02d2\3\2\2\2^\u02d9\3\2\2\2`\u02e0\3\2\2\2b\u02ee\3\2\2\2"+ - "d\u02f2\3\2\2\2f\u02f7\3\2\2\2h\u02fb\3\2\2\2j\u02fd\3\2\2\2l\u02ff\3"+ - "\2\2\2no\5\6\4\2op\7\2\2\3p\3\3\2\2\2qr\5,\27\2rs\7\2\2\3s\5\3\2\2\2t"+ - "\u00df\5\b\5\2u\u0083\7 \2\2v\177\7\3\2\2wx\7G\2\2x~\t\2\2\2yz\7$\2\2"+ - "z~\t\3\2\2{|\7Y\2\2|~\5V,\2}w\3\2\2\2}y\3\2\2\2}{\3\2\2\2~\u0081\3\2\2"+ - "\2\177}\3\2\2\2\177\u0080\3\2\2\2\u0080\u0082\3\2\2\2\u0081\177\3\2\2"+ - "\2\u0082\u0084\7\4\2\2\u0083v\3\2\2\2\u0083\u0084\3\2\2\2\u0084\u0085"+ - "\3\2\2\2\u0085\u00df\5\6\4\2\u0086\u0092\7\31\2\2\u0087\u008e\7\3\2\2"+ - "\u0088\u0089\7G\2\2\u0089\u008d\t\4\2\2\u008a\u008b\7$\2\2\u008b\u008d"+ - "\t\3\2\2\u008c\u0088\3\2\2\2\u008c\u008a\3\2\2\2\u008d\u0090\3\2\2\2\u008e"+ - "\u008c\3\2\2\2\u008e\u008f\3\2\2\2\u008f\u0091\3\2\2\2\u0090\u008e\3\2"+ - "\2\2\u0091\u0093\7\4\2\2\u0092\u0087\3\2\2\2\u0092\u0093\3\2\2\2\u0093"+ - "\u0094\3\2\2\2\u0094\u00df\5\6\4\2\u0095\u0096\7O\2\2\u0096\u0099\7R\2"+ - "\2\u0097\u009a\5\66\34\2\u0098\u009a\5b\62\2\u0099\u0097\3\2\2\2\u0099"+ - "\u0098\3\2\2\2\u0099\u009a\3\2\2\2\u009a\u00df\3\2\2\2\u009b\u009c\7O"+ - "\2\2\u009c\u009d\7\23\2\2\u009d\u00a0\t\5\2\2\u009e\u00a1\5\66\34\2\u009f"+ - "\u00a1\5b\62\2\u00a0\u009e\3\2\2\2\u00a0\u009f\3\2\2\2\u00a1\u00df\3\2"+ - "\2\2\u00a2\u00a5\t\6\2\2\u00a3\u00a6\5\66\34\2\u00a4\u00a6\5b\62\2\u00a5"+ - "\u00a3\3\2\2\2\u00a5\u00a4\3\2\2\2\u00a6\u00df\3\2\2\2\u00a7\u00a8\7O"+ - "\2\2\u00a8\u00aa\7\'\2\2\u00a9\u00ab\5\66\34\2\u00aa\u00a9\3\2\2\2\u00aa"+ - "\u00ab\3\2\2\2\u00ab\u00df\3\2\2\2\u00ac\u00ad\7O\2\2\u00ad\u00df\7K\2"+ - "\2\u00ae\u00af\7P\2\2\u00af\u00df\7\22\2\2\u00b0\u00b1\7P\2\2\u00b1\u00b4"+ - "\7R\2\2\u00b2\u00b3\7\21\2\2\u00b3\u00b5\5\66\34\2\u00b4\u00b2\3\2\2\2"+ - "\u00b4\u00b5\3\2\2\2\u00b5\u00b8\3\2\2\2\u00b6\u00b9\5\66\34\2\u00b7\u00b9"+ - "\5b\62\2\u00b8\u00b6\3\2\2\2\u00b8\u00b7\3\2\2\2\u00b8\u00b9\3\2\2\2\u00b9"+ - "\u00c3\3\2\2\2\u00ba\u00bb\7V\2\2\u00bb\u00c0\5j\66\2\u00bc\u00bd\7\5"+ - "\2\2\u00bd\u00bf\5j\66\2\u00be\u00bc\3\2\2\2\u00bf\u00c2\3\2\2\2\u00c0"+ - "\u00be\3\2\2\2\u00c0\u00c1\3\2\2\2\u00c1\u00c4\3\2\2\2\u00c2\u00c0\3\2"+ - "\2\2\u00c3\u00ba\3\2\2\2\u00c3\u00c4\3\2\2\2\u00c4\u00df\3\2\2\2\u00c5"+ - "\u00c6\7P\2\2\u00c6\u00c9\7\23\2\2\u00c7\u00c8\7\21\2\2\u00c8\u00ca\5"+ - "j\66\2\u00c9\u00c7\3\2\2\2\u00c9\u00ca\3\2\2\2\u00ca\u00ce\3\2\2\2\u00cb"+ - "\u00cc\7Q\2\2\u00cc\u00cf\5\66\34\2\u00cd\u00cf\5b\62\2\u00ce\u00cb\3"+ - "\2\2\2\u00ce\u00cd\3\2\2\2\u00ce\u00cf\3\2\2\2\u00cf\u00d1\3\2\2\2\u00d0"+ - "\u00d2\5\66\34\2\u00d1\u00d0\3\2\2\2\u00d1\u00d2\3\2\2\2\u00d2\u00df\3"+ - "\2\2\2\u00d3\u00d4\7P\2\2\u00d4\u00d9\7W\2\2\u00d5\u00d7\t\7\2\2\u00d6"+ - "\u00d5\3\2\2\2\u00d6\u00d7\3\2\2\2\u00d7\u00d8\3\2\2\2\u00d8\u00da\5h"+ - "\65\2\u00d9\u00d6\3\2\2\2\u00d9\u00da\3\2\2\2\u00da\u00df\3\2\2\2\u00db"+ - "\u00dc\7P\2\2\u00dc\u00dd\7Q\2\2\u00dd\u00df\7W\2\2\u00det\3\2\2\2\u00de"+ - "u\3\2\2\2\u00de\u0086\3\2\2\2\u00de\u0095\3\2\2\2\u00de\u009b\3\2\2\2"+ - "\u00de\u00a2\3\2\2\2\u00de\u00a7\3\2\2\2\u00de\u00ac\3\2\2\2\u00de\u00ae"+ - "\3\2\2\2\u00de\u00b0\3\2\2\2\u00de\u00c5\3\2\2\2\u00de\u00d3\3\2\2\2\u00de"+ - "\u00db\3\2\2\2\u00df\7\3\2\2\2\u00e0\u00e1\7[\2\2\u00e1\u00e6\5\34\17"+ - "\2\u00e2\u00e3\7\5\2\2\u00e3\u00e5\5\34\17\2\u00e4\u00e2\3\2\2\2\u00e5"+ - "\u00e8\3\2\2\2\u00e6\u00e4\3\2\2\2\u00e6\u00e7\3\2\2\2\u00e7\u00ea\3\2"+ - "\2\2\u00e8\u00e6\3\2\2\2\u00e9\u00e0\3\2\2\2\u00e9\u00ea\3\2\2\2\u00ea"+ - "\u00eb\3\2\2\2\u00eb\u00ec\5\n\6\2\u00ec\t\3\2\2\2\u00ed\u00f8\5\16\b"+ - "\2\u00ee\u00ef\7C\2\2\u00ef\u00f0\7\17\2\2\u00f0\u00f5\5\20\t\2\u00f1"+ - "\u00f2\7\5\2\2\u00f2\u00f4\5\20\t\2\u00f3\u00f1\3\2\2\2\u00f4\u00f7\3"+ - "\2\2\2\u00f5\u00f3\3\2\2\2\u00f5\u00f6\3\2\2\2\u00f6\u00f9\3\2\2\2\u00f7"+ - "\u00f5\3\2\2\2\u00f8\u00ee\3\2\2\2\u00f8\u00f9\3\2\2\2\u00f9\u00fb\3\2"+ - "\2\2\u00fa\u00fc\5\f\7\2\u00fb\u00fa\3\2\2\2\u00fb\u00fc\3\2\2\2\u00fc"+ - "\13\3\2\2\2\u00fd\u00fe\7\65\2\2\u00fe\u0103\t\b\2\2\u00ff\u0100\7`\2"+ - "\2\u0100\u0101\t\b\2\2\u0101\u0103\7e\2\2\u0102\u00fd\3\2\2\2\u0102\u00ff"+ - "\3\2\2\2\u0103\r\3\2\2\2\u0104\u010a\5\22\n\2\u0105\u0106\7\3\2\2\u0106"+ - "\u0107\5\n\6\2\u0107\u0108\7\4\2\2\u0108\u010a\3\2\2\2\u0109\u0104\3\2"+ - "\2\2\u0109\u0105\3\2\2\2\u010a\17\3\2\2\2\u010b\u010d\5,\27\2\u010c\u010e"+ - "\t\t\2\2\u010d\u010c\3\2\2\2\u010d\u010e\3\2\2\2\u010e\u0111\3\2\2\2\u010f"+ - "\u0110\7?\2\2\u0110\u0112\t\n\2\2\u0111\u010f\3\2\2\2\u0111\u0112\3\2"+ - "\2\2\u0112\21\3\2\2\2\u0113\u0115\7N\2\2\u0114\u0116\5\36\20\2\u0115\u0114"+ - "\3\2\2\2\u0115\u0116\3\2\2\2\u0116\u0117\3\2\2\2\u0117\u011c\5 \21\2\u0118"+ - "\u0119\7\5\2\2\u0119\u011b\5 \21\2\u011a\u0118\3\2\2\2\u011b\u011e\3\2"+ - "\2\2\u011c\u011a\3\2\2\2\u011c\u011d\3\2\2\2\u011d\u0120\3\2\2\2\u011e"+ - "\u011c\3\2\2\2\u011f\u0121\5\24\13\2\u0120\u011f\3\2\2\2\u0120\u0121\3"+ - "\2\2\2\u0121\u0124\3\2\2\2\u0122\u0123\7Z\2\2\u0123\u0125\5.\30\2\u0124"+ - "\u0122\3\2\2\2\u0124\u0125\3\2\2\2\u0125\u0129\3\2\2\2\u0126\u0127\7)"+ - "\2\2\u0127\u0128\7\17\2\2\u0128\u012a\5\26\f\2\u0129\u0126\3\2\2\2\u0129"+ - "\u012a\3\2\2\2\u012a\u012d\3\2\2\2\u012b\u012c\7*\2\2\u012c\u012e\5.\30"+ - "\2\u012d\u012b\3\2\2\2\u012d\u012e\3\2\2\2\u012e\23\3\2\2\2\u012f\u0130"+ - "\7%\2\2\u0130\u0135\5\"\22\2\u0131\u0132\7\5\2\2\u0132\u0134\5\"\22\2"+ - "\u0133\u0131\3\2\2\2\u0134\u0137\3\2\2\2\u0135\u0133\3\2\2\2\u0135\u0136"+ - "\3\2\2\2\u0136\25\3\2\2\2\u0137\u0135\3\2\2\2\u0138\u013a\5\36\20\2\u0139"+ - "\u0138\3\2\2\2\u0139\u013a\3\2\2\2\u013a\u013b\3\2\2\2\u013b\u0140\5\30"+ - "\r\2\u013c\u013d\7\5\2\2\u013d\u013f\5\30\r\2\u013e\u013c\3\2\2\2\u013f"+ - "\u0142\3\2\2\2\u0140\u013e\3\2\2\2\u0140\u0141\3\2\2\2\u0141\27\3\2\2"+ - "\2\u0142\u0140\3\2\2\2\u0143\u0144\5\32\16\2\u0144\31\3\2\2\2\u0145\u014e"+ - "\7\3\2\2\u0146\u014b\5,\27\2\u0147\u0148\7\5\2\2\u0148\u014a\5,\27\2\u0149"+ - "\u0147\3\2\2\2\u014a\u014d\3\2\2\2\u014b\u0149\3\2\2\2\u014b\u014c\3\2"+ - "\2\2\u014c\u014f\3\2\2\2\u014d\u014b\3\2\2\2\u014e\u0146\3\2\2\2\u014e"+ - "\u014f\3\2\2\2\u014f\u0150\3\2\2\2\u0150\u0153\7\4\2\2\u0151\u0153\5,"+ - "\27\2\u0152\u0145\3\2\2\2\u0152\u0151\3\2\2\2\u0153\33\3\2\2\2\u0154\u0155"+ - "\5`\61\2\u0155\u0156\7\f\2\2\u0156\u0157\7\3\2\2\u0157\u0158\5\n\6\2\u0158"+ - "\u0159\7\4\2\2\u0159\35\3\2\2\2\u015a\u015b\t\13\2\2\u015b\37\3\2\2\2"+ - "\u015c\u0161\5,\27\2\u015d\u015f\7\f\2\2\u015e\u015d\3\2\2\2\u015e\u015f"+ - "\3\2\2\2\u015f\u0160\3\2\2\2\u0160\u0162\5`\61\2\u0161\u015e\3\2\2\2\u0161"+ - "\u0162\3\2\2\2\u0162!\3\2\2\2\u0163\u0167\5*\26\2\u0164\u0166\5$\23\2"+ - "\u0165\u0164\3\2\2\2\u0166\u0169\3\2\2\2\u0167\u0165\3\2\2\2\u0167\u0168"+ - "\3\2\2\2\u0168#\3\2\2\2\u0169\u0167\3\2\2\2\u016a\u016b\5&\24\2\u016b"+ - "\u016c\7\61\2\2\u016c\u016e\5*\26\2\u016d\u016f\5(\25\2\u016e\u016d\3"+ - "\2\2\2\u016e\u016f\3\2\2\2\u016f\u0176\3\2\2\2\u0170\u0171\7<\2\2\u0171"+ - "\u0172\5&\24\2\u0172\u0173\7\61\2\2\u0173\u0174\5*\26\2\u0174\u0176\3"+ - "\2\2\2\u0175\u016a\3\2\2\2\u0175\u0170\3\2\2\2\u0176%\3\2\2\2\u0177\u0179"+ - "\7.\2\2\u0178\u0177\3\2\2\2\u0178\u0179\3\2\2\2\u0179\u0187\3\2\2\2\u017a"+ - "\u017c\7\63\2\2\u017b\u017d\7D\2\2\u017c\u017b\3\2\2\2\u017c\u017d\3\2"+ - "\2\2\u017d\u0187\3\2\2\2\u017e\u0180\7H\2\2\u017f\u0181\7D\2\2\u0180\u017f"+ - "\3\2\2\2\u0180\u0181\3\2\2\2\u0181\u0187\3\2\2\2\u0182\u0184\7&\2\2\u0183"+ - "\u0185\7D\2\2\u0184\u0183\3\2\2\2\u0184\u0185\3\2\2\2\u0185\u0187\3\2"+ - "\2\2\u0186\u0178\3\2\2\2\u0186\u017a\3\2\2\2\u0186\u017e\3\2\2\2\u0186"+ - "\u0182\3\2\2\2\u0187\'\3\2\2\2\u0188\u0189\7@\2\2\u0189\u0197\5.\30\2"+ - "\u018a\u018b\7X\2\2\u018b\u018c\7\3\2\2\u018c\u0191\5`\61\2\u018d\u018e"+ - "\7\5\2\2\u018e\u0190\5`\61\2\u018f\u018d\3\2\2\2\u0190\u0193\3\2\2\2\u0191"+ - "\u018f\3\2\2\2\u0191\u0192\3\2\2\2\u0192\u0194\3\2\2\2\u0193\u0191\3\2"+ - "\2\2\u0194\u0195\7\4\2\2\u0195\u0197\3\2\2\2\u0196\u0188\3\2\2\2\u0196"+ - "\u018a\3\2\2\2\u0197)\3\2\2\2\u0198\u019d\5b\62\2\u0199\u019b\7\f\2\2"+ - "\u019a\u0199\3\2\2\2\u019a\u019b\3\2\2\2\u019b\u019c\3\2\2\2\u019c\u019e"+ - "\5^\60\2\u019d\u019a\3\2\2\2\u019d\u019e\3\2\2\2\u019e\u01b2\3\2\2\2\u019f"+ - "\u01a0\7\3\2\2\u01a0\u01a1\5\n\6\2\u01a1\u01a6\7\4\2\2\u01a2\u01a4\7\f"+ - "\2\2\u01a3\u01a2\3\2\2\2\u01a3\u01a4\3\2\2\2\u01a4\u01a5\3\2\2\2\u01a5"+ - "\u01a7\5^\60\2\u01a6\u01a3\3\2\2\2\u01a6\u01a7\3\2\2\2\u01a7\u01b2\3\2"+ - "\2\2\u01a8\u01a9\7\3\2\2\u01a9\u01aa\5\"\22\2\u01aa\u01af\7\4\2\2\u01ab"+ - "\u01ad\7\f\2\2\u01ac\u01ab\3\2\2\2\u01ac\u01ad\3\2\2\2\u01ad\u01ae\3\2"+ - "\2\2\u01ae\u01b0\5^\60\2\u01af\u01ac\3\2\2\2\u01af\u01b0\3\2\2\2\u01b0"+ - "\u01b2\3\2\2\2\u01b1\u0198\3\2\2\2\u01b1\u019f\3\2\2\2\u01b1\u01a8\3\2"+ - "\2\2\u01b2+\3\2\2\2\u01b3\u01b4\5.\30\2\u01b4-\3\2\2\2\u01b5\u01b6\b\30"+ - "\1\2\u01b6\u01b7\7=\2\2\u01b7\u01d5\5.\30\n\u01b8\u01b9\7\37\2\2\u01b9"+ - "\u01ba\7\3\2\2\u01ba\u01bb\5\b\5\2\u01bb\u01bc\7\4\2\2\u01bc\u01d5\3\2"+ - "\2\2\u01bd\u01be\7J\2\2\u01be\u01bf\7\3\2\2\u01bf\u01c0\5j\66\2\u01c0"+ - "\u01c1\5\60\31\2\u01c1\u01c2\7\4\2\2\u01c2\u01d5\3\2\2\2\u01c3\u01c4\7"+ - "\67\2\2\u01c4\u01c5\7\3\2\2\u01c5\u01c6\5^\60\2\u01c6\u01c7\7\5\2\2\u01c7"+ - "\u01c8\5j\66\2\u01c8\u01c9\5\60\31\2\u01c9\u01ca\7\4\2\2\u01ca\u01d5\3"+ - "\2\2\2\u01cb\u01cc\7\67\2\2\u01cc\u01cd\7\3\2\2\u01cd\u01ce\5j\66\2\u01ce"+ - "\u01cf\7\5\2\2\u01cf\u01d0\5j\66\2\u01d0\u01d1\5\60\31\2\u01d1\u01d2\7"+ - "\4\2\2\u01d2\u01d5\3\2\2\2\u01d3\u01d5\5\62\32\2\u01d4\u01b5\3\2\2\2\u01d4"+ - "\u01b8\3\2\2\2\u01d4\u01bd\3\2\2\2\u01d4\u01c3\3\2\2\2\u01d4\u01cb\3\2"+ - "\2\2\u01d4\u01d3\3\2\2\2\u01d5\u01de\3\2\2\2\u01d6\u01d7\f\4\2\2\u01d7"+ - "\u01d8\7\n\2\2\u01d8\u01dd\5.\30\5\u01d9\u01da\f\3\2\2\u01da\u01db\7B"+ - "\2\2\u01db\u01dd\5.\30\4\u01dc\u01d6\3\2\2\2\u01dc\u01d9\3\2\2\2\u01dd"+ - "\u01e0\3\2\2\2\u01de\u01dc\3\2\2\2\u01de\u01df\3\2\2\2\u01df/\3\2\2\2"+ - "\u01e0\u01de\3\2\2\2\u01e1\u01e2\7\5\2\2\u01e2\u01e4\5j\66\2\u01e3\u01e1"+ - "\3\2\2\2\u01e4\u01e7\3\2\2\2\u01e5\u01e3\3\2\2\2\u01e5\u01e6\3\2\2\2\u01e6"+ - "\61\3\2\2\2\u01e7\u01e5\3\2\2\2\u01e8\u01ea\5<\37\2\u01e9\u01eb\5\64\33"+ - "\2\u01ea\u01e9\3\2\2\2\u01ea\u01eb\3\2\2\2\u01eb\63\3\2\2\2\u01ec\u01ee"+ - "\7=\2\2\u01ed\u01ec\3\2\2\2\u01ed\u01ee\3\2\2\2\u01ee\u01ef\3\2\2\2\u01ef"+ - "\u01f0\7\16\2\2\u01f0\u01f1\5<\37\2\u01f1\u01f2\7\n\2\2\u01f2\u01f3\5"+ - "<\37\2\u01f3\u021b\3\2\2\2\u01f4\u01f6\7=\2\2\u01f5\u01f4\3\2\2\2\u01f5"+ - "\u01f6\3\2\2\2\u01f6\u01f7\3\2\2\2\u01f7\u01f8\7-\2\2\u01f8\u01f9\7\3"+ - "\2\2\u01f9\u01fe\5<\37\2\u01fa\u01fb\7\5\2\2\u01fb\u01fd\5<\37\2\u01fc"+ - "\u01fa\3\2\2\2\u01fd\u0200\3\2\2\2\u01fe\u01fc\3\2\2\2\u01fe\u01ff\3\2"+ - "\2\2\u01ff\u0201\3\2\2\2\u0200\u01fe\3\2\2\2\u0201\u0202\7\4\2\2\u0202"+ - "\u021b\3\2\2\2\u0203\u0205\7=\2\2\u0204\u0203\3\2\2\2\u0204\u0205\3\2"+ - "\2\2\u0205\u0206\3\2\2\2\u0206\u0207\7-\2\2\u0207\u0208\7\3\2\2\u0208"+ - "\u0209\5\b\5\2\u0209\u020a\7\4\2\2\u020a\u021b\3\2\2\2\u020b\u020d\7="+ - "\2\2\u020c\u020b\3\2\2\2\u020c\u020d\3\2\2\2\u020d\u020e\3\2\2\2\u020e"+ - "\u020f\7\64\2\2\u020f\u021b\58\35\2\u0210\u0212\7=\2\2\u0211\u0210\3\2"+ - "\2\2\u0211\u0212\3\2\2\2\u0212\u0213\3\2\2\2\u0213\u0214\7I\2\2\u0214"+ - "\u021b\5j\66\2\u0215\u0217\7\60\2\2\u0216\u0218\7=\2\2\u0217\u0216\3\2"+ - "\2\2\u0217\u0218\3\2\2\2\u0218\u0219\3\2\2\2\u0219\u021b\7>\2\2\u021a"+ - "\u01ed\3\2\2\2\u021a\u01f5\3\2\2\2\u021a\u0204\3\2\2\2\u021a\u020c\3\2"+ - "\2\2\u021a\u0211\3\2\2\2\u021a\u0215\3\2\2\2\u021b\65\3\2\2\2\u021c\u021d"+ - "\7\64\2\2\u021d\u021e\58\35\2\u021e\67\3\2\2\2\u021f\u0221\5j\66\2\u0220"+ - "\u0222\5:\36\2\u0221\u0220\3\2\2\2\u0221\u0222\3\2\2\2\u02229\3\2\2\2"+ - "\u0223\u0224\7\35\2\2\u0224\u022a\5j\66\2\u0225\u0226\7^\2\2\u0226\u0227"+ - "\5j\66\2\u0227\u0228\7e\2\2\u0228\u022a\3\2\2\2\u0229\u0223\3\2\2\2\u0229"+ - "\u0225\3\2\2\2\u022a;\3\2\2\2\u022b\u022c\b\37\1\2\u022c\u0230\5> \2\u022d"+ - "\u022e\t\7\2\2\u022e\u0230\5<\37\6\u022f\u022b\3\2\2\2\u022f\u022d\3\2"+ - "\2\2\u0230\u023d\3\2\2\2\u0231\u0232\f\5\2\2\u0232\u0233\t\f\2\2\u0233"+ - "\u023c\5<\37\6\u0234\u0235\f\4\2\2\u0235\u0236\t\7\2\2\u0236\u023c\5<"+ - "\37\5\u0237\u0238\f\3\2\2\u0238\u0239\5T+\2\u0239\u023a\5<\37\4\u023a"+ - "\u023c\3\2\2\2\u023b\u0231\3\2\2\2\u023b\u0234\3\2\2\2\u023b\u0237\3\2"+ - "\2\2\u023c\u023f\3\2\2\2\u023d\u023b\3\2\2\2\u023d\u023e\3\2\2\2\u023e"+ - "=\3\2\2\2\u023f\u023d\3\2\2\2\u0240\u0255\5@!\2\u0241\u0255\5H%\2\u0242"+ - "\u0255\5D#\2\u0243\u0255\5R*\2\u0244\u0245\5^\60\2\u0245\u0246\7s\2\2"+ - "\u0246\u0248\3\2\2\2\u0247\u0244\3\2\2\2\u0247\u0248\3\2\2\2\u0248\u0249"+ - "\3\2\2\2\u0249\u0255\7o\2\2\u024a\u0255\5L\'\2\u024b\u024c\7\3\2\2\u024c"+ - "\u024d\5\b\5\2\u024d\u024e\7\4\2\2\u024e\u0255\3\2\2\2\u024f\u0255\5^"+ - "\60\2\u0250\u0251\7\3\2\2\u0251\u0252\5,\27\2\u0252\u0253\7\4\2\2\u0253"+ - "\u0255\3\2\2\2\u0254\u0240\3\2\2\2\u0254\u0241\3\2\2\2\u0254\u0242\3\2"+ - "\2\2\u0254\u0243\3\2\2\2\u0254\u0247\3\2\2\2\u0254\u024a\3\2\2\2\u0254"+ - "\u024b\3\2\2\2\u0254\u024f\3\2\2\2\u0254\u0250\3\2\2\2\u0255?\3\2\2\2"+ - "\u0256\u0261\5B\"\2\u0257\u0258\7_\2\2\u0258\u0259\5B\"\2\u0259\u025a"+ - "\7e\2\2\u025a\u0261\3\2\2\2\u025b\u0261\5F$\2\u025c\u025d\7_\2\2\u025d"+ - "\u025e\5F$\2\u025e\u025f\7e\2\2\u025f\u0261\3\2\2\2\u0260\u0256\3\2\2"+ - "\2\u0260\u0257\3\2\2\2\u0260\u025b\3\2\2\2\u0260\u025c\3\2\2\2\u0261A"+ - "\3\2\2\2\u0262\u0263\7\20\2\2\u0263\u0264\7\3\2\2\u0264\u0265\5,\27\2"+ - "\u0265\u0266\7\f\2\2\u0266\u0267\5\\/\2\u0267\u0268\7\4\2\2\u0268C\3\2"+ - "\2\2\u0269\u026f\7\26\2\2\u026a\u026c\7\3\2\2\u026b\u026d\7v\2\2\u026c"+ - "\u026b\3\2\2\2\u026c\u026d\3\2\2\2\u026d\u026e\3\2\2\2\u026e\u0270\7\4"+ - "\2\2\u026f\u026a\3\2\2\2\u026f\u0270\3\2\2\2\u0270E\3\2\2\2\u0271\u0272"+ - "\7\24\2\2\u0272\u0273\7\3\2\2\u0273\u0274\5,\27\2\u0274\u0275\7\5\2\2"+ - "\u0275\u0276\5\\/\2\u0276\u0277\7\4\2\2\u0277G\3\2\2\2\u0278\u027e\5J"+ - "&\2\u0279\u027a\7_\2\2\u027a\u027b\5J&\2\u027b\u027c\7e\2\2\u027c\u027e"+ - "\3\2\2\2\u027d\u0278\3\2\2\2\u027d\u0279\3\2\2\2\u027eI\3\2\2\2\u027f"+ - "\u0280\7!\2\2\u0280\u0281\7\3\2\2\u0281\u0282\5`\61\2\u0282\u0283\7%\2"+ - "\2\u0283\u0284\5<\37\2\u0284\u0285\7\4\2\2\u0285K\3\2\2\2\u0286\u028c"+ - "\5N(\2\u0287\u0288\7_\2\2\u0288\u0289\5N(\2\u0289\u028a\7e\2\2\u028a\u028c"+ - "\3\2\2\2\u028b\u0286\3\2\2\2\u028b\u0287\3\2\2\2\u028cM\3\2\2\2\u028d"+ - "\u028e\5P)\2\u028e\u029a\7\3\2\2\u028f\u0291\5\36\20\2\u0290\u028f\3\2"+ - "\2\2\u0290\u0291\3\2\2\2\u0291\u0292\3\2\2\2\u0292\u0297\5,\27\2\u0293"+ - "\u0294\7\5\2\2\u0294\u0296\5,\27\2\u0295\u0293\3\2\2\2\u0296\u0299\3\2"+ - "\2\2\u0297\u0295\3\2\2\2\u0297\u0298\3\2\2\2\u0298\u029b\3\2\2\2\u0299"+ - "\u0297\3\2\2\2\u029a\u0290\3\2\2\2\u029a\u029b\3\2\2\2\u029b\u029c\3\2"+ - "\2\2\u029c\u029d\7\4\2\2\u029dO\3\2\2\2\u029e\u02a2\7\63\2\2\u029f\u02a2"+ - "\7H\2\2\u02a0\u02a2\5`\61\2\u02a1\u029e\3\2\2\2\u02a1\u029f\3\2\2\2\u02a1"+ - "\u02a0\3\2\2\2\u02a2Q\3\2\2\2\u02a3\u02be\7>\2\2\u02a4\u02be\5X-\2\u02a5"+ - "\u02be\5h\65\2\u02a6\u02be\5V,\2\u02a7\u02a9\7u\2\2\u02a8\u02a7\3\2\2"+ - "\2\u02a9\u02aa\3\2\2\2\u02aa\u02a8\3\2\2\2\u02aa\u02ab\3\2\2\2\u02ab\u02be"+ - "\3\2\2\2\u02ac\u02be\7t\2\2\u02ad\u02ae\7a\2\2\u02ae\u02af\5j\66\2\u02af"+ - "\u02b0\7e\2\2\u02b0\u02be\3\2\2\2\u02b1\u02b2\7b\2\2\u02b2\u02b3\5j\66"+ - "\2\u02b3\u02b4\7e\2\2\u02b4\u02be\3\2\2\2\u02b5\u02b6\7c\2\2\u02b6\u02b7"+ - "\5j\66\2\u02b7\u02b8\7e\2\2\u02b8\u02be\3\2\2\2\u02b9\u02ba\7d\2\2\u02ba"+ - "\u02bb\5j\66\2\u02bb\u02bc\7e\2\2\u02bc\u02be\3\2\2\2\u02bd\u02a3\3\2"+ - "\2\2\u02bd\u02a4\3\2\2\2\u02bd\u02a5\3\2\2\2\u02bd\u02a6\3\2\2\2\u02bd"+ - "\u02a8\3\2\2\2\u02bd\u02ac\3\2\2\2\u02bd\u02ad\3\2\2\2\u02bd\u02b1\3\2"+ - "\2\2\u02bd\u02b5\3\2\2\2\u02bd\u02b9\3\2\2\2\u02beS\3\2\2\2\u02bf\u02c0"+ - "\t\r\2\2\u02c0U\3\2\2\2\u02c1\u02c2\t\16\2\2\u02c2W\3\2\2\2\u02c3\u02c5"+ - "\7/\2\2\u02c4\u02c6\t\7\2\2\u02c5\u02c4\3\2\2\2\u02c5\u02c6\3\2\2\2\u02c6"+ - "\u02c9\3\2\2\2\u02c7\u02ca\5h\65\2\u02c8\u02ca\5j\66\2\u02c9\u02c7\3\2"+ - "\2\2\u02c9\u02c8\3\2\2\2\u02ca\u02cb\3\2\2\2\u02cb\u02ce\5Z.\2\u02cc\u02cd"+ - "\7U\2\2\u02cd\u02cf\5Z.\2\u02ce\u02cc\3\2\2\2\u02ce\u02cf\3\2\2\2\u02cf"+ - "Y\3\2\2\2\u02d0\u02d1\t\17\2\2\u02d1[\3\2\2\2\u02d2\u02d3\5`\61\2\u02d3"+ - "]\3\2\2\2\u02d4\u02d5\5`\61\2\u02d5\u02d6\7s\2\2\u02d6\u02d8\3\2\2\2\u02d7"+ - "\u02d4\3\2\2\2\u02d8\u02db\3\2\2\2\u02d9\u02d7\3\2\2\2\u02d9\u02da\3\2"+ - "\2\2\u02da\u02dc\3\2\2\2\u02db\u02d9\3\2\2\2\u02dc\u02dd\5`\61\2\u02dd"+ - "_\3\2\2\2\u02de\u02e1\5d\63\2\u02df\u02e1\5f\64\2\u02e0\u02de\3\2\2\2"+ - "\u02e0\u02df\3\2\2\2\u02e1a\3\2\2\2\u02e2\u02e3\5`\61\2\u02e3\u02e4\7"+ - "\6\2\2\u02e4\u02e6\3\2\2\2\u02e5\u02e2\3\2\2\2\u02e5\u02e6\3\2\2\2\u02e6"+ - "\u02e7\3\2\2\2\u02e7\u02ef\7z\2\2\u02e8\u02e9\5`\61\2\u02e9\u02ea\7\6"+ - "\2\2\u02ea\u02ec\3\2\2\2\u02eb\u02e8\3\2\2\2\u02eb\u02ec\3\2\2\2\u02ec"+ - "\u02ed\3\2\2\2\u02ed\u02ef\5`\61\2\u02ee\u02e5\3\2\2\2\u02ee\u02eb\3\2"+ - "\2\2\u02efc\3\2\2\2\u02f0\u02f3\7{\2\2\u02f1\u02f3\7|\2\2\u02f2\u02f0"+ - "\3\2\2\2\u02f2\u02f1\3\2\2\2\u02f3e\3\2\2\2\u02f4\u02f8\7x\2\2\u02f5\u02f8"+ - "\5l\67\2\u02f6\u02f8\7y\2\2\u02f7\u02f4\3\2\2\2\u02f7\u02f5\3\2\2\2\u02f7"+ - "\u02f6\3\2\2\2\u02f8g\3\2\2\2\u02f9\u02fc\7w\2\2\u02fa\u02fc\7v\2\2\u02fb"+ - "\u02f9\3\2\2\2\u02fb\u02fa\3\2\2\2\u02fci\3\2\2\2\u02fd\u02fe\t\20\2\2"+ - "\u02fek\3\2\2\2\u02ff\u0300\t\21\2\2\u0300m\3\2\2\2h}\177\u0083\u008c"+ - "\u008e\u0092\u0099\u00a0\u00a5\u00aa\u00b4\u00b8\u00c0\u00c3\u00c9\u00ce"+ - "\u00d1\u00d6\u00d9\u00de\u00e6\u00e9\u00f5\u00f8\u00fb\u0102\u0109\u010d"+ - "\u0111\u0115\u011c\u0120\u0124\u0129\u012d\u0135\u0139\u0140\u014b\u014e"+ - "\u0152\u015e\u0161\u0167\u016e\u0175\u0178\u017c\u0180\u0184\u0186\u0191"+ - "\u0196\u019a\u019d\u01a3\u01a6\u01ac\u01af\u01b1\u01d4\u01dc\u01de\u01e5"+ - "\u01ea\u01ed\u01f5\u01fe\u0204\u020c\u0211\u0217\u021a\u0221\u0229\u022f"+ - "\u023b\u023d\u0247\u0254\u0260\u026c\u026f\u027d\u028b\u0290\u0297\u029a"+ - "\u02a1\u02aa\u02bd\u02c5\u02c9\u02ce\u02d9\u02e0\u02e5\u02eb\u02ee\u02f2"+ - "\u02f7\u02fb"; + "\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\5\30\u01d0"+ + "\n\30\3\30\3\30\3\30\3\30\3\30\3\30\7\30\u01d8\n\30\f\30\16\30\u01db\13"+ + "\30\3\31\3\31\7\31\u01df\n\31\f\31\16\31\u01e2\13\31\3\32\3\32\5\32\u01e6"+ + "\n\32\3\33\5\33\u01e9\n\33\3\33\3\33\3\33\3\33\3\33\3\33\5\33\u01f1\n"+ + "\33\3\33\3\33\3\33\3\33\3\33\7\33\u01f8\n\33\f\33\16\33\u01fb\13\33\3"+ + "\33\3\33\3\33\5\33\u0200\n\33\3\33\3\33\3\33\3\33\3\33\3\33\5\33\u0208"+ + "\n\33\3\33\3\33\3\33\5\33\u020d\n\33\3\33\3\33\3\33\3\33\5\33\u0213\n"+ + "\33\3\33\5\33\u0216\n\33\3\34\3\34\3\34\3\35\3\35\5\35\u021d\n\35\3\36"+ + "\3\36\3\36\3\36\3\36\3\36\5\36\u0225\n\36\3\37\3\37\3\37\3\37\5\37\u022b"+ + "\n\37\3\37\3\37\3\37\3\37\3\37\3\37\3\37\3\37\3\37\3\37\7\37\u0237\n\37"+ + "\f\37\16\37\u023a\13\37\3 \3 \3 \3 \3 \3 \3 \5 \u0243\n \3 \3 \3 \3 \3"+ + " \3 \3 \3 \3 \3 \3 \5 \u0250\n \3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\5!\u025c"+ + "\n!\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3#\3#\3#\5#\u0268\n#\3#\5#\u026b\n#\3"+ + "$\3$\3$\3$\3$\3$\3$\3%\3%\3%\3%\3%\5%\u0279\n%\3&\3&\3&\3&\3&\3&\3&\3"+ + "\'\3\'\3\'\3\'\3\'\5\'\u0287\n\'\3(\3(\3(\5(\u028c\n(\3(\3(\3(\7(\u0291"+ + "\n(\f(\16(\u0294\13(\5(\u0296\n(\3(\3(\3)\3)\3)\5)\u029d\n)\3*\3*\3*\3"+ + "*\3*\6*\u02a4\n*\r*\16*\u02a5\3*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3"+ + "*\3*\3*\3*\5*\u02b9\n*\3+\3+\3,\3,\3-\3-\5-\u02c1\n-\3-\3-\5-\u02c5\n"+ + "-\3-\3-\3-\5-\u02ca\n-\3.\3.\3/\3/\3\60\3\60\3\60\7\60\u02d3\n\60\f\60"+ + "\16\60\u02d6\13\60\3\60\3\60\3\61\3\61\5\61\u02dc\n\61\3\62\3\62\3\62"+ + "\5\62\u02e1\n\62\3\62\3\62\3\62\3\62\5\62\u02e7\n\62\3\62\5\62\u02ea\n"+ + "\62\3\63\3\63\5\63\u02ee\n\63\3\64\3\64\3\64\5\64\u02f3\n\64\3\65\3\65"+ + "\5\65\u02f7\n\65\3\66\3\66\3\67\3\67\3\67\2\4.<8\2\4\6\b\n\f\16\20\22"+ + "\24\26\30\32\34\36 \"$&(*,.\60\62\64\668:<>@BDFHJLNPRTVXZ\\^`bdfhjl\2"+ + "\22\b\2\7\7\t\t\36\36\66\66AAEE\4\2((SS\4\2\t\tAA\4\2%%--\3\2\32\33\3"+ + "\2mn\4\2\7\7vv\4\2\r\r\32\32\4\2##\62\62\4\2\7\7\34\34\3\2oq\3\2fl\4\2"+ + "\"\"TT\7\2\27\30+,8;LM\\]\3\2tu\31\2\b\t\22\23\25\25\27\27\31\31\36\36"+ + " #$&(++//\62\62\65\6688::AAEGILOPRSVWYY\\\\\u0358\2n\3\2\2\2\4q\3\2\2"+ + "\2\6\u00d9\3\2\2\2\b\u00e4\3\2\2\2\n\u00e8\3\2\2\2\f\u00fd\3\2\2\2\16"+ + "\u0104\3\2\2\2\20\u0106\3\2\2\2\22\u010e\3\2\2\2\24\u012a\3\2\2\2\26\u0134"+ + "\3\2\2\2\30\u013e\3\2\2\2\32\u014d\3\2\2\2\34\u014f\3\2\2\2\36\u0155\3"+ + "\2\2\2 \u0157\3\2\2\2\"\u015e\3\2\2\2$\u0170\3\2\2\2&\u0181\3\2\2\2(\u0191"+ + "\3\2\2\2*\u01ac\3\2\2\2,\u01ae\3\2\2\2.\u01cf\3\2\2\2\60\u01e0\3\2\2\2"+ + "\62\u01e3\3\2\2\2\64\u0215\3\2\2\2\66\u0217\3\2\2\28\u021a\3\2\2\2:\u0224"+ + "\3\2\2\2<\u022a\3\2\2\2>\u024f\3\2\2\2@\u025b\3\2\2\2B\u025d\3\2\2\2D"+ + "\u0264\3\2\2\2F\u026c\3\2\2\2H\u0278\3\2\2\2J\u027a\3\2\2\2L\u0286\3\2"+ + "\2\2N\u0288\3\2\2\2P\u029c\3\2\2\2R\u02b8\3\2\2\2T\u02ba\3\2\2\2V\u02bc"+ + "\3\2\2\2X\u02be\3\2\2\2Z\u02cb\3\2\2\2\\\u02cd\3\2\2\2^\u02d4\3\2\2\2"+ + "`\u02db\3\2\2\2b\u02e9\3\2\2\2d\u02ed\3\2\2\2f\u02f2\3\2\2\2h\u02f6\3"+ + "\2\2\2j\u02f8\3\2\2\2l\u02fa\3\2\2\2no\5\6\4\2op\7\2\2\3p\3\3\2\2\2qr"+ + "\5,\27\2rs\7\2\2\3s\5\3\2\2\2t\u00da\5\b\5\2u\u0083\7 \2\2v\177\7\3\2"+ + "\2wx\7G\2\2x~\t\2\2\2yz\7$\2\2z~\t\3\2\2{|\7Y\2\2|~\5V,\2}w\3\2\2\2}y"+ + "\3\2\2\2}{\3\2\2\2~\u0081\3\2\2\2\177}\3\2\2\2\177\u0080\3\2\2\2\u0080"+ + "\u0082\3\2\2\2\u0081\177\3\2\2\2\u0082\u0084\7\4\2\2\u0083v\3\2\2\2\u0083"+ + "\u0084\3\2\2\2\u0084\u0085\3\2\2\2\u0085\u00da\5\6\4\2\u0086\u0092\7\31"+ + "\2\2\u0087\u008e\7\3\2\2\u0088\u0089\7G\2\2\u0089\u008d\t\4\2\2\u008a"+ + "\u008b\7$\2\2\u008b\u008d\t\3\2\2\u008c\u0088\3\2\2\2\u008c\u008a\3\2"+ + "\2\2\u008d\u0090\3\2\2\2\u008e\u008c\3\2\2\2\u008e\u008f\3\2\2\2\u008f"+ + "\u0091\3\2\2\2\u0090\u008e\3\2\2\2\u0091\u0093\7\4\2\2\u0092\u0087\3\2"+ + "\2\2\u0092\u0093\3\2\2\2\u0093\u0094\3\2\2\2\u0094\u00da\5\6\4\2\u0095"+ + "\u0096\7O\2\2\u0096\u0099\7R\2\2\u0097\u009a\5\66\34\2\u0098\u009a\5b"+ + "\62\2\u0099\u0097\3\2\2\2\u0099\u0098\3\2\2\2\u0099\u009a\3\2\2\2\u009a"+ + "\u00da\3\2\2\2\u009b\u009c\7O\2\2\u009c\u009d\7\23\2\2\u009d\u00a0\t\5"+ + "\2\2\u009e\u00a1\5\66\34\2\u009f\u00a1\5b\62\2\u00a0\u009e\3\2\2\2\u00a0"+ + "\u009f\3\2\2\2\u00a1\u00da\3\2\2\2\u00a2\u00a5\t\6\2\2\u00a3\u00a6\5\66"+ + "\34\2\u00a4\u00a6\5b\62\2\u00a5\u00a3\3\2\2\2\u00a5\u00a4\3\2\2\2\u00a6"+ + "\u00da\3\2\2\2\u00a7\u00a8\7O\2\2\u00a8\u00aa\7\'\2\2\u00a9\u00ab\5\66"+ + "\34\2\u00aa\u00a9\3\2\2\2\u00aa\u00ab\3\2\2\2\u00ab\u00da\3\2\2\2\u00ac"+ + "\u00ad\7O\2\2\u00ad\u00da\7K\2\2\u00ae\u00af\7P\2\2\u00af\u00b2\7R\2\2"+ + "\u00b0\u00b1\7\21\2\2\u00b1\u00b3\5\66\34\2\u00b2\u00b0\3\2\2\2\u00b2"+ + "\u00b3\3\2\2\2\u00b3\u00b6\3\2\2\2\u00b4\u00b7\5\66\34\2\u00b5\u00b7\5"+ + "b\62\2\u00b6\u00b4\3\2\2\2\u00b6\u00b5\3\2\2\2\u00b6\u00b7\3\2\2\2\u00b7"+ + "\u00c1\3\2\2\2\u00b8\u00b9\7V\2\2\u00b9\u00be\5j\66\2\u00ba\u00bb\7\5"+ + "\2\2\u00bb\u00bd\5j\66\2\u00bc\u00ba\3\2\2\2\u00bd\u00c0\3\2\2\2\u00be"+ + "\u00bc\3\2\2\2\u00be\u00bf\3\2\2\2\u00bf\u00c2\3\2\2\2\u00c0\u00be\3\2"+ + "\2\2\u00c1\u00b8\3\2\2\2\u00c1\u00c2\3\2\2\2\u00c2\u00da\3\2\2\2\u00c3"+ + "\u00c4\7P\2\2\u00c4\u00c7\7\23\2\2\u00c5\u00c6\7\21\2\2\u00c6\u00c8\5"+ + "j\66\2\u00c7\u00c5\3\2\2\2\u00c7\u00c8\3\2\2\2\u00c8\u00cc\3\2\2\2\u00c9"+ + "\u00ca\7Q\2\2\u00ca\u00cd\5\66\34\2\u00cb\u00cd\5b\62\2\u00cc\u00c9\3"+ + "\2\2\2\u00cc\u00cb\3\2\2\2\u00cc\u00cd\3\2\2\2\u00cd\u00cf\3\2\2\2\u00ce"+ + "\u00d0\5\66\34\2\u00cf\u00ce\3\2\2\2\u00cf\u00d0\3\2\2\2\u00d0\u00da\3"+ + "\2\2\2\u00d1\u00d2\7P\2\2\u00d2\u00d7\7W\2\2\u00d3\u00d5\t\7\2\2\u00d4"+ + "\u00d3\3\2\2\2\u00d4\u00d5\3\2\2\2\u00d5\u00d6\3\2\2\2\u00d6\u00d8\5h"+ + "\65\2\u00d7\u00d4\3\2\2\2\u00d7\u00d8\3\2\2\2\u00d8\u00da\3\2\2\2\u00d9"+ + "t\3\2\2\2\u00d9u\3\2\2\2\u00d9\u0086\3\2\2\2\u00d9\u0095\3\2\2\2\u00d9"+ + "\u009b\3\2\2\2\u00d9\u00a2\3\2\2\2\u00d9\u00a7\3\2\2\2\u00d9\u00ac\3\2"+ + "\2\2\u00d9\u00ae\3\2\2\2\u00d9\u00c3\3\2\2\2\u00d9\u00d1\3\2\2\2\u00da"+ + "\7\3\2\2\2\u00db\u00dc\7[\2\2\u00dc\u00e1\5\34\17\2\u00dd\u00de\7\5\2"+ + "\2\u00de\u00e0\5\34\17\2\u00df\u00dd\3\2\2\2\u00e0\u00e3\3\2\2\2\u00e1"+ + "\u00df\3\2\2\2\u00e1\u00e2\3\2\2\2\u00e2\u00e5\3\2\2\2\u00e3\u00e1\3\2"+ + "\2\2\u00e4\u00db\3\2\2\2\u00e4\u00e5\3\2\2\2\u00e5\u00e6\3\2\2\2\u00e6"+ + "\u00e7\5\n\6\2\u00e7\t\3\2\2\2\u00e8\u00f3\5\16\b\2\u00e9\u00ea\7C\2\2"+ + "\u00ea\u00eb\7\17\2\2\u00eb\u00f0\5\20\t\2\u00ec\u00ed\7\5\2\2\u00ed\u00ef"+ + "\5\20\t\2\u00ee\u00ec\3\2\2\2\u00ef\u00f2\3\2\2\2\u00f0\u00ee\3\2\2\2"+ + "\u00f0\u00f1\3\2\2\2\u00f1\u00f4\3\2\2\2\u00f2\u00f0\3\2\2\2\u00f3\u00e9"+ + "\3\2\2\2\u00f3\u00f4\3\2\2\2\u00f4\u00f6\3\2\2\2\u00f5\u00f7\5\f\7\2\u00f6"+ + "\u00f5\3\2\2\2\u00f6\u00f7\3\2\2\2\u00f7\13\3\2\2\2\u00f8\u00f9\7\65\2"+ + "\2\u00f9\u00fe\t\b\2\2\u00fa\u00fb\7`\2\2\u00fb\u00fc\t\b\2\2\u00fc\u00fe"+ + "\7e\2\2\u00fd\u00f8\3\2\2\2\u00fd\u00fa\3\2\2\2\u00fe\r\3\2\2\2\u00ff"+ + "\u0105\5\22\n\2\u0100\u0101\7\3\2\2\u0101\u0102\5\n\6\2\u0102\u0103\7"+ + "\4\2\2\u0103\u0105\3\2\2\2\u0104\u00ff\3\2\2\2\u0104\u0100\3\2\2\2\u0105"+ + "\17\3\2\2\2\u0106\u0108\5,\27\2\u0107\u0109\t\t\2\2\u0108\u0107\3\2\2"+ + "\2\u0108\u0109\3\2\2\2\u0109\u010c\3\2\2\2\u010a\u010b\7?\2\2\u010b\u010d"+ + "\t\n\2\2\u010c\u010a\3\2\2\2\u010c\u010d\3\2\2\2\u010d\21\3\2\2\2\u010e"+ + "\u0110\7N\2\2\u010f\u0111\5\36\20\2\u0110\u010f\3\2\2\2\u0110\u0111\3"+ + "\2\2\2\u0111\u0112\3\2\2\2\u0112\u0117\5 \21\2\u0113\u0114\7\5\2\2\u0114"+ + "\u0116\5 \21\2\u0115\u0113\3\2\2\2\u0116\u0119\3\2\2\2\u0117\u0115\3\2"+ + "\2\2\u0117\u0118\3\2\2\2\u0118\u011b\3\2\2\2\u0119\u0117\3\2\2\2\u011a"+ + "\u011c\5\24\13\2\u011b\u011a\3\2\2\2\u011b\u011c\3\2\2\2\u011c\u011f\3"+ + "\2\2\2\u011d\u011e\7Z\2\2\u011e\u0120\5.\30\2\u011f\u011d\3\2\2\2\u011f"+ + "\u0120\3\2\2\2\u0120\u0124\3\2\2\2\u0121\u0122\7)\2\2\u0122\u0123\7\17"+ + "\2\2\u0123\u0125\5\26\f\2\u0124\u0121\3\2\2\2\u0124\u0125\3\2\2\2\u0125"+ + "\u0128\3\2\2\2\u0126\u0127\7*\2\2\u0127\u0129\5.\30\2\u0128\u0126\3\2"+ + "\2\2\u0128\u0129\3\2\2\2\u0129\23\3\2\2\2\u012a\u012b\7%\2\2\u012b\u0130"+ + "\5\"\22\2\u012c\u012d\7\5\2\2\u012d\u012f\5\"\22\2\u012e\u012c\3\2\2\2"+ + "\u012f\u0132\3\2\2\2\u0130\u012e\3\2\2\2\u0130\u0131\3\2\2\2\u0131\25"+ + "\3\2\2\2\u0132\u0130\3\2\2\2\u0133\u0135\5\36\20\2\u0134\u0133\3\2\2\2"+ + "\u0134\u0135\3\2\2\2\u0135\u0136\3\2\2\2\u0136\u013b\5\30\r\2\u0137\u0138"+ + "\7\5\2\2\u0138\u013a\5\30\r\2\u0139\u0137\3\2\2\2\u013a\u013d\3\2\2\2"+ + "\u013b\u0139\3\2\2\2\u013b\u013c\3\2\2\2\u013c\27\3\2\2\2\u013d\u013b"+ + "\3\2\2\2\u013e\u013f\5\32\16\2\u013f\31\3\2\2\2\u0140\u0149\7\3\2\2\u0141"+ + "\u0146\5,\27\2\u0142\u0143\7\5\2\2\u0143\u0145\5,\27\2\u0144\u0142\3\2"+ + "\2\2\u0145\u0148\3\2\2\2\u0146\u0144\3\2\2\2\u0146\u0147\3\2\2\2\u0147"+ + "\u014a\3\2\2\2\u0148\u0146\3\2\2\2\u0149\u0141\3\2\2\2\u0149\u014a\3\2"+ + "\2\2\u014a\u014b\3\2\2\2\u014b\u014e\7\4\2\2\u014c\u014e\5,\27\2\u014d"+ + "\u0140\3\2\2\2\u014d\u014c\3\2\2\2\u014e\33\3\2\2\2\u014f\u0150\5`\61"+ + "\2\u0150\u0151\7\f\2\2\u0151\u0152\7\3\2\2\u0152\u0153\5\n\6\2\u0153\u0154"+ + "\7\4\2\2\u0154\35\3\2\2\2\u0155\u0156\t\13\2\2\u0156\37\3\2\2\2\u0157"+ + "\u015c\5,\27\2\u0158\u015a\7\f\2\2\u0159\u0158\3\2\2\2\u0159\u015a\3\2"+ + "\2\2\u015a\u015b\3\2\2\2\u015b\u015d\5`\61\2\u015c\u0159\3\2\2\2\u015c"+ + "\u015d\3\2\2\2\u015d!\3\2\2\2\u015e\u0162\5*\26\2\u015f\u0161\5$\23\2"+ + "\u0160\u015f\3\2\2\2\u0161\u0164\3\2\2\2\u0162\u0160\3\2\2\2\u0162\u0163"+ + "\3\2\2\2\u0163#\3\2\2\2\u0164\u0162\3\2\2\2\u0165\u0166\5&\24\2\u0166"+ + "\u0167\7\61\2\2\u0167\u0169\5*\26\2\u0168\u016a\5(\25\2\u0169\u0168\3"+ + "\2\2\2\u0169\u016a\3\2\2\2\u016a\u0171\3\2\2\2\u016b\u016c\7<\2\2\u016c"+ + "\u016d\5&\24\2\u016d\u016e\7\61\2\2\u016e\u016f\5*\26\2\u016f\u0171\3"+ + "\2\2\2\u0170\u0165\3\2\2\2\u0170\u016b\3\2\2\2\u0171%\3\2\2\2\u0172\u0174"+ + "\7.\2\2\u0173\u0172\3\2\2\2\u0173\u0174\3\2\2\2\u0174\u0182\3\2\2\2\u0175"+ + "\u0177\7\63\2\2\u0176\u0178\7D\2\2\u0177\u0176\3\2\2\2\u0177\u0178\3\2"+ + "\2\2\u0178\u0182\3\2\2\2\u0179\u017b\7H\2\2\u017a\u017c\7D\2\2\u017b\u017a"+ + "\3\2\2\2\u017b\u017c\3\2\2\2\u017c\u0182\3\2\2\2\u017d\u017f\7&\2\2\u017e"+ + "\u0180\7D\2\2\u017f\u017e\3\2\2\2\u017f\u0180\3\2\2\2\u0180\u0182\3\2"+ + "\2\2\u0181\u0173\3\2\2\2\u0181\u0175\3\2\2\2\u0181\u0179\3\2\2\2\u0181"+ + "\u017d\3\2\2\2\u0182\'\3\2\2\2\u0183\u0184\7@\2\2\u0184\u0192\5.\30\2"+ + "\u0185\u0186\7X\2\2\u0186\u0187\7\3\2\2\u0187\u018c\5`\61\2\u0188\u0189"+ + "\7\5\2\2\u0189\u018b\5`\61\2\u018a\u0188\3\2\2\2\u018b\u018e\3\2\2\2\u018c"+ + "\u018a\3\2\2\2\u018c\u018d\3\2\2\2\u018d\u018f\3\2\2\2\u018e\u018c\3\2"+ + "\2\2\u018f\u0190\7\4\2\2\u0190\u0192\3\2\2\2\u0191\u0183\3\2\2\2\u0191"+ + "\u0185\3\2\2\2\u0192)\3\2\2\2\u0193\u0198\5b\62\2\u0194\u0196\7\f\2\2"+ + "\u0195\u0194\3\2\2\2\u0195\u0196\3\2\2\2\u0196\u0197\3\2\2\2\u0197\u0199"+ + "\5^\60\2\u0198\u0195\3\2\2\2\u0198\u0199\3\2\2\2\u0199\u01ad\3\2\2\2\u019a"+ + "\u019b\7\3\2\2\u019b\u019c\5\n\6\2\u019c\u01a1\7\4\2\2\u019d\u019f\7\f"+ + "\2\2\u019e\u019d\3\2\2\2\u019e\u019f\3\2\2\2\u019f\u01a0\3\2\2\2\u01a0"+ + "\u01a2\5^\60\2\u01a1\u019e\3\2\2\2\u01a1\u01a2\3\2\2\2\u01a2\u01ad\3\2"+ + "\2\2\u01a3\u01a4\7\3\2\2\u01a4\u01a5\5\"\22\2\u01a5\u01aa\7\4\2\2\u01a6"+ + "\u01a8\7\f\2\2\u01a7\u01a6\3\2\2\2\u01a7\u01a8\3\2\2\2\u01a8\u01a9\3\2"+ + "\2\2\u01a9\u01ab\5^\60\2\u01aa\u01a7\3\2\2\2\u01aa\u01ab\3\2\2\2\u01ab"+ + "\u01ad\3\2\2\2\u01ac\u0193\3\2\2\2\u01ac\u019a\3\2\2\2\u01ac\u01a3\3\2"+ + "\2\2\u01ad+\3\2\2\2\u01ae\u01af\5.\30\2\u01af-\3\2\2\2\u01b0\u01b1\b\30"+ + "\1\2\u01b1\u01b2\7=\2\2\u01b2\u01d0\5.\30\n\u01b3\u01b4\7\37\2\2\u01b4"+ + "\u01b5\7\3\2\2\u01b5\u01b6\5\b\5\2\u01b6\u01b7\7\4\2\2\u01b7\u01d0\3\2"+ + "\2\2\u01b8\u01b9\7J\2\2\u01b9\u01ba\7\3\2\2\u01ba\u01bb\5j\66\2\u01bb"+ + "\u01bc\5\60\31\2\u01bc\u01bd\7\4\2\2\u01bd\u01d0\3\2\2\2\u01be\u01bf\7"+ + "\67\2\2\u01bf\u01c0\7\3\2\2\u01c0\u01c1\5^\60\2\u01c1\u01c2\7\5\2\2\u01c2"+ + "\u01c3\5j\66\2\u01c3\u01c4\5\60\31\2\u01c4\u01c5\7\4\2\2\u01c5\u01d0\3"+ + "\2\2\2\u01c6\u01c7\7\67\2\2\u01c7\u01c8\7\3\2\2\u01c8\u01c9\5j\66\2\u01c9"+ + "\u01ca\7\5\2\2\u01ca\u01cb\5j\66\2\u01cb\u01cc\5\60\31\2\u01cc\u01cd\7"+ + "\4\2\2\u01cd\u01d0\3\2\2\2\u01ce\u01d0\5\62\32\2\u01cf\u01b0\3\2\2\2\u01cf"+ + "\u01b3\3\2\2\2\u01cf\u01b8\3\2\2\2\u01cf\u01be\3\2\2\2\u01cf\u01c6\3\2"+ + "\2\2\u01cf\u01ce\3\2\2\2\u01d0\u01d9\3\2\2\2\u01d1\u01d2\f\4\2\2\u01d2"+ + "\u01d3\7\n\2\2\u01d3\u01d8\5.\30\5\u01d4\u01d5\f\3\2\2\u01d5\u01d6\7B"+ + "\2\2\u01d6\u01d8\5.\30\4\u01d7\u01d1\3\2\2\2\u01d7\u01d4\3\2\2\2\u01d8"+ + "\u01db\3\2\2\2\u01d9\u01d7\3\2\2\2\u01d9\u01da\3\2\2\2\u01da/\3\2\2\2"+ + "\u01db\u01d9\3\2\2\2\u01dc\u01dd\7\5\2\2\u01dd\u01df\5j\66\2\u01de\u01dc"+ + "\3\2\2\2\u01df\u01e2\3\2\2\2\u01e0\u01de\3\2\2\2\u01e0\u01e1\3\2\2\2\u01e1"+ + "\61\3\2\2\2\u01e2\u01e0\3\2\2\2\u01e3\u01e5\5<\37\2\u01e4\u01e6\5\64\33"+ + "\2\u01e5\u01e4\3\2\2\2\u01e5\u01e6\3\2\2\2\u01e6\63\3\2\2\2\u01e7\u01e9"+ + "\7=\2\2\u01e8\u01e7\3\2\2\2\u01e8\u01e9\3\2\2\2\u01e9\u01ea\3\2\2\2\u01ea"+ + "\u01eb\7\16\2\2\u01eb\u01ec\5<\37\2\u01ec\u01ed\7\n\2\2\u01ed\u01ee\5"+ + "<\37\2\u01ee\u0216\3\2\2\2\u01ef\u01f1\7=\2\2\u01f0\u01ef\3\2\2\2\u01f0"+ + "\u01f1\3\2\2\2\u01f1\u01f2\3\2\2\2\u01f2\u01f3\7-\2\2\u01f3\u01f4\7\3"+ + "\2\2\u01f4\u01f9\5<\37\2\u01f5\u01f6\7\5\2\2\u01f6\u01f8\5<\37\2\u01f7"+ + "\u01f5\3\2\2\2\u01f8\u01fb\3\2\2\2\u01f9\u01f7\3\2\2\2\u01f9\u01fa\3\2"+ + "\2\2\u01fa\u01fc\3\2\2\2\u01fb\u01f9\3\2\2\2\u01fc\u01fd\7\4\2\2\u01fd"+ + "\u0216\3\2\2\2\u01fe\u0200\7=\2\2\u01ff\u01fe\3\2\2\2\u01ff\u0200\3\2"+ + "\2\2\u0200\u0201\3\2\2\2\u0201\u0202\7-\2\2\u0202\u0203\7\3\2\2\u0203"+ + "\u0204\5\b\5\2\u0204\u0205\7\4\2\2\u0205\u0216\3\2\2\2\u0206\u0208\7="+ + "\2\2\u0207\u0206\3\2\2\2\u0207\u0208\3\2\2\2\u0208\u0209\3\2\2\2\u0209"+ + "\u020a\7\64\2\2\u020a\u0216\58\35\2\u020b\u020d\7=\2\2\u020c\u020b\3\2"+ + "\2\2\u020c\u020d\3\2\2\2\u020d\u020e\3\2\2\2\u020e\u020f\7I\2\2\u020f"+ + "\u0216\5j\66\2\u0210\u0212\7\60\2\2\u0211\u0213\7=\2\2\u0212\u0211\3\2"+ + "\2\2\u0212\u0213\3\2\2\2\u0213\u0214\3\2\2\2\u0214\u0216\7>\2\2\u0215"+ + "\u01e8\3\2\2\2\u0215\u01f0\3\2\2\2\u0215\u01ff\3\2\2\2\u0215\u0207\3\2"+ + "\2\2\u0215\u020c\3\2\2\2\u0215\u0210\3\2\2\2\u0216\65\3\2\2\2\u0217\u0218"+ + "\7\64\2\2\u0218\u0219\58\35\2\u0219\67\3\2\2\2\u021a\u021c\5j\66\2\u021b"+ + "\u021d\5:\36\2\u021c\u021b\3\2\2\2\u021c\u021d\3\2\2\2\u021d9\3\2\2\2"+ + "\u021e\u021f\7\35\2\2\u021f\u0225\5j\66\2\u0220\u0221\7^\2\2\u0221\u0222"+ + "\5j\66\2\u0222\u0223\7e\2\2\u0223\u0225\3\2\2\2\u0224\u021e\3\2\2\2\u0224"+ + "\u0220\3\2\2\2\u0225;\3\2\2\2\u0226\u0227\b\37\1\2\u0227\u022b\5> \2\u0228"+ + "\u0229\t\7\2\2\u0229\u022b\5<\37\6\u022a\u0226\3\2\2\2\u022a\u0228\3\2"+ + "\2\2\u022b\u0238\3\2\2\2\u022c\u022d\f\5\2\2\u022d\u022e\t\f\2\2\u022e"+ + "\u0237\5<\37\6\u022f\u0230\f\4\2\2\u0230\u0231\t\7\2\2\u0231\u0237\5<"+ + "\37\5\u0232\u0233\f\3\2\2\u0233\u0234\5T+\2\u0234\u0235\5<\37\4\u0235"+ + "\u0237\3\2\2\2\u0236\u022c\3\2\2\2\u0236\u022f\3\2\2\2\u0236\u0232\3\2"+ + "\2\2\u0237\u023a\3\2\2\2\u0238\u0236\3\2\2\2\u0238\u0239\3\2\2\2\u0239"+ + "=\3\2\2\2\u023a\u0238\3\2\2\2\u023b\u0250\5@!\2\u023c\u0250\5H%\2\u023d"+ + "\u0250\5D#\2\u023e\u0250\5R*\2\u023f\u0240\5^\60\2\u0240\u0241\7s\2\2"+ + "\u0241\u0243\3\2\2\2\u0242\u023f\3\2\2\2\u0242\u0243\3\2\2\2\u0243\u0244"+ + "\3\2\2\2\u0244\u0250\7o\2\2\u0245\u0250\5L\'\2\u0246\u0247\7\3\2\2\u0247"+ + "\u0248\5\b\5\2\u0248\u0249\7\4\2\2\u0249\u0250\3\2\2\2\u024a\u0250\5^"+ + "\60\2\u024b\u024c\7\3\2\2\u024c\u024d\5,\27\2\u024d\u024e\7\4\2\2\u024e"+ + "\u0250\3\2\2\2\u024f\u023b\3\2\2\2\u024f\u023c\3\2\2\2\u024f\u023d\3\2"+ + "\2\2\u024f\u023e\3\2\2\2\u024f\u0242\3\2\2\2\u024f\u0245\3\2\2\2\u024f"+ + "\u0246\3\2\2\2\u024f\u024a\3\2\2\2\u024f\u024b\3\2\2\2\u0250?\3\2\2\2"+ + "\u0251\u025c\5B\"\2\u0252\u0253\7_\2\2\u0253\u0254\5B\"\2\u0254\u0255"+ + "\7e\2\2\u0255\u025c\3\2\2\2\u0256\u025c\5F$\2\u0257\u0258\7_\2\2\u0258"+ + "\u0259\5F$\2\u0259\u025a\7e\2\2\u025a\u025c\3\2\2\2\u025b\u0251\3\2\2"+ + "\2\u025b\u0252\3\2\2\2\u025b\u0256\3\2\2\2\u025b\u0257\3\2\2\2\u025cA"+ + "\3\2\2\2\u025d\u025e\7\20\2\2\u025e\u025f\7\3\2\2\u025f\u0260\5,\27\2"+ + "\u0260\u0261\7\f\2\2\u0261\u0262\5\\/\2\u0262\u0263\7\4\2\2\u0263C\3\2"+ + "\2\2\u0264\u026a\7\26\2\2\u0265\u0267\7\3\2\2\u0266\u0268\7v\2\2\u0267"+ + "\u0266\3\2\2\2\u0267\u0268\3\2\2\2\u0268\u0269\3\2\2\2\u0269\u026b\7\4"+ + "\2\2\u026a\u0265\3\2\2\2\u026a\u026b\3\2\2\2\u026bE\3\2\2\2\u026c\u026d"+ + "\7\24\2\2\u026d\u026e\7\3\2\2\u026e\u026f\5,\27\2\u026f\u0270\7\5\2\2"+ + "\u0270\u0271\5\\/\2\u0271\u0272\7\4\2\2\u0272G\3\2\2\2\u0273\u0279\5J"+ + "&\2\u0274\u0275\7_\2\2\u0275\u0276\5J&\2\u0276\u0277\7e\2\2\u0277\u0279"+ + "\3\2\2\2\u0278\u0273\3\2\2\2\u0278\u0274\3\2\2\2\u0279I\3\2\2\2\u027a"+ + "\u027b\7!\2\2\u027b\u027c\7\3\2\2\u027c\u027d\5`\61\2\u027d\u027e\7%\2"+ + "\2\u027e\u027f\5<\37\2\u027f\u0280\7\4\2\2\u0280K\3\2\2\2\u0281\u0287"+ + "\5N(\2\u0282\u0283\7_\2\2\u0283\u0284\5N(\2\u0284\u0285\7e\2\2\u0285\u0287"+ + "\3\2\2\2\u0286\u0281\3\2\2\2\u0286\u0282\3\2\2\2\u0287M\3\2\2\2\u0288"+ + "\u0289\5P)\2\u0289\u0295\7\3\2\2\u028a\u028c\5\36\20\2\u028b\u028a\3\2"+ + "\2\2\u028b\u028c\3\2\2\2\u028c\u028d\3\2\2\2\u028d\u0292\5,\27\2\u028e"+ + "\u028f\7\5\2\2\u028f\u0291\5,\27\2\u0290\u028e\3\2\2\2\u0291\u0294\3\2"+ + "\2\2\u0292\u0290\3\2\2\2\u0292\u0293\3\2\2\2\u0293\u0296\3\2\2\2\u0294"+ + "\u0292\3\2\2\2\u0295\u028b\3\2\2\2\u0295\u0296\3\2\2\2\u0296\u0297\3\2"+ + "\2\2\u0297\u0298\7\4\2\2\u0298O\3\2\2\2\u0299\u029d\7\63\2\2\u029a\u029d"+ + "\7H\2\2\u029b\u029d\5`\61\2\u029c\u0299\3\2\2\2\u029c\u029a\3\2\2\2\u029c"+ + "\u029b\3\2\2\2\u029dQ\3\2\2\2\u029e\u02b9\7>\2\2\u029f\u02b9\5X-\2\u02a0"+ + "\u02b9\5h\65\2\u02a1\u02b9\5V,\2\u02a2\u02a4\7u\2\2\u02a3\u02a2\3\2\2"+ + "\2\u02a4\u02a5\3\2\2\2\u02a5\u02a3\3\2\2\2\u02a5\u02a6\3\2\2\2\u02a6\u02b9"+ + "\3\2\2\2\u02a7\u02b9\7t\2\2\u02a8\u02a9\7a\2\2\u02a9\u02aa\5j\66\2\u02aa"+ + "\u02ab\7e\2\2\u02ab\u02b9\3\2\2\2\u02ac\u02ad\7b\2\2\u02ad\u02ae\5j\66"+ + "\2\u02ae\u02af\7e\2\2\u02af\u02b9\3\2\2\2\u02b0\u02b1\7c\2\2\u02b1\u02b2"+ + "\5j\66\2\u02b2\u02b3\7e\2\2\u02b3\u02b9\3\2\2\2\u02b4\u02b5\7d\2\2\u02b5"+ + "\u02b6\5j\66\2\u02b6\u02b7\7e\2\2\u02b7\u02b9\3\2\2\2\u02b8\u029e\3\2"+ + "\2\2\u02b8\u029f\3\2\2\2\u02b8\u02a0\3\2\2\2\u02b8\u02a1\3\2\2\2\u02b8"+ + "\u02a3\3\2\2\2\u02b8\u02a7\3\2\2\2\u02b8\u02a8\3\2\2\2\u02b8\u02ac\3\2"+ + "\2\2\u02b8\u02b0\3\2\2\2\u02b8\u02b4\3\2\2\2\u02b9S\3\2\2\2\u02ba\u02bb"+ + "\t\r\2\2\u02bbU\3\2\2\2\u02bc\u02bd\t\16\2\2\u02bdW\3\2\2\2\u02be\u02c0"+ + "\7/\2\2\u02bf\u02c1\t\7\2\2\u02c0\u02bf\3\2\2\2\u02c0\u02c1\3\2\2\2\u02c1"+ + "\u02c4\3\2\2\2\u02c2\u02c5\5h\65\2\u02c3\u02c5\5j\66\2\u02c4\u02c2\3\2"+ + "\2\2\u02c4\u02c3\3\2\2\2\u02c5\u02c6\3\2\2\2\u02c6\u02c9\5Z.\2\u02c7\u02c8"+ + "\7U\2\2\u02c8\u02ca\5Z.\2\u02c9\u02c7\3\2\2\2\u02c9\u02ca\3\2\2\2\u02ca"+ + "Y\3\2\2\2\u02cb\u02cc\t\17\2\2\u02cc[\3\2\2\2\u02cd\u02ce\5`\61\2\u02ce"+ + "]\3\2\2\2\u02cf\u02d0\5`\61\2\u02d0\u02d1\7s\2\2\u02d1\u02d3\3\2\2\2\u02d2"+ + "\u02cf\3\2\2\2\u02d3\u02d6\3\2\2\2\u02d4\u02d2\3\2\2\2\u02d4\u02d5\3\2"+ + "\2\2\u02d5\u02d7\3\2\2\2\u02d6\u02d4\3\2\2\2\u02d7\u02d8\5`\61\2\u02d8"+ + "_\3\2\2\2\u02d9\u02dc\5d\63\2\u02da\u02dc\5f\64\2\u02db\u02d9\3\2\2\2"+ + "\u02db\u02da\3\2\2\2\u02dca\3\2\2\2\u02dd\u02de\5`\61\2\u02de\u02df\7"+ + "\6\2\2\u02df\u02e1\3\2\2\2\u02e0\u02dd\3\2\2\2\u02e0\u02e1\3\2\2\2\u02e1"+ + "\u02e2\3\2\2\2\u02e2\u02ea\7z\2\2\u02e3\u02e4\5`\61\2\u02e4\u02e5\7\6"+ + "\2\2\u02e5\u02e7\3\2\2\2\u02e6\u02e3\3\2\2\2\u02e6\u02e7\3\2\2\2\u02e7"+ + "\u02e8\3\2\2\2\u02e8\u02ea\5`\61\2\u02e9\u02e0\3\2\2\2\u02e9\u02e6\3\2"+ + "\2\2\u02eac\3\2\2\2\u02eb\u02ee\7{\2\2\u02ec\u02ee\7|\2\2\u02ed\u02eb"+ + "\3\2\2\2\u02ed\u02ec\3\2\2\2\u02eee\3\2\2\2\u02ef\u02f3\7x\2\2\u02f0\u02f3"+ + "\5l\67\2\u02f1\u02f3\7y\2\2\u02f2\u02ef\3\2\2\2\u02f2\u02f0\3\2\2\2\u02f2"+ + "\u02f1\3\2\2\2\u02f3g\3\2\2\2\u02f4\u02f7\7w\2\2\u02f5\u02f7\7v\2\2\u02f6"+ + "\u02f4\3\2\2\2\u02f6\u02f5\3\2\2\2\u02f7i\3\2\2\2\u02f8\u02f9\t\20\2\2"+ + "\u02f9k\3\2\2\2\u02fa\u02fb\t\21\2\2\u02fbm\3\2\2\2h}\177\u0083\u008c"+ + "\u008e\u0092\u0099\u00a0\u00a5\u00aa\u00b2\u00b6\u00be\u00c1\u00c7\u00cc"+ + "\u00cf\u00d4\u00d7\u00d9\u00e1\u00e4\u00f0\u00f3\u00f6\u00fd\u0104\u0108"+ + "\u010c\u0110\u0117\u011b\u011f\u0124\u0128\u0130\u0134\u013b\u0146\u0149"+ + "\u014d\u0159\u015c\u0162\u0169\u0170\u0173\u0177\u017b\u017f\u0181\u018c"+ + "\u0191\u0195\u0198\u019e\u01a1\u01a7\u01aa\u01ac\u01cf\u01d7\u01d9\u01e0"+ + "\u01e5\u01e8\u01f0\u01f9\u01ff\u0207\u020c\u0212\u0215\u021c\u0224\u022a"+ + "\u0236\u0238\u0242\u024f\u025b\u0267\u026a\u0278\u0286\u028b\u0292\u0295"+ + "\u029c\u02a5\u02b8\u02c0\u02c4\u02c9\u02d4\u02db\u02e0\u02e6\u02e9\u02ed"+ + "\u02f2\u02f6"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseVisitor.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseVisitor.java index 1575e310c1469..ed64045191be0 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseVisitor.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlBaseVisitor.java @@ -71,13 +71,6 @@ interface SqlBaseVisitor extends ParseTreeVisitor { * @return the visitor result */ T visitShowSchemas(SqlBaseParser.ShowSchemasContext ctx); - /** - * Visit a parse tree produced by the {@code sysCatalogs} - * labeled alternative in {@link SqlBaseParser#statement}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitSysCatalogs(SqlBaseParser.SysCatalogsContext ctx); /** * Visit a parse tree produced by the {@code sysTables} * labeled alternative in {@link SqlBaseParser#statement}. @@ -99,13 +92,6 @@ interface SqlBaseVisitor extends ParseTreeVisitor { * @return the visitor result */ T visitSysTypes(SqlBaseParser.SysTypesContext ctx); - /** - * Visit a parse tree produced by the {@code sysTableTypes} - * labeled alternative in {@link SqlBaseParser#statement}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitSysTableTypes(SqlBaseParser.SysTableTypesContext ctx); /** * Visit a parse tree produced by {@link SqlBaseParser#query}. * @param ctx the parse tree diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysCatalogs.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysCatalogs.java deleted file mode 100644 index a98b1bdc1b7a7..0000000000000 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysCatalogs.java +++ /dev/null @@ -1,64 +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.sql.plan.logical.command.sys; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.xpack.sql.expression.Attribute; -import org.elasticsearch.xpack.sql.plan.logical.command.Command; -import org.elasticsearch.xpack.sql.session.Rows; -import org.elasticsearch.xpack.sql.session.SchemaRowSet; -import org.elasticsearch.xpack.sql.session.SqlSession; -import org.elasticsearch.xpack.sql.tree.Source; -import org.elasticsearch.xpack.sql.tree.NodeInfo; - -import java.util.List; - -import static java.util.Collections.singletonList; - -/** - * System command returning the catalogs (clusters) available. - * Currently returns only the current cluster name. - */ -public class SysCatalogs extends Command { - - public SysCatalogs(Source source) { - super(source); - } - - @Override - protected NodeInfo info() { - return NodeInfo.create(this); - } - - @Override - public List output() { - return singletonList(keyword("TABLE_CAT")); - } - - @Override - public final void execute(SqlSession session, ActionListener listener) { - String cluster = session.indexResolver().clusterName(); - listener.onResponse(Rows.of(output(), singletonList(singletonList(cluster)))); - } - - @Override - public int hashCode() { - return getClass().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (obj == null || getClass() != obj.getClass()) { - return false; - } - - return true; - } -} \ No newline at end of file diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTableTypes.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTableTypes.java deleted file mode 100644 index fef6171b95d22..0000000000000 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTableTypes.java +++ /dev/null @@ -1,70 +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.sql.plan.logical.command.sys; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.xpack.sql.analysis.index.IndexResolver.IndexType; -import org.elasticsearch.xpack.sql.expression.Attribute; -import org.elasticsearch.xpack.sql.plan.logical.command.Command; -import org.elasticsearch.xpack.sql.session.Rows; -import org.elasticsearch.xpack.sql.session.SchemaRowSet; -import org.elasticsearch.xpack.sql.session.SqlSession; -import org.elasticsearch.xpack.sql.tree.Source; -import org.elasticsearch.xpack.sql.tree.NodeInfo; - -import java.util.Comparator; -import java.util.List; - -import static java.util.Collections.singletonList; -import static java.util.stream.Collectors.toList; - -/** - * System command returning the types of tables supported, - * index and alias. - */ -public class SysTableTypes extends Command { - - public SysTableTypes(Source source) { - super(source); - } - - @Override - protected NodeInfo info() { - return NodeInfo.create(this); - } - - @Override - public List output() { - return singletonList(keyword("TABLE_TYPE")); - } - - @Override - public final void execute(SqlSession session, ActionListener listener) { - listener.onResponse(Rows.of(output(), IndexType.VALID.stream() - // *DBC requires ascending order - .sorted(Comparator.comparing(t -> t.toSql())) - .map(t -> singletonList(t.toSql())) - .collect(toList()))); - } - - @Override - public int hashCode() { - return getClass().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (obj == null || getClass() != obj.getClass()) { - return false; - } - - return true; - } -} \ No newline at end of file diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysCatalogsTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysCatalogsTests.java deleted file mode 100644 index 757c7ed010834..0000000000000 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysCatalogsTests.java +++ /dev/null @@ -1,61 +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.sql.plan.logical.command.sys; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.common.collect.Tuple; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.sql.TestUtils; -import org.elasticsearch.xpack.sql.analysis.analyzer.Analyzer; -import org.elasticsearch.xpack.sql.analysis.analyzer.Verifier; -import org.elasticsearch.xpack.sql.analysis.index.EsIndex; -import org.elasticsearch.xpack.sql.analysis.index.IndexResolution; -import org.elasticsearch.xpack.sql.analysis.index.IndexResolver; -import org.elasticsearch.xpack.sql.expression.function.FunctionRegistry; -import org.elasticsearch.xpack.sql.parser.SqlParser; -import org.elasticsearch.xpack.sql.plan.logical.command.Command; -import org.elasticsearch.xpack.sql.session.SqlSession; -import org.elasticsearch.xpack.sql.stats.Metrics; -import org.elasticsearch.xpack.sql.type.TypesTests; - -import static java.util.Collections.singletonList; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class SysCatalogsTests extends ESTestCase { - - private final SqlParser parser = new SqlParser(); - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private Tuple sql(String sql) { - EsIndex test = new EsIndex("test", TypesTests.loadMapping("mapping-multi-field-with-nested.json", true)); - Analyzer analyzer = new Analyzer(TestUtils.TEST_CFG, new FunctionRegistry(), IndexResolution.valid(test), - new Verifier(new Metrics())); - Command cmd = (Command) analyzer.analyze(parser.createStatement(sql), true); - - IndexResolver resolver = mock(IndexResolver.class); - when(resolver.clusterName()).thenReturn("cluster"); - - doAnswer(invocation -> { - ((ActionListener) invocation.getArguments()[2]).onResponse(singletonList(test)); - return Void.TYPE; - }).when(resolver).resolveAsSeparateMappings(any(), any(), any()); - - SqlSession session = new SqlSession(null, null, null, resolver, null, null, null, null); - return new Tuple<>(cmd, session); - } - - public void testSysCatalogs() throws Exception { - Tuple sql = sql("SYS CATALOGS"); - - sql.v1().execute(sql.v2(), ActionListener.wrap(r -> { - assertEquals(1, r.size()); - assertEquals("cluster", r.column(0)); - }, ex -> fail(ex.getMessage()))); - } -} \ No newline at end of file diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTableTypesTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTableTypesTests.java deleted file mode 100644 index 2458a3f34eb39..0000000000000 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTableTypesTests.java +++ /dev/null @@ -1,52 +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.sql.plan.logical.command.sys; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.common.collect.Tuple; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.sql.TestUtils; -import org.elasticsearch.xpack.sql.analysis.analyzer.Analyzer; -import org.elasticsearch.xpack.sql.analysis.analyzer.Verifier; -import org.elasticsearch.xpack.sql.analysis.index.EsIndex; -import org.elasticsearch.xpack.sql.analysis.index.IndexResolution; -import org.elasticsearch.xpack.sql.analysis.index.IndexResolver; -import org.elasticsearch.xpack.sql.expression.function.FunctionRegistry; -import org.elasticsearch.xpack.sql.parser.SqlParser; -import org.elasticsearch.xpack.sql.plan.logical.command.Command; -import org.elasticsearch.xpack.sql.session.SqlSession; -import org.elasticsearch.xpack.sql.stats.Metrics; -import org.elasticsearch.xpack.sql.type.TypesTests; - -import static org.mockito.Mockito.mock; - -public class SysTableTypesTests extends ESTestCase { - - private final SqlParser parser = new SqlParser(); - - private Tuple sql(String sql) { - EsIndex test = new EsIndex("test", TypesTests.loadMapping("mapping-multi-field-with-nested.json", true)); - Analyzer analyzer = new Analyzer(TestUtils.TEST_CFG, new FunctionRegistry(), IndexResolution.valid(test), - new Verifier(new Metrics())); - Command cmd = (Command) analyzer.analyze(parser.createStatement(sql), true); - - IndexResolver resolver = mock(IndexResolver.class); - SqlSession session = new SqlSession(null, null, null, resolver, null, null, null, null); - return new Tuple<>(cmd, session); - } - - public void testSysTableTypes() throws Exception { - Tuple sql = sql("SYS TABLE TYPES"); - - sql.v1().execute(sql.v2(), ActionListener.wrap(r -> { - assertEquals(2, r.size()); - assertEquals("ALIAS", r.column(0)); - assertTrue(r.advanceRow()); - assertEquals("BASE TABLE", r.column(0)); - }, ex -> fail(ex.getMessage()))); - } - -} \ No newline at end of file diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/stats/VerifierMetricsTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/stats/VerifierMetricsTests.java index 1db0d4383e756..3f50915f98637 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/stats/VerifierMetricsTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/stats/VerifierMetricsTests.java @@ -93,8 +93,7 @@ public void testOrderByQuery() { public void testCommand() { Counters c = sql(randomFrom("SHOW FUNCTIONS", "SHOW COLUMNS FROM library", "SHOW SCHEMAS", - "SHOW TABLES", "SYS CATALOGS", "SYS COLUMNS LIKE '%name'", - "SYS TABLES", "SYS TYPES")); + "SHOW TABLES", "SYS COLUMNS LIKE '%name'", "SYS TABLES", "SYS TYPES")); assertEquals(0, where(c)); assertEquals(0, limit(c)); assertEquals(0, groupby(c)); From 6d99e790b3ee78f99f4810ff79b38488e43a146d Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Wed, 16 Jan 2019 21:52:17 +1100 Subject: [PATCH 05/16] Add SSL Configuration Library (#37287) This introduces a new ssl-config library that can parse and validate SSL/TLS settings and files. It supports the standard configuration settings as used in the Elastic Stack such as "ssl.verification_mode" and "ssl.certificate_authorities" as well as all file formats used in other parts of Elasticsearch security (such as PEM, JKS, PKCS#12, PKCS#8, et al). --- libs/ssl-config/build.gradle | 42 ++ .../common/ssl/DefaultJdkTrustConfig.java | 128 ++++ .../elasticsearch/common/ssl/DerParser.java | 297 +++++++++ .../common/ssl/EmptyKeyConfig.java | 52 ++ .../common/ssl/KeyStoreUtil.java | 163 +++++ .../common/ssl/PemKeyConfig.java | 122 ++++ .../common/ssl/PemTrustConfig.java | 122 ++++ .../elasticsearch/common/ssl/PemUtils.java | 613 ++++++++++++++++++ .../ssl/SslClientAuthenticationMode.java | 101 +++ .../common/ssl/SslConfigException.java | 33 + .../common/ssl/SslConfiguration.java | 164 +++++ .../common/ssl/SslConfigurationKeys.java | 181 ++++++ .../common/ssl/SslConfigurationLoader.java | 371 +++++++++++ .../common/ssl/SslKeyConfig.java | 46 ++ .../common/ssl/SslTrustConfig.java | 46 ++ .../common/ssl/SslVerificationMode.java | 104 +++ .../common/ssl/StoreKeyConfig.java | 106 +++ .../common/ssl/StoreTrustConfig.java | 90 +++ .../common/ssl/TrustEverythingConfig.java | 92 +++ .../ssl/DefaultJdkTrustConfigTests.java | 79 +++ .../common/ssl/PemKeyConfigTests.java | 148 +++++ .../common/ssl/PemTrustConfigTests.java | 150 +++++ .../common/ssl/PemUtilsTests.java | 219 +++++++ .../ssl/SslConfigurationLoaderTests.java | 220 +++++++ .../common/ssl/SslConfigurationTests.java | 140 ++++ .../common/ssl/StoreKeyConfigTests.java | 215 ++++++ .../common/ssl/StoreTrustConfigTests.java | 169 +++++ .../src/test/resources/certs/README.txt | 75 +++ .../src/test/resources/certs/ca-all/ca.jks | Bin 0 -> 2460 bytes .../src/test/resources/certs/ca-all/ca.p12 | Bin 0 -> 2818 bytes .../src/test/resources/certs/ca1/ca.crt | 19 + .../src/test/resources/certs/ca1/ca.key | 27 + .../src/test/resources/certs/ca1/ca.p12 | Bin 0 -> 1066 bytes .../src/test/resources/certs/ca2/ca.crt | 19 + .../src/test/resources/certs/ca2/ca.key | 27 + .../src/test/resources/certs/ca2/ca.p12 | Bin 0 -> 1066 bytes .../src/test/resources/certs/ca3/ca.crt | 19 + .../src/test/resources/certs/ca3/ca.key | 27 + .../src/test/resources/certs/ca3/ca.p12 | Bin 0 -> 1066 bytes .../test/resources/certs/cert-all/certs.jks | Bin 0 -> 4268 bytes .../test/resources/certs/cert-all/certs.p12 | Bin 0 -> 4757 bytes .../src/test/resources/certs/cert1/cert1.crt | 19 + .../src/test/resources/certs/cert1/cert1.key | 27 + .../src/test/resources/certs/cert1/cert1.p12 | Bin 0 -> 2456 bytes .../src/test/resources/certs/cert2/cert2.crt | 19 + .../src/test/resources/certs/cert2/cert2.key | 30 + .../src/test/resources/certs/cert2/cert2.p12 | Bin 0 -> 2456 bytes .../resources/certs/pem-utils/README.asciidoc | 149 +++++ .../pem-utils/corrupted_key_pkcs8_plain.pem | 24 + .../pem-utils/dsa_key_openssl_encrypted.pem | 15 + .../certs/pem-utils/dsa_key_openssl_plain.pem | 12 + .../dsa_key_openssl_plain_with_params.pem | 18 + .../certs/pem-utils/dsa_key_pkcs8_plain.pem | 9 + .../pem-utils/ec_key_openssl_encrypted.pem | 7 + .../certs/pem-utils/ec_key_openssl_plain.pem | 4 + .../ec_key_openssl_plain_with_params.pem | 7 + .../certs/pem-utils/ec_key_pkcs8_plain.pem | 4 + .../test/resources/certs/pem-utils/empty.pem | 0 .../certs/pem-utils/key_pkcs8_encrypted.pem | 29 + .../certs/pem-utils/key_unsupported.pem | 7 + .../certs/pem-utils/rsa_key_pkcs8_plain.pem | 28 + .../certs/pem-utils/testnode-aes128.pem | 30 + .../certs/pem-utils/testnode-aes192.pem | 30 + .../certs/pem-utils/testnode-aes256.pem | 30 + .../certs/pem-utils/testnode-unprotected.pem | 27 + .../resources/certs/pem-utils/testnode.crt | 23 + .../resources/certs/pem-utils/testnode.jks | Bin 0 -> 9360 bytes .../resources/certs/pem-utils/testnode.pem | 30 + .../pem-utils/testnode_with_bagattrs.pem | 32 + settings.gradle | 9 +- 70 files changed, 5044 insertions(+), 1 deletion(-) create mode 100644 libs/ssl-config/build.gradle create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/DefaultJdkTrustConfig.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/DerParser.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/EmptyKeyConfig.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/KeyStoreUtil.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemKeyConfig.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemTrustConfig.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslClientAuthenticationMode.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigException.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfiguration.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationKeys.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslKeyConfig.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslTrustConfig.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslVerificationMode.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/StoreKeyConfig.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/StoreTrustConfig.java create mode 100644 libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/TrustEverythingConfig.java create mode 100644 libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/DefaultJdkTrustConfigTests.java create mode 100644 libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/PemKeyConfigTests.java create mode 100644 libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/PemTrustConfigTests.java create mode 100644 libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/PemUtilsTests.java create mode 100644 libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/SslConfigurationLoaderTests.java create mode 100644 libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/SslConfigurationTests.java create mode 100644 libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/StoreKeyConfigTests.java create mode 100644 libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/StoreTrustConfigTests.java create mode 100644 libs/ssl-config/src/test/resources/certs/README.txt create mode 100644 libs/ssl-config/src/test/resources/certs/ca-all/ca.jks create mode 100644 libs/ssl-config/src/test/resources/certs/ca-all/ca.p12 create mode 100644 libs/ssl-config/src/test/resources/certs/ca1/ca.crt create mode 100644 libs/ssl-config/src/test/resources/certs/ca1/ca.key create mode 100644 libs/ssl-config/src/test/resources/certs/ca1/ca.p12 create mode 100644 libs/ssl-config/src/test/resources/certs/ca2/ca.crt create mode 100644 libs/ssl-config/src/test/resources/certs/ca2/ca.key create mode 100644 libs/ssl-config/src/test/resources/certs/ca2/ca.p12 create mode 100644 libs/ssl-config/src/test/resources/certs/ca3/ca.crt create mode 100644 libs/ssl-config/src/test/resources/certs/ca3/ca.key create mode 100644 libs/ssl-config/src/test/resources/certs/ca3/ca.p12 create mode 100644 libs/ssl-config/src/test/resources/certs/cert-all/certs.jks create mode 100644 libs/ssl-config/src/test/resources/certs/cert-all/certs.p12 create mode 100644 libs/ssl-config/src/test/resources/certs/cert1/cert1.crt create mode 100644 libs/ssl-config/src/test/resources/certs/cert1/cert1.key create mode 100644 libs/ssl-config/src/test/resources/certs/cert1/cert1.p12 create mode 100644 libs/ssl-config/src/test/resources/certs/cert2/cert2.crt create mode 100644 libs/ssl-config/src/test/resources/certs/cert2/cert2.key create mode 100644 libs/ssl-config/src/test/resources/certs/cert2/cert2.p12 create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/README.asciidoc create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/corrupted_key_pkcs8_plain.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_openssl_encrypted.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_openssl_plain.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_openssl_plain_with_params.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_pkcs8_plain.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_openssl_encrypted.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_openssl_plain.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_openssl_plain_with_params.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_pkcs8_plain.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/empty.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/key_pkcs8_encrypted.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/key_unsupported.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/rsa_key_pkcs8_plain.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/testnode-aes128.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/testnode-aes192.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/testnode-aes256.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/testnode-unprotected.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/testnode.crt create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/testnode.jks create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/testnode.pem create mode 100644 libs/ssl-config/src/test/resources/certs/pem-utils/testnode_with_bagattrs.pem diff --git a/libs/ssl-config/build.gradle b/libs/ssl-config/build.gradle new file mode 100644 index 0000000000000..8d5b1d18b8c04 --- /dev/null +++ b/libs/ssl-config/build.gradle @@ -0,0 +1,42 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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. + */ + +dependencies { + compile "org.elasticsearch:elasticsearch-core:${version}" + + if (isEclipse == false || project.path == ":libs:ssl-config-tests") { + testCompile("org.elasticsearch.test:framework:${version}") { + exclude group: 'org.elasticsearch', module: 'elasticsearch-ssl-config' + } + } + + testCompile "com.carrotsearch.randomizedtesting:randomizedtesting-runner:${versions.randomizedrunner}" + testCompile "junit:junit:${versions.junit}" + testCompile "org.hamcrest:hamcrest-all:${versions.hamcrest}" +} + +forbiddenApisMain { + replaceSignatureFiles 'jdk-signatures' +} +forbiddenPatterns { + exclude '**/*.key' + exclude '**/*.pem' + exclude '**/*.p12' + exclude '**/*.jks' +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/DefaultJdkTrustConfig.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/DefaultJdkTrustConfig.java new file mode 100644 index 0000000000000..5a1fbe72c3f49 --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/DefaultJdkTrustConfig.java @@ -0,0 +1,128 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import org.elasticsearch.common.Nullable; + +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509ExtendedTrustManager; +import java.io.IOException; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.function.BiFunction; + +/** + * This class represents a trust configuration that corresponds to the default trusted CAs of the JDK + */ +final class DefaultJdkTrustConfig implements SslTrustConfig { + + private final BiFunction systemProperties; + private final char[] trustStorePassword; + + /** + * Create a trust config that uses System properties to determine the TrustStore type, and the relevant password. + */ + DefaultJdkTrustConfig() { + this(System::getProperty); + } + + /** + * Create a trust config that uses supplied {@link BiFunction} to determine the TrustStore type, and the relevant password. + */ + DefaultJdkTrustConfig(BiFunction systemProperties) { + this(systemProperties, isPkcs11Truststore(systemProperties) ? getSystemTrustStorePassword(systemProperties) : null); + } + + /** + * @param trustStorePassword the password for the truststore. It applies only when PKCS#11 tokens are used, is null otherwise + */ + DefaultJdkTrustConfig(BiFunction systemProperties, @Nullable char[] trustStorePassword) { + this.systemProperties = systemProperties; + this.trustStorePassword = trustStorePassword; + } + + @Override + public X509ExtendedTrustManager createTrustManager() { + try { + return KeyStoreUtil.createTrustManager(getSystemTrustStore(), TrustManagerFactory.getDefaultAlgorithm()); + } catch (GeneralSecurityException e) { + throw new SslConfigException("failed to initialize a TrustManager for the system keystore", e); + } + } + + /** + * When a PKCS#11 token is used as the system default keystore/truststore, we need to pass the keystore + * password when loading, even for reading certificates only ( as opposed to i.e. JKS keystores where + * we only need to pass the password for reading Private Key entries ). + * + * @return the KeyStore used as truststore for PKCS#11 initialized with the password, null otherwise + */ + private KeyStore getSystemTrustStore() { + if (isPkcs11Truststore(systemProperties) && trustStorePassword != null) { + try { + KeyStore keyStore = KeyStore.getInstance("PKCS11"); + keyStore.load(null, trustStorePassword); + return keyStore; + } catch (GeneralSecurityException | IOException e) { + throw new SslConfigException("failed to load the system PKCS#11 truststore", e); + } + } + return null; + } + + private static boolean isPkcs11Truststore(BiFunction systemProperties) { + return systemProperties.apply("javax.net.ssl.trustStoreType", "").equalsIgnoreCase("PKCS11"); + } + + private static char[] getSystemTrustStorePassword(BiFunction systemProperties) { + return systemProperties.apply("javax.net.ssl.trustStorePassword", "").toCharArray(); + } + + @Override + public Collection getDependentFiles() { + return Collections.emptyList(); + } + + @Override + public String toString() { + return "JDK-trusted-certs"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final DefaultJdkTrustConfig that = (DefaultJdkTrustConfig) o; + return Arrays.equals(this.trustStorePassword, that.trustStorePassword); + } + + @Override + public int hashCode() { + return Arrays.hashCode(trustStorePassword); + } +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/DerParser.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/DerParser.java new file mode 100644 index 0000000000000..da650369d508c --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/DerParser.java @@ -0,0 +1,297 @@ +/* + Copyright (c) 1998-2010 AOL Inc. + + Licensed 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.elasticsearch.common.ssl; + + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.util.Objects; + +/** + * A bare-minimum ASN.1 DER decoder, just having enough functions to + * decode PKCS#1 private keys in order to remain JCE/JVM agnostic. + *

    + * Based on https://github.com/groovenauts/jmeter_oauth_plugin/blob/master/jmeter/src/ + * main/java/org/apache/jmeter/protocol/oauth/sampler/PrivateKeyReader.java + */ +final class DerParser { + // Constructed Flag + private static final int CONSTRUCTED = 0x20; + + // Tag and data types + private static final int INTEGER = 0x02; + private static final int OCTET_STRING = 0x04; + private static final int OBJECT_OID = 0x06; + private static final int NUMERIC_STRING = 0x12; + private static final int PRINTABLE_STRING = 0x13; + private static final int VIDEOTEX_STRING = 0x15; + private static final int IA5_STRING = 0x16; + private static final int GRAPHIC_STRING = 0x19; + private static final int ISO646_STRING = 0x1A; + private static final int GENERAL_STRING = 0x1B; + + private static final int UTF8_STRING = 0x0C; + private static final int UNIVERSAL_STRING = 0x1C; + private static final int BMP_STRING = 0x1E; + + + private InputStream derInputStream; + private int maxAsnObjectLength; + + DerParser(byte[] bytes) { + this.derInputStream = new ByteArrayInputStream(bytes); + this.maxAsnObjectLength = bytes.length; + } + + Asn1Object readAsn1Object() throws IOException { + int tag = derInputStream.read(); + if (tag == -1) { + throw new IOException("Invalid DER: stream too short, missing tag"); + } + int length = getLength(); + // getLength() can return any 32 bit integer, so ensure that a corrupted encoding won't + // force us into allocating a very large array + if (length > maxAsnObjectLength) { + throw new IOException("Invalid DER: size of ASN.1 object to be parsed appears to be larger than the size of the key file " + + "itself."); + } + byte[] value = new byte[length]; + int n = derInputStream.read(value); + if (n < length) { + throw new IOException("Invalid DER: stream too short, missing value. " + + "Could only read " + n + " out of " + length + " bytes"); + } + return new Asn1Object(tag, length, value); + + } + + /** + * Decode the length of the field. Can only support length + * encoding up to 4 octets. + *

    + * In BER/DER encoding, length can be encoded in 2 forms: + *

    + *
      + *
    • Short form. One octet. Bit 8 has value "0" and bits 7-1 + * give the length. + *
    • + *
    • Long form. Two to 127 octets (only 4 is supported here). + * Bit 8 of first octet has value "1" and bits 7-1 give the + * number of additional length octets. Second and following + * octets give the length, base 256, most significant digit first. + *
    • + *
    + * + * @return The length as integer + */ + private int getLength() throws IOException { + + int i = derInputStream.read(); + if (i == -1) + throw new IOException("Invalid DER: length missing"); + + // A single byte short length + if ((i & ~0x7F) == 0) + return i; + + int num = i & 0x7F; + + // We can't handle length longer than 4 bytes + if (i >= 0xFF || num > 4) + throw new IOException("Invalid DER: length field too big (" + + i + ")"); //$NON-NLS-1$ + + byte[] bytes = new byte[num]; + int n = derInputStream.read(bytes); + if (n < num) + throw new IOException("Invalid DER: length too short"); + + return new BigInteger(1, bytes).intValue(); + } + + + /** + * An ASN.1 TLV. The object is not parsed. It can + * only handle integers. + * + * @author zhang + */ + static class Asn1Object { + + protected final int type; + protected final int length; + protected final byte[] value; + protected final int tag; + + /** + * Construct a ASN.1 TLV. The TLV could be either a + * constructed or primitive entity. + *

    + * The first byte in DER encoding is made of following fields: + *

    + *
    +         * -------------------------------------------------
    +         * |Bit 8|Bit 7|Bit 6|Bit 5|Bit 4|Bit 3|Bit 2|Bit 1|
    +         * -------------------------------------------------
    +         * |  Class    | CF  |     +      Type             |
    +         * -------------------------------------------------
    +         * 
    + *
      + *
    • Class: Universal, Application, Context or Private + *
    • CF: Constructed flag. If 1, the field is constructed. + *
    • Type: This is actually called tag in ASN.1. It + * indicates data type (Integer, String) or a construct + * (sequence, choice, set). + *
    + * + * @param tag Tag or Identifier + * @param length Length of the field + * @param value Encoded octet string for the field. + */ + Asn1Object(int tag, int length, byte[] value) { + this.tag = tag; + this.type = tag & 0x1F; + this.length = length; + this.value = value; + } + + public int getType() { + return type; + } + + public int getLength() { + return length; + } + + public byte[] getValue() { + return value; + } + + public boolean isConstructed() { + return (tag & DerParser.CONSTRUCTED) == DerParser.CONSTRUCTED; + } + + /** + * For constructed field, return a parser for its content. + * + * @return A parser for the construct. + */ + public DerParser getParser() throws IOException { + if (!isConstructed()) + throw new IOException("Invalid DER: can't parse primitive entity"); //$NON-NLS-1$ + + return new DerParser(value); + } + + /** + * Get the value as integer + * + * @return BigInteger + */ + public BigInteger getInteger() throws IOException { + if (type != DerParser.INTEGER) + throw new IOException("Invalid DER: object is not integer"); //$NON-NLS-1$ + + return new BigInteger(value); + } + + public String getString() throws IOException { + + String encoding; + + switch (type) { + case DerParser.OCTET_STRING: + // octet string is basically a byte array + return toHexString(value); + case DerParser.NUMERIC_STRING: + case DerParser.PRINTABLE_STRING: + case DerParser.VIDEOTEX_STRING: + case DerParser.IA5_STRING: + case DerParser.GRAPHIC_STRING: + case DerParser.ISO646_STRING: + case DerParser.GENERAL_STRING: + encoding = "ISO-8859-1"; //$NON-NLS-1$ + break; + + case DerParser.BMP_STRING: + encoding = "UTF-16BE"; //$NON-NLS-1$ + break; + + case DerParser.UTF8_STRING: + encoding = "UTF-8"; //$NON-NLS-1$ + break; + + case DerParser.UNIVERSAL_STRING: + throw new IOException("Invalid DER: can't handle UCS-4 string"); //$NON-NLS-1$ + + default: + throw new IOException("Invalid DER: object is not a string"); //$NON-NLS-1$ + } + + return new String(value, encoding); + } + + public String getOid() throws IOException { + + if (type != DerParser.OBJECT_OID) { + throw new IOException("Ivalid DER: object is not object OID"); + } + StringBuilder sb = new StringBuilder(64); + switch (value[0] / 40) { + case 0: + sb.append('0'); + break; + case 1: + sb.append('1'); + value[0] -= 40; + break; + default: + sb.append('2'); + value[0] -= 80; + break; + } + int oidPart = 0; + for (int i = 0; i < length; i++) { + oidPart = (oidPart << 7) + (value[i] & 0x7F); + if ((value[i] & 0x80) == 0) { + sb.append('.'); + sb.append(oidPart); + oidPart = 0; + } + } + + return sb.toString(); + } + } + + private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray(); + private static String toHexString(byte[] bytes) { + Objects.requireNonNull(bytes); + StringBuilder sb = new StringBuilder(2 * bytes.length); + + for (int i = 0; i < bytes.length; i++) { + byte b = bytes[i]; + sb.append(HEX_DIGITS[b >> 4 & 0xf]).append(HEX_DIGITS[b & 0xf]); + } + + return sb.toString(); + } + +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/EmptyKeyConfig.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/EmptyKeyConfig.java new file mode 100644 index 0000000000000..0844ffb7ee952 --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/EmptyKeyConfig.java @@ -0,0 +1,52 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import javax.net.ssl.X509ExtendedKeyManager; +import java.nio.file.Path; +import java.util.Collection; +import java.util.Collections; + +/** + * A {@link SslKeyConfig} that does nothing (provides a null key manager) + */ +final class EmptyKeyConfig implements SslKeyConfig { + + static final EmptyKeyConfig INSTANCE = new EmptyKeyConfig(); + + private EmptyKeyConfig() { + // Enforce a single instance + } + + @Override + public Collection getDependentFiles() { + return Collections.emptyList(); + } + + @Override + public X509ExtendedKeyManager createKeyManager() { + return null; + } + + @Override + public String toString() { + return "empty-key-config"; + } +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/KeyStoreUtil.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/KeyStoreUtil.java new file mode 100644 index 0000000000000..0a2526c7f7cfa --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/KeyStoreUtil.java @@ -0,0 +1,163 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import org.elasticsearch.common.Nullable; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509ExtendedKeyManager; +import javax.net.ssl.X509ExtendedTrustManager; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.util.Collection; +import java.util.Locale; + +/** + * A variety of utility methods for working with or constructing {@link KeyStore} instances. + */ +final class KeyStoreUtil { + + private KeyStoreUtil() { + throw new IllegalStateException("Utility class should not be instantiated"); + } + + /** + * Make a best guess about the "type" (see {@link KeyStore#getType()}) of the keystore file located at the given {@code Path}. + * This method only references the file name of the keystore, it does not look at its contents. + */ + static String inferKeyStoreType(Path path) { + String name = path == null ? "" : path.toString().toLowerCase(Locale.ROOT); + if (name.endsWith(".p12") || name.endsWith(".pfx") || name.endsWith(".pkcs12")) { + return "PKCS12"; + } else { + return "jks"; + } + } + + /** + * Read the given keystore file. + * + * @throws SslConfigException If there is a problem reading from the provided path + * @throws GeneralSecurityException If there is a problem with the keystore contents + */ + static KeyStore readKeyStore(Path path, String type, char[] password) throws GeneralSecurityException { + if (Files.notExists(path)) { + throw new SslConfigException("cannot read a [" + type + "] keystore from [" + path.toAbsolutePath() + + "] because the file does not exist"); + } + try { + KeyStore keyStore = KeyStore.getInstance(type); + try (InputStream in = Files.newInputStream(path)) { + keyStore.load(in, password); + } + return keyStore; + } catch (IOException e) { + throw new SslConfigException("cannot read a [" + type + "] keystore from [" + path.toAbsolutePath() + "] - " + e.getMessage(), + e); + } + } + + /** + * Construct an in-memory keystore with a single key entry. + * @param certificateChain A certificate chain (ordered from subject to issuer) + * @param privateKey The private key that corresponds to the subject certificate (index 0 of {@code certificateChain}) + * @param password The password for the private key + * + * @throws GeneralSecurityException If there is a problem with the provided certificates/key + */ + static KeyStore buildKeyStore(Collection certificateChain, PrivateKey privateKey, char[] password) + throws GeneralSecurityException { + KeyStore keyStore = buildNewKeyStore(); + keyStore.setKeyEntry("key", privateKey, password, certificateChain.toArray(new Certificate[0])); + return keyStore; + } + + /** + * Construct an in-memory keystore with multiple trusted cert entries. + * @param certificates The root certificates to trust + */ + static KeyStore buildTrustStore(Iterable certificates) throws GeneralSecurityException { + assert certificates != null : "Cannot create keystore with null certificates"; + KeyStore store = buildNewKeyStore(); + int counter = 0; + for (Certificate certificate : certificates) { + store.setCertificateEntry("cert-" + counter, certificate); + counter++; + } + return store; + } + + private static KeyStore buildNewKeyStore() throws GeneralSecurityException { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + try { + keyStore.load(null, null); + } catch (IOException e) { + // This should never happen so callers really shouldn't be forced to deal with it themselves. + throw new SslConfigException("Unexpected error initializing a new in-memory keystore", e); + } + return keyStore; + } + + /** + * Creates a {@link X509ExtendedKeyManager} based on the key material in the provided {@link KeyStore} + */ + static X509ExtendedKeyManager createKeyManager(KeyStore keyStore, char[] password, String algorithm) throws GeneralSecurityException { + KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); + kmf.init(keyStore, password); + KeyManager[] keyManagers = kmf.getKeyManagers(); + for (KeyManager keyManager : keyManagers) { + if (keyManager instanceof X509ExtendedKeyManager) { + return (X509ExtendedKeyManager) keyManager; + } + } + throw new SslConfigException("failed to find a X509ExtendedKeyManager in the key manager factory for [" + algorithm + + "] and keystore [" + keyStore + "]"); + } + + /** + * Creates a {@link X509ExtendedTrustManager} based on the trust material in the provided {@link KeyStore} + */ + static X509ExtendedTrustManager createTrustManager(@Nullable KeyStore trustStore, String algorithm) + throws NoSuchAlgorithmException, KeyStoreException { + TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); + tmf.init(trustStore); + TrustManager[] trustManagers = tmf.getTrustManagers(); + for (TrustManager trustManager : trustManagers) { + if (trustManager instanceof X509ExtendedTrustManager) { + return (X509ExtendedTrustManager) trustManager; + } + } + throw new SslConfigException("failed to find a X509ExtendedTrustManager in the trust manager factory for [" + algorithm + + "] and truststore [" + trustStore + "]"); + } + + +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemKeyConfig.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemKeyConfig.java new file mode 100644 index 0000000000000..dd091e0a22218 --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemKeyConfig.java @@ -0,0 +1,122 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.X509ExtendedKeyManager; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * A {@link SslKeyConfig} that reads from PEM formatted paths. + */ +public final class PemKeyConfig implements SslKeyConfig { + private final Path certificate; + private final Path key; + private final char[] keyPassword; + + public PemKeyConfig(Path certificate, Path key, char[] keyPassword) { + this.certificate = Objects.requireNonNull(certificate, "Certificate cannot be null"); + this.key = Objects.requireNonNull(key, "Key cannot be null"); + this.keyPassword = Objects.requireNonNull(keyPassword, "Key password cannot be null (but may be empty)"); + } + + @Override + public Collection getDependentFiles() { + return Arrays.asList(certificate, key); + } + + @Override + public X509ExtendedKeyManager createKeyManager() { + PrivateKey privateKey = getPrivateKey(); + List certificates = getCertificates(); + try { + final KeyStore keyStore = KeyStoreUtil.buildKeyStore(certificates, privateKey, keyPassword); + return KeyStoreUtil.createKeyManager(keyStore, keyPassword, KeyManagerFactory.getDefaultAlgorithm()); + } catch (GeneralSecurityException e) { + throw new SslConfigException("failed to load a KeyManager for certificate/key pair [" + certificate + "], [" + key + "]", e); + } + } + + private PrivateKey getPrivateKey() { + try { + final PrivateKey privateKey = PemUtils.readPrivateKey(key, () -> keyPassword); + if (privateKey == null) { + throw new SslConfigException("could not load ssl private key file [" + key + "]"); + } + return privateKey; + } catch (FileNotFoundException | NoSuchFileException e) { + throw new SslConfigException("the configured ssl private key file [" + key.toAbsolutePath() + "] does not exist", e); + } catch (IOException e) { + throw new SslConfigException("the configured ssl private key file [" + key.toAbsolutePath() + "] cannot be read", e); + } catch (GeneralSecurityException e) { + throw new SslConfigException("cannot load ssl private key file [" + key.toAbsolutePath() + "]", e); + } + } + + private List getCertificates() { + try { + return PemUtils.readCertificates(Collections.singleton(certificate)); + } catch (FileNotFoundException | NoSuchFileException e) { + throw new SslConfigException("the configured ssl certificate file [" + certificate.toAbsolutePath() + "] does not exist", e); + } catch (IOException e) { + throw new SslConfigException("the configured ssl certificate file [" + certificate .toAbsolutePath()+ "] cannot be read", e); + } catch (GeneralSecurityException e) { + throw new SslConfigException("cannot load ssl certificate from [" + certificate.toAbsolutePath() + "]", e); + } + } + + @Override + public String toString() { + return "PEM-key-config{cert=" + certificate.toAbsolutePath() + " key=" + key.toAbsolutePath() + "}"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final PemKeyConfig that = (PemKeyConfig) o; + return Objects.equals(this.certificate, that.certificate) && + Objects.equals(this.key, that.key) && + Arrays.equals(this.keyPassword, that.keyPassword); + } + + @Override + public int hashCode() { + int result = Objects.hash(certificate, key); + result = 31 * result + Arrays.hashCode(keyPassword); + return result; + } +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemTrustConfig.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemTrustConfig.java new file mode 100644 index 0000000000000..f3cf8cd8bd7aa --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemTrustConfig.java @@ -0,0 +1,122 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509ExtendedTrustManager; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * A {@link org.elasticsearch.common.ssl.SslTrustConfig} that reads a list of PEM encoded trusted certificates (CAs) from the file + * system. + * Strictly speaking, this class does not require PEM certificates, and will load any file that can be read by + * {@link java.security.cert.CertificateFactory#generateCertificate(InputStream)}. + */ +public final class PemTrustConfig implements SslTrustConfig { + private final List certificateAuthorities; + + /** + * Construct a new trust config for the provided paths. + * The paths are stored as-is, and are not read until {@link #createTrustManager()} is called. + * This means that + *
      + *
    1. validation of the file (contents and accessibility) is deferred, and this constructor will not fail on missing + * of invalid files.
    2. + *
    3. + * if the contents of the files are modified, then subsequent calls {@link #createTrustManager()} will return a new trust + * manager that trust a different set of CAs. + *
    4. + *
    + */ + public PemTrustConfig(List certificateAuthorities) { + this.certificateAuthorities = Collections.unmodifiableList(certificateAuthorities); + } + + @Override + public Collection getDependentFiles() { + return certificateAuthorities; + } + + @Override + public X509ExtendedTrustManager createTrustManager() { + try { + final List certificates = loadCertificates(); + KeyStore store = KeyStoreUtil.buildTrustStore(certificates); + return KeyStoreUtil.createTrustManager(store, TrustManagerFactory.getDefaultAlgorithm()); + } catch (GeneralSecurityException e) { + throw new SslConfigException("cannot create trust using PEM certificates [" + caPathsAsString() + "]", e); + } + } + + private List loadCertificates() throws CertificateException { + try { + return PemUtils.readCertificates(this.certificateAuthorities); + } catch (FileNotFoundException | NoSuchFileException e) { + throw new SslConfigException("cannot configure trust using PEM certificates [" + caPathsAsString() + + "] because one or more files do not exist", e); + } catch (IOException e) { + throw new SslConfigException("cannot configure trust using PEM certificates [" + caPathsAsString() + + "] because one or more files cannot be read", e); + } + } + + @Override + public String toString() { + return "PEM-trust{" + caPathsAsString() + "}"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final PemTrustConfig that = (PemTrustConfig) o; + return Objects.equals(this.certificateAuthorities, that.certificateAuthorities); + } + + @Override + public int hashCode() { + return Objects.hash(certificateAuthorities); + } + + private String caPathsAsString() { + return certificateAuthorities.stream() + .map(Path::toAbsolutePath) + .map(Object::toString) + .collect(Collectors.joining(",")); + } + +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java new file mode 100644 index 0000000000000..aca7ba56b2ae9 --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java @@ -0,0 +1,613 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import org.elasticsearch.common.CharArrays; + +import javax.crypto.Cipher; +import javax.crypto.EncryptedPrivateKeyInfo; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.interfaces.ECKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +final class PemUtils { + + private static final String PKCS1_HEADER = "-----BEGIN RSA PRIVATE KEY-----"; + private static final String PKCS1_FOOTER = "-----END RSA PRIVATE KEY-----"; + private static final String OPENSSL_DSA_HEADER = "-----BEGIN DSA PRIVATE KEY-----"; + private static final String OPENSSL_DSA_FOOTER = "-----END DSA PRIVATE KEY-----"; + private static final String OPENSSL_DSA_PARAMS_HEADER ="-----BEGIN DSA PARAMETERS-----"; + private static final String OPENSSL_DSA_PARAMS_FOOTER ="-----END DSA PARAMETERS-----"; + private static final String PKCS8_HEADER = "-----BEGIN PRIVATE KEY-----"; + private static final String PKCS8_FOOTER = "-----END PRIVATE KEY-----"; + private static final String PKCS8_ENCRYPTED_HEADER = "-----BEGIN ENCRYPTED PRIVATE KEY-----"; + private static final String PKCS8_ENCRYPTED_FOOTER = "-----END ENCRYPTED PRIVATE KEY-----"; + private static final String OPENSSL_EC_HEADER = "-----BEGIN EC PRIVATE KEY-----"; + private static final String OPENSSL_EC_FOOTER = "-----END EC PRIVATE KEY-----"; + private static final String OPENSSL_EC_PARAMS_HEADER = "-----BEGIN EC PARAMETERS-----"; + private static final String OPENSSL_EC_PARAMS_FOOTER = "-----END EC PARAMETERS-----"; + private static final String HEADER = "-----BEGIN"; + + private PemUtils() { + throw new IllegalStateException("Utility class should not be instantiated"); + } + + /** + * Creates a {@link PrivateKey} from the contents of a file. Supports PKCS#1, PKCS#8 + * encoded formats of encrypted and plaintext RSA, DSA and EC(secp256r1) keys + * + * @param keyPath the path for the key file + * @param passwordSupplier A password supplier for the potentially encrypted (password protected) key + * @return a private key from the contents of the file + */ + public static PrivateKey readPrivateKey(Path keyPath, Supplier passwordSupplier) throws IOException, GeneralSecurityException { + try (BufferedReader bReader = Files.newBufferedReader(keyPath, StandardCharsets.UTF_8)) { + String line = bReader.readLine(); + while (null != line && line.startsWith(HEADER) == false) { + line = bReader.readLine(); + } + if (null == line) { + throw new SslConfigException("Error parsing Private Key [" + keyPath.toAbsolutePath() + "], file is empty"); + } + if (PKCS8_ENCRYPTED_HEADER.equals(line.trim())) { + char[] password = passwordSupplier.get(); + if (password == null) { + throw new SslConfigException("cannot read encrypted key [" + keyPath.toAbsolutePath() + "] without a password"); + } + return parsePKCS8Encrypted(bReader, password); + } else if (PKCS8_HEADER.equals(line.trim())) { + return parsePKCS8(bReader); + } else if (PKCS1_HEADER.equals(line.trim())) { + return parsePKCS1Rsa(bReader, passwordSupplier); + } else if (OPENSSL_DSA_HEADER.equals(line.trim())) { + return parseOpenSslDsa(bReader, passwordSupplier); + } else if (OPENSSL_DSA_PARAMS_HEADER.equals(line.trim())) { + return parseOpenSslDsa(removeDsaHeaders(bReader), passwordSupplier); + } else if (OPENSSL_EC_HEADER.equals(line.trim())) { + return parseOpenSslEC(bReader, passwordSupplier); + } else if (OPENSSL_EC_PARAMS_HEADER.equals(line.trim())) { + return parseOpenSslEC(removeECHeaders(bReader), passwordSupplier); + } else { + throw new SslConfigException("error parsing Private Key [" + keyPath.toAbsolutePath() + + "], file does not contain a supported key format"); + } + } catch (FileNotFoundException | NoSuchFileException e) { + throw new SslConfigException("private key file [" + keyPath.toAbsolutePath() + "] does not exist", e); + } catch (IOException | GeneralSecurityException e) { + throw new SslConfigException("private key file [" + keyPath.toAbsolutePath() + "] cannot be parsed", e); + } + } + + /** + * Removes the EC Headers that OpenSSL adds to EC private keys as the information in them + * is redundant + * + * @throws IOException if the EC Parameter footer is missing + */ + private static BufferedReader removeECHeaders(BufferedReader bReader) throws IOException { + String line = bReader.readLine(); + while (line != null) { + if (OPENSSL_EC_PARAMS_FOOTER.equals(line.trim())) { + break; + } + line = bReader.readLine(); + } + if (null == line || OPENSSL_EC_PARAMS_FOOTER.equals(line.trim()) == false) { + throw new IOException("Malformed PEM file, EC Parameters footer is missing"); + } + // Verify that the key starts with the correct header before passing it to parseOpenSslEC + if (OPENSSL_EC_HEADER.equals(bReader.readLine()) == false) { + throw new IOException("Malformed PEM file, EC Key header is missing"); + } + return bReader; + } + + /** + * Removes the DSA Params Headers that OpenSSL adds to DSA private keys as the information in them + * is redundant + * + * @throws IOException if the EC Parameter footer is missing + */ + private static BufferedReader removeDsaHeaders(BufferedReader bReader) throws IOException { + String line = bReader.readLine(); + while (line != null) { + if (OPENSSL_DSA_PARAMS_FOOTER.equals(line.trim())) { + break; + } + line = bReader.readLine(); + } + if (null == line || OPENSSL_DSA_PARAMS_FOOTER.equals(line.trim()) == false) { + throw new IOException("Malformed PEM file, DSA Parameters footer is missing"); + } + // Verify that the key starts with the correct header before passing it to parseOpenSslDsa + if (OPENSSL_DSA_HEADER.equals(bReader.readLine()) == false) { + throw new IOException("Malformed PEM file, DSA Key header is missing"); + } + return bReader; + } + + /** + * Creates a {@link PrivateKey} from the contents of {@code bReader} that contains an plaintext private key encoded in + * PKCS#8 + * + * @param bReader the {@link BufferedReader} containing the key file contents + * @return {@link PrivateKey} + * @throws IOException if the file can't be read + * @throws GeneralSecurityException if the private key can't be generated from the {@link PKCS8EncodedKeySpec} + */ + private static PrivateKey parsePKCS8(BufferedReader bReader) throws IOException, GeneralSecurityException { + StringBuilder sb = new StringBuilder(); + String line = bReader.readLine(); + while (line != null) { + if (PKCS8_FOOTER.equals(line.trim())) { + break; + } + sb.append(line.trim()); + line = bReader.readLine(); + } + if (null == line || PKCS8_FOOTER.equals(line.trim()) == false) { + throw new IOException("Malformed PEM file, PEM footer is invalid or missing"); + } + byte[] keyBytes = Base64.getDecoder().decode(sb.toString()); + String keyAlgo = getKeyAlgorithmIdentifier(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(keyAlgo); + return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyBytes)); + } + + /** + * Creates a {@link PrivateKey} from the contents of {@code bReader} that contains an EC private key encoded in + * OpenSSL traditional format. + * + * @param bReader the {@link BufferedReader} containing the key file contents + * @param passwordSupplier A password supplier for the potentially encrypted (password protected) key + * @return {@link PrivateKey} + * @throws IOException if the file can't be read + * @throws GeneralSecurityException if the private key can't be generated from the {@link ECPrivateKeySpec} + */ + private static PrivateKey parseOpenSslEC(BufferedReader bReader, Supplier passwordSupplier) throws IOException, + GeneralSecurityException { + StringBuilder sb = new StringBuilder(); + String line = bReader.readLine(); + Map pemHeaders = new HashMap<>(); + while (line != null) { + if (OPENSSL_EC_FOOTER.equals(line.trim())) { + break; + } + // Parse PEM headers according to https://www.ietf.org/rfc/rfc1421.txt + if (line.contains(":")) { + String[] header = line.split(":"); + pemHeaders.put(header[0].trim(), header[1].trim()); + } else { + sb.append(line.trim()); + } + line = bReader.readLine(); + } + if (null == line || OPENSSL_EC_FOOTER.equals(line.trim()) == false) { + throw new IOException("Malformed PEM file, PEM footer is invalid or missing"); + } + byte[] keyBytes = possiblyDecryptPKCS1Key(pemHeaders, sb.toString(), passwordSupplier); + KeyFactory keyFactory = KeyFactory.getInstance("EC"); + ECPrivateKeySpec ecSpec = parseEcDer(keyBytes); + return keyFactory.generatePrivate(ecSpec); + } + + /** + * Creates a {@link PrivateKey} from the contents of {@code bReader} that contains an RSA private key encoded in + * OpenSSL traditional format. + * + * @param bReader the {@link BufferedReader} containing the key file contents + * @param passwordSupplier A password supplier for the potentially encrypted (password protected) key + * @return {@link PrivateKey} + * @throws IOException if the file can't be read + * @throws GeneralSecurityException if the private key can't be generated from the {@link RSAPrivateCrtKeySpec} + */ + private static PrivateKey parsePKCS1Rsa(BufferedReader bReader, Supplier passwordSupplier) throws IOException, + GeneralSecurityException { + StringBuilder sb = new StringBuilder(); + String line = bReader.readLine(); + Map pemHeaders = new HashMap<>(); + + while (line != null) { + if (PKCS1_FOOTER.equals(line.trim())) { + // Unencrypted + break; + } + // Parse PEM headers according to https://www.ietf.org/rfc/rfc1421.txt + if (line.contains(":")) { + String[] header = line.split(":"); + pemHeaders.put(header[0].trim(), header[1].trim()); + } else { + sb.append(line.trim()); + } + line = bReader.readLine(); + } + if (null == line || PKCS1_FOOTER.equals(line.trim()) == false) { + throw new IOException("Malformed PEM file, PEM footer is invalid or missing"); + } + byte[] keyBytes = possiblyDecryptPKCS1Key(pemHeaders, sb.toString(), passwordSupplier); + RSAPrivateCrtKeySpec spec = parseRsaDer(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePrivate(spec); + } + + /** + * Creates a {@link PrivateKey} from the contents of {@code bReader} that contains an DSA private key encoded in + * OpenSSL traditional format. + * + * @param bReader the {@link BufferedReader} containing the key file contents + * @param passwordSupplier A password supplier for the potentially encrypted (password protected) key + * @return {@link PrivateKey} + * @throws IOException if the file can't be read + * @throws GeneralSecurityException if the private key can't be generated from the {@link DSAPrivateKeySpec} + */ + private static PrivateKey parseOpenSslDsa(BufferedReader bReader, Supplier passwordSupplier) throws IOException, + GeneralSecurityException { + StringBuilder sb = new StringBuilder(); + String line = bReader.readLine(); + Map pemHeaders = new HashMap<>(); + + while (line != null) { + if (OPENSSL_DSA_FOOTER.equals(line.trim())) { + // Unencrypted + break; + } + // Parse PEM headers according to https://www.ietf.org/rfc/rfc1421.txt + if (line.contains(":")) { + String[] header = line.split(":"); + pemHeaders.put(header[0].trim(), header[1].trim()); + } else { + sb.append(line.trim()); + } + line = bReader.readLine(); + } + if (null == line || OPENSSL_DSA_FOOTER.equals(line.trim()) == false) { + throw new IOException("Malformed PEM file, PEM footer is invalid or missing"); + } + byte[] keyBytes = possiblyDecryptPKCS1Key(pemHeaders, sb.toString(), passwordSupplier); + DSAPrivateKeySpec spec = parseDsaDer(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("DSA"); + return keyFactory.generatePrivate(spec); + } + + /** + * Creates a {@link PrivateKey} from the contents of {@code bReader} that contains an encrypted private key encoded in + * PKCS#8 + * + * @param bReader the {@link BufferedReader} containing the key file contents + * @param keyPassword The password for the encrypted (password protected) key + * @return {@link PrivateKey} + * @throws IOException if the file can't be read + * @throws GeneralSecurityException if the private key can't be generated from the {@link PKCS8EncodedKeySpec} + */ + private static PrivateKey parsePKCS8Encrypted(BufferedReader bReader, char[] keyPassword) throws IOException, + GeneralSecurityException { + StringBuilder sb = new StringBuilder(); + String line = bReader.readLine(); + while (line != null) { + if (PKCS8_ENCRYPTED_FOOTER.equals(line.trim())) { + break; + } + sb.append(line.trim()); + line = bReader.readLine(); + } + if (null == line || PKCS8_ENCRYPTED_FOOTER.equals(line.trim()) == false) { + throw new IOException("Malformed PEM file, PEM footer is invalid or missing"); + } + byte[] keyBytes = Base64.getDecoder().decode(sb.toString()); + + EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = new EncryptedPrivateKeyInfo(keyBytes); + SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(encryptedPrivateKeyInfo.getAlgName()); + SecretKey secretKey = secretKeyFactory.generateSecret(new PBEKeySpec(keyPassword)); + Arrays.fill(keyPassword, '\u0000'); + Cipher cipher = Cipher.getInstance(encryptedPrivateKeyInfo.getAlgName()); + cipher.init(Cipher.DECRYPT_MODE, secretKey, encryptedPrivateKeyInfo.getAlgParameters()); + PKCS8EncodedKeySpec keySpec = encryptedPrivateKeyInfo.getKeySpec(cipher); + String keyAlgo = getKeyAlgorithmIdentifier(keySpec.getEncoded()); + KeyFactory keyFactory = KeyFactory.getInstance(keyAlgo); + return keyFactory.generatePrivate(keySpec); + } + + /** + * Decrypts the password protected contents using the algorithm and IV that is specified in the PEM Headers of the file + * + * @param pemHeaders The Proc-Type and DEK-Info PEM headers that have been extracted from the key file + * @param keyContents The key as a base64 encoded String + * @param passwordSupplier A password supplier for the encrypted (password protected) key + * @return the decrypted key bytes + * @throws GeneralSecurityException if the key can't be decrypted + * @throws IOException if the PEM headers are missing or malformed + */ + private static byte[] possiblyDecryptPKCS1Key(Map pemHeaders, String keyContents, Supplier passwordSupplier) + throws GeneralSecurityException, IOException { + byte[] keyBytes = Base64.getDecoder().decode(keyContents); + String procType = pemHeaders.get("Proc-Type"); + if ("4,ENCRYPTED".equals(procType)) { + //We only handle PEM encryption + String encryptionParameters = pemHeaders.get("DEK-Info"); + if (null == encryptionParameters) { + //malformed pem + throw new IOException("Malformed PEM File, DEK-Info header is missing"); + } + char[] password = passwordSupplier.get(); + if (password == null) { + throw new IOException("cannot read encrypted key without a password"); + } + Cipher cipher = getCipherFromParameters(encryptionParameters, password); + byte[] decryptedKeyBytes = cipher.doFinal(keyBytes); + return decryptedKeyBytes; + } + return keyBytes; + } + + /** + * Creates a {@link Cipher} from the contents of the DEK-Info header of a PEM file. RFC 1421 indicates that supported algorithms are + * defined in RFC 1423. RFC 1423 only defines DES-CBS and triple DES (EDE) in CBC mode. AES in CBC mode is also widely used though ( 3 + * different variants of 128, 192, 256 bit keys ) + * + * @param dekHeaderValue The value of the the DEK-Info PEM header + * @param password The password with which the key is encrypted + * @return a cipher of the appropriate algorithm and parameters to be used for decryption + * @throws GeneralSecurityException if the algorithm is not available in the used security provider, or if the key is inappropriate + * for the cipher + * @throws IOException if the DEK-Info PEM header is invalid + */ + private static Cipher getCipherFromParameters(String dekHeaderValue, char[] password) throws + GeneralSecurityException, IOException { + final String padding = "PKCS5Padding"; + final SecretKey encryptionKey; + final String[] valueTokens = dekHeaderValue.split(","); + if (valueTokens.length != 2) { + throw new IOException("Malformed PEM file, DEK-Info PEM header is invalid"); + } + final String algorithm = valueTokens[0]; + final String ivString = valueTokens[1]; + final byte[] iv; + try { + iv = hexStringToByteArray(ivString); + } catch (IllegalArgumentException e) { + throw new IOException("Malformed PEM file, DEK-Info IV is invalid", e); + } + if ("DES-CBC".equals(algorithm)) { + byte[] key = generateOpenSslKey(password, iv, 8); + encryptionKey = new SecretKeySpec(key, "DES"); + } else if ("DES-EDE3-CBC".equals(algorithm)) { + byte[] key = generateOpenSslKey(password, iv, 24); + encryptionKey = new SecretKeySpec(key, "DESede"); + } else if ("AES-128-CBC".equals(algorithm)) { + byte[] key = generateOpenSslKey(password, iv, 16); + encryptionKey = new SecretKeySpec(key, "AES"); + } else if ("AES-192-CBC".equals(algorithm)) { + byte[] key = generateOpenSslKey(password, iv, 24); + encryptionKey = new SecretKeySpec(key, "AES"); + } else if ("AES-256-CBC".equals(algorithm)) { + byte[] key = generateOpenSslKey(password, iv, 32); + encryptionKey = new SecretKeySpec(key, "AES"); + } else { + throw new GeneralSecurityException("Private Key encrypted with unsupported algorithm [" + algorithm + "]"); + } + String transformation = encryptionKey.getAlgorithm() + "/" + "CBC" + "/" + padding; + Cipher cipher = Cipher.getInstance(transformation); + cipher.init(Cipher.DECRYPT_MODE, encryptionKey, new IvParameterSpec(iv)); + return cipher; + } + + /** + * Performs key stretching in the same manner that OpenSSL does. This is basically a KDF + * that uses n rounds of salted MD5 (as many times as needed to get the necessary number of key bytes) + *

    + * https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_PrivateKey_traditional.html + */ + private static byte[] generateOpenSslKey(char[] password, byte[] salt, int keyLength) { + byte[] passwordBytes = CharArrays.toUtf8Bytes(password); + MessageDigest md5 = messageDigest("md5"); + byte[] key = new byte[keyLength]; + int copied = 0; + int remaining; + while (copied < keyLength) { + remaining = keyLength - copied; + md5.update(passwordBytes, 0, passwordBytes.length); + md5.update(salt, 0, 8);// AES IV (salt) is longer but we only need 8 bytes + byte[] tempDigest = md5.digest(); + int bytesToCopy = (remaining > 16) ? 16 : remaining; // MD5 digests are 16 bytes + System.arraycopy(tempDigest, 0, key, copied, bytesToCopy); + copied += bytesToCopy; + if (remaining == 0) { + break; + } + md5.update(tempDigest, 0, 16); // use previous round digest as IV + } + Arrays.fill(passwordBytes, (byte) 0); + return key; + } + + /** + * Converts a hexadecimal string to a byte array + */ + private static byte[] hexStringToByteArray(String hexString) { + int len = hexString.length(); + if (len % 2 == 0) { + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + final int k = Character.digit(hexString.charAt(i), 16); + final int l = Character.digit(hexString.charAt(i + 1), 16); + if (k == -1 || l == -1) { + throw new IllegalStateException("String [" + hexString + "] is not hexadecimal"); + } + data[i / 2] = (byte) ((k << 4) + l); + } + return data; + } else { + throw new IllegalStateException("Hexadecimal string [" + hexString + + "] has odd length and cannot be converted to a byte array"); + } + } + + /** + * Parses a DER encoded EC key to an {@link ECPrivateKeySpec} using a minimal {@link DerParser} + * + * @param keyBytes the private key raw bytes + * @return {@link ECPrivateKeySpec} + * @throws IOException if the DER encoded key can't be parsed + */ + private static ECPrivateKeySpec parseEcDer(byte[] keyBytes) throws IOException, + GeneralSecurityException { + DerParser parser = new DerParser(keyBytes); + DerParser.Asn1Object sequence = parser.readAsn1Object(); + parser = sequence.getParser(); + parser.readAsn1Object().getInteger(); // version + String keyHex = parser.readAsn1Object().getString(); + BigInteger privateKeyInt = new BigInteger(keyHex, 16); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC"); + AlgorithmParameterSpec prime256v1ParamSpec = new ECGenParameterSpec("secp256r1"); + keyPairGenerator.initialize(prime256v1ParamSpec); + ECParameterSpec parameterSpec = ((ECKey) keyPairGenerator.generateKeyPair().getPrivate()).getParams(); + return new ECPrivateKeySpec(privateKeyInt, parameterSpec); + } + + /** + * Parses a DER encoded RSA key to a {@link RSAPrivateCrtKeySpec} using a minimal {@link DerParser} + * + * @param keyBytes the private key raw bytes + * @return {@link RSAPrivateCrtKeySpec} + * @throws IOException if the DER encoded key can't be parsed + */ + private static RSAPrivateCrtKeySpec parseRsaDer(byte[] keyBytes) throws IOException { + DerParser parser = new DerParser(keyBytes); + DerParser.Asn1Object sequence = parser.readAsn1Object(); + parser = sequence.getParser(); + parser.readAsn1Object().getInteger(); // (version) We don't need it but must read to get to modulus + BigInteger modulus = parser.readAsn1Object().getInteger(); + BigInteger publicExponent = parser.readAsn1Object().getInteger(); + BigInteger privateExponent = parser.readAsn1Object().getInteger(); + BigInteger prime1 = parser.readAsn1Object().getInteger(); + BigInteger prime2 = parser.readAsn1Object().getInteger(); + BigInteger exponent1 = parser.readAsn1Object().getInteger(); + BigInteger exponent2 = parser.readAsn1Object().getInteger(); + BigInteger coefficient = parser.readAsn1Object().getInteger(); + return new RSAPrivateCrtKeySpec(modulus, publicExponent, privateExponent, prime1, prime2, exponent1, exponent2, coefficient); + } + + /** + * Parses a DER encoded DSA key to a {@link DSAPrivateKeySpec} using a minimal {@link DerParser} + * + * @param keyBytes the private key raw bytes + * @return {@link DSAPrivateKeySpec} + * @throws IOException if the DER encoded key can't be parsed + */ + private static DSAPrivateKeySpec parseDsaDer(byte[] keyBytes) throws IOException { + DerParser parser = new DerParser(keyBytes); + DerParser.Asn1Object sequence = parser.readAsn1Object(); + parser = sequence.getParser(); + parser.readAsn1Object().getInteger(); // (version) We don't need it but must read to get to p + BigInteger p = parser.readAsn1Object().getInteger(); + BigInteger q = parser.readAsn1Object().getInteger(); + BigInteger g = parser.readAsn1Object().getInteger(); + parser.readAsn1Object().getInteger(); // we don't need x + BigInteger x = parser.readAsn1Object().getInteger(); + return new DSAPrivateKeySpec(x, p, q, g); + } + + /** + * Parses a DER encoded private key and reads its algorithm identifier Object OID. + * + * @param keyBytes the private key raw bytes + * @return A string identifier for the key algorithm (RSA, DSA, or EC) + * @throws GeneralSecurityException if the algorithm oid that is parsed from ASN.1 is unknown + * @throws IOException if the DER encoded key can't be parsed + */ + private static String getKeyAlgorithmIdentifier(byte[] keyBytes) throws IOException, GeneralSecurityException { + DerParser parser = new DerParser(keyBytes); + DerParser.Asn1Object sequence = parser.readAsn1Object(); + parser = sequence.getParser(); + parser.readAsn1Object().getInteger(); // version + DerParser.Asn1Object algSequence = parser.readAsn1Object(); + parser = algSequence.getParser(); + String oidString = parser.readAsn1Object().getOid(); + switch (oidString) { + case "1.2.840.10040.4.1": + return "DSA"; + case "1.2.840.113549.1.1.1": + return "RSA"; + case "1.2.840.10045.2.1": + return "EC"; + } + throw new GeneralSecurityException("Error parsing key algorithm identifier. Algorithm with OID [" + oidString + + "] is not żsupported"); + } + + static List readCertificates(Collection certPaths) throws CertificateException, IOException { + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + List certificates = new ArrayList<>(certPaths.size()); + for (Path path : certPaths) { + try (InputStream input = Files.newInputStream(path)) { + final Collection parsed = certFactory.generateCertificates(input); + if (parsed.isEmpty()) { + throw new SslConfigException("failed to parse any certificates from [" + path.toAbsolutePath() + "]"); + } + certificates.addAll(parsed); + } + } + return certificates; + } + + private static MessageDigest messageDigest(String digestAlgorithm) { + try { + return MessageDigest.getInstance(digestAlgorithm); + } catch (NoSuchAlgorithmException e) { + throw new SslConfigException("unexpected exception creating MessageDigest instance for [" + digestAlgorithm + "]", e); + } + } +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslClientAuthenticationMode.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslClientAuthenticationMode.java new file mode 100644 index 0000000000000..8a972b6c78826 --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslClientAuthenticationMode.java @@ -0,0 +1,101 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import javax.net.ssl.SSLParameters; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * The client authentication mode that is used for SSL servers. + */ +public enum SslClientAuthenticationMode { + + /** + * Never request a client certificate. + */ + NONE() { + public boolean enabled() { + return false; + } + + public void configure(SSLParameters sslParameters) { + // nothing to do here + assert !sslParameters.getWantClientAuth(); + assert !sslParameters.getNeedClientAuth(); + } + }, + /** + * Request a client certificate, but do not enforce that one is provided. + */ + OPTIONAL() { + public boolean enabled() { + return true; + } + + public void configure(SSLParameters sslParameters) { + sslParameters.setWantClientAuth(true); + } + }, + /** + * Request and require a client certificate. + */ + REQUIRED() { + public boolean enabled() { + return true; + } + + public void configure(SSLParameters sslParameters) { + sslParameters.setNeedClientAuth(true); + } + }; + + /** + * @return true if client authentication is enabled + */ + public abstract boolean enabled(); + + /** + * Configure client authentication of the provided {@link SSLParameters} + */ + public abstract void configure(SSLParameters sslParameters); + + private static final Map LOOKUP = Collections.unmodifiableMap(buildLookup()); + + static Map buildLookup() { + final Map map = new LinkedHashMap<>(3); + map.put("none", NONE); + map.put("optional", OPTIONAL); + map.put("required", REQUIRED); + return map; + } + + public static SslClientAuthenticationMode parse(String value) { + final SslClientAuthenticationMode mode = LOOKUP.get(value.toLowerCase(Locale.ROOT)); + if (mode == null) { + final String allowedValues = LOOKUP.keySet().stream().collect(Collectors.joining(",")); + throw new SslConfigException("could not resolve ssl client authentication, unknown value [" + + value + "], recognised values are [" + allowedValues + "]"); + } + return mode; + } +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigException.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigException.java new file mode 100644 index 0000000000000..ae5d332e0a1e7 --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigException.java @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +/** + * A base exception for problems that occur while trying to configure SSL. + */ +public class SslConfigException extends RuntimeException { + public SslConfigException(String message, Exception cause) { + super(message, cause); + } + + public SslConfigException(String message) { + super(message); + } +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfiguration.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfiguration.java new file mode 100644 index 0000000000000..146ba916b6b07 --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfiguration.java @@ -0,0 +1,164 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.X509ExtendedKeyManager; +import javax.net.ssl.X509ExtendedTrustManager; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * A object encapsulating all necessary configuration for an SSL context (client or server). + * The configuration itself is immutable, but the {@link #getKeyConfig() key config} and + * {@link #getTrustConfig() trust config} may depend on reading key and certificate material + * from files (see {@link #getDependentFiles()}, and the content of those files may change. + */ +public class SslConfiguration { + + private final SslTrustConfig trustConfig; + private final SslKeyConfig keyConfig; + private final SslVerificationMode verificationMode; + private final SslClientAuthenticationMode clientAuth; + private final List ciphers; + private final List supportedProtocols; + + public SslConfiguration(SslTrustConfig trustConfig, SslKeyConfig keyConfig, SslVerificationMode verificationMode, + SslClientAuthenticationMode clientAuth, List ciphers, List supportedProtocols) { + if (ciphers == null || ciphers.isEmpty()) { + throw new SslConfigException("cannot configure SSL/TLS without any supported cipher suites"); + } + if (supportedProtocols == null || supportedProtocols.isEmpty()) { + throw new SslConfigException("cannot configure SSL/TLS without any supported protocols"); + } + this.trustConfig = Objects.requireNonNull(trustConfig, "trust config cannot be null"); + this.keyConfig = Objects.requireNonNull(keyConfig, "key config cannot be null"); + this.verificationMode = Objects.requireNonNull(verificationMode, "verification mode cannot be null"); + this.clientAuth = Objects.requireNonNull(clientAuth, "client authentication cannot be null"); + this.ciphers = Collections.unmodifiableList(ciphers); + this.supportedProtocols = Collections.unmodifiableList(supportedProtocols); + } + + public SslTrustConfig getTrustConfig() { + return trustConfig; + } + + public SslKeyConfig getKeyConfig() { + return keyConfig; + } + + public SslVerificationMode getVerificationMode() { + return verificationMode; + } + + public SslClientAuthenticationMode getClientAuth() { + return clientAuth; + } + + public List getCipherSuites() { + return ciphers; + } + + public List getSupportedProtocols() { + return supportedProtocols; + } + + /** + * @return A collection of files that are used by this SSL configuration. If the contents of these files change, then any + * subsequent call to {@link #createSslContext()} (or similar methods) may create a context with different behaviour. + * It is recommended that these files be monitored for changes, and a new ssl-context is created whenever any of the files are modified. + */ + public Collection getDependentFiles() { + Set paths = new HashSet<>(keyConfig.getDependentFiles()); + paths.addAll(trustConfig.getDependentFiles()); + return paths; + } + + /** + * Dynamically create a new SSL context based on the current state of the configuration. + * Because the {@link #getKeyConfig() key config} and {@link #getTrustConfig() trust config} may change based on the + * contents of their referenced files (see {@link #getDependentFiles()}, consecutive calls to this method may + * return ssl-contexts with different configurations. + */ + public SSLContext createSslContext() { + final X509ExtendedKeyManager keyManager = keyConfig.createKeyManager(); + final X509ExtendedTrustManager trustManager = trustConfig.createTrustManager(); + try { + SSLContext sslContext = SSLContext.getInstance(contextProtocol()); + sslContext.init(new X509ExtendedKeyManager[] { keyManager }, new X509ExtendedTrustManager[] { trustManager }, null); + return sslContext; + } catch (GeneralSecurityException e) { + throw new SslConfigException("cannot create ssl context", e); + } + } + + /** + * Picks the best (highest security / most recent standard) SSL/TLS protocol (/version) that is supported by the + * {@link #getSupportedProtocols() configured protocols}. + */ + private String contextProtocol() { + if (supportedProtocols.isEmpty()) { + throw new SslConfigException("no SSL/TLS protocols have been configured"); + } + for (String tryProtocol : Arrays.asList("TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3")) { + if (supportedProtocols.contains(tryProtocol)) { + return tryProtocol; + } + } + return "SSL"; + } + + @Override + public String toString() { + return getClass().getSimpleName() + '{' + + "trustConfig=" + trustConfig + + ", keyConfig=" + keyConfig + + ", verificationMode=" + verificationMode + + ", clientAuth=" + clientAuth + + ", ciphers=" + ciphers + + ", supportedProtocols=" + supportedProtocols + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final SslConfiguration that = (SslConfiguration) o; + return Objects.equals(this.trustConfig, that.trustConfig) && + Objects.equals(this.keyConfig, that.keyConfig) && + this.verificationMode == that.verificationMode && + this.clientAuth == that.clientAuth && + Objects.equals(this.ciphers, that.ciphers) && + Objects.equals(this.supportedProtocols, that.supportedProtocols); + } + + @Override + public int hashCode() { + return Objects.hash(trustConfig, keyConfig, verificationMode, clientAuth, ciphers, supportedProtocols); + } +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationKeys.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationKeys.java new file mode 100644 index 0000000000000..6e717f1c4cd11 --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationKeys.java @@ -0,0 +1,181 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import javax.net.ssl.TrustManagerFactory; +import java.security.KeyStore; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Utility class for handling the standard setting keys for use in SSL configuration. + * + * @see SslConfiguration + * @see SslConfigurationLoader + */ +public class SslConfigurationKeys { + /** + * The SSL/TLS protocols (i.e. versions) that should be used + */ + public static final String PROTOCOLS = "supported_protocols"; + + /** + * The SSL/TLS cipher suites that should be used + */ + public static final String CIPHERS = "cipher_suites"; + + /** + * Whether certificate and/or hostname verification should be used + */ + public static final String VERIFICATION_MODE = "verification_mode"; + + /** + * When operating as a server, whether to request/require client certificates + */ + public static final String CLIENT_AUTH = "client_authentication"; + + // Trust + /** + * A list of paths to PEM formatted certificates that should be trusted as CAs + */ + public static final String CERTIFICATE_AUTHORITIES = "certificate_authorities"; + /** + * The path to a KeyStore file (in a format supported by this JRE) that should be used as a trust-store + */ + public static final String TRUSTSTORE_PATH = "truststore.path"; + /** + * The password for the file configured in {@link #TRUSTSTORE_PATH}, as a secure setting. + */ + public static final String TRUSTSTORE_SECURE_PASSWORD = "truststore.secure_password"; + /** + * The password for the file configured in {@link #TRUSTSTORE_PATH}, as a non-secure setting. + * The use of this setting {@link #isDeprecated(String) is deprecated}. + */ + public static final String TRUSTSTORE_LEGACY_PASSWORD = "truststore.password"; + /** + * The {@link KeyStore#getType() keystore type} for the file configured in {@link #TRUSTSTORE_PATH}. + */ + public static final String TRUSTSTORE_TYPE = "truststore.type"; + /** + * The {@link TrustManagerFactory#getAlgorithm() trust management algorithm} to use when configuring trust + * with a {@link #TRUSTSTORE_PATH truststore}. + */ + public static final String TRUSTSTORE_ALGORITHM = "truststore.algorithm"; + + // Key Management + // -- Keystore + /** + * The path to a KeyStore file (in a format supported by this JRE) that should be used for key management + */ + public static final String KEYSTORE_PATH = "keystore.path"; + /** + * The password for the file configured in {@link #KEYSTORE_PATH}, as a secure setting. + */ + public static final String KEYSTORE_SECURE_PASSWORD = "keystore.secure_password"; + /** + * The password for the file configured in {@link #KEYSTORE_PATH}, as a non-secure setting. + * The use of this setting {@link #isDeprecated(String) is deprecated}. + */ + public static final String KEYSTORE_LEGACY_PASSWORD = "keystore.password"; + /** + * The password for the key within the {@link #KEYSTORE_PATH configured keystore}, as a secure setting. + * If no key password is specified, it will default to the keystore password. + */ + public static final String KEYSTORE_SECURE_KEY_PASSWORD = "keystore.secure_key_password"; + /** + * The password for the key within the {@link #KEYSTORE_PATH configured keystore}, as a non-secure setting. + * The use of this setting {@link #isDeprecated(String) is deprecated}. + * If no key password is specified, it will default to the keystore password. + */ + public static final String KEYSTORE_LEGACY_KEY_PASSWORD = "keystore.key_password"; + /** + * The {@link KeyStore#getType() keystore type} for the file configured in {@link #KEYSTORE_PATH}. + */ + public static final String KEYSTORE_TYPE = "keystore.type"; + /** + * The {@link javax.net.ssl.KeyManagerFactory#getAlgorithm() key management algorithm} to use when + * connstructing a Key manager from a {@link #KEYSTORE_PATH keystore}. + */ + public static final String KEYSTORE_ALGORITHM = "keystore.algorithm"; + // -- PEM + /** + * The path to a PEM formatted file that contains the certificate to be used as part of key management + */ + public static final String CERTIFICATE = "certificate"; + /** + * The path to a PEM formatted file that contains the private key for the configured {@link #CERTIFICATE}. + */ + public static final String KEY = "key"; + /** + * The password to read the configured {@link #KEY}, as a secure setting. + * This (or the {@link #KEY_LEGACY_PASSPHRASE legacy fallback}) is required if the key file is encrypted. + */ + public static final String KEY_SECURE_PASSPHRASE = "secure_key_passphrase"; + /** + * The password to read the configured {@link #KEY}, as a non-secure setting. + * The use of this setting {@link #isDeprecated(String) is deprecated}. + */ + public static final String KEY_LEGACY_PASSPHRASE = "key_passphrase"; + + private static final Set DEPRECATED_KEYS = new HashSet<>( + Arrays.asList(TRUSTSTORE_LEGACY_PASSWORD, KEYSTORE_LEGACY_PASSWORD, KEYSTORE_LEGACY_KEY_PASSWORD, KEY_LEGACY_PASSPHRASE) + ); + + private SslConfigurationKeys() { + throw new IllegalStateException("Utility class should not be instantiated"); + } + + /** + * The list of keys that are used to load a non-secure, non-list setting + */ + public static List getStringKeys() { + return Arrays.asList( + VERIFICATION_MODE, CLIENT_AUTH, + TRUSTSTORE_PATH, TRUSTSTORE_LEGACY_PASSWORD, TRUSTSTORE_TYPE, TRUSTSTORE_TYPE, + KEYSTORE_PATH, KEYSTORE_LEGACY_PASSWORD, KEYSTORE_LEGACY_KEY_PASSWORD, KEYSTORE_TYPE, KEYSTORE_ALGORITHM, + CERTIFICATE, KEY, KEY_LEGACY_PASSPHRASE + ); + } + + /** + * The list of keys that are used to load a non-secure, list setting + */ + public static List getListKeys() { + return Arrays.asList(PROTOCOLS, CIPHERS, CERTIFICATE_AUTHORITIES); + } + + /** + * The list of keys that are used to load a secure setting (such as a password) that would typically be stored in the elasticsearch + * keystore. + */ + public static List getSecureStringKeys() { + return Arrays.asList(TRUSTSTORE_SECURE_PASSWORD, KEYSTORE_SECURE_PASSWORD, KEYSTORE_SECURE_KEY_PASSWORD, KEY_SECURE_PASSPHRASE); + } + + /** + * @return {@code true} if the provided key is a deprecated setting + */ + public static boolean isDeprecated(String key) { + return DEPRECATED_KEYS.contains(key); + } + +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java new file mode 100644 index 0000000000000..186d20b1ea858 --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java @@ -0,0 +1,371 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import javax.crypto.Cipher; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManagerFactory; +import java.nio.file.Path; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.elasticsearch.common.ssl.KeyStoreUtil.inferKeyStoreType; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.CERTIFICATE; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.CERTIFICATE_AUTHORITIES; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.CIPHERS; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.CLIENT_AUTH; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.KEY; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.KEYSTORE_ALGORITHM; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.KEYSTORE_LEGACY_KEY_PASSWORD; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.KEYSTORE_LEGACY_PASSWORD; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.KEYSTORE_PATH; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.KEYSTORE_SECURE_KEY_PASSWORD; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.KEYSTORE_SECURE_PASSWORD; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.KEYSTORE_TYPE; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.KEY_LEGACY_PASSPHRASE; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.KEY_SECURE_PASSPHRASE; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.PROTOCOLS; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.TRUSTSTORE_ALGORITHM; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.TRUSTSTORE_LEGACY_PASSWORD; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.TRUSTSTORE_PATH; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.TRUSTSTORE_SECURE_PASSWORD; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.TRUSTSTORE_TYPE; +import static org.elasticsearch.common.ssl.SslConfigurationKeys.VERIFICATION_MODE; + +/** + * Loads {@link SslConfiguration} from settings. + * This class handles the logic of interpreting the various "ssl.*" configuration settings and their interactions + * (as well as being aware of dependencies and conflicts between different settings). + * The constructed {@code SslConfiguration} has sensible defaults for any settings that are not explicitly configured, + * and these defaults can be overridden through the various {@code setDefaultXyz} methods. + * It is {@code abstract} because this library has minimal dependencies, so the extraction of the setting values from + * the underlying setting source must be handled by the code that makes use of this class. + * + * @see SslConfiguration + * @see SslConfigurationKeys + */ +public abstract class SslConfigurationLoader { + + static final List DEFAULT_PROTOCOLS = Arrays.asList("TLSv1.2", "TLSv1.1", "TLSv1"); + static final List DEFAULT_CIPHERS = loadDefaultCiphers(); + private static final char[] EMPTY_PASSWORD = new char[0]; + + private final String settingPrefix; + + private SslTrustConfig defaultTrustConfig; + private SslKeyConfig defaultKeyConfig; + private SslVerificationMode defaultVerificationMode; + private SslClientAuthenticationMode defaultClientAuth; + private List defaultCiphers; + private List defaultProtocols; + + /** + * Construct a new loader with the "standard" default values. + * + * @param settingPrefix The prefix to apply to all settings that are loaded. It may be the empty string, otherwise it + * must end in a "." (period). For example, if the prefix is {@code "reindex.ssl."} then the keys that are + * passed to methods like {@link #getSettingAsString(String)} will be in the form + * {@code "reindex.ssl.verification_mode"}, and those same keys will be reported in error messages (via + * {@link SslConfigException}). + */ + public SslConfigurationLoader(String settingPrefix) { + this.settingPrefix = settingPrefix == null ? "" : settingPrefix; + if (this.settingPrefix.isEmpty() == false && this.settingPrefix.endsWith(".") == false) { + throw new IllegalArgumentException("Setting prefix [" + settingPrefix + "] must be blank or end in '.'"); + } + this.defaultTrustConfig = new DefaultJdkTrustConfig(); + this.defaultKeyConfig = EmptyKeyConfig.INSTANCE; + this.defaultVerificationMode = SslVerificationMode.FULL; + this.defaultClientAuth = SslClientAuthenticationMode.OPTIONAL; + this.defaultProtocols = DEFAULT_PROTOCOLS; + this.defaultCiphers = DEFAULT_CIPHERS; + } + + /** + * Change the default trust config. + * The initial trust config is {@link DefaultJdkTrustConfig}, which trusts the JDK's default CA certs + */ + public void setDefaultTrustConfig(SslTrustConfig defaultTrustConfig) { + this.defaultTrustConfig = defaultTrustConfig; + } + + /** + * Change the default key config. + * The initial key config is {@link EmptyKeyConfig}, which does not provide any keys + */ + public void setDefaultKeyConfig(SslKeyConfig defaultKeyConfig) { + this.defaultKeyConfig = defaultKeyConfig; + } + + /** + * Change the default verification mode. + * The initial verification mode is {@link SslVerificationMode#FULL}. + */ + public void setDefaultVerificationMode(SslVerificationMode defaultVerificationMode) { + this.defaultVerificationMode = defaultVerificationMode; + } + + /** + * Change the default client authentication mode. + * The initial client auth mode is {@link SslClientAuthenticationMode#OPTIONAL}. + */ + public void setDefaultClientAuth(SslClientAuthenticationMode defaultClientAuth) { + this.defaultClientAuth = defaultClientAuth; + } + + /** + * Change the default supported ciphers. + * The initial cipher list depends on the availability of {@link #has256BitAES() 256 bit AES}. + * + * @see #loadDefaultCiphers() + */ + public void setDefaultCiphers(List defaultCiphers) { + this.defaultCiphers = defaultCiphers; + } + + /** + * Change the default SSL/TLS protocol list. + * The initial protocol list is defined by {@link #DEFAULT_PROTOCOLS} + */ + public void setDefaultProtocols(List defaultProtocols) { + this.defaultProtocols = defaultProtocols; + } + + /** + * Clients of this class should implement this method to load a fully-qualified key from the preferred settings source. + * This method will be called for basic string settings (see {@link SslConfigurationKeys#getStringKeys()}). + *

    + * The setting should be returned as a string, and this class will convert it to the relevant type. + * + * @throws Exception If a {@link RuntimeException} is thrown, it will be rethrown unwrapped. All checked exceptions are wrapped in + * {@link SslConfigException} before being rethrown. + */ + protected abstract String getSettingAsString(String key) throws Exception; + + /** + * Clients of this class should implement this method to load a fully-qualified key from the preferred secure settings source. + * This method will be called for any setting keys that are marked as being + * {@link SslConfigurationKeys#getSecureStringKeys() secure} settings. + * + * @throws Exception If a {@link RuntimeException} is thrown, it will be rethrown unwrapped. All checked exceptions are wrapped in + * {@link SslConfigException} before being rethrown. + */ + protected abstract char[] getSecureSetting(String key) throws Exception; + + /** + * Clients of this class should implement this method to load a fully-qualified key from the preferred settings source. + * This method will be called for list settings (see {@link SslConfigurationKeys#getListKeys()}). + *

    + * The setting should be returned as a list of strings, and this class will convert the values to the relevant type. + * + * @throws Exception If a {@link RuntimeException} is thrown, it will be rethrown unwrapped. All checked exceptions are wrapped in + * {@link SslConfigException} before being rethrown. + */ + protected abstract List getSettingAsList(String key) throws Exception; + + /** + * Resolve all necessary configuration settings, and load a {@link SslConfiguration}. + * + * @param basePath The base path to use for any settings that represent file paths. Typically points to the Elasticsearch + * configuration directory. + * @throws SslConfigException For any problems with the configuration, or with loading the required SSL classes. + */ + public SslConfiguration load(Path basePath) { + Objects.requireNonNull(basePath, "Base Path cannot be null"); + final List protocols = resolveListSetting(PROTOCOLS, Function.identity(), defaultProtocols); + final List ciphers = resolveListSetting(CIPHERS, Function.identity(), defaultCiphers); + final SslVerificationMode verificationMode = resolveSetting(VERIFICATION_MODE, SslVerificationMode::parse, defaultVerificationMode); + final SslClientAuthenticationMode clientAuth = resolveSetting(CLIENT_AUTH, SslClientAuthenticationMode::parse, defaultClientAuth); + + final SslTrustConfig trustConfig = buildTrustConfig(basePath, verificationMode); + final SslKeyConfig keyConfig = buildKeyConfig(basePath); + + if (protocols == null || protocols.isEmpty()) { + throw new SslConfigException("no protocols configured in [" + settingPrefix + PROTOCOLS + "]"); + } + if (ciphers == null || ciphers.isEmpty()) { + throw new SslConfigException("no cipher suites configured in [" + settingPrefix + CIPHERS + "]"); + } + return new SslConfiguration(trustConfig, keyConfig, verificationMode, clientAuth, ciphers, protocols); + } + + private SslTrustConfig buildTrustConfig(Path basePath, SslVerificationMode verificationMode) { + final List certificateAuthorities = resolveListSetting(CERTIFICATE_AUTHORITIES, basePath::resolve, null); + final Path trustStorePath = resolveSetting(TRUSTSTORE_PATH, basePath::resolve, null); + + if (certificateAuthorities != null && trustStorePath != null) { + throw new SslConfigException("cannot specify both [" + settingPrefix + CERTIFICATE_AUTHORITIES + "] and [" + + settingPrefix + TRUSTSTORE_PATH + "]"); + } + if (verificationMode.isCertificateVerificationEnabled() == false) { + return TrustEverythingConfig.TRUST_EVERYTHING; + } + if (certificateAuthorities != null) { + return new PemTrustConfig(certificateAuthorities); + } + if (trustStorePath != null) { + final char[] password = resolvePasswordSetting(TRUSTSTORE_SECURE_PASSWORD, TRUSTSTORE_LEGACY_PASSWORD); + final String storeType = resolveSetting(TRUSTSTORE_TYPE, Function.identity(), inferKeyStoreType(trustStorePath)); + final String algorithm = resolveSetting(TRUSTSTORE_ALGORITHM, Function.identity(), TrustManagerFactory.getDefaultAlgorithm()); + return new StoreTrustConfig(trustStorePath, password, storeType, algorithm); + } + return defaultTrustConfig; + } + + private SslKeyConfig buildKeyConfig(Path basePath) { + final Path certificatePath = resolveSetting(CERTIFICATE, basePath::resolve, null); + final Path keyPath = resolveSetting(KEY, basePath::resolve, null); + final Path keyStorePath = resolveSetting(KEYSTORE_PATH, basePath::resolve, null); + + if (certificatePath != null && keyStorePath != null) { + throw new SslConfigException("cannot specify both [" + settingPrefix + CERTIFICATE + "] and [" + + settingPrefix + KEYSTORE_PATH + "]"); + } + + if (certificatePath != null || keyPath != null) { + if (keyPath == null) { + throw new SslConfigException("cannot specify [" + settingPrefix + CERTIFICATE + "] without also setting [" + + settingPrefix + KEY + "]"); + } + if (certificatePath == null) { + throw new SslConfigException("cannot specify [" + settingPrefix + KEYSTORE_PATH + "] without also setting [" + + settingPrefix + CERTIFICATE + "]"); + } + final char[] password = resolvePasswordSetting(KEY_SECURE_PASSPHRASE, KEY_LEGACY_PASSPHRASE); + return new PemKeyConfig(certificatePath, keyPath, password); + } + + if (keyStorePath != null) { + final char[] storePassword = resolvePasswordSetting(KEYSTORE_SECURE_PASSWORD, KEYSTORE_LEGACY_PASSWORD); + char[] keyPassword = resolvePasswordSetting(KEYSTORE_SECURE_KEY_PASSWORD, KEYSTORE_LEGACY_KEY_PASSWORD); + if (keyPassword.length == 0) { + keyPassword = storePassword; + } + final String storeType = resolveSetting(KEYSTORE_TYPE, Function.identity(), inferKeyStoreType(keyStorePath)); + final String algorithm = resolveSetting(KEYSTORE_ALGORITHM, Function.identity(), KeyManagerFactory.getDefaultAlgorithm()); + return new StoreKeyConfig(keyStorePath, storePassword, storeType, keyPassword, algorithm); + } + + return defaultKeyConfig; + } + + private char[] resolvePasswordSetting(String secureSettingKey, String legacySettingKey) { + final char[] securePassword = resolveSecureSetting(secureSettingKey, null); + final String legacyPassword = resolveSetting(legacySettingKey, Function.identity(), null); + if (securePassword == null) { + if (legacyPassword == null) { + return EMPTY_PASSWORD; + } else { + return legacyPassword.toCharArray(); + } + } else { + if (legacyPassword != null) { + throw new SslConfigException("cannot specify both [" + settingPrefix + secureSettingKey + "] and [" + + settingPrefix + legacySettingKey + "]"); + } else { + return securePassword; + } + } + } + + private V resolveSetting(String key, Function parser, V defaultValue) { + try { + String setting = getSettingAsString(settingPrefix + key); + if (setting == null || setting.isEmpty()) { + return defaultValue; + } + return parser.apply(setting); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new SslConfigException("cannot retrieve setting [" + settingPrefix + key + "]", e); + } + } + + private char[] resolveSecureSetting(String key, char[] defaultValue) { + try { + char[] setting = getSecureSetting(settingPrefix + key); + if (setting == null || setting.length == 0) { + return defaultValue; + } + return setting; + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new SslConfigException("cannot retrieve secure setting [" + settingPrefix + key + "]", e); + } + + } + + private List resolveListSetting(String key, Function parser, List defaultValue) { + try { + final List list = getSettingAsList(settingPrefix + key); + if (list == null || list.isEmpty()) { + return defaultValue; + } + return list.stream().map(parser).collect(Collectors.toList()); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new SslConfigException("cannot retrieve setting [" + settingPrefix + key + "]", e); + } + } + + private static List loadDefaultCiphers() { + final List ciphers128 = Arrays.asList( + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_128_CBC_SHA" + ); + final List ciphers256 = Arrays.asList( + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA256", + "TLS_RSA_WITH_AES_256_CBC_SHA" + ); + if (has256BitAES()) { + List ciphers = new ArrayList<>(ciphers256.size() + ciphers128.size()); + ciphers.addAll(ciphers256); + ciphers.addAll(ciphers128); + return ciphers; + } else { + return ciphers128; + } + } + + private static boolean has256BitAES() { + try { + return Cipher.getMaxAllowedKeyLength("AES") > 128; + } catch (NoSuchAlgorithmException e) { + // No AES? Things are going to be very weird, but technically that means we don't have 256 bit AES, so ... + return false; + } + } +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslKeyConfig.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslKeyConfig.java new file mode 100644 index 0000000000000..4f5e6b8669310 --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslKeyConfig.java @@ -0,0 +1,46 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import javax.net.ssl.X509ExtendedKeyManager; +import java.nio.file.Path; +import java.util.Collection; + +/** + * An interface for building a key manager at runtime. + * The method for constructing the key manager is implementation dependent. + */ +public interface SslKeyConfig { + + /** + * @return A collection of files that are read by this config object. + * The {@link #createKeyManager()} method will read these files dynamically, so the behaviour of this key config may change whenever + * any of these files are modified. + */ + Collection getDependentFiles(); + + /** + * @return A new {@link X509ExtendedKeyManager}. + * @throws SslConfigException if there is a problem configuring the key manager. + */ + X509ExtendedKeyManager createKeyManager(); + +} + diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslTrustConfig.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslTrustConfig.java new file mode 100644 index 0000000000000..2cd61218e6bb7 --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslTrustConfig.java @@ -0,0 +1,46 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import javax.net.ssl.X509ExtendedTrustManager; +import java.nio.file.Path; +import java.util.Collection; + +/** + * An interface for building a trust manager at runtime. + * The method for constructing the trust manager is implementation dependent. + */ +public interface SslTrustConfig { + + /** + * @return A collection of files that are read by this config object. + * The {@link #createTrustManager()} method will read these files dynamically, so the behaviour of this trust config may change if + * any of these files are modified. + */ + Collection getDependentFiles(); + + /** + * @return A new {@link X509ExtendedTrustManager}. + * @throws SslConfigException if there is a problem configuring the trust manager. + */ + X509ExtendedTrustManager createTrustManager(); + +} + diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslVerificationMode.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslVerificationMode.java new file mode 100644 index 0000000000000..eee6e9cb2d6a1 --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslVerificationMode.java @@ -0,0 +1,104 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Represents the verification mode to be used for SSL connections. + */ +public enum SslVerificationMode { + /** + * Verify neither the hostname, nor the provided certificate. + */ + NONE { + @Override + public boolean isHostnameVerificationEnabled() { + return false; + } + + @Override + public boolean isCertificateVerificationEnabled() { + return false; + } + }, + /** + * Verify the provided certificate against the trust chain, but do not verify the hostname. + */ + CERTIFICATE { + @Override + public boolean isHostnameVerificationEnabled() { + return false; + } + + @Override + public boolean isCertificateVerificationEnabled() { + return true; + } + }, + /** + * Verify the provided certificate against the trust chain, and also verify that the hostname to which this client is connected + * matches one of the Subject-Alternative-Names in the certificate. + */ + FULL { + @Override + public boolean isHostnameVerificationEnabled() { + return true; + } + + @Override + public boolean isCertificateVerificationEnabled() { + return true; + } + }; + + /** + * @return true if hostname verification is enabled + */ + public abstract boolean isHostnameVerificationEnabled(); + + /** + * @return true if certificate verification is enabled + */ + public abstract boolean isCertificateVerificationEnabled(); + + private static final Map LOOKUP = Collections.unmodifiableMap(buildLookup()); + + private static Map buildLookup() { + Map map = new LinkedHashMap<>(3); + map.put("none", NONE); + map.put("certificate", CERTIFICATE); + map.put("full", FULL); + return map; + } + + public static SslVerificationMode parse(String value) { + final SslVerificationMode mode = LOOKUP.get(value.toLowerCase(Locale.ROOT)); + if (mode == null) { + final String allowedValues = LOOKUP.keySet().stream().collect(Collectors.joining(",")); + throw new SslConfigException("could not resolve ssl client verification mode, unknown value [" + + value + "], recognised values are [" + allowedValues + "]"); + } + return mode; + } +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/StoreKeyConfig.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/StoreKeyConfig.java new file mode 100644 index 0000000000000..683aaaaa06cb4 --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/StoreKeyConfig.java @@ -0,0 +1,106 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.X509ExtendedKeyManager; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.UnrecoverableKeyException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; + +/** + * A {@link SslKeyConfig} that builds a Key Manager from a keystore file. + */ +public class StoreKeyConfig implements SslKeyConfig { + private final Path path; + private final char[] storePassword; + private final String type; + private final char[] keyPassword; + private final String algorithm; + + /** + * @param path The path to the keystore file + * @param storePassword The password for the keystore + * @param type The {@link KeyStore#getType() type} of the keystore (typically "PKCS12" or "jks"). + * See {@link KeyStoreUtil#inferKeyStoreType(Path)}. + * @param keyPassword The password for the key(s) within the keystore + * (see {@link javax.net.ssl.KeyManagerFactory#init(KeyStore, char[])}). + * @param algorithm The algorithm to use for the Key Manager (see {@link KeyManagerFactory#getAlgorithm()}). + */ + StoreKeyConfig(Path path, char[] storePassword, String type, char[] keyPassword, String algorithm) { + this.path = path; + this.storePassword = storePassword; + this.type = type; + this.keyPassword = keyPassword; + this.algorithm = algorithm; + } + + @Override + public Collection getDependentFiles() { + return Collections.singleton(path); + } + + @Override + public X509ExtendedKeyManager createKeyManager() { + try { + final KeyStore keyStore = KeyStoreUtil.readKeyStore(path, type, storePassword); + checkKeyStore(keyStore); + return KeyStoreUtil.createKeyManager(keyStore, keyPassword, algorithm); + } catch (UnrecoverableKeyException e) { + String message = "failed to load a KeyManager for keystore [" + path.toAbsolutePath() + + "], this is usually caused by an incorrect key-password"; + if (keyPassword.length == 0) { + message += " (no key-password was provided)"; + } else if (Arrays.equals(storePassword, keyPassword)) { + message += " (we tried to access the key using the same password as the keystore)"; + } + throw new SslConfigException(message, e); + } catch (GeneralSecurityException e) { + throw new SslConfigException("failed to load a KeyManager for keystore [" + path + "] of type [" + type + "]", e); + } + } + + /** + * Verifies that the keystore contains at least 1 private key entry. + */ + private void checkKeyStore(KeyStore keyStore) throws KeyStoreException { + Enumeration aliases = keyStore.aliases(); + while (aliases.hasMoreElements()) { + String alias = aliases.nextElement(); + if (keyStore.isKeyEntry(alias)) { + return; + } + } + final String message; + if (path != null) { + message = "the keystore [" + path + "] does not contain a private key entry"; + } else { + message = "the configured PKCS#11 token does not contain a private key entry"; + } + throw new SslConfigException(message); + } + +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/StoreTrustConfig.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/StoreTrustConfig.java new file mode 100644 index 0000000000000..0dc0a3818c8ed --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/StoreTrustConfig.java @@ -0,0 +1,90 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import javax.net.ssl.X509ExtendedTrustManager; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; + +/** + * A {@link SslTrustConfig} that builds a Trust Manager from a keystore file. + */ +final class StoreTrustConfig implements SslTrustConfig { + private final Path path; + private final char[] password; + private final String type; + private final String algorithm; + + /** + * @param path The path to the keystore file + * @param password The password for the keystore + * @param type The {@link KeyStore#getType() type} of the keystore (typically "PKCS12" or "jks"). + * See {@link KeyStoreUtil#inferKeyStoreType(Path)}. + * @param algorithm The algorithm to use for the Trust Manager (see {@link javax.net.ssl.TrustManagerFactory#getAlgorithm()}). + */ + StoreTrustConfig(Path path, char[] password, String type, String algorithm) { + this.path = path; + this.type = type; + this.algorithm = algorithm; + this.password = password; + } + + @Override + public Collection getDependentFiles() { + return Collections.singleton(path); + } + + @Override + public X509ExtendedTrustManager createTrustManager() { + try { + final KeyStore store = KeyStoreUtil.readKeyStore(path, type, password); + checkTrustStore(store); + return KeyStoreUtil.createTrustManager(store, algorithm); + } catch (GeneralSecurityException e) { + throw new SslConfigException("cannot create trust manager for path=[" + (path == null ? null : path.toAbsolutePath()) + + "] type=[" + type + "] password=[" + (password.length == 0 ? "" : "") + "]", e); + } + } + + /** + * Verifies that the keystore contains at least 1 trusted certificate entry. + */ + private void checkTrustStore(KeyStore store) throws GeneralSecurityException { + Enumeration aliases = store.aliases(); + while (aliases.hasMoreElements()) { + String alias = aliases.nextElement(); + if (store.isCertificateEntry(alias)) { + return; + } + } + final String message; + if (path != null) { + message = "the truststore [" + path + "] does not contain any trusted certificate entries"; + } else { + message = "the configured PKCS#11 token does not contain any trusted certificate entries"; + } + throw new SslConfigException(message); + } + +} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/TrustEverythingConfig.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/TrustEverythingConfig.java new file mode 100644 index 0000000000000..f3ed83a7e7d7b --- /dev/null +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/TrustEverythingConfig.java @@ -0,0 +1,92 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.X509ExtendedTrustManager; +import java.net.Socket; +import java.nio.file.Path; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Collections; + +/** + * A {@link SslTrustConfig} that trusts all certificates. Used when {@link SslVerificationMode#isCertificateVerificationEnabled()} is + * {@code false}. + * This class cannot be used on FIPS-140 JVM as it has its own trust manager implementation. + */ +final class TrustEverythingConfig implements SslTrustConfig { + + static final TrustEverythingConfig TRUST_EVERYTHING = new TrustEverythingConfig(); + + private TrustEverythingConfig() { + // single instances + } + + /** + * The {@link X509ExtendedTrustManager} that will trust all certificates. + * All methods are implemented as a no-op and do not throw exceptions regardless of the certificate presented. + */ + private static final X509ExtendedTrustManager TRUST_MANAGER = new X509ExtendedTrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) { + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) { + } + + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) { + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) { + } + + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) { + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + }; + + @Override + public Collection getDependentFiles() { + return Collections.emptyList(); + } + + @Override + public X509ExtendedTrustManager createTrustManager() { + return TRUST_MANAGER; + } + + @Override + public String toString() { + return "trust everything"; + } +} diff --git a/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/DefaultJdkTrustConfigTests.java b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/DefaultJdkTrustConfigTests.java new file mode 100644 index 0000000000000..b1aad439e47e1 --- /dev/null +++ b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/DefaultJdkTrustConfigTests.java @@ -0,0 +1,79 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import org.elasticsearch.test.ESTestCase; +import org.junit.Assert; + +import javax.net.ssl.X509ExtendedTrustManager; +import java.security.cert.X509Certificate; +import java.util.Locale; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.stream.Stream; + +import static org.hamcrest.Matchers.emptyArray; +import static org.hamcrest.Matchers.emptyIterable; +import static org.hamcrest.Matchers.not; + +public class DefaultJdkTrustConfigTests extends ESTestCase { + + private static final BiFunction EMPTY_SYSTEM_PROPERTIES = (key, defaultValue) -> defaultValue; + + public void testGetSystemTrustStoreWithNoSystemProperties() throws Exception { + final DefaultJdkTrustConfig trustConfig = new DefaultJdkTrustConfig((key, defaultValue) -> defaultValue); + assertThat(trustConfig.getDependentFiles(), emptyIterable()); + final X509ExtendedTrustManager trustManager = trustConfig.createTrustManager(); + assertStandardIssuers(trustManager); + } + + public void testGetNonPKCS11TrustStoreWithPasswordSet() throws Exception { + final DefaultJdkTrustConfig trustConfig = new DefaultJdkTrustConfig(EMPTY_SYSTEM_PROPERTIES, "fakepassword".toCharArray()); + assertThat(trustConfig.getDependentFiles(), emptyIterable()); + final X509ExtendedTrustManager trustManager = trustConfig.createTrustManager(); + assertStandardIssuers(trustManager); + } + + private void assertStandardIssuers(X509ExtendedTrustManager trustManager) { + assertThat(trustManager.getAcceptedIssuers(), not(emptyArray())); + // This is a sample of the CAs that we expect on every JRE. + // We can safely change this list if the JRE's issuer list changes, but we want to assert something useful. + assertHasTrustedIssuer(trustManager, "VeriSign"); + assertHasTrustedIssuer(trustManager, "GeoTrust"); + assertHasTrustedIssuer(trustManager, "DigiCert"); + assertHasTrustedIssuer(trustManager, "thawte"); + assertHasTrustedIssuer(trustManager, "COMODO"); + } + + private void assertHasTrustedIssuer(X509ExtendedTrustManager trustManager, String name) { + final String lowerName = name.toLowerCase(Locale.ROOT); + final Optional ca = Stream.of(trustManager.getAcceptedIssuers()) + .filter(cert -> cert.getSubjectDN().getName().toLowerCase(Locale.ROOT).contains(lowerName)) + .findAny(); + if (ca.isPresent() == false) { + logger.info("Failed to find issuer [{}] in trust manager, but did find ...", lowerName); + for (X509Certificate cert : trustManager.getAcceptedIssuers()) { + logger.info(" - {}", cert.getSubjectDN().getName().replaceFirst("^\\w+=([^,]+),.*", "$1")); + } + Assert.fail("Cannot find trusted issuer with name [" + name + "]."); + } + } + +} diff --git a/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/PemKeyConfigTests.java b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/PemKeyConfigTests.java new file mode 100644 index 0000000000000..8a5bb469e3c2c --- /dev/null +++ b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/PemKeyConfigTests.java @@ -0,0 +1,148 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import org.elasticsearch.test.ESTestCase; +import org.hamcrest.Matchers; + +import javax.net.ssl.X509ExtendedKeyManager; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.Arrays; + +import static org.hamcrest.Matchers.arrayWithSize; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.iterableWithSize; +import static org.hamcrest.Matchers.notNullValue; + +public class PemKeyConfigTests extends ESTestCase { + private static final int IP_NAME = 7; + private static final int DNS_NAME = 2; + + public void testBuildKeyConfigFromPemFilesWithoutPassword() throws Exception { + final Path cert = getDataPath("/certs/cert1/cert1.crt"); + final Path key = getDataPath("/certs/cert1/cert1.key"); + final PemKeyConfig keyConfig = new PemKeyConfig(cert, key, new char[0]); + assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(cert, key)); + assertCertificateAndKey(keyConfig, "CN=cert1"); + } + + public void testBuildKeyConfigFromPemFilesWithPassword() throws Exception { + final Path cert = getDataPath("/certs/cert2/cert2.crt"); + final Path key = getDataPath("/certs/cert2/cert2.key"); + final PemKeyConfig keyConfig = new PemKeyConfig(cert, key, "c2-pass".toCharArray()); + assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(cert, key)); + assertCertificateAndKey(keyConfig, "CN=cert2"); + } + + public void testKeyManagerFailsWithIncorrectPassword() throws Exception { + final Path cert = getDataPath("/certs/cert2/cert2.crt"); + final Path key = getDataPath("/certs/cert2/cert2.key"); + final PemKeyConfig keyConfig = new PemKeyConfig(cert, key, "wrong-password".toCharArray()); + assertPasswordIsIncorrect(keyConfig, key); + } + + public void testMissingCertificateFailsWithMeaningfulMessage() throws Exception { + final Path key = getDataPath("/certs/cert1/cert1.key"); + final Path cert = key.getParent().resolve("dne.crt"); + + final PemKeyConfig keyConfig = new PemKeyConfig(cert, key, new char[0]); + assertFileNotFound(keyConfig, "certificate", cert); + } + + public void testMissingKeyFailsWithMeaningfulMessage() throws Exception { + final Path cert = getDataPath("/certs/cert1/cert1.crt"); + final Path key = cert.getParent().resolve("dne.key"); + + final PemKeyConfig keyConfig = new PemKeyConfig(cert, key, new char[0]); + assertFileNotFound(keyConfig, "private key", key); + } + + public void testKeyConfigReloadsFileContents() throws Exception { + final Path cert1 = getDataPath("/certs/cert1/cert1.crt"); + final Path key1 = getDataPath("/certs/cert1/cert1.key"); + final Path cert2 = getDataPath("/certs/cert2/cert2.crt"); + final Path key2 = getDataPath("/certs/cert2/cert2.key"); + final Path cert = createTempFile("cert", ".crt"); + final Path key = createTempFile("cert", ".key"); + + final PemKeyConfig keyConfig = new PemKeyConfig(cert, key, new char[0]); + + Files.copy(cert1, cert, StandardCopyOption.REPLACE_EXISTING); + Files.copy(key1, key, StandardCopyOption.REPLACE_EXISTING); + assertCertificateAndKey(keyConfig, "CN=cert1"); + + Files.copy(cert2, cert, StandardCopyOption.REPLACE_EXISTING); + Files.copy(key2, key, StandardCopyOption.REPLACE_EXISTING); + assertPasswordIsIncorrect(keyConfig, key); + + Files.copy(cert1, cert, StandardCopyOption.REPLACE_EXISTING); + Files.copy(key1, key, StandardCopyOption.REPLACE_EXISTING); + assertCertificateAndKey(keyConfig, "CN=cert1"); + + Files.delete(cert); + assertFileNotFound(keyConfig, "certificate", cert); + } + + private void assertCertificateAndKey(PemKeyConfig keyConfig, String expectedDN) throws CertificateParsingException { + final X509ExtendedKeyManager keyManager = keyConfig.createKeyManager(); + assertThat(keyManager, notNullValue()); + + final PrivateKey privateKey = keyManager.getPrivateKey("key"); + assertThat(privateKey, notNullValue()); + assertThat(privateKey.getAlgorithm(), is("RSA")); + + final X509Certificate[] chain = keyManager.getCertificateChain("key"); + assertThat(chain, notNullValue()); + assertThat(chain, arrayWithSize(1)); + final X509Certificate certificate = chain[0]; + assertThat(certificate.getIssuerDN().getName(), is("CN=Test CA 1")); + assertThat(certificate.getSubjectDN().getName(), is(expectedDN)); + assertThat(certificate.getSubjectAlternativeNames(), iterableWithSize(2)); + assertThat(certificate.getSubjectAlternativeNames(), containsInAnyOrder( + Arrays.asList(DNS_NAME, "localhost"), + Arrays.asList(IP_NAME, "127.0.0.1") + )); + } + + private void assertPasswordIsIncorrect(PemKeyConfig keyConfig, Path key) { + final SslConfigException exception = expectThrows(SslConfigException.class, keyConfig::createKeyManager); + assertThat(exception.getMessage(), containsString("private key file")); + assertThat(exception.getMessage(), containsString(key.toAbsolutePath().toString())); + assertThat(exception.getCause(), instanceOf(GeneralSecurityException.class)); + } + + private void assertFileNotFound(PemKeyConfig keyConfig, String type, Path file) { + final SslConfigException exception = expectThrows(SslConfigException.class, keyConfig::createKeyManager); + assertThat(exception.getMessage(), containsString(type + " file")); + assertThat(exception.getMessage(), containsString(file.toAbsolutePath().toString())); + assertThat(exception.getMessage(), containsString("does not exist")); + assertThat(exception.getCause(), instanceOf(NoSuchFileException.class)); + } +} diff --git a/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/PemTrustConfigTests.java b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/PemTrustConfigTests.java new file mode 100644 index 0000000000000..3d78976e1e83b --- /dev/null +++ b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/PemTrustConfigTests.java @@ -0,0 +1,150 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import org.elasticsearch.test.ESTestCase; +import org.hamcrest.Matchers; + +import javax.net.ssl.X509ExtendedTrustManager; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; +import java.security.GeneralSecurityException; +import java.security.Principal; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class PemTrustConfigTests extends ESTestCase { + + public void testBuildTrustConfigFromSinglePemFile() throws Exception { + final Path cert = getDataPath("/certs/ca1/ca.crt"); + final PemTrustConfig trustConfig = new PemTrustConfig(Collections.singletonList(cert)); + assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(cert)); + assertCertificateChain(trustConfig, "CN=Test CA 1"); + } + + public void testBuildTrustConfigFromMultiplePemFiles() throws Exception { + final Path cert1 = getDataPath("/certs/ca1/ca.crt"); + final Path cert2 = getDataPath("/certs/ca2/ca.crt"); + final Path cert3 = getDataPath("/certs/ca3/ca.crt"); + final PemTrustConfig trustConfig = new PemTrustConfig(Arrays.asList(cert1, cert2, cert3)); + assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(cert1, cert2, cert3)); + assertCertificateChain(trustConfig, "CN=Test CA 1", "CN=Test CA 2", "CN=Test CA 3"); + } + + public void testBadFileFormatFails() throws Exception { + final Path ca = createTempFile("ca", ".crt"); + Files.write(ca, randomByteArrayOfLength(128), StandardOpenOption.APPEND); + final PemTrustConfig trustConfig = new PemTrustConfig(Collections.singletonList(ca)); + assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ca)); + assertInvalidFileFormat(trustConfig, ca); + } + + public void testEmptyFileFails() throws Exception { + final Path ca = createTempFile("ca", ".crt"); + final PemTrustConfig trustConfig = new PemTrustConfig(Collections.singletonList(ca)); + assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ca)); + assertEmptyFile(trustConfig, ca); + } + + public void testMissingFileFailsWithMeaningfulMessage() throws Exception { + final Path cert = getDataPath("/certs/ca1/ca.crt").getParent().resolve("dne.crt"); + final PemTrustConfig trustConfig = new PemTrustConfig(Collections.singletonList(cert)); + assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(cert)); + assertFileNotFound(trustConfig, cert); + } + + public void testOneMissingFileFailsWithMeaningfulMessageEvenIfOtherFileExist() throws Exception { + final Path cert1 = getDataPath("/certs/ca1/ca.crt"); + final Path cert2 = getDataPath("/certs/ca2/ca.crt").getParent().resolve("dne.crt"); + final Path cert3 = getDataPath("/certs/ca3/ca.crt"); + final PemTrustConfig trustConfig = new PemTrustConfig(Arrays.asList(cert1, cert2, cert3)); + assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(cert1, cert2, cert3)); + assertFileNotFound(trustConfig, cert2); + } + + public void testTrustConfigReloadsFileContents() throws Exception { + final Path cert1 = getDataPath("/certs/ca1/ca.crt"); + final Path cert2 = getDataPath("/certs/ca2/ca.crt"); + final Path cert3 = getDataPath("/certs/ca3/ca.crt"); + + final Path ca1 = createTempFile("ca1", ".crt"); + final Path ca2 = createTempFile("ca2", ".crt"); + + final PemTrustConfig trustConfig = new PemTrustConfig(Arrays.asList(ca1, ca2)); + + Files.copy(cert1, ca1, StandardCopyOption.REPLACE_EXISTING); + Files.copy(cert2, ca2, StandardCopyOption.REPLACE_EXISTING); + assertCertificateChain(trustConfig, "CN=Test CA 1", "CN=Test CA 2"); + + Files.copy(cert3, ca2, StandardCopyOption.REPLACE_EXISTING); + assertCertificateChain(trustConfig, "CN=Test CA 1", "CN=Test CA 3"); + + Files.delete(ca1); + assertFileNotFound(trustConfig, ca1); + + Files.write(ca1, randomByteArrayOfLength(128), StandardOpenOption.CREATE); + assertInvalidFileFormat(trustConfig, ca1); + } + + private void assertCertificateChain(PemTrustConfig trustConfig, String... caNames) { + final X509ExtendedTrustManager trustManager = trustConfig.createTrustManager(); + final X509Certificate[] issuers = trustManager.getAcceptedIssuers(); + final Set issuerNames = Stream.of(issuers) + .map(X509Certificate::getSubjectDN) + .map(Principal::getName) + .collect(Collectors.toSet()); + + assertThat(issuerNames, Matchers.containsInAnyOrder(caNames)); + } + + private void assertEmptyFile(PemTrustConfig trustConfig, Path file) { + final SslConfigException exception = expectThrows(SslConfigException.class, trustConfig::createTrustManager); + assertThat(exception.getMessage(), Matchers.containsString(file.toAbsolutePath().toString())); + assertThat(exception.getMessage(), Matchers.containsString("failed to parse any certificates")); + } + + private void assertInvalidFileFormat(PemTrustConfig trustConfig, Path file) { + if (inFipsJvm()) { + // When running on BC-FIPS, an invalid file format behaves like an empty file + assertEmptyFile(trustConfig, file); + return; + } + final SslConfigException exception = expectThrows(SslConfigException.class, trustConfig::createTrustManager); + assertThat(exception.getMessage(), Matchers.containsString(file.toAbsolutePath().toString())); + assertThat(exception.getMessage(), Matchers.containsString("cannot create trust")); + assertThat(exception.getMessage(), Matchers.containsString("PEM")); + assertThat(exception.getCause(), Matchers.instanceOf(GeneralSecurityException.class)); + } + + private void assertFileNotFound(PemTrustConfig trustConfig, Path file) { + final SslConfigException exception = expectThrows(SslConfigException.class, trustConfig::createTrustManager); + assertThat(exception.getMessage(), Matchers.containsString("files do not exist")); + assertThat(exception.getMessage(), Matchers.containsString("PEM")); + assertThat(exception.getMessage(), Matchers.containsString(file.toAbsolutePath().toString())); + assertThat(exception.getCause(), Matchers.instanceOf(NoSuchFileException.class)); + } +} diff --git a/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/PemUtilsTests.java b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/PemUtilsTests.java new file mode 100644 index 0000000000000..60f0cd168ce1e --- /dev/null +++ b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/PemUtilsTests.java @@ -0,0 +1,219 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import org.elasticsearch.test.ESTestCase; + +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.Key; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.util.function.Supplier; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.core.StringContains.containsString; + +public class PemUtilsTests extends ESTestCase { + + private static final Supplier EMPTY_PASSWORD = () -> new char[0]; + private static final Supplier TESTNODE_PASSWORD = "testnode"::toCharArray; + + public void testReadPKCS8RsaKey() throws Exception { + Key key = getKeyFromKeystore("RSA"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/rsa_key_pkcs8_plain.pem"), EMPTY_PASSWORD); + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadPKCS8RsaKeyWithBagAttrs() throws Exception { + Key key = getKeyFromKeystore("RSA"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/testnode_with_bagattrs.pem"), EMPTY_PASSWORD); + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadPKCS8DsaKey() throws Exception { + Key key = getKeyFromKeystore("DSA"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/dsa_key_pkcs8_plain.pem"), EMPTY_PASSWORD); + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadPKCS8EcKey() throws Exception { + Key key = getKeyFromKeystore("EC"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/ec_key_pkcs8_plain.pem"), EMPTY_PASSWORD); + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadEncryptedPKCS8Key() throws Exception { + assumeFalse("Can't run in a FIPS JVM, PBE KeySpec is not available", inFipsJvm()); + Key key = getKeyFromKeystore("RSA"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath + ("/certs/pem-utils/key_pkcs8_encrypted.pem"), TESTNODE_PASSWORD); + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadDESEncryptedPKCS1Key() throws Exception { + Key key = getKeyFromKeystore("RSA"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/testnode.pem"), TESTNODE_PASSWORD); + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadAESEncryptedPKCS1Key() throws Exception { + Key key = getKeyFromKeystore("RSA"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + String bits = randomFrom("128", "192", "256"); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/testnode-aes" + bits + ".pem"), TESTNODE_PASSWORD); + + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadPKCS1RsaKey() throws Exception { + Key key = getKeyFromKeystore("RSA"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/testnode-unprotected.pem"), TESTNODE_PASSWORD); + + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadOpenSslDsaKey() throws Exception { + Key key = getKeyFromKeystore("DSA"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/dsa_key_openssl_plain.pem"), EMPTY_PASSWORD); + + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadOpenSslDsaKeyWithParams() throws Exception { + Key key = getKeyFromKeystore("DSA"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/dsa_key_openssl_plain_with_params.pem"), + EMPTY_PASSWORD); + + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadEncryptedOpenSslDsaKey() throws Exception { + Key key = getKeyFromKeystore("DSA"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/dsa_key_openssl_encrypted.pem"), TESTNODE_PASSWORD); + + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadOpenSslEcKey() throws Exception { + Key key = getKeyFromKeystore("EC"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/ec_key_openssl_plain.pem"), EMPTY_PASSWORD); + + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadOpenSslEcKeyWithParams() throws Exception { + Key key = getKeyFromKeystore("EC"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/ec_key_openssl_plain_with_params.pem"), + EMPTY_PASSWORD); + + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadEncryptedOpenSslEcKey() throws Exception { + Key key = getKeyFromKeystore("EC"); + assertThat(key, notNullValue()); + assertThat(key, instanceOf(PrivateKey.class)); + PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/ec_key_openssl_encrypted.pem"), TESTNODE_PASSWORD); + + assertThat(privateKey, notNullValue()); + assertThat(privateKey, equalTo(key)); + } + + public void testReadUnsupportedKey() { + final Path path = getDataPath("/certs/pem-utils/key_unsupported.pem"); + SslConfigException e = expectThrows(SslConfigException.class, () -> PemUtils.readPrivateKey(path, TESTNODE_PASSWORD)); + assertThat(e.getMessage(), containsString("file does not contain a supported key format")); + assertThat(e.getMessage(), containsString(path.toAbsolutePath().toString())); + } + + public void testReadPemCertificateAsKey() { + final Path path = getDataPath("/certs/pem-utils/testnode.crt"); + SslConfigException e = expectThrows(SslConfigException.class, () -> PemUtils.readPrivateKey(path, TESTNODE_PASSWORD)); + assertThat(e.getMessage(), containsString("file does not contain a supported key format")); + assertThat(e.getMessage(), containsString(path.toAbsolutePath().toString())); + } + + public void testReadCorruptedKey() { + final Path path = getDataPath("/certs/pem-utils/corrupted_key_pkcs8_plain.pem"); + SslConfigException e = expectThrows(SslConfigException.class, () -> PemUtils.readPrivateKey(path, TESTNODE_PASSWORD)); + assertThat(e.getMessage(), containsString("private key")); + assertThat(e.getMessage(), containsString("cannot be parsed")); + assertThat(e.getMessage(), containsString(path.toAbsolutePath().toString())); + assertThat(e.getCause().getMessage(), containsString("PEM footer is invalid or missing")); + } + + public void testReadEmptyFile() { + final Path path = getDataPath("/certs/pem-utils/empty.pem"); + SslConfigException e = expectThrows(SslConfigException.class, () -> PemUtils.readPrivateKey(path, TESTNODE_PASSWORD)); + assertThat(e.getMessage(), containsString("file is empty")); + assertThat(e.getMessage(), containsString(path.toAbsolutePath().toString())); + } + + private Key getKeyFromKeystore(String algo) throws Exception { + Path keystorePath = getDataPath("/certs/pem-utils/testnode.jks"); + try (InputStream in = Files.newInputStream(keystorePath)) { + KeyStore keyStore = KeyStore.getInstance("jks"); + keyStore.load(in, "testnode".toCharArray()); + return keyStore.getKey("testnode_" + algo, "testnode".toCharArray()); + } + } +} diff --git a/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/SslConfigurationLoaderTests.java b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/SslConfigurationLoaderTests.java new file mode 100644 index 0000000000000..20a161b78fd5f --- /dev/null +++ b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/SslConfigurationLoaderTests.java @@ -0,0 +1,220 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import org.elasticsearch.common.settings.MockSecureSettings; +import org.elasticsearch.common.settings.SecureString; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.test.ESTestCase; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManagerFactory; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +public class SslConfigurationLoaderTests extends ESTestCase { + + private final Path certRoot = getDataPath("/certs/ca1/ca.crt").getParent().getParent(); + + private Settings settings; + private MockSecureSettings secureSettings = new MockSecureSettings(); + private SslConfigurationLoader loader = new SslConfigurationLoader("test.ssl.") { + @Override + protected String getSettingAsString(String key) throws Exception { + return settings.get(key); + } + + @Override + protected char[] getSecureSetting(String key) throws Exception { + final SecureString secStr = secureSettings.getString(key); + return secStr == null ? null : secStr.getChars(); + } + + @Override + protected List getSettingAsList(String key) throws Exception { + return settings.getAsList(key); + } + }; + + /** + * A test for non-trust, non-key configurations. + * These are straight forward and can all be tested together + */ + public void testBasicConfigurationOptions() { + final SslVerificationMode verificationMode = randomFrom(SslVerificationMode.values()); + final SslClientAuthenticationMode clientAuth = randomFrom(SslClientAuthenticationMode.values()); + final String[] ciphers = generateRandomStringArray(8, 12, false, false); + final String[] protocols = generateRandomStringArray(4, 5, false, false); + settings = Settings.builder() + .put("test.ssl.verification_mode", verificationMode.name().toLowerCase(Locale.ROOT)) + .put("test.ssl.client_authentication", clientAuth.name().toLowerCase(Locale.ROOT)) + .putList("test.ssl.cipher_suites", ciphers) + .putList("test.ssl.supported_protocols", protocols) + .build(); + final SslConfiguration configuration = loader.load(certRoot); + assertThat(configuration.getClientAuth(), is(clientAuth)); + assertThat(configuration.getVerificationMode(), is(verificationMode)); + assertThat(configuration.getCipherSuites(), equalTo(Arrays.asList(ciphers))); + assertThat(configuration.getSupportedProtocols(), equalTo(Arrays.asList(protocols))); + if (verificationMode == SslVerificationMode.NONE) { + final SslTrustConfig trustConfig = configuration.getTrustConfig(); + assertThat(trustConfig, instanceOf(TrustEverythingConfig.class)); + } + } + + public void testLoadTrustFromPemCAs() { + settings = Settings.builder() + .putList("test.ssl.certificate_authorities", "ca1/ca.crt", "ca2/ca.crt", "ca3/ca.crt") + .build(); + final SslConfiguration configuration = loader.load(certRoot); + final SslTrustConfig trustConfig = configuration.getTrustConfig(); + assertThat(trustConfig, instanceOf(PemTrustConfig.class)); + assertThat(trustConfig.getDependentFiles(), + containsInAnyOrder(getDataPath("/certs/ca1/ca.crt"), getDataPath("/certs/ca2/ca.crt"), getDataPath("/certs/ca3/ca.crt"))); + assertThat(trustConfig.createTrustManager(), notNullValue()); + } + + public void testLoadTrustFromPkcs12() { + final Settings.Builder builder = Settings.builder().put("test.ssl.truststore.path", "ca-all/ca.p12"); + if (randomBoolean()) { + builder.put("test.ssl.truststore.password", "p12-pass"); + } else { + secureSettings.setString("test.ssl.truststore.secure_password", "p12-pass"); + } + if (randomBoolean()) { + // If this is not set, the loader will guess from the extension + builder.put("test.ssl.truststore.type", "PKCS12"); + } + if (randomBoolean()) { + builder.put("test.ssl.truststore.algorithm", TrustManagerFactory.getDefaultAlgorithm()); + } + settings = builder.build(); + final SslConfiguration configuration = loader.load(certRoot); + final SslTrustConfig trustConfig = configuration.getTrustConfig(); + assertThat(trustConfig, instanceOf(StoreTrustConfig.class)); + assertThat(trustConfig.getDependentFiles(), containsInAnyOrder(getDataPath("/certs/ca-all/ca.p12"))); + assertThat(trustConfig.createTrustManager(), notNullValue()); + } + + public void testLoadTrustFromJKS() { + final Settings.Builder builder = Settings.builder().put("test.ssl.truststore.path", "ca-all/ca.jks"); + if (randomBoolean()) { + builder.put("test.ssl.truststore.password", "jks-pass"); + } else { + secureSettings.setString("test.ssl.truststore.secure_password", "jks-pass"); + } + if (randomBoolean()) { + // If this is not set, the loader will guess from the extension + builder.put("test.ssl.truststore.type", "jks"); + } + if (randomBoolean()) { + builder.put("test.ssl.truststore.algorithm", TrustManagerFactory.getDefaultAlgorithm()); + } + settings = builder.build(); + final SslConfiguration configuration = loader.load(certRoot); + final SslTrustConfig trustConfig = configuration.getTrustConfig(); + assertThat(trustConfig, instanceOf(StoreTrustConfig.class)); + assertThat(trustConfig.getDependentFiles(), containsInAnyOrder(getDataPath("/certs/ca-all/ca.jks"))); + assertThat(trustConfig.createTrustManager(), notNullValue()); + } + + public void testLoadKeysFromPemFiles() { + final boolean usePassword = randomBoolean(); + final boolean useLegacyPassword = usePassword && randomBoolean(); + final String certName = usePassword ? "cert2" : "cert1"; + final Settings.Builder builder = Settings.builder() + .put("test.ssl.certificate", certName + "/" + certName + ".crt") + .put("test.ssl.key", certName + "/" + certName + ".key"); + if (usePassword) { + if (useLegacyPassword) { + builder.put("test.ssl.key_passphrase", "c2-pass"); + } else { + secureSettings.setString("test.ssl.secure_key_passphrase", "c2-pass"); + } + } + settings = builder.build(); + final SslConfiguration configuration = loader.load(certRoot); + final SslKeyConfig keyConfig = configuration.getKeyConfig(); + assertThat(keyConfig, instanceOf(PemKeyConfig.class)); + assertThat(keyConfig.getDependentFiles(), containsInAnyOrder( + getDataPath("/certs/" + certName + "/" + certName + ".crt"), getDataPath("/certs/" + certName + "/" + certName + ".key"))); + assertThat(keyConfig.createKeyManager(), notNullValue()); + } + + public void testLoadKeysFromPKCS12() { + final Settings.Builder builder = Settings.builder() + .put("test.ssl.keystore.path", "cert-all/certs.p12"); + if (randomBoolean()) { + builder.put("test.ssl.keystore.password", "p12-pass"); + } else { + secureSettings.setString("test.ssl.keystore.secure_password", "p12-pass"); + } + if (randomBoolean()) { + // If this is not set, the loader will guess from the extension + builder.put("test.ssl.keystore.type", "PKCS12"); + } + if (randomBoolean()) { + builder.put("test.ssl.keystore.algorithm", KeyManagerFactory.getDefaultAlgorithm()); + } + settings = builder.build(); + final SslConfiguration configuration = loader.load(certRoot); + final SslKeyConfig keyConfig = configuration.getKeyConfig(); + assertThat(keyConfig, instanceOf(StoreKeyConfig.class)); + assertThat(keyConfig.getDependentFiles(), containsInAnyOrder(getDataPath("/certs/cert-all/certs.p12"))); + assertThat(keyConfig.createKeyManager(), notNullValue()); + } + + public void testLoadKeysFromJKS() { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Settings.Builder builder = Settings.builder() + .put("test.ssl.keystore.path", "cert-all/certs.jks"); + if (randomBoolean()) { + builder.put("test.ssl.keystore.password", "jks-pass"); + } else { + secureSettings.setString("test.ssl.keystore.secure_password", "jks-pass"); + } + if (randomBoolean()) { + builder.put("test.ssl.keystore.key_password", "key-pass"); + } else { + secureSettings.setString("test.ssl.keystore.secure_key_password", "key-pass"); + } + if (randomBoolean()) { + // If this is not set, the loader will guess from the extension + builder.put("test.ssl.keystore.type", "jks"); + } + if (randomBoolean()) { + builder.put("test.ssl.keystore.algorithm", KeyManagerFactory.getDefaultAlgorithm()); + } + settings = builder.build(); + final SslConfiguration configuration = loader.load(certRoot); + final SslKeyConfig keyConfig = configuration.getKeyConfig(); + assertThat(keyConfig, instanceOf(StoreKeyConfig.class)); + assertThat(keyConfig.getDependentFiles(), containsInAnyOrder(getDataPath("/certs/cert-all/certs.jks"))); + assertThat(keyConfig.createKeyManager(), notNullValue()); + } +} diff --git a/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/SslConfigurationTests.java b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/SslConfigurationTests.java new file mode 100644 index 0000000000000..b8986462ebe47 --- /dev/null +++ b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/SslConfigurationTests.java @@ -0,0 +1,140 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.EqualsHashCodeTestUtils; +import org.hamcrest.Matchers; +import org.mockito.Mockito; + +import javax.net.ssl.SSLContext; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.elasticsearch.common.ssl.SslConfigurationLoader.DEFAULT_CIPHERS; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +public class SslConfigurationTests extends ESTestCase { + + static final String[] VALID_PROTOCOLS = { "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3", "SSLv2Hello", "SSLv2" }; + + public void testBasicConstruction() { + final SslTrustConfig trustConfig = Mockito.mock(SslTrustConfig.class); + Mockito.when(trustConfig.toString()).thenReturn("TEST-TRUST"); + final SslKeyConfig keyConfig = Mockito.mock(SslKeyConfig.class); + Mockito.when(keyConfig.toString()).thenReturn("TEST-KEY"); + final SslVerificationMode verificationMode = randomFrom(SslVerificationMode.values()); + final SslClientAuthenticationMode clientAuth = randomFrom(SslClientAuthenticationMode.values()); + final List ciphers = randomSubsetOf(randomIntBetween(1, DEFAULT_CIPHERS.size()), DEFAULT_CIPHERS); + final List protocols = randomSubsetOf(randomIntBetween(1, 4), VALID_PROTOCOLS); + final SslConfiguration configuration = + new SslConfiguration(trustConfig, keyConfig, verificationMode, clientAuth, ciphers, protocols); + + assertThat(configuration.getTrustConfig(), is(trustConfig)); + assertThat(configuration.getKeyConfig(), is(keyConfig)); + assertThat(configuration.getVerificationMode(), is(verificationMode)); + assertThat(configuration.getClientAuth(), is(clientAuth)); + assertThat(configuration.getCipherSuites(), is(ciphers)); + assertThat(configuration.getSupportedProtocols(), is(protocols)); + + assertThat(configuration.toString(), containsString("TEST-TRUST")); + assertThat(configuration.toString(), containsString("TEST-KEY")); + assertThat(configuration.toString(), containsString(verificationMode.toString())); + assertThat(configuration.toString(), containsString(clientAuth.toString())); + assertThat(configuration.toString(), containsString(randomFrom(ciphers))); + assertThat(configuration.toString(), containsString(randomFrom(protocols))); + } + + public void testEqualsAndHashCode() { + final SslTrustConfig trustConfig = Mockito.mock(SslTrustConfig.class); + final SslKeyConfig keyConfig = Mockito.mock(SslKeyConfig.class); + final SslVerificationMode verificationMode = randomFrom(SslVerificationMode.values()); + final SslClientAuthenticationMode clientAuth = randomFrom(SslClientAuthenticationMode.values()); + final List ciphers = randomSubsetOf(randomIntBetween(1, DEFAULT_CIPHERS.size() - 1), DEFAULT_CIPHERS); + final List protocols = randomSubsetOf(randomIntBetween(1, VALID_PROTOCOLS.length - 1), VALID_PROTOCOLS); + final SslConfiguration configuration = + new SslConfiguration(trustConfig, keyConfig, verificationMode, clientAuth, ciphers, protocols); + + EqualsHashCodeTestUtils.checkEqualsAndHashCode(configuration, + orig -> new SslConfiguration(orig.getTrustConfig(), orig.getKeyConfig(), orig.getVerificationMode(), orig.getClientAuth(), + orig.getCipherSuites(), orig.getSupportedProtocols()), + orig -> { + switch (randomIntBetween(1, 4)) { + case 1: + return new SslConfiguration(orig.getTrustConfig(), orig.getKeyConfig(), + randomValueOtherThan(orig.getVerificationMode(), () -> randomFrom(SslVerificationMode.values())), + orig.getClientAuth(), orig.getCipherSuites(), orig.getSupportedProtocols()); + case 2: + return new SslConfiguration(orig.getTrustConfig(), orig.getKeyConfig(), orig.getVerificationMode(), + randomValueOtherThan(orig.getClientAuth(), () -> randomFrom(SslClientAuthenticationMode.values())), + orig.getCipherSuites(), orig.getSupportedProtocols()); + case 3: + return new SslConfiguration(orig.getTrustConfig(), orig.getKeyConfig(), + orig.getVerificationMode(), orig.getClientAuth(), DEFAULT_CIPHERS, orig.getSupportedProtocols()); + case 4: + default: + return new SslConfiguration(orig.getTrustConfig(), orig.getKeyConfig(), orig.getVerificationMode(), + orig.getClientAuth(), orig.getCipherSuites(), Arrays.asList(VALID_PROTOCOLS)); + } + }); + } + + public void testDependentFiles() { + final SslTrustConfig trustConfig = Mockito.mock(SslTrustConfig.class); + final SslKeyConfig keyConfig = Mockito.mock(SslKeyConfig.class); + final SslConfiguration configuration = new SslConfiguration(trustConfig, keyConfig, + randomFrom(SslVerificationMode.values()), randomFrom(SslClientAuthenticationMode.values()), + DEFAULT_CIPHERS, SslConfigurationLoader.DEFAULT_PROTOCOLS); + + final Path dir = createTempDir(); + final Path file1 = dir.resolve(randomAlphaOfLength(1) + ".pem"); + final Path file2 = dir.resolve(randomAlphaOfLength(2) + ".pem"); + final Path file3 = dir.resolve(randomAlphaOfLength(3) + ".pem"); + final Path file4 = dir.resolve(randomAlphaOfLength(4) + ".pem"); + final Path file5 = dir.resolve(randomAlphaOfLength(5) + ".pem"); + + Mockito.when(trustConfig.getDependentFiles()).thenReturn(Arrays.asList(file1, file2)); + Mockito.when(keyConfig.getDependentFiles()).thenReturn(Arrays.asList(file3, file4, file5)); + assertThat(configuration.getDependentFiles(), Matchers.containsInAnyOrder(file1, file2, file3, file4, file5)); + } + + public void testBuildSslContext() { + final SslTrustConfig trustConfig = Mockito.mock(SslTrustConfig.class); + final SslKeyConfig keyConfig = Mockito.mock(SslKeyConfig.class); + final String protocol = randomFrom(SslConfigurationLoader.DEFAULT_PROTOCOLS); + final SslConfiguration configuration = new SslConfiguration(trustConfig, keyConfig, + randomFrom(SslVerificationMode.values()), randomFrom(SslClientAuthenticationMode.values()), + DEFAULT_CIPHERS, Collections.singletonList(protocol)); + + Mockito.when(trustConfig.createTrustManager()).thenReturn(null); + Mockito.when(keyConfig.createKeyManager()).thenReturn(null); + final SSLContext sslContext = configuration.createSslContext(); + assertThat(sslContext.getProtocol(), equalTo(protocol)); + + Mockito.verify(trustConfig).createTrustManager(); + Mockito.verify(keyConfig).createKeyManager(); + Mockito.verifyNoMoreInteractions(trustConfig, keyConfig); + } + +} diff --git a/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/StoreKeyConfigTests.java b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/StoreKeyConfigTests.java new file mode 100644 index 0000000000000..f5fcc16c6a023 --- /dev/null +++ b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/StoreKeyConfigTests.java @@ -0,0 +1,215 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import org.elasticsearch.test.ESTestCase; +import org.hamcrest.Matchers; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.X509ExtendedKeyManager; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.Arrays; + +import static org.hamcrest.Matchers.arrayWithSize; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.iterableWithSize; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +public class StoreKeyConfigTests extends ESTestCase { + + private static final int IP_NAME = 7; + private static final int DNS_NAME = 2; + + private static final char[] P12_PASS = "p12-pass".toCharArray(); + private static final char[] JKS_PASS = "jks-pass".toCharArray(); + + public void testLoadSingleKeyPKCS12() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path p12 = getDataPath("/certs/cert1/cert1.p12"); + final StoreKeyConfig keyConfig = new StoreKeyConfig(p12, P12_PASS, "PKCS12", P12_PASS, KeyManagerFactory.getDefaultAlgorithm()); + assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(p12)); + assertKeysLoaded(keyConfig, "cert1"); + } + + public void testLoadMultipleKeyPKCS12() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path p12 = getDataPath("/certs/cert-all/certs.p12"); + final StoreKeyConfig keyConfig = new StoreKeyConfig(p12, P12_PASS, "PKCS12", P12_PASS, KeyManagerFactory.getDefaultAlgorithm()); + assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(p12)); + assertKeysLoaded(keyConfig, "cert1", "cert2"); + } + + public void testLoadMultipleKeyJksWithSeparateKeyPassword() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path jks = getDataPath("/certs/cert-all/certs.jks"); + final StoreKeyConfig keyConfig = new StoreKeyConfig(jks, JKS_PASS, "jks", "key-pass".toCharArray(), + KeyManagerFactory.getDefaultAlgorithm()); + assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(jks)); + assertKeysLoaded(keyConfig, "cert1", "cert2"); + } + + public void testKeyManagerFailsWithIncorrectStorePassword() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path jks = getDataPath("/certs/cert-all/certs.jks"); + final StoreKeyConfig keyConfig = new StoreKeyConfig(jks, P12_PASS, "jks", "key-pass".toCharArray(), + KeyManagerFactory.getDefaultAlgorithm()); + assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(jks)); + assertPasswordIsIncorrect(keyConfig, jks); + } + + public void testKeyManagerFailsWithIncorrectKeyPassword() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path jks = getDataPath("/certs/cert-all/certs.jks"); + final StoreKeyConfig keyConfig = new StoreKeyConfig(jks, JKS_PASS, "jks", JKS_PASS, KeyManagerFactory.getDefaultAlgorithm()); + assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(jks)); + assertPasswordIsIncorrect(keyConfig, jks); + } + + public void testKeyManagerFailsWithMissingKeystoreFile() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path path = getDataPath("/certs/cert-all/certs.jks").getParent().resolve("dne.jks"); + final StoreKeyConfig keyConfig = new StoreKeyConfig(path, JKS_PASS, "jks", JKS_PASS, KeyManagerFactory.getDefaultAlgorithm()); + assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(path)); + assertFileNotFound(keyConfig, path); + } + + public void testMissingKeyEntriesFailsWithMeaningfulMessage() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path ks; + final char[] password; + final String type; + if (randomBoolean()) { + type = "PKCS12"; + ks = getDataPath("/certs/ca-all/ca.p12"); + password = P12_PASS; + } else { + type = "jks"; + ks = getDataPath("/certs/ca-all/ca.jks"); + password = JKS_PASS; + } + final StoreKeyConfig keyConfig = new StoreKeyConfig(ks, password, type, password, KeyManagerFactory.getDefaultAlgorithm()); + assertThat(keyConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks)); + assertNoPrivateKeyEntries(keyConfig, ks); + } + + public void testKeyConfigReloadsFileContents() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path cert1 = getDataPath("/certs/cert1/cert1.p12"); + final Path cert2 = getDataPath("/certs/cert2/cert2.p12"); + final Path jks = getDataPath("/certs/cert-all/certs.jks"); + + final Path p12 = createTempFile("cert", ".p12"); + + final StoreKeyConfig keyConfig = new StoreKeyConfig(p12, P12_PASS, "PKCS12", P12_PASS, KeyManagerFactory.getDefaultAlgorithm()); + + Files.copy(cert1, p12, StandardCopyOption.REPLACE_EXISTING); + assertKeysLoaded(keyConfig, "cert1"); + assertKeysNotLoaded(keyConfig, "cert2"); + + Files.copy(jks, p12, StandardCopyOption.REPLACE_EXISTING); + // Because (a) cannot load a JKS as a PKCS12 & (b) the password is wrong. + assertBadKeyStore(keyConfig, p12); + + Files.copy(cert2, p12, StandardCopyOption.REPLACE_EXISTING); + assertKeysLoaded(keyConfig, "cert2"); + assertKeysNotLoaded(keyConfig, "cert1"); + + Files.delete(p12); + assertFileNotFound(keyConfig, p12); + } + + private void assertKeysLoaded(StoreKeyConfig keyConfig, String... names) throws CertificateParsingException { + final X509ExtendedKeyManager keyManager = keyConfig.createKeyManager(); + assertThat(keyManager, notNullValue()); + + for (String name : names) { + final PrivateKey privateKey = keyManager.getPrivateKey(name); + assertThat(privateKey, notNullValue()); + assertThat(privateKey.getAlgorithm(), is("RSA")); + + final X509Certificate[] chain = keyManager.getCertificateChain(name); + assertThat(chain, notNullValue()); + assertThat(chain, arrayWithSize(1)); + final X509Certificate certificate = chain[0]; + assertThat(certificate.getIssuerDN().getName(), is("CN=Test CA 1")); + assertThat(certificate.getSubjectDN().getName(), is("CN=" + name)); + assertThat(certificate.getSubjectAlternativeNames(), iterableWithSize(2)); + assertThat(certificate.getSubjectAlternativeNames(), containsInAnyOrder( + Arrays.asList(DNS_NAME, "localhost"), + Arrays.asList(IP_NAME, "127.0.0.1") + )); + } + } + + private void assertKeysNotLoaded(StoreKeyConfig keyConfig, String... names) throws CertificateParsingException { + final X509ExtendedKeyManager keyManager = keyConfig.createKeyManager(); + assertThat(keyManager, notNullValue()); + + for (String name : names) { + final PrivateKey privateKey = keyManager.getPrivateKey(name); + assertThat(privateKey, nullValue()); + } + } + + private void assertPasswordIsIncorrect(StoreKeyConfig keyConfig, Path key) { + final SslConfigException exception = expectThrows(SslConfigException.class, keyConfig::createKeyManager); + assertThat(exception.getMessage(), containsString("keystore")); + assertThat(exception.getMessage(), containsString(key.toAbsolutePath().toString())); + if (exception.getCause() instanceof GeneralSecurityException) { + assertThat(exception.getMessage(), containsString("password")); + } else { + assertThat(exception.getCause(), instanceOf(IOException.class)); + assertThat(exception.getCause().getMessage(), containsString("password")); + } + } + + private void assertBadKeyStore(StoreKeyConfig keyConfig, Path key) { + final SslConfigException exception = expectThrows(SslConfigException.class, keyConfig::createKeyManager); + assertThat(exception.getMessage(), containsString("keystore")); + assertThat(exception.getMessage(), containsString(key.toAbsolutePath().toString())); + assertThat(exception.getCause(), instanceOf(IOException.class)); + } + + private void assertFileNotFound(StoreKeyConfig keyConfig, Path file) { + final SslConfigException exception = expectThrows(SslConfigException.class, keyConfig::createKeyManager); + assertThat(exception.getMessage(), containsString("keystore")); + assertThat(exception.getMessage(), containsString(file.toAbsolutePath().toString())); + assertThat(exception.getMessage(), containsString("does not exist")); + assertThat(exception.getCause(), nullValue()); + } + + private void assertNoPrivateKeyEntries(StoreKeyConfig keyConfig, Path file) { + final SslConfigException exception = expectThrows(SslConfigException.class, keyConfig::createKeyManager); + assertThat(exception.getMessage(), containsString("keystore")); + assertThat(exception.getMessage(), containsString(file.toAbsolutePath().toString())); + assertThat(exception.getMessage(), containsString("does not contain a private key entry")); + } +} diff --git a/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/StoreTrustConfigTests.java b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/StoreTrustConfigTests.java new file mode 100644 index 0000000000000..207bf9179415f --- /dev/null +++ b/libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/StoreTrustConfigTests.java @@ -0,0 +1,169 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common.ssl; + +import org.elasticsearch.test.ESTestCase; +import org.hamcrest.Matchers; + +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509ExtendedTrustManager; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; +import java.security.Principal; +import java.security.cert.X509Certificate; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.nullValue; + +public class StoreTrustConfigTests extends ESTestCase { + + private static final char[] P12_PASS = "p12-pass".toCharArray(); + private static final char[] JKS_PASS = "jks-pass".toCharArray(); + private static final String DEFAULT_ALGORITHM = TrustManagerFactory.getDefaultAlgorithm(); + + public void testBuildTrustConfigFromPKCS12() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path ks = getDataPath("/certs/ca1/ca.p12"); + final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, P12_PASS, "PKCS12", DEFAULT_ALGORITHM); + assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks)); + assertCertificateChain(trustConfig, "CN=Test CA 1"); + } + + public void testBuildTrustConfigFromJKS() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path ks = getDataPath("/certs/ca-all/ca.jks"); + final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, JKS_PASS, "jks", DEFAULT_ALGORITHM); + assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks)); + assertCertificateChain(trustConfig, "CN=Test CA 1", "CN=Test CA 2", "CN=Test CA 3"); + } + + public void testBadKeyStoreFormatFails() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path ks = createTempFile("ca", ".p12"); + Files.write(ks, randomByteArrayOfLength(128), StandardOpenOption.APPEND); + final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, new char[0], randomFrom("PKCS12", "jks"), DEFAULT_ALGORITHM); + assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks)); + assertInvalidFileFormat(trustConfig, ks); + } + + public void testMissingKeyStoreFailsWithMeaningfulMessage() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path ks = getDataPath("/certs/ca-all/ca.p12").getParent().resolve("keystore.dne"); + final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, new char[0], randomFrom("PKCS12", "jks"), DEFAULT_ALGORITHM); + assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks)); + assertFileNotFound(trustConfig, ks); + } + + public void testIncorrectPasswordFailsWithMeaningfulMessage() throws Exception { + final Path ks = getDataPath("/certs/ca1/ca.p12"); + final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, new char[0], "PKCS12", DEFAULT_ALGORITHM); + assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks)); + assertPasswordIsIncorrect(trustConfig, ks); + } + + public void testMissingTrustEntriesFailsWithMeaningfulMessage() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path ks; + final char[] password; + final String type; + if (randomBoolean()) { + type = "PKCS12"; + ks = getDataPath("/certs/cert-all/certs.p12"); + password = P12_PASS; + } else { + type = "jks"; + ks = getDataPath("/certs/cert-all/certs.jks"); + password = JKS_PASS; + } + final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, password, type, DEFAULT_ALGORITHM); + assertThat(trustConfig.getDependentFiles(), Matchers.containsInAnyOrder(ks)); + assertNoCertificateEntries(trustConfig, ks); + } + + public void testTrustConfigReloadsKeysStoreContents() throws Exception { + assumeFalse("Can't use JKS/PKCS12 keystores in a FIPS JVM", inFipsJvm()); + final Path ks1 = getDataPath("/certs/ca1/ca.p12"); + final Path ksAll = getDataPath("/certs/ca-all/ca.p12"); + + final Path ks = createTempFile("ca", "p12"); + + final StoreTrustConfig trustConfig = new StoreTrustConfig(ks, P12_PASS, "PKCS12", DEFAULT_ALGORITHM); + + Files.copy(ks1, ks, StandardCopyOption.REPLACE_EXISTING); + assertCertificateChain(trustConfig, "CN=Test CA 1"); + + Files.delete(ks); + assertFileNotFound(trustConfig, ks); + + Files.write(ks, randomByteArrayOfLength(128), StandardOpenOption.CREATE); + assertInvalidFileFormat(trustConfig, ks); + + Files.copy(ksAll, ks, StandardCopyOption.REPLACE_EXISTING); + assertCertificateChain(trustConfig, "CN=Test CA 1", "CN=Test CA 2", "CN=Test CA 3"); + } + + private void assertCertificateChain(StoreTrustConfig trustConfig, String... caNames) { + final X509ExtendedTrustManager trustManager = trustConfig.createTrustManager(); + final X509Certificate[] issuers = trustManager.getAcceptedIssuers(); + final Set issuerNames = Stream.of(issuers) + .map(X509Certificate::getSubjectDN) + .map(Principal::getName) + .collect(Collectors.toSet()); + + assertThat(issuerNames, Matchers.containsInAnyOrder(caNames)); + } + + private void assertInvalidFileFormat(StoreTrustConfig trustConfig, Path file) { + final SslConfigException exception = expectThrows(SslConfigException.class, trustConfig::createTrustManager); + assertThat(exception.getMessage(), Matchers.containsString("cannot read")); + assertThat(exception.getMessage(), Matchers.containsString("keystore")); + assertThat(exception.getMessage(), Matchers.containsString(file.toAbsolutePath().toString())); + assertThat(exception.getCause(), Matchers.instanceOf(IOException.class)); + } + + private void assertFileNotFound(StoreTrustConfig trustConfig, Path file) { + final SslConfigException exception = expectThrows(SslConfigException.class, trustConfig::createTrustManager); + assertThat(exception.getMessage(), Matchers.containsString("file does not exist")); + assertThat(exception.getMessage(), Matchers.containsString("keystore")); + assertThat(exception.getMessage(), Matchers.containsString(file.toAbsolutePath().toString())); + assertThat(exception.getCause(), nullValue()); + } + + private void assertPasswordIsIncorrect(StoreTrustConfig trustConfig, Path key) { + final SslConfigException exception = expectThrows(SslConfigException.class, trustConfig::createTrustManager); + assertThat(exception.getMessage(), containsString("keystore")); + assertThat(exception.getMessage(), containsString(key.toAbsolutePath().toString())); + assertThat(exception.getMessage(), containsString("password")); + } + + private void assertNoCertificateEntries(StoreTrustConfig trustConfig, Path file) { + final SslConfigException exception = expectThrows(SslConfigException.class, trustConfig::createTrustManager); + assertThat(exception.getMessage(), Matchers.containsString("does not contain any trusted certificate entries")); + assertThat(exception.getMessage(), Matchers.containsString("truststore")); + assertThat(exception.getMessage(), Matchers.containsString(file.toAbsolutePath().toString())); + } + +} diff --git a/libs/ssl-config/src/test/resources/certs/README.txt b/libs/ssl-config/src/test/resources/certs/README.txt new file mode 100644 index 0000000000000..a04a31011b4dd --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/README.txt @@ -0,0 +1,75 @@ +#!/bin/bash +# +# This is README describes how the certificates in this directory were created. +# This file can also be executed as a script +# + +# 1. Create first CA PEM ("ca1") + +elasticsearch-certutil ca --pem --out ca1.zip --days 9999 --ca-dn "CN=Test CA 1" +unzip ca1.zip +mv ca ca1 + +# 2. Create first CA PEM ("ca2") + +elasticsearch-certutil ca --pem --out ca2.zip --days 9999 --ca-dn "CN=Test CA 2" +unzip ca2.zip +mv ca ca2 + +# 3. Create first CA PEM ("ca3") + +elasticsearch-certutil ca --pem --out ca3.zip --days 9999 --ca-dn "CN=Test CA 3" +unzip ca3.zip +mv ca ca3 + +# 4. Create "cert1" PEM + +elasticsearch-certutil cert --pem --out cert1.zip --name cert1 --ip 127.0.0.1 --dns localhost --days 9999 --ca-key ca1/ca.key --ca-cert ca1/ca.crt +unzip cert1.zip + +# 5. Create "cert2" PEM (same as cert1, but with a password) + +elasticsearch-certutil cert --pem --out cert2.zip --name cert2 --ip 127.0.0.1 --dns localhost --days 9999 --ca-key ca1/ca.key --ca-cert ca1/ca.crt --pass "c2-pass" +unzip cert2.zip + +# 6. Convert CAs to PKCS#12 + +for n in 1 2 3 +do + keytool -importcert -file ca${n}/ca.crt -alias ca -keystore ca${n}/ca.p12 -storetype PKCS12 -storepass p12-pass -v + keytool -importcert -file ca${n}/ca.crt -alias ca${n} -keystore ca-all/ca.p12 -storetype PKCS12 -storepass p12-pass -v +done + +# 7. Convert CAs to JKS + +for n in 1 2 3 +do + keytool -importcert -file ca${n}/ca.crt -alias ca${n} -keystore ca-all/ca.jks -storetype jks -storepass jks-pass -v +done + +# 8. Convert Certs to PKCS#12 + +for Cert in cert1 cert2 +do + openssl pkcs12 -export -out $Cert/$Cert.p12 -inkey $Cert/$Cert.key -in $Cert/$Cert.crt -name $Cert -passout pass:p12-pass +done + +# 9. Import Certs into single PKCS#12 keystore + +for Cert in cert1 cert2 +do + keytool -importkeystore -noprompt \ + -srckeystore $Cert/$Cert.p12 -srcstoretype PKCS12 -srcstorepass p12-pass \ + -destkeystore cert-all/certs.p12 -deststoretype PKCS12 -deststorepass p12-pass +done + +# 10. Import Certs into single JKS keystore with separate key-password + +for Cert in cert1 cert2 +do + keytool -importkeystore -noprompt \ + -srckeystore $Cert/$Cert.p12 -srcstoretype PKCS12 -srcstorepass p12-pass \ + -destkeystore cert-all/certs.jks -deststoretype jks -deststorepass jks-pass + keytool -keypasswd -keystore cert-all/certs.jks -alias $Cert -keypass p12-pass -new key-pass -storepass jks-pass +done + diff --git a/libs/ssl-config/src/test/resources/certs/ca-all/ca.jks b/libs/ssl-config/src/test/resources/certs/ca-all/ca.jks new file mode 100644 index 0000000000000000000000000000000000000000..0c00ff13d906ff3cb4e584dea41e702d31eab693 GIT binary patch literal 2460 zcma*oc{tST9suz9%|cTRV$3AQQjx9cXQzX5tu;7@>{~<;5o1Y0V{Buo7^5MMov|A_ zWhavCU~S0`5QGh01=QG_LV;u$5+nnQIWQ;yg`xw`v{}1nq>IMi**Irc@ry+KwMWxToDw-q7*bh1yBi8Q_@gT zw8Ns5RY4U+@ZaGNR*`}ITVD?#ATTn(3)%dlolr6WK(Zz}l6{tFb~G2T!_KoKrzpxl zVvoN>0Zr`$Wdhw&ToZmRQd@(M@sjeeXi5iO9QlMdEPi#(E?mCH{0%2ed!(0MV#K8^ z;fK}c5>q{Xn=96Vj%XsJ*9S1wrl=cfpR}&DC!$`T&8%r&m=aAm-{j$sl6LU-Vmv^8sg$T$9g7<`Tne-b+h7?;vzcH$`OWy5-53XtZ(3EBNp- z@>HKIl*o;M6;`ah)pXFU_9I$=~>s$DfK-tc%8^ek2{SSUQr^qr)5^&Nq%zA{Rc^5d|&?Nxct^vFwNLYaP6`6E}o z*FZi81wWO(**Z$8Zf8knWHKdl?bH|O@{p-@ViS*VfE7Niuz9AS_dPpoy2-cUj&Pp$ zDf3uQ;6%k+5-L28eNHH->cR3#Ls`@(QT#3V{CIFI*IINds(4s;d=+?ZXjIuvAZ7&U ziQ7tBx%*3$jPXBl8xM{3Y7!@H_$#<~m{|EV)Pzjf5Qesc5_@UVwY>yBCuq!n+4~_w zU`;EK{vDKU6MhDYEx1%=)hKuEfwjZRtQDclcBtEG4!u z`yK6?D-*nLzlF<8*~c_X-ami7K;1;yBR*NE(a;N}uSu~dw5h&*?I)Re^Kfi5WKz&m zE=vu!@Jb)QX7gg08TSa^K1DjSb1ckdfFwxW<>2|7*|YhqJ90jC-IKP9eHoM1mCn1Q zqlb@KEInu>^6!bWZPNr9t9R+`GNe+SnIXBr{!@7&y3@EPijqwfmfqlWm^7_wM82c; zFeB@_{5vLows*l1vZA+MV{-%3vVj1hqjZU-zwGE84AW{*8mCv?Q<9V+KiPT;A`{;SHQc+kP8zy%yQi&H4P zrV9jlePY`~?kfXa%G5)E?C#oiVMq3*PWH= zGGgiFXbdGFrrEXM9bo{-73zMU+z~Ty38&OS5Ue)3it#f4S?|{(_xF+ z9!dR_H_5qN=A0aQn)J(3g&>!zu%%rsm8)0bk4@=LbMv?-sG`3*jZaW6x+4W zIo;%NZz6v(Z*lR-88tux%I&h<55CKbq;pCH;*%*J1RxK#A8j?ps9^=^kv?wNR4uBu zz#wb4X2)A{)vU!x0N(zrrF;QDV^BI`6dwXP$N_gY7HjUV?RYe;De`R7<7`?K;u9ua zr5&bE?ru2+%COiFz3RjD{i^Giag%Tj0vfdpoDo)_Dm2FRS`D!Lcs zdON8K%x@=NSt180d6Tv$oLla<98yvOQ~8KTV(^OQ&~dNp#9@ZRjHwmD zu<%ooxx}oN3>e;AE>g=7Mjvx%zA{&eC$8R&;mTJB+q~!mO`M&GG6WQJ6wdtzpUE|? z^Cw8G@C0N$D^`kAkX|3{oZ%^6b`aK&Rq+$o8;bgqDa6407YoIjd7VSc&QT_wO#6bV z$~~EBu+b8cO+GqgOiBI>(5(n9VQWsJ`8k-h@RIS`;2J)&rnn+hN-%Ke*(g(7TZYRcn-A>Rc0NzRI9Y(ol^5Y9U;TJ0;{A{m6DC9e9l1n-*-G4?GfH}J=W{5b|G8O z0~V}EJLEdZ5vs^RB-;4=QEVq^r-`21cdu?gLt;~q&dACep$7YTuNqY->LBwbz9zbF zvc~kauu5Xc@Mey_Nk7IqNw+@BXNaOhruPpLr%m9B+uW~DO`3)pcgq*FYWf>T?-8q} zMSj|4&oLjOHv6W@*ZArE7g73)!K>#g0Mc%bVN02F)V3<32*_B0jtC1mIqw|ml>`ud zxZfd&Uw~(zih6WBb>KM^GYrObt@4;NkTnmC2v~?}{-m7Xx}8Cxzbo^Dq61q)@d|~h z!@IEN6VXle1j<>e2o6L3g2q+-vu}=#0>}45hQ8lPoFf*5&DbMvj*Js=Zg-Z7bwvrB zcfIBzJ9A0DFmE$3g_dlcl=O=*jp5lW4Rgz702DNMJsQ%M$enHr0lF zpX%A58UuOC5h8;?s>XfwODsw_q}Nx~ULQo+$q0UlnH6W@F^%O_n!i#Megd>8@j&pG zgD3~`VPRQ}nE?4zXEOWgc%~RRnz!d~L;9+2u%x!Ih4LPvpV*yej4B&pF_u8TLwy6H z-WYx8?Y&d{!z|Q!k(aa0cXzUJ>ZhI_t$dRgG?JdOLt^%640a7J8w*WHtv^|E^|J-WT()L+0$jR0YGpV1Li!Z24v)N)hLYy9nI&Nz zscOgiH6FVOsz)#q%_l;{7$wYn{l@fxPWt7;Opmom(;uSLmzF&5BX((|@Wq98BF6>Ps;tdY4Qg}Pyf8D&50bh+g zhg4jW9|WT*Rr$2cr_Qw_=O>ZVGv#sQ}0B zXvbLzIGek!*a(C&=DSMhyPI3N+vsbpJ&>1eX#dDy2&-Pl%~uMrIALzUZOqJ}-_ ze+CH>^Xo3`g~ywL0FG3hhwp`)!z$xEuP*pV%eIq`w#*z7kh0 z6;<{nXp>rEn2w4an!LgWvi28HgR8+32$p-GgnH{1QijAVWN1sLNwH)jcX#}#HW5Eh zLUR)^vSAS3YQzeEfK(LCGEfmlubbjY`r|j2S_`Me8i7Y~4dsO^*QQu^Kcr=b6rv>m zh|aWv2Ei)%G$Opr#}50T7U06s-3|cAnI)2rL}Nf&$I_~OQM~h|v?&n`RKGa@H`A6U z_qaH2A)_R{hpR(aBo>YitFW%ags5F}Y8UqCY<8hXMnY^YNV@*J;A_13KWwfg3cGIC z1+fDnKSEV}b158Oibg#sAnOJwoX^OQCSAw_s||Bd2vWv9Be3Jq-N547M=6rGADyRZ z%VeWbD7l+2E@>#4zgQpJ2t$^%1d$`jj=*}}0b$3_!w4A!XU=}mM7*Bk>;Z$~WCvlD zC2<6;ELmrR?Q8--#@yMSR3}@K?nPkJof?1Qjw< zi(S8eGPg_q=>kEPu_$h%Evt?=)-@?f4c*^~R=+O6;lfqq4HAiZq22%CNns__iI`r`H_ zVuUFdSW`7SUAx@I=2OtK>!d9~+-V@i5mQekSmW%9oc~AhQ#*bk4r z&_iJixZ`+w8?7oaIKUhsW5~YMQOCT@RCpi$Y)?!T-cl1dbjMCVc($8ld2=F>x{md UbeXLd#TYiI>bWM60s{etpl{Y(Qvd(} literal 0 HcmV?d00001 diff --git a/libs/ssl-config/src/test/resources/certs/ca1/ca.crt b/libs/ssl-config/src/test/resources/certs/ca1/ca.crt new file mode 100644 index 0000000000000..08e351d886c2f --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/ca1/ca.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCTCCAfGgAwIBAgIUZ0xcthORO/ye5P1Ia/IarOGvwHYwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJVGVzdCBDQSAxMB4XDTE5MDEwMzA3MzgyNloXDTQ2MDUy +MDA3MzgyNlowFDESMBAGA1UEAxMJVGVzdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEArrEcyCaTpx0JCZdNAhb/nGROBRNPl2QdKuFM1pLRMoKl +1XAMYRy88B1jSuteP18O+pk83F6jV7byYyp8f616nTHqoFfzl4rN/iM02b63/oQd +qSSn4oPyiPfsS4I49taSJnH+8slbNg9iyiwoFnywcVaj1X9t+DAQXDFxNczpuIiq +Q8apxoORiJz4U/sC9dNOV4y8DnB0Vi6Ypb3npMvt/H3mvHC6tRuibVNSh2oBSa3o +gA1+ovxmGXavxfX2uquE+R4umgTr3HiHBviFvw2o1EPc9wHbR0iuyUtym3REIFko +VmdzIanZEtdk3HyHa7wggP9zMWfETVZuurJ64VhL0wIDAQABo1MwUTAdBgNVHQ4E +FgQUh3fjY8KpBOoVTBJ5bcenE/g9dZcwHwYDVR0jBBgwFoAUh3fjY8KpBOoVTBJ5 +bcenE/g9dZcwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAWTDz +r1a7K41KefdsjMM75z6Vxm5nXeGDItmUWaerVVUmRkeln+bbY0uReoHELuTA76uR +TMt9fOAmXpmfhbssRKv9TffOg5nb5IAvjDDRkCIXCJvBHcNLuYsTkjC7beuQEfSg +3ayoRWfaF4EliTk96pEsnGNz0szWkhx/oWvZ8pvY/HA80xxiAbIFDgh4MJhwiCeh +1PwbvUx+i6VYfM/6eIGk1WIY5wJR56Dj8afVsOED+hn2Rs5oWFXY0Eu6XNHJfAFg +RyaTrL3+X9SK08yUJwQMFnW/k4IUKWi3JyWb3PwGOqIjUXIfNH/WkwMZSErkyNln +mHWm8kQbx9OLpi5BlQ== +-----END CERTIFICATE----- diff --git a/libs/ssl-config/src/test/resources/certs/ca1/ca.key b/libs/ssl-config/src/test/resources/certs/ca1/ca.key new file mode 100644 index 0000000000000..990ad2d005d34 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/ca1/ca.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEArrEcyCaTpx0JCZdNAhb/nGROBRNPl2QdKuFM1pLRMoKl1XAM +YRy88B1jSuteP18O+pk83F6jV7byYyp8f616nTHqoFfzl4rN/iM02b63/oQdqSSn +4oPyiPfsS4I49taSJnH+8slbNg9iyiwoFnywcVaj1X9t+DAQXDFxNczpuIiqQ8ap +xoORiJz4U/sC9dNOV4y8DnB0Vi6Ypb3npMvt/H3mvHC6tRuibVNSh2oBSa3ogA1+ +ovxmGXavxfX2uquE+R4umgTr3HiHBviFvw2o1EPc9wHbR0iuyUtym3REIFkoVmdz +IanZEtdk3HyHa7wggP9zMWfETVZuurJ64VhL0wIDAQABAoIBAG6T1fAr2xLRIkNb +7ncAL9TC+U/lJWBjEsNt0cGRNbKPWIF+Z5ehJUeoko195y6d8VFXZlrn3OVM/Kkg +36XCHfca/bV5dsvaJQJVLsMWIkmNP2kttsd/Viq1JHG3gG9e6yxCxGrSYlYZ7yKi +SM3TJ6zWduZRvz52ziRNd6fiiZ8wc/wwWMXvXoMJ39EhGdZKKTowvKU59oV4ieg8 +vEK1V2ec2D6RN6m0CHzm4erKZSIJoMJAhKV1D42+z73XhJuv/gbIlUlXrG1l4XW9 +Sd59dU9v4NGCv6BpqQqC//fVwW7KfTGwmMtL7AP5vria/dzf9EyZxPk+HLgC6bHK +Y3TU2WECgYEA9x0A/aB/4CepYAGUxIlc8r+ylhYTWmUafjvBJ8fPQs2PQi5JgE2s +HE4yRcnPIZPaDMYDUPluXoSkirX5jYqQAVeOhTut8tTwV1FMf57P470FPVMgV5X6 +axsiMBIcRvYAc1cq7n7k45Ix8YNKfp5WjG1r7XLR9Xa5Q0Bno9WxII8CgYEAtPlg +NuJnSnrka9jZQQTvzp6ULP448MWdjHmYmj93lUIC9XL3hkPqu+cZjZT5C2xf/36w +5wEAHSNVO8SUjJ1bKgjyfyvaxosonbrDv3TWl1Ib8NFmumXjMzCw6LfDmrJbZc8X +VA7VG1HClgPmojDc61s/F7unRbRUcIowP1dVOn0CgYA/u/xQbf/tSW129JFxK1iM +x4KBEUqGiwMNQc4su20qdqgXUqbkb6QPXN+8fjNtHpwjpUKftOWRfTaPDCZEKlO/ +9NwuYtkXg3JFoxNO6yAFRfA/A9yYmncO/t2PdmxSpQoytW2+O34/b6pv9wPUqnP6 +HhKzGGUsoSVhQhA5All/4wKBgA9Nv0sk3iM4PTS5g7Wx2y2Xz2P2o44IyAfnCHaS +w2QFzwY+kJv0BleZdVm5rU2//mY2qnL+bKoKIN0LBJzXeawWUZtbdAayId8kugTo +tnTZZq94pb1BfHMJvQwQ7iOYzY3Qc2KSVocW5OOWtNwmUag9cRpqrfyBAVr69JWG +pxhpAoGAUYkzE88ay83byRR+I/bVLDyI/OLs9mSfPJ1BbntDnmzv/ReUJCr9cZvo +18/iQyhICA1IO+V0JgQPRY7cz44cBTb9QiQJvtRtFyyKLBC9roYZ7Y8CfTAcX73H +7yY5UdS82r/Quu2Kp9EUbrTqmev7h8k5/kjXkvIdLv7soLMGJh8= +-----END RSA PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/ca1/ca.p12 b/libs/ssl-config/src/test/resources/certs/ca1/ca.p12 new file mode 100644 index 0000000000000000000000000000000000000000..0fd23865b718dbe636d5858e2df48de3de29f2c3 GIT binary patch literal 1066 zcmV+_1l9X6f&?Z40Ru3C1K$P-Duzgg_YDCD0ic2d&;)`5%rJrj$S{Hf#0Ci}hDe6@ z4FLxRpn?OnFoFZI0s#Opf&;1s2`Yw2hW8Bt2LUiC1_~;MNQUt@QkvZlv?-zL zNggUd=Re|zDkEVabP2V;Msf?oB-y<7Pc8o4(pOWQkuf5{aShe6GSeDmnhlWDp%)i9c!&h|PADoo3D|nb$bXX%5aLOfl9dcVRPg@AL|JoO_`? zsF>Wvv`v!}A~}dC)8s3}9PY21*vSc8!_dGj_OV_gvz5d$5&Md+S}R}CF#bJg>YAkB z)?S0?;8Yn?7N3SsUzb2Dc#vD3><*6{D8EnvmvN;igvOk(Iso(Kp`+oklQg5*~KJ6{d1g`NOctRsv^P zlR}xx1xE4XF&-TcUJ9SzyK!ZHk-hI!Fh0iC4??b^Mw$Cb^&dwt$69iBB(nbCf^JQ{ z5VkWz=MyE8_9n{glUkbl7VEZEENUhJ2n7;W?lE*S`<#9>#0I=-%Q>ylRlI(S7ocXb7O_Yk z?k68~slnmrnK69u)Z_&TM)xe0o)9vi54QjzUKC{Tam}{N3`Xi2D$)erTvRrw-Az$a z-ExCr6RtSEx#aOM$I8hOwz3Vr(|aHyUq$|V1~c*!%(P7NZjli5 z)I%;!I9Ms$9?Z=`WY~x;9kN8$#9ub^h4nFUW_b2PQ6RrXAMp+CFZ%;mC5`=?ROpAk zD3pM@qrbiSRpTgzhF2)HlI)`cj>l4_qU_Fv#`%M4_ltg2PZNtvH+zN*I!li9H1f|* zldfBjrXQ`TAp#!tr{Uqmb(H_ON1`Yb%yIvnt$2N_V%il!&nNc)59BqrS1do>`|#nq zsUMlE=I$En*Eh>$>U?A8#8G!TGeDetUe25zz=FNe$#hpu-`DG|H{5i)PHKn4y#-^& zq=c!UdjwswgS2^G@$x^w0$M?Bc`!aOAutIB1uG5%0vZJX1QadxGm=y)=j6x{eY~3m ked4onjVlBc>;V73IoP;Q@`&Z{sh*?z8@$}-9Zc8*3>YK0_UA8AEsf13{} z8Y%i;0zW}_8xrfYu$sXepN}%OcIvsI)Vgf7Lr3Lsb$~ZgtxbpDdax<6RlTC0|hGj_IO zAWC+x3`xzH-RSb10=2b&e%7lIA2@pceQe%3!c{Yi(`MBmvd&iPxaZEy|C*;q{KRVclj*>aG$>Stbk#p-02Op)DTlQh)h?U4 z ztNa0U!Y-BK)+IUM>)m|E)6e}k0OD_09@Q&xve{38er z+p^0XgF5*S=r^c@~w>{u{tjkhW5`a$}X{; zcZZ<&P-dDrWas%FzVN|qB^f$NWEHEVTD+n8miuE}fHt0%%UV?FD_2lYQzN3f5&Y$T zDwO|J#RAY{bdiY)9!@Y&59ZP~^{acj*Iu!Y(e!G^mW?;!s~FC;Y(An>Bf~5Ik(tS2Zd3}M0_d16)%g|Tm2NsG1w26 kQK^!Ii8llkx=mLVA{>|L9`%vqgfb~E0s{etpw}7kAOHXW literal 0 HcmV?d00001 diff --git a/libs/ssl-config/src/test/resources/certs/ca3/ca.crt b/libs/ssl-config/src/test/resources/certs/ca3/ca.crt new file mode 100644 index 0000000000000..3f408375378d4 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/ca3/ca.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCjCCAfKgAwIBAgIVAJMN07EKmD5RR6PmEZDjqSWBpRY9MA0GCSqGSIb3DQEB +CwUAMBQxEjAQBgNVBAMTCVRlc3QgQ0EgMzAeFw0xOTAxMDMwNzQwMTlaFw00NjA1 +MjAwNzQwMTlaMBQxEjAQBgNVBAMTCVRlc3QgQ0EgMzCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAJEPRYQiGOmfaHdOiCWPqzWgmHgbdw32yaQFKUOqqAQn +OhkujPg2jJdqMjp7aFrZjLjVi2WyHdAPe3ibuUHT6PyTmcgtDxe+xAUJCG6vJKpy +vrDNXVq9rotts+gEKeRbhr0lw2lppDhNNGiKkRm7R2sNRTyIW0vBNujicSWcli2H +hQDjFWornjcd8OBFLvhY3tSwic8uwuSAYgrZfWHOgBWSC1xqUFHa6561K264yeNZ +8cyb41euYAsohdQ/VPPFu3ISEYlZwTwwp/e2l8IpgKpB59Mrdc1TonpD5h3XMiW8 +iPJE0eZ9KJSv1SzEty2nno4s7LAu6cvwXQD2RP2vY4cCAwEAAaNTMFEwHQYDVR0O +BBYEFAQZfDT971m21ReFP+rO5pTFrLLIMB8GA1UdIwQYMBaAFAQZfDT971m21ReF +P+rO5pTFrLLIMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEHK +JublAXM3FprLQRU+MAIQyZp4VpSanxL/JE6UkGv3P0aQUQZt7BR+uv7xWc1Ygrk9 +gOK7pZh9vXZSUc6NFEa05O9lXUvYy9UN+iFxlWPe3niPHt8lW/6oUqMfnE2ePIG6 +Iaoaks29qwcbKYnl4ZcurdbcCfCoc7GAQYE1zKO4fJqnRogFaoPEwHJ5+5nmd4Xl +8TP/v4ISHzB/cyCIiA9O8EssRXLBxwd7zgY0kicBKgy3/Rtd/HfGLunZdBBun6Hk +T5L+SVLGLIoFFahA7NQUQPKzrx8KMgh6SiskWblc8pk4/Q1Z2q9E1L69z4SDl1oq +HDYgZBcLjn4QXONgz8Y= +-----END CERTIFICATE----- diff --git a/libs/ssl-config/src/test/resources/certs/ca3/ca.key b/libs/ssl-config/src/test/resources/certs/ca3/ca.key new file mode 100644 index 0000000000000..3626d71ba2032 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/ca3/ca.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAkQ9FhCIY6Z9od06IJY+rNaCYeBt3DfbJpAUpQ6qoBCc6GS6M ++DaMl2oyOntoWtmMuNWLZbId0A97eJu5QdPo/JOZyC0PF77EBQkIbq8kqnK+sM1d +Wr2ui22z6AQp5FuGvSXDaWmkOE00aIqRGbtHaw1FPIhbS8E26OJxJZyWLYeFAOMV +aiueNx3w4EUu+Fje1LCJzy7C5IBiCtl9Yc6AFZILXGpQUdrrnrUrbrjJ41nxzJvj +V65gCyiF1D9U88W7chIRiVnBPDCn97aXwimAqkHn0yt1zVOiekPmHdcyJbyI8kTR +5n0olK/VLMS3LaeejizssC7py/BdAPZE/a9jhwIDAQABAoIBADld7sIIsg2Ca0/z +kMg5/x2gO2wUgIrXNHtXRzBphzTNRp662Ck5eXRQHTkfoO985bgbS5uWS1ADL3NN +MoCkC5oHzWNq3nMnkGHlZp5PSZLW+i71qJvANA0T/3gcXWzf/XNEQfmoO7fAYJ+P +XT7t35qojt8XlfNpoAuNse2L9aBfQ8knEP7Aym/G3ko9mD1dvm2YKYYkzpLKYOoE +5MpCNCAcdn/va3bqEEgzq8ogwO9gNwerLnXCbId6xpInwfoTE6I15UySmeDQg+8P +nDiVWd+/xCEjFVBNwxDG1BjG0j2AlUZoDFuBeRmn48SjgRTc02PRdGKdC0Mys+1o +ZMIEpqECgYEA39/9vfGAQpz4ssLFL+AqKKRmgJwt/ZRkHtUK5w+c3dZBi1aRhWMY +5mrQt6USSm5YovJR6bxvjlD/nVwnENprLYdlrwAIEbT9jpVFtGHZqQumrH3JmGtu +Uz3mjZuHXblgoGUfAL6X20qK891iJoQ5VUtWYrP0ndd1f8CyE7/qzWkCgYEApeAD +aCBUMFBtmmXXrrQWBTu9tTgn26jMmFk/p5NBeSKGs2GCUB1sRgPUc35NCdtIetjs +frQlsEOKTD2PAnnTKL2ZFuk/mxFwQIXJVjAnhMICm92J8UL4GjWH1EuaLRQqks57 +n52dd9mDZFFE1lAfAihq9BEdLfwgFKlgoyl8W28CgYAzmwt/tGKveEWv10vjDFZL +hhIGxXmogYNOxCc+OhAb5t63At6Kk9xSiP7RxmBf/e26qgcNzR0d/jfeCzcKIH8i +QJrE60nw4vqr2mb1/LRSzle+XUSSOPl2gMdbjyV2ClxmvMiXwFd6+kTrj/WnEUWy +Dqq8F+VkWR1BtKaX/N5gOQKBgHsBNqWFq8i0K8LeGOYFx3qUBacYAH6kmyuyq0CC +M4A3uTnWakMsvnjhKC+JDmnrwcDPkfiXcIdYXnsQ/zbvzkWc66SQzUkZ0msWiuou +BXAuSq74xu0xIziUT6h/c9JP7Q42rnf78qTImOXQWkKu4X/BJybcdg3+tG999xqn +jf9jAoGAG4hzKaKqvqKOfDGr3Eebu2/uS73xtUTxiUheqIqoTJHO4jjWOcjKI1my +91pnfC/t3fGLB2ObqDTw+H3jRf7gqIkMbUAswjpMX3GpOm2+eI5U9B8y5dV5PoUt +RV32fzc/xu9Ib2i3Q29vuHrZczb4lxpi8UVWCLcrPuvC2lM8QTY= +-----END RSA PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/ca3/ca.p12 b/libs/ssl-config/src/test/resources/certs/ca3/ca.p12 new file mode 100644 index 0000000000000000000000000000000000000000..1331cec05d77efa8874e1488cdd01ff1d86fc940 GIT binary patch literal 1066 zcmV+_1l9X6f&?Z40Ru3C1K$P-Duzgg_YDCD0ic2d&;)`5%rJrj$S{Hf#0Ci}hDe6@ z4FLxRpn?OnFoFZI0s#Opf&;1s2`Yw2hW8Bt2LUiC1_~;MNQU0?F}#D_;xm*aa6sc0s{cUP=JC1aJD5(nerH+Wxf+5Jk;DOZ#buyM*_;P(}c9T z>PYG!7k*@G(StzDGwDGN<2a1!jLVC_p!+=s>ub9P15zr*-ZU zj`PaouF>j$iL?*Z^%g&?FL2wVG=I!hof?U*O(;IFD+}1ic+?kCmus*Fzg!4>U53*J z!E6?v0@UI48njrBewaRg(4ky3+3_9rHiVP1v}ga83x>cQ&XWX`E7qImcD;>};!Xq6LFFS$D`mRWga zE`Rs5p_4}-Tsm11roRflM%S!o2%@AO4s}h`f9!8_Q>c@YTAmr94l#X8r9Y4r zoO=vWkPF~Ax;j>W-ojK@(G8qN_JPjO3-lkGZFf!3iS~CQN!}e zUZYS+-<_F`=$)Q7)r{UnlYv@ zSogpwNka{+*?i*&aruM>$*z2Ly#KLC4!rTe#4Cp}PR)v!z2Xo}V|RMtS7EIqtX$`o zFi4`oAahbksnxL56N)+Y`1}=R7dC=Pm=CKDYhnEI%s{g_A(I&|+wFUHii7+xAqLQu zO#J0woy}intVTB)czqha`k~AO0U|XJ^?2SPk9{I)0iVzLA;J)QM!CTQNa=NzfX}1w zjLw%7FBmw>sqI7F6RebL7Eng`*BFc2B-lZpl9Sy%g^Onk)N*RNY3N~bS49^75<5)2 zC5;TUw&ac!7(!EAuq-_HbtL`KoeS4}tx<%tU)1ZBx8^cqY~*@;iUvEp=$(oGQStY@ zJIOT8+rN}HJMoaGtFI)OvCb9`pc9*Ddh2HcD4L)yXQHZLNGvPF%--ph>LcKF{)BTy zIIlR4#{?{rx0W!OQ60ali=Q-Gf=6{uEyL3}JyF2Iz}lTNs#TMkv;Z-$S_9)Ore?Hq zz;$$d(b09y3ey^%$=0SqHGlG8WiUQ4AutIB1uG5%0vZJX1QZZtwI7X?*GEMVo|vk1 kaJiE^Q7Z%#z<}{rL?7Te8a4k~6kM7xQr#1h0s{etp!Xs75&!@I literal 0 HcmV?d00001 diff --git a/libs/ssl-config/src/test/resources/certs/cert-all/certs.jks b/libs/ssl-config/src/test/resources/certs/cert-all/certs.jks new file mode 100644 index 0000000000000000000000000000000000000000..4cf839ce8d046fa5e18de403210a79844870d002 GIT binary patch literal 4268 zcmcJRWmFVgx5uaGhLM&~ItPXn5EzH<1|_6ZYDgIxB$O1CW?*S&*~tcZRSKmbLg^Ru(1MHeX{3PwxG|#-$PJ?o`>|_uCW{s zfx5s>6o}~LJruXW_#4_9fywxQ#hi!_Dv>o3=v*OJ@-1*f5`XemcP<_}TVE?m^;{E) zzEUCDD4&|YRrv&%A=HMwlZy)en*O^9M;@+NU45(Zi``3yRZ22%k1jceIIA(yw@urR zkD|@$=c?ABbv1e67f#+b_HVT07oLnf?$>0|t09)Na%7fbT&X2Z_eGt|sh-K1vs;dQ zQoMWhhL78C)HYO3Kd9R{mQ~C^ngQmN(|BBy_SfK{k`AF%cY1YR|6GQE<5)*(uL*pQ4Xagr@j>o`!;o!b+Nmw zq#TFaQ)@u)h3dvKkadL|>k7wy-+HX8O7UD5DBe4)x#sn5@+Lf4hm~#0DAEVbJB~O( zuPVs9(Z!S^)#{qO-ufyAov4@!54f1EG0&&x7v?AgE}^aJktv+_7bUk$i9Zu;Xh0H% zb01hfch95IZw8o zGTEIHHr{Z$uX-$;yfA8M!`F-fQVDj>$G|)#F&DgEacahY;&aj zL}F^XM)QT=x#`BnGV0VJN)_>n5a%J4nb)Rrx9elkQA>LI(GF#0leYJsHPFaxpsF=9 zf>FS|GWwRCVYQBWaFQ=lipTAT6lyO(bY8+rO$#wX8$l7blhGG+e^~DW(OAggNMcJC z%a*0@oOpP+Hjqx`u+ zQRj|G*-Q|m{;U}G&lB(M3jlq@b&?OTEC~W?$M!Qi?MGTgOc#S1~j^t<@XmTWt2u-%? zYwh%6yZ{4t+^=XirH9qF?}iya*KD?&GGv#t6b2K?q~x=9+vi&6)jIF5>&uuFdh<7|lf_VX^=K zm>m`cW`RY4z!)$H2m(QcTvFF$I|@cy$Ge(A*7pss6qBi76oe!KPt>3MrT_xT2mmms z7%hyN5NrYg(~%fEqWn1SDRYRy*cd3pWMN`3I80hXOj7bb1BHYXOi~>7?+`{UMhPST zd)ME#42uHZ`sdNtP7IC$QUR{#NkLISAYk~Bb?wZRN8Lp5=knWf{0{h|qZF;a4beb$ z5`x)zolZJFGs{g^zGKaY)MR&gZo#<$#-TZ$vG@>{UrglC)ML1S%+QDwF+wOvS0a`zO7us)1S^0d|P2mxFYnnTq zH!`Nfv#X8^EJ|v;n|YO63FpzzO8C^$^odiEBx-o+!u+{rp@``Fd$S4F?V^B8typ)% zmxC1q1A}xVG%X=y4iJ`iXIK}h2^|-}u%`lM3I(FR`bj*KKsSM~1kkc{_S&CsV!!s{ z<5lW84@`T1(3mJvpp|41;z#_HL?AE_0K~e&oMAVw@9icfgdPHIyCe_`BNq0zsa@A;;I}vc!5)EkI#vnmX z+;-%gl}t$pF*{bxfFq@Rs_MttlsBeAF5z^1XhEjbzGMk)*=_US3ssDfmqtvXW1Q%L zGNt!V8RQz_NGxu>ymG)S4c;(2wr%UjhPACrWUpG&5)elt9@xgF->axxrMB;g-Qaf0 zZZ{@LkPi12J(A8ZD+J}lwcWgZsOBd2Dp1a6)@%M9RksTf&7Fpb%m*o<;!7+4}hQL-_{+z;`^KEFEZPp!gt#unbEQs-XW6OUl zie=t2Z)#btUTv=Yv+DWfA<7^CZj}_#=oi2uL{)LJvyC7i=|g1CJZcpkH{j54^XZlQ z0(7Btl(qGhQleMQM7$SDuJx{`%^0L4ze-!NwVRwEGNCJ>DojnFVMt-%s^YtAHslDn zmwc%91$Jo|zY>YK-08Qmm$Fxv+Ed!8+(S*tepAVF1P8+22tncJAYN9 zzC*T}dKu0&w=90h#Q6=Sm@M3ls5sO@PX*PdDl z(g@!i5Hj9t#8WdvR%>?W>XdmEhXSGbExmYCsEAZdFkclba^0yk@?h=#nh3GX1kuuz zf*Y}gkJ*MKV@GVRUaY!=vqe#4@-a7cn`DpwyPPZ4C9S01ZTe=!nw|~4#KgYBc-d&N z3&&wfm-7Arl%w>CSAwxO4!o7RK9g;tPfX{P|FKNIt?s-X>vlyqzfA#ljf-NucD3H=pSjWsNR3*4Ai`k>Neu{MHi=W9s8 zRV%U1VjxkqHHQe(E&&5=r5(LEl61I`G*^Pokulu?Nk;|^UZ)2*M>`V`BZ zG*h}tv_Zvrn`%tx2YT%0#hiDeG(806X72x>O-kJ3O4(xdL|2Ldx-D%m+{sClG-0Lr zu`bL`A5lFz6vtK}4l=1HoW8RPT8kP*l55&lqo?p>W);+lWnZ&LcY4u1;kIx2SLcZ& z*^ygM0~6it+DuYEPJiR*8PNBg!`}oEIRl(7BgOvHE%1r7m5}9$cJ}#=VH`mQGn= zhtx=5AABf2?;KJBt=s)Ih>j}~?vbxFZVFaqpht1dFfs%M%vjm!^YJ4XFiGUa8Jnvc#1`_ZTXf)Bl- z%Zc6*sS7}}6EAR{t7UmJ;SOS;5fwH3(IWM(@XiP&i?J`@HtQyvUezh!jl1&XPQla6 za;uK(U!pW3%=1l>`IKfHAIiDbE)54!c?1jois-pnSdgRI1=ps^>NBQ z=v_x=#ZcI)#n(aZtcmJ?oIEO0Gt%?ku4(Mo4M~xLNLqZip$Eh??q1}U902H1ZeBps zV>apcUBl^)&)kov%y-3u`26BGY%ruB4HWiV(%pk=Uh964(KnEC_VP3bZAqQroRNZs z`kxh1phXsBN!XKCsKk$kFg-I-XOMd7=|jf*EwKbTZ)86!V?1q~!pfY@nLB(L&@PK%XW=TvtEz#{lT^fy2W%ZK oA{e*&IeKkn7Q)OmUv+aq;Cq<(2t5AN0di&a7x%PT&SK5K0P87#`~Uy| literal 0 HcmV?d00001 diff --git a/libs/ssl-config/src/test/resources/certs/cert-all/certs.p12 b/libs/ssl-config/src/test/resources/certs/cert-all/certs.p12 new file mode 100644 index 0000000000000000000000000000000000000000..b971a1e39c83baeea8e4fab3cf6b76804047ee48 GIT binary patch literal 4757 zcmb7`Wl$RmmxhCr0L9%36e-r=R$PJvC{_v-N{SR|a0?J5m*P%wY0yHE;#RasDQ*RF zarYJv6x;63?)~QbvpYNI$C-KFIp^myFBnCYgo}d*Mp0=K0{O!=!?9#IL^x;^l^i~b zO6m_51EWAq{}zEt@ll|nKNt;05kLt^{`-m)goBGl;a`JM_*n2`LeT%ZQW|>v zOXt{p;c9YKJ;i=Gq{^s&)aJN~Bx|d%*htydiR;8`<+R#p-DyH8?=MB&${HemTXdcoy~(7gxEmoNzq>rA z&z^TBA{y{hos(C!rD~-B(PjRIqs0W7x!=*sm&@}nnr$@9 z2l>`k`c265nbygglsTeLGIxL0Ses~uT|}(8-Ajm$l(e2gtU+x;dT*O`^rCV0Sp6f) zoXxn5I_C&2Vz9CBN)~e=^1}9<#ay^rZu8LFF-N#C^ufX`mqdI5 zl|@<&=aa_L;O1?It&b!DC^Ug9YdoTHsXetK^%2R}Po0{kP;LkN=YV=Q8c;gcCkCdi z!kR|5CD$n1Ad$QZ%fN5eHhE~NAq0}09_j#H(Q z=)f|k5pZ9PcFpZw9ryCKzhl)p$K*BA&lN-A*nLnzwDZ*HeVFVW_w-K((^5UFXOca+ z&L1PfHaxF)-#{LoUS(UL$C`K^Bmsi$n^ol@DYLe1m-+R!AA9ArEd`H+VKjQzlvHyJ zy=w5m4?J0G>Pw%w&ms}~u1dNrWkpY_A9BfNaaeZhKnGXdpXrrP0`9V=SoA(>5xu2e zy~QK*sO+`-E0?YO*J{q#w)XhfOu#O=IyAt%p}`xeLg-Gd^(6t;%GZg`hiPMzS14dkpE_Fr(Kk|=1 zSZY>f1d5w#=InNi%3sIrBLvt~&v8zer5Q17&`@%8`hrQHa8M3+Qe{tao|NqBqF(PE zr4?z})YkLnhO3297TGVYA6^j-S+S;bD&sKAP%;og3ixZa@m=M-&v@$rM9NV7vp2+xGE4IQv|C5;g3v zkVjo5(NtPB;C>?bV}y7Jij5%KxH{Vj!)LkUQG)lbeAFa(`8*mp*ntyHsH=~VR8M&; z@-*+`ZZhP4cYALc*6H65p;&)J($8oEnK-uYO8mJoIc=0uFGd7}ajD4`^RdgyUVwFx zo;jY5ErU}QMn};XSp*hs&k+&q&*qp<;7*@qv9?NGxs0V9L*^gzop%%pvKiFPK2eAi z&@zfBfEoW$C6Gphlnn&10oVaN0A2tQFvq_lS`iw2Dq}~u-9r%xaY+ejQ7~BK&-_1p zdMrsQ%Vb%YV9R17WYp1D`x?o?{Ett8A-_tO@CzRi#XjV*I&pAICZyByVc(LbyV`?M zA;asJQL`rJl*E^;lcuNNGIVOo09`;Kp8ETWI3MY_7*q4>60qw+xIdY?{*+K&WlHqW z#v&g&*e3rzK<}i-;sfqrommiNA#&+FIjJM)L$;S8E=0| z^n>{wYL}R17htxyXB>s|4cwP8s~6wDSYQoz&<_p)!~48+EJY(FMYWG&2JmA^F% zt1WzAlL*dS3kYLt_=y z$442qmu_R{(9&p}G^cQ->NQ<*W3FsAi}oNUAvTbS#AU)7H{Rz4U8<2VyIhANq5ICg zo9PNj#wVW53j$}Iak)g0K;xsxyhA*PK1y_VY}!pYg_@gbr{FxjpYP5p@#i2bk%`QQ zGQ5mB9k^ffq^N=hU*g+frhT(oM#r?qW^V(7dXQPywEWgLdzL%_Q5p`&5Au@f}(L!97 zwIlYDbJFYU^AwJ|siFtF-%s6kKj^q3u^pe*~21pKmlL6fSTBC;6 z&|N21nU+L;8y6UFP|=9dL8w05b#@{i899xM)S^{$~$rr78P4&B%nI;SZy zhsk=z^C{;GWhs5X)GAxwu0sy)@4wKTZb4e^s8wQZW0ZmPVjm(BLSFe<#K$Kb)=UY` zUUei+t9Y7h;^P~@YsP4Ij|K1`!2p>5L=Xd`b4GU>8peL+dj=P5h}sVr;v?S3hNUQ<8K3ZZtB)!`Z8m0Lc~k2tmBFm7}D37#uv;)opy z2heYp7`AMI0l{a_f_;lLW%_nmj78*^N*gABUj4KSqmpyEtvM-S`jzFf)YH7YV zwfdK*V(i(;#Jkcl5Ctx;Q8_FUXlRLjSw+jr zGka=V3^pFZ*cY2-<|lXMuanoN9$c~iCVu(kk4=CKDv#NoPwa9^W4UTOT7B;+tT0=~(UcpeOMp0q?hcy+>h zDf7urN>1gMGn_l_C_?J&g+2goY?C}_X6F6xTm-gwU+abS8$O}Emb@|IvLSQJT{tNwA02M$zst=7+FC?s_lX!VVrkbV`fzMP?-Dbs2{u{ z<$T~9*8eYm?xP1U2W1tZemM>BC7$GTF z%@5SVX|!7$6YlUUh$s!cfq!TuowxCF>ymM)JwvbW4%?0b;k+K&oXNVMV3cwgMPNKFaL4{tz`umkj#SmY-nJ2+K zquLnH9qzc7P9DZiDVG`A7hbg@G+gNmr~5OM$aoGb>QnIJzBmxH*Mpp@8e z7Z6Kt$V%w8MEBNt%WCxeQ0;ROE5;Ksy<2TV7}$P(jr`0E>MX|hgxA1;xJre%Gjz|)CwU9;(-``QM=?P*Vf%6He-fX z;Y+GqzS|R(Wj58kg@!55_rpZKGDCXI_hjosU0|L|OE$IBymoFy8&JzH`sg2>nKiM+ zMLAb1q951|@bRj@WPRJP#4*T{FgqLPCp5%g=nU<@ais*;8NH#<|N_K$WV< z26=5jV_-qj4|?k;JXqP3fcGZ{GIau`xix@i+oq^X$C1RgJ{)OdR;k@a?#xi?=2)%z zT!N6aA!nbexXz`n!zW6sen!#6;RC049iYH2OsV-P3WA0Dne@JpoUE1lOEt!~({6M!jqEn-7_BU`Qa$V5< zL<-~pp)QRmE$VRD+W}EU87HtIW*aMx3dVxBiB0bYCW#BhdIfJoBGX77Wzq3MBRXj# zldqnYC)jih497XpwV<+@LMZQ@$NeT}Pb@U~6@hp|jGV}(lt@P_wF3!v zo!F$}sy;Zc^Sz0GI@GtyDBC@C%;?%syv|wxhe7kOtc8iAyOg%&KCz@~yo@s*PE9w-Hg-91-n-jPPHt z!sn?I#is3ybg;XJM(2N}(!+j^-4fI3PDDK|e?Koh1pY}2_nvoq8+$+Q{btJ&C1rQ; z)JaI?c`XE=>pK-_)((z2T&Htk)=R41DSmQO%e3nF4kBuZ7#n*`YAw*gTBC;(pT*dV z^BDWUrPgovO?^kHwL7Dmc=dRpZ{W8O3U|-75_xd(6p}9#q7)@k1gsszT3m`{ybZgS z<{qD1qRGY{C^Bn2^ZrRt&H$yMHn4mw^wcJYuu-NxFgCqX@Io6X6kT)FQ=Jt_eSZ9x zesfN&r5_6=K@^dTzikjOn`M27wXTaYUpEu&WE6^;1aqx*8zP6bR{fRt-Za`cKzlII zP=(Zma|DDG-0{n{kf=TctN`W!0|^NP9^m0J5diRM>LA_>ql5Rofm|L{s#SVZ-A`_) g@M(HC31Qq>ap_mpB^BEC+2M7+VpwtUaKh350Zkq9zW@LL literal 0 HcmV?d00001 diff --git a/libs/ssl-config/src/test/resources/certs/cert1/cert1.crt b/libs/ssl-config/src/test/resources/certs/cert1/cert1.crt new file mode 100644 index 0000000000000..51f39295f62e3 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/cert1/cert1.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDGzCCAgOgAwIBAgIUCYPL1cogC+8WOfSZytklHmrHQh4wDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJVGVzdCBDQSAxMB4XDTE5MDEwMzA3NDA0MloXDTQ2MDUy +MDA3NDA0MlowEDEOMAwGA1UEAxMFY2VydDEwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQCWz6ITDTlkTLueB30Jx0+7sWHdlM5ObZjWhMQ1eyJD0gYU/gkH +2C88IN/PtSv04tzFS6PA4KPDLIyaAhczPlGElSansiui//CpieCI4tt5c2BgVo3X +dJaylYoW3CRILUrlSBOMUmJCQEokverxMrz8DeppNxRfj99pQkoxUkmFMZj/C7XN +VYrTttdF1li5FUtWJxw234OUfum3PQIzz6YTmoPtLrJ2fB8I4CH8R5hwGcryhBSA +qq8pgy61aTPCgEBZ1c4Dvl65X8dG2QEVPjwMZnnbGjvlZefOgkmAWJ1VjihA3GVg +O2mx4tB4D2x5K/OAxh2foZkDVhqJfBkOblLnAgMBAAGjaTBnMB0GA1UdDgQWBBRM +RZ6Qlozj5hWTqf3+oTznFyZTsDAfBgNVHSMEGDAWgBSHd+NjwqkE6hVMEnltx6cT ++D11lzAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwCQYDVR0TBAIwADANBgkq +hkiG9w0BAQsFAAOCAQEAOTUJ64T6kO2H51j2bKIof4ij4yoDD86gLmUF7qXB2Wt4 +tMDCqs9+5VnRzSWY1652mpwPClcK/MfE26PR6DUunoES+8VSbARWh0OB6zsAAWyp +WJ4RxlfYdNpJZjpx3umLGj4yeCh0iOhfoArBUT3vaJJrea+rTro4UFE2Z29uWALr +NvjKZ0Qrn1DMP3N9b7y81dR9RMlzeqk5tlPhAqhHzQM0hDdFKA5uIFn71QQpd5SI +y8MpllWFGGq/+5m7FD0t71GQ/m5xCyfUiqQU31Nj3ThU21SPHBqZIZvQ/na/OaAf +GySn+0ZHAvyNRTL2y2Fk/YAY68kgx2E44H5YSqbFJA== +-----END CERTIFICATE----- diff --git a/libs/ssl-config/src/test/resources/certs/cert1/cert1.key b/libs/ssl-config/src/test/resources/certs/cert1/cert1.key new file mode 100644 index 0000000000000..461ae5ee31ba7 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/cert1/cert1.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAls+iEw05ZEy7ngd9CcdPu7Fh3ZTOTm2Y1oTENXsiQ9IGFP4J +B9gvPCDfz7Ur9OLcxUujwOCjwyyMmgIXMz5RhJUmp7Irov/wqYngiOLbeXNgYFaN +13SWspWKFtwkSC1K5UgTjFJiQkBKJL3q8TK8/A3qaTcUX4/faUJKMVJJhTGY/wu1 +zVWK07bXRdZYuRVLViccNt+DlH7ptz0CM8+mE5qD7S6ydnwfCOAh/EeYcBnK8oQU +gKqvKYMutWkzwoBAWdXOA75euV/HRtkBFT48DGZ52xo75WXnzoJJgFidVY4oQNxl +YDtpseLQeA9seSvzgMYdn6GZA1YaiXwZDm5S5wIDAQABAoIBABCilJEfa045/JQA +5XT3rD7a4R2s9VjHVA2NlYsEqxHqD8uu/dYEraknQyjJJjEb+Rg2MLjszoOP3W57 +fo2jeSBzx1DGIXQYYTaCQ+c1htoNtPrLcVfrv1exkQrWe5YOkO1blvRqffYq20LU +RB8Y5qmy60Fx1uh3mUAmFML9/agYVJo4yCxnNDrMg9UjF4bn/39uOf6C7mEVJRTl +7ET5wcbdl10EOWW2m60hJOQLSOY9N1eafFEO+V2Xb80PC2t3Mqt5+T7n0CKCx/p9 +4F7QAz+hsfksY3oTUUXwL0KoJTLdJrjCoG4mWJ/Re3qEKJqmMfT4XpJKrF7HfgcK +RCyH06kCgYEA/5TVQK4G1Dc4LnSCmCb+ECQvmGRBtK6Alh3Txb4IwGHDGMfC8W4O +gt03A8ZE92pjITHd1+cLykKBsmaVmEtiyD7YL5G3mumR1YdMFEBSZdxOTeD95+aL +YxTofPsDIUIPSFecRWwri7TyYcvUGyDchL0vDc6Gp95/ZFFgt26uxAsCgYEAlw7e +g2McHws9cSAfouULbKbf6jXzy21t6CeqJGID/kjdUws63prcQvmFtFHWrv3rKO09 +hgb3Kd3gUz8t9tAD3F718bSZwzLASwO5ujPHZQVRTotutgCGeKPgXqzyVWeo45ji +4DfQl53jG0aA1DzoZSA3/owcuX6CVGPLzQnhehUCgYAHe9UuuqnKhv9nJNQ6HlIs +KNMX9D+USdPMEX2E+caJ05MB47+KkD1uiYm125VjZUMX0rz7OHG472+ayLQyrGpt +EKIF6o9kwtgZV4fbw/Jltyi30RG+O5rzQMZ5+mOiEqwd4yrZQYyY36iFQpGoZbLv +VBbPoa+BtNsoFdXuKRiG9wKBgBjJhdXFc53ceE6R2N8f+onvsBp8k+6znC9WIuMp +ekJFrpur4hMZEj+jNj9qlnHMlMP4efn+NpyWHfNLEL3JUHje1Di/S+Pt9gPZLqbR +TEzVXIwo8RfIakhti6m9c150ThBazA/C2OWoMNYO8aDiBbhiWw3X6/a8PaKfZZfV +oTwpAoGASCTx55uThl9rN+XDKFXN500K4r+Q9OBOEkfDuDUERpBohUfoy8dO5eiT +mGiqx5P0hoxEC70vnw5fJz4ZpSJ7LcpCfq2TezknJP3MZKwTdBM/pODSPMU5YCW4 +T9ocEQui5PKOTLlVo1QKrG8w6f/YMfZuGa9zP/LmTLZEado9nuk= +-----END RSA PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/cert1/cert1.p12 b/libs/ssl-config/src/test/resources/certs/cert1/cert1.p12 new file mode 100644 index 0000000000000000000000000000000000000000..2635a887bc87e4b0c7eab4a4609caf53fa701a27 GIT binary patch literal 2456 zcmY+Ec{CJ?9><3nlNpRPVyumtm|G3TI%tH*K4VSDb}fa>l-)%`b|FTVWU^$POoT!r zOV)JlGDz8%iEPDVZugw`-hJH>aWM4X4cu&CGz`SKqj5$QF}a6e zXXgY&k%8G2CVt&@Tzz-%O>VLZvUb($?Y!d`jb8hTdCRnIr7HWg&N2s+qOO|&iMxpf z@Y&thuj(%;es0L?g`2!&M!yg-vAunbD&YVrH)x9ySRGcsTMxTw&OJaRMD_frPFD}g zHmzuu)8LnHFZ^9+a4&dMq{i06ObBFfvhvOzb&R~=yzB;R>Z_Bsq%R#i?aSRqYLxk9 z9c@88l85B~q%Jb&qqrHo+cKdKE-&pS2J?wFJJkYDB_*ZKVD-O$BivvQc$79oyVwCt zJIK6Y(Sz=saU|q*JdTF@wC*9?wwg=gt^K#^mt^r9SE3clQf05i_)=JWi+F4Qjq1L! z%AoETsMjt$YW$42k*59Zq@A4NX;)L0ExV>?n%11l$Zb@f?-kMP{A`V(tqebskL$&- zgV-Zz`4h|sceO&V&kGvDb@9cC*N0qbkse8`+9(`=;k@>_A?H0OMw@pmE`Ktj&5}u2 zUDh)@W;s44B~7hX8Fl+Wih$S~!4r_J?arbsO;CP`wnU)7k$Jf@KG^1ZZUuGJNN#R? zft*0KHByP38F_~VuLmpFPS{vO30gtVB!5PSmZ(ARyS-L^IOemFnT z^OfVjV_llW!?Z5Ej}%smIH%8j>wT-~nJP+t#;4rBwLg2T-1IQg2!~;i zevIk~{i)8CZ$;nElR!6k>APvHu;Nds_4Rk?)z|ICs%O3(#r~@1GihP$#iwD8r1V^#Pw3RSSp_Mrn zAKzD1=P|rkuPL!nV)*FlDXV+(0s<_rnfxtfS)o8ak!fm=D5($rFINO66@jx$L;sKu z4A}2`z9~~Tu6DhuvaqkdbckqCFPr?(eM687-#e_OM3YVCTV@_pbS=a&XF?~qW}QTO zF60KeXQJLDHdD6+B#|-;jV{vfz!B3FeqP17He?M}KCntbHnB}>wdutf4CM^gjOAHQ?8gY#Y$CkGD;GnY%Uz$6 zPr?Qx=ra9g8P2(Cf>tghaMT(jHk27Sv~t)GmMeUjz2n=-FG8OQUecYI0Hd9orbPEj zlE$=0NP_)h0&~<^C&FPIrL!|!YW)!t62C!3a&kTPf-wMA0?}aUg_+`-ny@RuBQ)tj z=`7CEF1osM9eT8m4rmMC2Nr&`OZ(LMLhN&?w;v?l$aoc*PfIw@3mr@AQhpx2FwFs) z4dT*2sa{)Zu;@Jiwl;QseQW)Y+1jVSsKykH=f4U zGJYDRhnD?~Jwr5I%q|V;wwDzUT*d3BEssA7StqFj3vcxzHEHv`8Nre z#8u#1v$61X?33!ybP=*Zqg=CF3o-MBTJcjJfNwLM%nWNDUmSEM3*k18a z?7S~-tNKZFnY6or8%G$FAlh^&2EwS$>AX`Fa6EPvr-kUp+1%avguwM(9Z7noT6rmf z&%@m>$m>qvPSESY7TyQDP`gHJ0`9(R+N-bmL|?1B9j zC=NY-lwLQYNQkr?S|8!NT?|I`Bc3DZ>-3b>u}nhf)aW$uBB`lg&kTfG-+jy?U9j)m za{p5^gZL4K^*pGg!Y!+NY36_Oiu_W+#T4T&NE?!xeBoyEV_#Hq3+yyA05&xi*3c?^E?Aq7(XKt>+ zMn^vQasb4ocn)BJRzS<3Az%&^49G6V0RRcvcJo)$1BSSjczMLKzR^|JfdQf*&JL{~ MetwyX^uGu6FKEGTvH$=8 literal 0 HcmV?d00001 diff --git a/libs/ssl-config/src/test/resources/certs/cert2/cert2.crt b/libs/ssl-config/src/test/resources/certs/cert2/cert2.crt new file mode 100644 index 0000000000000..3b7ca01e48bae --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/cert2/cert2.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDGzCCAgOgAwIBAgIULGiQ5jnAntO91sS7Al5aUv8/jg8wDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJVGVzdCBDQSAxMB4XDTE5MDEwMzA3NDE1NVoXDTQ2MDUy +MDA3NDE1NVowEDEOMAwGA1UEAxMFY2VydDIwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDQbV6x3P9sstd5zKkjOylk+/X1j0vI6C93HwkF3d9NwhMoV1zq +aSj2SmAQCz4mIjMlAFR9mm6F+3sb8xkMFJD2Mypc5dW6TS5krhbhJdMpoVbceZtS +yuIsvQi1GT2Uwyu89doDiUNBIANqaexrK5x2S/Fy4L8dNl1x2k6PJi6zVpvbnNLV +TSbuSMp3oY23PpX/m6wzJlCYicO8ucMhPwmC0OL9WJNKny4vuEPdiV6/LwCVS4Vr +UpfNqgXLzRMJEbx7C2QEG7T6o2g2101oANBuPaDZcwIQ//EI3IkT10JcABIbwsdj +/Oqj0cf7iEW1IfJWx+kRVT8NfEA5QjL1KQ4HAgMBAAGjaTBnMB0GA1UdDgQWBBS+ +/gUxdwfGB0XcPHsbM6Qw50S2OTAfBgNVHSMEGDAWgBSHd+NjwqkE6hVMEnltx6cT ++D11lzAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwCQYDVR0TBAIwADANBgkq +hkiG9w0BAQsFAAOCAQEAiztFGa3uZVb6Fs8evN4CU+hPFYdhF57lEfT6Xa1OUD1B +5e5rDOZfVloy4gzLdtNCS9lieTgB7Yc3wDUCm0cS48JCMxykSRTI6M0Fmofsgd5d +OKR7CB+jR1Egj6nZren62XCgqjuJ+dbP4DinY6TifFzFX1vOD4RTb0mEn2WHL/JB +DnDxOETmBtKFyueprMtXkTO23dXsYXQeo2Gyih+t5ksqMnxCW2GFkkOqrOUQY8CF +6CVmmb9UCYk3f3Av9TedqJ8Cmoe+HSP0R2oxpnc7cd1v37QPxWgHETro9zS4FBrt +6KgNTP99b+aLxeeuMKJuRVR+TCZPuyYbBzUfp2ZZOg== +-----END CERTIFICATE----- diff --git a/libs/ssl-config/src/test/resources/certs/cert2/cert2.key b/libs/ssl-config/src/test/resources/certs/cert2/cert2.key new file mode 100644 index 0000000000000..1384b2daf309a --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/cert2/cert2.key @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,68F4EFD94D4D9BDF + +TL01d1JqaN0P1sb8284jOGpLn42cubkLY7JPj+bmpL2PEH9cT2xo7MM5cwvNSbPX +nuZ1CMFSFqAyxulh/rfZwU1BumKLiwM+ep0A/lWwKJEor+ancCBdkIHWfSg3Jc0i ++nHhL3e7+W+XRfSlafQQkhFkeOXs0hSa4WYX6tymvMAf8OLAenKB/0MOvKjd6EOu +ZIvnBxAjAaDoRr4X4izIVlNmsIbvYARW9WjjcK2FZhNn+WLLTkfwEkl0glRl440L +ET9qAjoH7j5KL5yKw5h2HhALSLaXdiAfCGvhpU4K0Afpb225mvR/uL3HLpJEGKKb +DuoK99zvjHqReq1YndIR688ioc0O4dUvujZKgn8OR2JvGJVSc+mgaIWadfs2aADz +CJIlqnSJa1EW6qm6knLJwieEBoNHbeFszrCKrYdy7uicys9PR1XsoMrOly+HhVnR +PChA3gV6AVIjyMAUkFLg4NAHjgDbb81lu8ENFmlJcjgVeXDMykrpBmhzmhSPtOEb +6bdQCKuA7zXIpJCmP66ZSuNHxikrfqLJjXW3PojLuCx5nfO0akpxjSeyLHzv/YXV +YxnpLJxMybG1KUHyDHRmDrd+UPzLnh52O/g9NoiAlluUcblH+BKer18dJdGSl95G +P+Ted08S0yP2niNz6XHv5KbztzsP73n0w82akCQB8ZAsGJ0CNw7S7N6tWam/UkMN +tvM9nFCjvwah1funu8nj9QyWrzac6ngPP0s8tcKG0ahLEJYn7Hx2Oqn7K39fbMkX +UOJVNEBQP2Anf5dJMfYPEI0xihv3ec1RxpipOm9DKQ878jxnqxgZxa+Pab9j/JxQ +j+BGaoOnYj2jHBnt4nCP75F0BEZaGxsZX2MjJySK+5jy2WW3JRC/E0qPkL6oBvT2 +3e37fep4XKSjqR9lSYjW+AlAVw2uPkwxDp5sD7XFGsH3SM1qj54NWwljpKXnOTbQ +Xws18VEiWsQ3kD7ft11w8/67Bb27TsWEJRo1vCC4KsYBCyjEOrp13aJxpSiNI24W +oSmrQTsCco1Yrxfs0noNu0FzfJHV6qmHR7ps0fj+AWJyquYbIEK1762+r2uutgSg +ZVaPWLkm9uq5K5rNXsj3w1L1CK4YcDre0yt+Kg4Pt3OQR2lF8CpABguA3gR9kO2g +9N8hAfiOq5MDliU+9r6Cr/dPkdzV0Eo971HdfaLD7S/pjSP37fcTcOpDhwNt3UcK +amhR/Zm8Ll414zc/iNiVTcu6+chzSY9Yhwfa8A/XuIfoqMrTiaBMPlxe0tNKaKVs +09d6U5JoTQJcnei/4ODkIIYOzsmMtHgKtmeg86AB8yeLNgqWCrJi+Fxnha+cJ9No ++STMQP4vS8qgRe5XkRGaAZBHyPAwxOou1Iu167LjlFFl0YSYUZTChha5XBG2Uhm8 +FeIH1Ip+83fxMoyiYROOdeMuLXtQIndA3fmjduBEO0kPtAwQ2xfH4g59XnnSL97S +9AslnPnUWzDR0zBr4GQBNAKLaMIFGzhDZEzaooYetoeDYSczil/Rf1D6wyM6Cgjq +BK7c0kNum9uXaDbYCh6spzYua0j1noqsBTm9V25178lNbkQ6yAPdeYCxRmUXHtXk +-----END RSA PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/cert2/cert2.p12 b/libs/ssl-config/src/test/resources/certs/cert2/cert2.p12 new file mode 100644 index 0000000000000000000000000000000000000000..269e855f7709843933975c58237541d8cec052b3 GIT binary patch literal 2456 zcmY+Ec{CJ^8pelN80%OX+eA#Zu?^Wve8^7L>^o&F8A)XuW(pPAVvLeRSz_!lmI>J= zjj}|xK1+k_TOmH&zH{!q-@Sjl=RN27o%8(nd(Z@E7BdqNO@O*Upr}NX#63B8vl+B&;;Q0KL}Dl01o_)=*&!j->>^0!h}XZ*#6zX!305bfmk<1=CtE^n1Yy@ zSpo3`AW83s$S_;38S{pdZ6Ev{f}1ZZ&~Mf=5*TKCVa|X2%+h^5`e_;K8Vkg39;Tvo zF>KV8k4*K+4-P?Ks8lgC?aP=w9{@s?AI`LqT`$%LmeT7@vCWy)sqUmpv|f5|#uw9f z_RUuXm!o4x>qUhKnO`HB=Ply3a4+PhoD*;_ed036(E{tW!PD?|AcNU(eP3 z{kB2xxcfS!im;N{nC2aMH>;&@a*mZL{E1hW1+a=;g6YIyZrAw_UIrKnPM_iJvfd)g zH({P3Ge=)&h2z{$vn9&5*c=csQp3p+{W;(W5q9YciO(wO{JFO$hEG=2P3Vpm-|S6Q zJb(qU7(*rCk;JJWxuS{FcB{JYC7Oho@z*>rhl6QT4^uR4XlH8lm zCB|PzlQbTujqCb&LJFd!t34`31sPr~0k&&7@Z(s+>&r%wcwHYzPA@xJUdp|O?c>AO zXSR%ye-3Qf>G=RAMWE~sr2Phm^|D>d@oZ?9n|f`S_k{eAjPL+n8P@1<^m+YQKh)8I zSpLaY+__T!k0_&N!2nGV<(^(kLL*mP{6NIENurz`DtFKe*BMpzG1_`>(zhGfJ4#5` zlXf!E$V9&B24?Oj+mUrH*5693%XKLa)8~y?iZZh; z)>SApy!I$2WD!3=lJ2>Y+AB^5&w3>|?5NG80qlwsSvkXH5GL=&=*{(0L~d=XG22$5 zbNd0;Ha-rPkI^q`aKE_Q^*AFf?k2!P;ymXlmFO7zSr+E-_H6SGxQ>OPLoowot&_fk z1@&68QFMQN!vgsYehOv}dC=1=f!ClMVlAA&f=lWFqZ@$Dp66?A1D>-+>|;31)v5;f z?shii{t7p28Z)$OJ@!_F>B+-0rx-6+Dw(EoX$*^YT4LYzEobY^hZVHI-W|7@Qn0+8 z^suXaKLim~;K+O0bEc9X@*uyRv#He7{!X4l&f?px%qhndP*FJjR5iQ7E~4I(Zw`Tr%sC3nOR(*zJErE+Bv{K?Jbr z@A%U1`vb!MAFbJ#m1{yUiTp>C&G#n-zV37xz9em#n`$auM#5F?|$}e8L~zB2rdba zcx!ll^0j)dnh8sf4Vk9*S3--c=8}4&jYFSg6FuLr1eyA)=+YpG72!Hp2Y7(;?4<)<8v<`7aSDyUepg5Uj1Eb_L@ ztC&P`K$p!e;g6PTaO^#AaPdHNQAM5LklcjYwb?7wXQS*xkPO!oHvf6P$ezv^m=(0o zQ@54Y5j(k&E>RJb%6XEc-GQR;5a}|KlTtj_+B752OcUEioqrw~E;ln_8Dr7H{txb_ z!K8|x8{c;9eKln+zoMj?J~_|4M9jdaUws{yYIp;ynbgfl0loimcbUU$jANP4M}re~ zg`x0N$S`o*i_o;p61^V^OAn3|bx&&}Dd}&nYm9L~A+p?LRf}+NtLIR8#=9V1|I zfpndN^ydzk%uEyO;Yxbws5HZ;G~Y$_3th67o>8L~o+0<`Q_6+VhGhc5b!N=IPi1=8 z?V9v}8Fz#i zi@7r5;NGQg&uWMGvb8|rBd~MHw{=gN2X=H#7gw6e(|)?ZGDL*jwoS?gt|vdP^ZK;y zSBjz+_DTnpM92uEoGH)wjj1j8J)m2boQWruZ(MXZ-1?-o8ha z4aQdbL}ZbW`tD@hESJFU)9Z~W%)*IZo9b0;$zSqZ8B@w%z?ur29F~*DcauPfcL}ar z_x#YvaSQpenhu?jbEfO1@dNfAT3b?(O#Q_tpGGo@mZ~;%#CIVP)_x|jWn9)xO<_Zz z$RD#%dt5yqb^IasJc^={i6oSjzx4hE#_55E)>gRgD_REZhOrAvginLQdz5UHfK_h~ zBFbPcOsb5!AmGL4hfX-S{!h(WD}tXvoySA=tSTMRn~+}7CPM?)c|T31!xG1KxWIaQ z(BQPx%8`c_k2K=^u1sBsvC?9C4YG4u3}s03FK=Igb;dJb&q3afDmz4rfyyGyvo1Bo zT!7k6!zotNtb1R97ekSQf|dslIFiN`4O&q1^47Nk{g<3leLktjJuc*pg!lL2@bf18 zqdpELx@;TrqH6kJ!O#diwxMm+UrYR4rQ8toE?1^`ShGmk5)?cqmSg+9`+)kzJzlq> zhDVA9KhAkv#y-3)m#|_F4#6EHqi`(MtO1e;^(yZxPq3mHzM*k<6}GUi1$Hi<_EuCk zC2U2f#9IX{)EyTxwU)N`7(r+)u=7bn{5oG+I=pLDRCkLf`r}{WWK*_`emb9jzY5Ps zb;ug<{#af;-~i*@N>kIq?LMy<*CXeL*)C7xVWg7c0=xXwK1s>!UiA+zXsi3kZ9+G} zD*~nJVsUY7GQ(9_4=wcHb%gRObBMA5d;$J|8-SYt6*Tf6bV?Zx;ums@I}D!mOI99P z6(T0`&T^bOxrkOqi=&|supAeVSr`le@h^r~f%Vd8(uH}--#=7cD5XGjk3g(b)tykr Kqh$NP2lQWnTyQ1; literal 0 HcmV?d00001 diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/README.asciidoc b/libs/ssl-config/src/test/resources/certs/pem-utils/README.asciidoc new file mode 100644 index 0000000000000..0136e967106e1 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/README.asciidoc @@ -0,0 +1,149 @@ += Keystore Details +This document details the steps used to create the certificate and keystore files in this directory. + +== Instructions on generating self-signed certificates +The certificates in this directory have been generated using the following openssl configuration and commands. + +OpenSSL Configuration File is located in this directory as `openssl_config.cnf`. + +NOTE: The `alt_names` section provides the Subject Alternative Names for each certificate. This is necessary for testing +with hostname verification enabled. + +[source,shell] +----------------------------------------------------------------------------------------------------------- +openssl req -new -x509 -extensions v3_req -out .cert -keyout .pem -days 1460 -config config.cnf +----------------------------------------------------------------------------------------------------------- + +When prompted the password is always set to the value of . + +Because we intend to import these certificates into a Java Keystore file, they certificate and private key must be combined +in a PKCS12 certificate. + +[source,shell] +----------------------------------------------------------------------------------------------------------- +openssl pkcs12 -export -name -in .cert -inkey .pem -out .p12 +----------------------------------------------------------------------------------------------------------- + +== Creating the Keystore +We need to create a keystore from the created PKCS12 certificate. + +[source,shell] +----------------------------------------------------------------------------------------------------------- +keytool -importkeystore -destkeystore .jks -srckeystore .p12 -srcstoretype pkcs12 -alias +----------------------------------------------------------------------------------------------------------- + +The keystore is now created and has the private/public key pair. You can import additional trusted certificates using +`keytool -importcert`. When doing so make sure to specify an alias so that others can recreate the keystore if necessary. + +=== Changes and additions for removing Bouncy Castle Dependency + +`testnode-unprotected.pem` is simply the decrypted `testnode.pem` +------ +openssl rsa -in testnode.pem -out testnode-unprotected.pem +------ + +`rsa_key_pkcs8_plain.pem` is the same plaintext key encoded in `PKCS#8` +------ +openssl pkcs8 -topk8 -inform PEM -outform PEM -in testnode-unprotected.pem -out rsa_key_pkcs8_plain.pem -nocrypt +------ + +`testnode-aes{128,192,256}.pem` is the testnode.pem private key, encrypted with `AES-128`, `AES-192` and `AES-256` +respectively, encoded in `PKCS#1` +[source,shell] +------ +openssl rsa -aes128 -in testnode-unprotected.pem -out testnode-aes128.pem +------ +[source,shell] +------ +openssl rsa -aes192 -in testnode-unprotected.pem -out testnode-aes192.pem +------ +[source,shell] +------ +openssl rsa -aes256 -in testnode-unprotected.pem -out testnode-aes256.pem +------ + +Adding `DSA` and `EC` Keys to the Keystore + +[source,shell] +------ +keytool -genkeypair -keyalg DSA -alias testnode_dsa -keystore testnode.jks -storepass testnode \ + -keypass testnode -validity 10000 -keysize 1024 -dname "CN=Elasticsearch Test Node" \ + -ext SAN=dns:localhost,dns:localhost.localdomain,dns:localhost4,dns:localhost4.localdomain4,dns:localhost6,dns:localhost6.localdomain6,ip:127.0.0.1,ip:0:0:0:0:0:0:0:1 +------ +[source,shell] +------ +keytool -genkeypair -keyalg EC -alias testnode_ec -keystore testnode.jks -storepass testnode \ + -keypass testnode -validity 10000 -keysize 256 -dname "CN=Elasticsearch Test Node" \ + -ext SAN=dns:localhost,dns:localhost.localdomain,dns:localhost4,dns:localhost4.localdomain4,dns:localhost6,dns:localhost6.localdomain6,ip:127.0.0.1,ip:0:0:0:0:0:0:0:1 +------ + +Exporting the `DSA` and `EC` private keys from the keystore + +[source,shell] +---- +keytool -importkeystore -srckeystore testnode.jks -destkeystore dsa.p12 -deststoretype PKCS12 \ + -srcalias testnode_dsa -deststorepass testnode -destkeypass testnode +---- +[source,shell] +---- +openssl pkcs12 -in dsa.p12 -nodes -nocerts | openssl pkcs8 -topk8 -nocrypt -outform pem \ + -out dsa_key_pkcs8_plain.pem +---- +[source,shell] +---- +keytool -importkeystore -srckeystore testnode.jks -destkeystore ec.p12 -deststoretype PKCS12 \ + -srcalias testnode_ec -deststorepass testnode -destkeypass testnode +---- +[source,shell] +---- +openssl pkcs12 -in ec.p12 -nodes -nocerts | openssl pkcs8 -topk8 -nocrypt -outform pem \ + -out ec_key_pkcs8_plain.pem +---- + + + +Create `PKCS#8` encrypted key from the encrypted `PKCS#1` encoded `testnode.pem` +[source,shell] +----- +openssl pkcs8 -topk8 -inform PEM -outform PEM -in testnode.pem -out key_pkcs8_encrypted.pem +----- +[source,shell] +----- +ssh-keygen -t ed25519 -f key_unsupported.pem +----- + + +Convert `prime256v1-key-noparam.pem` to `PKCS#8` format +----- +openssl pkcs8 -topk8 -in prime256v1-key-noparam.pem -nocrypt -out prime256v1-key-noparam-pkcs8.pem +----- + +Generate the keys and self-signed certificates in `nodes/self/` : + +------ +openssl req -newkey rsa:2048 -keyout n1.c1.key -x509 -days 3650 -subj "/CN=n1.c1" -reqexts SAN \ + -extensions SAN -config <(cat /etc/ssl/openssl.cnf \ + <(printf "[SAN]\nsubjectAltName=otherName.1:2.5.4.3;UTF8:node1.cluster1")) -out n1.c1.crt +------ + + +Create a `CA` keypair for testing +[source,shell] +----- +openssl req -newkey rsa:2048 -nodes -keyout ca.key -x509 -subj "/CN=certAuth" -days 10000 -out ca.crt +----- + +Generate Certificates signed with our CA for testing +[source,shell] +------ + openssl req -new -newkey rsa:2048 -keyout n2.c2.key -reqexts SAN -extensions SAN \ + -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=otherName.1:2.5.4.3;UTF8:node2.cluster2"))\ + -out n2.c2.csr +------ + +[source,shell] +------ +openssl x509 -req -in n2.c2.csr -extensions SAN -CA ca.crt -CAkey ca.key -CAcreateserial \ + -extfile <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=otherName.1:2.5.4.3;UTF8:node2.cluster2"))\ + -out n2.c2.crt -days 10000 +------ diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/corrupted_key_pkcs8_plain.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/corrupted_key_pkcs8_plain.pem new file mode 100644 index 0000000000000..4b2271a6f3971 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/corrupted_key_pkcs8_plain.pem @@ -0,0 +1,24 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDesZnVBuxbT4y7 +KtIuYx8MUq0sGQgVbxXSBG66sWDU9Qoo1HUyra0xXCONgRMBT9RjSIpk7OOC9g8q +ENNgFO179YdHVkrgJhW/tNBf+C0VAb+B79zu7SwtyH2nt9t378dmItL+sERkMiiG ++BS/O+cDz44hifDiS7Eqj/mJugAhLjWSUyD+UBObxXvUsxjryKeG3vX9mRCgAcqB +xH3PjI1i9DVaoobwMbwpE5eW2WXexOspuXnMmGfrrR6z/VmdHqe/C3rGdJOX+Y0c +yOR+/Vuzisn+nLeo/GJx2hIif8rKiNRyAdUXfx+4DLYJBN2NUbl9aP2LP6ZC8ubf +6qwhhB0XAgMBAAECggEBAKuzP6qSNfaJNTayY2/EmRHFRSP1ANiV17sgE8f6L3DC +pdypQtuaMSkXo4nc9SxTwqvyKFJ8m0ZENZj3dCJmwFyNCIqmLAD7HFW9MdRs40WJ +HYEv0aaeUyvRo6CHD74/r/w96XTZr0GZssmtyUFRDGNRyoJter7gIW9xprLcKHFr +YTmdaAXbOm5W/K3844EBouTYzYnZYWQjB3jT/g5dIic3AtLb5YfGlpaXXb74xTOU +BqY1uKonGiDCh0aXXRl2Ucyre6FWslNNy4cAAXm6/5GT6iMo7wDXQftvtyK2IszP +IFcOG6xcAaJjgZ5wvM3ch0qNhQi4vL7c4Bm5JS9meoECgYEA88ItaVrfm2osX/6/ +fA8wYxxYU5RQRyOgLuzBXoRkISynLJaLVj2gFOQxVQeUK++xK6R182RQatOJcWFT +WwmIL3CchCwnnXgPvMc51iFKY94DbdvrRatP8c5sSk7IQlpS3aVa7f7DCqexggr5 +3PYysuiLirL+n9I1oZiUxpsS6/cCgYEA6eCcDshQzb7UQfWy//BRMp7u6DDuq+54 +38kJIFsPX0/CGyWsiFYEac8VH7jaGof99j7Zuebeb50TX57ZCBEK2LaHe474ggkY +GGSoo3VWBn44A1P5ADaRGRwJ4/u79qAg0ldnyxFHWtW+Wbn11DoOg40rl+DOnFBJ +W+bWJn4az+ECgYEAzWduDt5lmLfiRs4LG4ZNFudWwq8y6o9ptsEIvRXArnfLM3Z0 +Waq6T4Bu1aD6Sf/EAuul/QAmB67TnbgOnqMsoBU7vuDaTQZT9JbI9Ni+r+Lwbs2n +tuCCEFgKxp8Wf1tPgriJJA3O2xauLNAE9x57YGk21Ry6FYD0coR5sdYRHscCgYEA +lGQM4Fw82K5RoqAwOK/T9RheYTha1v/x9ZtqjPr53/GNKQhYVhCtsCzSLFRvHhJX +EpyCLK/NRmgVWMBC2BloFmSJxd3K00bN4PxM+5mBQZFoHMR04qu8mH/vzpV0h2DG +Mm9+zZti+MFRi0CwNz2248T4ed8LeKaARS1LhxTQEkECgYBFsPNkfGWyP4zsgzFs diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_openssl_encrypted.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_openssl_encrypted.pem new file mode 100644 index 0000000000000..a251de23f4879 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_openssl_encrypted.pem @@ -0,0 +1,15 @@ +-----BEGIN DSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,BE9A0B63873F6B7A + +lGSpJkwN0J9p+2Wm58706EYz6mmjgz7okjMtsR87GMIiK/wVwjKmyUa73QTVVs15 +N/EOySftBk3VUSPx9G1ZMxKpp3l/hvkIcsDDfCPAZFqwdQQJ8BEeF9jDd5ZoI6Yz +Yus1+X8A1OpX1O7PCZ08e2fLeVuEWg62/JQcNukuvL7AKm+qa1sda5/ktquv2eMZ +nbTiOE3Xe+uDsgABQdy1h4EsMEaMdE6QrWdxLGWDGcdzSzfltvnhmmsK2CQsV4e1 +huQeb8ylShJuIr+mgtKgUlIlJwSd7ka8hIdmGt1LO9+NZOPUGN04daQkETtfwsmu +YIYkh66CuLbT4nZny64Spa7AeINSmf9GA72/QtRSo3M7Khlw/95Lz24iKAy7/Lbt +AKYenSQeJtlNgWzPcDIeUrIzXXmAXHN5YGMg/7X0h7EGu5BxYbLydkBRvSkV9gzU +Ms6JD5aON10DQhjIUwUcBnhSnwPPpIVa2xf9mqytkcg+zDgr57ygZ9n4D+iv4jiC +ZJuFCFrgeqHrCEKRphWRckyhPo25ix9XXv7FmUw8jxb/3uTk93CS4Wv5LK4JkK6Z +AyF99S2kDqsE1u71qHJU2w== +-----END DSA PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_openssl_plain.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_openssl_plain.pem new file mode 100644 index 0000000000000..a64642fc9ab0c --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_openssl_plain.pem @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR ++1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb ++DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdg +UI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlX +TAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCj +rh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQB +TDv+z0kqAoGAd0xuuUUSAXsXaQ/dp9ThBTVzdVhGk6VAcWb403uMXUyXKsnCIAST +m6bVWKjNxO1EsP3Slyd5CwbqIRUBK5NjzdQP/hHGtEIbqtYKY1VZI7T91Lk8/Dc/ +p9Vgh27bPR8Yq8wPKU3EIJzYi0Nw8AxZf10yK+5tQ6pPUa3dH6lXt5oCFF1LyfuB +qBYh7hyIsfkb+cZoQ57t +-----END DSA PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_openssl_plain_with_params.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_openssl_plain_with_params.pem new file mode 100644 index 0000000000000..0a2ea861b9b66 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_openssl_plain_with_params.pem @@ -0,0 +1,18 @@ +-----BEGIN DSA PARAMETERS----- +ThisisnotvalidabutwedontparseiteitherwaykFJyVA+0q1vAej5iQVmUvu1y +fuA5axTA5IT86U7acP0KV8eawbDXVhqiP0zcSeP731coxJaUHC6XB0FVMhYi4fZn +fexykg9Kxe/QBfDtcj3CEJNH/xoptJQVx3hi+0BPPK8+eUXTjwkQerGMwUD7UQak +xuUS/22GakHZV5G/kCc= +-----END DSA PARAMETERS----- +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR ++1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb ++DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdg +UI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlX +TAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCj +rh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQB +TDv+z0kqAoGAd0xuuUUSAXsXaQ/dp9ThBTVzdVhGk6VAcWb403uMXUyXKsnCIAST +m6bVWKjNxO1EsP3Slyd5CwbqIRUBK5NjzdQP/hHGtEIbqtYKY1VZI7T91Lk8/Dc/ +p9Vgh27bPR8Yq8wPKU3EIJzYi0Nw8AxZf10yK+5tQ6pPUa3dH6lXt5oCFF1LyfuB +qBYh7hyIsfkb+cZoQ57t +-----END DSA PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_pkcs8_plain.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_pkcs8_plain.pem new file mode 100644 index 0000000000000..fc5f17ce89897 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/dsa_key_pkcs8_plain.pem @@ -0,0 +1,9 @@ +-----BEGIN PRIVATE KEY----- +MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdS +PO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVCl +pJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith +1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7L +vKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3 +zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImo +g9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFgIUXUvJ+4GoFiHuHIix+Rv5xmhDnu0= +-----END PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_openssl_encrypted.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_openssl_encrypted.pem new file mode 100644 index 0000000000000..69dfde4b3c502 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_openssl_encrypted.pem @@ -0,0 +1,7 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,692E4272CB077E56A0D4772B323EFB14 + +BXvDiK0ulUFKw1fDq5TMVb9gAXCeWCGUGOg/+A65aaxd1zU+aR2dxhCGXjsiLzRn +YFSZR2J/L7YP1qvWC7f0NQ== +-----END EC PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_openssl_plain.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_openssl_plain.pem new file mode 100644 index 0000000000000..e1d0a6a8319c0 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_openssl_plain.pem @@ -0,0 +1,4 @@ +-----BEGIN EC PRIVATE KEY----- +MDECAQEEILEXCgqp9wZqKVmG6HTESPeCyx2O4TDoFqyILz7OGocEoAoGCCqGSM49 +AwEH +-----END EC PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_openssl_plain_with_params.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_openssl_plain_with_params.pem new file mode 100644 index 0000000000000..2ad57473236b3 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_openssl_plain_with_params.pem @@ -0,0 +1,7 @@ +-----BEGIN EC PARAMETERS----- +Notvalidbutnotparsed +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MDECAQEEILEXCgqp9wZqKVmG6HTESPeCyx2O4TDoFqyILz7OGocEoAoGCCqGSM49 +AwEH +-----END EC PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_pkcs8_plain.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_pkcs8_plain.pem new file mode 100644 index 0000000000000..7e6de54424702 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/ec_key_pkcs8_plain.pem @@ -0,0 +1,4 @@ +-----BEGIN PRIVATE KEY----- +MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCxFwoKqfcGailZhuh0 +xEj3gssdjuEw6BasiC8+zhqHBA== +-----END PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/empty.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/empty.pem new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/key_pkcs8_encrypted.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/key_pkcs8_encrypted.pem new file mode 100644 index 0000000000000..28059d5a2266d --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/key_pkcs8_encrypted.pem @@ -0,0 +1,29 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIE6TAbBgkqhkiG9w0BBQMwDgQI2jwlFL0XId0CAggABIIEyMujZbpG6zKb2pVu +soamTaoLcZwNofS9ncGIEH1nbI8UpPY81VeOIBm4mneDt8RU5bIOXP4IZEZY9uU+ +pugKQ3hT8vBQjJujjuctUPaFxB0kGEeITOInY2jn2BFDbUgy5Z7EVD4G2K06SDDK +oD+twbzZo9x34VizwpHHb8wE+DFyYc+sp+Re2Qk3FReKgjdJezfcRHbKrrlx2rJ+ +k/YAPmzcFYVbuUiB6HY6BGzSJO1JxT8iNJE+Hmk3ZLXG590hp0vuGSkY/ihbeix4 +1rQs7u4riqXJ+DJBmXt/wXUij0/k6s4igACNsT2MkZkGEDkzqzE+kj2VYOHSX+Wd +5W0WCfftcsIQ8eow4ACec/Ns9ionLjx1xnbTjRMkpGgbVsreupU9AQ4MhLNNgwyl +six/cxUxTvH8Modd0/4KQFkeo352A6+DKCaPZ87SoF2Rge1otcJaZVcX1gBvIztB +/xzYwyUydQEwblU0kCYWRgxlKP9jxFoke2RX1BodRfAMNDxS0XyYrA/JzB7ZRsS7 +QGYPy/PPb014U3KhpJdjwbNu2VaCVdGryYA9+BTP+Vzwcp8MZoMPnnjnBh1YyVAj +c7oyzKU5e5SVsYni1Kt/536YxQgFCAUHv/g+zQqqGEvyiMXhsCwVpoy7UcFYgmlw +40g3+ejwvlO3YA67gQQKebEv6/Laz1hVNiXT0m3okAXWxXgF/g2eBO5NTRdtaWn3 +VNH5ub+LOr6cMhk9BAtKgRG+xeh8/2SqH12UbwtlmxqnBAfHtqlE6yJ1ViMDHxF9 +101xJlEONmC3fcEAjShK6LEbFwPJns3WbGc0ds36CzXWtO29XGssr+YoiF9e3Eus +/XQjmjOJxRoWkNEYsxlJ3IRH2vUcdCoAp8IlD7JYxx8UBCSJDBo7/0QKU6INeWjo +5+aNbaLAJULSKo1LTZjjANm+G+KcSnbn5Ed8fmY+D61A5/7WMIVxq/uDLFvxCnRG +QcLbtqbPztiWwWZOuTwNTA3bfAhEG0ZzNr+0z33jW5T9ChvdutgxJMf3Khazx9cx +mWyCpJwtSv7hSbp4nCS2fmHCum2yIrOnou8TSOlQFERZ3UEZMgLpWeupH/W5C3Ad +rOspFrK6K8a/iNSs5OdYUIK2iHddTs5u7AEZ9I5MTuYnccuGuXfQTTA06TJvJTax +c2oDbXMnXs4pHLiiSRp34IHIYubdrj8X5vTODC5djl8h1167ToXo5zGdXqT1om+u +4ndNLbbI1vld5G7KAL6TlTETg+N7S8v3KYoBEWzykwgqqppWnWTqPWQxM8Iph5ly +AQlzz7feERi/h/s57RZ5ksoVAdbtk2U6wgHnLrWhKZ7+ZOAfpNAjGHwWyXTzylXo +zQ9A8Kmd0jBMsru4fsGpldf4lTsqO/abUSWrAAREGnlz/ZjEb944Yox7JUhWC15C +WxXK2rFbiF3S0HtEvU17rdn4HCsZBilnY+hTpHj1MA6O451/A3ghxGXFKz/9LUcS +YBRQJaSM3hTqC3WoTVBeVc5nCFOpu4F89JqhEgXOLKweueMbTMRSNm93tXWT13s3 +Q/o0pNJv/K6+bIQwsX/oDafMXcW7STxQJObbAleRbcn8/rGS2eEnVZ6907faUR/L +7eu9vgAa/jh9FHpZ0Q== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/key_unsupported.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/key_unsupported.pem new file mode 100644 index 0000000000000..96f95848d099f --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/key_unsupported.pem @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACBqIPMG94HL7zedFzsvi45mHS8ZuyLQXqvHpHobcdNCJAAAAJimRM7VpkTO +1QAAAAtzc2gtZWQyNTUxOQAAACBqIPMG94HL7zedFzsvi45mHS8ZuyLQXqvHpHobcdNCJA +AAAEBvVc8FVPGUs3LZ1o+LnjW4uUlEnk/5LQQ9yO2eiI3SFGog8wb3gcvvN50XOy+LjmYd +Lxm7ItBeq8ekehtx00IkAAAAEWlvYW5uaXNAc2VjdXJlYm94AQIDBA== +-----END OPENSSH PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/rsa_key_pkcs8_plain.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/rsa_key_pkcs8_plain.pem new file mode 100644 index 0000000000000..dd1675957f69f --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/rsa_key_pkcs8_plain.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDesZnVBuxbT4y7 +KtIuYx8MUq0sGQgVbxXSBG66sWDU9Qoo1HUyra0xXCONgRMBT9RjSIpk7OOC9g8q +ENNgFO179YdHVkrgJhW/tNBf+C0VAb+B79zu7SwtyH2nt9t378dmItL+sERkMiiG ++BS/O+cDz44hifDiS7Eqj/mJugAhLjWSUyD+UBObxXvUsxjryKeG3vX9mRCgAcqB +xH3PjI1i9DVaoobwMbwpE5eW2WXexOspuXnMmGfrrR6z/VmdHqe/C3rGdJOX+Y0c +yOR+/Vuzisn+nLeo/GJx2hIif8rKiNRyAdUXfx+4DLYJBN2NUbl9aP2LP6ZC8ubf +6qwhhB0XAgMBAAECggEBAKuzP6qSNfaJNTayY2/EmRHFRSP1ANiV17sgE8f6L3DC +pdypQtuaMSkXo4nc9SxTwqvyKFJ8m0ZENZj3dCJmwFyNCIqmLAD7HFW9MdRs40WJ +HYEv0aaeUyvRo6CHD74/r/w96XTZr0GZssmtyUFRDGNRyoJter7gIW9xprLcKHFr +YTmdaAXbOm5W/K3844EBouTYzYnZYWQjB3jT/g5dIic3AtLb5YfGlpaXXb74xTOU +BqY1uKonGiDCh0aXXRl2Ucyre6FWslNNy4cAAXm6/5GT6iMo7wDXQftvtyK2IszP +IFcOG6xcAaJjgZ5wvM3ch0qNhQi4vL7c4Bm5JS9meoECgYEA88ItaVrfm2osX/6/ +fA8wYxxYU5RQRyOgLuzBXoRkISynLJaLVj2gFOQxVQeUK++xK6R182RQatOJcWFT +WwmIL3CchCwnnXgPvMc51iFKY94DbdvrRatP8c5sSk7IQlpS3aVa7f7DCqexggr5 +3PYysuiLirL+n9I1oZiUxpsS6/cCgYEA6eCcDshQzb7UQfWy//BRMp7u6DDuq+54 +38kJIFsPX0/CGyWsiFYEac8VH7jaGof99j7Zuebeb50TX57ZCBEK2LaHe474ggkY +GGSoo3VWBn44A1P5ADaRGRwJ4/u79qAg0ldnyxFHWtW+Wbn11DoOg40rl+DOnFBJ +W+bWJn4az+ECgYEAzWduDt5lmLfiRs4LG4ZNFudWwq8y6o9ptsEIvRXArnfLM3Z0 +Waq6T4Bu1aD6Sf/EAuul/QAmB67TnbgOnqMsoBU7vuDaTQZT9JbI9Ni+r+Lwbs2n +tuCCEFgKxp8Wf1tPgriJJA3O2xauLNAE9x57YGk21Ry6FYD0coR5sdYRHscCgYEA +lGQM4Fw82K5RoqAwOK/T9RheYTha1v/x9ZtqjPr53/GNKQhYVhCtsCzSLFRvHhJX +EpyCLK/NRmgVWMBC2BloFmSJxd3K00bN4PxM+5mBQZFoHMR04qu8mH/vzpV0h2DG +Mm9+zZti+MFRi0CwNz2248T4ed8LeKaARS1LhxTQEkECgYBFsPNkfGWyP4zsgzFs +3tMgXnIgl3Lh+vnEIzVakASf3RZrSucJhA713u5L9YB64wPdVJp4YZIoEmHebP9J +Jt1f9ghcWk6ffUVBQJPmWuRbB/BU8SI+kgtf50Jnizbfm5qoQEt2UdGUbwU3P1+t +z4SnBvIZ3b2inN+Hwdm5onOBlw== +-----END PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/testnode-aes128.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode-aes128.pem new file mode 100644 index 0000000000000..b4448ec8afaf3 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode-aes128.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,AD45A956510B909DCCACCE07DE3BA1C2 + +Vk+KErTbsSdjNO5vaCpik/OLkaOQ4Fm3rNIUrQPMEBiK/TXnHMvC/X1DZenSwA8W +yHuSpoAAg/HjQv5UskRtn6Rt74ALViM4hO6BleNxr/8lIBZAeLNjqoGwf62MyExV +rraRhXvYepiTnVSQDYuTafxdIXqzg7O5kYcR46gpphXTjMWDMLxsEiKQ1u51lPFU +SzxSMGMKiJL3PAXuWyoKgUihw6sv+mVPzq4MVcZKTrlcNRGRFQWUhVzqNd5Qdx/v +vBUFbWVcMXx4tSsx/WtIOiUwZTbmLk4dpXysb0+Tp6lb+7AQ2RR+9tkBWEdBPUx9 +qkBfFdAvfnA5vKR0SwAZU0dFaDWlQD2ktCJv4hwPN0XYMIv5WW9HoA+R88y+dhHT +sYgM3eEusQv9byC+XCzxPNg40yC8X9TG2z2deMUl6ippsrTULPx1WaoLf12x1Yl3 +vZ7MFB2hvJmWYofjTVz7Xa3FMH1dhJgBTwpUY//EgPhSaTrEMGwrXJQk40nam/LX +KjK/acvYmZHZZZJ+E0Pv481tFiiWVlXqfI9Tw1ffi4EzezhQTtzz2EBHaanHNEFa +C+7XQnxmBoNPpwOBh4Lh9oLcDN9uOGBLb+dIzn2cNQZXhBCKI8IV14YtZGZYhRHg +D+q7V6I/lEd1WNerHZRNI9o4ZBTJl+7GlJ1gveDTdcx28hCdC5oae6ZwIzSZPuDA +JPF3vr2yci7JsUpBqnaSnxpz5eKYbng3WjqweBXNgRWLhF8HT8fmWNJyvYjWpg+x +c8vh/FEM1HY3jsxE8NtIAlObJDMm/K/k8keVbbGm8c58oKdO4kdM+Z6aLe53nFo8 +ISwxsps//eak25Rx2H0bNvO4LVhqNHPXyYQ2nqtx7UpEgndrggHP7n3vcjtdE1f3 +N83gSm6SIVIeQJom16Z5Cjm4PRvJltIf2njpLTeP43eMoYNNVSCr2iZyrSNXnEes +TI47HidjCNkCp5ahPnuzzyeBCo9L9x2odTNOrga8sBii7VQBE3cGhAFkaUf0E6os +gpPqUWHkXE9Nb6H6EBR4gwbdpUqcgrm+kp6Ei5N/z7gSfV91WO45WmMLpCPmlPDQ +An+drt25y+AhaIEmoczUGAiz3jOdyd6Xqw+dVXGb9WPxXL4YnXgr4mSC2am9Vad6 +/MgIqYfqA/AOW1wY2dhoqfAGG2ITadFh82W6cqMhmeDQtDFb6/s96O4e46zev+fP +Nhro3k+JnL3InC9qAvkxEa/FpbL205X3X3FTXM6xK9ZDvq8+hbPxCjg73mXQfbbG +0/M8hE5hDgILTPiHhHFzGVNjYTAvjNnttg1n7+A52WGs+Hfwlf2x10p8Y2YwyOon +qfEMM3G1C3sDzEYmo+w0IZ+pesMWejMPOFiHYRCWVl8r5jx9lTSvbB3Xj+0Ygyo9 +15iLEGyr623I8LDBegqpNntlhX+AeHuJcthPRB6Jl2S0Q1xikD4fW1Ge29/l9Ndi +7TvZoSGh1jfA71pE1Ay2RyH5PMNj8KJvTGZPFEuIdzDUKlJkC3xUEvl6Q0prU171 +d/ka98AxLR9jUur0ARqxsckd5IXDTlZqsRs8W/gk5FP9RibiN7upiJcKgwYddiJx +-----END RSA PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/testnode-aes192.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode-aes192.pem new file mode 100644 index 0000000000000..4696e77bd3f64 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode-aes192.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-192-CBC,FACBF3734C8DD3C53F31E294D7E8DC16 + +9g2VpXQljNeeag2/jh0b1aKE+xcbkNKfIMeUljhiOxULegO53Apn/THshhJhtgPG +VYRlmk1ImCnwbWiy4C7WVXbOh1yGbYMPLipbtjEI7dr7OPbRX+GYn2Sln6iW9K61 +A019xPz1dLJ4bciNf5gcq5Wf/Qxj8R33ZPqANIHyMeZDSdGqFu+BQyQuQtJqFLkv +nokev80VIRuxinfmV3RSdUHo3g7iXRNq10bwxV+fns5fyzm5eq4q8Ac0M2NbhWds +wVl2gft73W41nXFqgS17Xo7cuAIdE07EGXVOq7UGKwLvAkgRWhZEt0BJZKB3XQAs +GfApMSOfIfTIS0YFjmkbGMKfprc8cgqPyDafKLDAGwViTWfM5oO2duium7OjV80g +eaL6iAImxFzfg3n8hsHg31iisM5p6d9VegXlY7YacdkFR11LN47nXoFU9l9vtKPG +TSouB4/0Dw4eCxmfbmJiO4pe8jn4pk4XhMszqc0Q+fRkHXeEigQgFsI4SSkuNk7r +EPSMqPSHpB5SkLyccfvd/wSBv1DvfdMIA5+CUUj3qAT7pm6tvtj0ZnXXnUVexlfp +9+mPMrP0oJ8fSX5kQksCbw+a4C+1ffCzU4S1CUVKboopHzbU2LG80XvjPqXGj2OL +++ghD7OjcD7DqWkO81FQPadrHqWMa8gf2rHmuamZh58LIpattu99lIHVHfFJhYlg +s8EEJQRLa7V4/1Mx9uZGKNmjHNzw/QGW5VqZ3MoVTuXQ3uKmfsXdUTpGRszkJzU1 +zpIOGOMWctWcCmTXpYEhYfiNcPK/WyHntlQJpUgutX/Pho4Q9dP0U1fgsHiKTcRJ +IAg3/pdCiv48K3Wx8Ib+J09mx4wP0rYnaT6f3LSTV+O8u+D8swjngDJ9vYOnyBQt +Z5nYrCpQcvaTGhWAQdz9OqAmPwjY7aLn3hbT0Jf3aFxH3uiWJi0UE3ahLhNWiDTU +PT1VtQ1fSt/ZpJM6KduR1aBFYcEyPIE/MQq9Y2jcYKrIyc4OqkZBwVOFZtRx8cQ7 +tsy1iY3FJjKllp1VdDKRtPs1oKqyX3k446iYryjZs3cDbWV+H5MSwxh7yqw+j5qE +XfvhaImoDFAEisep+w2i7nu80D5uNhFr9bHC/MnRCVlzO1HfrNNns1Oncey1ebJL +PSmpYAiArym6m6fIM9EtTtUrkNUmU0LeqfAaDUmGgtufmmExOtH7/pEuOfbCzoO9 +ZX+TMBRMlOGg55Wc+J597AyEg9mqGKqgoPF8Si2qEElOFYVlaZ88YGPaXKLKI2DA +T7LXYlf+njThf948xsgM41JxE2VG6Ibo3ucHXFEF+QVk+Arrv8jQEGNc1n6cv4Ep +ICoWwHAWN4gvACBi6V0C8Mb5V9cRL6hkCsVZUyOGOKm580qiakxmUe+xGHuMW7Cs +208L5Lsgnn4ynRKLT0yfup73XdQzut/Bkws4ECdDSoSH45VNMR7bdjoGsWkCn5n/ +gbU8PWTPYL907KLpwRBx8fvmOgP2lLBj2gmwyJeowRlzc1MLtsUnH/7H2YSQJgbX +0ZKIRHASwjpnlL4uhp1QMn9Nj9H++MiJ59q7kUmZBJstlbyAw11HkP4cwCIccNO4 +-----END RSA PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/testnode-aes256.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode-aes256.pem new file mode 100644 index 0000000000000..64c765456a1ff --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode-aes256.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,134008CB231A5AD0F27EB8F6FB18A873 + +aJRdAed/XZ+Rl6/s/TwOw8rj+sw2ficvnKjCVJj5wt0+qD2NumPpkXmK9J0+SP21 +Mzzm8H0pQRWrI78vwfFXUxUmQMAuavB9k8HuvZtj1b4GvfHrT/BBbs5wS0RPbE6N +xZuvTvr5UMYFsP85lotcooau3CLtkVXz9ucMQv9v1r2dBvq/7owzl3M+AxhS1oU2 +f8qc3Q411RhVQl29tZha9gidfzBvOO2HH8AqjHxWMHw448oo/b+fXVrpezD1LkmP +0JxP+kJDt1KCiwXj7oRAMaHbHemA2HS713TK+6HammQroF0PCB33Dasy6zaPmP5G +HiJAHvBiblc+vCT7D1lUQCmbjRmeoSESq/P3l8Jhag+wT8SSm5nGaiX7aYHqc00Q +17Gw5e8/iWOU+c3DjCH5qXZFxVrpJgSvVBrrnF3y4sQCG41QpPC7X3mWYWLHZ5vX +GxcI4f1aJ+jECDTvdpE9KL6ncZ05p3A3wr+FqrDPJTb+S1mpD0f6lRhnKILXK83N ++EbRVRTCH5QIx5ZepX28ykuZQa6vHGtnL9WXLX4ZgAIe2abMA5hNs72Hi47LUrss +lA3gMdydKA/WtoimBLqb9brEy9qFsP/2YatKnyXYkjeCgtTQ5LELWSqnFkzQ51wk +VPhT8SqXcPIe9rrNmf7xwJvcZ0IS4tEkT+TovFAs1lo86bCx7VKfWfxcWG/FvW1L +5/1tU4uhpXLOjhOvWOx56zqxt9RORMw3SEh3At4vVHqT2xQAStT1d9QU0/QiM3EE +pBf9uQjRfzlwXph6Gs8XmQYLjSwHurT8hrkoa4/czhE4v7BTst+q6fB3gtxOgV6z +GVBsRK0Lz0ldd56UvnzyChUpE8EFE/Kv6P7T8cgTPnTcGchO4hcKyC31doAFn0pU +LURMC5szvRUEHbPriz9/9qeHBLFMAmGkCfXpwjNoynsKA7/VlAd/44CP82Ljd8Fb +PdwXjz8JNAL+gg3q8Xz4S+z6ZNXVJ1U9GDxjesp7QRbhl1J/ynsGyqIADUmPKjyk +8yFihQYBiZdgiYaOBl9F2X0SINUKaANmVO7HJG+WbPs68fcObfFHRWugC7FljY+b +Az6tNhkKVerCXBEMsZ9XNY05SsyAvcKsWcJbxon9ecIeu7/N8k9eseUL0xQg1oQX +L6wjgmS2ckpPnKVFPXhujZb45PtYEA2ObGd6fPV+82cSgfFM6sPorAmmFhThBXa+ +nE8o72MPVvdUFas3Fs7YugxeFTh9jO4zp/3XA+fFfpxPQbwWjnjxS87OAB+AF6iy +Ul/jZP46kDOnyLdMLvSf5Oq8A73bdGa/09ODsoWjrXlyYmfUZPKPGQ5Hbs5cUSvs +GciJvb3o3OYfSjkn6DVF95f53TiJ9pbGY+zG85f/F3BwbqpRmNYLyxvl4ZzjLs+U +PN24gC78ROzgvHAhY0Ta6PQw8SN5FEoQGmOQT2otZc+Apu1J1Z85mpxd0dYPh29m +kWvx13gZSGxCvNttqfqcRQJTOerQ4PRIyMDJG/sou8hDU51X9USAfjs1spuE6X/a +PIGNpM2TIOaqU/IIFJrGx01vVBhYGvYF8D/q+wwwnjJGYQl7Hscc+JdFmhWE0T2R +-----END RSA PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/testnode-unprotected.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode-unprotected.pem new file mode 100644 index 0000000000000..1602461b11517 --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode-unprotected.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEA3rGZ1QbsW0+MuyrSLmMfDFKtLBkIFW8V0gRuurFg1PUKKNR1 +Mq2tMVwjjYETAU/UY0iKZOzjgvYPKhDTYBTte/WHR1ZK4CYVv7TQX/gtFQG/ge/c +7u0sLch9p7fbd+/HZiLS/rBEZDIohvgUvzvnA8+OIYnw4kuxKo/5iboAIS41klMg +/lATm8V71LMY68inht71/ZkQoAHKgcR9z4yNYvQ1WqKG8DG8KROXltll3sTrKbl5 +zJhn660es/1ZnR6nvwt6xnSTl/mNHMjkfv1bs4rJ/py3qPxicdoSIn/KyojUcgHV +F38fuAy2CQTdjVG5fWj9iz+mQvLm3+qsIYQdFwIDAQABAoIBAQCrsz+qkjX2iTU2 +smNvxJkRxUUj9QDYlde7IBPH+i9wwqXcqULbmjEpF6OJ3PUsU8Kr8ihSfJtGRDWY +93QiZsBcjQiKpiwA+xxVvTHUbONFiR2BL9GmnlMr0aOghw++P6/8Pel02a9BmbLJ +rclBUQxjUcqCbXq+4CFvcaay3Chxa2E5nWgF2zpuVvyt/OOBAaLk2M2J2WFkIwd4 +0/4OXSInNwLS2+WHxpaWl12++MUzlAamNbiqJxogwodGl10ZdlHMq3uhVrJTTcuH +AAF5uv+Rk+ojKO8A10H7b7citiLMzyBXDhusXAGiY4GecLzN3IdKjYUIuLy+3OAZ +uSUvZnqBAoGBAPPCLWla35tqLF/+v3wPMGMcWFOUUEcjoC7swV6EZCEspyyWi1Y9 +oBTkMVUHlCvvsSukdfNkUGrTiXFhU1sJiC9wnIQsJ514D7zHOdYhSmPeA23b60Wr +T/HObEpOyEJaUt2lWu3+wwqnsYIK+dz2MrLoi4qy/p/SNaGYlMabEuv3AoGBAOng +nA7IUM2+1EH1sv/wUTKe7ugw7qvueN/JCSBbD19PwhslrIhWBGnPFR+42hqH/fY+ +2bnm3m+dE1+e2QgRCti2h3uO+IIJGBhkqKN1VgZ+OANT+QA2kRkcCeP7u/agINJX +Z8sRR1rVvlm59dQ6DoONK5fgzpxQSVvm1iZ+Gs/hAoGBAM1nbg7eZZi34kbOCxuG +TRbnVsKvMuqPabbBCL0VwK53yzN2dFmquk+AbtWg+kn/xALrpf0AJgeu0524Dp6j +LKAVO77g2k0GU/SWyPTYvq/i8G7Np7bgghBYCsafFn9bT4K4iSQNztsWrizQBPce +e2BpNtUcuhWA9HKEebHWER7HAoGBAJRkDOBcPNiuUaKgMDiv0/UYXmE4Wtb/8fWb +aoz6+d/xjSkIWFYQrbAs0ixUbx4SVxKcgiyvzUZoFVjAQtgZaBZkicXdytNGzeD8 +TPuZgUGRaBzEdOKrvJh/786VdIdgxjJvfs2bYvjBUYtAsDc9tuPE+HnfC3imgEUt +S4cU0BJBAoGARbDzZHxlsj+M7IMxbN7TIF5yIJdy4fr5xCM1WpAEn90Wa0rnCYQO +9d7uS/WAeuMD3VSaeGGSKBJh3mz/SSbdX/YIXFpOn31FQUCT5lrkWwfwVPEiPpIL +X+dCZ4s235uaqEBLdlHRlG8FNz9frc+EpwbyGd29opzfh8HZuaJzgZc= +-----END RSA PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.crt b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.crt new file mode 100644 index 0000000000000..08c160bcea5ff --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID0zCCArugAwIBAgIJALi5bDfjMszLMA0GCSqGSIb3DQEBCwUAMEgxDDAKBgNV +BAoTA29yZzEWMBQGA1UECxMNZWxhc3RpY3NlYXJjaDEgMB4GA1UEAxMXRWxhc3Rp +Y3NlYXJjaCBUZXN0IE5vZGUwHhcNMTUwOTIzMTg1MjU3WhcNMTkwOTIyMTg1MjU3 +WjBIMQwwCgYDVQQKEwNvcmcxFjAUBgNVBAsTDWVsYXN0aWNzZWFyY2gxIDAeBgNV +BAMTF0VsYXN0aWNzZWFyY2ggVGVzdCBOb2RlMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA3rGZ1QbsW0+MuyrSLmMfDFKtLBkIFW8V0gRuurFg1PUKKNR1 +Mq2tMVwjjYETAU/UY0iKZOzjgvYPKhDTYBTte/WHR1ZK4CYVv7TQX/gtFQG/ge/c +7u0sLch9p7fbd+/HZiLS/rBEZDIohvgUvzvnA8+OIYnw4kuxKo/5iboAIS41klMg +/lATm8V71LMY68inht71/ZkQoAHKgcR9z4yNYvQ1WqKG8DG8KROXltll3sTrKbl5 +zJhn660es/1ZnR6nvwt6xnSTl/mNHMjkfv1bs4rJ/py3qPxicdoSIn/KyojUcgHV +F38fuAy2CQTdjVG5fWj9iz+mQvLm3+qsIYQdFwIDAQABo4G/MIG8MAkGA1UdEwQC +MAAwHQYDVR0OBBYEFEMMWLWQi/g83PzlHYqAVnty5L7HMIGPBgNVHREEgYcwgYSC +CWxvY2FsaG9zdIIVbG9jYWxob3N0LmxvY2FsZG9tYWluggpsb2NhbGhvc3Q0ghds +b2NhbGhvc3Q0LmxvY2FsZG9tYWluNIIKbG9jYWxob3N0NoIXbG9jYWxob3N0Ni5s +b2NhbGRvbWFpbjaHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQEL +BQADggEBAMjGGXT8Nt1tbl2GkiKtmiuGE2Ej66YuZ37WSJViaRNDVHLlg87TCcHe +k2rdO+6sFqQbbzEfwQ05T7xGmVu7tm54HwKMRugoQ3wct0bQC5wEWYN+oMDvSyO6 +M28mZwWb4VtR2IRyWP+ve5DHwTM9mxWa6rBlGzsQqH6YkJpZojzqk/mQTug+Y8aE +mVoqRIPMHq9ob+S9qd5lp09+MtYpwPfTPx/NN+xMEooXWW/ARfpGhWPkg/FuCu4z +1tFmCqHgNcWirzMm3dQpF78muE9ng6OB2MXQwL4VgnVkxmlZNHbkR2v/t8MyZJxC +y4g6cTMM3S/UMt5/+aIB2JAuMKyuD+A= +-----END CERTIFICATE----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.jks b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.jks new file mode 100644 index 0000000000000000000000000000000000000000..ebe6146124e8fd607e46a1a3129bdf9b4de0370d GIT binary patch literal 9360 zcmdUV2T)YowrzLQl93!F2SGC3WF$w)IfLYGK$2vT*iDigl`N7oh@eEt83BokWI;th zKok%V_zil_#dF{N=hmxN@83^VSMRxd)mp3enq$l{$L93&>1O}{0788*FTTk=VD28y zE;cYOYe##Svj^8*Hy60QBMbllY8=Nx4**vTxdk91003Gv1c?>_L4sT!qk(`R5Eh_) zU50G!4F3%T4;_m=TrvCr4+zA$0)Q|==^?b}XnJ5Y;(s+egq9o+ikg;}4=OCcDIVy2IuGcP39Gn>U% zK!zH|Y#zr76z$THNrVtl2Hz*duE|_x{SHKW=Wy9~#x0?_!WxzreKbBd_{B!%FFc+} z#hS1iA!Ph9s*KL}5ZCWMX)1FD)R@OQManE3e-@+qd0nOC5~I@Wvv)K719(Ez^^D!& zt6;h^oFHXs|H>4zGnJ%}f+`Pp>rEdE;=+o<-25$T9lIy1B0c;S!Z_r&_k6nwupM+P z`QIj_3i+10?X14(vmJKmiZElETC3=_VBSWbe19M>na%UTgjKu!)Hb0X5AJ>=1@Lw7vcxjN}1eMG&CU^70?>@)@Jj3w6do zK=}wbX`7exBW2Hy$yVaDo$ICp=}fYb@;nQCWlEe6F`UeJ?OsbuRMGQ zgd{VQ1`}qlEo37p4u-{8N|I&os?=jM_S_F93rh*dwGvc4>^v;F@<@1%AfI?JIxoOG#d{a^ zfIt8&OKT5%FPM$J8|t~~u}>Z;{sXMDD6qapfwk=?SP2aA8Y;D$$)co!mluiHCH4RE zP$7X(VhABRHdYc#Wb!Vj4e%Nnnzf4)lmZJVJR-@b8DwGjw9y}xw)Rb-X`tOZ@L?r7m{x$tD>pf-DK8J8PK&?Rve%UmMWfn zkY1J8$6e`6OS^j3!ZBdDpQ)-!J@JJ984?Dw%90 z9h9Kf+y~ zZ;X4CM_eV}GZ5(`=K*hqpZ8TuPP9ObD5GdI!|KXQ!DE#8?8q-!J#9& z<{0CP?#6ZZ#oFo@=oP4^3J28dh2~!eXSx~~6ipLu^f&9MPd~6p^1dZo&i#yysyksD zk}_18V>Qk~vQwzp^Jc<7;yAcH?9kbl>dg;vDb^QW7vRS}huY7Q{j*f_g#JtPV*wf` zQ+Jb8TG{^cI3dbVTnP3#FtLfzT-or(bOGc4(Y5{#j-5r{Ppfe;7RN>qhPm0{UaW%Vx1xCa5qm=3uM*tyDmx^f zYB_a@Gg~w4N2l?k$LGG^P!NIepM`u@h$CVHNvqI zC)X{Bme~#(ow!*Q{K^N&ikb6+rMH->KX;ZbN6hV7!(1Bu`qVw?;aP#3&Yrekzjpej zK?ev|N zXpSYGJX7Ur@l^_!fa=P>E&WMk1O|eS+U?%te$I}MSaKjCeWH%kki*#p`IR^ zVzx|rZ=W!gg0!F0H2VQ^^Fbof!}9le_))5Y=S5|6FO7Cv zbx_><@>*LeHI$ay>|Nv}{__#cG`gqE5HI=yy!zq2=%Sr>Y-uEp7wE@yxeIf4w6R19 z0pRVhFITw##6I{Y1PK;IRe#z)WcoxH4#%|zmFAbRe+4DeU7$D@vJi|;4ARs2BfumE z$x8ph0~o}3YA&A69w?nhuWt|Yh7v%o{$vY`Up(-~NEBoI#tcxx3+_iT2BrpTtEzI+ znim8i1QFsDfC}TOWK!IHlvq*$BEG}@fH_Cm@4K8Uq-IvD*m|7@F6Jq zuwGO-ZesCM!egNa*#)E@4QIrW8I23(sbgFL z-JqdF#j`8Vy}VmdE^%g2k0bzk-aO3BahcB5rNS zxl7R4(8SoexacwQK1c1P8)rsVPYAtP{l+gAnS>z5E){N%TZk`R&*4@b12lj~mK`oDh0NG!mg`Hy?PMdCk{$fc$gg@y}Zfu}F? zSu0-A5J<7i9~u3DF0|o^$U)%UsmE_ku>)^Gq%Eedjl|h!miFi4Sf0Lza4Yh$3`(a- zlSoW|GYZ|6+ksyVU2ZqAPbBTjepxQ8f5SX?^^wnbkC^~H#@eED&|5^5(CZW?&81lp zuK(Kl>+YUJ=bsA;AOPnN zL%!JXclJ}LX4jeGrIbUTc!v*~SOh1OiRa(L7uS+&TRqzL$=2m37@-?ugp z;<967zk5`#GF$mwu!!%bjbE#w?DiH;8#?Wzm57N|0FrE zn;pF<1Q#6>WkZaJqlDvMT!`PO>8EH>M_C>hj3f*ZfC@oG_ynO46eIBqKp_y`U*T^q z#J`%u2ttgGaj`B4_-g}bKnye)0C)>_&44m!Or)#1Ut8&;!v0wFl7XiLS&Hkpf6yQ+ zS$u^RL1(ei^U17X7FKiWIm_PUG%*qPkB-&%nj|U<+I{m8br3|&CFH3AtedxB3{(XP zEn%Zcf>g8WD}%`mB@~WM zp9uG(2Oy&6>W}bkjBJFW3kT}F6e9aa)BSXsD4RZ=aNVx{s&pychT8+Y$$l_!H^FaL z3LLd5q?EMk(g;f9FP8|X)yaCx6I!~n)nmu%`$=|;KQj#O^GGWI)jJJs z7>Ac9vNah6&K&AwA1hzS{iHejdVYVmZF*^BM|8K!2)nP`sY>CxeFi~sC&l{Y_0{O- zR3w-dQMDW`5;v=7NA6>dI8VL&`0&n)2=-n!aIaAxvy^GPc>jC8J0k!|&vN;X?e2o? zwky$-nw!ods}&g=K8Qr_j^(ku%x(XbPEm^7#X#04E>m|5a#SCvn|mjcA-(GfSo!6& zwo4GA-&byR`#aIaH8CYDzQA5wsTt$tD+m|9?pO*JTVtH)G_p-^rk-c&&hGLBJ0dr& z2HYnandk_~8S)LW z{)anZ&dF##-IbO!HlOrrA1oi$i|ZKRW2P#NW12=pa%4>IZtA*obM+ zUr`Tno4i}q5^Kd+o7JSL=5rZPlc46PloNW-aFxv_(_h*;*fV`daXfEiSnv3Vr)ub+ zGvw0>%{HX26_R#m)1Q}ov&mmtWdu>LrUjHJ2jK4u9jC@di^dq=M4hG)N(@7*Ibn94fDkgeZ1{bnK4+j=-Bc-b2kbl zB2~`9MlJg3nM9CMwMj#DMNZkY^(!}d=9l~B)2~-t=jY-H@fnybqV&{T6)llgafjWi zre8Oej@qni0pGukP;yElQPyUbR0vj64{6xhQ&{gaRu9*}FbDPDrKEY?oF2X`^?(_4 zmb)GR`9|N;k_xAaOKOcB-X5VI4lS)VpXq&hy5>;c=;P=Toe{dSmZd>q!5ROshhh@8 zezz8bnn9YgLPmvb&zHYGpx{ZvsYY(jgBa_`6ML+^wSF{M8|!4r?N-PPovp{FEv z=Pcib1<|(w1v)7kIBo9?+~*w?elzPllgNPEn;f9$IlZoM!$#4pBvCIflR?r-u)c6+ z(<;2~Ya?~aow*x1$ftJceu3cv-rdSCcqt5`!-iUS;QcI~^>3#oN1~~|xtRM0-|ar2 z-}HJmdu!h-8}h(C+}L*|A=$sKNQ*=nCXxLHm$0Of+U)vQ=e8;`-id27tf^>6nRV(o zD_35LMQCiXvc;2P5C$3ZExN#sI331)j7wM4?A}WR5y0vQHB4^!9Cb#LW2-5h8Wg_W zE?(7>&&`t(tsSfKU2gO8^6pwlf#)k(@H#E`*xxz}(ZGA`$b|V!H-7Eo_a;mxUQoaG z@iUWo&dy;${A)aMi66W&;E|)TL`@ITKe|!zaenPBdhYvMi9C1z&?Zn0VDle+KtrRW z&1xm~aLZ+Za#F!ldcDg52k7y8`+5HkKBT>PLT)EHQ+wS0?)^4H3rz7L`xRQ?0#5WuV4tJA^+R{Ul!N!Swi%8vAG}bX`+Jl z{oGbt`~Cx^#3hmbhxOmzd(GpA;JlOb?eHYV$_$QhVoRotB5vEjX~hRt_QbNfZtp`z zCa^jdlJCrmZdH&KP`Nvizsp}P9;bei0LINMRZ>umh z@wu?rUddcG(Rvf=W_VWZm(bV2C!R@~vHk=`B}z~dn3j-Xlqa^He3+oVCSlzhnr_T4 z7xI#}+RkP5Md<>pSR;^knyvj{LXvJ+Xj7FairmPhUH(WR%z8ECi!=5X-}D$9J9kN- zC$E~1Wqy*4yp5$n!!{%z@uufhdn+l@)27$nh~I1VmcvD^9)+Fcjc{mRqB-6n{4VXay+HKSqK6{!h@8K($I}H)GZL zd+vn7OSEuCTdiM0|B8QpC@%zZ-qoWKv;9Igy)4Yl!yayLZRr7{*L87mq?h*eaIu9s z!`x7JZ0LU(_QDWeC`vr@i$J00%{&wp^8X4Ugiw6cLKm~5yIVS0S@NUg`v3iXT_puI zWzN=ski(8IGp7|TpM;&i+%EXYl{BUj)_2s7CuR6q-a0@K^u0%!{YEWpYsrF1XERyZ zf$tMSTink}o&$ffH!`}Es;V{6M4j$g-H?#|zQ}jW+UO?yG=&aPZ`u&)cNLS#c$E%; zP1mx?uy^0lDm~1Sxl4AS3}fIGtsrpPzu9UsUFfLaHBjFbJbOC8(^<{SnS0n!StB#g zL}+<5vF5jPm0~0Vjt%Q?>}z(+kvmw*edbY` z@SqjXB|6rfvcCz`u_)Y;_+8ajHX`pJD&kNHczrrb!=?w{fiV124cV4iCdMz&zJwqK zE{Xo+XoqLy?Bk=64cI=0e(aTjm0Xe#m-AMZ32X;}2a~{K(-z>-Z{9+k8X@v&$i>E+ zQXRR%1%i z+gZhDOYfLI95J{tK}^7qxH4qdT=iwIXI;%~<(7x#tDq?=+?_Bwkrz$Q`TdVlR))UZ zB@j7mCy|Sc;&$|B7PbW~9eY=&!EdvD*IjQ)sB0(+cInMrs1{CN7*c3cOPQ|Rp{(Mt zOjz!_eLXl-Mnq|AsoQfh;NJug*Q+l)T z8)*rHeYv|M#Ut?%U?vsg>xas%hWwvYC#0-Sur)F2=FtkgqgCA#-e%z?+T?CPv=igi zT1bbmLe@F14M@f`Vd)CEd&TVRZ9lERix`Pv&Rj93@;7`u^|14k-pNBn{fTijp&Qtp z1B1q7E%*$Cjn_4DC1sJoqaH8jlQik)F@7bhGU9K_XgO4mt1xyV1wx@8p6R>!Z=zo} zJP|z{6Si_^2=pvzAdCS%KC?wD74V_1_=k2eaRNll~ zg_)0a(KkYGbiWo&D8{^z3der9T|L|venrzv_U)qcQ^$MFo;M|wFp-P!qEO(#sfdZ1oL-r?nXuCiHy2Qq0 ziM;!sUs2F`&Az?Mh;}V|OcB@zA_b&cXvUK=;k^R`-C{MPC+tX)V!8h%5RdT?@P(Uf7yaQA1qCnw{nH+*r>*BMBG9Ld(hllZ5Ey>&8FWz*Q!dPYoj zCzFk0KZGQUrz|3zXT|9#%3tEMsddw5y@{5+yMt>KbeorB%SpCOL#uM0uGFADE&g#g#^|1;Itr9?;L0YErGBwTfC_I{Rc$*iOkJ|A4=@L50Z x`UE0joFCFX(i+qD)1h^DcPJOtN>)kRbQgMUO*p!K@AKymmi%I+{Ip*({}0#og{%Mo literal 0 HcmV?d00001 diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.pem new file mode 100644 index 0000000000000..5a67e1033440d --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,9D867F7E0C94D013 + +dVoVCjPeg1wgS7rVtOvGfQcrZyLkx393aWRnFq45tbjKBVuITtJ9vI7o4QXOV/15 +Gnb6WhXGIdWrzsxEAd46K6hIuNSISd4Emsx6c2Q5hTqWXXfexbOZBNfTtXtdJPnJ +1jAaikhtztLo3JSLTKNY5sNxd+XbaQyYVUWvueK6zOaIIMETvB+VPVFd9i1ROibk +Sgdtyj01KjkoalifqK/tA0CIYNKL0S6/eoK3UhAlpIprlpV+cnXa940C6bjLeJPt +PMAGGp5RrplxSgrSerw3I9DOWkHGtpqzIka3XneNUXJP8k4HUJ+aZkGH2ZILKS8d +4KMIb+KZSpHEGn+6uGccWLtZZmAjWJrDw56JbQtSHdRYLBRSOjLbTvQoPu/2Hpli +7HOxbotlvjptMunncq5aqK57SHA1dh0cwF7J3LUmGFJ67eoz+VV3b5qMn4MopSeI +mS16Ydd3nGpjSrln/elM0CQxqWfcOAXRZpDpFUQoXcBrLVzvz2DBl/0CrTRLhgzi +CO+5/IVcBWRlYpRNGgjjP7q0j6URID3jk5J06fYQXmBiwQT5j+GZqqzpMCJ9mIy2 +1O9SN1hebJnIcEU+E0njn/MGjlYdPywhaCy8pqElp6Q8TUEJpwLRFO/owCoBet/n +ZmCXUjfCGhc1pWHufFcDEQ6xMgEWWY/tdwCZeSU7EhErTjCbfupg+55A5fpDml0m +3wH4CFcuRjlqyx6Ywixm1ATeitDtJl5HQTw6b8OtEXwSgRmZ0eSqSRVk9QbVS7gu +IpQe09/Zimb5HzjZqZ3fdqHlcW4xax8hyJeyIvF5ZJ57eY8CBvu/wP2GDn26QnvF +xQqdfDbq1H4JmpwUHpbFwBoQK4Q6WFd1z4EA9bRQeo3H9PoqoOwMDjzajwLRF7b7 +q6tYH/n9PyHwdf1c4fFwgSmL1toXGfKlA9hjIaLsRSDD6srT5EdUk78bsnddwI51 +tu7C7P4JG+h1VdRNMNTlqtileWsIE7Nn2A1OkcUxZdF5mamENpDpJcHePLto6c8q +FKiwyFMsxhgsj6HK2HqO+UA4sX5Ni4oHwiPmb//EZLn045M5i1AN26KosJmb8++D +sgR5reWRy+UqJCTYblVg+7Dx++ggUnfxVyQEsWmw5r5f4KU5wXBkvoVMGtPNa9DE +n/uLtObD1qkNL38pRsr2OGRchYCgEoKGqEISBP4knfGXLOlWiW/246j9QzI97r1u +tvy7fKg28G7AUz9l6bpewsPHefBUeRQeieP9eJINaEpxkF/w2RpKDLpQjWxwDDOM +s+D0mrBMJve17AmJ8rMw6dIQPZYNZ88/jz1uQuUwQ2YlbmtZbCG81k9YMFGEU9XS +cyhJxj8hvYnt2PR5Z9/cJPyWOs0m/ufOeeQQ8SnU/lzmrQnpzUd2Z6p5i/B7LdRP +n1kX+l1qynuPnjvBz4nJQE0p6nzW8RyCDSniC9mtYtZmhgC8icqxgbvS7uEOBIYJ +NbK+0bEETTO34iY/JVTIqLOw3iQZYMeUpxpj6Phgx/oooxMTquMecPKNgeVtaBst +qjTNPX0ti1/HYpZqzYi8SV8YjHSJWCVMsZjKPr3W/HIcCKqYoIfgzi83Ha2KMQx6 +-----END RSA PRIVATE KEY----- diff --git a/libs/ssl-config/src/test/resources/certs/pem-utils/testnode_with_bagattrs.pem b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode_with_bagattrs.pem new file mode 100644 index 0000000000000..ce8299cd070fc --- /dev/null +++ b/libs/ssl-config/src/test/resources/certs/pem-utils/testnode_with_bagattrs.pem @@ -0,0 +1,32 @@ +Bag Attributes + friendlyName: testnode_rsa + localKeyID: 54 69 6D 65 20 31 35 32 35 33 33 36 38 32 39 33 39 37 +Key Attributes: +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDesZnVBuxbT4y7 +KtIuYx8MUq0sGQgVbxXSBG66sWDU9Qoo1HUyra0xXCONgRMBT9RjSIpk7OOC9g8q +ENNgFO179YdHVkrgJhW/tNBf+C0VAb+B79zu7SwtyH2nt9t378dmItL+sERkMiiG ++BS/O+cDz44hifDiS7Eqj/mJugAhLjWSUyD+UBObxXvUsxjryKeG3vX9mRCgAcqB +xH3PjI1i9DVaoobwMbwpE5eW2WXexOspuXnMmGfrrR6z/VmdHqe/C3rGdJOX+Y0c +yOR+/Vuzisn+nLeo/GJx2hIif8rKiNRyAdUXfx+4DLYJBN2NUbl9aP2LP6ZC8ubf +6qwhhB0XAgMBAAECggEBAKuzP6qSNfaJNTayY2/EmRHFRSP1ANiV17sgE8f6L3DC +pdypQtuaMSkXo4nc9SxTwqvyKFJ8m0ZENZj3dCJmwFyNCIqmLAD7HFW9MdRs40WJ +HYEv0aaeUyvRo6CHD74/r/w96XTZr0GZssmtyUFRDGNRyoJter7gIW9xprLcKHFr +YTmdaAXbOm5W/K3844EBouTYzYnZYWQjB3jT/g5dIic3AtLb5YfGlpaXXb74xTOU +BqY1uKonGiDCh0aXXRl2Ucyre6FWslNNy4cAAXm6/5GT6iMo7wDXQftvtyK2IszP +IFcOG6xcAaJjgZ5wvM3ch0qNhQi4vL7c4Bm5JS9meoECgYEA88ItaVrfm2osX/6/ +fA8wYxxYU5RQRyOgLuzBXoRkISynLJaLVj2gFOQxVQeUK++xK6R182RQatOJcWFT +WwmIL3CchCwnnXgPvMc51iFKY94DbdvrRatP8c5sSk7IQlpS3aVa7f7DCqexggr5 +3PYysuiLirL+n9I1oZiUxpsS6/cCgYEA6eCcDshQzb7UQfWy//BRMp7u6DDuq+54 +38kJIFsPX0/CGyWsiFYEac8VH7jaGof99j7Zuebeb50TX57ZCBEK2LaHe474ggkY +GGSoo3VWBn44A1P5ADaRGRwJ4/u79qAg0ldnyxFHWtW+Wbn11DoOg40rl+DOnFBJ +W+bWJn4az+ECgYEAzWduDt5lmLfiRs4LG4ZNFudWwq8y6o9ptsEIvRXArnfLM3Z0 +Waq6T4Bu1aD6Sf/EAuul/QAmB67TnbgOnqMsoBU7vuDaTQZT9JbI9Ni+r+Lwbs2n +tuCCEFgKxp8Wf1tPgriJJA3O2xauLNAE9x57YGk21Ry6FYD0coR5sdYRHscCgYEA +lGQM4Fw82K5RoqAwOK/T9RheYTha1v/x9ZtqjPr53/GNKQhYVhCtsCzSLFRvHhJX +EpyCLK/NRmgVWMBC2BloFmSJxd3K00bN4PxM+5mBQZFoHMR04qu8mH/vzpV0h2DG +Mm9+zZti+MFRi0CwNz2248T4ed8LeKaARS1LhxTQEkECgYBFsPNkfGWyP4zsgzFs +3tMgXnIgl3Lh+vnEIzVakASf3RZrSucJhA713u5L9YB64wPdVJp4YZIoEmHebP9J +Jt1f9ghcWk6ffUVBQJPmWuRbB/BU8SI+kgtf50Jnizbfm5qoQEt2UdGUbwU3P1+t +z4SnBvIZ3b2inN+Hwdm5onOBlw== +-----END PRIVATE KEY----- diff --git a/settings.gradle b/settings.gradle index 40fb419b0bf3c..95285e20da6ce 100644 --- a/settings.gradle +++ b/settings.gradle @@ -96,6 +96,7 @@ if (isEclipse) { projects << 'libs:secure-sm-tests' projects << 'libs:grok-tests' projects << 'libs:geo-tests' + projects << 'libs:ssl-config' } include projects.toArray(new String[0]) @@ -134,7 +135,12 @@ if (isEclipse) { project(":libs:geo").projectDir = new File(rootProject.projectDir, 'libs/geo/src/main') project(":libs:geo").buildFileName = 'eclipse-build.gradle' project(":libs:geo-tests").projectDir = new File(rootProject.projectDir, 'libs/geo/src/test') - project(":libs:geo-tests").buildFileName = 'eclipse-build.gradle'} + project(":libs:geo-tests").buildFileName = 'eclipse-build.gradle' + project(":libs:ssl-config").projectDir = new File(rootProject.projectDir, 'libs/ssl-config/src/main') + project(":libs:ssl-config").buildFileName = 'eclipse-build.gradle' + project(":libs:ssl-config-tests").projectDir = new File(rootProject.projectDir, 'libs/ssl-config/src/test') + project(":libs:ssl-config-tests").buildFileName = 'eclipse-build.gradle' +} // look for extra plugins for elasticsearch File extraProjects = new File(rootProject.projectDir.parentFile, "${dirName}-extra") @@ -146,3 +152,4 @@ if (extraProjects.exists()) { project(":libs:cli").name = 'elasticsearch-cli' project(":libs:geo").name = 'elasticsearch-geo' +project(":libs:ssl-config").name = 'elasticsearch-ssl-config' From 347cbaf0ed10c421a7887d424a50064b601fe2ec Mon Sep 17 00:00:00 2001 From: Dimitrios Liappis Date: Wed, 16 Jan 2019 13:06:29 +0200 Subject: [PATCH 06/16] Fix line length for aliases and remove suppression (#37455) Relates #34884 --- .../resources/checkstyle_suppressions.xml | 4 -- .../elasticsearch/aliases/IndexAliasesIT.java | 59 +++++++++++++------ 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/buildSrc/src/main/resources/checkstyle_suppressions.xml b/buildSrc/src/main/resources/checkstyle_suppressions.xml index e2aab6b82d35a..775c89c257a9c 100644 --- a/buildSrc/src/main/resources/checkstyle_suppressions.xml +++ b/buildSrc/src/main/resources/checkstyle_suppressions.xml @@ -46,10 +46,6 @@ - - - diff --git a/server/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java b/server/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java index 122b305df971c..a1058b03dacb0 100644 --- a/server/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java +++ b/server/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java @@ -187,7 +187,8 @@ public void testFilteringAliases() throws Exception { logger.info("--> making sure that filter was stored with alias [alias1] and filter [user:kimchy]"); ClusterState clusterState = admin().cluster().prepareState().get().getState(); IndexMetaData indexMd = clusterState.metaData().index("test"); - assertThat(indexMd.getAliases().get("alias1").filter().string(), equalTo("{\"term\":{\"user\":{\"value\":\"kimchy\",\"boost\":1.0}}}")); + assertThat(indexMd.getAliases().get("alias1").filter().string(), + equalTo("{\"term\":{\"user\":{\"value\":\"kimchy\",\"boost\":1.0}}}")); } @@ -321,32 +322,38 @@ public void testSearchingFilteringAliasesTwoIndices() throws Exception { logger.info("--> checking filtering alias for two indices"); SearchResponse searchResponse = client().prepareSearch("foos").setQuery(QueryBuilders.matchAllQuery()).get(); assertHits(searchResponse.getHits(), "1", "5"); - assertThat(client().prepareSearch("foos").setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(2L)); + assertThat(client().prepareSearch("foos") + .setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(2L)); logger.info("--> checking filtering alias for one index"); searchResponse = client().prepareSearch("bars").setQuery(QueryBuilders.matchAllQuery()).get(); assertHits(searchResponse.getHits(), "2"); - assertThat(client().prepareSearch("bars").setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(1L)); + assertThat(client().prepareSearch("bars") + .setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(1L)); logger.info("--> checking filtering alias for two indices and one complete index"); searchResponse = client().prepareSearch("foos", "test1").setQuery(QueryBuilders.matchAllQuery()).get(); assertHits(searchResponse.getHits(), "1", "2", "3", "4", "5"); - assertThat(client().prepareSearch("foos", "test1").setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(5L)); + assertThat(client().prepareSearch("foos", "test1") + .setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(5L)); logger.info("--> checking filtering alias for two indices and non-filtering alias for one index"); searchResponse = client().prepareSearch("foos", "aliasToTest1").setQuery(QueryBuilders.matchAllQuery()).get(); assertHits(searchResponse.getHits(), "1", "2", "3", "4", "5"); - assertThat(client().prepareSearch("foos", "aliasToTest1").setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(5L)); + assertThat(client().prepareSearch("foos", "aliasToTest1") + .setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(5L)); logger.info("--> checking filtering alias for two indices and non-filtering alias for both indices"); searchResponse = client().prepareSearch("foos", "aliasToTests").setQuery(QueryBuilders.matchAllQuery()).get(); assertThat(searchResponse.getHits().getTotalHits().value, equalTo(8L)); - assertThat(client().prepareSearch("foos", "aliasToTests").setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(8L)); + assertThat(client().prepareSearch("foos", "aliasToTests") + .setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(8L)); logger.info("--> checking filtering alias for two indices and non-filtering alias for both indices"); searchResponse = client().prepareSearch("foos", "aliasToTests").setQuery(QueryBuilders.termQuery("name", "something")).get(); assertHits(searchResponse.getHits(), "4", "8"); - assertThat(client().prepareSearch("foos", "aliasToTests").setSize(0).setQuery(QueryBuilders.termQuery("name", "something")).get().getHits().getTotalHits().value, equalTo(2L)); + assertThat(client().prepareSearch("foos", "aliasToTests") + .setSize(0).setQuery(QueryBuilders.termQuery("name", "something")).get().getHits().getTotalHits().value, equalTo(2L)); } public void testSearchingFilteringAliasesMultipleIndices() throws Exception { @@ -390,27 +397,33 @@ public void testSearchingFilteringAliasesMultipleIndices() throws Exception { logger.info("--> checking filtering alias for multiple indices"); SearchResponse searchResponse = client().prepareSearch("filter23", "filter13").setQuery(QueryBuilders.matchAllQuery()).get(); assertHits(searchResponse.getHits(), "21", "31", "13", "33"); - assertThat(client().prepareSearch("filter23", "filter13").setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(4L)); + assertThat(client().prepareSearch("filter23", "filter13") + .setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(4L)); searchResponse = client().prepareSearch("filter23", "filter1").setQuery(QueryBuilders.matchAllQuery()).get(); assertHits(searchResponse.getHits(), "21", "31", "11", "12", "13"); - assertThat(client().prepareSearch("filter23", "filter1").setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(5L)); + assertThat(client().prepareSearch("filter23", "filter1") + .setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(5L)); searchResponse = client().prepareSearch("filter13", "filter1").setQuery(QueryBuilders.matchAllQuery()).get(); assertHits(searchResponse.getHits(), "11", "12", "13", "33"); - assertThat(client().prepareSearch("filter13", "filter1").setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(4L)); + assertThat(client().prepareSearch("filter13", "filter1") + .setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(4L)); searchResponse = client().prepareSearch("filter13", "filter1", "filter23").setQuery(QueryBuilders.matchAllQuery()).get(); assertHits(searchResponse.getHits(), "11", "12", "13", "21", "31", "33"); - assertThat(client().prepareSearch("filter13", "filter1", "filter23").setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(6L)); + assertThat(client().prepareSearch("filter13", "filter1", "filter23") + .setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(6L)); searchResponse = client().prepareSearch("filter23", "filter13", "test2").setQuery(QueryBuilders.matchAllQuery()).get(); assertHits(searchResponse.getHits(), "21", "22", "23", "31", "13", "33"); - assertThat(client().prepareSearch("filter23", "filter13", "test2").setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(6L)); + assertThat(client().prepareSearch("filter23", "filter13", "test2") + .setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(6L)); searchResponse = client().prepareSearch("filter23", "filter13", "test1", "test2").setQuery(QueryBuilders.matchAllQuery()).get(); assertHits(searchResponse.getHits(), "11", "12", "13", "21", "22", "23", "31", "33"); - assertThat(client().prepareSearch("filter23", "filter13", "test1", "test2").setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(8L)); + assertThat(client().prepareSearch("filter23", "filter13", "test1", "test2") + .setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(8L)); } public void testDeletingByQueryFilteringAliases() throws Exception { @@ -447,7 +460,8 @@ public void testDeletingByQueryFilteringAliases() throws Exception { refresh(); logger.info("--> checking counts before delete"); - assertThat(client().prepareSearch("bars").setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(1L)); + assertThat(client().prepareSearch("bars") + .setSize(0).setQuery(QueryBuilders.matchAllQuery()).get().getHits().getTotalHits().value, equalTo(1L)); } public void testDeleteAliases() throws Exception { @@ -511,13 +525,17 @@ public void testWaitForAliasCreationMultipleShards() throws Exception { public void testWaitForAliasCreationSingleShard() throws Exception { logger.info("--> creating index [test]"); - assertAcked(admin().indices().create(createIndexRequest("test").settings(Settings.builder().put("index.number_of_replicas", 0).put("index.number_of_shards", 1))).get()); + assertAcked(admin().indices().create(createIndexRequest("test").settings(Settings.builder() + .put("index.number_of_replicas", 0) + .put("index.number_of_shards", 1))) + .get()); ensureGreen(); for (int i = 0; i < 10; i++) { assertAcked(admin().indices().prepareAliases().addAlias("test", "alias" + i)); - client().index(indexRequest("alias" + i).type("type1").id("1").source(source("1", "test"), XContentType.JSON)).get(); + client().index(indexRequest("alias" + i).type("type1").id("1").source(source("1", "test"), + XContentType.JSON)).get(); } } @@ -579,7 +597,8 @@ public void testSameAlias() throws Exception { assertThat(stopWatch.stop().lastTaskTime().millis(), lessThan(timeout.millis())); logger.info("--> verify that filter was updated"); - AliasMetaData aliasMetaData = ((AliasOrIndex.Alias) internalCluster().clusterService().state().metaData().getAliasAndIndexLookup().get("alias1")).getFirstAliasMetaData(); + AliasMetaData aliasMetaData = ((AliasOrIndex.Alias) internalCluster() + .clusterService().state().metaData().getAliasAndIndexLookup().get("alias1")).getFirstAliasMetaData(); assertThat(aliasMetaData.getFilter().toString(), equalTo("{\"term\":{\"name\":{\"value\":\"bar\",\"boost\":1.0}}}")); logger.info("--> deleting alias1"); @@ -905,8 +924,10 @@ public void testAddAliasWithFilterNoMapping() throws Exception { public void testAliasFilterWithNowInRangeFilterAndQuery() throws Exception { assertAcked(prepareCreate("my-index").addMapping("my-type", "timestamp", "type=date")); - assertAcked(admin().indices().prepareAliases().addAlias("my-index", "filter1", rangeQuery("timestamp").from("2016-12-01").to("2016-12-31"))); - assertAcked(admin().indices().prepareAliases().addAlias("my-index", "filter2", rangeQuery("timestamp").from("2016-01-01").to("2016-12-31"))); + assertAcked(admin().indices().prepareAliases() + .addAlias("my-index", "filter1", rangeQuery("timestamp").from("2016-12-01").to("2016-12-31"))); + assertAcked(admin().indices().prepareAliases() + .addAlias("my-index", "filter2", rangeQuery("timestamp").from("2016-01-01").to("2016-12-31"))); final int numDocs = scaledRandomIntBetween(5, 52); for (int i = 1; i <= numDocs; i++) { From 75410dc632469ef602760801b35e1eae5e2375d4 Mon Sep 17 00:00:00 2001 From: David Kyle Date: Wed, 16 Jan 2019 08:38:46 +0000 Subject: [PATCH 07/16] [Ml] Prevent config snapshot failure blocking migration (#37493) --- .../xpack/ml/MlConfigMigrator.java | 10 +++- .../ml/integration/MlConfigMigratorIT.java | 56 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MlConfigMigrator.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MlConfigMigrator.java index bb03b1170ceca..cd025dc37101d 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MlConfigMigrator.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MlConfigMigrator.java @@ -34,6 +34,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.IndexSettings; +import org.elasticsearch.index.engine.VersionConflictEngineException; import org.elasticsearch.persistent.PersistentTasksCustomMetaData; import org.elasticsearch.xpack.core.ml.MlMetadata; import org.elasticsearch.xpack.core.ml.MlTasks; @@ -460,7 +461,14 @@ public void snapshotMlMeta(MlMetadata mlMetadata, ActionListener listen indexResponse -> { listener.onResponse(indexResponse.getResult() == DocWriteResponse.Result.CREATED); }, - listener::onFailure), + e -> { + if (e instanceof VersionConflictEngineException) { + // the snapshot already exists + listener.onResponse(Boolean.TRUE); + } else { + listener.onFailure(e); + } + }), client::index ); } diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/integration/MlConfigMigratorIT.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/integration/MlConfigMigratorIT.java index b6a0c5346ba37..b8eae71b4bcab 100644 --- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/integration/MlConfigMigratorIT.java +++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/integration/MlConfigMigratorIT.java @@ -6,8 +6,11 @@ package org.elasticsearch.xpack.ml.integration; import org.elasticsearch.Version; +import org.elasticsearch.action.DocWriteRequest; +import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterStateUpdateTask; @@ -180,6 +183,59 @@ public void testMigrateConfigs() throws InterruptedException, IOException { assertEquals("df-1", datafeedsHolder.get().get(0).getId()); } + public void testExistingSnapshotDoesNotBlockMigration() throws InterruptedException { + // index a doc with the same Id as the config snapshot + IndexRequestBuilder indexRequest = client().prepareIndex(AnomalyDetectorsIndex.jobStateIndexName(), + ElasticsearchMappings.DOC_TYPE, "ml-config") + .setSource(Collections.singletonMap("a_field", "a_value")) + .setOpType(DocWriteRequest.OpType.CREATE) + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); + + indexRequest.execute().actionGet(); + + // define the configs + MlMetadata.Builder mlMetadata = new MlMetadata.Builder(); + mlMetadata.putJob(buildJobBuilder("job-foo").build(), false); + + MetaData.Builder metaData = MetaData.builder(); + RoutingTable.Builder routingTable = RoutingTable.builder(); + addMlConfigIndex(metaData, routingTable); + ClusterState clusterState = ClusterState.builder(new ClusterName("_name")) + .metaData(metaData.putCustom(MlMetadata.TYPE, mlMetadata.build())) + .routingTable(routingTable.build()) + .build(); + + doAnswer(invocation -> { + ClusterStateUpdateTask listener = (ClusterStateUpdateTask) invocation.getArguments()[1]; + listener.clusterStateProcessed("source", mock(ClusterState.class), mock(ClusterState.class)); + return null; + }).when(clusterService).submitStateUpdateTask(eq("remove-migrated-ml-configs"), any()); + + AtomicReference exceptionHolder = new AtomicReference<>(); + AtomicReference responseHolder = new AtomicReference<>(); + + // do the migration + MlConfigMigrator mlConfigMigrator = new MlConfigMigrator(nodeSettings(), client(), clusterService); + // writing the snapshot should fail because the doc already exists + // in which case the migration should continue + blockingCall(actionListener -> mlConfigMigrator.migrateConfigs(clusterState, actionListener), + responseHolder, exceptionHolder); + + assertNull(exceptionHolder.get()); + assertTrue(responseHolder.get()); + + // check the jobs have been migrated + AtomicReference> jobsHolder = new AtomicReference<>(); + JobConfigProvider jobConfigProvider = new JobConfigProvider(client()); + blockingCall(actionListener -> jobConfigProvider.expandJobs("*", true, true, actionListener), + jobsHolder, exceptionHolder); + + assertNull(exceptionHolder.get()); + assertThat(jobsHolder.get(), hasSize(1)); + assertTrue(jobsHolder.get().get(0).build().getCustomSettings().containsKey(MlConfigMigrator.MIGRATED_FROM_VERSION)); + assertEquals("job-foo", jobsHolder.get().get(0).build().getId()); + } + public void testMigrateConfigs_GivenLargeNumberOfJobsAndDatafeeds() throws InterruptedException { int jobCount = randomIntBetween(150, 201); int datafeedCount = randomIntBetween(150, jobCount); From 687978b7d167d4c20a29861b2558b2749c349529 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Wed, 16 Jan 2019 07:29:25 -0500 Subject: [PATCH 08/16] Reject all requests that have an unconsumed body (#37504) This commit removes some leniency from REST handling where we move to reject all requests that have a body where the body is not used during the course of handling the request. For example, DELETE /index { "query" : { "term" : { "field" : "value" } } } is now rejected. --- .../elasticsearch/rest/BaseRestHandler.java | 4 + .../org/elasticsearch/rest/RestRequest.java | 13 +++- .../admin/indices/RestForceMergeAction.java | 9 +-- .../forcemerge/RestForceMergeActionTests.java | 10 ++- .../rest/BaseRestHandlerTests.java | 78 +++++++++++++++++++ .../elasticsearch/rest/RestRequestTests.java | 65 ++++++++++++++-- .../test/rest/FakeRestRequest.java | 7 +- 7 files changed, 165 insertions(+), 21 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/rest/BaseRestHandler.java b/server/src/main/java/org/elasticsearch/rest/BaseRestHandler.java index 98611e4c9d8ab..36189381c5b22 100644 --- a/server/src/main/java/org/elasticsearch/rest/BaseRestHandler.java +++ b/server/src/main/java/org/elasticsearch/rest/BaseRestHandler.java @@ -99,6 +99,10 @@ public final void handleRequest(RestRequest request, RestChannel channel, NodeCl throw new IllegalArgumentException(unrecognized(request, unconsumedParams, candidateParams, "parameter")); } + if (request.hasContent() && request.isContentConsumed() == false) { + throw new IllegalArgumentException("request [" + request.method() + " " + request.path() + "] does not support having a body"); + } + usageCount.increment(); // execute the action action.accept(channel); diff --git a/server/src/main/java/org/elasticsearch/rest/RestRequest.java b/server/src/main/java/org/elasticsearch/rest/RestRequest.java index 813d6feb55167..fe976ee4ddce6 100644 --- a/server/src/main/java/org/elasticsearch/rest/RestRequest.java +++ b/server/src/main/java/org/elasticsearch/rest/RestRequest.java @@ -66,6 +66,12 @@ public class RestRequest implements ToXContent.Params { private final HttpRequest httpRequest; private final HttpChannel httpChannel; + private boolean contentConsumed = false; + + public boolean isContentConsumed() { + return contentConsumed; + } + protected RestRequest(NamedXContentRegistry xContentRegistry, Map params, String path, Map> headers, HttpRequest httpRequest, HttpChannel httpChannel) { final XContentType xContentType; @@ -173,10 +179,15 @@ public final String path() { } public boolean hasContent() { - return content().length() > 0; + return content(false).length() > 0; } public BytesReference content() { + return content(true); + } + + protected BytesReference content(final boolean contentConsumed) { + this.contentConsumed = this.contentConsumed | contentConsumed; return httpRequest.content(); } diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestForceMergeAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestForceMergeAction.java index 6ec4cec77193e..2d9d691d2c71a 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestForceMergeAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestForceMergeAction.java @@ -34,7 +34,8 @@ import static org.elasticsearch.rest.RestRequest.Method.POST; public class RestForceMergeAction extends BaseRestHandler { - public RestForceMergeAction(Settings settings, RestController controller) { + + public RestForceMergeAction(final Settings settings, final RestController controller) { super(settings); controller.registerHandler(POST, "/_forcemerge", this); controller.registerHandler(POST, "/{index}/_forcemerge", this); @@ -47,14 +48,12 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { - if (request.hasContent()) { - throw new IllegalArgumentException("forcemerge takes arguments in query parameters, not in the request body"); - } - ForceMergeRequest mergeRequest = new ForceMergeRequest(Strings.splitStringByCommaToArray(request.param("index"))); + final ForceMergeRequest mergeRequest = new ForceMergeRequest(Strings.splitStringByCommaToArray(request.param("index"))); mergeRequest.indicesOptions(IndicesOptions.fromRequest(request, mergeRequest.indicesOptions())); mergeRequest.maxNumSegments(request.paramAsInt("max_num_segments", mergeRequest.maxNumSegments())); mergeRequest.onlyExpungeDeletes(request.paramAsBoolean("only_expunge_deletes", mergeRequest.onlyExpungeDeletes())); mergeRequest.flush(request.paramAsBoolean("flush", mergeRequest.flush())); return channel -> client.admin().indices().forceMerge(mergeRequest, new RestToXContentListener<>(channel)); } + } diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/forcemerge/RestForceMergeActionTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/forcemerge/RestForceMergeActionTests.java index aeb5beb09e2fc..2d4093d8525d9 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/forcemerge/RestForceMergeActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/forcemerge/RestForceMergeActionTests.java @@ -28,6 +28,7 @@ import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.action.admin.indices.RestForceMergeAction; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.rest.FakeRestChannel; import org.elasticsearch.test.rest.FakeRestRequest; import static org.hamcrest.Matchers.equalTo; @@ -39,9 +40,12 @@ public void testBodyRejection() throws Exception { final RestForceMergeAction handler = new RestForceMergeAction(Settings.EMPTY, mock(RestController.class)); String json = JsonXContent.contentBuilder().startObject().field("max_num_segments", 1).endObject().toString(); final FakeRestRequest request = new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY) - .withContent(new BytesArray(json), XContentType.JSON).build(); + .withContent(new BytesArray(json), XContentType.JSON) + .withPath("/_forcemerge") + .build(); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, - () -> handler.prepareRequest(request, mock(NodeClient.class))); - assertThat(e.getMessage(), equalTo("forcemerge takes arguments in query parameters, not in the request body")); + () -> handler.handleRequest(request, new FakeRestChannel(request, randomBoolean(), 1), mock(NodeClient.class))); + assertThat(e.getMessage(), equalTo("request [GET /_forcemerge] does not support having a body")); } + } diff --git a/server/src/test/java/org/elasticsearch/rest/BaseRestHandlerTests.java b/server/src/test/java/org/elasticsearch/rest/BaseRestHandlerTests.java index 835dd7cd9fab0..68e3c8416b9c2 100644 --- a/server/src/test/java/org/elasticsearch/rest/BaseRestHandlerTests.java +++ b/server/src/test/java/org/elasticsearch/rest/BaseRestHandlerTests.java @@ -21,7 +21,11 @@ import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.Table; +import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.rest.action.cat.AbstractCatAction; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.rest.FakeRestChannel; @@ -232,4 +236,78 @@ public String getName() { assertTrue(executed.get()); } + public void testConsumedBody() throws Exception { + final AtomicBoolean executed = new AtomicBoolean(); + final BaseRestHandler handler = new BaseRestHandler(Settings.EMPTY) { + @Override + protected RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { + request.content(); + return channel -> executed.set(true); + } + + @Override + public String getName() { + return "test_consumed_body"; + } + + }; + + try (XContentBuilder builder = JsonXContent.contentBuilder().startObject().endObject()) { + final RestRequest request = new FakeRestRequest.Builder(xContentRegistry()) + .withContent(new BytesArray(builder.toString()), XContentType.JSON) + .build(); + final RestChannel channel = new FakeRestChannel(request, randomBoolean(), 1); + handler.handleRequest(request, channel, mock(NodeClient.class)); + assertTrue(executed.get()); + } + } + + public void testUnconsumedNoBody() throws Exception { + final AtomicBoolean executed = new AtomicBoolean(); + final BaseRestHandler handler = new BaseRestHandler(Settings.EMPTY) { + @Override + protected RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { + return channel -> executed.set(true); + } + + @Override + public String getName() { + return "test_unconsumed_body"; + } + + }; + + final RestRequest request = new FakeRestRequest.Builder(xContentRegistry()).build(); + final RestChannel channel = new FakeRestChannel(request, randomBoolean(), 1); + handler.handleRequest(request, channel, mock(NodeClient.class)); + assertTrue(executed.get()); + } + + public void testUnconsumedBody() throws IOException { + final AtomicBoolean executed = new AtomicBoolean(); + final BaseRestHandler handler = new BaseRestHandler(Settings.EMPTY) { + @Override + protected RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { + return channel -> executed.set(true); + } + + @Override + public String getName() { + return "test_unconsumed_body"; + } + + }; + + try (XContentBuilder builder = JsonXContent.contentBuilder().startObject().endObject()) { + final RestRequest request = new FakeRestRequest.Builder(xContentRegistry()) + .withContent(new BytesArray(builder.toString()), XContentType.JSON) + .build(); + final RestChannel channel = new FakeRestChannel(request, randomBoolean(), 1); + final IllegalArgumentException e = + expectThrows(IllegalArgumentException.class, () -> handler.handleRequest(request, channel, mock(NodeClient.class))); + assertThat(e, hasToString(containsString("request [GET /] does not support having a body"))); + assertFalse(executed.get()); + } + } + } diff --git a/server/src/test/java/org/elasticsearch/rest/RestRequestTests.java b/server/src/test/java/org/elasticsearch/rest/RestRequestTests.java index 3ad9c61de3c8e..8a2994a69816b 100644 --- a/server/src/test/java/org/elasticsearch/rest/RestRequestTests.java +++ b/server/src/test/java/org/elasticsearch/rest/RestRequestTests.java @@ -20,12 +20,15 @@ package org.elasticsearch.rest; import org.elasticsearch.ElasticsearchParseException; -import org.elasticsearch.common.Strings; +import org.elasticsearch.common.CheckedConsumer; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.collect.MapBuilder; import org.elasticsearch.common.xcontent.NamedXContentRegistry; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.http.HttpChannel; +import org.elasticsearch.http.HttpRequest; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.rest.FakeRestRequest; @@ -41,8 +44,62 @@ import static java.util.Collections.singletonMap; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class RestRequestTests extends ESTestCase { + + public void testContentConsumesContent() { + runConsumesContentTest(RestRequest::content, true); + } + + public void testRequiredContentConsumesContent() { + runConsumesContentTest(RestRequest::requiredContent, true); + } + + public void testContentParserConsumesContent() { + runConsumesContentTest(RestRequest::contentParser, true); + } + + public void testContentOrSourceParamConsumesContent() { + runConsumesContentTest(RestRequest::contentOrSourceParam, true); + } + + public void testContentOrSourceParamsParserConsumesContent() { + runConsumesContentTest(RestRequest::contentOrSourceParamParser, true); + } + + public void testWithContentOrSourceParamParserOrNullConsumesContent() { + @SuppressWarnings("unchecked") CheckedConsumer consumer = mock(CheckedConsumer.class); + runConsumesContentTest(request -> request.withContentOrSourceParamParserOrNull(consumer), true); + } + + public void testApplyContentParserConsumesContent() { + @SuppressWarnings("unchecked") CheckedConsumer consumer = mock(CheckedConsumer.class); + runConsumesContentTest(request -> request.applyContentParser(consumer), true); + } + + public void testHasContentDoesNotConsumesContent() { + runConsumesContentTest(RestRequest::hasContent, false); + } + + private void runConsumesContentTest( + final CheckedConsumer consumer, final boolean expected) { + final HttpRequest httpRequest = mock(HttpRequest.class); + when (httpRequest.uri()).thenReturn(""); + when (httpRequest.content()).thenReturn(new BytesArray(new byte[1])); + final RestRequest request = + RestRequest.request(mock(NamedXContentRegistry.class), httpRequest, mock(HttpChannel.class)); + request.setXContentType(XContentType.JSON); + assertFalse(request.isContentConsumed()); + try { + consumer.accept(request); + } catch (final Exception e) { + throw new RuntimeException(e); + } + assertThat(request.isContentConsumed(), equalTo(expected)); + } + public void testContentParser() throws IOException { Exception e = expectThrows(ElasticsearchParseException.class, () -> contentRestRequest("", emptyMap()).contentParser()); @@ -211,14 +268,10 @@ public String uri() { return restRequest.uri(); } - @Override - public boolean hasContent() { - return Strings.hasLength(content()); - } - @Override public BytesReference content() { return restRequest.content(); } } + } diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/FakeRestRequest.java b/test/framework/src/main/java/org/elasticsearch/test/rest/FakeRestRequest.java index 2aec495390b6c..a659d6af5c6aa 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/FakeRestRequest.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/FakeRestRequest.java @@ -48,11 +48,6 @@ private FakeRestRequest(NamedXContentRegistry xContentRegistry, HttpRequest http super(xContentRegistry, params, httpRequest.uri(), httpRequest.getHeaders(), httpRequest, httpChannel); } - @Override - public boolean hasContent() { - return content() != null; - } - private static class FakeHttpRequest implements HttpRequest { private final Method method; @@ -166,7 +161,7 @@ public static class Builder { private Map params = new HashMap<>(); - private BytesReference content; + private BytesReference content = BytesArray.EMPTY; private String path = "/"; From 21a88d5505835592dcaea1e56690c94c723daa4e Mon Sep 17 00:00:00 2001 From: Armin Braun Date: Wed, 16 Jan 2019 13:57:16 +0100 Subject: [PATCH 09/16] Simplify + Cleanup Dead Code in Settings (#37341) * Remove dead code * Simplify some overly complex code, this class is long enough already --- .../common/settings/Settings.java | 101 ++---------------- 1 file changed, 9 insertions(+), 92 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/common/settings/Settings.java b/server/src/main/java/org/elasticsearch/common/settings/Settings.java index ac43a1800b40f..107c7bb9b8a59 100644 --- a/server/src/main/java/org/elasticsearch/common/settings/Settings.java +++ b/server/src/main/java/org/elasticsearch/common/settings/Settings.java @@ -34,8 +34,6 @@ import org.elasticsearch.common.unit.ByteSizeUnit; import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.common.unit.MemorySizeValue; -import org.elasticsearch.common.unit.RatioValue; -import org.elasticsearch.common.unit.SizeValue; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.DeprecationHandler; import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; @@ -64,6 +62,7 @@ import java.util.List; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Set; import java.util.TreeMap; import java.util.ListIterator; @@ -75,7 +74,6 @@ import java.util.stream.Stream; import static org.elasticsearch.common.unit.ByteSizeValue.parseBytesSizeValue; -import static org.elasticsearch.common.unit.SizeValue.parseSizeValue; import static org.elasticsearch.common.unit.TimeValue.parseTimeValue; /** @@ -100,7 +98,7 @@ public final class Settings implements ToXContentFragment { */ private final SetOnce> keys = new SetOnce<>(); - Settings(Map settings, SecureSettings secureSettings) { + private Settings(Map settings, SecureSettings secureSettings) { // we use a sorted map for consistent serialization when using getAsMap() this.settings = Collections.unmodifiableSortedMap(new TreeMap<>(settings)); this.secureSettings = secureSettings; @@ -245,30 +243,6 @@ public String get(String setting, String defaultValue) { return retVal == null ? defaultValue : retVal; } - /** - * Returns the setting value associated with the setting key. If it does not exists, - * returns the default value provided. - */ - String get(String setting, String defaultValue, boolean isList) { - Object value = settings.get(setting); - if (value != null) { - if (value instanceof List) { - if (isList == false) { - throw new IllegalArgumentException( - "Found list type value for setting [" + setting + "] but but did not expect a list for it." - ); - } - } else if (isList) { - throw new IllegalArgumentException( - "Expected list type value for setting [" + setting + "] but found [" + value.getClass() + ']' - ); - } - return toString(value); - } else { - return defaultValue; - } - } - /** * Returns the setting value (as float) associated with the setting key. If it does not exists, * returns the default value provided. @@ -382,23 +356,6 @@ public ByteSizeValue getAsMemory(String setting, String defaultValue) throws Set return MemorySizeValue.parseBytesSizeValueOrHeapRatio(get(setting, defaultValue), setting); } - /** - * Returns the setting value (as a RatioValue) associated with the setting key. Provided values can - * either be a percentage value (eg. 23%), or expressed as a floating point number (eg. 0.23). If - * it does not exist, parses the default value provided. - */ - public RatioValue getAsRatio(String setting, String defaultValue) throws SettingsException { - return RatioValue.parseRatioValue(get(setting, defaultValue)); - } - - /** - * Returns the setting value (as size) associated with the setting key. If it does not exists, - * returns the default value provided. - */ - public SizeValue getAsSize(String setting, SizeValue defaultValue) throws SettingsException { - return parseSizeValue(get(setting), defaultValue); - } - /** * The values associated with a setting key as an immutable list. *

    @@ -503,11 +460,7 @@ private Map getGroupsInternal(String settingPrefix, boolean ig * Returns group settings for the given setting prefix. */ public Map getAsGroups() throws SettingsException { - return getAsGroups(false); - } - - public Map getAsGroups(boolean ignoreNonGrouped) throws SettingsException { - return getGroupsInternal("", ignoreNonGrouped); + return getGroupsInternal("", false); } /** @@ -566,14 +519,12 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; Settings that = (Settings) o; - if (settings != null ? !settings.equals(that.settings) : that.settings != null) return false; - return true; + return Objects.equals(settings, that.settings); } @Override public int hashCode() { - int result = settings != null ? settings.hashCode() : 0; - return result; + return settings != null ? settings.hashCode() : 0; } public static Settings readSettingsFromStream(StreamInput in) throws IOException { @@ -791,7 +742,7 @@ public static class Builder { // we use a sorted map for consistent serialization when using getAsMap() private final Map map = new TreeMap<>(); - private SetOnce secureSettings = new SetOnce<>(); + private final SetOnce secureSettings = new SetOnce<>(); private Builder() { @@ -935,18 +886,6 @@ public Builder putNull(String key) { return put(key, (String) null); } - /** - * Sets a setting with the provided setting key and class as value. - * - * @param key The setting key - * @param clazz The setting class value - * @return The builder - */ - public Builder put(String key, Class clazz) { - map.put(key, clazz.getName()); - return this; - } - /** * Sets the setting with the provided setting key and the boolean value. * @@ -1061,22 +1000,6 @@ public Builder putList(String setting, List values) { return this; } - /** - * Sets the setting group. - */ - public Builder put(String settingPrefix, String groupName, String[] settings, String[] values) throws SettingsException { - if (settings.length != values.length) { - throw new SettingsException("The settings length must match the value length"); - } - for (int i = 0; i < settings.length; i++) { - if (values[i] == null) { - continue; - } - put(settingPrefix + "." + groupName + "." + settings[i], values[i]); - } - return this; - } - /** * Sets all the provided settings including secure settings */ @@ -1210,18 +1133,12 @@ public String resolvePlaceholder(String placeholderName) { @Override public boolean shouldIgnoreMissing(String placeholderName) { - if (placeholderName.startsWith("prompt.")) { - return true; - } - return false; + return placeholderName.startsWith("prompt."); } @Override public boolean shouldRemoveMissingPlaceholder(String placeholderName) { - if (placeholderName.startsWith("prompt.")) { - return false; - } - return true; + return !placeholderName.startsWith("prompt."); } }; @@ -1395,7 +1312,7 @@ public boolean containsKey(Object key) { @Override public int size() { if (size == -1) { - size = Math.toIntExact(delegate.keySet().stream().filter((e) -> filter.test(e)).count()); + size = Math.toIntExact(delegate.keySet().stream().filter(filter).count()); } return size; } From 9d8afe68a534741a4cc9357b6ab4c719e46011eb Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Wed, 16 Jan 2019 14:01:09 +0100 Subject: [PATCH 10/16] IndexMetaData#mappingOrDefault doesn't need to take a type argument. (#37480) Currently it takes a type, but this isn't really needed now that indices can have at most one type. The only downside is that we might return a different error when trying to index into a type that doesnt't exist yet. --- .../action/bulk/TransportBulkAction.java | 2 +- .../action/bulk/TransportShardBulkAction.java | 2 +- .../cluster/metadata/IndexMetaData.java | 13 ++++--- .../cluster/metadata/IndexMetaDataTests.java | 36 +++++++++++++++++++ 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/bulk/TransportBulkAction.java b/server/src/main/java/org/elasticsearch/action/bulk/TransportBulkAction.java index 7979b633efebe..567b7fb808090 100644 --- a/server/src/main/java/org/elasticsearch/action/bulk/TransportBulkAction.java +++ b/server/src/main/java/org/elasticsearch/action/bulk/TransportBulkAction.java @@ -351,7 +351,7 @@ protected void doRun() throws Exception { case INDEX: IndexRequest indexRequest = (IndexRequest) docWriteRequest; final IndexMetaData indexMetaData = metaData.index(concreteIndex); - MappingMetaData mappingMd = indexMetaData.mappingOrDefault(indexRequest.type()); + MappingMetaData mappingMd = indexMetaData.mappingOrDefault(); Version indexCreated = indexMetaData.getCreationVersion(); indexRequest.resolveRouting(metaData); indexRequest.process(indexCreated, mappingMd, concreteIndex.getName()); diff --git a/server/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java b/server/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java index d56cd5c8cbce3..4df8efa6b2743 100644 --- a/server/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java +++ b/server/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java @@ -191,7 +191,7 @@ static void executeBulkItemRequest(BulkPrimaryExecutionContext context, UpdateHe case UPDATED: IndexRequest indexRequest = updateResult.action(); IndexMetaData metaData = context.getPrimary().indexSettings().getIndexMetaData(); - MappingMetaData mappingMd = metaData.mappingOrDefault(indexRequest.type()); + MappingMetaData mappingMd = metaData.mappingOrDefault(); indexRequest.process(metaData.getCreationVersion(), mappingMd, updateRequest.concreteIndex()); context.setRequestToExecute(indexRequest); break; diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java index 73e3c6b67eccf..e349bd6fb7383 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java @@ -505,12 +505,15 @@ public Index getResizeSourceIndex() { * setting its routing, timestamp, and so on if needed. */ @Nullable - public MappingMetaData mappingOrDefault(String mappingType) { - MappingMetaData mapping = mappings.get(mappingType); - if (mapping != null) { - return mapping; + public MappingMetaData mappingOrDefault() { + MappingMetaData mapping = null; + for (ObjectCursor m : mappings.values()) { + if (mapping == null || mapping.type().equals(MapperService.DEFAULT_MAPPING)) { + mapping = m.value; + } } - return mappings.get(MapperService.DEFAULT_MAPPING); + + return mapping; } ImmutableOpenMap getCustomData() { diff --git a/server/src/test/java/org/elasticsearch/cluster/metadata/IndexMetaDataTests.java b/server/src/test/java/org/elasticsearch/cluster/metadata/IndexMetaDataTests.java index 1fdea596afbf9..e3b6234daa7ca 100644 --- a/server/src/test/java/org/elasticsearch/cluster/metadata/IndexMetaDataTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/metadata/IndexMetaDataTests.java @@ -19,6 +19,7 @@ package org.elasticsearch.cluster.metadata; +import org.elasticsearch.Version; import org.elasticsearch.action.admin.indices.rollover.MaxAgeCondition; import org.elasticsearch.action.admin.indices.rollover.MaxDocsCondition; import org.elasticsearch.action.admin.indices.rollover.MaxSizeCondition; @@ -39,6 +40,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.indices.IndicesModule; import org.elasticsearch.test.ESTestCase; @@ -287,4 +289,38 @@ public void testNumberOfRoutingShards() { () -> IndexMetaData.INDEX_NUMBER_OF_ROUTING_SHARDS_SETTING.get(notAFactorySettings)); assertEquals("the number of source shards [2] must be a factor of [3]", iae.getMessage()); } + + public void testMappingOrDefault() throws IOException { + Settings settings = Settings.builder() + .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) + .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 2) + .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 1) + .build(); + IndexMetaData meta = IndexMetaData.builder("index") + .settings(settings) + .build(); + assertNull(meta.mappingOrDefault()); + + meta = IndexMetaData.builder("index") + .settings(settings) + .putMapping("type", "{}") + .build(); + assertNotNull(meta.mappingOrDefault()); + assertEquals("type", meta.mappingOrDefault().type()); + + meta = IndexMetaData.builder("index") + .settings(settings) + .putMapping(MapperService.DEFAULT_MAPPING, "{}") + .build(); + assertNotNull(meta.mappingOrDefault()); + assertEquals(MapperService.DEFAULT_MAPPING, meta.mappingOrDefault().type()); + + meta = IndexMetaData.builder("index") + .settings(settings) + .putMapping("type", "{}") + .putMapping(MapperService.DEFAULT_MAPPING, "{}") + .build(); + assertNotNull(meta.mappingOrDefault()); + assertEquals("type", meta.mappingOrDefault().type()); + } } From 8932750efbafb54a16e313bc613209bdc57702d2 Mon Sep 17 00:00:00 2001 From: Marios Trivyzas Date: Wed, 16 Jan 2019 16:16:21 +0200 Subject: [PATCH 11/16] SQL: [Docs] Add an ES-SQL column for data types (#37529) In order to distinguish the ES-SQL type from the standard SQL type add a new ES-SQL column that will make clear this distingstion, e.g.: datetime vs TIMSTAMP Fixes: #37519 --- .../sql/language/data-types.asciidoc | 59 ++++++++++--------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/docs/reference/sql/language/data-types.asciidoc b/docs/reference/sql/language/data-types.asciidoc index a4a407f175e17..60bdf0c5f66d3 100644 --- a/docs/reference/sql/language/data-types.asciidoc +++ b/docs/reference/sql/language/data-types.asciidoc @@ -5,41 +5,44 @@ beta[] -Most of {es} <> are available in {es-sql}, as indicated below: +Most of {es} <> are available in {es-sql}, as indicated below. +As one can see, all of {es} <> are mapped to the data type with the same +name in {es-sql}, with the exception of **date** data type which is mapped to **datetime** in {es-sql}: -[cols="^,^m,^"] +[cols="^,^m,^,^"] |=== s|{es} type +s|{es-sql} type s|SQL type s|SQL precision -3+h| Core types - -| <> | null | 0 -| <> | boolean | 1 -| <> | tinyint | 3 -| <> | smallint | 5 -| <> | integer | 10 -| <> | bigint | 19 -| <> | double | 15 -| <> | real | 7 -| <> | float | 16 -| <> | float | 19 -| <> | varchar | based on <> -| <> | varchar | 2,147,483,647 -| <> | varbinary | 2,147,483,647 -| <> | timestamp | 24 -| <> | varchar | 39 - -3+h| Complex types - -| <> | struct | 0 -| <> | struct | 0 - -3+h| Unsupported types - -| _types not mentioned above_ | unsupported | 0 +4+h| Core types + +| <> | null | NULL | 0 +| <> | boolean | BOOLEAN | 1 +| <> | byte | TINYINT | 3 +| <> | short | SMALLINT | 5 +| <> | integer | INTEGER | 10 +| <> | long | BIGINT | 19 +| <> | double | DOUBLE | 15 +| <> | float | REAL | 7 +| <> | half_float | FLOAT | 16 +| <> | scaled_float | FLOAT | 19 +| <> | keyword | VARCHAR | based on <> +| <> | text | VARCHAR | 2,147,483,647 +| <> | binary | VARBINARY | 2,147,483,647 +| <> | datetime | TIMESTAMP | 24 +| <> | ip | VARCHAR | 39 + +4+h| Complex types + +| <> | object | STRUCT | 0 +| <> | nested | STRUCT | 0 + +4+h| Unsupported types + +| _types not mentioned above_ | unsupported | OTHER | 0 |=== From 659326fdd63097626a82d2f004a446482a042cd7 Mon Sep 17 00:00:00 2001 From: Andrei Stefan Date: Wed, 16 Jan 2019 16:28:46 +0200 Subject: [PATCH 12/16] SQL: Add protocol tests and remove jdbc_type from drivers response (#37516) --- .../sql/qa/single_node/SqlProtocolIT.java | 12 ++ .../xpack/sql/qa/SqlProtocolTestCase.java | 193 ++++++++++++++++++ .../xpack/sql/qa/jdbc/JdbcTestUtils.java | 2 +- .../xpack/sql/qa/rest/RestSqlTestCase.java | 1 - .../sql/qa/src/main/resources/agg.csv-spec | 8 + .../xpack/sql/action/SqlQueryResponse.java | 21 +- .../sql/action/SqlQueryResponseTests.java | 4 +- .../command/ServerQueryCliCommandTests.java | 3 +- .../xpack/sql/proto/ColumnInfo.java | 34 +-- .../sql/plugin/TransportSqlQueryAction.java | 3 +- .../xpack/sql/action/CliFormatterTests.java | 11 +- .../xpack/sql/action/SqlActionIT.java | 6 +- .../sql/execution/search/CursorTests.java | 3 +- 13 files changed, 237 insertions(+), 64 deletions(-) create mode 100644 x-pack/plugin/sql/qa/single-node/src/test/java/org/elasticsearch/xpack/sql/qa/single_node/SqlProtocolIT.java create mode 100644 x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/SqlProtocolTestCase.java diff --git a/x-pack/plugin/sql/qa/single-node/src/test/java/org/elasticsearch/xpack/sql/qa/single_node/SqlProtocolIT.java b/x-pack/plugin/sql/qa/single-node/src/test/java/org/elasticsearch/xpack/sql/qa/single_node/SqlProtocolIT.java new file mode 100644 index 0000000000000..ec0cbe3f2ce4a --- /dev/null +++ b/x-pack/plugin/sql/qa/single-node/src/test/java/org/elasticsearch/xpack/sql/qa/single_node/SqlProtocolIT.java @@ -0,0 +1,12 @@ +/* + * 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.sql.qa.single_node; + +import org.elasticsearch.xpack.sql.qa.SqlProtocolTestCase; + +public class SqlProtocolIT extends SqlProtocolTestCase { +} diff --git a/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/SqlProtocolTestCase.java b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/SqlProtocolTestCase.java new file mode 100644 index 0000000000000..51de82f97413b --- /dev/null +++ b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/SqlProtocolTestCase.java @@ -0,0 +1,193 @@ +/* + * 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.sql.qa; + +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.elasticsearch.client.Request; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.Response; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.common.xcontent.cbor.CborXContent; +import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.common.xcontent.smile.SmileXContent; +import org.elasticsearch.common.xcontent.yaml.YamlXContent; +import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.xpack.sql.proto.Mode; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import static org.elasticsearch.xpack.sql.proto.RequestInfo.CLIENT_IDS; +import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.mode; + +public abstract class SqlProtocolTestCase extends ESRestTestCase { + + public void testNulls() throws IOException { + assertQuery("SELECT NULL", "NULL", "null", null, 0); + } + + public void testBooleanType() throws IOException { + assertQuery("SELECT TRUE", "TRUE", "boolean", true, 1); + assertQuery("SELECT FALSE", "FALSE", "boolean", false, 1); + } + + public void testNumericTypes() throws IOException { + assertQuery("SELECT CAST(3 AS TINYINT)", "CAST(3 AS TINYINT)", "byte", 3, 5); + assertQuery("SELECT CAST(-123 AS TINYINT)", "CAST(-123 AS TINYINT)", "byte", -123, 5); + assertQuery("SELECT CAST(5 AS SMALLINT)", "CAST(5 AS SMALLINT)", "short", 5, 6); + assertQuery("SELECT CAST(-25 AS SMALLINT)", "CAST(-25 AS SMALLINT)", "short", -25, 6); + assertQuery("SELECT 123", "123", "integer", 123, 11); + assertQuery("SELECT -2123", "-2123", "integer", -2123, 11); + assertQuery("SELECT 1234567890123", "1234567890123", "long", 1234567890123L, 20); + assertQuery("SELECT -1234567890123", "-1234567890123", "long", -1234567890123L, 20); + assertQuery("SELECT 1234567890123.34", "1234567890123.34", "double", 1234567890123.34, 25); + assertQuery("SELECT -1234567890123.34", "-1234567890123.34", "double", -1234567890123.34, 25); + assertQuery("SELECT CAST(1234.34 AS REAL)", "CAST(1234.34 AS REAL)", "float", 1234.34f, 15); + assertQuery("SELECT CAST(-1234.34 AS REAL)", "CAST(-1234.34 AS REAL)", "float", -1234.34f, 15); + assertQuery("SELECT CAST(1234567890123.34 AS FLOAT)", "CAST(1234567890123.34 AS FLOAT)", "double", 1234567890123.34, 25); + assertQuery("SELECT CAST(-1234567890123.34 AS FLOAT)", "CAST(-1234567890123.34 AS FLOAT)", "double", -1234567890123.34, 25); + } + + public void testTextualType() throws IOException { + assertQuery("SELECT 'abc123'", "'abc123'", "keyword", "abc123", 0); + } + + public void testDateTimes() throws IOException { + assertQuery("SELECT CAST('2019-01-14T12:29:25.000Z' AS DATE)", "CAST('2019-01-14T12:29:25.000Z' AS DATE)", "date", + "2019-01-14T12:29:25.000Z", 24); + assertQuery("SELECT CAST(-26853765751000 AS DATE)", "CAST(-26853765751000 AS DATE)", "date", "1119-01-15T12:37:29.000Z", 24); + assertQuery("SELECT CAST(CAST('-26853765751000' AS BIGINT) AS DATE)", "CAST(CAST('-26853765751000' AS BIGINT) AS DATE)", "date", + "1119-01-15T12:37:29.000Z", 24); + } + + public void testIPs() throws IOException { + assertQuery("SELECT CAST('12.13.14.15' AS IP)", "CAST('12.13.14.15' AS IP)", "ip", "12.13.14.15", 0); + assertQuery("SELECT CAST('2001:0db8:0000:0000:0000:ff00:0042:8329' AS IP)", "CAST('2001:0db8:0000:0000:0000:ff00:0042:8329' AS IP)", + "ip", "2001:0db8:0000:0000:0000:ff00:0042:8329", 0); + } + + public void testDateTimeIntervals() throws IOException { + assertQuery("SELECT INTERVAL '326' YEAR", "INTERVAL '326' YEAR", "interval_year", "P326Y", 7); + assertQuery("SELECT INTERVAL '50' MONTH", "INTERVAL '50' MONTH", "interval_month", "P50M", 7); + assertQuery("SELECT INTERVAL '520' DAY", "INTERVAL '520' DAY", "interval_day", "PT12480H", 23); + assertQuery("SELECT INTERVAL '163' HOUR", "INTERVAL '163' HOUR", "interval_hour", "PT163H", 23); + assertQuery("SELECT INTERVAL '163' MINUTE", "INTERVAL '163' MINUTE", "interval_minute", "PT2H43M", 23); + assertQuery("SELECT INTERVAL '223.16' SECOND", "INTERVAL '223.16' SECOND", "interval_second", "PT3M43.016S", 23); + assertQuery("SELECT INTERVAL '163-11' YEAR TO MONTH", "INTERVAL '163-11' YEAR TO MONTH", "interval_year_to_month", "P163Y11M", 7); + assertQuery("SELECT INTERVAL '163 12' DAY TO HOUR", "INTERVAL '163 12' DAY TO HOUR", "interval_day_to_hour", "PT3924H", 23); + assertQuery("SELECT INTERVAL '163 12:39' DAY TO MINUTE", "INTERVAL '163 12:39' DAY TO MINUTE", "interval_day_to_minute", + "PT3924H39M", 23); + assertQuery("SELECT INTERVAL '163 12:39:59.163' DAY TO SECOND", "INTERVAL '163 12:39:59.163' DAY TO SECOND", + "interval_day_to_second", "PT3924H39M59.163S", 23); + assertQuery("SELECT INTERVAL -'163 23:39:56.23' DAY TO SECOND", "INTERVAL -'163 23:39:56.23' DAY TO SECOND", + "interval_day_to_second", "PT-3935H-39M-56.023S", 23); + assertQuery("SELECT INTERVAL '163:39' HOUR TO MINUTE", "INTERVAL '163:39' HOUR TO MINUTE", "interval_hour_to_minute", + "PT163H39M", 23); + assertQuery("SELECT INTERVAL '163:39:59.163' HOUR TO SECOND", "INTERVAL '163:39:59.163' HOUR TO SECOND", "interval_hour_to_second", + "PT163H39M59.163S", 23); + assertQuery("SELECT INTERVAL '163:59.163' MINUTE TO SECOND", "INTERVAL '163:59.163' MINUTE TO SECOND", "interval_minute_to_second", + "PT2H43M59.163S", 23); + } + + @SuppressWarnings({ "unchecked" }) + private void assertQuery(String sql, String columnName, String columnType, Object columnValue, int displaySize) throws IOException { + for (Mode mode : Mode.values()) { + Map response = runSql(mode.toString(), sql); + List columns = (ArrayList) response.get("columns"); + assertEquals(1, columns.size()); + + Map column = (HashMap) columns.get(0); + assertEquals(columnName, column.get("name")); + assertEquals(columnType, column.get("type")); + if (mode != Mode.PLAIN) { + assertEquals(3, column.size()); + assertEquals(displaySize, column.get("display_size")); + } else { + assertEquals(2, column.size()); + } + + List rows = (ArrayList) response.get("rows"); + assertEquals(1, rows.size()); + List row = (ArrayList) rows.get(0); + assertEquals(1, row.size()); + + // from xcontent we can get float or double, depending on the conversion + // method of the specific xcontent format implementation + if (columnValue instanceof Float && row.get(0) instanceof Double) { + assertEquals(columnValue, (float)((Number) row.get(0)).doubleValue()); + } else { + assertEquals(columnValue, row.get(0)); + } + } + } + + private Map runSql(String mode, String sql) throws IOException { + Request request = new Request("POST", "/_sql"); + String requestContent = "{\"query\":\"" + sql + "\"" + mode(mode) + "}"; + String format = randomFrom(XContentType.values()).name().toLowerCase(Locale.ROOT); + + // add a client_id to the request + if (randomBoolean()) { + String clientId = randomFrom(randomFrom(CLIENT_IDS), randomAlphaOfLengthBetween(10, 20)); + requestContent = new StringBuilder(requestContent) + .insert(requestContent.length() - 1, ",\"client_id\":\"" + clientId + "\"").toString(); + } + if (randomBoolean()) { + request.addParameter("error_trace", "true"); + } + if (randomBoolean()) { + request.addParameter("pretty", "true"); + } + if (!"json".equals(format) || randomBoolean()) { + // since we default to JSON if a format is not specified, randomize setting it or not, explicitly; + // for any other format, just set the format explicitly + request.addParameter("format", format); + } + if (randomBoolean()) { + // randomly use the Accept header for the response format + RequestOptions.Builder options = request.getOptions().toBuilder(); + options.addHeader("Accept", randomFrom("*/*", "application/" + format)); + request.setOptions(options); + } + + // send the query either as body or as request parameter + if (randomBoolean()) { + request.setEntity(new StringEntity(requestContent, ContentType.APPLICATION_JSON)); + } else { + request.setEntity(null); + request.addParameter("source", requestContent); + request.addParameter("source_content_type", ContentType.APPLICATION_JSON.getMimeType()); + RequestOptions.Builder options = request.getOptions().toBuilder(); + options.addHeader("Content-Type", "application/json"); + request.setOptions(options); + } + + Response response = client().performRequest(request); + try (InputStream content = response.getEntity().getContent()) { + switch(format) { + case "cbor": { + return XContentHelper.convertToMap(CborXContent.cborXContent, content, false); + } + case "yaml": { + return XContentHelper.convertToMap(YamlXContent.yamlXContent, content, false); + } + case "smile": { + return XContentHelper.convertToMap(SmileXContent.smileXContent, content, false); + } + default: + return XContentHelper.convertToMap(JsonXContent.jsonXContent, content, false); + } + } + } +} diff --git a/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/JdbcTestUtils.java b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/JdbcTestUtils.java index 9d1b68a92f46f..e91f9fc727238 100644 --- a/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/JdbcTestUtils.java +++ b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/JdbcTestUtils.java @@ -117,7 +117,7 @@ public static void logLikeCLI(ResultSet rs, Logger logger) throws SQLException { for (int i = 1; i <= columns; i++) { cols.add(new ColumnInfo(metaData.getTableName(i), metaData.getColumnName(i), metaData.getColumnTypeName(i), - metaData.getColumnType(i), metaData.getColumnDisplaySize(i))); + metaData.getColumnDisplaySize(i))); } diff --git a/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/rest/RestSqlTestCase.java b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/rest/RestSqlTestCase.java index 21faaf17c4ea1..331c02ffcb193 100644 --- a/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/rest/RestSqlTestCase.java +++ b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/rest/RestSqlTestCase.java @@ -57,7 +57,6 @@ public static Map columnInfo(String mode, String name, String ty column.put("name", name); column.put("type", type); if ("jdbc".equals(mode)) { - column.put("jdbc_type", jdbcType.getVendorTypeNumber()); column.put("display_size", size); } return unmodifiableMap(column); diff --git a/x-pack/plugin/sql/qa/src/main/resources/agg.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/agg.csv-spec index 3717afefab3bd..668316372c4bb 100644 --- a/x-pack/plugin/sql/qa/src/main/resources/agg.csv-spec +++ b/x-pack/plugin/sql/qa/src/main/resources/agg.csv-spec @@ -98,6 +98,14 @@ SELECT CAST(SUM(salary) AS DOUBLE) FROM test_emp; 4824855.0 ; +aggregateWithUpCastAsFloat +SELECT CAST(SUM(salary) AS FLOAT) FROM test_emp; + + CAST(SUM(salary) AS FLOAT) +----------------------------- +4824855.0 +; + aggregateWithCastNumericToString SELECT CAST(AVG(salary) AS VARCHAR) FROM test_emp; diff --git a/x-pack/plugin/sql/sql-action/src/main/java/org/elasticsearch/xpack/sql/action/SqlQueryResponse.java b/x-pack/plugin/sql/sql-action/src/main/java/org/elasticsearch/xpack/sql/action/SqlQueryResponse.java index 49c0758adbed0..7301e86befa02 100644 --- a/x-pack/plugin/sql/sql-action/src/main/java/org/elasticsearch/xpack/sql/action/SqlQueryResponse.java +++ b/x-pack/plugin/sql/sql-action/src/main/java/org/elasticsearch/xpack/sql/action/SqlQueryResponse.java @@ -183,29 +183,16 @@ public static ColumnInfo readColumnInfo(StreamInput in) throws IOException { String table = in.readString(); String name = in.readString(); String esType = in.readString(); - Integer jdbcType; - int displaySize; - if (in.readBoolean()) { - jdbcType = in.readVInt(); - displaySize = in.readVInt(); - } else { - jdbcType = null; - displaySize = 0; - } - return new ColumnInfo(table, name, esType, jdbcType, displaySize); + Integer displaySize = in.readOptionalVInt(); + + return new ColumnInfo(table, name, esType, displaySize); } public static void writeColumnInfo(StreamOutput out, ColumnInfo columnInfo) throws IOException { out.writeString(columnInfo.table()); out.writeString(columnInfo.name()); out.writeString(columnInfo.esType()); - if (columnInfo.jdbcType() != null) { - out.writeBoolean(true); - out.writeVInt(columnInfo.jdbcType()); - out.writeVInt(columnInfo.displaySize()); - } else { - out.writeBoolean(false); - } + out.writeOptionalVInt(columnInfo.displaySize()); } @Override diff --git a/x-pack/plugin/sql/sql-action/src/test/java/org/elasticsearch/xpack/sql/action/SqlQueryResponseTests.java b/x-pack/plugin/sql/sql-action/src/test/java/org/elasticsearch/xpack/sql/action/SqlQueryResponseTests.java index 7379e5d35bf89..26a3c8189c591 100644 --- a/x-pack/plugin/sql/sql-action/src/test/java/org/elasticsearch/xpack/sql/action/SqlQueryResponseTests.java +++ b/x-pack/plugin/sql/sql-action/src/test/java/org/elasticsearch/xpack/sql/action/SqlQueryResponseTests.java @@ -46,8 +46,7 @@ public static SqlQueryResponse createRandomInstance(String cursor, Mode mode) { if (randomBoolean()) { columns = new ArrayList<>(columnCount); for (int i = 0; i < columnCount; i++) { - columns.add(new ColumnInfo(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10), - randomInt(), randomInt(25))); + columns.add(new ColumnInfo(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10), randomInt(25))); } } @@ -96,7 +95,6 @@ public void testToXContent() throws IOException { assertEquals(columnInfo.name(), columnMap.get("name")); assertEquals(columnInfo.esType(), columnMap.get("type")); assertEquals(columnInfo.displaySize(), columnMap.get("display_size")); - assertEquals(columnInfo.jdbcType(), columnMap.get("jdbc_type")); } } else { assertNull(rootMap.get("columns")); diff --git a/x-pack/plugin/sql/sql-cli/src/test/java/org/elasticsearch/xpack/sql/cli/command/ServerQueryCliCommandTests.java b/x-pack/plugin/sql/sql-cli/src/test/java/org/elasticsearch/xpack/sql/cli/command/ServerQueryCliCommandTests.java index 015769f641bf6..498bbf7754c8d 100644 --- a/x-pack/plugin/sql/sql-cli/src/test/java/org/elasticsearch/xpack/sql/cli/command/ServerQueryCliCommandTests.java +++ b/x-pack/plugin/sql/sql-cli/src/test/java/org/elasticsearch/xpack/sql/cli/command/ServerQueryCliCommandTests.java @@ -12,7 +12,6 @@ import org.elasticsearch.xpack.sql.proto.SqlQueryResponse; import java.sql.SQLException; -import java.sql.Types; import java.util.Collections; import java.util.List; @@ -109,7 +108,7 @@ private SqlQueryResponse fakeResponse(String cursor, boolean includeColumns, Str List> rows; List columns; if (includeColumns) { - columns = singletonList(new ColumnInfo("", "field", "string", Types.VARCHAR, 0)); + columns = singletonList(new ColumnInfo("", "field", "string", 0)); } else { columns = null; } diff --git a/x-pack/plugin/sql/sql-proto/src/main/java/org/elasticsearch/xpack/sql/proto/ColumnInfo.java b/x-pack/plugin/sql/sql-proto/src/main/java/org/elasticsearch/xpack/sql/proto/ColumnInfo.java index 64ff8b4b96332..ef4e603564ef6 100644 --- a/x-pack/plugin/sql/sql-proto/src/main/java/org/elasticsearch/xpack/sql/proto/ColumnInfo.java +++ b/x-pack/plugin/sql/sql-proto/src/main/java/org/elasticsearch/xpack/sql/proto/ColumnInfo.java @@ -5,7 +5,6 @@ */ package org.elasticsearch.xpack.sql.proto; -import org.elasticsearch.common.Nullable; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.ToXContentObject; @@ -21,7 +20,7 @@ /** * Information about a column returned with first query response. * As this represents the response for all drivers, it is important for it to be explicit about - * its structure, in particular types (using es_type and jdbc_type instead of DataType). + * its structure, in particular types (using es_type instead of DataType). */ public class ColumnInfo implements ToXContentObject { @@ -31,35 +30,29 @@ public class ColumnInfo implements ToXContentObject { objects[0] == null ? "" : (String) objects[0], (String) objects[1], (String) objects[2], - objects[3] == null ? null : (int) objects[3], - objects[4] == null ? 0 : (int) objects[4])); + (Integer) objects[3])); private static final ParseField TABLE = new ParseField("table"); private static final ParseField NAME = new ParseField("name"); private static final ParseField ES_TYPE = new ParseField("type"); - private static final ParseField JDBC_TYPE = new ParseField("jdbc_type"); private static final ParseField DISPLAY_SIZE = new ParseField("display_size"); static { PARSER.declareString(optionalConstructorArg(), TABLE); PARSER.declareString(constructorArg(), NAME); PARSER.declareString(constructorArg(), ES_TYPE); - PARSER.declareInt(optionalConstructorArg(), JDBC_TYPE); PARSER.declareInt(optionalConstructorArg(), DISPLAY_SIZE); } private final String table; private final String name; private final String esType; - @Nullable - private final Integer jdbcType; - private final int displaySize; + private final Integer displaySize; - public ColumnInfo(String table, String name, String esType, Integer jdbcType, int displaySize) { + public ColumnInfo(String table, String name, String esType, Integer displaySize) { this.table = table; this.name = name; this.esType = esType; - this.jdbcType = jdbcType; this.displaySize = displaySize; } @@ -67,8 +60,7 @@ public ColumnInfo(String table, String name, String esType) { this.table = table; this.name = name; this.esType = esType; - this.jdbcType = null; - this.displaySize = 0; + this.displaySize = null; } @Override @@ -79,8 +71,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws } builder.field("name", name); builder.field("type", esType); - if (jdbcType != null) { - builder.field("jdbc_type", jdbcType); + if (displaySize != null) { builder.field("display_size", displaySize); } return builder.endObject(); @@ -112,13 +103,6 @@ public String esType() { return esType; } - /** - * The type of the column as it would be returned by a JDBC driver. - */ - public Integer jdbcType() { - return jdbcType; - } - /** * Used by JDBC */ @@ -138,14 +122,12 @@ public boolean equals(Object o) { return displaySize == that.displaySize && Objects.equals(table, that.table) && Objects.equals(name, that.name) && - Objects.equals(esType, that.esType) && - Objects.equals(jdbcType, that.jdbcType); + Objects.equals(esType, that.esType); } @Override public int hashCode() { - - return Objects.hash(table, name, esType, jdbcType, displaySize); + return Objects.hash(table, name, esType, displaySize); } @Override diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plugin/TransportSqlQueryAction.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plugin/TransportSqlQueryAction.java index 738cd77af1ea4..c0c1f67c05901 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plugin/TransportSqlQueryAction.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plugin/TransportSqlQueryAction.java @@ -100,8 +100,7 @@ static SqlQueryResponse createResponse(SqlQueryRequest request, SchemaRowSet row List columns = new ArrayList<>(rowSet.columnCount()); for (Schema.Entry entry : rowSet.schema()) { if (Mode.isDriver(request.mode())) { - columns.add(new ColumnInfo("", entry.name(), entry.type().esType, entry.type().sqlType.getVendorTypeNumber(), - entry.type().displaySize)); + columns.add(new ColumnInfo("", entry.name(), entry.type().esType, entry.type().displaySize)); } else { columns.add(new ColumnInfo("", entry.name(), entry.type().esType)); } diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/action/CliFormatterTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/action/CliFormatterTests.java index ad4f1c998bbc8..e1b551d2aeddb 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/action/CliFormatterTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/action/CliFormatterTests.java @@ -9,7 +9,6 @@ import org.elasticsearch.xpack.sql.proto.ColumnInfo; import org.elasticsearch.xpack.sql.proto.Mode; -import java.sql.Types; import java.util.Arrays; import static org.hamcrest.Matchers.arrayWithSize; @@ -17,11 +16,11 @@ public class CliFormatterTests extends ESTestCase { private final SqlQueryResponse firstResponse = new SqlQueryResponse("", Mode.PLAIN, Arrays.asList( - new ColumnInfo("", "foo", "string", Types.VARCHAR, 0), - new ColumnInfo("", "bar", "long", Types.BIGINT, 15), - new ColumnInfo("", "15charwidename!", "double", Types.DOUBLE, 25), - new ColumnInfo("", "superduperwidename!!!", "double", Types.DOUBLE, 25), - new ColumnInfo("", "baz", "keyword", Types.VARCHAR, 0)), + new ColumnInfo("", "foo", "string", 0), + new ColumnInfo("", "bar", "long", 15), + new ColumnInfo("", "15charwidename!", "double", 25), + new ColumnInfo("", "superduperwidename!!!", "double", 25), + new ColumnInfo("", "baz", "keyword", 0)), Arrays.asList( Arrays.asList("15charwidedata!", 1, 6.888, 12, "rabbit"), Arrays.asList("dog", 1.7976931348623157E308, 123124.888, 9912, "goat"))); diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/action/SqlActionIT.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/action/SqlActionIT.java index 43ea7fe92ebee..60047fcdbe799 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/action/SqlActionIT.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/action/SqlActionIT.java @@ -10,8 +10,6 @@ import org.elasticsearch.xpack.sql.proto.ColumnInfo; import org.elasticsearch.xpack.sql.proto.Mode; -import java.sql.Types; - import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; @@ -35,8 +33,8 @@ public void testSqlAction() { assertThat(response.columns(), hasSize(2)); int dataIndex = dataBeforeCount ? 0 : 1; int countIndex = dataBeforeCount ? 1 : 0; - assertEquals(new ColumnInfo("", "data", "text", Types.VARCHAR, 0), response.columns().get(dataIndex)); - assertEquals(new ColumnInfo("", "count", "long", Types.BIGINT, 20), response.columns().get(countIndex)); + assertEquals(new ColumnInfo("", "data", "text", 0), response.columns().get(dataIndex)); + assertEquals(new ColumnInfo("", "count", "long", 20), response.columns().get(countIndex)); assertThat(response.rows(), hasSize(2)); assertEquals("bar", response.rows().get(0).get(dataIndex)); diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/CursorTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/CursorTests.java index 83545ebdde6e9..f3e27d852b3fe 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/CursorTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/CursorTests.java @@ -66,8 +66,7 @@ private static SqlQueryResponse createRandomSqlResponse() { if (randomBoolean()) { columns = new ArrayList<>(columnCount); for (int i = 0; i < columnCount; i++) { - columns.add(new ColumnInfo(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10), - randomInt(), randomInt(25))); + columns.add(new ColumnInfo(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10), randomInt(25))); } } return new SqlQueryResponse("", randomFrom(Mode.values()), columns, Collections.emptyList()); From 0160ba2539d3b2335e8bc825972128403a449f9c Mon Sep 17 00:00:00 2001 From: Nhat Nguyen Date: Wed, 16 Jan 2019 09:18:52 -0500 Subject: [PATCH 13/16] AwaitsFix testAddNewReplicas Tracked at #37183 --- .../index/replication/RecoveryDuringReplicationTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/test/java/org/elasticsearch/index/replication/RecoveryDuringReplicationTests.java b/server/src/test/java/org/elasticsearch/index/replication/RecoveryDuringReplicationTests.java index d7f8a73c225ef..80107e6f1e83b 100644 --- a/server/src/test/java/org/elasticsearch/index/replication/RecoveryDuringReplicationTests.java +++ b/server/src/test/java/org/elasticsearch/index/replication/RecoveryDuringReplicationTests.java @@ -691,6 +691,7 @@ public void testTransferMaxSeenAutoIdTimestampOnResync() throws Exception { } } + @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/37183") public void testAddNewReplicas() throws Exception { try (ReplicationGroup shards = createGroup(between(0, 1))) { shards.startAll(); From 86697f23a309f1648ccc257bf438f51a95d8622d Mon Sep 17 00:00:00 2001 From: Michael Basnight Date: Wed, 16 Jan 2019 08:50:03 -0600 Subject: [PATCH 14/16] Update Put Watch to allow unknown fields (#37494) PutWatchResponse did not allow unknown fields. This commit fixes the test and ConstructingObjectParser such that it does now allow unknown fields. Relates #36938 --- .../client/watcher/PutWatchResponse.java | 15 +------ .../client/watcher/PutWatchResponseTests.java | 39 ++++++++++++------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/PutWatchResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/PutWatchResponse.java index 5c8d7bde9b158..8f7070b2565a2 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/PutWatchResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/PutWatchResponse.java @@ -20,17 +20,15 @@ import org.elasticsearch.common.ParseField; import org.elasticsearch.common.xcontent.ObjectParser; -import org.elasticsearch.common.xcontent.ToXContentObject; -import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; import java.util.Objects; -public class PutWatchResponse implements ToXContentObject { +public class PutWatchResponse { private static final ObjectParser PARSER - = new ObjectParser<>("x_pack_put_watch_response", PutWatchResponse::new); + = new ObjectParser<>("x_pack_put_watch_response", true, PutWatchResponse::new); static { PARSER.declareString(PutWatchResponse::setId, new ParseField("_id")); @@ -90,15 +88,6 @@ public int hashCode() { return Objects.hash(id, version, created); } - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return builder.startObject() - .field("_id", id) - .field("_version", version) - .field("created", created) - .endObject(); - } - public static PutWatchResponse fromXContent(XContentParser parser) throws IOException { return PARSER.parse(parser, null); } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/PutWatchResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/PutWatchResponseTests.java index e82ccd11cb2cb..af327abc1a728 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/PutWatchResponseTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/PutWatchResponseTests.java @@ -18,28 +18,37 @@ */ package org.elasticsearch.client.watcher; -import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.test.AbstractXContentTestCase; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.test.ESTestCase; import java.io.IOException; -public class PutWatchResponseTests extends AbstractXContentTestCase { +import static org.elasticsearch.test.AbstractXContentTestCase.xContentTester; - @Override - protected PutWatchResponse createTestInstance() { - String id = randomAlphaOfLength(10); - long version = randomLongBetween(1, 10); - boolean created = randomBoolean(); - return new PutWatchResponse(id, version, created); +public class PutWatchResponseTests extends ESTestCase { + + public void testFromXContent() throws IOException { + xContentTester(this::createParser, + PutWatchResponseTests::createTestInstance, + PutWatchResponseTests::toXContent, + PutWatchResponse::fromXContent) + .supportsUnknownFields(true) + .assertToXContentEquivalence(false) + .test(); } - @Override - protected PutWatchResponse doParseInstance(XContentParser parser) throws IOException { - return PutWatchResponse.fromXContent(parser); + private static XContentBuilder toXContent(PutWatchResponse response, XContentBuilder builder) throws IOException { + return builder.startObject() + .field("_id", response.getId()) + .field("_version", response.getVersion()) + .field("created", response.isCreated()) + .endObject(); } - @Override - protected boolean supportsUnknownFields() { - return false; + private static PutWatchResponse createTestInstance() { + String id = randomAlphaOfLength(10); + long version = randomLongBetween(1, 10); + boolean created = randomBoolean(); + return new PutWatchResponse(id, version, created); } } From 0b5af276a8b3d4cf3e94ff6ba4264d1bd1f0334c Mon Sep 17 00:00:00 2001 From: Tim Brooks Date: Wed, 16 Jan 2019 07:52:38 -0700 Subject: [PATCH 15/16] Allow system privilege to execute proxied actions (#37508) Currently all proxied actions are denied for the `SystemPrivilege`. Unfortunately, there are use cases (CCR) where we would like to proxy actions to a remote node that are normally performed by the system context. This commit allows the system context to perform proxy actions if they are actions that the system context is normally allowed to execute. --- .../transport/TransportActionProxy.java | 8 +++++ .../authz/privilege/SystemPrivilege.java | 35 ++++++++++++------- .../authz/privilege/PrivilegeTests.java | 1 + 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/transport/TransportActionProxy.java b/server/src/main/java/org/elasticsearch/transport/TransportActionProxy.java index a5b926249f8e2..e1e3c25f083cf 100644 --- a/server/src/main/java/org/elasticsearch/transport/TransportActionProxy.java +++ b/server/src/main/java/org/elasticsearch/transport/TransportActionProxy.java @@ -175,6 +175,14 @@ public static TransportRequest unwrapRequest(TransportRequest request) { return request; } + /** + * Unwraps a proxy action and returns the underlying action + */ + public static String unwrapAction(String action) { + assert isProxyAction(action) : "Attempted to unwrap non-proxy action: " + action; + return action.substring(PROXY_ACTION_PREFIX.length()); + } + /** * Returns true iff the given action is a proxy action */ diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/SystemPrivilege.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/SystemPrivilege.java index c673b8ee3276c..ca8318212c9ee 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/SystemPrivilege.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/SystemPrivilege.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.xpack.core.security.authz.privilege; +import org.elasticsearch.transport.TransportActionProxy; import org.elasticsearch.xpack.core.security.support.Automatons; import java.util.Collections; @@ -14,19 +15,27 @@ public final class SystemPrivilege extends Privilege { public static SystemPrivilege INSTANCE = new SystemPrivilege(); - private static final Predicate PREDICATE = Automatons.predicate(Automatons. - minusAndMinimize(Automatons.patterns( - "internal:*", - "indices:monitor/*", // added for monitoring - "cluster:monitor/*", // added for monitoring - "cluster:admin/bootstrap/*", // for the bootstrap service - "cluster:admin/reroute", // added for DiskThresholdDecider.DiskListener - "indices:admin/mapping/put", // needed for recovery and shrink api - "indices:admin/template/put", // needed for the TemplateUpgradeService - "indices:admin/template/delete", // needed for the TemplateUpgradeService - "indices:admin/seq_no/global_checkpoint_sync*", // needed for global checkpoint syncs - "indices:admin/settings/update" // needed for DiskThresholdMonitor.markIndicesReadOnly - ), Automatons.patterns("internal:transport/proxy/*"))); // no proxy actions for system user! + private static final Predicate ALLOWED_ACTIONS = Automatons.predicate( + "internal:*", + "indices:monitor/*", // added for monitoring + "cluster:monitor/*", // added for monitoring + "cluster:admin/bootstrap/*", // for the bootstrap service + "cluster:admin/reroute", // added for DiskThresholdDecider.DiskListener + "indices:admin/mapping/put", // needed for recovery and shrink api + "indices:admin/template/put", // needed for the TemplateUpgradeService + "indices:admin/template/delete", // needed for the TemplateUpgradeService + "indices:admin/seq_no/global_checkpoint_sync*", // needed for global checkpoint syncs + "indices:admin/settings/update" // needed for DiskThresholdMonitor.markIndicesReadOnly + ); + + private static final Predicate PREDICATE = (action) -> { + // Only allow a proxy action if the underlying action is allowed + if (TransportActionProxy.isProxyAction(action)) { + return ALLOWED_ACTIONS.test(TransportActionProxy.unwrapAction(action)); + } else { + return ALLOWED_ACTIONS.test(action); + } + }; private SystemPrivilege() { super(Collections.singleton("internal")); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java index 58432cdf6c79e..1484e7a878141 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java @@ -123,6 +123,7 @@ public void testSystem() throws Exception { assertThat(predicate.test("indices:admin/mapping/put"), is(true)); assertThat(predicate.test("indices:admin/mapping/whatever"), is(false)); assertThat(predicate.test("internal:transport/proxy/indices:data/read/query"), is(false)); + assertThat(predicate.test("internal:transport/proxy/indices:monitor/whatever"), is(true)); assertThat(predicate.test("indices:admin/seq_no/global_checkpoint_sync"), is(true)); assertThat(predicate.test("indices:admin/seq_no/global_checkpoint_sync[p]"), is(true)); assertThat(predicate.test("indices:admin/seq_no/global_checkpoint_sync[r]"), is(true)); From 3d8c04659c8ea849d2621cd1b8edb29882d1eed2 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 16 Jan 2019 07:05:09 -0800 Subject: [PATCH 16/16] Deprecate _type from LeafDocLookup (#37491) * Deprecate _type from LeafDocLookup * Response to PR comments. * Response to PR comments. --- .../elasticsearch/search/lookup/LeafDocLookup.java | 12 ++++++++++++ .../search/lookup/LeafDocLookupTests.java | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/server/src/main/java/org/elasticsearch/search/lookup/LeafDocLookup.java b/server/src/main/java/org/elasticsearch/search/lookup/LeafDocLookup.java index 4beb2507d7f25..17518b2f1f60f 100644 --- a/server/src/main/java/org/elasticsearch/search/lookup/LeafDocLookup.java +++ b/server/src/main/java/org/elasticsearch/search/lookup/LeafDocLookup.java @@ -18,9 +18,11 @@ */ package org.elasticsearch.search.lookup; +import org.apache.logging.log4j.LogManager; import org.apache.lucene.index.LeafReaderContext; import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.fielddata.ScriptDocValues; import org.elasticsearch.index.mapper.MappedFieldType; @@ -38,6 +40,12 @@ public class LeafDocLookup implements Map> { + private static final DeprecationLogger DEPRECATION_LOGGER + = new DeprecationLogger(LogManager.getLogger(LeafDocLookup.class)); + static final String TYPES_DEPRECATION_KEY = "type-field-doc-lookup"; + static final String TYPES_DEPRECATION_MESSAGE = + "[types removal] Looking up doc types in scripts is deprecated."; + private final Map> localCacheFieldData = new HashMap<>(4); private final MapperService mapperService; @@ -72,6 +80,10 @@ public void setDocument(int docId) { @Override public ScriptDocValues get(Object key) { + // deprecate _type + if ("_type".equals(key)) { + DEPRECATION_LOGGER.deprecatedAndMaybeLog(TYPES_DEPRECATION_KEY, TYPES_DEPRECATION_MESSAGE); + } // assume its a string... String fieldName = key.toString(); ScriptDocValues scriptValues = localCacheFieldData.get(fieldName); diff --git a/server/src/test/java/org/elasticsearch/search/lookup/LeafDocLookupTests.java b/server/src/test/java/org/elasticsearch/search/lookup/LeafDocLookupTests.java index dfdbef1c3d539..fca61bf2564b9 100644 --- a/server/src/test/java/org/elasticsearch/search/lookup/LeafDocLookupTests.java +++ b/server/src/test/java/org/elasticsearch/search/lookup/LeafDocLookupTests.java @@ -26,6 +26,7 @@ import org.elasticsearch.test.ESTestCase; import org.junit.Before; +import static org.elasticsearch.search.lookup.LeafDocLookup.TYPES_DEPRECATION_MESSAGE; import static org.mockito.AdditionalAnswers.returnsFirstArg; import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.doReturn; @@ -45,6 +46,7 @@ public void setUp() throws Exception { when(fieldType.valueForDisplay(anyObject())).then(returnsFirstArg()); MapperService mapperService = mock(MapperService.class); + when(mapperService.fullName("_type")).thenReturn(fieldType); when(mapperService.fullName("field")).thenReturn(fieldType); when(mapperService.fullName("alias")).thenReturn(fieldType); @@ -72,4 +74,10 @@ public void testLookupWithFieldAlias() { ScriptDocValues fetchedDocValues = docLookup.get("alias"); assertEquals(docValues, fetchedDocValues); } + + public void testTypesDeprecation() { + ScriptDocValues fetchedDocValues = docLookup.get("_type"); + assertEquals(docValues, fetchedDocValues); + assertWarnings(TYPES_DEPRECATION_MESSAGE); + } }