Merge branch 'master' into deprecate

Original commit: elastic/x-pack-elasticsearch@c9636bd3f1
This commit is contained in:
Jack Conradson 2016-09-01 14:53:42 -07:00
commit 670a57274a
43 changed files with 445 additions and 175 deletions

View File

@ -14,4 +14,5 @@ subprojects {
approvedLicenses = ['Elasticsearch Confidential']
additionalLicense 'ESCON', 'Elasticsearch Confidential', 'ELASTICSEARCH CONFIDENTIAL'
}
ext.projectSubstitutions += [ "org.elasticsearch.plugin:x-pack-client:${version}": ':x-plugins:elasticsearch:x-pack' ]
}

View File

@ -2,6 +2,7 @@ apply plugin: 'elasticsearch.rest-test'
dependencies {
testCompile project(path: ':x-plugins:elasticsearch:x-pack', configuration: 'runtime')
testCompile project(path: ':x-plugins:elasticsearch:x-pack-transport', configuration: 'runtime')
}
String outputDir = "generated-resources/${project.name}"

View File

@ -14,7 +14,7 @@ import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.ESIntegTestCase;
@ -118,6 +118,8 @@ public class SecurityTransportClientIT extends ESIntegTestCase {
.put("cluster.name", clusterName)
.build();
return new XPackTransportClient(settings).addTransportAddress(publishAddress);
TransportClient client = new PreBuiltXPackTransportClient(settings);
client.addTransportAddress(publishAddress);
return client;
}
}

View File

@ -5,8 +5,10 @@ apply plugin: 'elasticsearch.build'
dependencies {
provided "org.elasticsearch:elasticsearch:${versions.elasticsearch}"
testCompile "org.elasticsearch.test:framework:${project.versions.elasticsearch}"
provided project(path: ':x-plugins:elasticsearch:x-pack', configuration: 'runtime')
testCompile "org.elasticsearch.test:framework:${project.versions.elasticsearch}"
testCompile project(path: ':x-plugins:elasticsearch:x-pack-transport', configuration: 'runtime')
}
Map generateSubstitutions() {

View File

@ -21,7 +21,7 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
import java.util.Collection;
import java.util.Collections;
@ -80,7 +80,7 @@ public class CustomRealmIT extends ESIntegTestCase {
.put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER)
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.build();
try (TransportClient client = new XPackTransportClient(settings)) {
try (TransportClient client = new PreBuiltXPackTransportClient(settings)) {
client.addTransportAddress(publishAddress);
ClusterHealthResponse response = client.admin().cluster().prepareHealth().execute().actionGet();
assertThat(response.isTimedOut(), is(false));
@ -100,7 +100,7 @@ public class CustomRealmIT extends ESIntegTestCase {
.put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER + randomAsciiOfLength(1))
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.build();
try (TransportClient client = new XPackTransportClient(settings)) {
try (TransportClient client = new PreBuiltXPackTransportClient(settings)) {
client.addTransportAddress(publishAddress);
client.admin().cluster().prepareHealth().execute().actionGet();
fail("authentication failure should have resulted in a NoNodesAvailableException");

View File

@ -2,6 +2,7 @@ apply plugin: 'elasticsearch.rest-test'
dependencies {
testCompile project(path: ':x-plugins:elasticsearch:x-pack', configuration: 'runtime')
testCompile project(path: ':x-plugins:elasticsearch:x-pack-transport', configuration: 'runtime')
}
integTest {

View File

@ -15,7 +15,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
@ -77,12 +77,10 @@ public abstract class MigrateToolTestCase extends LuceneTestCase {
.put(Security.USER_SETTING.getKey(), "transport_user:changeme")
.build();
TransportClient client = new XPackTransportClient(clientSettings).addTransportAddresses(transportAddresses);
logger.info("--> Elasticsearch Java TransportClient started");
TransportClient client = new PreBuiltXPackTransportClient(clientSettings).addTransportAddresses(transportAddresses);
Exception clientException = null;
try {
logger.info("--> Elasticsearch Java TransportClient started");
ClusterHealthResponse health = client.admin().cluster().prepareHealth().get();
logger.info("--> connected to [{}] cluster which is running [{}] node(s).",
health.getClusterName(), health.getNumberOfNodes());

View File

@ -0,0 +1,30 @@
import org.elasticsearch.gradle.precommit.PrecommitTasks
apply plugin: 'elasticsearch.build'
apply plugin: 'nebula.maven-base-publish'
apply plugin: 'nebula.maven-scm'
group = 'org.elasticsearch.client'
dependencies {
compile "org.elasticsearch.plugin:x-pack-client:${version}"
compile "org.elasticsearch.client:transport:${version}"
testCompile "com.carrotsearch.randomizedtesting:randomizedtesting-runner:${versions.randomizedrunner}"
testCompile "junit:junit:${versions.junit}"
testCompile "org.hamcrest:hamcrest-all:${versions.hamcrest}"
}
dependencyLicenses.enabled = false
forbiddenApisTest {
// we don't use the core test-framework, no lucene classes present so we don't want the es-test-signatures to
// be pulled in
signaturesURLs = [PrecommitTasks.getResource('/forbidden/jdk-signatures.txt'),
PrecommitTasks.getResource('/forbidden/es-all-signatures.txt')]
}
namingConventions {
testClass = 'com.carrotsearch.randomizedtesting.RandomizedTest'
//we don't have integration tests
skipIntegTestInDisguise = true
}

View File

@ -0,0 +1,57 @@
/*
* 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.client;
import io.netty.util.ThreadDeathWatcher;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.security.Security;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
/**
* A builder to create an instance of {@link TransportClient} that pre-installs
* all of the plugins installed by the {@link PreBuiltTransportClient} and the
* {@link XPackPlugin} so that the client may be used with an x-pack enabled
* cluster.
*/
@SuppressWarnings({"unchecked","varargs"})
public class PreBuiltXPackTransportClient extends PreBuiltTransportClient {
@SafeVarargs
public PreBuiltXPackTransportClient(Settings settings, Class<? extends Plugin>... plugins) {
this(settings, Arrays.asList(plugins));
}
public PreBuiltXPackTransportClient(Settings settings, Collection<Class<? extends Plugin>> plugins) {
super(settings, addPlugins(plugins, Collections.singletonList(XPackPlugin.class)));
}
@Override
public void close() {
super.close();
if (NetworkModule.TRANSPORT_TYPE_SETTING.get(settings).equals(Security.NAME4)) {
try {
GlobalEventExecutor.INSTANCE.awaitInactivity(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
try {
ThreadDeathWatcher.awaitInactivity(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.client;
import com.carrotsearch.randomizedtesting.RandomizedTest;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.security.Security;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for the {@link PreBuiltXPackTransportClient}
*/
public class PreBuiltXPackTransportClientTests extends RandomizedTest {
@Test
public void testPluginInstalled() {
try (TransportClient client = new PreBuiltXPackTransportClient(Settings.EMPTY)) {
Settings settings = client.settings();
assertEquals(Security.NAME4, NetworkModule.TRANSPORT_TYPE_SETTING.get(settings));
}
}
}

View File

@ -7,13 +7,17 @@ package org.elasticsearch.xpack.monitoring.collector.cluster;
import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
import org.elasticsearch.license.License;
import org.elasticsearch.xpack.XPackFeatureSet;
import org.elasticsearch.xpack.monitoring.exporter.MonitoringDoc;
import java.util.List;
public class ClusterInfoMonitoringDoc extends MonitoringDoc {
private String clusterName;
private String version;
private License license;
private List<XPackFeatureSet.Usage> usage;
private ClusterStatsResponse clusterStats;
public ClusterInfoMonitoringDoc(String monitoringId, String monitoringVersion) {
@ -44,6 +48,14 @@ public class ClusterInfoMonitoringDoc extends MonitoringDoc {
this.license = license;
}
public List<XPackFeatureSet.Usage> getUsage() {
return usage;
}
public void setUsage(List<XPackFeatureSet.Usage> usage) {
this.usage = usage;
}
public ClusterStatsResponse getClusterStats() {
return clusterStats;
}

View File

@ -13,10 +13,13 @@ import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.LicenseService;
import org.elasticsearch.license.LicenseUtils;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.xpack.XPackFeatureSet;
import org.elasticsearch.xpack.action.XPackUsageRequestBuilder;
import org.elasticsearch.xpack.monitoring.MonitoringSettings;
import org.elasticsearch.xpack.monitoring.collector.AbstractCollector;
import org.elasticsearch.xpack.monitoring.exporter.MonitoringDoc;
@ -60,25 +63,17 @@ public class ClusterStatsCollector extends AbstractCollector {
@Override
protected Collection<MonitoringDoc> doCollect() throws Exception {
List<MonitoringDoc> results = new ArrayList<>(1);
final Supplier<ClusterStatsResponse> clusterStatsSupplier =
() -> client.admin().cluster().prepareClusterStats().get(monitoringSettings.clusterStatsTimeout());
final Supplier<List<XPackFeatureSet.Usage>> usageSupplier = () -> new XPackUsageRequestBuilder(client).get().getUsages();
// Retrieves cluster stats
ClusterStatsResponse clusterStats = null;
try {
clusterStats = client.admin().cluster().prepareClusterStats().get(monitoringSettings.clusterStatsTimeout());
} catch (ElasticsearchSecurityException e) {
if (LicenseUtils.isLicenseExpiredException(e)) {
logger.trace(
(Supplier<?>) () -> new ParameterizedMessage(
"collector [{}] - unable to collect data because of expired license", name()), e);
} else {
throw e;
}
}
final ClusterStatsResponse clusterStats = clusterStatsSupplier.get();
long timestamp = System.currentTimeMillis();
String clusterUUID = clusterUUID();
DiscoveryNode sourceNode = localNode();
final long timestamp = System.currentTimeMillis();
final String clusterUUID = clusterUUID();
final DiscoveryNode sourceNode = localNode();
final List<MonitoringDoc> results = new ArrayList<>(1);
// Adds a cluster info document
ClusterInfoMonitoringDoc clusterInfoDoc = new ClusterInfoMonitoringDoc(monitoringId(), monitoringVersion());
@ -89,6 +84,7 @@ public class ClusterStatsCollector extends AbstractCollector {
clusterInfoDoc.setVersion(Version.CURRENT.toString());
clusterInfoDoc.setLicense(licenseService.getLicense());
clusterInfoDoc.setClusterStats(clusterStats);
clusterInfoDoc.setUsage(collect(usageSupplier));
results.add(clusterInfoDoc);
// Adds a cluster stats document
@ -103,4 +99,21 @@ public class ClusterStatsCollector extends AbstractCollector {
return Collections.unmodifiableCollection(results);
}
@Nullable
private <T> T collect(final Supplier<T> supplier) {
try {
return supplier.get();
} catch (ElasticsearchSecurityException e) {
if (LicenseUtils.isLicenseExpiredException(e)) {
logger.trace((Supplier<?>) () -> new ParameterizedMessage(
"collector [{}] - unable to collect data because of expired license", name()), e);
} else {
throw e;
}
}
return null;
}
}

View File

@ -11,11 +11,13 @@ import org.elasticsearch.common.hash.MessageDigests;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.license.License;
import org.elasticsearch.xpack.XPackFeatureSet;
import org.elasticsearch.xpack.monitoring.collector.cluster.ClusterInfoMonitoringDoc;
import org.elasticsearch.xpack.monitoring.resolver.MonitoringIndexNameResolver;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
public class ClusterInfoResolver extends MonitoringIndexNameResolver.Data<ClusterInfoMonitoringDoc> {
@ -34,27 +36,38 @@ public class ClusterInfoResolver extends MonitoringIndexNameResolver.Data<Cluste
@Override
protected void buildXContent(ClusterInfoMonitoringDoc document, XContentBuilder builder, ToXContent.Params params) throws IOException {
builder.field(Fields.CLUSTER_NAME, document.getClusterName());
builder.field(Fields.VERSION, document.getVersion());
builder.field("cluster_name", document.getClusterName());
builder.field("version", document.getVersion());
License license = document.getLicense();
final License license = document.getLicense();
if (license != null) {
builder.startObject(Fields.LICENSE);
builder.startObject("license");
Map<String, String> extraParams = new MapBuilder<String, String>()
.put(License.REST_VIEW_MODE, "true")
.map();
params = new ToXContent.DelegatingMapParams(extraParams, params);
license.toInnerXContent(builder, params);
builder.field(Fields.HKEY, hash(license, document.getClusterUUID()));
builder.field("hkey", hash(license, document.getClusterUUID()));
builder.endObject();
}
builder.startObject(Fields.CLUSTER_STATS);
ClusterStatsResponse clusterStats = document.getClusterStats();
final ClusterStatsResponse clusterStats = document.getClusterStats();
if (clusterStats != null) {
builder.startObject("cluster_stats");
clusterStats.toXContent(builder, params);
builder.endObject();
}
final List<XPackFeatureSet.Usage> usages = document.getUsage();
if (usages != null) {
// in the future we may choose to add other usages under the stack_stats section, but it is only xpack for now
// it may also be combined on the UI side of phone-home to add things like "kibana" and "logstash" under "stack_stats"
builder.startObject("stack_stats").startObject("xpack");
for (final XPackFeatureSet.Usage usage : usages) {
builder.field(usage.name(), usage);
}
builder.endObject().endObject();
}
builder.endObject();
}
public static String hash(License license, String clusterName) {
@ -66,15 +79,4 @@ public class ClusterInfoResolver extends MonitoringIndexNameResolver.Data<Cluste
return MessageDigests.toHexString(MessageDigests.sha256().digest(toHash.getBytes(StandardCharsets.UTF_8)));
}
static final class Fields {
static final String CLUSTER_NAME = "cluster_name";
static final String LICENSE = "license";
static final String VERSION = "version";
static final String CLUSTER_STATS = "cluster_stats";
static final String HKEY = "hkey";
static final String UID = "uid";
static final String TYPE = "type";
}
}

View File

@ -98,7 +98,16 @@ public class NodeStatsResolver extends MonitoringIndexNameResolver.Timestamped<N
"node_stats.thread_pool.search.rejected",
"node_stats.thread_pool.watcher.threads",
"node_stats.thread_pool.watcher.queue",
"node_stats.thread_pool.watcher.rejected");
"node_stats.thread_pool.watcher.rejected",
// Linux Only (at least for now)
// Disk Info
"node_stats.fs.data.spins",
// Node IO Stats
"node_stats.fs.io_stats.operations",
"node_stats.fs.io_stats.read_operations",
"node_stats.fs.io_stats.write_operations",
"node_stats.fs.io_stats.read_kilobytes",
"node_stats.fs.io_stats.write_kilobytes");
FILTERS = Collections.unmodifiableSet(filters);
}

View File

@ -556,7 +556,34 @@
}
},
"fs": {
"type": "object"
"properties": {
"data": {
"properties": {
"spins": {
"type": "boolean"
}
}
},
"io_stats": {
"properties": {
"operations": {
"type": "long"
},
"read_operations": {
"type": "long"
},
"write_operations": {
"type": "long"
},
"read_kilobytes": {
"type": "long"
},
"write_kilobytes": {
"type": "long"
}
}
}
}
},
"os": {
"type": "object"

View File

@ -15,6 +15,7 @@ import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.license.License;
import org.elasticsearch.xpack.monitoring.MonitoringFeatureSet;
import org.elasticsearch.xpack.monitoring.collector.cluster.ClusterInfoMonitoringDoc;
import org.elasticsearch.xpack.monitoring.exporter.MonitoringTemplateUtils;
import org.elasticsearch.xpack.monitoring.resolver.MonitoringIndexNameResolverTestCase;
@ -49,6 +50,7 @@ public class ClusterInfoResolverTests extends MonitoringIndexNameResolverTestCas
doc.setClusterName(randomAsciiOfLength(5));
doc.setClusterStats(new ClusterStatsResponse(Math.abs(randomLong()), ClusterName.CLUSTER_NAME_SETTING
.getDefault(Settings.EMPTY), randomAsciiOfLength(5), Collections.emptyList(), Collections.emptyList()));
doc.setUsage(Collections.singletonList(new MonitoringFeatureSet.Usage(randomBoolean(), randomBoolean(), emptyMap())));
return doc;
} catch (Exception e) {
throw new IllegalStateException("Failed to generated random ClusterInfoMonitoringDoc", e);
@ -72,13 +74,14 @@ public class ClusterInfoResolverTests extends MonitoringIndexNameResolverTestCas
assertThat(resolver.id(doc), equalTo(clusterUUID));
assertSource(resolver.source(doc, XContentType.JSON),
Sets.newHashSet(
"cluster_uuid",
"timestamp",
"source_node",
"cluster_name",
"version",
"license",
"cluster_stats"));
Sets.newHashSet(
"cluster_uuid",
"timestamp",
"source_node",
"cluster_name",
"version",
"license",
"cluster_stats",
"stack_stats.xpack"));
}
}

View File

@ -27,6 +27,7 @@ import static org.elasticsearch.test.ESIntegTestCase.Scope.TEST;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.isEmptyOrNullString;
import static org.hamcrest.Matchers.not;
@ -61,14 +62,14 @@ public class ClusterInfoTests extends MonitoringIntegTestCase {
final String clusterUUID = client().admin().cluster().prepareState().setMetaData(true).get().getState().metaData().clusterUUID();
assertTrue(Strings.hasText(clusterUUID));
logger.debug("--> waiting for the monitoring data index to be created (it should have been created by the ClusterInfoCollector)");
// waiting for the monitoring data index to be created (it should have been created by the ClusterInfoCollector
String dataIndex = ".monitoring-data-" + MonitoringTemplateUtils.TEMPLATE_VERSION;
awaitIndexExists(dataIndex);
logger.debug("--> waiting for cluster info collector to collect data");
// waiting for cluster info collector to collect data
awaitMonitoringDocsCount(equalTo(1L), ClusterInfoResolver.TYPE);
logger.debug("--> retrieving cluster info document");
// retrieving cluster info document
GetResponse response = client().prepareGet(dataIndex, ClusterInfoResolver.TYPE, clusterUUID).get();
assertTrue("cluster_info document does not exist in data index", response.isExists());
@ -80,20 +81,19 @@ public class ClusterInfoTests extends MonitoringIntegTestCase {
assertThat(source.get(MonitoringIndexNameResolver.Fields.CLUSTER_UUID), notNullValue());
assertThat(source.get(MonitoringIndexNameResolver.Fields.TIMESTAMP), notNullValue());
assertThat(source.get(MonitoringIndexNameResolver.Fields.SOURCE_NODE), notNullValue());
assertThat(source.get(ClusterInfoResolver.Fields.CLUSTER_NAME), equalTo(cluster().getClusterName()));
assertThat(source.get(ClusterInfoResolver.Fields.VERSION), equalTo(Version.CURRENT.toString()));
assertThat(source.get("cluster_name"), equalTo(cluster().getClusterName()));
assertThat(source.get("version"), equalTo(Version.CURRENT.toString()));
logger.debug("--> checking that the document contains license information");
Object licenseObj = source.get(ClusterInfoResolver.Fields.LICENSE);
Object licenseObj = source.get("license");
assertThat(licenseObj, instanceOf(Map.class));
Map license = (Map) licenseObj;
assertThat(license, instanceOf(Map.class));
String uid = (String) license.get(ClusterInfoResolver.Fields.UID);
String uid = (String) license.get("uid");
assertThat(uid, not(isEmptyOrNullString()));
String type = (String) license.get(ClusterInfoResolver.Fields.TYPE);
String type = (String) license.get("type");
assertThat(type, not(isEmptyOrNullString()));
String status = (String) license.get(License.Fields.STATUS);
@ -103,7 +103,7 @@ public class ClusterInfoTests extends MonitoringIntegTestCase {
assertThat(expiryDate, greaterThan(0L));
// We basically recompute the hash here
String hkey = (String) license.get(ClusterInfoResolver.Fields.HKEY);
String hkey = (String) license.get("hkey");
String recalculated = ClusterInfoResolver.hash(status, uid, type, String.valueOf(expiryDate), clusterUUID);
assertThat(hkey, equalTo(recalculated));
@ -112,14 +112,30 @@ public class ClusterInfoTests extends MonitoringIntegTestCase {
assertThat((Long) license.get(License.Fields.ISSUE_DATE_IN_MILLIS), greaterThan(0L));
assertThat((Integer) license.get(License.Fields.MAX_NODES), greaterThan(0));
Object clusterStats = source.get(ClusterInfoResolver.Fields.CLUSTER_STATS);
Object clusterStats = source.get("cluster_stats");
assertNotNull(clusterStats);
assertThat(clusterStats, instanceOf(Map.class));
assertThat(((Map) clusterStats).size(), greaterThan(0));
Object stackStats = source.get("stack_stats");
assertNotNull(stackStats);
assertThat(stackStats, instanceOf(Map.class));
assertThat(((Map) stackStats).size(), equalTo(1));
Object xpack = ((Map)stackStats).get("xpack");
assertNotNull(xpack);
assertThat(xpack, instanceOf(Map.class));
// it must have at least monitoring, but others may be hidden
assertThat(((Map) xpack).size(), greaterThanOrEqualTo(1));
Object monitoring = ((Map)xpack).get("monitoring");
assertNotNull(monitoring);
// we don't make any assumptions about what's in it, only that it's there
assertThat(monitoring, instanceOf(Map.class));
waitForMonitoringTemplates();
logger.debug("--> check that the cluster_info is not indexed");
// check that the cluster_info is not indexed
securedFlush();
securedRefresh();
@ -131,8 +147,7 @@ public class ClusterInfoTests extends MonitoringIntegTestCase {
.should(QueryBuilders.matchQuery(License.Fields.STATUS, License.Status.ACTIVE.label()))
.should(QueryBuilders.matchQuery(License.Fields.STATUS, License.Status.INVALID.label()))
.should(QueryBuilders.matchQuery(License.Fields.STATUS, License.Status.EXPIRED.label()))
.should(QueryBuilders.matchQuery(ClusterInfoResolver.Fields.CLUSTER_NAME,
cluster().getClusterName()))
.should(QueryBuilders.matchQuery("cluster_name", cluster().getClusterName()))
.minimumNumberShouldMatch(1)
).get(), 0L);
}

View File

@ -15,6 +15,7 @@ import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.routing.RecoverySource;
import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.cluster.routing.UnassignedInfo;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.transport.LocalTransportAddress;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.common.xcontent.XContentType;
@ -81,6 +82,19 @@ public class NodeStatsResolverTests extends MonitoringIndexNameResolverTestCase<
if (Constants.WINDOWS && field.startsWith("node_stats.os.cpu.load_average")) {
return;
}
// we only report IoStats and spins on Linux
if (Constants.LINUX == false) {
if (field.startsWith("node_stats.fs.io_stats")) {
return;
}
}
// node_stats.fs.data.spins can be null and it's only reported on Linux
if (field.startsWith("node_stats.fs.data.spins")) {
return;
}
super.assertSourceField(field, sourceFields);
}
@ -140,6 +154,22 @@ public class NodeStatsResolverTests extends MonitoringIndexNameResolverTestCase<
new NodeIndicesStats(new CommonStats(), statsByShard), OsProbe.getInstance().osStats(),
ProcessProbe.getInstance().processStats(), JvmStats.jvmStats(),
new ThreadPoolStats(threadPoolStats),
new FsInfo(0, null, pathInfo), null, null, null, null, null, null);
new FsInfo(0, randomIoStats(), pathInfo), null, null, null, null, null, null);
}
@Nullable
private FsInfo.IoStats randomIoStats() {
if (Constants.LINUX) {
final int stats = randomIntBetween(1, 3);
final FsInfo.DeviceStats[] devices = new FsInfo.DeviceStats[stats];
for (int i = 0; i < devices.length; ++i) {
devices[i] = new FsInfo.DeviceStats(253, 0, "dm-" + i, 287734, 7185242, 8398869, 118857776, null);
}
return new FsInfo.IoStats(devices);
}
return null;
}
}

View File

@ -519,9 +519,6 @@ public abstract class MonitoringIntegTestCase extends ESIntegTestCase {
"\n" +
"admin:\n" +
" cluster: [ 'cluster:monitor/nodes/info', 'cluster:monitor/nodes/liveness' ]\n" +
"transport_client:\n" +
" cluster: [ 'cluster:monitor/nodes/info', 'cluster:monitor/nodes/liveness' ]\n" +
"\n" +
"monitor:\n" +
" cluster: [ 'cluster:monitor/nodes/info', 'cluster:monitor/nodes/liveness' ]\n"
;

View File

@ -30,10 +30,7 @@ public class AuthenticateRequest extends ActionRequest<AuthenticateRequest> impl
@Override
public ActionRequestValidationException validate() {
Validation.Error error = Validation.Users.validateUsername(username);
if (error != null) {
return addValidationError(error.toString(), null);
}
// we cannot apply our validation rules here as an authenticate request could be for an LDAP user that doesn't fit our restrictions
return null;
}

View File

@ -49,7 +49,7 @@ import org.elasticsearch.node.Node;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.authc.AuthenticationToken;
@ -740,9 +740,9 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
+ REMOTE_CLIENT_SETTINGS.getKey() + ".hosts]");
}
final Settings theClientSetting = clientSettings.filter((s) -> s.startsWith("hosts") == false); // hosts is not a valid setting
final TransportClient transportClient = new XPackTransportClient(Settings.builder()
.put("node.name", DEFAULT_CLIENT_NAME + "-" + Node.NODE_NAME_SETTING.get(settings))
.put(theClientSetting).build());
final TransportClient transportClient = new TransportClient(Settings.builder()
.put("node.name", DEFAULT_CLIENT_NAME + "-" + Node.NODE_NAME_SETTING.get(settings))
.put(theClientSetting).build(), Settings.EMPTY, Collections.singletonList(XPackPlugin.class)) {};
for (Tuple<String, Integer> pair : hostPortPairs) {
try {
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(pair.v1()), pair.v2()));

View File

@ -80,9 +80,6 @@ public class FileUserPasswdStore {
}
public boolean verifyPassword(String username, SecuredString password) {
if (users == null) {
return false;
}
char[] hash = users.get(username);
return hash != null && hasher.verify(password, hash);
}

View File

@ -143,7 +143,7 @@ public class FileUserRolesStore {
continue;
}
String role = line.substring(0, i).trim();
Validation.Error validationError = Validation.Roles.validateRoleName(role);
Validation.Error validationError = Validation.Roles.validateRoleName(role, true);
if (validationError != null) {
logger.error("invalid role entry in users_roles file [{}], line [{}] - {}. skipping...", path.toAbsolutePath(), lineNr,
validationError);

View File

@ -446,7 +446,7 @@ public class UsersTool extends MultiCommand {
}
String[] roles = rolesStr.split(",");
for (String role : roles) {
Validation.Error validationError = Validation.Roles.validateRoleName(role);
Validation.Error validationError = Validation.Roles.validateRoleName(role, true);
if (validationError != null) {
throw new UserException(ExitCodes.DATA_ERROR, "Invalid role [" + role + "]... " + validationError);
}

View File

@ -168,7 +168,7 @@ public class RoleDescriptor implements ToXContent {
public static RoleDescriptor parse(String name, XContentParser parser) throws IOException {
// validate name
Validation.Error validationError = Validation.Roles.validateRoleName(name);
Validation.Error validationError = Validation.Roles.validateRoleName(name, true);
if (validationError != null) {
ValidationException ve = new ValidationException();
ve.addValidationError(validationError.toString());

View File

@ -5,6 +5,9 @@
*/
package org.elasticsearch.xpack.security.support;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
import org.elasticsearch.xpack.security.authz.store.ReservedRolesStore;
import java.util.regex.Pattern;
/**
@ -19,12 +22,16 @@ public final class Validation {
private static final int MIN_PASSWD_LENGTH = 6;
public static Error validateUsername(String username) {
return COMMON_NAME_PATTERN.matcher(username).matches() ?
null :
new Error("A valid username must be at least 1 character and no longer than 30 characters. " +
"It must begin with a letter (`a-z` or `A-Z`) or an underscore (`_`). Subsequent " +
"characters can be letters, underscores (`_`), digits (`0-9`) or any of the following " +
"symbols `@`, `-`, `.` or `$`");
if (COMMON_NAME_PATTERN.matcher(username).matches() == false) {
return new Error("A valid username must be at least 1 character and no longer than 30 characters. " +
"It must begin with a letter (`a-z` or `A-Z`) or an underscore (`_`). Subsequent " +
"characters can be letters, underscores (`_`), digits (`0-9`) or any of the following " +
"symbols `@`, `-`, `.` or `$`");
}
if (ReservedRealm.isReserved(username)) {
return new Error("Username [" + username + "] is reserved and may not be used.");
}
return null;
}
public static Error validatePassword(char[] password) {
@ -38,12 +45,20 @@ public final class Validation {
public static final class Roles {
public static Error validateRoleName(String roleName) {
return COMMON_NAME_PATTERN.matcher(roleName).matches() ?
null :
new Error("A valid role name must be at least 1 character and no longer than 30 characters. " +
"It must begin with a letter (`a-z` or `A-Z`) or an underscore (`_`). Subsequent " +
"characters can be letters, underscores (`_`), digits (`0-9`) or any of the following " +
"symbols `@`, `-`, `.` or `$`");
return validateRoleName(roleName, false);
}
public static Error validateRoleName(String roleName, boolean allowReserved) {
if (COMMON_NAME_PATTERN.matcher(roleName).matches() == false) {
return new Error("A valid role name must be at least 1 character and no longer than 30 characters. " +
"It must begin with a letter (`a-z` or `A-Z`) or an underscore (`_`). Subsequent " +
"characters can be letters, underscores (`_`), digits (`0-9`) or any of the following " +
"symbols `@`, `-`, `.` or `$`");
}
if (allowReserved == false && ReservedRolesStore.isReserved(roleName)) {
return new Error("Role [" + roleName + "] is reserved and may not be used.");
}
return null;
}
}

View File

@ -43,11 +43,6 @@ public class PermissionPrecedenceTests extends SecurityIntegTestCase {
" - names: '*'\n" +
" privileges: [ all ]" +
"\n" +
"transport_client:\n" +
" cluster:\n" +
" - cluster:monitor/nodes/info\n" +
" - cluster:monitor/state\n" +
"\n" +
"user:\n" +
" indices:\n" +
" - names: 'test_*'\n" +

View File

@ -33,7 +33,7 @@ import org.elasticsearch.transport.Netty3Plugin;
import org.elasticsearch.transport.Netty4Plugin;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.TestXPackTransportClient;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.action.user.GetUsersResponse;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
@ -190,7 +190,7 @@ public class LicensingTests extends SecurityIntegTestCase {
public void testSecurityActionsByLicenseType() throws Exception {
// security actions should not work!
try (TransportClient client = new XPackTransportClient(internalCluster().transportClient().settings())) {
try (TransportClient client = new TestXPackTransportClient(internalCluster().transportClient().settings())) {
client.addTransportAddress(internalCluster().getDataNodeInstance(Transport.class).boundAddress().publishAddress());
new SecurityClient(client).prepareGetUsers().get();
fail("security actions should not be enabled!");
@ -204,7 +204,7 @@ public class LicensingTests extends SecurityIntegTestCase {
License.OperationMode.PLATINUM, License.OperationMode.STANDARD);
enableLicensing(mode);
// security actions should not work!
try (TransportClient client = new XPackTransportClient(internalCluster().transportClient().settings())) {
try (TransportClient client = new TestXPackTransportClient(internalCluster().transportClient().settings())) {
client.addTransportAddress(internalCluster().getDataNodeInstance(Transport.class).boundAddress().publishAddress());
GetUsersResponse response = new SecurityClient(client).prepareGetUsers().get();
assertNotNull(response);
@ -219,7 +219,7 @@ public class LicensingTests extends SecurityIntegTestCase {
builder.remove(ThreadContext.PREFIX + "." + UsernamePasswordToken.BASIC_AUTH_HEADER);
// basic has no auth
try (TransportClient client = new XPackTransportClient(builder.build())) {
try (TransportClient client = new TestXPackTransportClient(builder.build())) {
client.addTransportAddress(internalCluster().getDataNodeInstance(Transport.class).boundAddress().publishAddress());
assertGreenClusterState(client);
}
@ -229,7 +229,7 @@ public class LicensingTests extends SecurityIntegTestCase {
License.OperationMode.PLATINUM, License.OperationMode.STANDARD);
enableLicensing(mode);
try (TransportClient client = new XPackTransportClient(builder.build())) {
try (TransportClient client = new TestXPackTransportClient(builder.build())) {
client.addTransportAddress(internalCluster().getDataNodeInstance(Transport.class).boundAddress().publishAddress());
client.admin().cluster().prepareHealth().get();
fail("should not have been able to connect to a node!");

View File

@ -57,7 +57,7 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
public static final String DEFAULT_PASSWORD_HASHED = new String(Hasher.BCRYPT.hash(new SecuredString(DEFAULT_PASSWORD.toCharArray())));
public static final String DEFAULT_ROLE = "user";
public static final String DEFAULT_TRANSPORT_CLIENT_ROLE = "trans_client_user";
public static final String DEFAULT_TRANSPORT_CLIENT_ROLE = "transport_client";
public static final String DEFAULT_TRANSPORT_CLIENT_USER_NAME = "test_trans_client_user";
public static final String CONFIG_STANDARD_USER =
@ -73,10 +73,7 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
" cluster: [ ALL ]\n" +
" indices:\n" +
" - names: '*'\n" +
" privileges: [ ALL ]\n" +
DEFAULT_TRANSPORT_CLIENT_ROLE + ":\n" +
" cluster:\n" +
" - transport_client";
" privileges: [ ALL ]\n";
private final Path parentFolder;
private final String subfolderPrefix;

View File

@ -22,7 +22,7 @@ import org.elasticsearch.xpack.security.authc.support.SecuredStringTests;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.TestXPackTransportClient;
import java.util.Collections;
import java.util.HashMap;
@ -39,8 +39,6 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
static final String RUN_AS_USER = "run_as_user";
static final String TRANSPORT_CLIENT_USER = "transport_user";
static final String ROLES =
"transport_client:\n" +
" cluster: [ 'cluster:monitor/nodes/liveness' ]\n" +
"run_as_role:\n" +
" run_as: [ '" + SecuritySettingsSource.DEFAULT_USER_NAME + "', 'idontexist' ]\n";
@ -231,7 +229,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
.put("xpack.security.transport.ssl.enabled", false)
.build();
return new XPackTransportClient(settings)
return new TestXPackTransportClient(settings)
.addTransportAddress(publishAddress);
}
}

View File

@ -25,7 +25,7 @@ import org.elasticsearch.xpack.ssl.SSLClientAuth;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.TestXPackTransportClient;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
@ -155,7 +155,7 @@ public class PkiAuthenticationTests extends SecurityIntegTestCase {
.put("cluster.name", internalCluster().getClusterName());
builder.remove(Security.USER_SETTING.getKey());
builder.remove("request.headers.Authorization");
return new XPackTransportClient(builder.build());
return new TestXPackTransportClient(builder.build());
}
private String getNodeUrl() {

View File

@ -17,7 +17,7 @@ import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.TestXPackTransportClient;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
@ -108,7 +108,7 @@ public class PkiOptionalClientAuthTests extends SecurityIntegTestCase {
.build();
try (TransportClient client = new XPackTransportClient(settings)) {
try (TransportClient client = new TestXPackTransportClient(settings)) {
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), port));
assertGreenClusterState(client);
}

View File

@ -7,7 +7,6 @@ package org.elasticsearch.xpack.security.authz.store;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LogEvent;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.XPackPlugin;
@ -361,14 +360,14 @@ public class FileRolesStoreTests extends ESTestCase {
assertThat(roles, hasKey("admin"));
List<String> events = CapturingLogger.output(logger.getName(), Level.WARN);
List<String> events = CapturingLogger.output(logger.getName(), Level.ERROR);
assertThat(events, notNullValue());
assertThat(events, hasSize(4));
// the system role will always be checked first
assertThat(events.get(0), containsString("role [_system] is reserved"));
assertThat(events.get(1), containsString("role [superuser] is reserved"));
assertThat(events.get(2), containsString("role [kibana] is reserved"));
assertThat(events.get(3), containsString("role [transport_client] is reserved"));
assertThat(events.get(0), containsString("Role [_system] is reserved"));
assertThat(events.get(1), containsString("Role [superuser] is reserved"));
assertThat(events.get(2), containsString("Role [kibana] is reserved"));
assertThat(events.get(3), containsString("Role [transport_client] is reserved"));
}
public void testUsageStats() throws Exception {

View File

@ -5,11 +5,16 @@
*/
package org.elasticsearch.xpack.security.support;
import org.elasticsearch.xpack.security.authz.store.ReservedRolesStore;
import org.elasticsearch.xpack.security.support.Validation.Error;
import org.elasticsearch.xpack.security.support.Validation.Users;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.security.user.ElasticUser;
import org.elasticsearch.xpack.security.user.KibanaUser;
import java.util.Arrays;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
@ -53,6 +58,13 @@ public class ValidationTests extends ESTestCase {
assertThat(Users.validateUsername(name), nullValue());
}
public void testReservedUsernames() {
final String username = randomFrom(ElasticUser.NAME, KibanaUser.NAME);
final Error error = Users.validateUsername(username);
assertNotNull(error);
assertThat(error.toString(), containsString("is reserved"));
}
public void testUsersValidateUsernameInvalidLength() throws Exception {
int length = frequently() ? randomIntBetween(31, 200) : 0; // invalid length
char[] name = new char[length];
@ -84,6 +96,16 @@ public class ValidationTests extends ESTestCase {
assertThat(Validation.Roles.validateRoleName(name), nullValue());
}
public void testReservedRoleName() {
final String rolename = randomFrom(ReservedRolesStore.names());
final Error error = Validation.Roles.validateRoleName(rolename);
assertNotNull(error);
assertThat(error.toString(), containsString("is reserved"));
final Error allowed = Validation.Roles.validateRoleName(rolename, true);
assertNull(allowed);
}
public void testRolesValidateRoleNameInvalidLength() throws Exception {
int length = frequently() ? randomIntBetween(31, 200) : 0; // invalid length
char[] name = new char[length];

View File

@ -14,7 +14,7 @@ import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.TestXPackTransportClient;
import java.net.InetSocketAddress;
import java.nio.file.Files;
@ -99,7 +99,7 @@ public class SslHostnameVerificationTests extends SecurityIntegTestCase {
.put("xpack.ssl.verification_mode", "full")
.build();
try (TransportClient client = new XPackTransportClient(settings)) {
try (TransportClient client = new TestXPackTransportClient(settings)) {
client.addTransportAddress(new InetSocketTransportAddress(inetSocketAddress.getAddress(), inetSocketAddress.getPort()));
client.admin().cluster().prepareHealth().get();
fail("Expected a NoNodeAvailableException due to hostname verification failures");

View File

@ -26,7 +26,7 @@ import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.xpack.ssl.SSLService;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.TestXPackTransportClient;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
@ -57,7 +57,7 @@ public class SslIntegrationTests extends SecurityIntegTestCase {
// no SSL exception as this is the exception is returned when connecting
public void testThatUnconfiguredCiphersAreRejected() {
try (TransportClient transportClient = new XPackTransportClient(Settings.builder()
try (TransportClient transportClient = new TestXPackTransportClient(Settings.builder()
.put(transportClientSettings())
.put("node.name", "programmatic_transport_client")
.put("cluster.name", internalCluster().getClusterName())
@ -76,7 +76,7 @@ public class SslIntegrationTests extends SecurityIntegTestCase {
// no SSL exception as this is the exception is returned when connecting
public void testThatTransportClientUsingSSLv3ProtocolIsRejected() {
try(TransportClient transportClient = new XPackTransportClient(Settings.builder()
try(TransportClient transportClient = new TestXPackTransportClient(Settings.builder()
.put(transportClientSettings())
.put("node.name", "programmatic_transport_client")
.put("cluster.name", internalCluster().getClusterName())

View File

@ -14,7 +14,7 @@ import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.ssl.SSLClientAuth;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.TestXPackTransportClient;
import org.junit.BeforeClass;
import java.net.InetAddress;
@ -103,7 +103,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
.put("cluster.name", internalCluster().getClusterName())
.put(additionalSettings)
.build();
return new XPackTransportClient(settings);
return new TestXPackTransportClient(settings);
}
/**
@ -236,7 +236,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
.put("xpack.security.transport.ssl.enabled", false)
.put("cluster.name", internalCluster().getClusterName())
.build();
try (TransportClient transportClient = new XPackTransportClient(settings)) {
try (TransportClient transportClient = new TestXPackTransportClient(settings)) {
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("no_ssl")));
assertGreenClusterState(transportClient);
}
@ -251,7 +251,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
.put("cluster.name", internalCluster().getClusterName())
.build();
try (TransportClient transportClient = new XPackTransportClient(settings)) {
try (TransportClient transportClient = new TestXPackTransportClient(settings)) {
transportClient.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()));
assertGreenClusterState(transportClient);
fail("Expected NoNodeAvailableException");
@ -269,7 +269,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
.put("cluster.name", internalCluster().getClusterName())
.build();
try (TransportClient transportClient = new XPackTransportClient(settings)) {
try (TransportClient transportClient = new TestXPackTransportClient(settings)) {
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("client")));
assertGreenClusterState(transportClient);
fail("Expected NoNodeAvailableException");
@ -287,7 +287,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
.put("cluster.name", internalCluster().getClusterName())
.build();
try (TransportClient transportClient = new XPackTransportClient(settings)) {
try (TransportClient transportClient = new TestXPackTransportClient(settings)) {
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(),
getProfilePort("no_client_auth")));
assertGreenClusterState(transportClient);
@ -311,7 +311,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks"))
.put("xpack.ssl.truststore.password", "truststore-testnode-only")
.build();
try (TransportClient transportClient = new XPackTransportClient(settings)) {
try (TransportClient transportClient = new TestXPackTransportClient(settings)) {
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(),
getProfilePort("no_client_auth")));
assertGreenClusterState(transportClient);
@ -333,7 +333,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks"))
.put("xpack.ssl.truststore.password", "truststore-testnode-only")
.build();
try (TransportClient transportClient = new XPackTransportClient(settings)) {
try (TransportClient transportClient = new TestXPackTransportClient(settings)) {
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("client")));
assertGreenClusterState(transportClient);
fail("Expected NoNodeAvailableException");
@ -357,7 +357,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks"))
.put("xpack.ssl.truststore.password", "truststore-testnode-only")
.build();
try (TransportClient transportClient = new XPackTransportClient(settings)) {
try (TransportClient transportClient = new TestXPackTransportClient(settings)) {
transportClient.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()));
assertGreenClusterState(transportClient);
fail("Expected NoNodeAvailableException");
@ -380,7 +380,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks"))
.put("xpack.ssl.truststore.password", "truststore-testnode-only")
.build();
try (TransportClient transportClient = new XPackTransportClient(settings)) {
try (TransportClient transportClient = new TestXPackTransportClient(settings)) {
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("no_ssl")));
assertGreenClusterState(transportClient);
fail("Expected NoNodeAvailableException");
@ -400,7 +400,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
.put("cluster.name", internalCluster().getClusterName())
.put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED)
.build();
try (TransportClient transportClient = new XPackTransportClient(settings)) {
try (TransportClient transportClient = new TestXPackTransportClient(settings)) {
transportClient.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()));
assertGreenClusterState(transportClient);
fail("Expected NoNodeAvailableException");
@ -420,7 +420,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
.put("cluster.name", internalCluster().getClusterName())
.put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED)
.build();
try (TransportClient transportClient = new XPackTransportClient(settings)) {
try (TransportClient transportClient = new TestXPackTransportClient(settings)) {
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("client")));
assertGreenClusterState(transportClient);
fail("Expected NoNodeAvailableException");
@ -440,7 +440,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
.put("cluster.name", internalCluster().getClusterName())
.put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED)
.build();
try (TransportClient transportClient = new XPackTransportClient(settings)) {
try (TransportClient transportClient = new TestXPackTransportClient(settings)) {
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(),
getProfilePort("no_client_auth")));
assertGreenClusterState(transportClient);

View File

@ -264,16 +264,16 @@ public class CertUtils {
/**
* Generates a CA certificate
*/
static X509Certificate generateCACertificate(X500Principal x500Principal, KeyPair keyPair) throws Exception {
return generateSignedCertificate(x500Principal, null, keyPair, null, null, true);
static X509Certificate generateCACertificate(X500Principal x500Principal, KeyPair keyPair, int days) throws Exception {
return generateSignedCertificate(x500Principal, null, keyPair, null, null, true, days);
}
/**
* Generates a signed certificate using the provided CA private key and information from the CA certificate
*/
static X509Certificate generateSignedCertificate(X500Principal principal, GeneralNames subjectAltNames, KeyPair keyPair,
X509Certificate caCert, PrivateKey caPrivKey) throws Exception {
return generateSignedCertificate(principal, subjectAltNames, keyPair, caCert, caPrivKey, false);
X509Certificate caCert, PrivateKey caPrivKey, int days) throws Exception {
return generateSignedCertificate(principal, subjectAltNames, keyPair, caCert, caPrivKey, false, days);
}
/**
@ -289,9 +289,15 @@ public class CertUtils {
* @throws Exception if an error occurs during the certificate creation
*/
private static X509Certificate generateSignedCertificate(X500Principal principal, GeneralNames subjectAltNames, KeyPair keyPair,
X509Certificate caCert, PrivateKey caPrivKey, boolean isCa) throws Exception {
X509Certificate caCert, PrivateKey caPrivKey, boolean isCa
, int days) throws
Exception {
final DateTime notBefore = new DateTime(DateTimeZone.UTC);
final DateTime notAfter = notBefore.plusYears(1);
if (days < 1) {
throw new IllegalArgumentException("the certificate must be valid for at least one day");
}
final DateTime notAfter = notBefore.plusDays(days);
final BigInteger serial = CertUtils.getSerial();
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();

View File

@ -67,6 +67,7 @@ public class CertificateTool extends SettingCommand {
private static final String DESCRIPTION = "Simplifies certificate creation for use with the Elastic Stack";
private static final String DEFAULT_CSR_FILE = "csr-bundle.zip";
private static final String DEFAULT_CERT_FILE = "certificate-bundle.zip";
private static final int DEFAULT_DAYS = 3 * 365;
private static final int FILE_EXTENSION_LENGTH = 4;
static final int MAX_FILENAME_LENGTH = 255 - FILE_EXTENSION_LENGTH;
private static final Pattern ALLOWED_FILENAME_CHAR_PATTERN =
@ -95,6 +96,7 @@ public class CertificateTool extends SettingCommand {
private final OptionSpec<String> caDnSpec;
private final OptionSpec<Integer> keysizeSpec;
private final OptionSpec<String> inputFileSpec;
private final OptionSpec<Integer> daysSpec;
CertificateTool() {
super(DESCRIPTION);
@ -114,6 +116,8 @@ public class CertificateTool extends SettingCommand {
.withRequiredArg();
keysizeSpec = parser.accepts("keysize", "size in bits of RSA keys").withRequiredArg().ofType(Integer.class);
inputFileSpec = parser.accepts("in", "file containing details of the instances in yaml format").withRequiredArg();
daysSpec =
parser.accepts("days", "number of days that the generated certificates are valid").withRequiredArg().ofType(Integer.class);
}
public static void main(String[] args) throws Exception {
@ -135,10 +139,11 @@ public class CertificateTool extends SettingCommand {
final String dn = options.has(caDnSpec) ? caDnSpec.value(options) : AUTO_GEN_CA_DN;
final boolean prompt = options.has(caPasswordSpec);
final char[] keyPass = options.hasArgument(caPasswordSpec) ? caPasswordSpec.value(options).toCharArray() : null;
CAInfo caInfo =
getCAInfo(terminal, dn, caCertPathSpec.value(options), caKeyPathSpec.value(options), keyPass, prompt, env, keysize);
final int days = options.hasArgument(daysSpec) ? daysSpec.value(options) : DEFAULT_DAYS;
CAInfo caInfo = getCAInfo(terminal, dn, caCertPathSpec.value(options), caKeyPathSpec.value(options), keyPass, prompt, env,
keysize, days);
Collection<CertificateInformation> certificateInformations = getCertificateInformationList(terminal, inputFile, env);
generateAndWriteSignedCertificates(outputFile, certificateInformations, caInfo, keysize);
generateAndWriteSignedCertificates(outputFile, certificateInformations, caInfo, keysize, days);
}
printConclusion(terminal, csrOnly, outputFile);
}
@ -281,12 +286,15 @@ public class CertificateTool extends SettingCommand {
* @param dn the distinguished name to use for the CA
* @param caCertPath the path to the CA certificate or {@code null} if not provided
* @param caKeyPath the path to the CA private key or {@code null} if not provided
* @param prompt whether we should prompt the user for a password
* @param keyPass the password to the private key. If not present and the key is encrypted the user will be prompted
* @param env the environment for this tool to resolve files with
* @param keysize the size of the key in bits
* @param days the number of days that the certificate should be valid for
* @return CA cert and private key
*/
static CAInfo getCAInfo(Terminal terminal, String dn, String caCertPath, String caKeyPath, char[] keyPass, boolean prompt,
Environment env, int keysize) throws Exception {
Environment env, int keysize, int days) throws Exception {
if (caCertPath != null) {
assert caKeyPath != null;
Certificate[] certificates = CertUtils.readCertificates(Collections.singletonList(caCertPath), env);
@ -302,7 +310,7 @@ public class CertificateTool extends SettingCommand {
// generate the CA keys and cert
X500Principal x500Principal = new X500Principal(dn);
KeyPair keyPair = CertUtils.generateKeyPair(keysize);
Certificate caCert = CertUtils.generateCACertificate(x500Principal, keyPair);
Certificate caCert = CertUtils.generateCACertificate(x500Principal, keyPair, days);
final char[] password;
if (prompt) {
password = terminal.readSecret("Enter password for CA private key: ");
@ -317,9 +325,11 @@ public class CertificateTool extends SettingCommand {
* @param outputFile the file that the certificates will be written to. This file must not exist
* @param certificateInformations details for creation of the certificates
* @param caInfo the CA information to sign the certificates with
* @param keysize the size of the key in bits
* @param days the number of days that the certificate should be valid for
*/
static void generateAndWriteSignedCertificates(Path outputFile, Collection<CertificateInformation> certificateInformations,
CAInfo caInfo, int keysize) throws Exception {
CAInfo caInfo, int keysize, int days) throws Exception {
fullyWriteFile(outputFile, (outputStream, pemWriter) -> {
// write out the CA info first if it was generated
writeCAInfoIfGenerated(outputStream, pemWriter, caInfo);
@ -328,7 +338,7 @@ public class CertificateTool extends SettingCommand {
KeyPair keyPair = CertUtils.generateKeyPair(keysize);
Certificate certificate = CertUtils.generateSignedCertificate(certificateInformation.name.x500Principal,
getSubjectAlternativeNamesValue(certificateInformation.ipAddresses, certificateInformation.dnsNames),
keyPair, caInfo.caCert, caInfo.privateKey);
keyPair, caInfo.caCert, caInfo.privateKey, days);
final String dirName = certificateInformation.name.filename + "/";
ZipEntry zipEntry = new ZipEntry(dirName);

View File

@ -9,7 +9,6 @@ import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -17,14 +16,14 @@ import java.util.Collection;
* TransportClient.Builder that installs the XPackPlugin by default.
*/
@SuppressWarnings({"unchecked","varargs"})
public class XPackTransportClient extends TransportClient {
public class TestXPackTransportClient extends TransportClient {
@SafeVarargs
public XPackTransportClient(Settings settings, Class<? extends Plugin>... plugins) {
public TestXPackTransportClient(Settings settings, Class<? extends Plugin>... plugins) {
this(settings, Arrays.asList(plugins));
}
public XPackTransportClient(Settings settings, Collection<Class<? extends Plugin>> plugins) {
public TestXPackTransportClient(Settings settings, Collection<Class<? extends Plugin>> plugins) {
super(settings, Settings.EMPTY, addPlugins(plugins, XPackPlugin.class));
}
}

View File

@ -42,6 +42,7 @@ import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAKey;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -207,14 +208,15 @@ public class CertificateToolTests extends ESTestCase {
assertEquals(4, certInfos.size());
final int keysize = randomFrom(1024, 2048);
final int days = randomIntBetween(1, 1024);
KeyPair keyPair = CertUtils.generateKeyPair(keysize);
X509Certificate caCert = CertUtils.generateCACertificate(new X500Principal("CN=test ca"), keyPair);
X509Certificate caCert = CertUtils.generateCACertificate(new X500Principal("CN=test ca"), keyPair, days);
final boolean generatedCa = randomBoolean();
final char[] keyPassword = randomBoolean() ? "changeme".toCharArray() : null;
assertFalse(Files.exists(outputFile));
CAInfo caInfo = new CAInfo(caCert, keyPair.getPrivate(), generatedCa, keyPassword);
CertificateTool.generateAndWriteSignedCertificates(outputFile, certInfos, caInfo, keysize);
CertificateTool.generateAndWriteSignedCertificates(outputFile, certInfos, caInfo, keysize, days);
assertTrue(Files.exists(outputFile));
FileSystem fileSystem = FileSystems.newFileSystem(new URI("jar:" + outputFile.toUri()), Collections.emptyMap());
@ -229,6 +231,8 @@ public class CertificateToolTests extends ESTestCase {
X509Certificate parsedCaCert = readX509Certificate(reader);
assertThat(parsedCaCert.getSubjectX500Principal().getName(), containsString("test ca"));
assertEquals(caCert, parsedCaCert);
long daysBetween = ChronoUnit.DAYS.between(caCert.getNotBefore().toInstant(), caCert.getNotAfter().toInstant());
assertEquals(days, (int) daysBetween);
}
// check the CA key
@ -283,15 +287,17 @@ public class CertificateToolTests extends ESTestCase {
terminal.addSecretInput("testnode");
}
final int days = randomIntBetween(1, 1024);
CAInfo caInfo = CertificateTool.getCAInfo(terminal, "CN=foo", testNodeCertPath.toString(), testNodeKeyPath.toString(),
passwordPrompt ? null : "testnode".toCharArray(), passwordPrompt, env, randomFrom(1024, 2048));
passwordPrompt ? null : "testnode".toCharArray(), passwordPrompt, env, randomFrom(1024, 2048), days);
assertTrue(terminal.getOutput().isEmpty());
assertThat(caInfo.caCert, instanceOf(X509Certificate.class));
assertEquals(caInfo.caCert.getSubjectX500Principal().getName(),
"CN=Elasticsearch Test Node,OU=elasticsearch,O=org");
assertThat(caInfo.privateKey.getAlgorithm(), containsString("RSA"));
assertEquals(2048, ((RSAKey) caInfo.privateKey).getModulus().bitLength());
assertFalse(caInfo.generated);
long daysBetween = ChronoUnit.DAYS.between(caInfo.caCert.getNotBefore().toInstant(), caInfo.caCert.getNotAfter().toInstant());
assertEquals(1460L, daysBetween);
// test generation
final boolean passwordProtected = randomBoolean();
@ -303,13 +309,16 @@ public class CertificateToolTests extends ESTestCase {
password = "testnode".toCharArray();
}
final int keysize = randomFrom(1024, 2048);
caInfo = CertificateTool.getCAInfo(terminal, "CN=foo bar", null, null, password, passwordProtected && passwordPrompt, env, keysize);
caInfo = CertificateTool.getCAInfo(terminal, "CN=foo bar", null, null, password, passwordProtected && passwordPrompt, env,
keysize, days);
assertTrue(terminal.getOutput().isEmpty());
assertThat(caInfo.caCert, instanceOf(X509Certificate.class));
assertEquals(caInfo.caCert.getSubjectX500Principal().getName(), "CN=foo bar");
assertThat(caInfo.privateKey.getAlgorithm(), containsString("RSA"));
assertTrue(caInfo.generated);
assertEquals(keysize, ((RSAKey) caInfo.privateKey).getModulus().bitLength());
daysBetween = ChronoUnit.DAYS.between(caInfo.caCert.getNotBefore().toInstant(), caInfo.caCert.getNotAfter().toInstant());
assertEquals(days, (int) daysBetween);
}
public void testNameValues() throws Exception {

View File

@ -20,7 +20,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.TestXPackTransportClient;
import org.elasticsearch.xpack.security.Security;
import javax.net.ssl.KeyManagerFactory;
@ -98,7 +98,7 @@ public class SSLClientAuthTests extends SecurityIntegTestCase {
.put(Security.USER_SETTING.getKey(),
transportClientUsername() + ":" + new String(transportClientPassword().internalChars()))
.build();
try (TransportClient client = new XPackTransportClient(settings)) {
try (TransportClient client = new TestXPackTransportClient(settings)) {
Transport transport = internalCluster().getDataNodeInstance(Transport.class);
TransportAddress transportAddress = transport.boundAddress().publishAddress();
client.addTransportAddress(transportAddress);

View File

@ -676,9 +676,6 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
"\n" +
"admin:\n" +
" cluster: [ 'manage' ]\n" +
"transport_client:\n" +
" cluster: [ 'transport_client' ]\n" +
"\n" +
"monitor:\n" +
" cluster: [ 'monitor' ]\n"
;