Merge branch 'master' into kibana-shield-user-role-ui

Original commit: elastic/x-pack-elasticsearch@631196d5b1
This commit is contained in:
Lukas Olson 2016-02-09 12:09:01 -07:00
commit d0b8195f8f
120 changed files with 693 additions and 873 deletions

View File

@ -98,7 +98,7 @@ public class HistoryTemplateTransformMappingsTests extends AbstractWatcherIntegr
assertThat(mappingsResponse, notNullValue());
assertThat(mappingsResponse.getMappings().isEmpty(), is(false));
for (ObjectObjectCursor<String, ImmutableOpenMap<String, MappingMetaData>> metadatas : mappingsResponse.getMappings()) {
if (!metadatas.key.startsWith(".watch_history")) {
if (!metadatas.key.startsWith(".watcher-history")) {
continue;
}
MappingMetaData metadata = metadatas.value.get("watch_record");

View File

@ -3,7 +3,7 @@
* 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.watcher.test.integration;
package org.elasticsearch.messy.tests;
import org.apache.lucene.util.LuceneTestCase.BadApple;
import org.elasticsearch.ExceptionsHelper;
@ -18,6 +18,9 @@ import org.elasticsearch.discovery.zen.elect.ElectMasterService;
import org.elasticsearch.discovery.zen.ping.ZenPing;
import org.elasticsearch.discovery.zen.ping.ZenPingService;
import org.elasticsearch.discovery.zen.ping.unicast.UnicastZenPing;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.MockMustacheScriptEngine;
import org.elasticsearch.script.mustache.MustachePlugin;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.ESIntegTestCase.SuppressLocalMode;
import org.elasticsearch.test.discovery.ClusterDiscoveryConfiguration;
@ -33,6 +36,10 @@ import org.elasticsearch.watcher.test.WatcherTestUtils;
import org.elasticsearch.watcher.transport.actions.delete.DeleteWatchResponse;
import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsResponse;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
@ -81,6 +88,23 @@ public class NoMasterNodeTests extends AbstractWatcherIntegrationTestCase {
.build();
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
Collection<Class<? extends Plugin>> types = new ArrayList<>();
types.addAll(super.nodePlugins());
// TODO remove dependency on mustache
types.add(MustachePlugin.class);
return types;
}
@Override
protected Collection<Class<? extends Plugin>> getMockPlugins() {
Set<Class<? extends Plugin>> plugins = new HashSet<>(super.getMockPlugins());
// remove the mock because we use mustache here...
plugins.remove(MockMustacheScriptEngine.TestPlugin.class);
return plugins;
}
public void testSimpleFailure() throws Exception {
// we need 3 hosts here because we stop the master and start another - it doesn't restart the pre-existing node...
config = new ClusterDiscoveryConfiguration.UnicastZen(3, Settings.EMPTY);

View File

@ -3,7 +3,7 @@
* 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.watcher.transport.action.ack;
package org.elasticsearch.messy.tests;
import org.apache.lucene.util.LuceneTestCase.BadApple;
@ -13,6 +13,9 @@ import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.MockMustacheScriptEngine;
import org.elasticsearch.script.mustache.MustachePlugin;
import org.elasticsearch.watcher.actions.ActionStatus;
import org.elasticsearch.watcher.client.WatcherClient;
import org.elasticsearch.watcher.condition.compare.CompareCondition;
@ -29,6 +32,10 @@ import org.elasticsearch.watcher.watch.Watch;
import org.elasticsearch.watcher.watch.WatchStore;
import org.hamcrest.Matchers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
@ -52,6 +59,24 @@ import static org.hamcrest.core.IsEqual.equalTo;
//test is just too slow, please fix it to not be sleep-based
@BadApple(bugUrl = "https://github.com/elastic/x-plugins/issues/1007")
public class WatchAckTests extends AbstractWatcherIntegrationTestCase {
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
Collection<Class<? extends Plugin>> types = new ArrayList<>();
types.addAll(super.nodePlugins());
// TODO remove dependency on mustache
types.add(MustachePlugin.class);
return types;
}
@Override
protected Collection<Class<? extends Plugin>> getMockPlugins() {
Set<Class<? extends Plugin>> plugins = new HashSet<>(super.getMockPlugins());
// remove the mock because we use mustache here...
plugins.remove(MockMustacheScriptEngine.TestPlugin.class);
return plugins;
}
private IndexResponse indexTestDoc() {
createIndex("actions", "events");
ensureGreen("actions", "events");

View File

@ -10,7 +10,7 @@ integTest {
systemProperty 'es.shield.audit.enabled', 'true'
systemProperty 'es.shield.audit.outputs', 'index'
setupCommand 'setupDummyUser',
'bin/x-pack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
'bin/xpack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}",

View File

@ -5,10 +5,14 @@
*/
package org.elasticsearch.shield.audit;
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateResponse;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.shield.audit.index.IndexAuditTrail;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.ESIntegTestCase;
@ -49,6 +53,35 @@ public class IndexAuditIT extends ESIntegTestCase {
assertThat((String) searchResponse.getHits().getAt(0).sourceAsMap().get("principal"), is(USER));
}
public void testAuditTrailTemplateIsRecreatedAfterDelete() throws Exception {
// this is already "tested" by the test framework since we wipe the templates before and after,
// but lets be explicit about the behavior
awaitIndexTemplateCreation();
// delete the template
DeleteIndexTemplateResponse deleteResponse = client().admin().indices()
.prepareDeleteTemplate(IndexAuditTrail.INDEX_TEMPLATE_NAME).execute().actionGet();
assertThat(deleteResponse.isAcknowledged(), is(true));
awaitIndexTemplateCreation();
}
private void awaitIndexTemplateCreation() throws InterruptedException {
boolean found = awaitBusy(() -> {
GetIndexTemplatesResponse response = client().admin().indices()
.prepareGetTemplates(IndexAuditTrail.INDEX_TEMPLATE_NAME).execute().actionGet();
if (response.getIndexTemplates().size() > 0) {
for (IndexTemplateMetaData indexTemplateMetaData : response.getIndexTemplates()) {
if (IndexAuditTrail.INDEX_TEMPLATE_NAME.equals(indexTemplateMetaData.name())) {
return true;
}
}
}
return false;
});
assertThat("index template [" + IndexAuditTrail.INDEX_TEMPLATE_NAME + "] was not created", found, is(true));
}
@Override
protected Settings externalClusterClientSettings() {
return Settings.builder()

View File

@ -8,9 +8,9 @@ integTest {
cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
setupCommand 'setupDummyUser',
'bin/x-pack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
'bin/xpack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
setupCommand 'setupTransportClientUser',
'bin/x-pack/esusers', 'useradd', 'transport', '-p', 'changeme', '-r', 'transport_client'
'bin/xpack/esusers', 'useradd', 'transport', '-p', 'changeme', '-r', 'transport_client'
waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}",

View File

@ -35,7 +35,7 @@ integTest {
systemProperty 'es.watcher.enabled', 'false'
systemProperty 'es.marvel.enabled', 'false'
setupCommand 'setupDummyUser',
'bin/x-pack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
'bin/xpack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}",

View File

@ -23,7 +23,7 @@ integTest {
systemProperty 'es.shield.authc.realms.esusers.type', 'esusers'
setupCommand 'setupDummyUser',
'bin/x-pack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
'bin/xpack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}",

View File

@ -75,10 +75,10 @@
<property name="home" location="${integ.scratch}/elasticsearch-${elasticsearch.version}"/>
<echo>Adding roles.yml</echo>
<copy file="shield-roles.yml" tofile="${home}/config/shield/roles.yml" overwrite="true"/>
<copy file="shield-roles.yml" tofile="${home}/config/xpack/roles.yml" overwrite="true"/>
<echo>Adding shield users...</echo>
<run-script script="${home}/bin/shield/esusers">
<run-script script="${home}/bin/xpack/esusers">
<nested>
<arg value="useradd"/>
<arg value="test_admin"/>

View File

@ -63,10 +63,10 @@
<property name="home" location="${integ.scratch}/elasticsearch-${elasticsearch.version}"/>
<echo>Adding roles.yml with watcher roles</echo>
<copy file="watcher-with-shield-roles.yml" tofile="${home}/config/shield/roles.yml" overwrite="true"/>
<copy file="watcher-with-shield-roles.yml" tofile="${home}/config/xpack/roles.yml" overwrite="true"/>
<echo>Adding shield users...</echo>
<run-script script="${home}/bin/shield/esusers">
<run-script script="${home}/bin/xpack/esusers">
<nested>
<arg value="useradd"/>
<arg value="test_admin"/>
@ -76,7 +76,7 @@
<arg value="admin"/>
</nested>
</run-script>
<run-script script="${home}/bin/shield/esusers">
<run-script script="${home}/bin/xpack/esusers">
<nested>
<arg value="useradd"/>
<arg value="watcher_manager"/>
@ -86,7 +86,7 @@
<arg value="watcher_manager"/>
</nested>
</run-script>
<run-script script="${home}/bin/shield/esusers">
<run-script script="${home}/bin/xpack/esusers">
<nested>
<arg value="useradd"/>
<arg value="powerless_user"/>

View File

@ -6,12 +6,12 @@ admin:
watcher_manager:
cluster: manage_watcher, cluster:monitor/nodes/info, cluster:monitor/health
indices:
'.watch_history-*': all
'.watcher-history-*': all
watcher_monitor:
cluster: monitor_watcher
indices:
'.watch_history-*': read
'.watcher-history-*': read
crapy_role:
cluster:

View File

@ -57,9 +57,9 @@ integTest {
// copy keystore into config/
extraConfigFile keystore.name, keystore
setupCommand 'setupTestUser',
'bin/x-pack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
'bin/xpack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
setupCommand 'setupMarvelUser',
'bin/x-pack/esusers', 'useradd', 'marvel_export', '-p', 'changeme', '-r', 'marvel_agent'
'bin/xpack/esusers', 'useradd', 'marvel_export', '-p', 'changeme', '-r', 'marvel_agent'
waitCondition = { node, ant ->
// we just return true, doing an https check is tricky here
return true

View File

@ -18,7 +18,7 @@ integTest {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
setupCommand 'setupDummyUser',
'bin/x-pack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
'bin/xpack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}",

View File

@ -58,5 +58,5 @@
- do:
search:
index: .watch_history-*
index: .watcher-history-*
- match: { hits.hits.0._source.result.actions.0.logging.logged_text: "value1 value2" }

View File

@ -20,13 +20,13 @@ integTest {
cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
extraConfigFile 'x-pack/roles.yml', 'roles.yml'
extraConfigFile 'xpack/roles.yml', 'roles.yml'
setupCommand 'setupTestAdminUser',
'bin/x-pack/esusers', 'useradd', 'test_admin', '-p', 'changeme', '-r', 'admin'
'bin/xpack/esusers', 'useradd', 'test_admin', '-p', 'changeme', '-r', 'admin'
setupCommand 'setupWatcherManagerUser',
'bin/x-pack/esusers', 'useradd', 'watcher_manager', '-p', 'changeme', '-r', 'watcher_manager'
'bin/xpack/esusers', 'useradd', 'watcher_manager', '-p', 'changeme', '-r', 'watcher_manager'
setupCommand 'setupPowerlessUser',
'bin/x-pack/esusers', 'useradd', 'powerless_user', '-p', 'changeme', '-r', 'crappy_role'
'bin/xpack/esusers', 'useradd', 'powerless_user', '-p', 'changeme', '-r', 'crappy_role'
waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}",

View File

@ -6,13 +6,13 @@ admin:
watcher_manager:
cluster: manage_watcher, cluster:monitor/nodes/info, cluster:monitor/health
indices:
'.watch_history-*': all
'.watcher-history-*': all
run_as: powerless_user, watcher_manager
watcher_monitor:
cluster: monitor_watcher
indices:
'.watch_history-*': read
'.watcher-history-*': read
crappy_role:
cluster:

View File

@ -1,97 +0,0 @@
<?xml version="1.0"?>
<project name="shield-overrides"
xmlns:ac="antlib:net.sf.antcontrib">
<!-- redefined to work with auth -->
<macrodef name="waitfor-elasticsearch">
<attribute name="port"/>
<attribute name="timeoutproperty"/>
<sequential>
<echo>Waiting for elasticsearch to become available on port @{port}...</echo>
<waitfor maxwait="30" maxwaitunit="second"
checkevery="500" checkeveryunit="millisecond"
timeoutproperty="@{timeoutproperty}">
<socket server="127.0.0.1" port="@{port}"/>
</waitfor>
</sequential>
</macrodef>
<target name="start-external-cluster-with-plugins" depends="setup-workspace">
<ac:for list="${xplugins.list}" param="xplugin.name">
<sequential>
<fail message="Expected @{xplugin.name}-${version}.zip as a dependency, but could not be found in ${integ.deps}/plugins}">
<condition>
<not>
<available file="${integ.deps}/plugins/@{xplugin.name}-${elasticsearch.version}.zip" />
</not>
</condition>
</fail>
<ac:if>
<equals arg1="@{xplugin.name}" arg2="elasticsearch-marvel"/>
<ac:then>
<property name="marvel.enabled">true</property>
</ac:then>
</ac:if>
</sequential>
</ac:for>
<ac:for param="file">
<path>
<fileset dir="${integ.deps}/plugins"/>
</path>
<sequential>
<local name="plugin.name"/>
<convert-plugin-name file="@{file}" outputproperty="plugin.name"/>
<install-plugin name="${plugin.name}" file="@{file}"/>
</sequential>
</ac:for>
<local name="home"/>
<property name="home" location="${integ.scratch}/elasticsearch-${elasticsearch.version}"/>
<echo>Setting up Shield auth</echo>
<run-script script="${home}/bin/shield/esusers">
<nested>
<arg value="useradd"/>
<arg value="test_user"/>
<arg value="-p"/>
<arg value="changeme"/>
<arg value="-r"/>
<arg value="admin"/>
</nested>
</run-script>
<ac:if>
<equals arg1="${marvel.enabled}" arg2="true"/>
<ac:then>
<run-script script="${home}/bin/shield/esusers">
<nested>
<arg value="useradd"/>
<arg value="marvel_export"/>
<arg value="-p"/>
<arg value="changeme"/>
<arg value="-r"/>
<arg value="marvel_agent"/>
</nested>
</run-script>
<startup-elasticsearch>
<additional-args>
<arg value="-Des.marvel.agent.exporter.es.hosts=http://marvel_export:changeme@localhost:${integ.http.port}"/>
</additional-args>
</startup-elasticsearch>
</ac:then>
<ac:else>
<startup-elasticsearch/>
</ac:else>
</ac:if>
<echo>Checking we can connect with basic auth on port ${integ.http.port}...</echo>
<local name="temp.file"/>
<tempfile property="temp.file" destdir="${java.io.tmpdir}"/>
<get src="http://127.0.0.1:${integ.http.port}" dest="${temp.file}"
username="test_user" password="changeme" verbose="true" retries="10"/>
</target>
</project>

View File

@ -1,14 +0,0 @@
ELASTICSEARCH CONFIDENTIAL
__________________
[2014] Elasticsearch Incorporated. All Rights Reserved.
NOTICE: All information contained herein is, and remains
the property of Elasticsearch Incorporated and its suppliers,
if any. The intellectual and technical concepts contained
herein are proprietary to Elasticsearch Incorporated
and its suppliers and may be covered by U.S. and Foreign Patents,
patents in process, and are protected by trade secret or copyright law.
Dissemination of this information or reproduction of this material
is strictly forbidden unless prior written permission is obtained
from Elasticsearch Incorporated.

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<additionalHeaders>
<javadoc_style>
<firstLine>/*</firstLine>
<beforeEachLine> * </beforeEachLine>
<endLine> */</endLine>
<!--skipLine></skipLine-->
<firstLineDetectionPattern>(\s|\t)*/\*.*$</firstLineDetectionPattern>
<lastLineDetectionPattern>.*\*/(\s|\t)*$</lastLineDetectionPattern>
<allowBlankLines>false</allowBlankLines>
<isMultiline>true</isMultiline>
</javadoc_style>
</additionalHeaders>

View File

@ -3,7 +3,7 @@ import org.elasticsearch.gradle.test.NodeInfo
apply plugin: 'elasticsearch.esplugin'
esplugin {
name 'x-pack'
name 'xpack'
description 'Elasticsearch Expanded Pack Plugin'
classname 'org.elasticsearch.xpack.XPackPlugin'
// FIXME we still can't be isolated due to shield custom realms
@ -74,6 +74,9 @@ ext.expansions = [
// Used in marvel index templates
'marvel.plugin.version': version,
'marvel.template.version': '1',
// Used in watcher index template
'watcher.plugin.version': version,
'watcher.template.version': '1',
]
processResources {
@ -111,13 +114,13 @@ bundlePlugin {
include 'LICENSE.txt'
include 'NOTICE.txt'
}
from('shield/bin/shield') {
from('shield/bin/xpack') {
into 'bin'
}
from('shield/config/shield') {
from('shield/config/xpack') {
into 'config'
}
from('watcher/bin/watcher') {
from('watcher/bin/xpack') {
into 'bin'
}
}
@ -126,7 +129,7 @@ integTest {
// TODO: fix this rest test to not depend on a hardcoded port!
systemProperty 'tests.rest.blacklist', 'getting_started/10_monitor_cluster_health/*'
cluster {
setupCommand 'setupDummyUser', 'bin/x-pack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
setupCommand 'setupDummyUser', 'bin/xpack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
waitCondition = { NodeInfo node, AntBuilder ant ->
File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}",
@ -154,7 +157,7 @@ artifacts {
}
run {
setupCommand 'setupDummyUser', 'bin/x-pack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
setupCommand 'setupDummyUser', 'bin/xpack/esusers', 'useradd', 'test_user', '-p', 'changeme', '-r', 'admin'
}
// classes are missing, e.g. com.ibm.icu.lang.UCharacter

View File

@ -19,6 +19,7 @@ import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.shield.InternalClient;
import org.elasticsearch.shield.ShieldPlugin;
import java.util.ArrayList;
import java.util.Arrays;
@ -26,8 +27,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.shield.ShieldPlugin.shieldEnabled;
/**
* Collector for the Recovery API.
* <p>
@ -73,7 +72,7 @@ public class IndexRecoveryCollector extends AbstractCollector<IndexRecoveryColle
results.add(indexRecoveryDoc);
}
} catch (IndexNotFoundException e) {
if (shieldEnabled(settings) && IndexNameExpressionResolver.isAllIndices(Arrays.asList(marvelSettings.indices()))) {
if (ShieldPlugin.enabled(settings) && IndexNameExpressionResolver.isAllIndices(Arrays.asList(marvelSettings.indices()))) {
logger.debug("collector [{}] - unable to collect data for missing index [{}]", name(), e.getIndex());
} else {
throw e;

View File

@ -21,6 +21,7 @@ import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.shield.InternalClient;
import org.elasticsearch.shield.ShieldPlugin;
import java.util.ArrayList;
import java.util.Arrays;
@ -28,8 +29,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.shield.ShieldPlugin.shieldEnabled;
/**
* Collector for indices statistics.
* <p>
@ -87,7 +86,7 @@ public class IndexStatsCollector extends AbstractCollector<IndexStatsCollector>
results.add(indexStatsDoc);
}
} catch (IndexNotFoundException e) {
if (shieldEnabled(settings) && IndexNameExpressionResolver.isAllIndices(Arrays.asList(marvelSettings.indices()))) {
if (ShieldPlugin.enabled(settings) && IndexNameExpressionResolver.isAllIndices(Arrays.asList(marvelSettings.indices()))) {
logger.debug("collector [{}] - unable to collect data for missing index [{}]", name(), e.getIndex());
} else {
throw e;

View File

@ -19,13 +19,12 @@ import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.shield.InternalClient;
import org.elasticsearch.shield.ShieldPlugin;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import static org.elasticsearch.shield.ShieldPlugin.shieldEnabled;
/**
* Collector for indices statistics.
* <p>
@ -72,7 +71,7 @@ public class IndicesStatsCollector extends AbstractCollector<IndicesStatsCollect
return Collections.singletonList(indicesStatsDoc);
} catch (IndexNotFoundException e) {
if (shieldEnabled(settings) && IndexNameExpressionResolver.isAllIndices(Arrays.asList(marvelSettings.indices()))) {
if (ShieldPlugin.enabled(settings) && IndexNameExpressionResolver.isAllIndices(Arrays.asList(marvelSettings.indices()))) {
logger.debug("collector [{}] - unable to collect data for missing index [{}]", name(), e.getIndex());
return Collections.emptyList();
}

View File

@ -66,7 +66,7 @@ public class MarvelPluginTests extends MarvelIntegTestCase {
break;
}
}
assertThat("x-pack plugin not found", found, equalTo(true));
assertThat("xpack plugin not found", found, equalTo(true));
}
}

View File

@ -76,7 +76,7 @@ REM JAVA_OPTS=%JAVA_OPTS% -XX:HeapDumpPath=$ES_HOME/logs/heapdump.hprof
REM Disables explicit GC
set JAVA_OPTS=%JAVA_OPTS% -XX:+DisableExplicitGC
set ES_CLASSPATH=%ES_CLASSPATH%;%ES_HOME%/lib/elasticsearch-1.4.0-SNAPSHOT.jar;%ES_HOME%/lib/*;%ES_HOME%/lib/sigar/*;%ES_HOME%/plugins/x-pack/*
set ES_CLASSPATH=%ES_CLASSPATH%;%ES_HOME%/lib/*;%ES_HOME%/lib/sigar/*;%ES_HOME%/plugins/xpack/*
set ES_PARAMS=-Des.path.home="%ES_HOME%"
SET HOSTNAME=%COMPUTERNAME%

View File

@ -102,9 +102,9 @@ if [ -e "$CONF_DIR" ]; then
case "$properties" in
*-Des.default.path.conf=*) ;;
*)
if [ ! -d "$CONF_DIR/shield" ]; then
echo "ERROR: The configuration directory [$CONF_DIR/shield] does not exist. The esusers tool expects Shield configuration files in that location."
echo "The plugin may not have been installed with the correct configuration path. If [$ES_HOME/config/shield] exists, please copy the shield directory to [$CONF_DIR]"
if [ ! -d "$CONF_DIR/xpack" ]; then
echo "ERROR: The configuration directory [$CONF_DIR/xpack] does not exist. The esusers tool expects security configuration files in that location."
echo "The plugin may not have been installed with the correct configuration path. If [$ES_HOME/config/xpack] exists, please copy the 'xpack' directory to [$CONF_DIR]"
exit 1
fi
properties="$properties -Des.default.path.conf=$CONF_DIR"
@ -123,7 +123,7 @@ fi
export HOSTNAME=`hostname -s`
# include shield jars in classpath
ES_CLASSPATH="$ES_CLASSPATH:$ES_HOME/plugins/x-pack/*"
ES_CLASSPATH="$ES_CLASSPATH:$ES_HOME/plugins/xpack/*"
cd "$ES_HOME" > /dev/null
"$JAVA" $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" $properties org.elasticsearch.shield.authc.esusers.tool.ESUsersTool "$@"

View File

@ -102,9 +102,9 @@ if [ -e "$CONF_DIR" ]; then
case "$properties" in
*-Des.default.path.conf=*) ;;
*)
if [ ! -d "$CONF_DIR/shield" ]; then
echo "ERROR: The configuration directory [$CONF_DIR/shield] does not exist. The syskeygen tool expects Shield configuration files in that location."
echo "The plugin may not have been installed with the correct configuration path. If [$ES_HOME/config/shield] exists, please copy the shield directory to [$CONF_DIR]"
if [ ! -d "$CONF_DIR/xpack" ]; then
echo "ERROR: The configuration directory [$CONF_DIR/xpack] does not exist. The syskeygen tool expects security configuration files in that location."
echo "The plugin may not have been installed with the correct configuration path. If [$ES_HOME/config/xpack] exists, please copy the 'xpack' directory to [$CONF_DIR]"
exit 1
fi
properties="$properties -Des.default.path.conf=$CONF_DIR"
@ -123,7 +123,7 @@ fi
export HOSTNAME=`hostname -s`
# include shield jars in classpath
ES_CLASSPATH="$ES_CLASSPATH:$ES_HOME/plugins/x-pack/*"
ES_CLASSPATH="$ES_CLASSPATH:$ES_HOME/plugins/xpack/*"
cd "$ES_HOME" > /dev/null
$JAVA $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" $properties org.elasticsearch.shield.crypto.tool.SystemKeyTool "$@"

View File

@ -6,7 +6,6 @@
package org.elasticsearch.shield;
import org.elasticsearch.action.ActionModule;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.network.NetworkModule;
@ -14,7 +13,6 @@ import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexModule;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.shield.action.ShieldActionFilter;
@ -71,7 +69,6 @@ import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport;
import org.elasticsearch.shield.transport.netty.ShieldNettyTransport;
import org.elasticsearch.xpack.XPackPlugin;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -85,22 +82,19 @@ import java.util.Map;
public class ShieldPlugin extends Plugin {
public static final String NAME = "shield";
public static final String ENABLED_SETTING_NAME = NAME + ".enabled";
public static final String DLS_FLS_FEATURE = "shield.dls_fls";
public static final String OPT_OUT_QUERY_CACHE = "opt_out_cache";
public static final String DLS_FLS_ENABLED_SETTING = "shield.dls_fls.enabled";
private static final boolean DEFAULT_ENABLED_SETTING = true;
private final Settings settings;
private final boolean enabled;
private final boolean clientMode;
private final boolean transportClientMode;
private ShieldLicenseState shieldLicenseState;
public ShieldPlugin(Settings settings) {
this.settings = settings;
this.enabled = shieldEnabled(settings);
this.clientMode = clientMode(settings);
if (enabled && clientMode == false) {
this.transportClientMode = XPackPlugin.transportClientMode(settings);
this.enabled = XPackPlugin.featureEnabled(settings, NAME, true);
if (enabled && !transportClientMode) {
failIfShieldQueryCacheIsNotActive(settings, true);
}
}
@ -118,11 +112,11 @@ public class ShieldPlugin extends Plugin {
@Override
public Collection<Module> nodeModules() {
if (!enabled) {
if (enabled == false) {
return Collections.singletonList(new ShieldDisabledModule(settings));
}
if (clientMode) {
if (transportClientMode == true) {
return Arrays.<Module>asList(
new ShieldTransportModule(settings),
new SSLModule(settings));
@ -147,9 +141,13 @@ public class ShieldPlugin extends Plugin {
@Override
public Collection<Class<? extends LifecycleComponent>> nodeServices() {
if (enabled && clientMode == false) {
if (enabled == false || transportClientMode == true) {
return Collections.emptyList();
}
List<Class<? extends LifecycleComponent>> list = new ArrayList<>();
if (AuditTrailModule.fileAuditLoggingEnabled(settings)) {
//TODO why only focus on file audit logs? shouldn't we just check if audit trail is enabled in general?
if (AuditTrailModule.fileAuditLoggingEnabled(settings) == true) {
list.add(LoggingAuditTrail.class);
}
list.add(ShieldLicensee.class);
@ -157,8 +155,7 @@ public class ShieldPlugin extends Plugin {
list.add(FileRolesStore.class);
list.add(Realms.class);
return list;
}
return Collections.emptyList();
}
@Override
@ -178,6 +175,7 @@ public class ShieldPlugin extends Plugin {
}
public void onModule(SettingsModule settingsModule) {
//TODO shouldn't we register these settings only if shield is enabled and we're not in a client mode?
settingsModule.registerSetting(IPFilter.IP_FILTER_ENABLED_SETTING);
settingsModule.registerSetting(IPFilter.IP_FILTER_ENABLED_HTTP_SETTING);
settingsModule.registerSetting(IPFilter.HTTP_FILTER_ALLOW_SETTING);
@ -187,6 +185,9 @@ public class ShieldPlugin extends Plugin {
settingsModule.registerSetting(Setting.boolSetting("plugins.load_classpath_plugins", true, false, Setting.Scope.CLUSTER));
// TODO add real settings for this wildcard here
settingsModule.registerSetting(Setting.groupSetting("shield.", false, Setting.Scope.CLUSTER));
// TODO please let's just drop the old settings before releasing
settingsModule.registerSetting(Setting.groupSetting("xpack.shield.", false, Setting.Scope.CLUSTER));
String[] asArray = settings.getAsArray("shield.hide_settings");
for (String pattern : asArray) {
settingsModule.registerSettingsFilter(pattern);
@ -207,14 +208,15 @@ public class ShieldPlugin extends Plugin {
if (enabled == false) {
return;
}
assert shieldLicenseState != null;
if (flsDlsEnabled(settings)) {
module.setSearcherWrapper((indexService) -> new ShieldIndexSearcherWrapper(indexService.getIndexSettings(),
indexService.getQueryShardContext(), indexService.mapperService(),
indexService.newQueryShardContext(), indexService.mapperService(),
indexService.cache().bitsetFilterCache(), indexService.getIndexServices().getThreadPool().getThreadContext(),
shieldLicenseState));
}
if (clientMode == false) {
if (transportClientMode == false) {
module.registerQueryCache(ShieldPlugin.OPT_OUT_QUERY_CACHE, OptOutQueryCache::new);
failIfShieldQueryCacheIsNotActive(module.getSettings(), false);
}
@ -225,7 +227,7 @@ public class ShieldPlugin extends Plugin {
return;
}
// registering the security filter only for nodes
if (clientMode == false) {
if (transportClientMode == false) {
module.registerFilter(ShieldActionFilter.class);
}
@ -241,23 +243,21 @@ public class ShieldPlugin extends Plugin {
}
public void onModule(NetworkModule module) {
if (clientMode == false) {
// we want to expose the shield rest action even when the plugin is disabled
module.registerRestHandler(RestShieldInfoAction.class);
}
if (enabled == false) {
if (transportClientMode) {
if (enabled) {
module.registerTransport(ShieldPlugin.NAME, ShieldNettyTransport.class);
module.registerTransportService(ShieldPlugin.NAME, ShieldClientTransportService.class);
}
return;
}
module.registerTransport(ShieldPlugin.NAME, ShieldNettyTransport.class);
if (clientMode) {
module.registerTransportService(ShieldPlugin.NAME, ShieldClientTransportService.class);
} else {
module.registerTransportService(ShieldPlugin.NAME, ShieldServerTransportService.class);
}
// we want to expose the shield rest action even when the plugin is disabled
module.registerRestHandler(RestShieldInfoAction.class);
if (clientMode == false) {
if (enabled) {
module.registerTransport(ShieldPlugin.NAME, ShieldNettyTransport.class);
module.registerTransportService(ShieldPlugin.NAME, ShieldServerTransportService.class);
module.registerRestHandler(RestAuthenticateAction.class);
module.registerRestHandler(RestClearRealmCacheAction.class);
module.registerRestHandler(RestClearRolesCacheAction.class);
@ -290,39 +290,41 @@ public class ShieldPlugin extends Plugin {
.toCharArray())));
}
/*
We inject additional settings on each tribe client if the current node is a tribe node, to make sure that every tribe has shield
installed and enabled too:
- if shield is loaded on the tribe node we make sure it is also loaded on every tribe, by making it mandatory there
(this means that the tribe node will fail at startup if shield is not loaded on any tribe due to missing mandatory plugin)
- if shield is loaded and enabled on the tribe node, we make sure it is also enabled on every tribe, by forcibly enabling it
(that means it's not possible to disable shield on the tribe clients)
/**
* If the current node is a tribe node, we inject additional settings on each tribe client. We do this to make sure
* that every tribe cluster has shield installed and is enabled. We do that by:
*
* - making it mandatory on the tribe client (this means that the tribe node will fail at startup if shield is
* not loaded on any tribe due to missing mandatory plugin)
*
* - forcibly enabling it (that means it's not possible to disable shield on the tribe clients)
*/
private void addTribeSettings(Settings.Builder settingsBuilder) {
Map<String, Settings> tribesSettings = settings.getGroups("tribe", true);
if (tribesSettings.isEmpty()) {
// it's not a tribe node
return;
}
for (Map.Entry<String, Settings> tribeSettings : tribesSettings.entrySet()) {
String tribePrefix = "tribe." + tribeSettings.getKey() + ".";
// we copy over existing mandatory plugins under additional settings, as they would get overridden otherwise (arrays don't get
// merged)
// we copy over existing mandatory plugins under additional settings, as they would get overridden
// otherwise (arrays don't get merged)
String[] existingMandatoryPlugins = tribeSettings.getValue().getAsArray("plugin.mandatory", null);
if (existingMandatoryPlugins == null) {
//shield is mandatory on every tribe if installed and enabled on the tribe node
settingsBuilder.putArray(tribePrefix + "plugin.mandatory", NAME);
settingsBuilder.putArray(tribePrefix + "plugin.mandatory", XPackPlugin.NAME);
} else {
if (!isShieldMandatory(existingMandatoryPlugins)) {
throw new IllegalStateException("when [plugin.mandatory] is explicitly configured, [" + NAME + "] must be included in" +
" this list");
if (Arrays.binarySearch(existingMandatoryPlugins, XPackPlugin.NAME) < 0) {
throw new IllegalStateException("when [plugin.mandatory] is explicitly configured, [" +
XPackPlugin.NAME + "] must be included in this list");
}
}
final String tribeEnabledSetting = tribePrefix + ENABLED_SETTING_NAME;
final String tribeEnabledSetting = tribePrefix + XPackPlugin.featureEnabledSetting(NAME);
if (settings.get(tribeEnabledSetting) != null) {
boolean enabled = shieldEnabled(tribeSettings.getValue());
boolean enabled = enabled(tribeSettings.getValue());
if (!enabled) {
throw new IllegalStateException("tribe setting [" + tribeEnabledSetting + "] must be set to true but the value is ["
+ settings.get(tribeEnabledSetting) + "]");
@ -334,43 +336,22 @@ public class ShieldPlugin extends Plugin {
}
}
/*
We need to forcefully overwrite the query cache implementation to use Shield's opt out query cache implementation.
This impl. disabled the query cache if field level security is used for a particular request. If we wouldn't do
forcefully overwrite the query cache implementation then we leave the system vulnerable to leakages of data to
unauthorized users.
/**
* We need to forcefully overwrite the query cache implementation to use Shield's opt out query cache implementation.
* This impl. disabled the query cache if field level security is used for a particular request. If we wouldn't do
* forcefully overwrite the query cache implementation then we leave the system vulnerable to leakages of data to
* unauthorized users.
*/
private void addQueryCacheSettings(Settings.Builder settingsBuilder) {
settingsBuilder.put(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey(), OPT_OUT_QUERY_CACHE);
}
private static boolean isShieldMandatory(String[] existingMandatoryPlugins) {
for (String existingMandatoryPlugin : existingMandatoryPlugins) {
if (NAME.equals(existingMandatoryPlugin)) {
return true;
}
}
return false;
}
public static Path configDir(Environment env) {
return env.configFile().resolve(XPackPlugin.NAME);
}
public static Path resolveConfigFile(Environment env, String name) {
return configDir(env).resolve(name);
}
public static boolean clientMode(Settings settings) {
return !"node".equals(settings.get(Client.CLIENT_TYPE_SETTING_S.getKey()));
}
public static boolean shieldEnabled(Settings settings) {
return settings.getAsBoolean(ENABLED_SETTING_NAME, DEFAULT_ENABLED_SETTING);
public static boolean enabled(Settings settings) {
return XPackPlugin.featureEnabled(settings, NAME, true);
}
public static boolean flsDlsEnabled(Settings settings) {
return settings.getAsBoolean(DLS_FLS_ENABLED_SETTING, true);
return XPackPlugin.featureEnabled(settings, DLS_FLS_FEATURE, true);
}
private void failIfShieldQueryCacheIsNotActive(Settings settings, boolean nodeSettings) {

View File

@ -54,7 +54,7 @@ import org.elasticsearch.shield.action.user.DeleteUserRequest;
import org.elasticsearch.shield.authc.AuthenticationService;
import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.shield.client.SecurityClient;
import org.elasticsearch.threadpool.ThreadPool;
import java.util.ArrayList;
@ -458,10 +458,10 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat
}
private <Response> void clearRealmCache(String username, ActionListener<Response> listener, Response response) {
ShieldClient shieldClient = new ShieldClient(client);
ClearRealmCacheRequest request = shieldClient.prepareClearRealmCache()
SecurityClient securityClient = new SecurityClient(client);
ClearRealmCacheRequest request = securityClient.prepareClearRealmCache()
.usernames(username).request();
shieldClient.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() {
securityClient.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() {
@Override
public void onResponse(ClearRealmCacheResponse nodes) {
listener.onResponse(response);

View File

@ -20,6 +20,7 @@ import org.elasticsearch.shield.support.Validation;
import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import java.io.IOException;
import java.io.PrintWriter;
@ -98,7 +99,7 @@ public class FileUserPasswdStore {
public static Path resolveFile(Settings settings, Environment env) {
String location = settings.get("files.users");
if (location == null) {
return ShieldPlugin.resolveConfigFile(env, "users");
return XPackPlugin.resolveConfigFile(env, "users");
}
return env.binFile().getParent().resolve(location);
}
@ -166,7 +167,7 @@ public class FileUserPasswdStore {
}
if (users.isEmpty()) {
logger.warn("no users found in users file [{}]. use bin/shield/esusers to add users and role mappings", path.toAbsolutePath());
logger.warn("no users found in users file [{}]. use bin/xpack/esusers to add users and role mappings", path.toAbsolutePath());
}
return unmodifiableMap(users);
}

View File

@ -19,6 +19,7 @@ import org.elasticsearch.shield.support.Validation;
import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import java.io.IOException;
import java.io.PrintWriter;
@ -91,7 +92,7 @@ public class FileUserRolesStore {
public static Path resolveFile(Settings settings, Environment env) {
String location = settings.get("files.users_roles");
if (location == null) {
return ShieldPlugin.resolveConfigFile(env, "users_roles");
return XPackPlugin.resolveConfigFile(env, "users_roles");
}
return env.binFile().getParent().resolve(location);
}
@ -181,7 +182,7 @@ public class FileUserRolesStore {
}
if (usersRoles.isEmpty()) {
logger.warn("no entries found in users_roles file [{}]. use bin/shield/esusers to add users and role mappings", path
logger.warn("no entries found in users_roles file [{}]. use bin/xpack/esusers to add users and role mappings", path
.toAbsolutePath());
}

View File

@ -17,6 +17,7 @@ import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import java.io.IOException;
import java.io.InputStream;
@ -82,7 +83,7 @@ public class DnRoleMapper {
public static Path resolveFile(Settings settings, Environment env) {
String location = settings.get(ROLE_MAPPING_FILE_SETTING);
if (location == null) {
return ShieldPlugin.resolveConfigFile(env, DEFAULT_FILE_NAME);
return XPackPlugin.resolveConfigFile(env, DEFAULT_FILE_NAME);
}
return env.binFile().getParent().resolve(location);
}

View File

@ -7,6 +7,7 @@ package org.elasticsearch.shield.authc.support;
import org.elasticsearch.common.Base64;
import org.elasticsearch.common.Randomness;
import org.elasticsearch.common.hash.MessageDigests;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
@ -142,7 +143,7 @@ public enum Hasher {
@Override
public char[] hash(SecuredString text) {
byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars());
MessageDigest md = SHA1Provider.sha1();
MessageDigest md = MessageDigests.sha1();
md.update(textBytes);
String hash = Base64.encodeBytes(md.digest());
return (SHA1_PREFIX + hash).toCharArray();
@ -155,7 +156,7 @@ public enum Hasher {
return false;
}
byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars());
MessageDigest md = SHA1Provider.sha1();
MessageDigest md = MessageDigests.sha1();
md.update(textBytes);
String passwd64 = Base64.encodeBytes(md.digest());
String hashNoPrefix = hashStr.substring(SHA1_PREFIX.length());
@ -166,7 +167,7 @@ public enum Hasher {
MD5() {
@Override
public char[] hash(SecuredString text) {
MessageDigest md = MD5Provider.md5();
MessageDigest md = MessageDigests.md5();
md.update(CharArrays.toUtf8Bytes(text.internalChars()));
String hash = Base64.encodeBytes(md.digest());
return (MD5_PREFIX + hash).toCharArray();
@ -179,7 +180,7 @@ public enum Hasher {
return false;
}
hashStr = hashStr.substring(MD5_PREFIX.length());
MessageDigest md = MD5Provider.md5();
MessageDigest md = MessageDigests.md5();
md.update(CharArrays.toUtf8Bytes(text.internalChars()));
String computedHashStr = Base64.encodeBytes(md.digest());
return SecuredString.constantTimeEquals(hashStr, computedHashStr);
@ -189,7 +190,7 @@ public enum Hasher {
SSHA256() {
@Override
public char[] hash(SecuredString text) {
MessageDigest md = SHA256Provider.sha256();
MessageDigest md = MessageDigests.sha256();
md.update(CharArrays.toUtf8Bytes(text.internalChars()));
char[] salt = SaltProvider.salt(8);
md.update(CharArrays.toUtf8Bytes(salt));
@ -209,7 +210,7 @@ public enum Hasher {
}
hashStr = hashStr.substring(SSHA256_PREFIX.length());
char[] saltAndHash = hashStr.toCharArray();
MessageDigest md = SHA256Provider.sha256();
MessageDigest md = MessageDigests.sha256();
md.update(CharArrays.toUtf8Bytes(text.internalChars()));
md.update(new String(saltAndHash, 0, 8).getBytes(StandardCharsets.UTF_8));
String computedHash = Base64.encodeBytes(md.digest());
@ -279,76 +280,6 @@ public enum Hasher {
public abstract boolean verify(SecuredString data, char[] hash);
static final class MD5Provider {
private static final MessageDigest digest;
static {
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("unsupported digest algorithm [MD5]. Please verify you are running on Java 7 or above", e);
}
}
private static MessageDigest md5() {
try {
MessageDigest md5 = (MessageDigest) digest.clone();
md5.reset();
return md5;
} catch (CloneNotSupportedException e) {
throw new IllegalStateException("could not create MD5 digest", e);
}
}
}
static final class SHA1Provider {
private static final MessageDigest digest;
static {
try {
digest = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("unsupported digest algorithm [SHA-1]", e);
}
}
private static MessageDigest sha1() {
try {
MessageDigest sha1 = (MessageDigest) digest.clone();
sha1.reset();
return sha1;
} catch (CloneNotSupportedException e) {
throw new IllegalStateException("could not create SHA-1 digest", e);
}
}
}
static final class SHA256Provider {
private static final MessageDigest digest;
static {
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
String msg = "unsupported digest algorithm [SHA-256]. Please verify you are running on Java 7 or above";
throw new IllegalStateException(msg, e);
}
}
private static MessageDigest sha256() {
try {
MessageDigest sha = (MessageDigest) digest.clone();
sha.reset();
return sha;
} catch (CloneNotSupportedException e) {
throw new IllegalStateException("could not create [SHA-256] digest", e);
}
}
}
static final class SaltProvider {
static final char[] ALPHABET = new char[]{

View File

@ -48,7 +48,7 @@ import org.elasticsearch.shield.authc.AuthenticationService;
import org.elasticsearch.shield.authz.RoleDescriptor;
import org.elasticsearch.shield.authz.permission.Role;
import org.elasticsearch.shield.authz.store.RolesStore;
import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.shield.client.SecurityClient;
import org.elasticsearch.threadpool.ThreadPool;
import java.util.ArrayList;
@ -84,7 +84,7 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
private final ConcurrentHashMap<String, RoleAndVersion> roleCache = new ConcurrentHashMap<>();
private Client client;
private ShieldClient shieldClient;
private SecurityClient securityClient;
private int scrollSize;
private TimeValue scrollKeepAlive;
private ScheduledFuture<?> versionChecker;
@ -353,7 +353,7 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
try {
if (state.compareAndSet(State.INITIALIZED, State.STARTING)) {
this.client = clientProvider.get();
this.shieldClient = new ShieldClient(client);
this.securityClient = new SecurityClient(client);
this.scrollSize = settings.getAsInt("shield.authc.native.scroll.size", 1000);
this.scrollKeepAlive = settings.getAsTime("shield.authc.native.scroll.keep_alive", TimeValue.timeValueSeconds(10L));
TimeValue pollInterval = settings.getAsTime("shield.authc.native.reload.interval", TimeValue.timeValueSeconds(30L));
@ -407,7 +407,7 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
private <Response> void clearRoleCache(final String role, ActionListener<Response> listener, Response response) {
ClearRolesCacheRequest request = new ClearRolesCacheRequest().roles(role);
shieldClient.clearRolesCache(request, new ActionListener<ClearRolesCacheResponse>() {
securityClient.clearRolesCache(request, new ActionListener<ClearRolesCacheResponse>() {
@Override
public void onResponse(ClearRolesCacheResponse nodes) {
listener.onResponse(response);

View File

@ -32,16 +32,18 @@ public class IndexPrivilege extends AbstractAutomatonPrivilege<IndexPrivilege> {
public static final IndexPrivilege CREATE_INDEX = new IndexPrivilege("create_index", CreateIndexAction.NAME);
public static final IndexPrivilege MANAGE_ALIASES = new IndexPrivilege("manage_aliases", "indices:admin/aliases*");
public static final IndexPrivilege MONITOR = new IndexPrivilege("monitor", "indices:monitor/*");
public static final IndexPrivilege DATA_ACCESS = new IndexPrivilege("data_access", "indices:data/*");
public static final IndexPrivilege CRUD = new IndexPrivilege("crud", "indices:data/write/*", "indices:data/read/*");
public static final IndexPrivilege DATA_ACCESS = new IndexPrivilege("data_access", "indices:data/*", "indices:admin/mapping/put");
public static final IndexPrivilege CRUD =
new IndexPrivilege("crud", "indices:data/write/*", "indices:data/read/*", "indices:admin/mapping/put");
public static final IndexPrivilege READ = new IndexPrivilege("read", "indices:data/read/*");
public static final IndexPrivilege SEARCH = new IndexPrivilege("search", SearchAction.NAME + "*", MultiSearchAction.NAME + "*",
SuggestAction.NAME + "*");
public static final IndexPrivilege SEARCH =
new IndexPrivilege("search", SearchAction.NAME + "*", MultiSearchAction.NAME + "*", SuggestAction.NAME + "*");
public static final IndexPrivilege GET = new IndexPrivilege("get", GetAction.NAME + "*", MultiGetAction.NAME + "*");
public static final IndexPrivilege SUGGEST = new IndexPrivilege("suggest", SuggestAction.NAME + "*");
public static final IndexPrivilege INDEX = new IndexPrivilege("index", "indices:data/write/index*", "indices:data/write/update*");
public static final IndexPrivilege INDEX =
new IndexPrivilege("index", "indices:data/write/index*", "indices:data/write/update*", "indices:admin/mapping/put");
public static final IndexPrivilege DELETE = new IndexPrivilege("delete", "indices:data/write/delete*");
public static final IndexPrivilege WRITE = new IndexPrivilege("write", "indices:data/write/*");
public static final IndexPrivilege WRITE = new IndexPrivilege("write", "indices:data/write/*", "indices:admin/mapping/put");
private static final Set<IndexPrivilege> values = new CopyOnWriteArraySet<>();

View File

@ -22,8 +22,7 @@ public class SystemPrivilege extends Privilege<SystemPrivilege> {
"internal:*",
"indices:monitor/*", // added for marvel
"cluster:monitor/*", // added for marvel
"cluster:admin/reroute", // added for DiskThresholdDecider.DiskListener
"indices:admin/mapping/put" // ES 2.0 MappingUpdatedAction - updateMappingOnMasterSynchronously
"cluster:admin/reroute" // added for DiskThresholdDecider.DiskListener
));
SystemPrivilege() {

View File

@ -34,6 +34,7 @@ import org.elasticsearch.shield.support.Validation;
import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@ -109,7 +110,7 @@ public class FileRolesStore extends AbstractLifecycleComponent<RolesStore> imple
public static Path resolveFile(Settings settings, Environment env) {
String location = settings.get("shield.authz.store.files.roles");
if (location == null) {
return ShieldPlugin.resolveConfigFile(env, "roles.yml");
return XPackPlugin.resolveConfigFile(env, "roles.yml");
}
return env.binFile().getParent().resolve(location);
@ -285,10 +286,10 @@ public class FileRolesStore extends AbstractLifecycleComponent<RolesStore> imple
if (token == XContentParser.Token.VALUE_STRING) {
names.add(parser.text());
} else {
logger.error("invalid role definition [{}] in roles file [{}]. could " +
"not parse " +
"[{}] as index privilege. privilege names must be strings. " +
"skipping role...", roleName, path.toAbsolutePath(), token);
logger.error("invalid role definition [{}] in roles file [{}]. " +
"could not parse [{}] as index privilege. privilege " +
"names must be strings. skipping role...", roleName,
path.toAbsolutePath(), token);
return null;
}
}
@ -301,26 +302,27 @@ public class FileRolesStore extends AbstractLifecycleComponent<RolesStore> imple
if (name != null) {
if ((query != null || (fields != null && fields.isEmpty() == false)) &&
ShieldPlugin.flsDlsEnabled(settings) == false) {
logger.error("invalid role definition [{}] in roles file [{}]. document and field" +
" level security is not enabled. set [{}] to [true] in the configuration " +
"file. skipping role...", roleName, path.toAbsolutePath(), ShieldPlugin
.DLS_FLS_ENABLED_SETTING);
logger.error("invalid role definition [{}] in roles file [{}]. " +
"document and field level security is not enabled. " +
"set [{}] to [true] in the configuration file. skipping role...",
roleName, path.toAbsolutePath(),
XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE));
return null;
}
try {
role.add(fields, query, IndexPrivilege.get(name), indices);
} catch (IllegalArgumentException e) {
logger.error("invalid role definition [{}] in roles file [{}]. could not resolve " +
"indices privileges [{}]. skipping role...", roleName,
logger.error("invalid role definition [{}] in roles file [{}]. could not " +
"resolve indices privileges [{}]. skipping role...", roleName,
path.toAbsolutePath(), name);
return null;
}
}
continue;
} else {
logger.error("invalid role definition [{}] in roles file [{}]. could not parse [{}] as " +
"index privileges. privilege lists must either " +
logger.error("invalid role definition [{}] in roles file [{}]. " +
"could not parse [{}] as index privileges. privilege lists must either " +
"be a comma delimited string or an array of strings. skipping role...", roleName,
path.toAbsolutePath(), token);
return null;

View File

@ -44,19 +44,12 @@ import org.elasticsearch.shield.action.role.ClearRolesCacheResponse;
/**
* A wrapper to elasticsearch clients that exposes all Shield related APIs
*/
public class ShieldClient {
public class SecurityClient {
private final ElasticsearchClient client;
private final ShieldAuthcClient authcClient;
public ShieldClient(ElasticsearchClient client) {
public SecurityClient(ElasticsearchClient client) {
this.client = client;
this.authcClient = new ShieldAuthcClient(client);
}
@Deprecated
public ShieldAuthcClient authc() {
return authcClient;
}
/****************

View File

@ -1,54 +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.shield.client;
import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.shield.action.realm.ClearRealmCacheAction;
import org.elasticsearch.shield.action.realm.ClearRealmCacheRequest;
import org.elasticsearch.shield.action.realm.ClearRealmCacheRequestBuilder;
import org.elasticsearch.shield.action.realm.ClearRealmCacheResponse;
/**
* A client to manage Shield's authentication
*
* @deprecated Use {@link ShieldClient} directly instead
*/
@Deprecated
public class ShieldAuthcClient {
private final ElasticsearchClient client;
ShieldAuthcClient(ElasticsearchClient client) {
this.client = client;
}
/**
* Clears the realm caches. It's possible to clear all user entries from all realms in the cluster or alternatively
* select the realms (by their unique names) and/or users (by their usernames) that should be evicted.
*/
public ClearRealmCacheRequestBuilder prepareClearRealmCache() {
return new ClearRealmCacheRequestBuilder(client);
}
/**
* Clears the realm caches. It's possible to clear all user entries from all realms in the cluster or alternatively
* select the realms (by their unique names) and/or users (by their usernames) that should be evicted.
*/
public void clearRealmCache(ClearRealmCacheRequest request, ActionListener<ClearRealmCacheResponse> listener) {
client.execute(ClearRealmCacheAction.INSTANCE, request, listener);
}
/**
* Clears the realm caches. It's possible to clear all user entries from all realms in the cluster or alternatively
* select the realms (by their unique names) and/or users (by their usernames) that should be evicted.
*/
public ActionFuture<ClearRealmCacheResponse> clearRealmCache(ClearRealmCacheRequest request) {
return client.execute(ClearRealmCacheAction.INSTANCE, request);
}
}

View File

@ -17,6 +17,7 @@ import org.elasticsearch.shield.authc.support.CharArrays;
import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@ -159,7 +160,7 @@ public class InternalCryptoService extends AbstractLifecycleComponent<InternalCr
public static Path resolveSystemKey(Settings settings, Environment env) {
String location = settings.get(FILE_SETTING);
if (location == null) {
return ShieldPlugin.resolveConfigFile(env, FILE_NAME);
return XPackPlugin.resolveConfigFile(env, FILE_NAME);
}
return env.binFile().getParent().resolve(location);
}
@ -564,30 +565,25 @@ public class InternalCryptoService extends AbstractLifecycleComponent<InternalCr
}
/**
* Provider class for the HmacSHA1 {@link Mac} that provides an optimization by using clone instead of calling
* Mac#getInstance and obtaining a lock
* Provider class for the HmacSHA1 {@link Mac} that provides an optimization by using a thread local instead of calling
* Mac#getInstance and obtaining a lock (in the internals)
*/
private static class HmacSHA1Provider {
private static final Mac mac;
static {
private static final ThreadLocal<Mac> MAC = ThreadLocal.withInitial(() -> {
try {
mac = Mac.getInstance(HMAC_ALGO);
return Mac.getInstance(HMAC_ALGO);
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("could not create message authentication code instance with algorithm [HmacSHA1]", e);
}
throw new IllegalStateException("could not create Mac instance with algorithm [" + HMAC_ALGO + "]", e);
}
});
private static Mac hmacSHA1() {
try {
Mac hmac = (Mac) mac.clone();
hmac.reset();
return hmac;
} catch (CloneNotSupportedException e) {
throw new IllegalStateException("could not create [HmacSHA1] MAC", e);
}
Mac instance = MAC.get();
instance.reset();
return instance;
}
}
/**

View File

@ -37,7 +37,7 @@ public class RestShieldInfoAction extends BaseRestHandler {
super(settings, client);
this.clusterName = clusterName;
this.shieldLicenseState = licenseState;
this.shieldEnabled = ShieldPlugin.shieldEnabled(settings);
this.shieldEnabled = ShieldPlugin.enabled(settings);
controller.registerHandler(GET, "/_shield", this);
controller.registerHandler(HEAD, "/_shield", this);
}

View File

@ -20,7 +20,7 @@ import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.realm.ClearRealmCacheRequest;
import org.elasticsearch.shield.action.realm.ClearRealmCacheResponse;
import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.shield.client.SecurityClient;
import static org.elasticsearch.rest.RestRequest.Method.POST;
@ -41,7 +41,7 @@ public class RestClearRealmCacheAction extends BaseRestHandler {
ClearRealmCacheRequest req = new ClearRealmCacheRequest().realms(realms).usernames(usernames);
new ShieldClient(client).clearRealmCache(req, new RestBuilderListener<ClearRealmCacheResponse>(channel) {
new SecurityClient(client).clearRealmCache(req, new RestBuilderListener<ClearRealmCacheResponse>(channel) {
@Override
public RestResponse buildResponse(ClearRealmCacheResponse response, XContentBuilder builder) throws Exception {
response.toXContent(builder, ToXContent.EMPTY_PARAMS);

View File

@ -19,7 +19,7 @@ import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.role.AddRoleRequest;
import org.elasticsearch.shield.action.role.AddRoleResponse;
import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.shield.client.SecurityClient;
/**
* Rest endpoint to add a Role to the shield index
@ -38,7 +38,7 @@ public class RestAddRoleAction extends BaseRestHandler {
AddRoleRequest addRoleReq = new AddRoleRequest(request.content());
addRoleReq.name(request.param("id"));
new ShieldClient(client).addRole(addRoleReq, new RestBuilderListener<AddRoleResponse>(channel) {
new SecurityClient(client).addRole(addRoleReq, new RestBuilderListener<AddRoleResponse>(channel) {
@Override
public RestResponse buildResponse(AddRoleResponse addRoleResponse, XContentBuilder builder) throws Exception {
return new BytesRestResponse(RestStatus.OK,

View File

@ -20,7 +20,7 @@ import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.role.ClearRolesCacheRequest;
import org.elasticsearch.shield.action.role.ClearRolesCacheResponse;
import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.shield.client.SecurityClient;
import static org.elasticsearch.rest.RestRequest.Method.POST;
@ -42,7 +42,7 @@ public class RestClearRolesCacheAction extends BaseRestHandler {
ClearRolesCacheRequest req = new ClearRolesCacheRequest().roles(roles);
new ShieldClient(client).clearRolesCache(req, new RestBuilderListener<ClearRolesCacheResponse>(channel) {
new SecurityClient(client).clearRolesCache(req, new RestBuilderListener<ClearRolesCacheResponse>(channel) {
@Override
public RestResponse buildResponse(ClearRolesCacheResponse response, XContentBuilder builder) throws Exception {
response.toXContent(builder, ToXContent.EMPTY_PARAMS);

View File

@ -19,7 +19,7 @@ import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.role.DeleteRoleRequest;
import org.elasticsearch.shield.action.role.DeleteRoleResponse;
import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.shield.client.SecurityClient;
/**
* Rest endpoint to delete a Role from the shield index
@ -37,7 +37,7 @@ public class RestDeleteRoleAction extends BaseRestHandler {
String role = request.param("id");
DeleteRoleRequest delRoleRequest = new DeleteRoleRequest(role);
new ShieldClient(client).deleteRole(delRoleRequest, new RestBuilderListener<DeleteRoleResponse>(channel) {
new SecurityClient(client).deleteRole(delRoleRequest, new RestBuilderListener<DeleteRoleResponse>(channel) {
@Override
public RestResponse buildResponse(DeleteRoleResponse response, XContentBuilder builder) throws Exception {
return new BytesRestResponse(response.found() ? RestStatus.OK : RestStatus.NOT_FOUND,

View File

@ -20,7 +20,7 @@ import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.role.GetRolesResponse;
import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.shield.client.SecurityClient;
/**
* Rest endpoint to retrieve a Role from the shield index
@ -38,7 +38,7 @@ public class RestGetRolesAction extends BaseRestHandler {
protected void handleRequest(RestRequest request, final RestChannel channel, Client client) throws Exception {
String[] roles = Strings.splitStringByCommaToArray(request.param("id"));
new ShieldClient(client).prepareGetRoles().roles(roles).execute(new RestBuilderListener<GetRolesResponse>(channel) {
new SecurityClient(client).prepareGetRoles().roles(roles).execute(new RestBuilderListener<GetRolesResponse>(channel) {
@Override
public RestResponse buildResponse(GetRolesResponse getRolesResponse, XContentBuilder builder) throws Exception {
builder.startObject();

View File

@ -20,7 +20,7 @@ import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.user.AddUserRequest;
import org.elasticsearch.shield.action.user.AddUserResponse;
import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.shield.client.SecurityClient;
/**
* Rest endpoint to add a User to the shield index
@ -40,7 +40,7 @@ public class RestAddUserAction extends BaseRestHandler {
addUserReq.username(request.param("username"));
addUserReq.source(request.content());
new ShieldClient(client).addUser(addUserReq, new RestBuilderListener<AddUserResponse>(channel) {
new SecurityClient(client).addUser(addUserReq, new RestBuilderListener<AddUserResponse>(channel) {
@Override
public RestResponse buildResponse(AddUserResponse addUserResponse, XContentBuilder builder) throws Exception {
return new BytesRestResponse(RestStatus.OK,

View File

@ -19,7 +19,7 @@ import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.user.DeleteUserRequest;
import org.elasticsearch.shield.action.user.DeleteUserResponse;
import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.shield.client.SecurityClient;
/**
* Rest action to delete a user from the shield index
@ -37,7 +37,7 @@ public class RestDeleteUserAction extends BaseRestHandler {
String user = request.param("username");
DeleteUserRequest delUserRequest = new DeleteUserRequest(user);
new ShieldClient(client).deleteUser(delUserRequest, new RestBuilderListener<DeleteUserResponse>(channel) {
new SecurityClient(client).deleteUser(delUserRequest, new RestBuilderListener<DeleteUserResponse>(channel) {
@Override
public RestResponse buildResponse(DeleteUserResponse response, XContentBuilder builder) throws Exception {
return new BytesRestResponse(response.found() ? RestStatus.OK : RestStatus.NOT_FOUND,

View File

@ -21,7 +21,7 @@ import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.User;
import org.elasticsearch.shield.action.user.GetUsersResponse;
import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.shield.client.SecurityClient;
/**
* Rest action to retrieve a user from the shield index
@ -39,7 +39,7 @@ public class RestGetUsersAction extends BaseRestHandler {
protected void handleRequest(RestRequest request, final RestChannel channel, Client client) throws Exception {
String[] users = Strings.splitStringByCommaToArray(request.param("username"));
new ShieldClient(client).prepareGetUsers().users(users).execute(new RestBuilderListener<GetUsersResponse>(channel) {
new SecurityClient(client).prepareGetUsers().users(users).execute(new RestBuilderListener<GetUsersResponse>(channel) {
@Override
public RestResponse buildResponse(GetUsersResponse getUsersResponse, XContentBuilder builder) throws Exception {
builder.startObject();

View File

@ -22,7 +22,7 @@ public abstract class AbstractShieldModule extends AbstractModule {
public AbstractShieldModule(Settings settings) {
this.settings = settings;
this.clientMode = !"node".equals(settings.get(Client.CLIENT_TYPE_SETTING_S.getKey()));
this.shieldEnabled = ShieldPlugin.shieldEnabled(settings);
this.shieldEnabled = ShieldPlugin.enabled(settings);
}
@Override

View File

@ -9,7 +9,7 @@ SYNOPSIS
DESCRIPTION
Generates the system key and stores in the system_key file. By default
it will be stored in 'config/shield/.system_key' file. If the file location
it will be stored in 'config/xpack/system_key' file. If the file location
is customized in the elasticsearch.yml (under the 'shield.system_key.file'
setting), the generated key will be stored in that custom location.

View File

@ -16,6 +16,7 @@ import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.test.ShieldSettingsSource;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.elasticsearch.xpack.XPackPlugin;
import java.io.IOException;
@ -30,7 +31,7 @@ public class BulkUpdateTests extends ShieldIntegTestCase {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, randomBoolean())
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), randomBoolean())
.build();
}

View File

@ -21,7 +21,7 @@ import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authc.support.SecuredStringTests;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.shield.client.SecurityClient;
import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.test.ShieldSettingsSource;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
@ -140,11 +140,11 @@ public class ClearRealmsCacheTests extends ShieldIntegTestCase {
public abstract void executeRequest() throws Exception;
static void executeTransportRequest(ClearRealmCacheRequest request) throws Exception {
ShieldClient shieldClient = new ShieldClient(client());
SecurityClient securityClient = securityClient(client());
final CountDownLatch latch = new CountDownLatch(1);
final AtomicReference<Throwable> error = new AtomicReference<>();
shieldClient.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() {
securityClient.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() {
@Override
public void onResponse(ClearRealmCacheResponse response) {
assertThat(response.getNodes().length, equalTo(internalCluster().getNodeNames().length));

View File

@ -21,7 +21,7 @@ import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.shield.authz.RoleDescriptor;
import org.elasticsearch.shield.authz.esnative.ESNativeRolesStore;
import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.shield.client.SecurityClient;
import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.test.ShieldSettingsSource;
import org.elasticsearch.test.junit.annotations.TestLogging;
@ -57,7 +57,7 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
@Before
public void setupForTest() throws Exception {
// Clear the realm cache for all realms since we use a SUITE scoped cluster
ShieldClient client = new ShieldClient(internalCluster().transportClient());
SecurityClient client = securityClient(internalCluster().transportClient());
client.prepareClearRealmCache().get();
for (ESNativeUsersStore store : internalCluster().getInstances(ESNativeUsersStore.class)) {
@ -78,7 +78,7 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
});
}
ShieldClient c = new ShieldClient(client());
SecurityClient c = securityClient();
// create roles
for (String role : roles) {
c.prepareAddRole().name(role)
@ -109,13 +109,13 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
public void testModifyingViaApiClearsCache() throws Exception {
Client client = internalCluster().transportClient();
ShieldClient shieldClient = new ShieldClient(client);
SecurityClient securityClient = securityClient(client);
int modifiedRolesCount = randomIntBetween(1, roles.length);
List<String> toModify = randomSubsetOf(modifiedRolesCount, roles);
logger.debug("--> modifying roles {} to have run_as", toModify);
for (String role : toModify) {
AddRoleResponse response = shieldClient.prepareAddRole().name(role)
AddRoleResponse response = securityClient.prepareAddRole().name(role)
.cluster("none")
.addIndices(new String[] { "*" }, new String[] { "ALL" }, null, null)
.runAs(role)
@ -124,7 +124,7 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
logger.debug("--> updated role [{}] with run_as", role);
}
assertRolesAreCorrect(shieldClient, toModify);
assertRolesAreCorrect(securityClient, toModify);
}
public void testModifyingDocumentsDirectly() throws Exception {
@ -144,7 +144,7 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
// in this test, the poller runs too frequently to check the cache still has roles without run as
// clear the cache and we should definitely see the latest values!
ShieldClient shieldClient = new ShieldClient(client);
SecurityClient securityClient = securityClient(client);
final boolean useHttp = randomBoolean();
final boolean clearAll = randomBoolean();
logger.debug("--> starting to clear roles. using http [{}] clearing all [{}]", useHttp, clearAll);
@ -163,18 +163,18 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
.execute();
assertThat(response.getStatusCode(), is(RestStatus.OK.getStatus()));
} else {
shieldClient.prepareClearRolesCache().roles(rolesToClear).get();
securityClient.prepareClearRolesCache().roles(rolesToClear).get();
}
assertRolesAreCorrect(shieldClient, toModify);
assertRolesAreCorrect(securityClient, toModify);
}
public void testDeletingRoleDocumentDirectly() throws Exception {
Client client = internalCluster().transportClient();
ShieldClient shieldClient = new ShieldClient(client);
SecurityClient securityClient = securityClient(client);
final String role = randomFrom(roles);
List<RoleDescriptor> foundRoles = shieldClient.prepareGetRoles().roles(role).get().roles();
List<RoleDescriptor> foundRoles = securityClient.prepareGetRoles().roles(role).get().roles();
assertThat(foundRoles.size(), is(1));
logger.debug("--> deleting role [{}]", role);
DeleteResponse response = client.prepareDelete(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME,
@ -184,15 +184,15 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
assertBusy(new Runnable() {
@Override
public void run() {
assertThat(shieldClient.prepareGetRoles().roles(role).get().roles().isEmpty(), is(true));
assertThat(securityClient.prepareGetRoles().roles(role).get().roles().isEmpty(), is(true));
}
});
}
private void assertRolesAreCorrect(ShieldClient shieldClient, List<String> toModify) {
private void assertRolesAreCorrect(SecurityClient securityClient, List<String> toModify) {
for (String role : roles) {
logger.debug("--> getting role [{}]", role);
GetRolesResponse roleResponse = shieldClient.prepareGetRoles().roles(role).get();
GetRolesResponse roleResponse = securityClient.prepareGetRoles().roles(role).get();
assertThat(roleResponse.isExists(), is(true));
final String[] runAs = roleResponse.roles().get(0).getRunAs();
if (toModify.contains(role)) {

View File

@ -12,6 +12,7 @@ import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.Collections;
@ -75,7 +76,7 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase {
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true)
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), true)
.build();
}

View File

@ -14,6 +14,7 @@ import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.ArrayList;
import java.util.Collections;
@ -74,7 +75,7 @@ public class DocumentLevelSecurityRandomTests extends ShieldIntegTestCase {
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true)
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), true)
.build();
}

View File

@ -28,6 +28,7 @@ import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.Collections;
@ -87,7 +88,7 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true)
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), true)
.build();
}

View File

@ -14,6 +14,7 @@ import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.ArrayList;
import java.util.Collections;
@ -111,7 +112,7 @@ public class FieldLevelSecurityRandomTests extends ShieldIntegTestCase {
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true)
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), true)
.build();
}

View File

@ -28,6 +28,7 @@ import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.Collections;
@ -116,7 +117,7 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true)
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), true)
.build();
}

View File

@ -8,10 +8,11 @@ package org.elasticsearch.integration;
import org.apache.lucene.util.LuceneTestCase.BadApple;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.node.Node;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.junit.Before;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@ -21,6 +22,7 @@ import static org.hamcrest.Matchers.is;
//test is just too slow, please fix it to not be sleep-based
@BadApple(bugUrl = "https://github.com/elastic/x-plugins/issues/1007")
@ESIntegTestCase.ClusterScope(randomDynamicTemplates = false)
public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
private String jsonDoc = "{ \"name\" : \"elasticsearch\"}";
@ -94,8 +96,7 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
"u11:" + USERS_PASSWD_HASHED + "\n" +
"u12:" + USERS_PASSWD_HASHED + "\n" +
"u13:" + USERS_PASSWD_HASHED + "\n" +
"u14:" + USERS_PASSWD_HASHED + "\n" +
"u15:" + USERS_PASSWD_HASHED + "\n";
"u14:" + USERS_PASSWD_HASHED + "\n";
public static final String USERS_ROLES =
"all_indices_role:admin,u8\n" +
@ -120,7 +121,6 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder().put(super.nodeSettings(nodeOrdinal))
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
.put("action.disable_shutdown", true)
.build();
}
@ -139,6 +139,17 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
return super.configUsersRoles() + USERS_ROLES;
}
// we reduce the number of shards and replicas to help speed up this test since that is not the focus of this test
@Override
public int maximumNumberOfReplicas() {
return 1;
}
@Override
public int maximumNumberOfShards() {
return 2;
}
@Before
public void insertBaseDocumentsAsAdmin() throws Exception {
// indices: a,b,c,abc
@ -296,24 +307,13 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
assertUserIsDenied("u14", "all", "c");
}
public void testUserU15() throws Exception {
//u15 has access to manage and search a, so that adding warmer templates work
assertUserIsAllowed("u15", "manage", "a");
assertUserIsAllowed("u15", "search", "a");
assertAccessIsAllowed("u15", "PUT", "/a/_warmer/w1", "{ \"query\" : { \"match_all\" : {} } }");
assertAccessIsAllowed("u15", "DELETE", "/a/_warmer/w1");
assertUserIsDenied("u15", "all", "b");
assertUserIsDenied("u15", "all", "c");
}
public void testThatUnknownUserIsRejectedProperly() throws Exception {
HttpResponse response = executeRequest("idonotexist", "GET", "/", null, new HashMap<>());
assertThat(response.getStatusCode(), is(401));
}
private void assertUserExecutes(String user, String action, String index, boolean userIsAllowed) throws Exception {
Map<String, String> refreshParams = singletonMap("refresh", "true");
Map<String, String> refreshParams = Collections.emptyMap();//singletonMap("refresh", "true");
switch (action) {
case "all" :
@ -353,11 +353,6 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
assertAccessIsAllowed("admin", "PUT", "/" + index + "/foo/1", jsonDoc, refreshParams);
client().admin().cluster().prepareHealth(index).setWaitForGreenStatus().get();
assertAccessIsAllowed(user, "GET", "/" + index + "/_mapping/foo/field/name");
// putting warmers only works if the user is allowed to search as well, as the query gets validated, added an own
// test for this
assertAccessIsAllowed("admin", "PUT", "/" + index + "/_warmer/w1", "{ \"query\" : { \"match_all\" : {} } }");
assertAccessIsAllowed(user, "GET", "/" + index + "/_warmer/w1");
assertAccessIsAllowed(user, "DELETE", "/" + index + "/_warmer/w1");
assertAccessIsAllowed(user, "GET", "/" + index + "/_settings");
} else {
assertAccessIsDenied(user, "DELETE", "/" + index);
@ -372,9 +367,6 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
assertAccessIsDenied(user, "POST", "/" + index + "/_open");
assertAccessIsDenied(user, "POST", "/" + index + "/_cache/clear");
assertAccessIsDenied(user, "GET", "/" + index + "/_mapping/foo/field/name");
assertAccessIsDenied(user, "PUT", "/" + index + "/_warmer/w1", "{ \"query\" : { \"match_all\" : {} } }");
assertAccessIsDenied(user, "GET", "/" + index + "/_warmer/w1");
assertAccessIsDenied(user, "DELETE", "/" + index + "/_warmer/w1");
assertAccessIsDenied(user, "GET", "/" + index + "/_settings");
}
break;

View File

@ -12,6 +12,7 @@ import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.Collections;
@ -60,7 +61,7 @@ public class IndicesPermissionsWithAliasesWildcardsAndRegexsTests extends Shield
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true)
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), true)
.build();
}

View File

@ -5,7 +5,6 @@
*/
package org.elasticsearch.integration;
import org.apache.lucene.util.LuceneTestCase.BadApple;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse;
@ -33,8 +32,6 @@ import static org.hamcrest.Matchers.hasSize;
* actions that are normally categorized as index actions as cluster actions - for example,
* index template actions.
*/
//test is just too slow, please fix it to not be sleep-based
@BadApple(bugUrl = "https://github.com/elastic/x-plugins/issues/1007")
public class PermissionPrecedenceTests extends ShieldIntegTestCase {
protected static final String USERS_PASSWD_HASHED = new String(Hasher.BCRYPT.hash(new SecuredString("test123".toCharArray())));

View File

@ -66,7 +66,7 @@ public class ShieldPluginEnabledDisabledTests extends ShieldIntegTestCase {
logger.info("******* shield is " + (enabled ? "enabled" : "disabled"));
return Settings.settingsBuilder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.ENABLED_SETTING_NAME, enabled)
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.NAME), enabled)
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
.build();
}
@ -75,7 +75,7 @@ public class ShieldPluginEnabledDisabledTests extends ShieldIntegTestCase {
protected Settings transportClientSettings() {
return Settings.settingsBuilder()
.put(super.transportClientSettings())
.put(ShieldPlugin.ENABLED_SETTING_NAME, enabled)
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.NAME), enabled)
.build();
}

View File

@ -7,6 +7,7 @@ package org.elasticsearch.shield;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
@ -14,8 +15,9 @@ import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.arrayContaining;
public class ShieldPluginSettingsTests extends ESTestCase {
private static final String TRIBE_T1_SHIELD_ENABLED = "tribe.t1." + ShieldPlugin.ENABLED_SETTING_NAME;
private static final String TRIBE_T2_SHIELD_ENABLED = "tribe.t2." + ShieldPlugin.ENABLED_SETTING_NAME;
private static final String TRIBE_T1_SHIELD_ENABLED = "tribe.t1." + XPackPlugin.featureEnabledSetting(ShieldPlugin.NAME);
private static final String TRIBE_T2_SHIELD_ENABLED = "tribe.t2." + XPackPlugin.featureEnabledSetting(ShieldPlugin.NAME);
public void testShieldIsMandatoryOnTribes() {
Settings settings = Settings.builder().put("tribe.t1.cluster.name", "non_existing")
@ -26,8 +28,8 @@ public class ShieldPluginSettingsTests extends ESTestCase {
Settings additionalSettings = shieldPlugin.additionalSettings();
assertThat(additionalSettings.getAsArray("tribe.t1.plugin.mandatory", null), arrayContaining(ShieldPlugin.NAME));
assertThat(additionalSettings.getAsArray("tribe.t2.plugin.mandatory", null), arrayContaining(ShieldPlugin.NAME));
assertThat(additionalSettings.getAsArray("tribe.t1.plugin.mandatory", null), arrayContaining(XPackPlugin.NAME));
assertThat(additionalSettings.getAsArray("tribe.t2.plugin.mandatory", null), arrayContaining(XPackPlugin.NAME));
}
public void testAdditionalMandatoryPluginsOnTribes() {
@ -41,14 +43,14 @@ public class ShieldPluginSettingsTests extends ESTestCase {
Settings.builder().put(settings).put(shieldPlugin.additionalSettings()).build();
fail("shield cannot change the value of a setting that is already defined, so a exception should be thrown");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("shield"));
assertThat(e.getMessage(), containsString(XPackPlugin.NAME));
assertThat(e.getMessage(), containsString("plugin.mandatory"));
}
}
public void testMandatoryPluginsOnTribesShieldAlreadyMandatory() {
Settings settings = Settings.builder().put("tribe.t1.cluster.name", "non_existing")
.putArray("tribe.t1.plugin.mandatory", "test_plugin", ShieldPlugin.NAME).build();
.putArray("tribe.t1.plugin.mandatory", "test_plugin", XPackPlugin.NAME).build();
ShieldPlugin shieldPlugin = new ShieldPlugin(settings);
@ -59,7 +61,7 @@ public class ShieldPluginSettingsTests extends ESTestCase {
assertThat(finalMandatoryPlugins, notNullValue());
assertThat(finalMandatoryPlugins.length, equalTo(2));
assertThat(finalMandatoryPlugins[0], equalTo("test_plugin"));
assertThat(finalMandatoryPlugins[1], equalTo(ShieldPlugin.NAME));
assertThat(finalMandatoryPlugins[1], equalTo(XPackPlugin.NAME));
}
public void testShieldIsEnabledByDefaultOnTribes() {
@ -93,7 +95,7 @@ public class ShieldPluginSettingsTests extends ESTestCase {
Settings settings = Settings.builder().put("tribe.t1.cluster.name", "non_existing")
.put(TRIBE_T1_SHIELD_ENABLED, false)
.put("tribe.t2.cluster.name", "non_existing")
.putArray("tribe.t1.plugin.mandatory", "test_plugin", ShieldPlugin.NAME).build();
.putArray("tribe.t1.plugin.mandatory", "test_plugin", XPackPlugin.NAME).build();
ShieldPlugin shieldPlugin = new ShieldPlugin(settings);

View File

@ -1,108 +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.shield.audit.index;
import org.apache.lucene.util.LuceneTestCase.BadApple;
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateResponse;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.audit.logfile.LoggingAuditTrail;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.ESIntegTestCase.Scope;
import org.elasticsearch.test.ShieldIntegTestCase;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.util.Collections;
import java.util.Set;
import static org.hamcrest.Matchers.is;
//test is just too slow, please fix it to not be sleep-based
@BadApple(bugUrl = "https://github.com/elastic/x-plugins/issues/1007")
@ClusterScope(scope = Scope.TEST, randomDynamicTemplates = false)
public class IndexAuditTrailEnabledTests extends ShieldIntegTestCase {
IndexNameResolver.Rollover rollover = randomFrom(IndexNameResolver.Rollover.values());
@Override
protected Set<String> excludeTemplates() {
return Collections.singleton(IndexAuditTrail.INDEX_TEMPLATE_NAME);
}
@Override
protected Settings nodeSettings(int nodeOrdinal) {
Settings.Builder builder = Settings.builder()
.put(super.nodeSettings(nodeOrdinal));
builder.put("shield.audit.enabled", true);
if (randomBoolean()) {
builder.putArray("shield.audit.outputs", LoggingAuditTrail.NAME, IndexAuditTrail.NAME);
} else {
builder.putArray("shield.audit.outputs", IndexAuditTrail.NAME);
}
builder.put(IndexAuditTrail.ROLLOVER_SETTING, rollover);
return builder.build();
}
@Override
public void beforeIndexDeletion() {
// For this test, this is a NO-OP because the index audit trail will continue to capture events and index after
// the tests have completed. The default implementation of this method expects that nothing is performing operations
// after the test has completed
}
public void testAuditTrailIndexAndTemplateExists() throws Exception {
awaitIndexTemplateCreation();
// Wait for the index to be created since we have our own startup
awaitAuditDocumentCreation();
}
public void testAuditTrailTemplateIsRecreatedAfterDelete() throws Exception {
// this is already "tested" by the test framework since we wipe the templates before and after, but lets be explicit about the
// behavior
awaitIndexTemplateCreation();
// delete the template
DeleteIndexTemplateResponse deleteResponse = client().admin().indices()
.prepareDeleteTemplate(IndexAuditTrail.INDEX_TEMPLATE_NAME).execute().actionGet();
assertThat(deleteResponse.isAcknowledged(), is(true));
awaitIndexTemplateCreation();
}
void awaitAuditDocumentCreation() throws Exception {
final String indexName = IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, DateTime.now(DateTimeZone.UTC), rollover);
boolean success = awaitBusy(() -> {
try {
SearchResponse searchResponse = client().prepareSearch(indexName).setSize(0).setTerminateAfter(1).execute().actionGet();
return searchResponse.getHits().totalHits() > 0;
} catch (Exception e) {
return false;
}
});
assertThat("no audit document exists!", success, is(true));
}
void awaitIndexTemplateCreation() throws InterruptedException {
boolean found = awaitBusy(() -> {
GetIndexTemplatesResponse response = client().admin().indices()
.prepareGetTemplates(IndexAuditTrail.INDEX_TEMPLATE_NAME).execute().actionGet();
if (response.getIndexTemplates().size() > 0) {
for (IndexTemplateMetaData indexTemplateMetaData : response.getIndexTemplates()) {
if (IndexAuditTrail.INDEX_TEMPLATE_NAME.equals(indexTemplateMetaData.name())) {
return true;
}
}
}
return false;
});
assertThat("index template [" + IndexAuditTrail.INDEX_TEMPLATE_NAME + "] was not created", found, is(true));
}
}

View File

@ -42,6 +42,7 @@ import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportInfo;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.xpack.XPackPlugin;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.ISODateTimeFormat;
@ -166,18 +167,21 @@ public class IndexAuditTrailTests extends ShieldIntegTestCase {
public Settings nodeSettings(int nodeOrdinal) {
Settings.Builder builder = Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.ENABLED_SETTING_NAME, useShield);
// For tests we forcefully configure Shield's custom query cache because the test framework randomizes the query
// cache impl,
// but if shield is disabled then we don't need to forcefully set the query cache
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.NAME), useShield);
// For tests we forcefully configure Shield's custom query cache because the test framework
// randomizes the query cache impl but if shield is disabled then we don't need to forcefully
// set the query cache
if (useShield == false) {
builder.remove(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey());
}
return builder.build();
}
};
cluster2 = new InternalTestCluster("network", randomLong(), createTempDir(), numNodes, numNodes, cluster2Name,
cluster2SettingsSource, 0, false, SECOND_CLUSTER_NODE_PREFIX, getMockPlugins(), Function.identity());
cluster2SettingsSource, 0, false, SECOND_CLUSTER_NODE_PREFIX, getMockPlugins(),
useShield ? getClientWrapper() : Function.identity());
cluster2.beforeTest(getRandom(), 0.5);
remoteClient = cluster2.client();
@ -187,7 +191,7 @@ public class IndexAuditTrailTests extends ShieldIntegTestCase {
Settings.Builder builder = Settings.builder()
.put(settings)
.put(ShieldPlugin.ENABLED_SETTING_NAME, useShield)
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.NAME), useShield)
.put(remoteSettings(NetworkAddress.formatAddress(inet.address().getAddress()), inet.address().getPort(), cluster2Name))
.put("shield.audit.index.client.shield.user", DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD);

View File

@ -22,7 +22,7 @@ import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authz.RoleDescriptor;
import org.elasticsearch.shield.authz.esnative.ESNativeRolesStore;
import org.elasticsearch.shield.authz.permission.Role;
import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.shield.client.SecurityClient;
import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.test.ShieldSettingsSource;
import org.junit.After;
@ -43,7 +43,7 @@ import static org.hamcrest.Matchers.isOneOf;
public class ESNativeTests extends ShieldIntegTestCase {
public void testDeletingNonexistingUserAndRole() throws Exception {
ShieldClient c = new ShieldClient(client());
SecurityClient c = securityClient();
DeleteUserResponse resp = c.prepareDeleteUser().user("joe").get();
assertFalse("user shouldn't be found", resp.found());
DeleteRoleResponse resp2 = c.prepareDeleteRole().role("role").get();
@ -51,7 +51,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
}
public void testGettingUserThatDoesntExist() throws Exception {
ShieldClient c = new ShieldClient(client());
SecurityClient c = securityClient();
GetUsersResponse resp = c.prepareGetUsers().users("joe").get();
assertFalse("user should not exist", resp.isExists());
GetRolesResponse resp2 = c.prepareGetRoles().roles("role").get();
@ -59,7 +59,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
}
public void testAddAndGetUser() throws Exception {
ShieldClient c = new ShieldClient(client());
SecurityClient c = securityClient();
logger.error("--> creating user");
c.prepareAddUser()
.username("joe")
@ -117,7 +117,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
}
public void testAddAndGetRole() throws Exception {
ShieldClient c = new ShieldClient(client());
SecurityClient c = securityClient();
logger.error("--> creating role");
c.prepareAddRole()
.name("test_role")
@ -171,7 +171,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
}
public void testAddUserAndRoleThenAuth() throws Exception {
ShieldClient c = new ShieldClient(client());
SecurityClient c = securityClient();
logger.error("--> creating role");
c.prepareAddRole()
.name("test_role")
@ -204,7 +204,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
}
public void testUpdatingUserAndAuthentication() throws Exception {
ShieldClient c = new ShieldClient(client());
SecurityClient c = securityClient();
logger.error("--> creating user");
c.prepareAddUser()
.username("joe")
@ -248,7 +248,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
}
public void testCreateDeleteAuthenticate() {
ShieldClient c = new ShieldClient(client());
SecurityClient c = securityClient();
logger.error("--> creating user");
c.prepareAddUser()
.username("joe")
@ -285,7 +285,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
public void testCreateAndUpdateRole() {
final boolean authenticate = randomBoolean();
ShieldClient c = new ShieldClient(client());
SecurityClient c = securityClient();
logger.error("--> creating role");
c.prepareAddRole()
.name("test_role")
@ -340,7 +340,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
}
public void testAuthenticateWithDeletedRole() {
ShieldClient c = new ShieldClient(client());
SecurityClient c = securityClient();
logger.error("--> creating role");
c.prepareAddRole()
.name("test_role")
@ -373,7 +373,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
@Before
public void ensureStoresStarted() throws Exception {
// Clear the realm cache for all realms since we use a SUITE scoped cluster
ShieldClient client = new ShieldClient(client());
SecurityClient client = securityClient();
client.prepareClearRealmCache().get();
for (ESNativeUsersStore store : internalCluster().getInstances(ESNativeUsersStore.class)) {

View File

@ -5,7 +5,6 @@
*/
package org.elasticsearch.shield.authc.support;
import org.apache.lucene.util.LuceneTestCase.BadApple;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.shield.User;
@ -25,8 +24,6 @@ import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
//test is just too slow, please fix it to not be sleep-based
@BadApple(bugUrl = "https://github.com/elastic/x-plugins/issues/1007")
public class CachingUsernamePasswordRealmTests extends ESTestCase {
private Settings globalSettings;
@ -206,7 +203,9 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
};
final CountDownLatch latch = new CountDownLatch(1);
final int numberOfThreads = randomIntBetween(8, 24);
final int numberOfProcessors = Runtime.getRuntime().availableProcessors();
final int numberOfThreads = scaledRandomIntBetween((numberOfProcessors + 1) / 2, numberOfProcessors * 3);
final int numberOfIterations = scaledRandomIntBetween(20, 100);
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < numberOfThreads; i++) {
final boolean invalidPassword = randomBoolean();
@ -215,9 +214,9 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
public void run() {
try {
latch.await();
for (int i = 0; i < 100; i++) {
User user = realm.authenticate(
new UsernamePasswordToken(username, invalidPassword ? randomPassword : password));
for (int i = 0; i < numberOfIterations; i++) {
UsernamePasswordToken token = new UsernamePasswordToken(username, invalidPassword ? randomPassword : password);
User user = realm.authenticate(token);
if (invalidPassword && user != null) {
throw new RuntimeException("invalid password led to an authenticated user: " + user.toString());
} else if (invalidPassword == false && user == null) {

View File

@ -245,7 +245,7 @@ public class PrivilegeTests extends ESTestCase {
assertThat(predicate.test("whatever"), is(false));
assertThat(predicate.test("cluster:admin/reroute"), is(true));
assertThat(predicate.test("cluster:admin/whatever"), is(false));
assertThat(predicate.test("indices:admin/mapping/put"), is(true));
assertThat(predicate.test("indices:admin/mapping/put"), is(false));
assertThat(predicate.test("indices:admin/mapping/whatever"), is(false));
}

View File

@ -19,6 +19,7 @@ import org.elasticsearch.shield.authz.privilege.IndexPrivilege;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import java.io.BufferedWriter;
import java.io.OutputStream;
@ -52,8 +53,9 @@ public class FileRolesStoreTests extends ESTestCase {
public void testParseFile() throws Exception {
Path path = getDataPath("roles.yml");
Map<String, Role> roles = FileRolesStore.parseFile(path, logger,
Settings.builder().put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true).build());
Map<String, Role> roles = FileRolesStore.parseFile(path, logger, Settings.builder()
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), true)
.build());
assertThat(roles, notNullValue());
assertThat(roles.size(), is(10));
@ -208,8 +210,9 @@ public class FileRolesStoreTests extends ESTestCase {
public void testParseFileWithFLSAndDLSDisabled() throws Exception {
Path path = getDataPath("roles.yml");
CapturingLogger logger = new CapturingLogger(CapturingLogger.Level.ERROR);
Map<String, Role> roles = FileRolesStore.parseFile(path,
logger, Settings.builder().put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, false).build());
Map<String, Role> roles = FileRolesStore.parseFile(path, logger, Settings.builder()
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), false)
.build());
assertThat(roles, notNullValue());
assertThat(roles.size(), is(7));
assertThat(roles.get("role_fields"), nullValue());

View File

@ -251,17 +251,17 @@ public class ClientSSLServiceTests extends ESTestCase {
}
}
@AwaitsFix(bugUrl = "https://github.com/elastic/x-plugins/issues/2")
public void testThatSSLSocketFactoryHasProperCiphersAndProtocols() throws Exception {
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build());
SSLSocketFactory factory = sslService.sslSocketFactory();
assertThat(factory.getDefaultCipherSuites(), is(sslService.ciphers()));
final String[] ciphers = sslService.supportedCiphers(factory.getSupportedCipherSuites(), sslService.ciphers());
assertThat(factory.getDefaultCipherSuites(), is(ciphers));
try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
assertThat(socket.getEnabledCipherSuites(), is(sslService.ciphers()));
assertThat(socket.getEnabledCipherSuites(), is(ciphers));
assertThat(socket.getEnabledProtocols(), is(sslService.supportedProtocols()));
}
}

View File

@ -32,7 +32,6 @@ import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.mockito.Mockito.mock;
public class ServerSSLServiceTests extends ESTestCase {
Path testnodeStore;
@ -223,17 +222,17 @@ public class ServerSSLServiceTests extends ESTestCase {
}
}
@AwaitsFix(bugUrl = "https://github.com/elastic/x-plugins/issues/2")
public void testThatSSLSocketFactoryHasProperCiphersAndProtocols() throws Exception {
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.build(), env);
SSLSocketFactory factory = sslService.sslSocketFactory();
assertThat(factory.getDefaultCipherSuites(), is(sslService.ciphers()));
final String[] ciphers = sslService.supportedCiphers(factory.getSupportedCipherSuites(), sslService.ciphers());
assertThat(factory.getDefaultCipherSuites(), is(ciphers));
try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
assertThat(socket.getEnabledCipherSuites(), is(sslService.ciphers()));
assertThat(socket.getEnabledCipherSuites(), is(ciphers));
assertThat(socket.getEnabledProtocols(), is(sslService.supportedProtocols()));
}
}

View File

@ -15,9 +15,11 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.shield.InternalClient;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.client.SecurityClient;
import org.elasticsearch.test.ESIntegTestCase.SuppressLocalMode;
import org.elasticsearch.test.transport.AssertingLocalTransport;
import org.elasticsearch.test.transport.MockTransportService;
import org.elasticsearch.xpack.XPackClient;
import org.elasticsearch.xpack.XPackPlugin;
import org.junit.AfterClass;
import org.junit.Before;
@ -267,6 +269,7 @@ public abstract class ShieldIntegTestCase extends ESIntegTestCase {
}
private class CustomShieldSettingsSource extends ShieldSettingsSource {
private CustomShieldSettingsSource(boolean sslTransportEnabled, Path configDir, Scope scope) {
super(maxNumberOfNodes(), sslTransportEnabled, configDir, scope);
}
@ -339,4 +342,12 @@ public abstract class ShieldIntegTestCase extends ESIntegTestCase {
protected InternalClient internalClient(String node) {
return internalCluster().getInstance(InternalClient.class, node);
}
protected SecurityClient securityClient() {
return securityClient(client());
}
public static SecurityClient securityClient(Client client) {
return randomBoolean() ? new XPackClient(client).security() : new SecurityClient(client);
}
}

View File

@ -9,6 +9,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.transport.ShieldServerTransportService;
import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.Map;
@ -21,7 +22,7 @@ public class ShieldServerTransportServiceTests extends ShieldIntegTestCase {
protected Settings transportClientSettings() {
return Settings.settingsBuilder()
.put(super.transportClientSettings())
.put(ShieldPlugin.ENABLED_SETTING_NAME, true)
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.NAME), true)
.build();
}

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;
import org.elasticsearch.client.Client;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.shield.client.SecurityClient;
import org.elasticsearch.watcher.client.WatcherClient;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
/**
*
*/
public class XPackClient {
private final Client client;
private final SecurityClient securityClient;
private final WatcherClient watcherClient;
public XPackClient(Client client) {
this.client = client;
this.securityClient = new SecurityClient(client);
this.watcherClient = new WatcherClient(client);
}
public SecurityClient security() {
return securityClient;
}
public WatcherClient watcher() {
return watcherClient;
}
public XPackClient withHeaders(Map<String, String> headers) {
return new XPackClient(client.filterWithHeader(headers));
}
/**
* Returns a client that will call xpack APIs on behalf of the given user.
*
* @param username The username of the user
* @param passwd The password of the user. This char array can be cleared after calling this method.
*/
public XPackClient withAuth(String username, char[] passwd) {
return withHeaders(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue(username, new SecuredString(passwd))));
}
}

View File

@ -7,13 +7,13 @@ package org.elasticsearch.xpack;
import org.elasticsearch.SpecialPermission;
import org.elasticsearch.action.ActionModule;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexModule;
import org.elasticsearch.license.plugin.LicensePlugin;
import org.elasticsearch.marvel.MarvelPlugin;
@ -22,6 +22,7 @@ import org.elasticsearch.script.ScriptModule;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.watcher.WatcherPlugin;
import java.nio.file.Path;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
@ -29,9 +30,7 @@ import java.util.Collection;
public class XPackPlugin extends Plugin {
public static final String NAME = "x-pack";
private final static ESLogger logger = Loggers.getLogger(XPackPlugin.class);
public static final String NAME = "xpack";
// TODO: clean up this library to not ask for write access to all system properties!
static {
@ -143,4 +142,30 @@ public class XPackPlugin extends Plugin {
watcherPlugin.onIndexModule(module);
marvelPlugin.onIndexModule(module);
}
public static boolean transportClientMode(Settings settings) {
return !"node".equals(settings.get(Client.CLIENT_TYPE_SETTING_S.getKey()));
}
public static Path resolveConfigFile(Environment env, String name) {
return env.configFile().resolve(NAME).resolve(name);
}
/**
* A consistent way to enable disable features using the following setting:
*
* {@code "xpack.<feature>.enabled": true | false}
*
* Also supports the following setting as a fallback (for BWC with 1.x/2.x):
*
* {@code "<feature>.enabled": true | false}
*/
public static boolean featureEnabled(Settings settings, String featureName, boolean defaultValue) {
return settings.getAsBoolean(featureEnabledSetting(featureName),
settings.getAsBoolean(featureName + ".enabled", defaultValue)); // for bwc
}
public static String featureEnabledSetting(String featureName) {
return NAME + "." + featureName + ".enabled";
}
}

View File

@ -10,4 +10,4 @@
- do:
nodes.info: {}
- match: { nodes.$master.plugins.0.name: x-pack }
- match: { nodes.$master.plugins.0.name: xpack }

View File

@ -76,7 +76,7 @@ REM JAVA_OPTS=%JAVA_OPTS% -XX:HeapDumpPath=$ES_HOME/logs/heapdump.hprof
REM Disables explicit GC
set JAVA_OPTS=%JAVA_OPTS% -XX:+DisableExplicitGC
set ES_CLASSPATH=%ES_CLASSPATH%;%ES_HOME%/lib/elasticsearch-1.4.0-SNAPSHOT.jar;%ES_HOME%/lib/*;%ES_HOME%/lib/sigar/*;%ES_HOME%/plugins/x-pack/*
set ES_CLASSPATH=%ES_CLASSPATH%;%ES_HOME%/lib/*;%ES_HOME%/lib/sigar/*;%ES_HOME%/plugins/xpack/*
set ES_PARAMS=-Des.path.home="%ES_HOME%"
SET HOSTNAME=%COMPUTERNAME%

View File

@ -114,7 +114,7 @@ fi
export HOSTNAME=`hostname -s`
# include watcher jars in classpath
ES_CLASSPATH="$ES_CLASSPATH:$ES_HOME/plugins/x-pack/*"
ES_CLASSPATH="$ES_CLASSPATH:$ES_HOME/plugins/xpack/*"
cd "$ES_HOME" > /dev/null
$JAVA $ES_JAVA_OPTS -cp "$ES_CLASSPATH" org.elasticsearch.watcher.trigger.schedule.tool.CronEvalTool "$@" $properties

View File

@ -6,6 +6,7 @@
package org.elasticsearch.watcher;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.multibindings.Multibinder;
import org.elasticsearch.common.settings.Setting;
@ -14,10 +15,17 @@ import org.elasticsearch.watcher.support.WatcherIndexTemplateRegistry;
import org.elasticsearch.watcher.support.WatcherIndexTemplateRegistry.TemplateConfig;
import org.elasticsearch.watcher.support.validation.WatcherSettingsValidation;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class WatcherModule extends AbstractModule {
public static final String HISTORY_TEMPLATE_NAME = "watch_history";
static final String PROPERTIES_FILE = "/watcher.properties";
static final String VERSION_FIELD = "watcher.template.version";
public static final String HISTORY_TEMPLATE_NAME = "watch_history_" + getHistoryIndexTemplateVersion();
public static final String TRIGGERED_TEMPLATE_NAME = "triggered_watches";
public static final String WATCHES_TEMPLATE_NAME = "watches";
public static final Setting<Settings> HISTORY_TEMPLATE_SETTING = Setting.groupSetting("watcher.history.index.", true,
@ -30,7 +38,7 @@ public class WatcherModule extends AbstractModule {
public final static TemplateConfig[] TEMPLATE_CONFIGS = new TemplateConfig[]{
new TemplateConfig(TRIGGERED_TEMPLATE_NAME, TRIGGERED_TEMPLATE_SETTING),
new TemplateConfig(HISTORY_TEMPLATE_NAME, HISTORY_TEMPLATE_SETTING),
new TemplateConfig(HISTORY_TEMPLATE_NAME, "watch_history", HISTORY_TEMPLATE_SETTING),
new TemplateConfig(WATCHES_TEMPLATE_NAME, WATCHES_TEMPLATE_SETTING)
};
@ -53,4 +61,19 @@ public class WatcherModule extends AbstractModule {
}
}
public static final Integer getHistoryIndexTemplateVersion() {
try (InputStream is = WatcherModule.class.getResourceAsStream(PROPERTIES_FILE)) {
Properties properties = new Properties();
properties.load(is);
String version = properties.getProperty(VERSION_FIELD);
if (Strings.hasLength(version)) {
return Integer.parseInt(version);
}
return null;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("failed to parse watcher template version");
} catch (IOException e) {
throw new IllegalArgumentException("failed to load watcher template version");
}
}
}

View File

@ -22,6 +22,8 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.ScriptModule;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authz.privilege.ClusterPrivilege;
import org.elasticsearch.watcher.actions.WatcherActionModule;
import org.elasticsearch.watcher.actions.email.service.EmailService;
import org.elasticsearch.watcher.actions.email.service.InternalEmailService;
@ -50,8 +52,7 @@ import org.elasticsearch.watcher.rest.action.RestPutWatchAction;
import org.elasticsearch.watcher.rest.action.RestWatchServiceAction;
import org.elasticsearch.watcher.rest.action.RestWatcherInfoAction;
import org.elasticsearch.watcher.rest.action.RestWatcherStatsAction;
import org.elasticsearch.watcher.shield.ShieldSecretService;
import org.elasticsearch.watcher.shield.WatcherShieldModule;
import org.elasticsearch.watcher.support.secret.SecretService;
import org.elasticsearch.watcher.support.WatcherIndexTemplateRegistry.TemplateConfig;
import org.elasticsearch.watcher.support.clock.ClockModule;
import org.elasticsearch.watcher.support.http.HttpClient;
@ -91,13 +92,19 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import static org.elasticsearch.common.settings.Setting.Scope.CLUSTER;
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
public class WatcherPlugin extends Plugin {
public static final String NAME = "watcher";
public static final String ENABLED_SETTING = NAME + ".enabled";
public static final Setting<String> INDEX_WATCHER_VERSION_SETTING =
new Setting<>("index.watcher.plugin.version", "", Function.identity(), false, Setting.Scope.INDEX);
public static final Setting<String> INDEX_WATCHER_TEMPLATE_VERSION_SETTING =
new Setting<>("index.watcher.template.version", "", Function.identity(), false, Setting.Scope.INDEX);
private final static ESLogger logger = Loggers.getLogger(XPackPlugin.class);
@ -114,7 +121,14 @@ public class WatcherPlugin extends Plugin {
transportClient = "transport".equals(settings.get(Client.CLIENT_TYPE_SETTING_S.getKey()));
enabled = watcherEnabled(settings);
validAutoCreateIndex(settings);
// adding the watcher privileges to shield
if (ShieldPlugin.enabled(settings)) {
registerClusterPrivilege("manage_watcher", "cluster:admin/watcher/*", "cluster:monitor/watcher/*");
registerClusterPrivilege("monitor_watcher", "cluster:monitor/watcher/*");
}
}
@Override public String name() {
return NAME;
@ -146,7 +160,6 @@ public class WatcherPlugin extends Plugin {
new WatcherActionModule(),
new HistoryModule(),
new ExecutionModule(),
new WatcherShieldModule(settings),
new SecretModule(settings));
}
@ -193,37 +206,41 @@ public class WatcherPlugin extends Plugin {
module.registerSetting(InternalEmailService.EMAIL_ACCOUNT_SETTING);
module.registerSetting(InternalHipChatService.HIPCHAT_ACCOUNT_SETTING);
module.registerSetting(InternalPagerDutyService.PAGERDUTY_ACCOUNT_SETTING);
module.registerSetting(Setting.intSetting("watcher.execution.scroll.size", 0, false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.intSetting("watcher.watch.scroll.size", 0, false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.boolSetting("watcher.enabled", false, false, Setting.Scope.CLUSTER));
module.registerSetting(ShieldSecretService.ENCRYPT_SENSITIVE_DATA_SETTING);
module.registerSetting(INDEX_WATCHER_VERSION_SETTING);
module.registerSetting(INDEX_WATCHER_TEMPLATE_VERSION_SETTING);
module.registerSetting(Setting.intSetting("watcher.execution.scroll.size", 0, false, CLUSTER));
module.registerSetting(Setting.intSetting("watcher.watch.scroll.size", 0, false, CLUSTER));
module.registerSetting(Setting.boolSetting("watcher.enabled", false, false, CLUSTER));
module.registerSetting(SecretService.Secure.ENCRYPT_SENSITIVE_DATA_SETTING);
// TODO add real settings for these
module.registerSetting(Setting.simpleString("resource.reload.interval", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("resource.reload.enabled", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("resource.reload.interval.low", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("resource.reload.interval.medium", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.internal.ops.search.default_timeout", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.internal.ops.bulk.default_timeout", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.internal.ops.index.default_timeout", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.execution.default_throttle_period", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.http.default_read_timeout", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.groupSetting("watcher.http.ssl.", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.groupSetting("watcher.http.proxy.", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.actions.index.default_timeout", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.index.rest.direct_access", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.trigger.schedule.engine", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.input.search.default_timeout", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.transform.search.default_timeout", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.trigger.schedule.ticker.tick_interval", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.execution.scroll.timeout", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.start_immediately", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("watcher.http.default_connection_timeout", false, Setting.Scope.CLUSTER));
module.registerSetting(Setting.simpleString("resource.reload.interval", false, CLUSTER));
module.registerSetting(Setting.simpleString("resource.reload.enabled", false, CLUSTER));
module.registerSetting(Setting.simpleString("resource.reload.interval.low", false, CLUSTER));
module.registerSetting(Setting.simpleString("resource.reload.interval.medium", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.internal.ops.search.default_timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.internal.ops.bulk.default_timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.internal.ops.index.default_timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.execution.default_throttle_period", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.http.default_read_timeout", false, CLUSTER));
module.registerSetting(Setting.groupSetting("watcher.http.ssl.", false, CLUSTER));
module.registerSetting(Setting.groupSetting("watcher.http.proxy.", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.actions.index.default_timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.index.rest.direct_access", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.trigger.schedule.engine", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.input.search.default_timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.transform.search.default_timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.trigger.schedule.ticker.tick_interval", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.execution.scroll.timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.start_immediately", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.http.default_connection_timeout", false, CLUSTER));
module.registerSettingsFilter("watcher.actions.email.service.account.*.smtp.password");
module.registerSettingsFilter("watcher.actions.slack.service.account.*.url");
module.registerSettingsFilter("watcher.actions.pagerduty.service.account.*.url");
module.registerSettingsFilter("watcher.actions.pagerduty.service." + PagerDutyAccount.SERVICE_KEY_SETTING);
module.registerSettingsFilter("watcher.actions.pagerduty.service.account.*." + PagerDutyAccount.SERVICE_KEY_SETTING);
module.registerSettingsFilter("watcher.actions.pagerduty.service.account.*." +
PagerDutyAccount.SERVICE_KEY_SETTING);
module.registerSettingsFilter("watcher.actions.hipchat.service.account.*.auth_token");
}
@ -265,8 +282,9 @@ public class WatcherPlugin extends Plugin {
return;
}
String errorMessage = LoggerMessageFormat.format("the [action.auto_create_index] setting value [{}] is too restrictive. disable " +
"[action.auto_create_index] or set it to [.watches,.triggered_watches,.watch_history*]", (Object) settings);
String errorMessage = LoggerMessageFormat.format("the [action.auto_create_index] setting value [{}] is too" +
" restrictive. disable [action.auto_create_index] or set it to " +
"[.watches,.triggered_watches,.watcher-history*]", (Object) settings);
if (Booleans.isExplicitFalse(value)) {
throw new IllegalArgumentException(errorMessage);
}
@ -312,9 +330,22 @@ public class WatcherPlugin extends Plugin {
throw new IllegalArgumentException(errorMessage);
}
}
logger.warn("the [action.auto_create_index] setting is configured to be restrictive [{}]. for the next 6 months daily history " +
"indices are allowed to be created, but please make sure that any future history indices after 6 months with the pattern " +
"[.watch_history-YYYY.MM.dd] are allowed to be created", value);
logger.warn("the [action.auto_create_index] setting is configured to be restrictive [{}]. " +
" for the next 6 months daily history indices are allowed to be created, but please make sure" +
" that any future history indices after 6 months with the pattern " +
"[.watcher-history-YYYY.MM.dd] are allowed to be created", value);
}
void registerClusterPrivilege(String name, String... patterns) {
try {
ClusterPrivilege.addCustom(name, patterns);
} catch (Exception se) {
logger.warn("could not register cluster privilege [{}]", name);
// we need to prevent bubbling the shield exception here for the tests. In the tests
// we create multiple nodes in the same jvm and since the custom cluster is a static binding
// multiple nodes will try to add the same privileges multiple times.
}
}
}

View File

@ -70,7 +70,7 @@ public abstract class WatchExecutionContext {
public abstract boolean skipThrottling(String actionId);
/**
* @return true if this execution should be recorded in the .watch_history index
* @return true if this execution should be recorded in the .watcher-history index
*/
public abstract boolean recordExecution();

View File

@ -12,6 +12,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.engine.VersionConflictEngineException;
import org.elasticsearch.watcher.WatcherModule;
import org.elasticsearch.watcher.execution.ExecutionState;
import org.elasticsearch.watcher.support.init.proxy.ClientProxy;
import org.joda.time.DateTime;
@ -30,7 +31,7 @@ import static org.elasticsearch.watcher.support.Exceptions.ioException;
*/
public class HistoryStore extends AbstractComponent {
public static final String INDEX_PREFIX = ".watch_history-";
public static final String INDEX_PREFIX = ".watcher-history-" + WatcherModule.getHistoryIndexTemplateVersion() + "-";
public static final String DOC_TYPE = "watch_record";
static final DateTimeFormatter indexTimeFormat = DateTimeFormat.forPattern("YYYY.MM.dd");

View File

@ -1,41 +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.watcher.shield;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.crypto.CryptoService;
import org.elasticsearch.watcher.support.secret.SecretService;
/**
*
*/
public class ShieldSecretService extends AbstractComponent implements SecretService {
private final CryptoService cryptoService;
private final boolean encryptSensitiveData;
public static final Setting<Boolean> ENCRYPT_SENSITIVE_DATA_SETTING =
Setting.boolSetting("watcher.shield.encrypt_sensitive_data", false, false, Setting.Scope.CLUSTER);
@Inject
public ShieldSecretService(Settings settings, CryptoService cryptoService) {
super(settings);
this.encryptSensitiveData = ENCRYPT_SENSITIVE_DATA_SETTING.get(settings);
this.cryptoService = cryptoService;
}
@Override
public char[] encrypt(char[] text) {
return encryptSensitiveData ? cryptoService.encrypt(text) : text;
}
@Override
public char[] decrypt(char[] text) {
return encryptSensitiveData ? cryptoService.decrypt(text) : text;
}
}

View File

@ -1,45 +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.watcher.shield;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authz.privilege.ClusterPrivilege;
/**
*
*/
public class WatcherShieldModule extends AbstractModule {
private final ESLogger logger;
public WatcherShieldModule(Settings settings) {
this.logger = Loggers.getLogger(WatcherShieldModule.class, settings);
if (ShieldPlugin.shieldEnabled(settings)) {
registerClusterPrivilege("manage_watcher", "cluster:admin/watcher/*", "cluster:monitor/watcher/*");
registerClusterPrivilege("monitor_watcher", "cluster:monitor/watcher/*");
}
}
void registerClusterPrivilege(String name, String... patterns) {
try {
ClusterPrivilege.addCustom(name, patterns);
} catch (Exception se) {
logger.warn("could not register cluster privilege [{}]", name);
// we need to prevent bubbling the shield exception here for the tests. In the tests
// we create multiple nodes in the same jvm and since the custom cluster is a static binding
// multiple nodes will try to add the same privileges multiple times.
}
}
@Override
protected void configure() {
}
}

View File

@ -153,9 +153,9 @@ public class WatcherIndexTemplateRegistry extends AbstractComponent implements C
executor.execute(new Runnable() {
@Override
public void run() {
try (InputStream is = WatchStore.class.getResourceAsStream("/" + config.getTemplateName() + ".json")) {
try (InputStream is = WatchStore.class.getResourceAsStream("/" + config.getFileName()+ ".json")) {
if (is == null) {
logger.error("Resource [/" + config.getTemplateName() + ".json] not found in classpath");
logger.error("Resource [/" + config.getFileName() + ".json] not found in classpath");
return;
}
final byte[] template;
@ -184,13 +184,23 @@ public class WatcherIndexTemplateRegistry extends AbstractComponent implements C
public static class TemplateConfig {
private final String templateName;
private String fileName;
private final Setting<Settings> setting;
public TemplateConfig(String templateName, Setting<Settings> setting) {
this(templateName, templateName, setting);
}
public TemplateConfig(String templateName, String fileName, Setting<Settings> setting) {
this.templateName = templateName;
this.fileName = fileName;
this.setting = setting;
}
public String getFileName() {
return fileName;
}
public String getTemplateName() {
return templateName;
}

View File

@ -8,7 +8,6 @@ package org.elasticsearch.watcher.support.secret;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.watcher.shield.ShieldSecretService;
/**
*
@ -18,17 +17,16 @@ public class SecretModule extends AbstractModule {
private final boolean shieldEnabled;
public SecretModule(Settings settings) {
shieldEnabled = ShieldPlugin.shieldEnabled(settings);
shieldEnabled = ShieldPlugin.enabled(settings);
}
@Override
protected void configure() {
if (shieldEnabled) {
bind(ShieldSecretService.class).asEagerSingleton();
bind(SecretService.class).to(ShieldSecretService.class);
bind(SecretService.Secure.class).asEagerSingleton();
bind(SecretService.class).to(SecretService.Secure.class);
} else {
bind(SecretService.PlainText.class).asEagerSingleton();
bind(SecretService.class).to(SecretService.PlainText.class);
bind(SecretService.class).toInstance(SecretService.Insecure.INSTANCE);
}
}
}

View File

@ -5,6 +5,12 @@
*/
package org.elasticsearch.watcher.support.secret;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.crypto.CryptoService;
/**
*
*/
@ -14,7 +20,12 @@ public interface SecretService {
char[] decrypt(char[] text);
class PlainText implements SecretService {
class Insecure implements SecretService {
public static final Insecure INSTANCE = new Insecure();
Insecure() {
}
@Override
public char[] encrypt(char[] text) {
@ -26,4 +37,31 @@ public interface SecretService {
return text;
}
}
/**
*
*/
class Secure extends AbstractComponent implements SecretService {
private final CryptoService cryptoService;
private final boolean encryptSensitiveData;
public static final Setting<Boolean> ENCRYPT_SENSITIVE_DATA_SETTING =
Setting.boolSetting("watcher.shield.encrypt_sensitive_data", false, false, Setting.Scope.CLUSTER);
@Inject
public Secure(Settings settings, CryptoService cryptoService) {
super(settings);
this.encryptSensitiveData = ENCRYPT_SENSITIVE_DATA_SETTING.get(settings);
this.cryptoService = cryptoService;
}
@Override
public char[] encrypt(char[] text) {
return encryptSensitiveData ? cryptoService.encrypt(text) : text;
}
@Override
public char[] decrypt(char[] text) {
return encryptSensitiveData ? cryptoService.decrypt(text) : text;
}
}
}

View File

@ -257,7 +257,7 @@ public class Watch implements TriggerEngine.Job, ToXContent {
* Such that the returned watch will potentially hide this sensitive data behind a "secret". A secret
* is an abstraction around sensitive data (text). There can be different implementations of how the
* secret holds the data, depending on the wired up {@link SecretService}. When shield is installed, a
* {@link org.elasticsearch.watcher.shield.ShieldSecretService} is used, that potentially encrypts the data
* {@link SecretService.Secure} is used, that potentially encrypts the data
* using Shield's configured system key.
*
* This method is only called once - when the user adds a new watch. From that moment on, all representations

View File

@ -1,7 +1,9 @@
{
"template": ".watch_history*",
"template": ".watcher-history-${watcher.template.version}*",
"order": 2147483647,
"settings": {
"watcher.plugin.version": "${watcher.plugin.version}",
"watcher.template.version": "${watcher.template.version}",
"index.number_of_shards": 1,
"index.mapper.dynamic": false
},
@ -29,7 +31,7 @@
}
}
],
"dynamic": "strict",
"dynamic": false,
"_all": {
"enabled": false
},

View File

@ -0,0 +1 @@
watcher.template.version=${watcher.template.version}

View File

@ -41,8 +41,10 @@ public class WatcherPluginDisableTests extends ESIntegTestCase {
return Settings.settingsBuilder()
.put(super.nodeSettings(nodeOrdinal))
.put(WatcherPlugin.ENABLED_SETTING, false)
// disable shield because of query cache check and authentication/authorization
.put(ShieldPlugin.ENABLED_SETTING_NAME, false)
.put(XPackPlugin.featureEnabledSetting(ShieldPlugin.NAME), false)
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
.build();
}

Some files were not shown because too many files have changed in this diff Show More