test: Add more Shield related tests for testing the Watcher roles.

Original commit: elastic/x-pack-elasticsearch@482d8fe65c
This commit is contained in:
Martijn van Groningen 2015-05-19 17:50:53 +02:00
parent 284a60e16d
commit 2861f8ce21
2 changed files with 208 additions and 13 deletions
src/test/java/org/elasticsearch/watcher/test

@ -35,6 +35,7 @@ import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import org.elasticsearch.test.InternalTestCluster;
import org.elasticsearch.test.TestCluster;
import org.elasticsearch.watcher.WatcherLifeCycleService;
import org.elasticsearch.watcher.WatcherPlugin;
import org.elasticsearch.watcher.WatcherService;
import org.elasticsearch.watcher.WatcherState;
@ -155,7 +156,7 @@ public abstract class AbstractWatcherIntegrationTests extends ElasticsearchInteg
if (checkWatcherRunningOnlyOnce()) {
ensureWatcherOnlyRunningOnce();
}
stopWatcher();
stopWatcher(false);
}
@AfterClass
@ -189,15 +190,15 @@ public abstract class AbstractWatcherIntegrationTests extends ElasticsearchInteg
private void startWatcherIfNodesExist() throws Exception {
if (internalTestCluster().size() > 0) {
ensureLicenseEnabled();
WatcherStatsResponse response = watcherClient().prepareWatcherStats().get();
if (response.getWatcherState() == WatcherState.STOPPED) {
WatcherState state = getInstanceFromMaster(WatcherService.class).state();
if (state == WatcherState.STOPPED) {
logger.info("[{}#{}]: starting watcher", getTestClass().getSimpleName(), getTestName());
startWatcher();
} else if (response.getWatcherState() == WatcherState.STARTING) {
startWatcher(false);
} else if (state == WatcherState.STARTING) {
logger.info("[{}#{}]: watcher is starting, waiting for it to get in a started state", getTestClass().getSimpleName(), getTestName());
ensureWatcherStarted(false);
} else {
logger.info("[{}#{}]: not starting watcher, because watcher is in state [{}]", getTestClass().getSimpleName(), getTestName(), response.getWatcherState());
logger.info("[{}#{}]: not starting watcher, because watcher is in state [{}]", getTestClass().getSimpleName(), getTestName(), state);
}
} else {
logger.info("[{}#{}]: not starting watcher, because test cluster has no nodes", getTestClass().getSimpleName(), getTestName());
@ -427,13 +428,29 @@ public abstract class AbstractWatcherIntegrationTests extends ElasticsearchInteg
}
protected void startWatcher() throws Exception {
watcherClient().prepareWatchService().start().get();
ensureWatcherStarted(false);
startWatcher(true);
}
protected void stopWatcher() throws Exception {
watcherClient().prepareWatchService().stop().get();
ensureWatcherStopped(false);
stopWatcher(true);
}
protected void startWatcher(boolean useClient) throws Exception {
if (useClient) {
watcherClient().prepareWatchService().start().get();
} else {
getInstanceFromMaster(WatcherLifeCycleService.class).start();
}
ensureWatcherStarted(useClient);
}
protected void stopWatcher(boolean useClient) throws Exception {
if (useClient) {
watcherClient().prepareWatchService().stop().get();
} else {
getInstanceFromMaster(WatcherLifeCycleService.class).stop();
}
ensureWatcherStopped(useClient);
}
protected void ensureWatcherOnlyRunningOnce() {
@ -587,8 +604,6 @@ public abstract class AbstractWatcherIntegrationTests extends ElasticsearchInteg
public static final String TEST_USERNAME = "test";
public static final String TEST_PASSWORD = "changeme";
public static final String TEST_BASIC_AUTH_TOKEN = UsernamePasswordToken.basicAuthHeaderValue(TEST_USERNAME, new SecuredString(TEST_PASSWORD.toCharArray()));
public static final String ADMIN_BASIC_AUTH_TOKEN = UsernamePasswordToken.basicAuthHeaderValue("admin", new SecuredString("changeme".toCharArray()));
static boolean auditLogsEnabled = SystemPropertyUtil.getBoolean("tests.audit_logs", true);
static byte[] systemKey = generateKey(); // must be the same for all nodes
@ -596,23 +611,27 @@ public abstract class AbstractWatcherIntegrationTests extends ElasticsearchInteg
public static final String IP_FILTER = "allow: all\n";
public static final String USERS =
"transport_client:{plain}changeme\n" +
TEST_USERNAME + ":{plain}" + TEST_PASSWORD + "\n" +
"admin:{plain}changeme\n" +
"monitor:{plain}changeme";
public static final String USER_ROLES =
"transport_client:transport_client\n" +
"test:test\n" +
"admin:admin\n" +
"monitor:monitor";
public static final String ROLES =
"test:\n" + // a user for the test infra.
" cluster: all\n" +
" cluster: cluster:monitor/state, cluster:monitor/health, indices:admin/template/delete, cluster:admin/repository/delete, indices:admin/template/put, cluster:monitor/stats\n" +
" indices:\n" +
" '*': all\n" +
"\n" +
"admin:\n" +
" cluster: manage_watcher, cluster:monitor/nodes/info\n" +
"transport_client:\n" +
" cluster: cluster:monitor/nodes/info\n" +
"\n" +
"monitor:\n" +
" cluster: monitor_watcher, cluster:monitor/nodes/info\n"

@ -0,0 +1,176 @@
/*
* 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.test.integration;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.joda.time.DateTime;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.AuthenticationException;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authz.AuthorizationException;
import org.elasticsearch.watcher.WatcherPlugin;
import org.elasticsearch.watcher.WatcherState;
import org.elasticsearch.watcher.client.WatchSourceBuilders;
import org.elasticsearch.watcher.condition.ConditionBuilders;
import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests;
import org.elasticsearch.watcher.transport.actions.delete.DeleteWatchResponse;
import org.elasticsearch.watcher.transport.actions.execute.ExecuteWatchResponse;
import org.elasticsearch.watcher.transport.actions.get.GetWatchResponse;
import org.elasticsearch.watcher.transport.actions.put.PutWatchResponse;
import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsResponse;
import org.elasticsearch.watcher.trigger.TriggerBuilders;
import org.elasticsearch.watcher.trigger.TriggerEvent;
import org.elasticsearch.watcher.trigger.schedule.IntervalSchedule;
import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent;
import org.junit.Test;
import static org.elasticsearch.common.joda.time.DateTimeZone.UTC;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.watcher.client.WatchSourceBuilders.watchBuilder;
import static org.elasticsearch.watcher.trigger.TriggerBuilders.schedule;
import static org.elasticsearch.watcher.trigger.schedule.Schedules.interval;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.core.Is.is;
public class BasicShieldTests extends AbstractWatcherIntegrationTests {
@Override
protected boolean enableShield() {
return true;
}
@Override
protected Settings transportClientSettings() {
return ImmutableSettings.builder()
.put("client.transport.sniff", false)
.put("plugin.types", ShieldPlugin.class.getName() + "," + WatcherPlugin.class.getName())
// Use just the transport user here, so we can test Watcher roles specifically
.put("shield.user", "transport_client:changeme")
.build();
}
@Test
public void testNoAuthorization() throws Exception {
try {
watcherClient().prepareWatcherStats().get();
fail("authentication failure should have occurred");
} catch (AuthorizationException e) {
// transport_client is the default user
assertThat(e.getMessage(), equalTo("action [cluster:monitor/watcher/stats] is unauthorized for user [transport_client]"));
}
}
@Test
public void testWatcherMonitorRole() throws Exception {
// stats and get watch apis require at least monitor role:
String token = basicAuthHeaderValue("test", new SecuredString("changeme".toCharArray()));
try {
watcherClient().prepareWatcherStats()
.putHeader("Authorization", token)
.get();
fail("authentication failure should have occurred");
} catch (AuthorizationException e) {
assertThat(e.getMessage(), equalTo("action [cluster:monitor/watcher/stats] is unauthorized for user [test]"));
}
try {
watcherClient().prepareGetWatch("_id")
.putHeader("Authorization", token)
.get();
fail("authentication failure should have occurred");
} catch (AuthorizationException e) {
assertThat(e.getMessage(), equalTo("action [cluster:monitor/watcher/watch/get] is unauthorized for user [test]"));
}
// stats and get watch are allowed by role monitor:
token = basicAuthHeaderValue("monitor", new SecuredString("changeme".toCharArray()));
WatcherStatsResponse statsResponse = watcherClient().prepareWatcherStats()
.putHeader("Authorization", token)
.get();
assertThat(statsResponse.getWatcherState(), equalTo(WatcherState.STARTED));
GetWatchResponse getWatchResponse = watcherClient().prepareGetWatch("_id")
.putHeader("Authorization", token)
.get();
assertThat(getWatchResponse.isFound(), is(false));
// but put watch isn't allowed by monitor:
try {
watcherClient().preparePutWatch("_id")
.setSource(watchBuilder().trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))))
.putHeader("Authorization", token)
.get();
fail("authentication failure should have occurred");
} catch (AuthorizationException e) {
assertThat(e.getMessage(), equalTo("action [cluster:admin/watcher/watch/put] is unauthorized for user [monitor]"));
}
}
@Test
public void testWatcherAdminRole() throws Exception {
// put, execute and delete watch apis requires watcher admin role:
String token = basicAuthHeaderValue("test", new SecuredString("changeme".toCharArray()));
try {
watcherClient().preparePutWatch("_id")
.setSource(watchBuilder().trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))))
.putHeader("Authorization", token)
.get();
fail("authentication failure should have occurred");
} catch (AuthorizationException e) {
assertThat(e.getMessage(), equalTo("action [cluster:admin/watcher/watch/put] is unauthorized for user [test]"));
}
TriggerEvent triggerEvent = new ScheduleTriggerEvent(new DateTime(UTC), new DateTime(UTC));
try {
watcherClient().prepareExecuteWatch("_id")
.setTriggerEvent(triggerEvent)
.putHeader("Authorization", token)
.get();
fail("authentication failure should have occurred");
} catch (AuthorizationException e) {
assertThat(e.getMessage(), equalTo("action [cluster:admin/watcher/watch/execute] is unauthorized for user [test]"));
}
try {
watcherClient().prepareDeleteWatch("_id")
.putHeader("Authorization", token)
.get();
fail("authentication failure should have occurred");
} catch (AuthorizationException e) {
assertThat(e.getMessage(), equalTo("action [cluster:admin/watcher/watch/delete] is unauthorized for user [test]"));
}
// put, execute and delete watch apis are allowed by role admin:
token = basicAuthHeaderValue("admin", new SecuredString("changeme".toCharArray()));
PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("_id")
.setSource(watchBuilder().trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))))
.putHeader("Authorization", token)
.get();
assertThat(putWatchResponse.getVersion(), equalTo(1l));
ExecuteWatchResponse executeWatchResponse = watcherClient().prepareExecuteWatch("_id")
.setTriggerEvent(triggerEvent)
.putHeader("Authorization", token)
.get();
DeleteWatchResponse deleteWatchResponse = watcherClient().prepareDeleteWatch("_id")
.putHeader("Authorization", token)
.get();
assertThat(deleteWatchResponse.getVersion(), equalTo(2l));
assertThat(deleteWatchResponse.isFound(), is(true));
// stats and get watch are also allowed by role monitor:
token = basicAuthHeaderValue("monitor", new SecuredString("changeme".toCharArray()));
WatcherStatsResponse statsResponse = watcherClient().prepareWatcherStats()
.putHeader("Authorization", token)
.get();
assertThat(statsResponse.getWatcherState(), equalTo(WatcherState.STARTED));
GetWatchResponse getWatchResponse = watcherClient().prepareGetWatch("_id")
.putHeader("Authorization", token)
.get();
assertThat(getWatchResponse.isFound(), is(false));
}
}