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, notNullValue());
assertThat(mappingsResponse.getMappings().isEmpty(), is(false)); assertThat(mappingsResponse.getMappings().isEmpty(), is(false));
for (ObjectObjectCursor<String, ImmutableOpenMap<String, MappingMetaData>> metadatas : mappingsResponse.getMappings()) { for (ObjectObjectCursor<String, ImmutableOpenMap<String, MappingMetaData>> metadatas : mappingsResponse.getMappings()) {
if (!metadatas.key.startsWith(".watch_history")) { if (!metadatas.key.startsWith(".watcher-history")) {
continue; continue;
} }
MappingMetaData metadata = metadatas.value.get("watch_record"); MappingMetaData metadata = metadatas.value.get("watch_record");

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with 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.apache.lucene.util.LuceneTestCase.BadApple;
import org.elasticsearch.ExceptionsHelper; 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.ZenPing;
import org.elasticsearch.discovery.zen.ping.ZenPingService; import org.elasticsearch.discovery.zen.ping.ZenPingService;
import org.elasticsearch.discovery.zen.ping.unicast.UnicastZenPing; 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.ClusterScope;
import org.elasticsearch.test.ESIntegTestCase.SuppressLocalMode; import org.elasticsearch.test.ESIntegTestCase.SuppressLocalMode;
import org.elasticsearch.test.discovery.ClusterDiscoveryConfiguration; 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.delete.DeleteWatchResponse;
import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsResponse; 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 java.util.concurrent.TimeUnit;
import static org.elasticsearch.index.query.QueryBuilders.termQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery;
@ -81,6 +88,23 @@ public class NoMasterNodeTests extends AbstractWatcherIntegrationTestCase {
.build(); .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 { 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... // 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); config = new ClusterDiscoveryConfiguration.UnicastZen(3, Settings.EMPTY);

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with 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; 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.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.common.unit.TimeValue; 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.actions.ActionStatus;
import org.elasticsearch.watcher.client.WatcherClient; import org.elasticsearch.watcher.client.WatcherClient;
import org.elasticsearch.watcher.condition.compare.CompareCondition; 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.elasticsearch.watcher.watch.WatchStore;
import org.hamcrest.Matchers; 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 java.util.concurrent.TimeUnit;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; 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 //test is just too slow, please fix it to not be sleep-based
@BadApple(bugUrl = "https://github.com/elastic/x-plugins/issues/1007") @BadApple(bugUrl = "https://github.com/elastic/x-plugins/issues/1007")
public class WatchAckTests extends AbstractWatcherIntegrationTestCase { 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() { private IndexResponse indexTestDoc() {
createIndex("actions", "events"); createIndex("actions", "events");
ensureGreen("actions", "events"); ensureGreen("actions", "events");

View File

@ -10,7 +10,7 @@ integTest {
systemProperty 'es.shield.audit.enabled', 'true' systemProperty 'es.shield.audit.enabled', 'true'
systemProperty 'es.shield.audit.outputs', 'index' systemProperty 'es.shield.audit.outputs', 'index'
setupCommand 'setupDummyUser', 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 -> waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success') File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}", ant.get(src: "http://${node.httpUri()}",

View File

@ -5,10 +5,14 @@
*/ */
package org.elasticsearch.shield.audit; 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.action.search.SearchResponse;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.plugins.Plugin; 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.SecuredString;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.ESIntegTestCase; 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)); 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 @Override
protected Settings externalClusterClientSettings() { protected Settings externalClusterClientSettings() {
return Settings.builder() return Settings.builder()

View File

@ -8,9 +8,9 @@ integTest {
cluster { cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack') plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
setupCommand 'setupDummyUser', 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', 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 -> waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success') File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}", ant.get(src: "http://${node.httpUri()}",

View File

@ -35,7 +35,7 @@ integTest {
systemProperty 'es.watcher.enabled', 'false' systemProperty 'es.watcher.enabled', 'false'
systemProperty 'es.marvel.enabled', 'false' systemProperty 'es.marvel.enabled', 'false'
setupCommand 'setupDummyUser', 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 -> waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success') File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}", ant.get(src: "http://${node.httpUri()}",

View File

@ -23,7 +23,7 @@ integTest {
systemProperty 'es.shield.authc.realms.esusers.type', 'esusers' systemProperty 'es.shield.authc.realms.esusers.type', 'esusers'
setupCommand 'setupDummyUser', 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 -> waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success') File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}", ant.get(src: "http://${node.httpUri()}",

View File

@ -75,10 +75,10 @@
<property name="home" location="${integ.scratch}/elasticsearch-${elasticsearch.version}"/> <property name="home" location="${integ.scratch}/elasticsearch-${elasticsearch.version}"/>
<echo>Adding roles.yml</echo> <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> <echo>Adding shield users...</echo>
<run-script script="${home}/bin/shield/esusers"> <run-script script="${home}/bin/xpack/esusers">
<nested> <nested>
<arg value="useradd"/> <arg value="useradd"/>
<arg value="test_admin"/> <arg value="test_admin"/>

View File

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

View File

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

View File

@ -57,9 +57,9 @@ integTest {
// copy keystore into config/ // copy keystore into config/
extraConfigFile keystore.name, keystore extraConfigFile keystore.name, keystore
setupCommand 'setupTestUser', 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', 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 -> waitCondition = { node, ant ->
// we just return true, doing an https check is tricky here // we just return true, doing an https check is tricky here
return true return true

View File

@ -18,7 +18,7 @@ integTest {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack') plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
setupCommand 'setupDummyUser', 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 -> waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success') File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}", ant.get(src: "http://${node.httpUri()}",

View File

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

View File

@ -20,13 +20,13 @@ integTest {
cluster { cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack') plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
extraConfigFile 'x-pack/roles.yml', 'roles.yml' extraConfigFile 'xpack/roles.yml', 'roles.yml'
setupCommand 'setupTestAdminUser', 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', 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', 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 -> waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success') File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}", ant.get(src: "http://${node.httpUri()}",

View File

@ -6,13 +6,13 @@ admin:
watcher_manager: watcher_manager:
cluster: manage_watcher, cluster:monitor/nodes/info, cluster:monitor/health cluster: manage_watcher, cluster:monitor/nodes/info, cluster:monitor/health
indices: indices:
'.watch_history-*': all '.watcher-history-*': all
run_as: powerless_user, watcher_manager run_as: powerless_user, watcher_manager
watcher_monitor: watcher_monitor:
cluster: monitor_watcher cluster: monitor_watcher
indices: indices:
'.watch_history-*': read '.watcher-history-*': read
crappy_role: crappy_role:
cluster: 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' apply plugin: 'elasticsearch.esplugin'
esplugin { esplugin {
name 'x-pack' name 'xpack'
description 'Elasticsearch Expanded Pack Plugin' description 'Elasticsearch Expanded Pack Plugin'
classname 'org.elasticsearch.xpack.XPackPlugin' classname 'org.elasticsearch.xpack.XPackPlugin'
// FIXME we still can't be isolated due to shield custom realms // FIXME we still can't be isolated due to shield custom realms
@ -74,6 +74,9 @@ ext.expansions = [
// Used in marvel index templates // Used in marvel index templates
'marvel.plugin.version': version, 'marvel.plugin.version': version,
'marvel.template.version': '1', 'marvel.template.version': '1',
// Used in watcher index template
'watcher.plugin.version': version,
'watcher.template.version': '1',
] ]
processResources { processResources {
@ -111,13 +114,13 @@ bundlePlugin {
include 'LICENSE.txt' include 'LICENSE.txt'
include 'NOTICE.txt' include 'NOTICE.txt'
} }
from('shield/bin/shield') { from('shield/bin/xpack') {
into 'bin' into 'bin'
} }
from('shield/config/shield') { from('shield/config/xpack') {
into 'config' into 'config'
} }
from('watcher/bin/watcher') { from('watcher/bin/xpack') {
into 'bin' into 'bin'
} }
} }
@ -126,7 +129,7 @@ integTest {
// TODO: fix this rest test to not depend on a hardcoded port! // TODO: fix this rest test to not depend on a hardcoded port!
systemProperty 'tests.rest.blacklist', 'getting_started/10_monitor_cluster_health/*' systemProperty 'tests.rest.blacklist', 'getting_started/10_monitor_cluster_health/*'
cluster { 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 -> waitCondition = { NodeInfo node, AntBuilder ant ->
File tmpFile = new File(node.cwd, 'wait.success') File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}", ant.get(src: "http://${node.httpUri()}",
@ -154,7 +157,7 @@ artifacts {
} }
run { 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 // 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.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.MarvelLicensee; import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.shield.InternalClient; import org.elasticsearch.shield.InternalClient;
import org.elasticsearch.shield.ShieldPlugin;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -26,8 +27,6 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import static org.elasticsearch.shield.ShieldPlugin.shieldEnabled;
/** /**
* Collector for the Recovery API. * Collector for the Recovery API.
* <p> * <p>
@ -73,7 +72,7 @@ public class IndexRecoveryCollector extends AbstractCollector<IndexRecoveryColle
results.add(indexRecoveryDoc); results.add(indexRecoveryDoc);
} }
} catch (IndexNotFoundException e) { } 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()); logger.debug("collector [{}] - unable to collect data for missing index [{}]", name(), e.getIndex());
} else { } else {
throw e; 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.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.MarvelLicensee; import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.shield.InternalClient; import org.elasticsearch.shield.InternalClient;
import org.elasticsearch.shield.ShieldPlugin;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -28,8 +29,6 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import static org.elasticsearch.shield.ShieldPlugin.shieldEnabled;
/** /**
* Collector for indices statistics. * Collector for indices statistics.
* <p> * <p>
@ -87,7 +86,7 @@ public class IndexStatsCollector extends AbstractCollector<IndexStatsCollector>
results.add(indexStatsDoc); results.add(indexStatsDoc);
} }
} catch (IndexNotFoundException e) { } 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()); logger.debug("collector [{}] - unable to collect data for missing index [{}]", name(), e.getIndex());
} else { } else {
throw e; 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.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.MarvelLicensee; import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.shield.InternalClient; import org.elasticsearch.shield.InternalClient;
import org.elasticsearch.shield.ShieldPlugin;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import static org.elasticsearch.shield.ShieldPlugin.shieldEnabled;
/** /**
* Collector for indices statistics. * Collector for indices statistics.
* <p> * <p>
@ -72,7 +71,7 @@ public class IndicesStatsCollector extends AbstractCollector<IndicesStatsCollect
return Collections.singletonList(indicesStatsDoc); return Collections.singletonList(indicesStatsDoc);
} catch (IndexNotFoundException e) { } 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()); logger.debug("collector [{}] - unable to collect data for missing index [{}]", name(), e.getIndex());
return Collections.emptyList(); return Collections.emptyList();
} }

View File

@ -66,7 +66,7 @@ public class MarvelPluginTests extends MarvelIntegTestCase {
break; 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 REM Disables explicit GC
set JAVA_OPTS=%JAVA_OPTS% -XX:+DisableExplicitGC 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 ES_PARAMS=-Des.path.home="%ES_HOME%"
SET HOSTNAME=%COMPUTERNAME% SET HOSTNAME=%COMPUTERNAME%

View File

@ -102,9 +102,9 @@ if [ -e "$CONF_DIR" ]; then
case "$properties" in case "$properties" in
*-Des.default.path.conf=*) ;; *-Des.default.path.conf=*) ;;
*) *)
if [ ! -d "$CONF_DIR/shield" ]; then if [ ! -d "$CONF_DIR/xpack" ]; then
echo "ERROR: The configuration directory [$CONF_DIR/shield] does not exist. The esusers tool expects Shield configuration files in that location." 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/shield] exists, please copy the shield directory to [$CONF_DIR]" 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 exit 1
fi fi
properties="$properties -Des.default.path.conf=$CONF_DIR" properties="$properties -Des.default.path.conf=$CONF_DIR"
@ -123,7 +123,7 @@ fi
export HOSTNAME=`hostname -s` export HOSTNAME=`hostname -s`
# include shield jars in classpath # 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 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 "$@" "$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 case "$properties" in
*-Des.default.path.conf=*) ;; *-Des.default.path.conf=*) ;;
*) *)
if [ ! -d "$CONF_DIR/shield" ]; then if [ ! -d "$CONF_DIR/xpack" ]; then
echo "ERROR: The configuration directory [$CONF_DIR/shield] does not exist. The syskeygen tool expects Shield configuration files in that location." 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/shield] exists, please copy the shield directory to [$CONF_DIR]" 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 exit 1
fi fi
properties="$properties -Des.default.path.conf=$CONF_DIR" properties="$properties -Des.default.path.conf=$CONF_DIR"
@ -123,7 +123,7 @@ fi
export HOSTNAME=`hostname -s` export HOSTNAME=`hostname -s`
# include shield jars in classpath # 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 cd "$ES_HOME" > /dev/null
$JAVA $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" $properties org.elasticsearch.shield.crypto.tool.SystemKeyTool "$@" $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; package org.elasticsearch.shield;
import org.elasticsearch.action.ActionModule; import org.elasticsearch.action.ActionModule;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.component.LifecycleComponent; import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.network.NetworkModule; 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.Settings;
import org.elasticsearch.common.settings.SettingsModule; import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.IndexModule;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.shield.action.ShieldActionFilter; 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.shield.transport.netty.ShieldNettyTransport;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -85,22 +82,19 @@ import java.util.Map;
public class ShieldPlugin extends Plugin { public class ShieldPlugin extends Plugin {
public static final String NAME = "shield"; 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 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 Settings settings;
private final boolean enabled; private final boolean enabled;
private final boolean clientMode; private final boolean transportClientMode;
private ShieldLicenseState shieldLicenseState; private ShieldLicenseState shieldLicenseState;
public ShieldPlugin(Settings settings) { public ShieldPlugin(Settings settings) {
this.settings = settings; this.settings = settings;
this.enabled = shieldEnabled(settings); this.transportClientMode = XPackPlugin.transportClientMode(settings);
this.clientMode = clientMode(settings); this.enabled = XPackPlugin.featureEnabled(settings, NAME, true);
if (enabled && clientMode == false) { if (enabled && !transportClientMode) {
failIfShieldQueryCacheIsNotActive(settings, true); failIfShieldQueryCacheIsNotActive(settings, true);
} }
} }
@ -118,11 +112,11 @@ public class ShieldPlugin extends Plugin {
@Override @Override
public Collection<Module> nodeModules() { public Collection<Module> nodeModules() {
if (!enabled) { if (enabled == false) {
return Collections.singletonList(new ShieldDisabledModule(settings)); return Collections.singletonList(new ShieldDisabledModule(settings));
} }
if (clientMode) { if (transportClientMode == true) {
return Arrays.<Module>asList( return Arrays.<Module>asList(
new ShieldTransportModule(settings), new ShieldTransportModule(settings),
new SSLModule(settings)); new SSLModule(settings));
@ -147,9 +141,13 @@ public class ShieldPlugin extends Plugin {
@Override @Override
public Collection<Class<? extends LifecycleComponent>> nodeServices() { 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<>(); 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(LoggingAuditTrail.class);
} }
list.add(ShieldLicensee.class); list.add(ShieldLicensee.class);
@ -157,8 +155,7 @@ public class ShieldPlugin extends Plugin {
list.add(FileRolesStore.class); list.add(FileRolesStore.class);
list.add(Realms.class); list.add(Realms.class);
return list; return list;
}
return Collections.emptyList();
} }
@Override @Override
@ -178,6 +175,7 @@ public class ShieldPlugin extends Plugin {
} }
public void onModule(SettingsModule settingsModule) { 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_SETTING);
settingsModule.registerSetting(IPFilter.IP_FILTER_ENABLED_HTTP_SETTING); settingsModule.registerSetting(IPFilter.IP_FILTER_ENABLED_HTTP_SETTING);
settingsModule.registerSetting(IPFilter.HTTP_FILTER_ALLOW_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)); settingsModule.registerSetting(Setting.boolSetting("plugins.load_classpath_plugins", true, false, Setting.Scope.CLUSTER));
// TODO add real settings for this wildcard here // TODO add real settings for this wildcard here
settingsModule.registerSetting(Setting.groupSetting("shield.", false, Setting.Scope.CLUSTER)); 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"); String[] asArray = settings.getAsArray("shield.hide_settings");
for (String pattern : asArray) { for (String pattern : asArray) {
settingsModule.registerSettingsFilter(pattern); settingsModule.registerSettingsFilter(pattern);
@ -207,14 +208,15 @@ public class ShieldPlugin extends Plugin {
if (enabled == false) { if (enabled == false) {
return; return;
} }
assert shieldLicenseState != null; assert shieldLicenseState != null;
if (flsDlsEnabled(settings)) { if (flsDlsEnabled(settings)) {
module.setSearcherWrapper((indexService) -> new ShieldIndexSearcherWrapper(indexService.getIndexSettings(), module.setSearcherWrapper((indexService) -> new ShieldIndexSearcherWrapper(indexService.getIndexSettings(),
indexService.getQueryShardContext(), indexService.mapperService(), indexService.newQueryShardContext(), indexService.mapperService(),
indexService.cache().bitsetFilterCache(), indexService.getIndexServices().getThreadPool().getThreadContext(), indexService.cache().bitsetFilterCache(), indexService.getIndexServices().getThreadPool().getThreadContext(),
shieldLicenseState)); shieldLicenseState));
} }
if (clientMode == false) { if (transportClientMode == false) {
module.registerQueryCache(ShieldPlugin.OPT_OUT_QUERY_CACHE, OptOutQueryCache::new); module.registerQueryCache(ShieldPlugin.OPT_OUT_QUERY_CACHE, OptOutQueryCache::new);
failIfShieldQueryCacheIsNotActive(module.getSettings(), false); failIfShieldQueryCacheIsNotActive(module.getSettings(), false);
} }
@ -225,7 +227,7 @@ public class ShieldPlugin extends Plugin {
return; return;
} }
// registering the security filter only for nodes // registering the security filter only for nodes
if (clientMode == false) { if (transportClientMode == false) {
module.registerFilter(ShieldActionFilter.class); module.registerFilter(ShieldActionFilter.class);
} }
@ -241,23 +243,21 @@ public class ShieldPlugin extends Plugin {
} }
public void onModule(NetworkModule module) { 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; return;
} }
module.registerTransport(ShieldPlugin.NAME, ShieldNettyTransport.class); // we want to expose the shield rest action even when the plugin is disabled
if (clientMode) { module.registerRestHandler(RestShieldInfoAction.class);
module.registerTransportService(ShieldPlugin.NAME, ShieldClientTransportService.class);
} else {
module.registerTransportService(ShieldPlugin.NAME, ShieldServerTransportService.class);
}
if (clientMode == false) { if (enabled) {
module.registerTransport(ShieldPlugin.NAME, ShieldNettyTransport.class);
module.registerTransportService(ShieldPlugin.NAME, ShieldServerTransportService.class);
module.registerRestHandler(RestAuthenticateAction.class); module.registerRestHandler(RestAuthenticateAction.class);
module.registerRestHandler(RestClearRealmCacheAction.class); module.registerRestHandler(RestClearRealmCacheAction.class);
module.registerRestHandler(RestClearRolesCacheAction.class); module.registerRestHandler(RestClearRolesCacheAction.class);
@ -290,39 +290,41 @@ public class ShieldPlugin extends Plugin {
.toCharArray()))); .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 * If the current node is a tribe node, we inject additional settings on each tribe client. We do this to make sure
installed and enabled too: * that every tribe cluster has shield installed and is enabled. We do that by:
- 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) * - making it mandatory on the tribe client (this means that the tribe node will fail at startup if shield is
- if shield is loaded and enabled on the tribe node, we make sure it is also enabled on every tribe, by forcibly enabling it * not loaded on any tribe due to missing mandatory plugin)
(that means it's not possible to disable shield on the tribe clients) *
* - forcibly enabling it (that means it's not possible to disable shield on the tribe clients)
*/ */
private void addTribeSettings(Settings.Builder settingsBuilder) { private void addTribeSettings(Settings.Builder settingsBuilder) {
Map<String, Settings> tribesSettings = settings.getGroups("tribe", true); Map<String, Settings> tribesSettings = settings.getGroups("tribe", true);
if (tribesSettings.isEmpty()) { if (tribesSettings.isEmpty()) {
// it's not a tribe node
return; return;
} }
for (Map.Entry<String, Settings> tribeSettings : tribesSettings.entrySet()) { for (Map.Entry<String, Settings> tribeSettings : tribesSettings.entrySet()) {
String tribePrefix = "tribe." + tribeSettings.getKey() + "."; String tribePrefix = "tribe." + tribeSettings.getKey() + ".";
// we copy over existing mandatory plugins under additional settings, as they would get overridden otherwise (arrays don't get // we copy over existing mandatory plugins under additional settings, as they would get overridden
// merged) // otherwise (arrays don't get merged)
String[] existingMandatoryPlugins = tribeSettings.getValue().getAsArray("plugin.mandatory", null); String[] existingMandatoryPlugins = tribeSettings.getValue().getAsArray("plugin.mandatory", null);
if (existingMandatoryPlugins == null) { if (existingMandatoryPlugins == null) {
//shield is mandatory on every tribe if installed and enabled on the tribe node //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 { } else {
if (!isShieldMandatory(existingMandatoryPlugins)) { if (Arrays.binarySearch(existingMandatoryPlugins, XPackPlugin.NAME) < 0) {
throw new IllegalStateException("when [plugin.mandatory] is explicitly configured, [" + NAME + "] must be included in" + throw new IllegalStateException("when [plugin.mandatory] is explicitly configured, [" +
" this list"); 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) { if (settings.get(tribeEnabledSetting) != null) {
boolean enabled = shieldEnabled(tribeSettings.getValue()); boolean enabled = enabled(tribeSettings.getValue());
if (!enabled) { if (!enabled) {
throw new IllegalStateException("tribe setting [" + tribeEnabledSetting + "] must be set to true but the value is [" throw new IllegalStateException("tribe setting [" + tribeEnabledSetting + "] must be set to true but the value is ["
+ settings.get(tribeEnabledSetting) + "]"); + 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. * 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 * 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 * forcefully overwrite the query cache implementation then we leave the system vulnerable to leakages of data to
unauthorized users. * unauthorized users.
*/ */
private void addQueryCacheSettings(Settings.Builder settingsBuilder) { private void addQueryCacheSettings(Settings.Builder settingsBuilder) {
settingsBuilder.put(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey(), OPT_OUT_QUERY_CACHE); settingsBuilder.put(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey(), OPT_OUT_QUERY_CACHE);
} }
private static boolean isShieldMandatory(String[] existingMandatoryPlugins) { public static boolean enabled(Settings settings) {
for (String existingMandatoryPlugin : existingMandatoryPlugins) { return XPackPlugin.featureEnabled(settings, NAME, true);
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 flsDlsEnabled(Settings settings) { 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) { 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.AuthenticationService;
import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; 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 org.elasticsearch.threadpool.ThreadPool;
import java.util.ArrayList; 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) { private <Response> void clearRealmCache(String username, ActionListener<Response> listener, Response response) {
ShieldClient shieldClient = new ShieldClient(client); SecurityClient securityClient = new SecurityClient(client);
ClearRealmCacheRequest request = shieldClient.prepareClearRealmCache() ClearRealmCacheRequest request = securityClient.prepareClearRealmCache()
.usernames(username).request(); .usernames(username).request();
shieldClient.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() { securityClient.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() {
@Override @Override
public void onResponse(ClearRealmCacheResponse nodes) { public void onResponse(ClearRealmCacheResponse nodes) {
listener.onResponse(response); listener.onResponse(response);

View File

@ -20,6 +20,7 @@ import org.elasticsearch.shield.support.Validation;
import org.elasticsearch.watcher.FileChangesListener; import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
@ -98,7 +99,7 @@ public class FileUserPasswdStore {
public static Path resolveFile(Settings settings, Environment env) { public static Path resolveFile(Settings settings, Environment env) {
String location = settings.get("files.users"); String location = settings.get("files.users");
if (location == null) { if (location == null) {
return ShieldPlugin.resolveConfigFile(env, "users"); return XPackPlugin.resolveConfigFile(env, "users");
} }
return env.binFile().getParent().resolve(location); return env.binFile().getParent().resolve(location);
} }
@ -166,7 +167,7 @@ public class FileUserPasswdStore {
} }
if (users.isEmpty()) { 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); return unmodifiableMap(users);
} }

View File

@ -19,6 +19,7 @@ import org.elasticsearch.shield.support.Validation;
import org.elasticsearch.watcher.FileChangesListener; import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
@ -91,7 +92,7 @@ public class FileUserRolesStore {
public static Path resolveFile(Settings settings, Environment env) { public static Path resolveFile(Settings settings, Environment env) {
String location = settings.get("files.users_roles"); String location = settings.get("files.users_roles");
if (location == null) { if (location == null) {
return ShieldPlugin.resolveConfigFile(env, "users_roles"); return XPackPlugin.resolveConfigFile(env, "users_roles");
} }
return env.binFile().getParent().resolve(location); return env.binFile().getParent().resolve(location);
} }
@ -181,7 +182,7 @@ public class FileUserRolesStore {
} }
if (usersRoles.isEmpty()) { 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()); .toAbsolutePath());
} }

View File

@ -17,6 +17,7 @@ import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.watcher.FileChangesListener; import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -82,7 +83,7 @@ public class DnRoleMapper {
public static Path resolveFile(Settings settings, Environment env) { public static Path resolveFile(Settings settings, Environment env) {
String location = settings.get(ROLE_MAPPING_FILE_SETTING); String location = settings.get(ROLE_MAPPING_FILE_SETTING);
if (location == null) { if (location == null) {
return ShieldPlugin.resolveConfigFile(env, DEFAULT_FILE_NAME); return XPackPlugin.resolveConfigFile(env, DEFAULT_FILE_NAME);
} }
return env.binFile().getParent().resolve(location); 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.Base64;
import org.elasticsearch.common.Randomness; import org.elasticsearch.common.Randomness;
import org.elasticsearch.common.hash.MessageDigests;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
@ -142,7 +143,7 @@ public enum Hasher {
@Override @Override
public char[] hash(SecuredString text) { public char[] hash(SecuredString text) {
byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars()); byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars());
MessageDigest md = SHA1Provider.sha1(); MessageDigest md = MessageDigests.sha1();
md.update(textBytes); md.update(textBytes);
String hash = Base64.encodeBytes(md.digest()); String hash = Base64.encodeBytes(md.digest());
return (SHA1_PREFIX + hash).toCharArray(); return (SHA1_PREFIX + hash).toCharArray();
@ -155,7 +156,7 @@ public enum Hasher {
return false; return false;
} }
byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars()); byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars());
MessageDigest md = SHA1Provider.sha1(); MessageDigest md = MessageDigests.sha1();
md.update(textBytes); md.update(textBytes);
String passwd64 = Base64.encodeBytes(md.digest()); String passwd64 = Base64.encodeBytes(md.digest());
String hashNoPrefix = hashStr.substring(SHA1_PREFIX.length()); String hashNoPrefix = hashStr.substring(SHA1_PREFIX.length());
@ -166,7 +167,7 @@ public enum Hasher {
MD5() { MD5() {
@Override @Override
public char[] hash(SecuredString text) { public char[] hash(SecuredString text) {
MessageDigest md = MD5Provider.md5(); MessageDigest md = MessageDigests.md5();
md.update(CharArrays.toUtf8Bytes(text.internalChars())); md.update(CharArrays.toUtf8Bytes(text.internalChars()));
String hash = Base64.encodeBytes(md.digest()); String hash = Base64.encodeBytes(md.digest());
return (MD5_PREFIX + hash).toCharArray(); return (MD5_PREFIX + hash).toCharArray();
@ -179,7 +180,7 @@ public enum Hasher {
return false; return false;
} }
hashStr = hashStr.substring(MD5_PREFIX.length()); hashStr = hashStr.substring(MD5_PREFIX.length());
MessageDigest md = MD5Provider.md5(); MessageDigest md = MessageDigests.md5();
md.update(CharArrays.toUtf8Bytes(text.internalChars())); md.update(CharArrays.toUtf8Bytes(text.internalChars()));
String computedHashStr = Base64.encodeBytes(md.digest()); String computedHashStr = Base64.encodeBytes(md.digest());
return SecuredString.constantTimeEquals(hashStr, computedHashStr); return SecuredString.constantTimeEquals(hashStr, computedHashStr);
@ -189,7 +190,7 @@ public enum Hasher {
SSHA256() { SSHA256() {
@Override @Override
public char[] hash(SecuredString text) { public char[] hash(SecuredString text) {
MessageDigest md = SHA256Provider.sha256(); MessageDigest md = MessageDigests.sha256();
md.update(CharArrays.toUtf8Bytes(text.internalChars())); md.update(CharArrays.toUtf8Bytes(text.internalChars()));
char[] salt = SaltProvider.salt(8); char[] salt = SaltProvider.salt(8);
md.update(CharArrays.toUtf8Bytes(salt)); md.update(CharArrays.toUtf8Bytes(salt));
@ -209,7 +210,7 @@ public enum Hasher {
} }
hashStr = hashStr.substring(SSHA256_PREFIX.length()); hashStr = hashStr.substring(SSHA256_PREFIX.length());
char[] saltAndHash = hashStr.toCharArray(); char[] saltAndHash = hashStr.toCharArray();
MessageDigest md = SHA256Provider.sha256(); MessageDigest md = MessageDigests.sha256();
md.update(CharArrays.toUtf8Bytes(text.internalChars())); md.update(CharArrays.toUtf8Bytes(text.internalChars()));
md.update(new String(saltAndHash, 0, 8).getBytes(StandardCharsets.UTF_8)); md.update(new String(saltAndHash, 0, 8).getBytes(StandardCharsets.UTF_8));
String computedHash = Base64.encodeBytes(md.digest()); String computedHash = Base64.encodeBytes(md.digest());
@ -279,76 +280,6 @@ public enum Hasher {
public abstract boolean verify(SecuredString data, char[] hash); 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 class SaltProvider {
static final char[] ALPHABET = new char[]{ 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.RoleDescriptor;
import org.elasticsearch.shield.authz.permission.Role; import org.elasticsearch.shield.authz.permission.Role;
import org.elasticsearch.shield.authz.store.RolesStore; 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 org.elasticsearch.threadpool.ThreadPool;
import java.util.ArrayList; import java.util.ArrayList;
@ -84,7 +84,7 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
private final ConcurrentHashMap<String, RoleAndVersion> roleCache = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, RoleAndVersion> roleCache = new ConcurrentHashMap<>();
private Client client; private Client client;
private ShieldClient shieldClient; private SecurityClient securityClient;
private int scrollSize; private int scrollSize;
private TimeValue scrollKeepAlive; private TimeValue scrollKeepAlive;
private ScheduledFuture<?> versionChecker; private ScheduledFuture<?> versionChecker;
@ -353,7 +353,7 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
try { try {
if (state.compareAndSet(State.INITIALIZED, State.STARTING)) { if (state.compareAndSet(State.INITIALIZED, State.STARTING)) {
this.client = clientProvider.get(); 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.scrollSize = settings.getAsInt("shield.authc.native.scroll.size", 1000);
this.scrollKeepAlive = settings.getAsTime("shield.authc.native.scroll.keep_alive", TimeValue.timeValueSeconds(10L)); 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)); 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) { private <Response> void clearRoleCache(final String role, ActionListener<Response> listener, Response response) {
ClearRolesCacheRequest request = new ClearRolesCacheRequest().roles(role); ClearRolesCacheRequest request = new ClearRolesCacheRequest().roles(role);
shieldClient.clearRolesCache(request, new ActionListener<ClearRolesCacheResponse>() { securityClient.clearRolesCache(request, new ActionListener<ClearRolesCacheResponse>() {
@Override @Override
public void onResponse(ClearRolesCacheResponse nodes) { public void onResponse(ClearRolesCacheResponse nodes) {
listener.onResponse(response); 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 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 MANAGE_ALIASES = new IndexPrivilege("manage_aliases", "indices:admin/aliases*");
public static final IndexPrivilege MONITOR = new IndexPrivilege("monitor", "indices:monitor/*"); 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 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/*"); 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 READ = new IndexPrivilege("read", "indices:data/read/*");
public static final IndexPrivilege SEARCH = new IndexPrivilege("search", SearchAction.NAME + "*", MultiSearchAction.NAME + "*", public static final IndexPrivilege SEARCH =
SuggestAction.NAME + "*"); 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 GET = new IndexPrivilege("get", GetAction.NAME + "*", MultiGetAction.NAME + "*");
public static final IndexPrivilege SUGGEST = new IndexPrivilege("suggest", SuggestAction.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 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<>(); private static final Set<IndexPrivilege> values = new CopyOnWriteArraySet<>();

View File

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

View File

@ -34,6 +34,7 @@ import org.elasticsearch.shield.support.Validation;
import org.elasticsearch.watcher.FileChangesListener; import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -109,7 +110,7 @@ public class FileRolesStore extends AbstractLifecycleComponent<RolesStore> imple
public static Path resolveFile(Settings settings, Environment env) { public static Path resolveFile(Settings settings, Environment env) {
String location = settings.get("shield.authz.store.files.roles"); String location = settings.get("shield.authz.store.files.roles");
if (location == null) { if (location == null) {
return ShieldPlugin.resolveConfigFile(env, "roles.yml"); return XPackPlugin.resolveConfigFile(env, "roles.yml");
} }
return env.binFile().getParent().resolve(location); return env.binFile().getParent().resolve(location);
@ -285,10 +286,10 @@ public class FileRolesStore extends AbstractLifecycleComponent<RolesStore> imple
if (token == XContentParser.Token.VALUE_STRING) { if (token == XContentParser.Token.VALUE_STRING) {
names.add(parser.text()); names.add(parser.text());
} else { } else {
logger.error("invalid role definition [{}] in roles file [{}]. could " + logger.error("invalid role definition [{}] in roles file [{}]. " +
"not parse " + "could not parse [{}] as index privilege. privilege " +
"[{}] as index privilege. privilege names must be strings. " + "names must be strings. skipping role...", roleName,
"skipping role...", roleName, path.toAbsolutePath(), token); path.toAbsolutePath(), token);
return null; return null;
} }
} }
@ -301,26 +302,27 @@ public class FileRolesStore extends AbstractLifecycleComponent<RolesStore> imple
if (name != null) { if (name != null) {
if ((query != null || (fields != null && fields.isEmpty() == false)) && if ((query != null || (fields != null && fields.isEmpty() == false)) &&
ShieldPlugin.flsDlsEnabled(settings) == false) { ShieldPlugin.flsDlsEnabled(settings) == false) {
logger.error("invalid role definition [{}] in roles file [{}]. document and field" + logger.error("invalid role definition [{}] in roles file [{}]. " +
" level security is not enabled. set [{}] to [true] in the configuration " + "document and field level security is not enabled. " +
"file. skipping role...", roleName, path.toAbsolutePath(), ShieldPlugin "set [{}] to [true] in the configuration file. skipping role...",
.DLS_FLS_ENABLED_SETTING); roleName, path.toAbsolutePath(),
XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE));
return null; return null;
} }
try { try {
role.add(fields, query, IndexPrivilege.get(name), indices); role.add(fields, query, IndexPrivilege.get(name), indices);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
logger.error("invalid role definition [{}] in roles file [{}]. could not resolve " + logger.error("invalid role definition [{}] in roles file [{}]. could not " +
"indices privileges [{}]. skipping role...", roleName, "resolve indices privileges [{}]. skipping role...", roleName,
path.toAbsolutePath(), name); path.toAbsolutePath(), name);
return null; return null;
} }
} }
continue; continue;
} else { } else {
logger.error("invalid role definition [{}] in roles file [{}]. could not parse [{}] as " + logger.error("invalid role definition [{}] in roles file [{}]. " +
"index privileges. privilege lists must either " + "could not parse [{}] as index privileges. privilege lists must either " +
"be a comma delimited string or an array of strings. skipping role...", roleName, "be a comma delimited string or an array of strings. skipping role...", roleName,
path.toAbsolutePath(), token); path.toAbsolutePath(), token);
return null; 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 * A wrapper to elasticsearch clients that exposes all Shield related APIs
*/ */
public class ShieldClient { public class SecurityClient {
private final ElasticsearchClient client; private final ElasticsearchClient client;
private final ShieldAuthcClient authcClient;
public ShieldClient(ElasticsearchClient client) { public SecurityClient(ElasticsearchClient client) {
this.client = 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.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import javax.crypto.BadPaddingException; import javax.crypto.BadPaddingException;
import javax.crypto.Cipher; import javax.crypto.Cipher;
@ -159,7 +160,7 @@ public class InternalCryptoService extends AbstractLifecycleComponent<InternalCr
public static Path resolveSystemKey(Settings settings, Environment env) { public static Path resolveSystemKey(Settings settings, Environment env) {
String location = settings.get(FILE_SETTING); String location = settings.get(FILE_SETTING);
if (location == null) { if (location == null) {
return ShieldPlugin.resolveConfigFile(env, FILE_NAME); return XPackPlugin.resolveConfigFile(env, FILE_NAME);
} }
return env.binFile().getParent().resolve(location); 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 * 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 * Mac#getInstance and obtaining a lock (in the internals)
*/ */
private static class HmacSHA1Provider { private static class HmacSHA1Provider {
private static final Mac mac; private static final ThreadLocal<Mac> MAC = ThreadLocal.withInitial(() -> {
static {
try { try {
mac = Mac.getInstance(HMAC_ALGO); return Mac.getInstance(HMAC_ALGO);
} catch (NoSuchAlgorithmException e) { } 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() { private static Mac hmacSHA1() {
try { Mac instance = MAC.get();
Mac hmac = (Mac) mac.clone(); instance.reset();
hmac.reset(); return instance;
return hmac;
} catch (CloneNotSupportedException e) {
throw new IllegalStateException("could not create [HmacSHA1] MAC", e);
}
} }
} }
/** /**

View File

@ -37,7 +37,7 @@ public class RestShieldInfoAction extends BaseRestHandler {
super(settings, client); super(settings, client);
this.clusterName = clusterName; this.clusterName = clusterName;
this.shieldLicenseState = licenseState; this.shieldLicenseState = licenseState;
this.shieldEnabled = ShieldPlugin.shieldEnabled(settings); this.shieldEnabled = ShieldPlugin.enabled(settings);
controller.registerHandler(GET, "/_shield", this); controller.registerHandler(GET, "/_shield", this);
controller.registerHandler(HEAD, "/_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.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.realm.ClearRealmCacheRequest; import org.elasticsearch.shield.action.realm.ClearRealmCacheRequest;
import org.elasticsearch.shield.action.realm.ClearRealmCacheResponse; 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; 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); 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 @Override
public RestResponse buildResponse(ClearRealmCacheResponse response, XContentBuilder builder) throws Exception { public RestResponse buildResponse(ClearRealmCacheResponse response, XContentBuilder builder) throws Exception {
response.toXContent(builder, ToXContent.EMPTY_PARAMS); 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.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.role.AddRoleRequest; import org.elasticsearch.shield.action.role.AddRoleRequest;
import org.elasticsearch.shield.action.role.AddRoleResponse; 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 * 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()); AddRoleRequest addRoleReq = new AddRoleRequest(request.content());
addRoleReq.name(request.param("id")); addRoleReq.name(request.param("id"));
new ShieldClient(client).addRole(addRoleReq, new RestBuilderListener<AddRoleResponse>(channel) { new SecurityClient(client).addRole(addRoleReq, new RestBuilderListener<AddRoleResponse>(channel) {
@Override @Override
public RestResponse buildResponse(AddRoleResponse addRoleResponse, XContentBuilder builder) throws Exception { public RestResponse buildResponse(AddRoleResponse addRoleResponse, XContentBuilder builder) throws Exception {
return new BytesRestResponse(RestStatus.OK, 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.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.role.ClearRolesCacheRequest; import org.elasticsearch.shield.action.role.ClearRolesCacheRequest;
import org.elasticsearch.shield.action.role.ClearRolesCacheResponse; 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; import static org.elasticsearch.rest.RestRequest.Method.POST;
@ -42,7 +42,7 @@ public class RestClearRolesCacheAction extends BaseRestHandler {
ClearRolesCacheRequest req = new ClearRolesCacheRequest().roles(roles); 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 @Override
public RestResponse buildResponse(ClearRolesCacheResponse response, XContentBuilder builder) throws Exception { public RestResponse buildResponse(ClearRolesCacheResponse response, XContentBuilder builder) throws Exception {
response.toXContent(builder, ToXContent.EMPTY_PARAMS); 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.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.role.DeleteRoleRequest; import org.elasticsearch.shield.action.role.DeleteRoleRequest;
import org.elasticsearch.shield.action.role.DeleteRoleResponse; 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 * Rest endpoint to delete a Role from the shield index
@ -37,7 +37,7 @@ public class RestDeleteRoleAction extends BaseRestHandler {
String role = request.param("id"); String role = request.param("id");
DeleteRoleRequest delRoleRequest = new DeleteRoleRequest(role); DeleteRoleRequest delRoleRequest = new DeleteRoleRequest(role);
new ShieldClient(client).deleteRole(delRoleRequest, new RestBuilderListener<DeleteRoleResponse>(channel) { new SecurityClient(client).deleteRole(delRoleRequest, new RestBuilderListener<DeleteRoleResponse>(channel) {
@Override @Override
public RestResponse buildResponse(DeleteRoleResponse response, XContentBuilder builder) throws Exception { public RestResponse buildResponse(DeleteRoleResponse response, XContentBuilder builder) throws Exception {
return new BytesRestResponse(response.found() ? RestStatus.OK : RestStatus.NOT_FOUND, 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.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener; import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.role.GetRolesResponse; 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 * 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 { protected void handleRequest(RestRequest request, final RestChannel channel, Client client) throws Exception {
String[] roles = Strings.splitStringByCommaToArray(request.param("id")); 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 @Override
public RestResponse buildResponse(GetRolesResponse getRolesResponse, XContentBuilder builder) throws Exception { public RestResponse buildResponse(GetRolesResponse getRolesResponse, XContentBuilder builder) throws Exception {
builder.startObject(); builder.startObject();

View File

@ -20,7 +20,7 @@ import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener; import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.user.AddUserRequest; import org.elasticsearch.shield.action.user.AddUserRequest;
import org.elasticsearch.shield.action.user.AddUserResponse; 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 * 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.username(request.param("username"));
addUserReq.source(request.content()); addUserReq.source(request.content());
new ShieldClient(client).addUser(addUserReq, new RestBuilderListener<AddUserResponse>(channel) { new SecurityClient(client).addUser(addUserReq, new RestBuilderListener<AddUserResponse>(channel) {
@Override @Override
public RestResponse buildResponse(AddUserResponse addUserResponse, XContentBuilder builder) throws Exception { public RestResponse buildResponse(AddUserResponse addUserResponse, XContentBuilder builder) throws Exception {
return new BytesRestResponse(RestStatus.OK, 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.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.user.DeleteUserRequest; import org.elasticsearch.shield.action.user.DeleteUserRequest;
import org.elasticsearch.shield.action.user.DeleteUserResponse; 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 * Rest action to delete a user from the shield index
@ -37,7 +37,7 @@ public class RestDeleteUserAction extends BaseRestHandler {
String user = request.param("username"); String user = request.param("username");
DeleteUserRequest delUserRequest = new DeleteUserRequest(user); DeleteUserRequest delUserRequest = new DeleteUserRequest(user);
new ShieldClient(client).deleteUser(delUserRequest, new RestBuilderListener<DeleteUserResponse>(channel) { new SecurityClient(client).deleteUser(delUserRequest, new RestBuilderListener<DeleteUserResponse>(channel) {
@Override @Override
public RestResponse buildResponse(DeleteUserResponse response, XContentBuilder builder) throws Exception { public RestResponse buildResponse(DeleteUserResponse response, XContentBuilder builder) throws Exception {
return new BytesRestResponse(response.found() ? RestStatus.OK : RestStatus.NOT_FOUND, 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.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.action.user.GetUsersResponse; 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 * 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 { protected void handleRequest(RestRequest request, final RestChannel channel, Client client) throws Exception {
String[] users = Strings.splitStringByCommaToArray(request.param("username")); 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 @Override
public RestResponse buildResponse(GetUsersResponse getUsersResponse, XContentBuilder builder) throws Exception { public RestResponse buildResponse(GetUsersResponse getUsersResponse, XContentBuilder builder) throws Exception {
builder.startObject(); builder.startObject();

View File

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

View File

@ -9,7 +9,7 @@ SYNOPSIS
DESCRIPTION DESCRIPTION
Generates the system key and stores in the system_key file. By default 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' is customized in the elasticsearch.yml (under the 'shield.system_key.file'
setting), the generated key will be stored in that custom location. 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.ShieldIntegTestCase;
import org.elasticsearch.test.ShieldSettingsSource; import org.elasticsearch.test.ShieldSettingsSource;
import org.elasticsearch.test.rest.client.http.HttpResponse; import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.elasticsearch.xpack.XPackPlugin;
import java.io.IOException; import java.io.IOException;
@ -30,7 +31,7 @@ public class BulkUpdateTests extends ShieldIntegTestCase {
return Settings.builder() return Settings.builder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(NetworkModule.HTTP_ENABLED.getKey(), true) .put(NetworkModule.HTTP_ENABLED.getKey(), true)
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, randomBoolean()) .put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), randomBoolean())
.build(); .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.SecuredString;
import org.elasticsearch.shield.authc.support.SecuredStringTests; import org.elasticsearch.shield.authc.support.SecuredStringTests;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken; 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.ShieldIntegTestCase;
import org.elasticsearch.test.ShieldSettingsSource; import org.elasticsearch.test.ShieldSettingsSource;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder; import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
@ -140,11 +140,11 @@ public class ClearRealmsCacheTests extends ShieldIntegTestCase {
public abstract void executeRequest() throws Exception; public abstract void executeRequest() throws Exception;
static void executeTransportRequest(ClearRealmCacheRequest request) 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 CountDownLatch latch = new CountDownLatch(1);
final AtomicReference<Throwable> error = new AtomicReference<>(); final AtomicReference<Throwable> error = new AtomicReference<>();
shieldClient.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() { securityClient.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() {
@Override @Override
public void onResponse(ClearRealmCacheResponse response) { public void onResponse(ClearRealmCacheResponse response) {
assertThat(response.getNodes().length, equalTo(internalCluster().getNodeNames().length)); 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.authc.support.UsernamePasswordToken;
import org.elasticsearch.shield.authz.RoleDescriptor; import org.elasticsearch.shield.authz.RoleDescriptor;
import org.elasticsearch.shield.authz.esnative.ESNativeRolesStore; 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.ShieldIntegTestCase;
import org.elasticsearch.test.ShieldSettingsSource; import org.elasticsearch.test.ShieldSettingsSource;
import org.elasticsearch.test.junit.annotations.TestLogging; import org.elasticsearch.test.junit.annotations.TestLogging;
@ -57,7 +57,7 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
@Before @Before
public void setupForTest() throws Exception { public void setupForTest() throws Exception {
// Clear the realm cache for all realms since we use a SUITE scoped cluster // 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(); client.prepareClearRealmCache().get();
for (ESNativeUsersStore store : internalCluster().getInstances(ESNativeUsersStore.class)) { 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 // create roles
for (String role : roles) { for (String role : roles) {
c.prepareAddRole().name(role) c.prepareAddRole().name(role)
@ -109,13 +109,13 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
public void testModifyingViaApiClearsCache() throws Exception { public void testModifyingViaApiClearsCache() throws Exception {
Client client = internalCluster().transportClient(); Client client = internalCluster().transportClient();
ShieldClient shieldClient = new ShieldClient(client); SecurityClient securityClient = securityClient(client);
int modifiedRolesCount = randomIntBetween(1, roles.length); int modifiedRolesCount = randomIntBetween(1, roles.length);
List<String> toModify = randomSubsetOf(modifiedRolesCount, roles); List<String> toModify = randomSubsetOf(modifiedRolesCount, roles);
logger.debug("--> modifying roles {} to have run_as", toModify); logger.debug("--> modifying roles {} to have run_as", toModify);
for (String role : toModify) { for (String role : toModify) {
AddRoleResponse response = shieldClient.prepareAddRole().name(role) AddRoleResponse response = securityClient.prepareAddRole().name(role)
.cluster("none") .cluster("none")
.addIndices(new String[] { "*" }, new String[] { "ALL" }, null, null) .addIndices(new String[] { "*" }, new String[] { "ALL" }, null, null)
.runAs(role) .runAs(role)
@ -124,7 +124,7 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
logger.debug("--> updated role [{}] with run_as", role); logger.debug("--> updated role [{}] with run_as", role);
} }
assertRolesAreCorrect(shieldClient, toModify); assertRolesAreCorrect(securityClient, toModify);
} }
public void testModifyingDocumentsDirectly() throws Exception { 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 // 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! // 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 useHttp = randomBoolean();
final boolean clearAll = randomBoolean(); final boolean clearAll = randomBoolean();
logger.debug("--> starting to clear roles. using http [{}] clearing all [{}]", useHttp, clearAll); logger.debug("--> starting to clear roles. using http [{}] clearing all [{}]", useHttp, clearAll);
@ -163,18 +163,18 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
.execute(); .execute();
assertThat(response.getStatusCode(), is(RestStatus.OK.getStatus())); assertThat(response.getStatusCode(), is(RestStatus.OK.getStatus()));
} else { } else {
shieldClient.prepareClearRolesCache().roles(rolesToClear).get(); securityClient.prepareClearRolesCache().roles(rolesToClear).get();
} }
assertRolesAreCorrect(shieldClient, toModify); assertRolesAreCorrect(securityClient, toModify);
} }
public void testDeletingRoleDocumentDirectly() throws Exception { public void testDeletingRoleDocumentDirectly() throws Exception {
Client client = internalCluster().transportClient(); Client client = internalCluster().transportClient();
ShieldClient shieldClient = new ShieldClient(client); SecurityClient securityClient = securityClient(client);
final String role = randomFrom(roles); 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)); assertThat(foundRoles.size(), is(1));
logger.debug("--> deleting role [{}]", role); logger.debug("--> deleting role [{}]", role);
DeleteResponse response = client.prepareDelete(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME, DeleteResponse response = client.prepareDelete(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME,
@ -184,15 +184,15 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
assertBusy(new Runnable() { assertBusy(new Runnable() {
@Override @Override
public void run() { 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) { for (String role : roles) {
logger.debug("--> getting role [{}]", role); logger.debug("--> getting role [{}]", role);
GetRolesResponse roleResponse = shieldClient.prepareGetRoles().roles(role).get(); GetRolesResponse roleResponse = securityClient.prepareGetRoles().roles(role).get();
assertThat(roleResponse.isExists(), is(true)); assertThat(roleResponse.isExists(), is(true));
final String[] runAs = roleResponse.roles().get(0).getRunAs(); final String[] runAs = roleResponse.roles().get(0).getRunAs();
if (toModify.contains(role)) { 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.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.Collections; import java.util.Collections;
@ -75,7 +76,7 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase {
public Settings nodeSettings(int nodeOrdinal) { public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder() return Settings.builder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true) .put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), true)
.build(); .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.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -74,7 +75,7 @@ public class DocumentLevelSecurityRandomTests extends ShieldIntegTestCase {
public Settings nodeSettings(int nodeOrdinal) { public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder() return Settings.builder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true) .put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), true)
.build(); .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.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.Collections; import java.util.Collections;
@ -87,7 +88,7 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
public Settings nodeSettings(int nodeOrdinal) { public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder() return Settings.builder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true) .put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), true)
.build(); .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.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -111,7 +112,7 @@ public class FieldLevelSecurityRandomTests extends ShieldIntegTestCase {
public Settings nodeSettings(int nodeOrdinal) { public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder() return Settings.builder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true) .put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), true)
.build(); .build();
} }

View File

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

View File

@ -8,10 +8,11 @@ package org.elasticsearch.integration;
import org.apache.lucene.util.LuceneTestCase.BadApple; import org.apache.lucene.util.LuceneTestCase.BadApple;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; 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.elasticsearch.test.rest.client.http.HttpResponse;
import org.junit.Before; import org.junit.Before;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; 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 //test is just too slow, please fix it to not be sleep-based
@BadApple(bugUrl = "https://github.com/elastic/x-plugins/issues/1007") @BadApple(bugUrl = "https://github.com/elastic/x-plugins/issues/1007")
@ESIntegTestCase.ClusterScope(randomDynamicTemplates = false)
public class IndexPrivilegeTests extends AbstractPrivilegeTestCase { public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
private String jsonDoc = "{ \"name\" : \"elasticsearch\"}"; private String jsonDoc = "{ \"name\" : \"elasticsearch\"}";
@ -94,8 +96,7 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
"u11:" + USERS_PASSWD_HASHED + "\n" + "u11:" + USERS_PASSWD_HASHED + "\n" +
"u12:" + USERS_PASSWD_HASHED + "\n" + "u12:" + USERS_PASSWD_HASHED + "\n" +
"u13:" + USERS_PASSWD_HASHED + "\n" + "u13:" + USERS_PASSWD_HASHED + "\n" +
"u14:" + USERS_PASSWD_HASHED + "\n" + "u14:" + USERS_PASSWD_HASHED + "\n";
"u15:" + USERS_PASSWD_HASHED + "\n";
public static final String USERS_ROLES = public static final String USERS_ROLES =
"all_indices_role:admin,u8\n" + "all_indices_role:admin,u8\n" +
@ -120,7 +121,6 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
protected Settings nodeSettings(int nodeOrdinal) { protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder().put(super.nodeSettings(nodeOrdinal)) return Settings.builder().put(super.nodeSettings(nodeOrdinal))
.put(NetworkModule.HTTP_ENABLED.getKey(), true) .put(NetworkModule.HTTP_ENABLED.getKey(), true)
.put("action.disable_shutdown", true)
.build(); .build();
} }
@ -139,6 +139,17 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
return super.configUsersRoles() + USERS_ROLES; 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 @Before
public void insertBaseDocumentsAsAdmin() throws Exception { public void insertBaseDocumentsAsAdmin() throws Exception {
// indices: a,b,c,abc // indices: a,b,c,abc
@ -296,24 +307,13 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
assertUserIsDenied("u14", "all", "c"); 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 { public void testThatUnknownUserIsRejectedProperly() throws Exception {
HttpResponse response = executeRequest("idonotexist", "GET", "/", null, new HashMap<>()); HttpResponse response = executeRequest("idonotexist", "GET", "/", null, new HashMap<>());
assertThat(response.getStatusCode(), is(401)); assertThat(response.getStatusCode(), is(401));
} }
private void assertUserExecutes(String user, String action, String index, boolean userIsAllowed) throws Exception { 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) { switch (action) {
case "all" : case "all" :
@ -353,11 +353,6 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
assertAccessIsAllowed("admin", "PUT", "/" + index + "/foo/1", jsonDoc, refreshParams); assertAccessIsAllowed("admin", "PUT", "/" + index + "/foo/1", jsonDoc, refreshParams);
client().admin().cluster().prepareHealth(index).setWaitForGreenStatus().get(); client().admin().cluster().prepareHealth(index).setWaitForGreenStatus().get();
assertAccessIsAllowed(user, "GET", "/" + index + "/_mapping/foo/field/name"); 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"); assertAccessIsAllowed(user, "GET", "/" + index + "/_settings");
} else { } else {
assertAccessIsDenied(user, "DELETE", "/" + index); assertAccessIsDenied(user, "DELETE", "/" + index);
@ -372,9 +367,6 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
assertAccessIsDenied(user, "POST", "/" + index + "/_open"); assertAccessIsDenied(user, "POST", "/" + index + "/_open");
assertAccessIsDenied(user, "POST", "/" + index + "/_cache/clear"); assertAccessIsDenied(user, "POST", "/" + index + "/_cache/clear");
assertAccessIsDenied(user, "GET", "/" + index + "/_mapping/foo/field/name"); 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"); assertAccessIsDenied(user, "GET", "/" + index + "/_settings");
} }
break; 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.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.Collections; import java.util.Collections;
@ -60,7 +61,7 @@ public class IndicesPermissionsWithAliasesWildcardsAndRegexsTests extends Shield
public Settings nodeSettings(int nodeOrdinal) { public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder() return Settings.builder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true) .put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), true)
.build(); .build();
} }

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.integration; package org.elasticsearch.integration;
import org.apache.lucene.util.LuceneTestCase.BadApple;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse; import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse; 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, * actions that are normally categorized as index actions as cluster actions - for example,
* index template actions. * 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 { public class PermissionPrecedenceTests extends ShieldIntegTestCase {
protected static final String USERS_PASSWD_HASHED = new String(Hasher.BCRYPT.hash(new SecuredString("test123".toCharArray()))); 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")); logger.info("******* shield is " + (enabled ? "enabled" : "disabled"));
return Settings.settingsBuilder() return Settings.settingsBuilder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.ENABLED_SETTING_NAME, enabled) .put(XPackPlugin.featureEnabledSetting(ShieldPlugin.NAME), enabled)
.put(NetworkModule.HTTP_ENABLED.getKey(), true) .put(NetworkModule.HTTP_ENABLED.getKey(), true)
.build(); .build();
} }
@ -75,7 +75,7 @@ public class ShieldPluginEnabledDisabledTests extends ShieldIntegTestCase {
protected Settings transportClientSettings() { protected Settings transportClientSettings() {
return Settings.settingsBuilder() return Settings.settingsBuilder()
.put(super.transportClientSettings()) .put(super.transportClientSettings())
.put(ShieldPlugin.ENABLED_SETTING_NAME, enabled) .put(XPackPlugin.featureEnabledSetting(ShieldPlugin.NAME), enabled)
.build(); .build();
} }

View File

@ -7,6 +7,7 @@ package org.elasticsearch.shield;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
@ -14,8 +15,9 @@ import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.arrayContaining;
public class ShieldPluginSettingsTests extends ESTestCase { 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() { public void testShieldIsMandatoryOnTribes() {
Settings settings = Settings.builder().put("tribe.t1.cluster.name", "non_existing") Settings settings = Settings.builder().put("tribe.t1.cluster.name", "non_existing")
@ -26,8 +28,8 @@ public class ShieldPluginSettingsTests extends ESTestCase {
Settings additionalSettings = shieldPlugin.additionalSettings(); Settings additionalSettings = shieldPlugin.additionalSettings();
assertThat(additionalSettings.getAsArray("tribe.t1.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(ShieldPlugin.NAME)); assertThat(additionalSettings.getAsArray("tribe.t2.plugin.mandatory", null), arrayContaining(XPackPlugin.NAME));
} }
public void testAdditionalMandatoryPluginsOnTribes() { public void testAdditionalMandatoryPluginsOnTribes() {
@ -41,14 +43,14 @@ public class ShieldPluginSettingsTests extends ESTestCase {
Settings.builder().put(settings).put(shieldPlugin.additionalSettings()).build(); 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"); fail("shield cannot change the value of a setting that is already defined, so a exception should be thrown");
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("shield")); assertThat(e.getMessage(), containsString(XPackPlugin.NAME));
assertThat(e.getMessage(), containsString("plugin.mandatory")); assertThat(e.getMessage(), containsString("plugin.mandatory"));
} }
} }
public void testMandatoryPluginsOnTribesShieldAlreadyMandatory() { public void testMandatoryPluginsOnTribesShieldAlreadyMandatory() {
Settings settings = Settings.builder().put("tribe.t1.cluster.name", "non_existing") 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); ShieldPlugin shieldPlugin = new ShieldPlugin(settings);
@ -59,7 +61,7 @@ public class ShieldPluginSettingsTests extends ESTestCase {
assertThat(finalMandatoryPlugins, notNullValue()); assertThat(finalMandatoryPlugins, notNullValue());
assertThat(finalMandatoryPlugins.length, equalTo(2)); assertThat(finalMandatoryPlugins.length, equalTo(2));
assertThat(finalMandatoryPlugins[0], equalTo("test_plugin")); assertThat(finalMandatoryPlugins[0], equalTo("test_plugin"));
assertThat(finalMandatoryPlugins[1], equalTo(ShieldPlugin.NAME)); assertThat(finalMandatoryPlugins[1], equalTo(XPackPlugin.NAME));
} }
public void testShieldIsEnabledByDefaultOnTribes() { public void testShieldIsEnabledByDefaultOnTribes() {
@ -93,7 +95,7 @@ public class ShieldPluginSettingsTests extends ESTestCase {
Settings settings = Settings.builder().put("tribe.t1.cluster.name", "non_existing") Settings settings = Settings.builder().put("tribe.t1.cluster.name", "non_existing")
.put(TRIBE_T1_SHIELD_ENABLED, false) .put(TRIBE_T1_SHIELD_ENABLED, false)
.put("tribe.t2.cluster.name", "non_existing") .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); 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.TransportInfo;
import org.elasticsearch.transport.TransportMessage; import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.xpack.XPackPlugin;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import org.joda.time.format.ISODateTimeFormat; import org.joda.time.format.ISODateTimeFormat;
@ -166,18 +167,21 @@ public class IndexAuditTrailTests extends ShieldIntegTestCase {
public Settings nodeSettings(int nodeOrdinal) { public Settings nodeSettings(int nodeOrdinal) {
Settings.Builder builder = Settings.builder() Settings.Builder builder = Settings.builder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.ENABLED_SETTING_NAME, useShield); .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, // For tests we forcefully configure Shield's custom query cache because the test framework
// but if shield is disabled then we don't need to forcefully set the query cache // randomizes the query cache impl but if shield is disabled then we don't need to forcefully
// set the query cache
if (useShield == false) { if (useShield == false) {
builder.remove(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey()); builder.remove(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey());
} }
return builder.build(); return builder.build();
} }
}; };
cluster2 = new InternalTestCluster("network", randomLong(), createTempDir(), numNodes, numNodes, cluster2Name, 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); cluster2.beforeTest(getRandom(), 0.5);
remoteClient = cluster2.client(); remoteClient = cluster2.client();
@ -187,7 +191,7 @@ public class IndexAuditTrailTests extends ShieldIntegTestCase {
Settings.Builder builder = Settings.builder() Settings.Builder builder = Settings.builder()
.put(settings) .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(remoteSettings(NetworkAddress.formatAddress(inet.address().getAddress()), inet.address().getPort(), cluster2Name))
.put("shield.audit.index.client.shield.user", DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD); .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.RoleDescriptor;
import org.elasticsearch.shield.authz.esnative.ESNativeRolesStore; import org.elasticsearch.shield.authz.esnative.ESNativeRolesStore;
import org.elasticsearch.shield.authz.permission.Role; 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.ShieldIntegTestCase;
import org.elasticsearch.test.ShieldSettingsSource; import org.elasticsearch.test.ShieldSettingsSource;
import org.junit.After; import org.junit.After;
@ -43,7 +43,7 @@ import static org.hamcrest.Matchers.isOneOf;
public class ESNativeTests extends ShieldIntegTestCase { public class ESNativeTests extends ShieldIntegTestCase {
public void testDeletingNonexistingUserAndRole() throws Exception { public void testDeletingNonexistingUserAndRole() throws Exception {
ShieldClient c = new ShieldClient(client()); SecurityClient c = securityClient();
DeleteUserResponse resp = c.prepareDeleteUser().user("joe").get(); DeleteUserResponse resp = c.prepareDeleteUser().user("joe").get();
assertFalse("user shouldn't be found", resp.found()); assertFalse("user shouldn't be found", resp.found());
DeleteRoleResponse resp2 = c.prepareDeleteRole().role("role").get(); DeleteRoleResponse resp2 = c.prepareDeleteRole().role("role").get();
@ -51,7 +51,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
} }
public void testGettingUserThatDoesntExist() throws Exception { public void testGettingUserThatDoesntExist() throws Exception {
ShieldClient c = new ShieldClient(client()); SecurityClient c = securityClient();
GetUsersResponse resp = c.prepareGetUsers().users("joe").get(); GetUsersResponse resp = c.prepareGetUsers().users("joe").get();
assertFalse("user should not exist", resp.isExists()); assertFalse("user should not exist", resp.isExists());
GetRolesResponse resp2 = c.prepareGetRoles().roles("role").get(); GetRolesResponse resp2 = c.prepareGetRoles().roles("role").get();
@ -59,7 +59,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
} }
public void testAddAndGetUser() throws Exception { public void testAddAndGetUser() throws Exception {
ShieldClient c = new ShieldClient(client()); SecurityClient c = securityClient();
logger.error("--> creating user"); logger.error("--> creating user");
c.prepareAddUser() c.prepareAddUser()
.username("joe") .username("joe")
@ -117,7 +117,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
} }
public void testAddAndGetRole() throws Exception { public void testAddAndGetRole() throws Exception {
ShieldClient c = new ShieldClient(client()); SecurityClient c = securityClient();
logger.error("--> creating role"); logger.error("--> creating role");
c.prepareAddRole() c.prepareAddRole()
.name("test_role") .name("test_role")
@ -171,7 +171,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
} }
public void testAddUserAndRoleThenAuth() throws Exception { public void testAddUserAndRoleThenAuth() throws Exception {
ShieldClient c = new ShieldClient(client()); SecurityClient c = securityClient();
logger.error("--> creating role"); logger.error("--> creating role");
c.prepareAddRole() c.prepareAddRole()
.name("test_role") .name("test_role")
@ -204,7 +204,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
} }
public void testUpdatingUserAndAuthentication() throws Exception { public void testUpdatingUserAndAuthentication() throws Exception {
ShieldClient c = new ShieldClient(client()); SecurityClient c = securityClient();
logger.error("--> creating user"); logger.error("--> creating user");
c.prepareAddUser() c.prepareAddUser()
.username("joe") .username("joe")
@ -248,7 +248,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
} }
public void testCreateDeleteAuthenticate() { public void testCreateDeleteAuthenticate() {
ShieldClient c = new ShieldClient(client()); SecurityClient c = securityClient();
logger.error("--> creating user"); logger.error("--> creating user");
c.prepareAddUser() c.prepareAddUser()
.username("joe") .username("joe")
@ -285,7 +285,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
public void testCreateAndUpdateRole() { public void testCreateAndUpdateRole() {
final boolean authenticate = randomBoolean(); final boolean authenticate = randomBoolean();
ShieldClient c = new ShieldClient(client()); SecurityClient c = securityClient();
logger.error("--> creating role"); logger.error("--> creating role");
c.prepareAddRole() c.prepareAddRole()
.name("test_role") .name("test_role")
@ -340,7 +340,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
} }
public void testAuthenticateWithDeletedRole() { public void testAuthenticateWithDeletedRole() {
ShieldClient c = new ShieldClient(client()); SecurityClient c = securityClient();
logger.error("--> creating role"); logger.error("--> creating role");
c.prepareAddRole() c.prepareAddRole()
.name("test_role") .name("test_role")
@ -373,7 +373,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
@Before @Before
public void ensureStoresStarted() throws Exception { public void ensureStoresStarted() throws Exception {
// Clear the realm cache for all realms since we use a SUITE scoped cluster // 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(); client.prepareClearRealmCache().get();
for (ESNativeUsersStore store : internalCluster().getInstances(ESNativeUsersStore.class)) { for (ESNativeUsersStore store : internalCluster().getInstances(ESNativeUsersStore.class)) {

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.shield.authc.support; package org.elasticsearch.shield.authc.support;
import org.apache.lucene.util.LuceneTestCase.BadApple;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.shield.User; 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.nullValue;
import static org.hamcrest.Matchers.sameInstance; 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 { public class CachingUsernamePasswordRealmTests extends ESTestCase {
private Settings globalSettings; private Settings globalSettings;
@ -206,7 +203,9 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
}; };
final CountDownLatch latch = new CountDownLatch(1); 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<>(); List<Thread> threads = new ArrayList<>();
for (int i = 0; i < numberOfThreads; i++) { for (int i = 0; i < numberOfThreads; i++) {
final boolean invalidPassword = randomBoolean(); final boolean invalidPassword = randomBoolean();
@ -215,9 +214,9 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
public void run() { public void run() {
try { try {
latch.await(); latch.await();
for (int i = 0; i < 100; i++) { for (int i = 0; i < numberOfIterations; i++) {
User user = realm.authenticate( UsernamePasswordToken token = new UsernamePasswordToken(username, invalidPassword ? randomPassword : password);
new UsernamePasswordToken(username, invalidPassword ? randomPassword : password)); User user = realm.authenticate(token);
if (invalidPassword && user != null) { if (invalidPassword && user != null) {
throw new RuntimeException("invalid password led to an authenticated user: " + user.toString()); throw new RuntimeException("invalid password led to an authenticated user: " + user.toString());
} else if (invalidPassword == false && user == null) { } 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("whatever"), is(false));
assertThat(predicate.test("cluster:admin/reroute"), is(true)); assertThat(predicate.test("cluster:admin/reroute"), is(true));
assertThat(predicate.test("cluster:admin/whatever"), is(false)); 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)); 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.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.OutputStream; import java.io.OutputStream;
@ -52,8 +53,9 @@ public class FileRolesStoreTests extends ESTestCase {
public void testParseFile() throws Exception { public void testParseFile() throws Exception {
Path path = getDataPath("roles.yml"); Path path = getDataPath("roles.yml");
Map<String, Role> roles = FileRolesStore.parseFile(path, logger, Map<String, Role> roles = FileRolesStore.parseFile(path, logger, Settings.builder()
Settings.builder().put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true).build()); .put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), true)
.build());
assertThat(roles, notNullValue()); assertThat(roles, notNullValue());
assertThat(roles.size(), is(10)); assertThat(roles.size(), is(10));
@ -208,8 +210,9 @@ public class FileRolesStoreTests extends ESTestCase {
public void testParseFileWithFLSAndDLSDisabled() throws Exception { public void testParseFileWithFLSAndDLSDisabled() throws Exception {
Path path = getDataPath("roles.yml"); Path path = getDataPath("roles.yml");
CapturingLogger logger = new CapturingLogger(CapturingLogger.Level.ERROR); CapturingLogger logger = new CapturingLogger(CapturingLogger.Level.ERROR);
Map<String, Role> roles = FileRolesStore.parseFile(path, Map<String, Role> roles = FileRolesStore.parseFile(path, logger, Settings.builder()
logger, Settings.builder().put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, false).build()); .put(XPackPlugin.featureEnabledSetting(ShieldPlugin.DLS_FLS_FEATURE), false)
.build());
assertThat(roles, notNullValue()); assertThat(roles, notNullValue());
assertThat(roles.size(), is(7)); assertThat(roles.size(), is(7));
assertThat(roles.get("role_fields"), nullValue()); 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 { public void testThatSSLSocketFactoryHasProperCiphersAndProtocols() throws Exception {
ClientSSLService sslService = createClientSSLService(settingsBuilder() ClientSSLService sslService = createClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore) .put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient") .put("shield.ssl.keystore.password", "testclient")
.build()); .build());
SSLSocketFactory factory = sslService.sslSocketFactory(); 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()) { try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
assertThat(socket.getEnabledCipherSuites(), is(sslService.ciphers())); assertThat(socket.getEnabledCipherSuites(), is(ciphers));
assertThat(socket.getEnabledProtocols(), is(sslService.supportedProtocols())); 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.notNullValue;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance; import static org.hamcrest.Matchers.sameInstance;
import static org.mockito.Mockito.mock;
public class ServerSSLServiceTests extends ESTestCase { public class ServerSSLServiceTests extends ESTestCase {
Path testnodeStore; 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 { public void testThatSSLSocketFactoryHasProperCiphersAndProtocols() throws Exception {
ServerSSLService sslService = new ServerSSLService(settingsBuilder() ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore) .put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode") .put("shield.ssl.keystore.password", "testnode")
.build(), env); .build(), env);
SSLSocketFactory factory = sslService.sslSocketFactory(); 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()) { try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
assertThat(socket.getEnabledCipherSuites(), is(sslService.ciphers())); assertThat(socket.getEnabledCipherSuites(), is(ciphers));
assertThat(socket.getEnabledProtocols(), is(sslService.supportedProtocols())); 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.plugins.Plugin;
import org.elasticsearch.shield.InternalClient; import org.elasticsearch.shield.InternalClient;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.client.SecurityClient;
import org.elasticsearch.test.ESIntegTestCase.SuppressLocalMode; import org.elasticsearch.test.ESIntegTestCase.SuppressLocalMode;
import org.elasticsearch.test.transport.AssertingLocalTransport; import org.elasticsearch.test.transport.AssertingLocalTransport;
import org.elasticsearch.test.transport.MockTransportService; import org.elasticsearch.test.transport.MockTransportService;
import org.elasticsearch.xpack.XPackClient;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
@ -267,6 +269,7 @@ public abstract class ShieldIntegTestCase extends ESIntegTestCase {
} }
private class CustomShieldSettingsSource extends ShieldSettingsSource { private class CustomShieldSettingsSource extends ShieldSettingsSource {
private CustomShieldSettingsSource(boolean sslTransportEnabled, Path configDir, Scope scope) { private CustomShieldSettingsSource(boolean sslTransportEnabled, Path configDir, Scope scope) {
super(maxNumberOfNodes(), sslTransportEnabled, configDir, scope); super(maxNumberOfNodes(), sslTransportEnabled, configDir, scope);
} }
@ -339,4 +342,12 @@ public abstract class ShieldIntegTestCase extends ESIntegTestCase {
protected InternalClient internalClient(String node) { protected InternalClient internalClient(String node) {
return internalCluster().getInstance(InternalClient.class, 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.ShieldPlugin;
import org.elasticsearch.shield.transport.ShieldServerTransportService; import org.elasticsearch.shield.transport.ShieldServerTransportService;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.Map; import java.util.Map;
@ -21,7 +22,7 @@ public class ShieldServerTransportServiceTests extends ShieldIntegTestCase {
protected Settings transportClientSettings() { protected Settings transportClientSettings() {
return Settings.settingsBuilder() return Settings.settingsBuilder()
.put(super.transportClientSettings()) .put(super.transportClientSettings())
.put(ShieldPlugin.ENABLED_SETTING_NAME, true) .put(XPackPlugin.featureEnabledSetting(ShieldPlugin.NAME), true)
.build(); .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.SpecialPermission;
import org.elasticsearch.action.ActionModule; import org.elasticsearch.action.ActionModule;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.component.LifecycleComponent; import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module; 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.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule; import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.IndexModule;
import org.elasticsearch.license.plugin.LicensePlugin; import org.elasticsearch.license.plugin.LicensePlugin;
import org.elasticsearch.marvel.MarvelPlugin; import org.elasticsearch.marvel.MarvelPlugin;
@ -22,6 +22,7 @@ import org.elasticsearch.script.ScriptModule;
import org.elasticsearch.shield.ShieldPlugin; import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.watcher.WatcherPlugin; import org.elasticsearch.watcher.WatcherPlugin;
import java.nio.file.Path;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.util.ArrayList; import java.util.ArrayList;
@ -29,9 +30,7 @@ import java.util.Collection;
public class XPackPlugin extends Plugin { public class XPackPlugin extends Plugin {
public static final String NAME = "x-pack"; public static final String NAME = "xpack";
private final static ESLogger logger = Loggers.getLogger(XPackPlugin.class);
// TODO: clean up this library to not ask for write access to all system properties! // TODO: clean up this library to not ask for write access to all system properties!
static { static {
@ -143,4 +142,30 @@ public class XPackPlugin extends Plugin {
watcherPlugin.onIndexModule(module); watcherPlugin.onIndexModule(module);
marvelPlugin.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: - do:
nodes.info: {} 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 REM Disables explicit GC
set JAVA_OPTS=%JAVA_OPTS% -XX:+DisableExplicitGC 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 ES_PARAMS=-Des.path.home="%ES_HOME%"
SET HOSTNAME=%COMPUTERNAME% SET HOSTNAME=%COMPUTERNAME%

View File

@ -114,7 +114,7 @@ fi
export HOSTNAME=`hostname -s` export HOSTNAME=`hostname -s`
# include watcher jars in classpath # 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 cd "$ES_HOME" > /dev/null
$JAVA $ES_JAVA_OPTS -cp "$ES_CLASSPATH" org.elasticsearch.watcher.trigger.schedule.tool.CronEvalTool "$@" $properties $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; package org.elasticsearch.watcher;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.multibindings.Multibinder; import org.elasticsearch.common.inject.multibindings.Multibinder;
import org.elasticsearch.common.settings.Setting; 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.WatcherIndexTemplateRegistry.TemplateConfig;
import org.elasticsearch.watcher.support.validation.WatcherSettingsValidation; 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 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 TRIGGERED_TEMPLATE_NAME = "triggered_watches";
public static final String WATCHES_TEMPLATE_NAME = "watches"; public static final String WATCHES_TEMPLATE_NAME = "watches";
public static final Setting<Settings> HISTORY_TEMPLATE_SETTING = Setting.groupSetting("watcher.history.index.", true, 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[]{ public final static TemplateConfig[] TEMPLATE_CONFIGS = new TemplateConfig[]{
new TemplateConfig(TRIGGERED_TEMPLATE_NAME, TRIGGERED_TEMPLATE_SETTING), 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) 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.common.settings.SettingsModule;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.ScriptModule; 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.WatcherActionModule;
import org.elasticsearch.watcher.actions.email.service.EmailService; import org.elasticsearch.watcher.actions.email.service.EmailService;
import org.elasticsearch.watcher.actions.email.service.InternalEmailService; 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.RestWatchServiceAction;
import org.elasticsearch.watcher.rest.action.RestWatcherInfoAction; import org.elasticsearch.watcher.rest.action.RestWatcherInfoAction;
import org.elasticsearch.watcher.rest.action.RestWatcherStatsAction; import org.elasticsearch.watcher.rest.action.RestWatcherStatsAction;
import org.elasticsearch.watcher.shield.ShieldSecretService; import org.elasticsearch.watcher.support.secret.SecretService;
import org.elasticsearch.watcher.shield.WatcherShieldModule;
import org.elasticsearch.watcher.support.WatcherIndexTemplateRegistry.TemplateConfig; import org.elasticsearch.watcher.support.WatcherIndexTemplateRegistry.TemplateConfig;
import org.elasticsearch.watcher.support.clock.ClockModule; import org.elasticsearch.watcher.support.clock.ClockModule;
import org.elasticsearch.watcher.support.http.HttpClient; import org.elasticsearch.watcher.support.http.HttpClient;
@ -91,13 +92,19 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; 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; import static org.elasticsearch.common.settings.Settings.settingsBuilder;
public class WatcherPlugin extends Plugin { public class WatcherPlugin extends Plugin {
public static final String NAME = "watcher"; public static final String NAME = "watcher";
public static final String ENABLED_SETTING = NAME + ".enabled"; 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); 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())); transportClient = "transport".equals(settings.get(Client.CLIENT_TYPE_SETTING_S.getKey()));
enabled = watcherEnabled(settings); enabled = watcherEnabled(settings);
validAutoCreateIndex(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() { @Override public String name() {
return NAME; return NAME;
@ -146,7 +160,6 @@ public class WatcherPlugin extends Plugin {
new WatcherActionModule(), new WatcherActionModule(),
new HistoryModule(), new HistoryModule(),
new ExecutionModule(), new ExecutionModule(),
new WatcherShieldModule(settings),
new SecretModule(settings)); new SecretModule(settings));
} }
@ -193,37 +206,41 @@ public class WatcherPlugin extends Plugin {
module.registerSetting(InternalEmailService.EMAIL_ACCOUNT_SETTING); module.registerSetting(InternalEmailService.EMAIL_ACCOUNT_SETTING);
module.registerSetting(InternalHipChatService.HIPCHAT_ACCOUNT_SETTING); module.registerSetting(InternalHipChatService.HIPCHAT_ACCOUNT_SETTING);
module.registerSetting(InternalPagerDutyService.PAGERDUTY_ACCOUNT_SETTING); module.registerSetting(InternalPagerDutyService.PAGERDUTY_ACCOUNT_SETTING);
module.registerSetting(Setting.intSetting("watcher.execution.scroll.size", 0, false, Setting.Scope.CLUSTER)); module.registerSetting(INDEX_WATCHER_VERSION_SETTING);
module.registerSetting(Setting.intSetting("watcher.watch.scroll.size", 0, false, Setting.Scope.CLUSTER)); module.registerSetting(INDEX_WATCHER_TEMPLATE_VERSION_SETTING);
module.registerSetting(Setting.boolSetting("watcher.enabled", false, false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.intSetting("watcher.execution.scroll.size", 0, false, CLUSTER));
module.registerSetting(ShieldSecretService.ENCRYPT_SENSITIVE_DATA_SETTING); 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 // TODO add real settings for these
module.registerSetting(Setting.simpleString("resource.reload.interval", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("resource.reload.interval", false, CLUSTER));
module.registerSetting(Setting.simpleString("resource.reload.enabled", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("resource.reload.enabled", false, CLUSTER));
module.registerSetting(Setting.simpleString("resource.reload.interval.low", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("resource.reload.interval.low", false, CLUSTER));
module.registerSetting(Setting.simpleString("resource.reload.interval.medium", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("resource.reload.interval.medium", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.internal.ops.search.default_timeout", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("watcher.internal.ops.search.default_timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.internal.ops.bulk.default_timeout", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("watcher.internal.ops.bulk.default_timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.internal.ops.index.default_timeout", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("watcher.internal.ops.index.default_timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.execution.default_throttle_period", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("watcher.execution.default_throttle_period", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.http.default_read_timeout", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("watcher.http.default_read_timeout", false, CLUSTER));
module.registerSetting(Setting.groupSetting("watcher.http.ssl.", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.groupSetting("watcher.http.ssl.", false, CLUSTER));
module.registerSetting(Setting.groupSetting("watcher.http.proxy.", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.groupSetting("watcher.http.proxy.", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.actions.index.default_timeout", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("watcher.actions.index.default_timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.index.rest.direct_access", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("watcher.index.rest.direct_access", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.trigger.schedule.engine", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("watcher.trigger.schedule.engine", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.input.search.default_timeout", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("watcher.input.search.default_timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.transform.search.default_timeout", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("watcher.transform.search.default_timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.trigger.schedule.ticker.tick_interval", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("watcher.trigger.schedule.ticker.tick_interval", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.execution.scroll.timeout", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("watcher.execution.scroll.timeout", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.start_immediately", false, Setting.Scope.CLUSTER)); module.registerSetting(Setting.simpleString("watcher.start_immediately", false, CLUSTER));
module.registerSetting(Setting.simpleString("watcher.http.default_connection_timeout", false, Setting.Scope.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.email.service.account.*.smtp.password");
module.registerSettingsFilter("watcher.actions.slack.service.account.*.url"); module.registerSettingsFilter("watcher.actions.slack.service.account.*.url");
module.registerSettingsFilter("watcher.actions.pagerduty.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." + 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"); module.registerSettingsFilter("watcher.actions.hipchat.service.account.*.auth_token");
} }
@ -265,8 +282,9 @@ public class WatcherPlugin extends Plugin {
return; return;
} }
String errorMessage = LoggerMessageFormat.format("the [action.auto_create_index] setting value [{}] is too restrictive. disable " + String errorMessage = LoggerMessageFormat.format("the [action.auto_create_index] setting value [{}] is too" +
"[action.auto_create_index] or set it to [.watches,.triggered_watches,.watch_history*]", (Object) settings); " restrictive. disable [action.auto_create_index] or set it to " +
"[.watches,.triggered_watches,.watcher-history*]", (Object) settings);
if (Booleans.isExplicitFalse(value)) { if (Booleans.isExplicitFalse(value)) {
throw new IllegalArgumentException(errorMessage); throw new IllegalArgumentException(errorMessage);
} }
@ -312,9 +330,22 @@ public class WatcherPlugin extends Plugin {
throw new IllegalArgumentException(errorMessage); throw new IllegalArgumentException(errorMessage);
} }
} }
logger.warn("the [action.auto_create_index] setting is configured to be restrictive [{}]. for the next 6 months daily history " + logger.warn("the [action.auto_create_index] setting is configured to be restrictive [{}]. " +
"indices are allowed to be created, but please make sure that any future history indices after 6 months with the pattern " + " for the next 6 months daily history indices are allowed to be created, but please make sure" +
"[.watch_history-YYYY.MM.dd] are allowed to be created", value); " 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); 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(); 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.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.engine.VersionConflictEngineException; import org.elasticsearch.index.engine.VersionConflictEngineException;
import org.elasticsearch.watcher.WatcherModule;
import org.elasticsearch.watcher.execution.ExecutionState; import org.elasticsearch.watcher.execution.ExecutionState;
import org.elasticsearch.watcher.support.init.proxy.ClientProxy; import org.elasticsearch.watcher.support.init.proxy.ClientProxy;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -30,7 +31,7 @@ import static org.elasticsearch.watcher.support.Exceptions.ioException;
*/ */
public class HistoryStore extends AbstractComponent { 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"; public static final String DOC_TYPE = "watch_record";
static final DateTimeFormatter indexTimeFormat = DateTimeFormat.forPattern("YYYY.MM.dd"); 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() { executor.execute(new Runnable() {
@Override @Override
public void run() { public void run() {
try (InputStream is = WatchStore.class.getResourceAsStream("/" + config.getTemplateName() + ".json")) { try (InputStream is = WatchStore.class.getResourceAsStream("/" + config.getFileName()+ ".json")) {
if (is == null) { if (is == null) {
logger.error("Resource [/" + config.getTemplateName() + ".json] not found in classpath"); logger.error("Resource [/" + config.getFileName() + ".json] not found in classpath");
return; return;
} }
final byte[] template; final byte[] template;
@ -184,13 +184,23 @@ public class WatcherIndexTemplateRegistry extends AbstractComponent implements C
public static class TemplateConfig { public static class TemplateConfig {
private final String templateName; private final String templateName;
private String fileName;
private final Setting<Settings> setting; private final Setting<Settings> setting;
public TemplateConfig(String templateName, 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.templateName = templateName;
this.fileName = fileName;
this.setting = setting; this.setting = setting;
} }
public String getFileName() {
return fileName;
}
public String getTemplateName() { public String getTemplateName() {
return templateName; return templateName;
} }

View File

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

View File

@ -5,6 +5,12 @@
*/ */
package org.elasticsearch.watcher.support.secret; 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); char[] decrypt(char[] text);
class PlainText implements SecretService { class Insecure implements SecretService {
public static final Insecure INSTANCE = new Insecure();
Insecure() {
}
@Override @Override
public char[] encrypt(char[] text) { public char[] encrypt(char[] text) {
@ -26,4 +37,31 @@ public interface SecretService {
return text; 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 * 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 * 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 * 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. * 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 * 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, "order": 2147483647,
"settings": { "settings": {
"watcher.plugin.version": "${watcher.plugin.version}",
"watcher.template.version": "${watcher.template.version}",
"index.number_of_shards": 1, "index.number_of_shards": 1,
"index.mapper.dynamic": false "index.mapper.dynamic": false
}, },
@ -29,7 +31,7 @@
} }
} }
], ],
"dynamic": "strict", "dynamic": false,
"_all": { "_all": {
"enabled": false "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() return Settings.settingsBuilder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(WatcherPlugin.ENABLED_SETTING, false) .put(WatcherPlugin.ENABLED_SETTING, false)
// disable shield because of query cache check and authentication/authorization // 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) .put(NetworkModule.HTTP_ENABLED.getKey(), true)
.build(); .build();
} }

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