Merge branch 'master' into feature/account-settings

Original commit: elastic/x-pack-elasticsearch@6942ae6cb2
This commit is contained in:
Lukas Olson 2016-06-17 13:54:20 -07:00
commit f5d8a7c4e6
82 changed files with 1426 additions and 1156 deletions

View File

@ -14,7 +14,6 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.script.ScriptContextRegistry;
import org.elasticsearch.script.ScriptEngineRegistry;
import org.elasticsearch.script.ScriptEngineService;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.script.groovy.GroovyScriptEngineService;
@ -25,8 +24,7 @@ import org.junit.Ignore;
import org.mockito.Mockito;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.Collections;
@Ignore // not a test.
@SuppressForbidden(reason = "gradle is broken and tries to run me as a test")
@ -38,19 +36,13 @@ public final class MessyTestUtils {
.put("path.home", LuceneTestCase.createTempDir())
.build();
GroovyScriptEngineService groovyScriptEngineService = new GroovyScriptEngineService(settings);
Set<ScriptEngineService> engineServiceSet = new HashSet<>();
engineServiceSet.add(groovyScriptEngineService);
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(
Arrays.asList(
new ScriptEngineRegistry.ScriptEngineRegistration(GroovyScriptEngineService.class, GroovyScriptEngineService.NAME)
)
);
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singleton(groovyScriptEngineService));
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Arrays.asList(ScriptServiceProxy.INSTANCE));
ClusterService clusterService = Mockito.mock(ClusterService.class);
Mockito.when(clusterService.state()).thenReturn(ClusterState.builder(new ClusterName("_name")).build());
ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
return ScriptServiceProxy.of(new ScriptService(settings, new Environment(settings), engineServiceSet,
return ScriptServiceProxy.of(new ScriptService(settings, new Environment(settings),
new ResourceWatcherService(settings, tp), scriptEngineRegistry, scriptContextRegistry, scriptSettings),
clusterService);
}

View File

@ -49,18 +49,14 @@ public class WatcherTemplateTests extends ESTestCase {
public void init() throws Exception {
Settings setting = Settings.builder().put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING, true).build();
Environment environment = Mockito.mock(Environment.class);
Set<ScriptEngineService> engines = Collections.singleton(new MustacheScriptEngineService(setting));
ResourceWatcherService resourceWatcherService = Mockito.mock(ResourceWatcherService.class);
ScriptContextRegistry registry = new ScriptContextRegistry(Collections.singletonList(ScriptServiceProxy.INSTANCE));
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(
Arrays.asList(
new ScriptEngineRegistry.ScriptEngineRegistration(MustacheScriptEngineService.class,
MustacheScriptEngineService.NAME)
)
Collections.singleton(new MustacheScriptEngineService(setting))
);
ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, registry);
ScriptService scriptService = new ScriptService(setting, environment, engines, resourceWatcherService, scriptEngineRegistry,
ScriptService scriptService = new ScriptService(setting, environment, resourceWatcherService, scriptEngineRegistry,
registry, scriptSettings);
ClusterService clusterService = Mockito.mock(ClusterService.class);
Mockito.when(clusterService.state()).thenReturn(ClusterState.builder(new ClusterName("_name")).build());

View File

@ -20,6 +20,7 @@ import org.elasticsearch.xpack.graph.rest.action.RestGraphAction;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class Graph extends Plugin {
@ -31,16 +32,6 @@ public class Graph extends Plugin {
public Graph(Settings settings) {
this.transportClientMode = XPackPlugin.transportClientMode(settings);
enabled = enabled(settings);
}
@Override
public String name() {
return NAME;
}
@Override
public String description() {
return "Elasticsearch Graph Plugin";
}
public static boolean enabled(Settings settings) {
@ -69,10 +60,12 @@ public class Graph extends Plugin {
if (enabled && transportClientMode == false) {
module.registerRestHandler(RestGraphAction.class);
}
}
public void onModule(SettingsModule module) {
module.registerSetting(Setting.boolSetting(XPackPlugin.featureEnabledSetting(NAME), true, Setting.Property.NodeScope));
}
}
@Override
public List<Setting<?>> getSettings() {
return Collections.singletonList(Setting.boolSetting(XPackPlugin.featureEnabledSetting(NAME), true, Setting.Property.NodeScope));
}
}

View File

@ -15,6 +15,7 @@ import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.ScriptQueryBuilder;
import org.elasticsearch.marvel.Monitoring;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.AbstractSearchScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.NativeScriptFactory;
@ -34,6 +35,8 @@ import org.elasticsearch.xpack.graph.action.Vertex;
import org.elasticsearch.xpack.graph.action.VertexRequest;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
@ -346,19 +349,10 @@ public class GraphTests extends ESSingleNodeTestCase {
assertThat(why, strongVertex.getWeight(), greaterThan(weakVertex.getWeight()));
}
public static class ScriptedTimeoutPlugin extends Plugin {
public static class ScriptedTimeoutPlugin extends Plugin implements ScriptPlugin {
@Override
public String name() {
return "test-scripted-graph-timeout";
}
@Override
public String description() {
return "Test for scripted timeouts on graph searches";
}
public void onModule(ScriptModule module) {
module.registerScript(NativeTestScriptedTimeout.TEST_NATIVE_SCRIPT_TIMEOUT, NativeTestScriptedTimeout.Factory.class);
public List<NativeScriptFactory> getNativeScripts() {
return Collections.singletonList(new NativeTestScriptedTimeout.Factory());
}
}
@ -377,6 +371,11 @@ public class GraphTests extends ESSingleNodeTestCase {
public boolean needsScores() {
return false;
}
@Override
public String getName() {
return TEST_NATIVE_SCRIPT_TIMEOUT;
}
}
@Override

View File

@ -28,6 +28,7 @@ import org.elasticsearch.license.plugin.rest.RestPutLicenseAction;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.xpack.XPackPlugin.isTribeClientNode;
import static org.elasticsearch.xpack.XPackPlugin.isTribeNode;
@ -80,8 +81,8 @@ public class Licensing {
return Collections.emptyList();
}
public void onModule(SettingsModule module) {
public List<Setting<?>> getSettings() {
// TODO convert this wildcard to a real setting
module.registerSetting(Setting.groupSetting("license.", Setting.Property.NodeScope));
return Collections.singletonList(Setting.groupSetting("license.", Setting.Property.NodeScope));
}
}

View File

@ -415,7 +415,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
long issueDate = System.currentTimeMillis();
License.Builder specBuilder = License.builder()
.uid(UUID.randomUUID().toString())
.issuedTo(clusterService.state().getClusterName().value())
.issuedTo(clusterService.getClusterName().value())
.maxNodes(trialLicenseMaxNodes)
.issueDate(issueDate)
.expiryDate(issueDate + trialLicenseDuration.getMillis());

View File

@ -28,11 +28,6 @@ public class EagerLicenseRegistrationConsumerPlugin extends TestConsumerPluginBa
return EagerLicenseRegistrationPluginService.class;
}
@Override
protected String pluginName() {
return NAME;
}
@Override
public String id() {
return EagerLicenseRegistrationPluginService.ID;

View File

@ -16,8 +16,6 @@ import org.elasticsearch.common.settings.Settings;
*/
public class LazyLicenseRegistrationConsumerPlugin extends TestConsumerPluginBase {
public static String NAME = "test_consumer_plugin_2";
@Inject
public LazyLicenseRegistrationConsumerPlugin(Settings settings) {
super(settings);
@ -28,11 +26,6 @@ public class LazyLicenseRegistrationConsumerPlugin extends TestConsumerPluginBas
return LazyLicenseRegistrationPluginService.class;
}
@Override
protected String pluginName() {
return NAME;
}
@Override
public String id() {
return LazyLicenseRegistrationPluginService.ID;

View File

@ -14,7 +14,9 @@ import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.plugins.Plugin;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public abstract class TestConsumerPluginBase extends Plugin {
@ -24,17 +26,6 @@ public abstract class TestConsumerPluginBase extends Plugin {
this.isEnabled = TransportClient.CLIENT_TYPE.equals(settings.get(Client.CLIENT_TYPE_SETTING_S.getKey())) == false;
}
@Override
public String name() {
return pluginName();
}
@Override
public String description() {
return "test licensing consumer plugin";
}
@Override
public Collection<Class<? extends LifecycleComponent>> nodeServices() {
Collection<Class<? extends LifecycleComponent>> services = new ArrayList<>();
@ -44,18 +35,14 @@ public abstract class TestConsumerPluginBase extends Plugin {
return services;
}
public void onModule(SettingsModule module) {
try {
module.registerSetting(Setting.simpleString("_trial_license_duration_in_seconds", Setting.Property.NodeScope));
module.registerSetting(Setting.simpleString("_grace_duration_in_seconds", Setting.Property.NodeScope));
} catch (IllegalArgumentException ex) {
// already loaded
}
@Override
public List<Setting<?>> getSettings() {
return Arrays.asList(Setting.simpleString("_trial_license_duration_in_seconds", Setting.Property.NodeScope,
Setting.Property.Shared), Setting.simpleString("_grace_duration_in_seconds", Setting.Property.NodeScope,
Setting.Property.Shared));
}
public abstract Class<? extends TestPluginServiceBase> service();
protected abstract String pluginName();
public abstract String id();
}

View File

@ -7,9 +7,10 @@ package org.elasticsearch.shield.authz;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.authc.Authentication.RealmRef;
import org.elasticsearch.shield.user.SystemUser;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.shield.authc.InternalAuthenticationService;
import org.elasticsearch.test.ESTestCase;
import org.junit.Before;
@ -33,21 +34,24 @@ public class AuthorizationUtilsTests extends ESTestCase {
public void testSystemUserSwitchWithNullorSystemUser() {
if (randomBoolean()) {
threadContext.putTransient(InternalAuthenticationService.USER_KEY, SystemUser.INSTANCE);
threadContext.putTransient(Authentication.AUTHENTICATION_KEY,
new Authentication(SystemUser.INSTANCE, new RealmRef("test", "test", "foo"), null));
}
assertThat(AuthorizationUtils.shouldReplaceUserWithSystem(threadContext, "internal:something"), is(true));
}
public void testSystemUserSwitchWithNonSystemUser() {
User user = new User(randomAsciiOfLength(6), new String[] {});
threadContext.putTransient(InternalAuthenticationService.USER_KEY, user);
Authentication authentication = new Authentication(user, new RealmRef("test", "test", "foo"), null);
threadContext.putTransient(Authentication.AUTHENTICATION_KEY, authentication);
threadContext.putTransient(InternalAuthorizationService.ORIGINATING_ACTION_KEY, randomFrom("indices:foo", "cluster:bar"));
assertThat(AuthorizationUtils.shouldReplaceUserWithSystem(threadContext, "internal:something"), is(true));
}
public void testSystemUserSwitchWithNonSystemUserAndInternalAction() {
User user = new User(randomAsciiOfLength(6), new String[] {});
threadContext.putTransient(InternalAuthenticationService.USER_KEY, user);
Authentication authentication = new Authentication(user, new RealmRef("test", "test", "foo"), null);
threadContext.putTransient(Authentication.AUTHENTICATION_KEY, authentication);
threadContext.putTransient(InternalAuthorizationService.ORIGINATING_ACTION_KEY, randomFrom("internal:foo/bar"));
assertThat(AuthorizationUtils.shouldReplaceUserWithSystem(threadContext, "internal:something"), is(false));
}

View File

@ -9,6 +9,7 @@ import org.elasticsearch.action.ActionModule;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.marvel.action.MonitoringBulkAction;
@ -80,7 +81,6 @@ public class Monitoring {
}
public void onModule(SettingsModule module) {
MonitoringSettings.register(module);
}
public void onModule(ActionModule module) {

View File

@ -15,6 +15,7 @@ import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
@ -125,22 +126,23 @@ public class MonitoringSettings extends AbstractComponent {
public static final Setting<Settings> EXPORTERS_SETTINGS =
groupSetting(key("agent.exporters."), Property.Dynamic, Property.NodeScope);
static void register(SettingsModule module) {
module.registerSetting(INDICES);
module.registerSetting(INTERVAL);
module.registerSetting(INDEX_RECOVERY_TIMEOUT);
module.registerSetting(INDEX_STATS_TIMEOUT);
module.registerSetting(INDICES_STATS_TIMEOUT);
module.registerSetting(INDEX_RECOVERY_ACTIVE_ONLY);
module.registerSetting(COLLECTORS);
module.registerSetting(CLUSTER_STATE_TIMEOUT);
module.registerSetting(CLUSTER_STATS_TIMEOUT);
module.registerSetting(HISTORY_DURATION);
module.registerSetting(EXPORTERS_SETTINGS);
module.registerSetting(ENABLED);
public static List<Setting<?>> getSettings() {
return Arrays.asList(INDICES,
INTERVAL,
INDEX_RECOVERY_TIMEOUT,
INDEX_STATS_TIMEOUT,
INDICES_STATS_TIMEOUT,
INDEX_RECOVERY_ACTIVE_ONLY,
COLLECTORS,
CLUSTER_STATE_TIMEOUT,
CLUSTER_STATS_TIMEOUT,
HISTORY_DURATION,
EXPORTERS_SETTINGS,
ENABLED);
}
module.registerSettingsFilter("xpack.monitoring.agent.exporters.*.auth.*");
module.registerSettingsFilter("xpack.monitoring.agent.exporters.*.ssl.*");
public static List<String> getSettingsFilter() {
return Arrays.asList("xpack.monitoring.agent.exporters.*.auth.*", "xpack.monitoring.agent.exporters.*.ssl.*");
}

View File

@ -41,17 +41,15 @@ public class ClusterStatsCollector extends AbstractCollector<ClusterStatsCollect
public static final String NAME = "cluster-stats-collector";
private final ClusterName clusterName;
private final LicensesManagerService licensesManagerService;
private final Client client;
@Inject
public ClusterStatsCollector(Settings settings, ClusterService clusterService,
MonitoringSettings monitoringSettings, MonitoringLicensee licensee, InternalClient client,
LicensesManagerService licensesManagerService, ClusterName clusterName) {
LicensesManagerService licensesManagerService) {
super(settings, NAME, clusterService, monitoringSettings, licensee);
this.client = client;
this.clusterName = clusterName;
this.licensesManagerService = licensesManagerService;
}
@ -86,7 +84,7 @@ public class ClusterStatsCollector extends AbstractCollector<ClusterStatsCollect
clusterInfoDoc.setClusterUUID(clusterUUID);
clusterInfoDoc.setTimestamp(timestamp);
clusterInfoDoc.setSourceNode(sourceNode);
clusterInfoDoc.setClusterName(clusterName.value());
clusterInfoDoc.setClusterName(clusterService.getClusterName().value());
clusterInfoDoc.setVersion(Version.CURRENT.toString());
clusterInfoDoc.setLicense(licensesManagerService.getLicense());
clusterInfoDoc.setClusterStats(clusterStats);

View File

@ -20,4 +20,4 @@
"enabled": false
}
}
}
}

View File

@ -136,6 +136,9 @@
},
"used_in_bytes": {
"type": "float"
},
"size_limit": {
"type": "float"
}
}
},

View File

@ -79,7 +79,7 @@ public class MarvelPluginTests extends MarvelIntegTestCase {
for (PluginInfo plugin : nodeInfo.getPlugins().getPluginInfos()) {
assertNotNull(plugin);
if (XPackPlugin.NAME.equals(plugin.getName())) {
if (XPackPlugin.class.getName().equals(plugin.getName())) {
found = true;
break;
}

View File

@ -88,9 +88,9 @@ public class TransportMonitoringBulkActionTests extends ESTestCase {
public void setUp() throws Exception {
super.setUp();
CapturingTransport transport = new CapturingTransport();
clusterService = new ClusterService(Settings.EMPTY, null, new ClusterSettings(Settings.EMPTY,
ClusterSettings.BUILT_IN_CLUSTER_SETTINGS), threadPool,
new ClusterName(TransportMonitoringBulkActionTests.class.getName()));
clusterService = new ClusterService(Settings.builder().put("cluster.name",
TransportMonitoringBulkActionTests.class.getName()).build(),
new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS), threadPool);
clusterService.setLocalNode(new DiscoveryNode("node", DummyTransportAddress.INSTANCE, emptyMap(), emptySet(), Version.CURRENT));
clusterService.setNodeConnectionsService(new NodeConnectionsService(Settings.EMPTY, null, null) {
@Override
@ -106,7 +106,7 @@ public class TransportMonitoringBulkActionTests extends ESTestCase {
clusterService.setClusterStatePublisher((event, ackListener) -> {});
clusterService.start();
transportService = new TransportService(Settings.EMPTY, transport, threadPool, clusterService.state().getClusterName());
transportService = new TransportService(clusterService.getSettings(), transport, threadPool);
transportService.start();
transportService.acceptIncomingRequests();
exportService = new CapturingExporters();

View File

@ -134,8 +134,7 @@ public class ClusterStatsCollectorTests extends AbstractCollectorTestCase {
internalCluster().getInstance(MonitoringSettings.class, nodeId),
internalCluster().getInstance(MonitoringLicensee.class, nodeId),
securedClient(nodeId),
internalCluster().getInstance(LicensesManagerService.class, nodeId),
internalCluster().getInstance(ClusterName.class, nodeId));
internalCluster().getInstance(LicensesManagerService.class, nodeId));
}
private void assertCanCollect(AbstractCollector collector, Class<?>... classes) {

View File

@ -223,7 +223,8 @@ public class ExportersTests extends ESTestCase {
DiscoveryNodes nodes = mock(DiscoveryNodes.class);
when(nodes.isLocalNodeElectedMaster()).thenReturn(true);
when(clusterService.state()).thenReturn(ClusterState.builder(ClusterName.DEFAULT).nodes(nodes).build());
when(clusterService.state()).thenReturn(ClusterState.builder(ClusterName.CLUSTER_NAME_SETTING.getDefault(Settings.EMPTY))
.nodes(nodes).build());
ExportBulk bulk = exporters.openBulk();
assertThat(bulk, notNullValue());
@ -247,7 +248,8 @@ public class ExportersTests extends ESTestCase {
DiscoveryNodes nodes = mock(DiscoveryNodes.class);
when(nodes.isLocalNodeElectedMaster()).thenReturn(false);
when(clusterService.state()).thenReturn(ClusterState.builder(ClusterName.DEFAULT).nodes(nodes).build());
when(clusterService.state()).thenReturn(ClusterState.builder(ClusterName.CLUSTER_NAME_SETTING.getDefault(Settings.EMPTY))
.nodes(nodes).build());
ExportBulk bulk = exporters.openBulk();
assertThat(bulk, notNullValue());

View File

@ -9,6 +9,7 @@ import org.elasticsearch.Version;
import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.DummyTransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
@ -45,8 +46,8 @@ public class ClusterInfoResolverTests extends MonitoringIndexNameResolverTestCas
doc.setVersion(randomFrom(Version.V_2_0_0, Version.CURRENT).toString());
doc.setLicense(licenseBuilder.build());
doc.setClusterName(randomAsciiOfLength(5));
doc.setClusterStats(new ClusterStatsResponse(Math.abs(randomLong()), ClusterName.DEFAULT,
randomAsciiOfLength(5), Collections.emptyList(), Collections.emptyList()));
doc.setClusterStats(new ClusterStatsResponse(Math.abs(randomLong()), ClusterName.CLUSTER_NAME_SETTING
.getDefault(Settings.EMPTY), randomAsciiOfLength(5), Collections.emptyList(), Collections.emptyList()));
return doc;
} catch (Exception e) {
throw new IllegalStateException("Failed to generated random ClusterInfoMarvelDoc", e);

View File

@ -97,8 +97,8 @@ public class ClusterStatsResolverTests extends MonitoringIndexNameResolverTestCa
emptyMap(), emptySet(), Version.CURRENT),
ClusterHealthStatus.GREEN, randomNodeInfo(), randomNodeStats(), randomShardStats())
);
return new ClusterStatsResponse(Math.abs(randomLong()), ClusterName.DEFAULT, UUID.randomUUID().toString(),
responses, Collections.emptyList());
return new ClusterStatsResponse(Math.abs(randomLong()), ClusterName.CLUSTER_NAME_SETTING.getDefault(Settings.EMPTY),
UUID.randomUUID().toString(), responses, Collections.emptyList());
}
/**

View File

@ -62,7 +62,7 @@ public abstract class InternalClient extends FilterClient {
try (ThreadContext.StoredContext ctx = threadPool().getThreadContext().stashContext()) {
try {
authcService.attachUserHeaderIfMissing(XPackUser.INSTANCE);
authcService.attachUserIfMissing(XPackUser.INSTANCE);
} catch (IOException ioe) {
throw new ElasticsearchException("failed to attach internal user to request", ioe);
}

View File

@ -18,7 +18,6 @@ import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.index.IndexModule;
import org.elasticsearch.shield.action.ShieldActionModule;
@ -188,62 +187,70 @@ public class Security {
return settingsBuilder.build();
}
public void onModule(SettingsModule settingsModule) {
public List<Setting<?>> getSettings() {
List<Setting<?>> settingsList = new ArrayList<>();
// always register for both client and node modes
XPackPlugin.registerFeatureEnabledSettings(settingsModule, NAME, true);
settingsModule.registerSetting(USER_SETTING);
XPackPlugin.addFeatureEnabledSettings(settingsList, NAME, true);
settingsList.add(USER_SETTING);
// SSL settings
SSLConfiguration.Global.registerSettings(settingsModule);
SSLConfiguration.Global.addSettings(settingsList);
// transport settings
ShieldNettyTransport.registerSettings(settingsModule);
ShieldNettyTransport.addSettings(settingsList);
if (transportClientMode) {
return;
return settingsList;
}
// The following just apply in node mode
XPackPlugin.registerFeatureEnabledSettings(settingsModule, DLS_FLS_FEATURE, true);
XPackPlugin.addFeatureEnabledSettings(settingsList, DLS_FLS_FEATURE, true);
// IP Filter settings
IPFilter.registerSettings(settingsModule);
IPFilter.addSettings(settingsList);
// audit settings
AuditTrailModule.registerSettings(settingsModule);
AuditTrailModule.addSettings(settingsList);
// authentication settings
FileRolesStore.registerSettings(settingsModule);
AnonymousUser.registerSettings(settingsModule);
Realms.registerSettings(settingsModule);
NativeUsersStore.registerSettings(settingsModule);
NativeRolesStore.registerSettings(settingsModule);
InternalAuthenticationService.registerSettings(settingsModule);
InternalAuthorizationService.registerSettings(settingsModule);
FileRolesStore.addSettings(settingsList);
AnonymousUser.addSettings(settingsList);
Realms.addSettings(settingsList);
NativeUsersStore.addSettings(settingsList);
NativeRolesStore.addSettings(settingsList);
InternalAuthenticationService.addSettings(settingsList);
InternalAuthorizationService.addSettings(settingsList);
// HTTP settings
ShieldNettyHttpServerTransport.registerSettings(settingsModule);
ShieldNettyHttpServerTransport.addSettings(settingsList);
// encryption settings
InternalCryptoService.registerSettings(settingsModule);
InternalCryptoService.addSettings(settingsList);
// hide settings
settingsModule.registerSetting(Setting.listSetting(setting("hide_settings"), Collections.emptyList(), Function.identity(),
settingsList.add(Setting.listSetting(setting("hide_settings"), Collections.emptyList(), Function.identity(),
Property.NodeScope, Property.Filtered));
return settingsList;
}
public List<String> getSettingsFilter() {
ArrayList<String> settingsFilter = new ArrayList<>();
String[] asArray = settings.getAsArray(setting("hide_settings"));
for (String pattern : asArray) {
settingsModule.registerSettingsFilter(pattern);
settingsFilter.add(pattern);
}
settingsModule.registerSettingsFilter(setting("authc.realms.*.bind_dn"));
settingsModule.registerSettingsFilter(setting("authc.realms.*.bind_password"));
settingsModule.registerSettingsFilter(setting("authc.realms.*." + SessionFactory.HOSTNAME_VERIFICATION_SETTING));
settingsModule.registerSettingsFilter(setting("authc.realms.*.truststore.password"));
settingsModule.registerSettingsFilter(setting("authc.realms.*.truststore.path"));
settingsModule.registerSettingsFilter(setting("authc.realms.*.truststore.algorithm"));
settingsFilter.add(setting("authc.realms.*.bind_dn"));
settingsFilter.add(setting("authc.realms.*.bind_password"));
settingsFilter.add(setting("authc.realms.*." + SessionFactory.HOSTNAME_VERIFICATION_SETTING));
settingsFilter.add(setting("authc.realms.*.truststore.password"));
settingsFilter.add(setting("authc.realms.*.truststore.path"));
settingsFilter.add(setting("authc.realms.*.truststore.algorithm"));
// hide settings where we don't define them - they are part of a group...
settingsModule.registerSettingsFilter("transport.profiles.*." + setting("*"));
settingsFilter.add("transport.profiles.*." + setting("*"));
return settingsFilter;
}
public void onIndexModule(IndexModule module) {

View File

@ -8,6 +8,7 @@ package org.elasticsearch.shield;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.authc.AuthenticationService;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.threadpool.ThreadPool;
@ -26,6 +27,12 @@ public interface SecurityContext {
User getUser();
Authentication getAuthentication();
default boolean hasAuthentication() {
return getAuthentication() != null;
}
class Insecure implements SecurityContext {
public static final Insecure INSTANCE = new Insecure();
@ -51,6 +58,11 @@ public interface SecurityContext {
public User getUser() {
return null;
}
@Override
public Authentication getAuthentication() {
return null;
}
}
class Secure implements SecurityContext {
@ -82,14 +94,20 @@ public interface SecurityContext {
@Override
public User getUser() {
return authcService.getCurrentUser();
Authentication authentication = authcService.getCurrentAuthentication();
return authentication == null ? null : authentication.getUser();
}
@Override
public Authentication getAuthentication() {
return authcService.getCurrentAuthentication();
}
private void setUser(User user) {
try {
authcService.attachUserHeaderIfMissing(user);
} catch (IOException e) {
throw new ElasticsearchException("failed to attach watcher user to request", e);
authcService.attachUserIfMissing(user);
} catch (IOException | IllegalArgumentException e) {
throw new ElasticsearchException("failed to attach user to request", e);
}
}
}

View File

@ -20,13 +20,14 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.plugin.core.LicenseUtils;
import org.elasticsearch.shield.Security;
import org.elasticsearch.shield.SecurityContext;
import org.elasticsearch.shield.action.ShieldActionMapper;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.user.SystemUser;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.shield.action.interceptor.RequestInterceptor;
import org.elasticsearch.shield.audit.AuditTrail;
import org.elasticsearch.shield.authc.AuthenticationService;
import org.elasticsearch.shield.authc.InternalAuthenticationService;
import org.elasticsearch.shield.authz.AuthorizationService;
import org.elasticsearch.shield.authz.AuthorizationUtils;
import org.elasticsearch.shield.authz.privilege.HealthAndStatsPrivilege;
@ -58,11 +59,13 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte
private final Set<RequestInterceptor> requestInterceptors;
private final SecurityLicenseState licenseState;
private final ThreadContext threadContext;
private final SecurityContext securityContext;
@Inject
public ShieldActionFilter(Settings settings, AuthenticationService authcService, AuthorizationService authzService,
CryptoService cryptoService, AuditTrail auditTrail, SecurityLicenseState licenseState,
ShieldActionMapper actionMapper, Set<RequestInterceptor> requestInterceptors, ThreadPool threadPool) {
ShieldActionMapper actionMapper, Set<RequestInterceptor> requestInterceptors, ThreadPool threadPool,
SecurityContext securityContext) {
super(settings);
this.authcService = authcService;
this.authzService = authzService;
@ -72,6 +75,7 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte
this.licenseState = licenseState;
this.requestInterceptors = requestInterceptors;
this.threadContext = threadPool.getThreadContext();
this.securityContext = securityContext;
}
@Override
@ -91,8 +95,7 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte
// only restore the context if it is not empty. This is needed because sometimes a response is sent to the user
// and then a cleanup action is executed (like for search without a scroll)
final ThreadContext.StoredContext original = threadContext.newStoredContext();
final boolean restoreOriginalContext = threadContext.getHeader(InternalAuthenticationService.USER_KEY) != null ||
threadContext.getTransient(InternalAuthenticationService.USER_KEY) != null;
final boolean restoreOriginalContext = securityContext.hasAuthentication();
try {
if (licenseState.authenticationAndAuthorizationEnabled()) {
if (AuthorizationUtils.shouldReplaceUserWithSystem(threadContext, action)) {
@ -133,9 +136,11 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte
the {@link Rest} filter and the {@link ServerTransport} filter respectively), it's safe to assume a system user
here if a request is not associated with any other user.
*/
String shieldAction = actionMapper.action(action, request);
User user = authcService.authenticate(shieldAction, request, SystemUser.INSTANCE);
authzService.authorize(user, shieldAction, request);
final String shieldAction = actionMapper.action(action, request);
Authentication authentication = authcService.authenticate(shieldAction, request, SystemUser.INSTANCE);
assert authentication != null;
authzService.authorize(authentication, shieldAction, request);
final User user = authentication.getUser();
request = unsign(user, shieldAction, request);
/*

View File

@ -9,7 +9,6 @@ import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.FailedNodeException;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.nodes.TransportNodesAction;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.inject.Inject;
@ -31,11 +30,11 @@ public class TransportClearRealmCacheAction extends TransportNodesAction<ClearRe
private final Realms realms;
@Inject
public TransportClearRealmCacheAction(Settings settings, ClusterName clusterName, ThreadPool threadPool,
public TransportClearRealmCacheAction(Settings settings, ThreadPool threadPool,
ClusterService clusterService, TransportService transportService,
ActionFilters actionFilters, Realms realms,
IndexNameExpressionResolver indexNameExpressionResolver) {
super(settings, ClearRealmCacheAction.NAME, clusterName, threadPool, clusterService, transportService, actionFilters,
super(settings, ClearRealmCacheAction.NAME, threadPool, clusterService, transportService, actionFilters,
indexNameExpressionResolver, ClearRealmCacheRequest::new, ClearRealmCacheRequest.Node::new, ThreadPool.Names.MANAGEMENT,
ClearRealmCacheResponse.Node.class);
this.realms = realms;
@ -44,7 +43,7 @@ public class TransportClearRealmCacheAction extends TransportNodesAction<ClearRe
@Override
protected ClearRealmCacheResponse newResponse(ClearRealmCacheRequest request,
List<ClearRealmCacheResponse.Node> responses, List<FailedNodeException> failures) {
return new ClearRealmCacheResponse(clusterName, responses, failures);
return new ClearRealmCacheResponse(clusterService.getClusterName(), responses, failures);
}
@Override

View File

@ -8,7 +8,6 @@ package org.elasticsearch.shield.action.role;
import org.elasticsearch.action.FailedNodeException;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.nodes.TransportNodesAction;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.inject.Inject;
@ -28,10 +27,10 @@ public class TransportClearRolesCacheAction extends TransportNodesAction<ClearRo
private final NativeRolesStore rolesStore;
@Inject
public TransportClearRolesCacheAction(Settings settings, ClusterName clusterName, ThreadPool threadPool,
public TransportClearRolesCacheAction(Settings settings, ThreadPool threadPool,
ClusterService clusterService, TransportService transportService, ActionFilters actionFilters,
NativeRolesStore rolesStore, IndexNameExpressionResolver indexNameExpressionResolver) {
super(settings, ClearRolesCacheAction.NAME, clusterName, threadPool, clusterService, transportService,
super(settings, ClearRolesCacheAction.NAME, threadPool, clusterService, transportService,
actionFilters, indexNameExpressionResolver, ClearRolesCacheRequest::new, ClearRolesCacheRequest.Node::new,
ThreadPool.Names.MANAGEMENT, ClearRolesCacheResponse.Node.class);
this.rolesStore = rolesStore;
@ -40,7 +39,7 @@ public class TransportClearRolesCacheAction extends TransportNodesAction<ClearRo
@Override
protected ClearRolesCacheResponse newResponse(ClearRolesCacheRequest request,
List<ClearRolesCacheResponse.Node> responses, List<FailedNodeException> failures) {
return new ClearRolesCacheResponse(clusterName, responses, failures);
return new ClearRolesCacheResponse(clusterService.getClusterName(), responses, failures);
}
@Override

View File

@ -94,6 +94,10 @@ public interface AuditTrail {
@Override
public void runAsDenied(User user, String action, TransportMessage message) {
}
@Override
public void runAsDenied(User user, RestRequest request) {
}
};
String name();
@ -131,4 +135,6 @@ public interface AuditTrail {
void runAsGranted(User user, String action, TransportMessage message);
void runAsDenied(User user, String action, TransportMessage message);
void runAsDenied(User user, RestRequest request);
}

View File

@ -102,10 +102,10 @@ public class AuditTrailModule extends AbstractShieldModule.Node {
return false;
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(ENABLED_SETTING);
settingsModule.registerSetting(OUTPUTS_SETTING);
LoggingAuditTrail.registerSettings(settingsModule);
IndexAuditTrail.registerSettings(settingsModule);
public static void addSettings(List<Setting<?>> settings) {
settings.add(ENABLED_SETTING);
settings.add(OUTPUTS_SETTING);
LoggingAuditTrail.registerSettings(settings);
IndexAuditTrail.registerSettings(settings);
}
}

View File

@ -188,4 +188,13 @@ public class AuditTrailService extends AbstractComponent implements AuditTrail {
}
}
}
@Override
public void runAsDenied(User user, RestRequest request) {
if (securityLicenseState.auditingEnabled()) {
for (AuditTrail auditTrail : auditTrails) {
auditTrail.runAsDenied(user, request);
}
}
}
}

View File

@ -512,7 +512,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
public void runAsGranted(User user, String action, TransportMessage message) {
if (events.contains(RUN_AS_GRANTED)) {
try {
enqueue(message("run_as_granted", action, user, null, message), "access_granted");
enqueue(message("run_as_granted", action, user, null, message), "run_as_granted");
} catch (Exception e) {
logger.warn("failed to index audit event: [run_as_granted]", e);
}
@ -523,7 +523,18 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
public void runAsDenied(User user, String action, TransportMessage message) {
if (events.contains(RUN_AS_DENIED)) {
try {
enqueue(message("run_as_denied", action, user, null, message), "access_granted");
enqueue(message("run_as_denied", action, user, null, message), "run_as_denied");
} catch (Exception e) {
logger.warn("failed to index audit event: [run_as_denied]", e);
}
}
}
@Override
public void runAsDenied(User user, RestRequest request) {
if (events.contains(RUN_AS_DENIED)) {
try {
enqueue(message("run_as_denied", user, request), "run_as_denied");
} catch (Exception e) {
logger.warn("failed to index audit event: [run_as_denied]", e);
}
@ -620,6 +631,26 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
return msg.end();
}
private Message message(String type, User user, RestRequest request) throws Exception {
Message msg = new Message().start();
common("rest", type, msg.builder);
msg.builder.field(Field.PRINCIPAL, user.principal());
msg.builder.field(Field.REQUEST_BODY, restRequestContent(request));
msg.builder.field(Field.ORIGIN_TYPE, "rest");
SocketAddress address = request.getRemoteAddress();
if (address instanceof InetSocketAddress) {
msg.builder.field(Field.ORIGIN_ADDRESS, NetworkAddress.format(((InetSocketAddress) request.getRemoteAddress())
.getAddress()));
} else {
msg.builder.field(Field.ORIGIN_ADDRESS, address);
}
msg.builder.field(Field.URI, request.uri());
return msg.end();
}
private Message message(String layer, String type, InetAddress originAddress, String profile,
ShieldIpFilterRule rule) throws IOException {
@ -877,15 +908,15 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
}
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(INDEX_SETTINGS);
settingsModule.registerSetting(EXCLUDE_EVENT_SETTINGS);
settingsModule.registerSetting(INCLUDE_EVENT_SETTINGS);
settingsModule.registerSetting(ROLLOVER_SETTING);
settingsModule.registerSetting(BULK_SIZE_SETTING);
settingsModule.registerSetting(FLUSH_TIMEOUT_SETTING);
settingsModule.registerSetting(QUEUE_SIZE_SETTING);
settingsModule.registerSetting(REMOTE_CLIENT_SETTINGS);
public static void registerSettings(List<Setting<?>> settings) {
settings.add(INDEX_SETTINGS);
settings.add(EXCLUDE_EVENT_SETTINGS);
settings.add(INCLUDE_EVENT_SETTINGS);
settings.add(ROLLOVER_SETTING);
settings.add(BULK_SIZE_SETTING);
settings.add(FLUSH_TIMEOUT_SETTING);
settings.add(QUEUE_SIZE_SETTING);
settings.add(REMOTE_CLIENT_SETTINGS);
}
private class QueueConsumer extends Thread {

View File

@ -35,6 +35,7 @@ import org.elasticsearch.transport.TransportMessage;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import static org.elasticsearch.common.Strings.arrayToCommaDelimitedString;
import static org.elasticsearch.shield.audit.AuditUtil.indices;
@ -383,6 +384,17 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
}
}
@Override
public void runAsDenied(User user, RestRequest request) {
if (logger.isDebugEnabled()) {
logger.debug("{}[rest] [run_as_denied]\t{}, principal=[{}], uri=[{}], request_body=[{}]", prefix,
hostAttributes(request), user.principal(), request.uri(), restRequestContent(request));
} else {
logger.info("{}[transport] [run_as_denied]\t{}, principal=[{}], uri=[{}]", prefix,
hostAttributes(request), user.principal(), request.uri());
}
}
private static String hostAttributes(RestRequest request) {
String formattedAddress;
SocketAddress socketAddress = request.getRemoteAddress();
@ -463,9 +475,9 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
return builder.append(user.principal()).append("]").toString();
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(HOST_ADDRESS_SETTING);
settingsModule.registerSetting(HOST_NAME_SETTING);
settingsModule.registerSetting(NODE_NAME_SETTING);
public static void registerSettings(List<Setting<?>> settings) {
settings.add(HOST_ADDRESS_SETTING);
settings.add(HOST_NAME_SETTING);
settings.add(NODE_NAME_SETTING);
}
}

View File

@ -0,0 +1,186 @@
/*
* 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.authc;
import org.elasticsearch.Version;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.shield.crypto.CryptoService;
import org.elasticsearch.shield.user.User;
import java.io.IOException;
import java.util.Base64;
import java.util.Objects;
public class Authentication {
public static final String AUTHENTICATION_KEY = "_xpack_security_authentication";
private final User user;
private final RealmRef authenticatedBy;
private final RealmRef lookedUpBy;
public Authentication(User user, RealmRef authenticatedBy, RealmRef lookedUpBy) {
this.user = Objects.requireNonNull(user);
this.authenticatedBy = Objects.requireNonNull(authenticatedBy);
this.lookedUpBy = lookedUpBy;
}
public Authentication(StreamInput in) throws IOException {
this.user = User.readFrom(in);
this.authenticatedBy = new RealmRef(in);
if (in.readBoolean()) {
this.lookedUpBy = new RealmRef(in);
} else {
this.lookedUpBy = null;
}
}
public User getUser() {
return user;
}
// TODO remove run as from the User object...
public User getRunAsUser() {
if (user.runAs() != null) {
return user.runAs();
}
return user;
}
public RealmRef getAuthenticatedBy() {
return authenticatedBy;
}
public RealmRef getLookedUpBy() {
return lookedUpBy;
}
public static Authentication readFromContext(ThreadContext ctx, CryptoService cryptoService, boolean sign)
throws IOException, IllegalArgumentException {
Authentication authentication = ctx.getTransient(AUTHENTICATION_KEY);
if (authentication != null) {
assert ctx.getHeader(AUTHENTICATION_KEY) != null;
return authentication;
}
String authenticationHeader = ctx.getHeader(AUTHENTICATION_KEY);
if (authenticationHeader == null) {
return null;
}
return deserializeHeaderAndPutInContext(authenticationHeader, ctx, cryptoService, sign);
}
static Authentication deserializeHeaderAndPutInContext(String header, ThreadContext ctx, CryptoService cryptoService, boolean sign)
throws IOException, IllegalArgumentException {
assert ctx.getTransient(AUTHENTICATION_KEY) == null;
if (sign) {
header = cryptoService.unsignAndVerify(header);
}
byte[] bytes = Base64.getDecoder().decode(header);
StreamInput input = StreamInput.wrap(bytes);
Version version = Version.readVersion(input);
input.setVersion(version);
Authentication authentication = new Authentication(input);
ctx.putTransient(AUTHENTICATION_KEY, authentication);
return authentication;
}
void writeToContextIfMissing(ThreadContext context, CryptoService cryptoService, boolean sign)
throws IOException, IllegalArgumentException {
if (context.getTransient(AUTHENTICATION_KEY) != null) {
if (context.getHeader(AUTHENTICATION_KEY) == null) {
throw new IllegalStateException("authentication present as a transient but not a header");
}
return;
}
if (context.getHeader(AUTHENTICATION_KEY) != null) {
deserializeHeaderAndPutInContext(context.getHeader(AUTHENTICATION_KEY), context, cryptoService, sign);
} else {
writeToContext(context, cryptoService, sign);
}
}
void writeToContext(ThreadContext ctx, CryptoService cryptoService, boolean sign)
throws IOException, IllegalArgumentException {
ensureContextDoesNotContainAuthentication(ctx);
String header = encode();
if (sign) {
header = cryptoService.sign(header);
}
ctx.putTransient(AUTHENTICATION_KEY, this);
ctx.putHeader(AUTHENTICATION_KEY, header);
}
void ensureContextDoesNotContainAuthentication(ThreadContext ctx) {
if (ctx.getTransient(AUTHENTICATION_KEY) != null) {
if (ctx.getHeader(AUTHENTICATION_KEY) == null) {
throw new IllegalStateException("authentication present as a transient but not a header");
}
throw new IllegalStateException("authentication is already present in the context");
}
}
String encode() throws IOException {
BytesStreamOutput output = new BytesStreamOutput();
Version.writeVersion(Version.CURRENT, output);
writeTo(output);
return Base64.getEncoder().encodeToString(output.bytes().toBytes());
}
void writeTo(StreamOutput out) throws IOException {
User.writeTo(user, out);
authenticatedBy.writeTo(out);
if (lookedUpBy != null) {
out.writeBoolean(true);
lookedUpBy.writeTo(out);
} else {
out.writeBoolean(false);
}
}
public static class RealmRef {
private final String nodeName;
private final String name;
private final String type;
public RealmRef(String name, String type, String nodeName) {
this.nodeName = nodeName;
this.name = name;
this.type = type;
}
public RealmRef(StreamInput in) throws IOException {
this.nodeName = in.readString();
this.name = in.readString();
this.type = in.readString();
}
void writeTo(StreamOutput out) throws IOException {
out.writeString(nodeName);
out.writeString(name);
out.writeString(type);
}
public String getNodeName() {
return nodeName;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
}
}

View File

@ -23,12 +23,12 @@ public interface AuthenticationService {
* the user and that user is then "attached" to the request's context.
*
* @param request The request to be authenticated
* @return The authenticated user
* @return A object containing the authentication information (user, realm, etc)
* @throws ElasticsearchSecurityException If no user was associated with the request or if the associated
* user credentials were found to be invalid
* @throws IOException If an error occurs when reading or writing
*/
User authenticate(RestRequest request) throws IOException, ElasticsearchSecurityException;
Authentication authenticate(RestRequest request) throws IOException, ElasticsearchSecurityException;
/**
* Authenticates the user that is associated with the given message. If the user was authenticated successfully (i.e.
@ -43,13 +43,13 @@ public interface AuthenticationService {
* authentication will be based on the whether there's an attached user to in the message and
* if there is, whether its credentials are valid.
*
* @return The authenticated user (either the attached one or if there isn't the fallback one if provided)
* @return A object containing the authentication information (user, realm, etc)
*
* @throws ElasticsearchSecurityException If the associated user credentials were found to be invalid or in the
* case where there was no user associated with the request, if the defautl
* token could not be authenticated.
*/
User authenticate(String action, TransportMessage message, User fallbackUser) throws IOException;
Authentication authenticate(String action, TransportMessage message, User fallbackUser) throws IOException;
/**
* Checks if there's already a user header attached to the given message. If missing, a new header is
@ -57,7 +57,7 @@ public interface AuthenticationService {
*
* @param user The user to be attached if the header is missing
*/
void attachUserHeaderIfMissing(User user) throws IOException;
void attachUserIfMissing(User user) throws IOException, IllegalArgumentException;
User getCurrentUser();
Authentication getCurrentAuthentication();
}

View File

@ -6,20 +6,18 @@
package org.elasticsearch.shield.authc;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.node.Node;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.authc.Authentication.RealmRef;
import org.elasticsearch.shield.user.AnonymousUser;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.shield.audit.AuditTrail;
@ -28,10 +26,9 @@ import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage;
import java.io.IOException;
import java.util.Base64;
import java.util.List;
import static org.elasticsearch.shield.Security.setting;
import static org.elasticsearch.shield.support.Exceptions.authenticationError;
/**
* An authentication service that delegates the authentication process to its configured {@link Realm realms}.
@ -46,14 +43,12 @@ public class InternalAuthenticationService extends AbstractComponent implements
Setting.boolSetting(setting("authc.run_as.enabled"), true, Property.NodeScope);
public static final String RUN_AS_USER_HEADER = "es-shield-runas-user";
static final String TOKEN_KEY = "_shield_token";
public static final String USER_KEY = "_shield_user";
private final Realms realms;
private final AuditTrail auditTrail;
private final CryptoService cryptoService;
private final AuthenticationFailureHandler failureHandler;
private final ThreadContext threadContext;
private final String nodeName;
private final boolean signUserHeader;
private final boolean runAsEnabled;
@ -61,6 +56,7 @@ public class InternalAuthenticationService extends AbstractComponent implements
public InternalAuthenticationService(Settings settings, Realms realms, AuditTrail auditTrail, CryptoService cryptoService,
AuthenticationFailureHandler failureHandler, ThreadPool threadPool, RestController controller) {
super(settings);
this.nodeName = Node.NODE_NAME_SETTING.get(settings);
this.realms = realms;
this.auditTrail = auditTrail;
this.cryptoService = cryptoService;
@ -74,394 +70,331 @@ public class InternalAuthenticationService extends AbstractComponent implements
}
@Override
public User authenticate(RestRequest request) throws IOException, ElasticsearchSecurityException {
return authenticate(newRequest(request), (User) null);
public Authentication authenticate(RestRequest request) throws IOException, ElasticsearchSecurityException {
return createAuthenticator(request).authenticate();
}
@Override
public User authenticate(String action, TransportMessage message, User fallbackUser) throws IOException {
return authenticate(newRequest(action, message), fallbackUser);
}
User authenticate(AuditableRequest request, User fallbackUser) throws IOException {
User user = getUserFromContext();
if (user != null) {
return user;
}
String header = threadContext.getHeader(USER_KEY);
if (header != null) {
if (request instanceof Rest) {
request.tamperedRequest();
throw new ElasticsearchSecurityException("rest request attempted to inject a user");
}
if (signUserHeader) {
try {
header = cryptoService.unsignAndVerify(header);
} catch (Exception e) {
request.tamperedRequest();
throw e;
}
}
user = decodeUser(header);
assert user != null;
putUserInContext(user);
} else {
user = authenticateWithRealms(request, fallbackUser);
setUser(user);
}
return user;
public Authentication authenticate(String action, TransportMessage message, User fallbackUser) throws IOException {
return createAuthenticator(action, message, fallbackUser).authenticate();
}
@Override
public void attachUserHeaderIfMissing(User user) throws IOException {
if (threadContext.getHeader(USER_KEY) != null) {
return;
}
User transientUser = threadContext.getTransient(USER_KEY);
if (transientUser != null) {
setUserHeader(transientUser);
return;
}
setUser(user);
public void attachUserIfMissing(User user) throws IOException {
Authentication authentication = new Authentication(user, new RealmRef("__attach", "__attach", nodeName), null);
authentication.writeToContextIfMissing(threadContext, cryptoService, signUserHeader);
}
@Override
public User getCurrentUser() {
return getUserFromContext();
}
void setUserHeader(User user) throws IOException {
String userHeader = signUserHeader ? cryptoService.sign(encodeUser(user, logger)) : encodeUser(user, logger);
threadContext.putHeader(USER_KEY, userHeader);
}
void setUser(User user) throws IOException {
putUserInContext(user);
setUserHeader(user);
}
void putUserInContext(User user) {
if (threadContext.getTransient(USER_KEY) != null) {
User ctxUser = threadContext.getTransient(USER_KEY);
throw new IllegalArgumentException("context already has user [" + ctxUser.principal() + "]. trying to set user [" + user
.principal() + "]");
}
threadContext.putTransient(USER_KEY, user);
}
User getUserFromContext() {
return threadContext.getTransient(USER_KEY);
}
static User decodeUser(String text) {
public Authentication getCurrentAuthentication() {
try {
byte[] bytes = Base64.getDecoder().decode(text);
StreamInput input = StreamInput.wrap(bytes);
Version version = Version.readVersion(input);
input.setVersion(version);
return User.readFrom(input);
} catch (IOException ioe) {
throw authenticationError("could not read authenticated user", ioe);
}
}
static String encodeUser(User user, ESLogger logger) {
try {
BytesStreamOutput output = new BytesStreamOutput();
Version.writeVersion(Version.CURRENT, output);
User.writeTo(user, output);
byte[] bytes = output.bytes().toBytes();
return Base64.getEncoder().encodeToString(bytes);
} catch (IOException ioe) {
if (logger != null) {
logger.error("could not encode authenticated user in message header... falling back to token headers", ioe);
}
Authentication authentication = Authentication.readFromContext(threadContext, cryptoService, signUserHeader);
return authentication == null ? null : authentication;
} catch (IOException e) {
logger.error("failed to read authentication", e);
return null;
}
}
/**
* Authenticates the user associated with the given request by delegating the authentication to
* the configured realms. Each realm that supports the given token will be asked to perform authentication,
* the first realm that successfully authenticates will "win" and its authenticated user will be returned.
* If none of the configured realms successfully authenticates the request, an {@link ElasticsearchSecurityException}
* will be thrown.
* <p>
* The order by which the realms are checked is defined in {@link Realms}.
*
* @param request the request to authenticate
* @param fallbackUser The user to assume if there is not other user attached to the message
* @return The authenticated user
* @throws ElasticsearchSecurityException If none of the configured realms successfully authenticated the
* request
*/
User authenticateWithRealms(AuditableRequest request, User fallbackUser) throws ElasticsearchSecurityException {
AuthenticationToken token;
try {
token = token(request);
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("failed to extract token from request: [{}]", e, request);
} else {
logger.warn("failed to extract token from request: [{}]", request, e.getMessage());
}
throw request.exceptionProcessingRequest(e);
Authenticator createAuthenticator(RestRequest request) {
return new Authenticator(request);
}
Authenticator createAuthenticator(String action, TransportMessage message, User fallbackUser) {
return new Authenticator(action, message, fallbackUser);
}
class Authenticator {
private final AuditableRequest request;
private final User fallbackUser;
private RealmRef authenticatedBy = null;
private RealmRef lookedupBy = null;
Authenticator(RestRequest request) {
this.request = new Rest(request);
this.fallbackUser = null;
}
if (token == null) {
if (fallbackUser != null) {
return fallbackUser;
Authenticator(String action, TransportMessage message, User fallbackUser) {
this.request = new Transport(action, message);
this.fallbackUser = fallbackUser;
}
Authentication authenticate() throws IOException, IllegalArgumentException {
Authentication existing = getCurrentAuthentication();
if (existing != null) {
return existing;
}
if (AnonymousUser.enabled()) {
return AnonymousUser.INSTANCE;
AuthenticationToken token = extractToken();
if (token == null) {
return handleNullToken();
}
User user = authenticateToken(token);
if (user == null) {
throw handleNullUser(token);
}
user = lookupRunAsUserIfNecessary(user, token);
final Authentication authentication = new Authentication(user, authenticatedBy, lookedupBy);
authentication.writeToContext(threadContext, cryptoService, signUserHeader);
return authentication;
}
Authentication getCurrentAuthentication() {
Authentication authentication;
try {
authentication = Authentication.readFromContext(threadContext, cryptoService, signUserHeader);
} catch (Exception e) {
throw request.tamperedRequest();
}
// make sure this isn't a rest request since we don't allow authentication to be read via a HTTP request...
if (authentication != null && request instanceof Rest) {
throw request.tamperedRequest();
}
return authentication;
}
AuthenticationToken extractToken() {
AuthenticationToken token = null;
try {
for (Realm realm : realms) {
token = realm.token(threadContext);
if (token != null) {
logger.trace("realm [{}] resolved authentication token [{}] from [{}]", realm, token.principal(), request);
break;
}
}
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("failed to extract token from request: [{}]", e, request);
} else {
logger.warn("failed to extract token from request: [{}]", request, e.getMessage());
}
throw request.exceptionProcessingRequest(e, null);
}
return token;
}
Authentication handleNullToken() throws IOException {
Authentication authentication = null;
if (fallbackUser != null) {
RealmRef authenticatedBy = new RealmRef("__fallback", "__fallback", nodeName);
authentication = new Authentication(fallbackUser, authenticatedBy, null);
} else if (AnonymousUser.enabled()) {
RealmRef authenticatedBy = new RealmRef("__anonymous", "__anonymous", nodeName);
authentication = new Authentication(AnonymousUser.INSTANCE, authenticatedBy, null);
}
if (authentication != null) {
authentication.writeToContext(threadContext, cryptoService, signUserHeader);
return authentication;
}
throw request.anonymousAccessDenied();
}
User user;
try {
user = authenticate(request, token);
} catch (Exception e) {
if (logger.isDebugEnabled()) {
User authenticateToken(AuthenticationToken token) {
User user = null;
try {
for (Realm realm : realms) {
if (realm.supports(token)) {
user = realm.authenticate(token);
if (user != null) {
authenticatedBy = new RealmRef(realm.name(), realm.type(), nodeName);
break;
}
request.realmAuthenticationFailed(token, realm.name());
}
}
} catch (Exception e) {
logger.debug("authentication failed for principal [{}], [{}]", e, request);
throw request.exceptionProcessingRequest(e, token);
} finally {
token.clearCredentials();
}
throw request.exceptionProcessingRequest(e, token);
return user;
}
if (user == null) {
throw request.failedAuthentication(token);
ElasticsearchSecurityException handleNullUser(AuthenticationToken token) {
throw request.authenticationFailed(token);
}
if (runAsEnabled) {
boolean shouldTryToRunAs(User authenticatedUser, AuthenticationToken token) {
if (runAsEnabled == false) {
return false;
}
String runAsUsername = threadContext.getHeader(RUN_AS_USER_HEADER);
if (runAsUsername != null) {
if (runAsUsername.isEmpty()) {
logger.warn("user [{}] attempted to runAs with an empty username", user.principal());
throw request.failedAuthentication(token);
}
User runAsUser;
try {
runAsUser = lookupUser(runAsUsername);
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("lookup of run as user failed for principal [{}], [{}], run as username [{}]", e,
token.principal(), request, runAsUsername);
if (runAsUsername == null) {
return false;
}
if (runAsUsername.isEmpty()) {
logger.debug("user [{}] attempted to runAs with an empty username", authenticatedUser.principal());
throw request.runAsDenied(new User(authenticatedUser.principal(), authenticatedUser.roles(),
new User(runAsUsername, Strings.EMPTY_ARRAY)), token);
}
return true;
}
User lookupRunAsUserIfNecessary(User authenticatedUser, AuthenticationToken token) {
User user = authenticatedUser;
if (shouldTryToRunAs(user, token) == false) {
return user;
}
final String runAsUsername = threadContext.getHeader(RUN_AS_USER_HEADER);
try {
for (Realm realm : realms) {
if (realm.userLookupSupported()) {
User runAsUser = realm.lookupUser(runAsUsername);
if (runAsUser != null) {
lookedupBy = new RealmRef(realm.name(), realm.type(), nodeName);
user = new User(user.principal(), user.roles(), runAsUser);
return user;
}
}
throw request.exceptionProcessingRequest(e, token);
}
// wrap in a try catch because the user constructor could throw an exception if we are trying to runAs the system user
try {
if (runAsUser != null) {
user = new User(user.principal(), user.roles(), runAsUser);
} else {
// the requested run as user does not exist, but we don't throw an error here otherwise this could let
// information leak about users in the system... instead we'll just let the authz service fail throw an
// authorization error
user = new User(user.principal(), user.roles(), new User(runAsUsername, Strings.EMPTY_ARRAY));
}
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("user creation failed for principal [{}], [{}], run as username [{}]", e, token.principal(),
request, runAsUsername);
}
throw request.exceptionProcessingRequest(e, token);
// the requested run as user does not exist, but we don't throw an error here otherwise this could let
// information leak about users in the system... instead we'll just let the authz service fail throw an
// authorization error
user = new User(user.principal(), user.roles(), new User(runAsUsername, Strings.EMPTY_ARRAY));
} catch (Exception e) {
logger.debug("run as failed for principal [{}], [{}], run as username [{}]", e, token.principal(), request, runAsUsername);
throw request.exceptionProcessingRequest(e, token);
}
return user;
}
abstract class AuditableRequest {
abstract void realmAuthenticationFailed(AuthenticationToken token, String realm);
abstract ElasticsearchSecurityException tamperedRequest();
abstract ElasticsearchSecurityException exceptionProcessingRequest(Exception e, @Nullable AuthenticationToken token);
abstract ElasticsearchSecurityException authenticationFailed(AuthenticationToken token);
abstract ElasticsearchSecurityException anonymousAccessDenied();
abstract ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token);
}
class Transport extends AuditableRequest {
private final String action;
private final TransportMessage message;
Transport(String action, TransportMessage message) {
this.action = action;
this.message = message;
}
@Override
void realmAuthenticationFailed(AuthenticationToken token, String realm) {
auditTrail.authenticationFailed(realm, token, action, message);
}
@Override
ElasticsearchSecurityException tamperedRequest() {
auditTrail.tamperedRequest(action, message);
return new ElasticsearchSecurityException("failed to verify signed authentication information");
}
@Override
ElasticsearchSecurityException exceptionProcessingRequest(Exception e, @Nullable AuthenticationToken token) {
if (token != null) {
auditTrail.authenticationFailed(token, action, message);
} else {
auditTrail.authenticationFailed(action, message);
}
return failureHandler.exceptionProcessingRequest(message, action, e, threadContext);
}
@Override
ElasticsearchSecurityException authenticationFailed(AuthenticationToken token) {
auditTrail.authenticationFailed(token, action, message);
return failureHandler.failedAuthentication(message, token, action, threadContext);
}
@Override
ElasticsearchSecurityException anonymousAccessDenied() {
auditTrail.anonymousAccessDenied(action, message);
return failureHandler.missingToken(message, action, threadContext);
}
@Override
ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token) {
auditTrail.runAsDenied(user, action, message);
return failureHandler.failedAuthentication(message, token, action, threadContext);
}
public String toString() {
return "transport request action [" + action + "]";
}
}
return user;
}
User authenticate(AuditableRequest request, AuthenticationToken token) throws ElasticsearchSecurityException {
assert token != null : "cannot authenticate null tokens";
try {
for (Realm realm : realms) {
if (realm.supports(token)) {
User user = realm.authenticate(token);
if (user != null) {
return user;
}
request.authenticationFailed(token, realm.name());
class Rest extends AuditableRequest {
private final RestRequest request;
Rest(RestRequest request) {
this.request = request;
}
@Override
void realmAuthenticationFailed(AuthenticationToken token, String realm) {
auditTrail.authenticationFailed(realm, token, request);
}
@Override
ElasticsearchSecurityException tamperedRequest() {
auditTrail.tamperedRequest(request);
return new ElasticsearchSecurityException("rest request attempted to inject a user");
}
@Override
ElasticsearchSecurityException exceptionProcessingRequest(Exception e, @Nullable AuthenticationToken token) {
if (token != null) {
auditTrail.authenticationFailed(token, request);
} else {
auditTrail.authenticationFailed(request);
}
return failureHandler.exceptionProcessingRequest(request, e, threadContext);
}
request.authenticationFailed(token);
return null;
} finally {
token.clearCredentials();
}
}
AuthenticationToken token(AuditableRequest request) throws ElasticsearchSecurityException {
for (Realm realm : realms) {
AuthenticationToken token = realm.token(threadContext);
if (token != null) {
request.tokenResolved(realm.name(), token);
return token;
@Override
ElasticsearchSecurityException authenticationFailed(AuthenticationToken token) {
auditTrail.authenticationFailed(token, request);
return failureHandler.failedAuthentication(request, token, threadContext);
}
@Override
ElasticsearchSecurityException anonymousAccessDenied() {
auditTrail.anonymousAccessDenied(request);
return failureHandler.missingToken(request, threadContext);
}
@Override
ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token) {
auditTrail.runAsDenied(user, request);
return failureHandler.failedAuthentication(request, token, threadContext);
}
public String toString() {
return "rest request uri [" + request.uri() + "]";
}
}
return null;
}
User lookupUser(String username) {
for (Realm realm : realms) {
if (realm.userLookupSupported()) {
User user = realm.lookupUser(username);
if (user != null) {
return user;
}
}
}
return null;
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(SIGN_USER_HEADER);
settingsModule.registerSetting(RUN_AS_ENABLED);
}
// these methods are package private for testing. They are also needed so that a AuditableRequest can be created in tests
AuditableRequest newRequest(String action, TransportMessage message) {
return new Transport(action, message);
}
AuditableRequest newRequest(RestRequest request) {
return new Rest(request);
}
abstract class AuditableRequest {
abstract void authenticationFailed(AuthenticationToken token);
abstract void authenticationFailed(AuthenticationToken token, String realm);
abstract void tamperedRequest();
abstract void tokenResolved(String realm, AuthenticationToken token);
abstract ElasticsearchSecurityException exceptionProcessingRequest(Exception e);
abstract ElasticsearchSecurityException exceptionProcessingRequest(Exception e, AuthenticationToken token);
abstract ElasticsearchSecurityException failedAuthentication(AuthenticationToken token);
abstract ElasticsearchSecurityException anonymousAccessDenied();
}
class Transport extends AuditableRequest {
private final String action;
private final TransportMessage message;
Transport(String action, TransportMessage message) {
this.action = action;
this.message = message;
}
@Override
void authenticationFailed(AuthenticationToken token) {
auditTrail.authenticationFailed(token, action, message);
}
@Override
void authenticationFailed(AuthenticationToken token, String realm) {
auditTrail.authenticationFailed(realm, token, action, message);
}
@Override
void tamperedRequest() {
auditTrail.tamperedRequest(action, message);
}
@Override
void tokenResolved(String realm, AuthenticationToken token) {
logger.trace("realm [{}] resolved authentication token [{}] from transport request with action [{}]",
realm, token.principal(), action);
}
@Override
ElasticsearchSecurityException exceptionProcessingRequest(Exception e) {
auditTrail.authenticationFailed(action, message);
return failureHandler.exceptionProcessingRequest(message, action, e, threadContext);
}
@Override
ElasticsearchSecurityException exceptionProcessingRequest(Exception e, AuthenticationToken token) {
authenticationFailed(token);
return failureHandler.exceptionProcessingRequest(message, action, e, threadContext);
}
ElasticsearchSecurityException failedAuthentication(AuthenticationToken token) {
auditTrail.authenticationFailed(token, action, message);
return failureHandler.failedAuthentication(message, token, action, threadContext);
}
@Override
ElasticsearchSecurityException anonymousAccessDenied() {
auditTrail.anonymousAccessDenied(action, message);
return failureHandler.missingToken(message, action, threadContext);
}
public String toString() {
return "transport action [" + action + "]";
}
}
class Rest extends AuditableRequest {
private final RestRequest request;
Rest(RestRequest request) {
this.request = request;
}
@Override
void authenticationFailed(AuthenticationToken token) {
auditTrail.authenticationFailed(token, request);
}
@Override
void authenticationFailed(AuthenticationToken token, String realm) {
auditTrail.authenticationFailed(realm, token, request);
}
@Override
void tamperedRequest() {
auditTrail.tamperedRequest(request);
}
@Override
void tokenResolved(String realm, AuthenticationToken token) {
logger.trace("realm [{}] resolved authentication token [{}] from rest request with uri [{}]",
realm, token.principal(), request.uri());
}
@Override
ElasticsearchSecurityException exceptionProcessingRequest(Exception e) {
auditTrail.authenticationFailed(request);
return failureHandler.exceptionProcessingRequest(request, e, threadContext);
}
@Override
ElasticsearchSecurityException exceptionProcessingRequest(Exception e, AuthenticationToken token) {
authenticationFailed(token);
return failureHandler.exceptionProcessingRequest(request, e, threadContext);
}
ElasticsearchSecurityException failedAuthentication(AuthenticationToken token) {
auditTrail.authenticationFailed(token, request);
return failureHandler.failedAuthentication(request, token, threadContext);
}
@Override
ElasticsearchSecurityException anonymousAccessDenied() {
auditTrail.anonymousAccessDenied(request);
return failureHandler.missingToken(request, threadContext);
}
public String toString() {
return "rest uri [" + request.uri() + "]";
}
public static void addSettings(List<Setting<?>> settings) {
settings.add(SIGN_USER_HEADER);
settings.add(RUN_AS_ENABLED);
}
}

View File

@ -212,7 +212,7 @@ public class Realms extends AbstractLifecycleComponent<Realms> implements Iterab
}
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(REALMS_GROUPS_SETTINGS);
public static void addSettings(List<Setting<?>> settingsModule) {
settingsModule.add(REALMS_GROUPS_SETTINGS);
}
}

View File

@ -867,9 +867,9 @@ public class NativeUsersStore extends AbstractComponent implements ClusterStateL
void onUsersChanged(List<String> username);
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(SCROLL_SIZE_SETTING);
settingsModule.registerSetting(SCROLL_KEEP_ALIVE_SETTING);
settingsModule.registerSetting(POLL_INTERVAL_SETTING);
public static void addSettings(List<Setting<?>> settings) {
settings.add(SCROLL_SIZE_SETTING);
settings.add(SCROLL_KEEP_ALIVE_SETTING);
settings.add(POLL_INTERVAL_SETTING);
}
}

View File

@ -6,6 +6,7 @@
package org.elasticsearch.shield.authz;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.transport.TransportRequest;
@ -29,11 +30,11 @@ public interface AuthorizationService {
* have the appropriate privileges for this action/request, an {@link ElasticsearchSecurityException}
* will be thrown.
*
* @param user The user
* @param action The action
* @param request The request
* @param authentication The authentication information
* @param action The action
* @param request The request
* @throws ElasticsearchSecurityException If the given user is no allowed to execute the given request
*/
void authorize(User user, String action, TransportRequest request) throws ElasticsearchSecurityException;
void authorize(Authentication authentication, String action, TransportRequest request) throws ElasticsearchSecurityException;
}

View File

@ -6,6 +6,7 @@
package org.elasticsearch.shield.authz;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.user.SystemUser;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.shield.authc.InternalAuthenticationService;
@ -44,8 +45,8 @@ public final class AuthorizationUtils {
return false;
}
User user = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
if (user == null || SystemUser.is(user)) {
Authentication authentication = threadContext.getTransient(Authentication.AUTHENTICATION_KEY);
if (authentication == null || SystemUser.is(authentication.getUser())) {
return true;
}

View File

@ -23,11 +23,11 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.search.action.SearchTransportService;
import org.elasticsearch.shield.ShieldTemplateService;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.user.AnonymousUser;
import org.elasticsearch.shield.user.SystemUser;
import org.elasticsearch.shield.user.User;
@ -140,32 +140,32 @@ public class InternalAuthorizationService extends AbstractComponent implements A
}
@Override
public void authorize(User user, String action, TransportRequest request) throws ElasticsearchSecurityException {
public void authorize(Authentication authentication, String action, TransportRequest request) throws ElasticsearchSecurityException {
// prior to doing any authorization lets set the originating action in the context only
setOriginatingAction(action);
User effectiveUser = user;
// first we need to check if the user is the system. If it is, we'll just authorize the system access
if (SystemUser.is(user)) {
if (SystemUser.isAuthorized(action)) {
if (SystemUser.is(authentication.getRunAsUser())) {
if (SystemUser.isAuthorized(action) && SystemUser.is(authentication.getUser())) {
setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
grant(user, action, request);
grant(authentication, action, request);
return;
}
throw denial(user, action, request);
throw denial(authentication, action, request);
}
GlobalPermission permission = permission(user.roles());
// get the roles of the authenticated user, which may be different than the effective
GlobalPermission permission = permission(authentication.getUser().roles());
final boolean isRunAs = user.runAs() != null;
final boolean isRunAs = authentication.getUser() != authentication.getRunAsUser();
// permission can be null as it might be that the user's role
// is unknown
if (permission == null || permission.isEmpty()) {
if (isRunAs) {
// the request is a run as request so we should call the specific audit event for a denied run as attempt
throw denyRunAs(user, action, request);
throw denyRunAs(authentication, action, request);
} else {
throw denial(user, action, request);
throw denial(authentication, action, request);
}
}
@ -173,18 +173,17 @@ public class InternalAuthorizationService extends AbstractComponent implements A
if (isRunAs) {
// first we must authorize for the RUN_AS action
RunAsPermission runAs = permission.runAs();
if (runAs != null && runAs.check(user.runAs().principal())) {
grantRunAs(user, action, request);
permission = permission(user.runAs().roles());
if (runAs != null && runAs.check(authentication.getRunAsUser().principal())) {
grantRunAs(authentication, action, request);
permission = permission(authentication.getRunAsUser().roles());
// permission can be null as it might be that the user's role
// is unknown
if (permission == null || permission.isEmpty()) {
throw denial(user, action, request);
throw denial(authentication, action, request);
}
effectiveUser = user.runAs();
} else {
throw denyRunAs(user, action, request);
throw denyRunAs(authentication, action, request);
}
}
@ -193,17 +192,17 @@ public class InternalAuthorizationService extends AbstractComponent implements A
if (ClusterPrivilege.ACTION_MATCHER.test(action)) {
ClusterPermission cluster = permission.cluster();
// we use the effectiveUser for permission checking since we are running as a user!
if (cluster != null && cluster.check(action, request, effectiveUser)) {
if (cluster != null && cluster.check(action, request, authentication)) {
setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
grant(user, action, request);
grant(authentication, action, request);
return;
}
throw denial(user, action, request);
throw denial(authentication, action, request);
}
// ok... this is not a cluster action, let's verify it's an indices action
if (!IndexPrivilege.ACTION_MATCHER.test(action)) {
throw denial(user, action, request);
throw denial(authentication, action, request);
}
// some APIs are indices requests that are not actually associated with indices. For example,
@ -217,33 +216,34 @@ public class InternalAuthorizationService extends AbstractComponent implements A
//note that clear scroll shard level actions can originate from a clear scroll all, which doesn't require any
//indices permission as it's categorized under cluster. This is why the scroll check is performed
//even before checking if the user has any indices permission.
grant(user, action, request);
grant(authentication, action, request);
return;
}
assert false : "only scroll related requests are known indices api that don't support retrieving the indices they relate to";
throw denial(user, action, request);
throw denial(authentication, action, request);
}
if (permission.indices() == null || permission.indices().isEmpty()) {
throw denial(user, action, request);
throw denial(authentication, action, request);
}
ClusterState clusterState = clusterService.state();
Set<String> indexNames = resolveIndices(user, action, request, clusterState);
Set<String> indexNames = resolveIndices(authentication, action, request, clusterState);
assert !indexNames.isEmpty() : "every indices request needs to have its indices set thus the resolved indices must not be empty";
MetaData metaData = clusterState.metaData();
IndicesAccessControl indicesAccessControl = permission.authorize(action, indexNames, metaData);
if (!indicesAccessControl.isGranted()) {
throw denial(user, action, request);
throw denial(authentication, action, request);
} else if (indicesAccessControl.getIndexPermissions(ShieldTemplateService.SECURITY_INDEX_NAME) != null
&& indicesAccessControl.getIndexPermissions(ShieldTemplateService.SECURITY_INDEX_NAME).isGranted()
&& XPackUser.is(user) == false
&& XPackUser.is(authentication.getRunAsUser()) == false
&& MONITOR_INDEX_PREDICATE.test(action) == false) {
// only the XPackUser is allowed to work with this index, but we should allow indices monitoring actions through for debugging
// purposes. These monitor requests also sometimes resolve indices concretely and then requests them
logger.debug("user [{}] attempted to directly perform [{}] against the security index [{}]", user.principal(), action,
ShieldTemplateService.SECURITY_INDEX_NAME);
throw denial(user, action, request);
// FIXME its not just the XPackUser. We said the elastic user and superusers could access this!
logger.debug("user [{}] attempted to directly perform [{}] against the security index [{}]",
authentication.getRunAsUser().principal(), action, ShieldTemplateService.SECURITY_INDEX_NAME);
throw denial(authentication, action, request);
} else {
setIndicesAccessControl(indicesAccessControl);
}
@ -259,14 +259,14 @@ public class InternalAuthorizationService extends AbstractComponent implements A
}
indicesAccessControl = permission.authorize("indices:admin/aliases", aliasesAndIndices, metaData);
if (!indicesAccessControl.isGranted()) {
throw denial(user, "indices:admin/aliases", request);
throw denial(authentication, "indices:admin/aliases", request);
}
// no need to re-add the indicesAccessControl in the context,
// because the create index call doesn't do anything FLS or DLS
}
}
grant(user, action, request);
grant(authentication, action, request);
}
private void setIndicesAccessControl(IndicesAccessControl accessControl) {
@ -304,15 +304,15 @@ public class InternalAuthorizationService extends AbstractComponent implements A
return roles.build();
}
private Set<String> resolveIndices(User user, String action, TransportRequest request, ClusterState clusterState) {
private Set<String> resolveIndices(Authentication authentication, String action, TransportRequest request, ClusterState clusterState) {
MetaData metaData = clusterState.metaData();
for (IndicesAndAliasesResolver resolver : indicesAndAliasesResolvers) {
if (resolver.requestType().isInstance(request)) {
return resolver.resolve(user, action, request, metaData);
return resolver.resolve(authentication.getRunAsUser(), action, request, metaData);
}
}
assert false : "we should be able to resolve indices for any known request that requires indices privileges";
throw denial(user, action, request);
throw denial(authentication, action, request);
}
private static boolean isScrollRelatedAction(String action) {
@ -325,39 +325,41 @@ public class InternalAuthorizationService extends AbstractComponent implements A
action.equals(SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME);
}
private ElasticsearchSecurityException denial(User user, String action, TransportRequest request) {
auditTrail.accessDenied(user, action, request);
return denialException(user, action);
private ElasticsearchSecurityException denial(Authentication authentication, String action, TransportRequest request) {
auditTrail.accessDenied(authentication.getUser(), action, request);
return denialException(authentication, action);
}
private ElasticsearchSecurityException denyRunAs(User user, String action, TransportRequest request) {
auditTrail.runAsDenied(user, action, request);
return denialException(user, action);
private ElasticsearchSecurityException denyRunAs(Authentication authentication, String action, TransportRequest request) {
auditTrail.runAsDenied(authentication.getUser(), action, request);
return denialException(authentication, action);
}
private void grant(User user, String action, TransportRequest request) {
auditTrail.accessGranted(user, action, request);
private void grant(Authentication authentication, String action, TransportRequest request) {
auditTrail.accessGranted(authentication.getUser(), action, request);
}
private void grantRunAs(User user, String action, TransportRequest request) {
auditTrail.runAsGranted(user, action, request);
private void grantRunAs(Authentication authentication, String action, TransportRequest request) {
auditTrail.runAsGranted(authentication.getUser(), action, request);
}
private ElasticsearchSecurityException denialException(User user, String action) {
private ElasticsearchSecurityException denialException(Authentication authentication, String action) {
final User user = authentication.getUser();
// Special case for anonymous user
if (AnonymousUser.enabled() && AnonymousUser.is(user)) {
if (anonymousAuthzExceptionEnabled == false) {
throw authcFailureHandler.authenticationRequired(action, threadContext);
}
}
if (user.runAs() != null) {
// check for run as
if (user != authentication.getRunAsUser()) {
return authorizationError("action [{}] is unauthorized for user [{}] run as [{}]", action, user.principal(),
user.runAs().principal());
authentication.getRunAsUser().principal());
}
return authorizationError("action [{}] is unauthorized for user [{}]", action, user.principal());
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING);
public static void addSettings(List<Setting<?>> settings) {
settings.add(ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING);
}
}

View File

@ -5,8 +5,8 @@
*/
package org.elasticsearch.shield.authz.permission;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.authz.privilege.ClusterPrivilege;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.transport.TransportRequest;
import java.util.List;
@ -17,13 +17,13 @@ import java.util.function.Predicate;
*/
public interface ClusterPermission extends Permission {
boolean check(String action, TransportRequest request, User user);
boolean check(String action, TransportRequest request, Authentication authentication);
public static class Core implements ClusterPermission {
public static final Core NONE = new Core(ClusterPrivilege.NONE) {
@Override
public boolean check(String action, TransportRequest request, User user) {
public boolean check(String action, TransportRequest request, Authentication authentication) {
return false;
}
@ -46,7 +46,7 @@ public interface ClusterPermission extends Permission {
}
@Override
public boolean check(String action, TransportRequest request, User user) {
public boolean check(String action, TransportRequest request, Authentication authentication) {
return predicate.test(action);
}
@ -65,7 +65,7 @@ public interface ClusterPermission extends Permission {
}
@Override
public boolean check(String action, TransportRequest request, User user) {
public boolean check(String action, TransportRequest request, Authentication authentication) {
if (globals == null) {
return false;
}
@ -73,7 +73,7 @@ public interface ClusterPermission extends Permission {
if (global == null || global.cluster() == null) {
throw new RuntimeException();
}
if (global.cluster().check(action, request, user)) {
if (global.cluster().check(action, request, authentication)) {
return true;
}
}

View File

@ -5,7 +5,9 @@
*/
package org.elasticsearch.shield.authz.permission;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.authc.esnative.NativeRealm;
import org.elasticsearch.shield.authc.esnative.ReservedRealm;
import org.elasticsearch.shield.action.user.AuthenticateAction;
import org.elasticsearch.shield.action.user.ChangePasswordAction;
import org.elasticsearch.shield.action.user.UserRequest;
@ -40,18 +42,47 @@ public class DefaultRole extends Role {
}
@Override
public boolean check(String action, TransportRequest request, User user) {
final boolean actionAllowed = super.check(action, request, user);
public boolean check(String action, TransportRequest request, Authentication authentication) {
final boolean actionAllowed = super.check(action, request, authentication);
if (actionAllowed) {
assert request instanceof UserRequest;
if (request instanceof UserRequest == false) {
assert false : "right now only a user request should be allowed";
return false;
}
UserRequest userRequest = (UserRequest) request;
String[] usernames = userRequest.usernames();
assert usernames != null && usernames.length == 1;
if (usernames == null || usernames.length != 1 || usernames[0] == null) {
assert false : "this role should only be used for actions to apply to a single user";
return false;
}
final String username = usernames[0];
assert username != null;
return user.principal().equals(username);
final boolean sameUsername = authentication.getRunAsUser().principal().equals(username);
if (sameUsername && ChangePasswordAction.NAME.equals(action)) {
return checkChangePasswordAction(authentication);
}
assert AuthenticateAction.NAME.equals(action) || sameUsername == false;
return sameUsername;
}
return false;
}
}
static boolean checkChangePasswordAction(Authentication authentication) {
// we need to verify that this user was authenticated by or looked up by a realm type that support password changes
// otherwise we open ourselves up to issues where a user in a different realm could be created with the same username
// and do malicious things
final boolean isRunAs = authentication.getUser() != authentication.getRunAsUser();
final String realmType;
if (isRunAs) {
realmType = authentication.getLookedUpBy().getType();
} else {
realmType = authentication.getAuthenticatedBy().getType();
}
assert realmType != null;
// ensure the user was authenticated by a realm that we can change a password for. The native realm is an internal realm and right
// now only one can exist in the realm configuration - if this changes we should update this check
return ReservedRealm.TYPE.equals(realmType) || NativeRealm.TYPE.equals(realmType);
}
}

View File

@ -163,7 +163,11 @@ public interface IndicesPermission extends Permission, Iterable<IndicesPermissio
}
Set<String> roleFields = rolesFieldsByIndex.get(index);
if (roleFields != null) {
roleFields = unmodifiableSet(roleFields);
if (roleFields.contains("*")) {
roleFields = null;
} else {
roleFields = unmodifiableSet(roleFields);
}
}
indexPermissions.put(index, new IndicesAccessControl.IndexAccessControl(entry.getValue(), roleFields, roleQueries));
}

View File

@ -260,7 +260,7 @@ public class FileRolesStore extends AbstractLifecycleComponent<RolesStore> imple
}
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(ROLES_FILE_SETTING);
public static void addSettings(List<Setting<?>> settings) {
settings.add(ROLES_FILE_SETTING);
}
}

View File

@ -31,7 +31,6 @@ import org.elasticsearch.common.inject.Provider;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.common.xcontent.ToXContent;
@ -604,9 +603,9 @@ public class NativeRolesStore extends AbstractComponent implements RolesStore, C
}
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(SCROLL_SIZE_SETTING);
settingsModule.registerSetting(SCROLL_KEEP_ALIVE_SETTING);
settingsModule.registerSetting(POLL_INTERVAL_SETTING);
public static void addSettings(List<Setting<?>> settings) {
settings.add(SCROLL_SIZE_SETTING);
settings.add(SCROLL_KEEP_ALIVE_SETTING);
settings.add(POLL_INTERVAL_SETTING);
}
}

View File

@ -676,10 +676,10 @@ public class InternalCryptoService extends AbstractLifecycleComponent<InternalCr
}
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(FILE_SETTING);
settingsModule.registerSetting(ENCRYPTION_KEY_LENGTH_SETTING);
settingsModule.registerSetting(ENCRYPTION_KEY_ALGO_SETTING);
settingsModule.registerSetting(ENCRYPTION_ALGO_SETTING);
public static void addSettings(List<Setting<?>> settings) {
settings.add(FILE_SETTING);
settings.add(ENCRYPTION_KEY_LENGTH_SETTING);
settings.add(ENCRYPTION_KEY_ALGO_SETTING);
settings.add(ENCRYPTION_ALGO_SETTING);
}
}

View File

@ -147,25 +147,25 @@ public abstract class SSLConfiguration {
static final Setting<Boolean> INCLUDE_JDK_CERTS_SETTING = Setting.boolSetting(globalKey(Custom.INCLUDE_JDK_CERTS_SETTING), true,
Property.NodeScope, Property.Filtered);
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(Global.CIPHERS_SETTING);
settingsModule.registerSetting(Global.SUPPORTED_PROTOCOLS_SETTING);
settingsModule.registerSetting(Global.KEYSTORE_PATH_SETTING);
settingsModule.registerSetting(Global.KEYSTORE_PASSWORD_SETTING);
settingsModule.registerSetting(Global.KEYSTORE_ALGORITHM_SETTING);
settingsModule.registerSetting(Global.KEYSTORE_KEY_PASSWORD_SETTING);
settingsModule.registerSetting(Global.KEY_PATH_SETTING);
settingsModule.registerSetting(Global.KEY_PASSWORD_SETTING);
settingsModule.registerSetting(Global.CERT_SETTING);
settingsModule.registerSetting(Global.TRUSTSTORE_PATH_SETTING);
settingsModule.registerSetting(Global.TRUSTSTORE_PASSWORD_SETTING);
settingsModule.registerSetting(Global.TRUSTSTORE_ALGORITHM_SETTING);
settingsModule.registerSetting(Global.PROTOCOL_SETTING);
settingsModule.registerSetting(Global.SESSION_CACHE_SIZE_SETTING);
settingsModule.registerSetting(Global.SESSION_CACHE_TIMEOUT_SETTING);
settingsModule.registerSetting(Global.CA_PATHS_SETTING);
settingsModule.registerSetting(Global.INCLUDE_JDK_CERTS_SETTING);
settingsModule.registerSetting(Global.RELOAD_ENABLED_SETTING);
public static void addSettings(List<Setting<?>> settings) {
settings.add(Global.CIPHERS_SETTING);
settings.add(Global.SUPPORTED_PROTOCOLS_SETTING);
settings.add(Global.KEYSTORE_PATH_SETTING);
settings.add(Global.KEYSTORE_PASSWORD_SETTING);
settings.add(Global.KEYSTORE_ALGORITHM_SETTING);
settings.add(Global.KEYSTORE_KEY_PASSWORD_SETTING);
settings.add(Global.KEY_PATH_SETTING);
settings.add(Global.KEY_PASSWORD_SETTING);
settings.add(Global.CERT_SETTING);
settings.add(Global.TRUSTSTORE_PATH_SETTING);
settings.add(Global.TRUSTSTORE_PASSWORD_SETTING);
settings.add(Global.TRUSTSTORE_ALGORITHM_SETTING);
settings.add(Global.PROTOCOL_SETTING);
settings.add(Global.SESSION_CACHE_SIZE_SETTING);
settings.add(Global.SESSION_CACHE_TIMEOUT_SETTING);
settings.add(Global.CA_PATHS_SETTING);
settings.add(Global.INCLUDE_JDK_CERTS_SETTING);
settings.add(Global.RELOAD_ENABLED_SETTING);
}
private final KeyConfig keyConfig;

View File

@ -19,13 +19,13 @@ public class Exceptions {
public static ElasticsearchSecurityException authenticationError(String msg, Throwable cause, Object... args) {
ElasticsearchSecurityException e = new ElasticsearchSecurityException(msg, RestStatus.UNAUTHORIZED, cause, args);
e.addHeader("WWW-Authenticate", "Basic realm=\"" + Security.NAME + "\"");
e.addHeader("WWW-Authenticate", "Basic realm=\"" + Security.NAME + "\" charset=\"UTF-8\"");
return e;
}
public static ElasticsearchSecurityException authenticationError(String msg, Object... args) {
ElasticsearchSecurityException e = new ElasticsearchSecurityException(msg, RestStatus.UNAUTHORIZED, args);
e.addHeader("WWW-Authenticate", "Basic realm=\"" + Security.NAME + "\"");
e.addHeader("WWW-Authenticate", "Basic realm=\"" + Security.NAME + "\" charset=\"UTF-8\"");
return e;
}

View File

@ -56,7 +56,7 @@ public interface ClientTransportFilter {
the system user will be attached. There cannot be a request outgoing from this
node that is not associated with a user.
*/
authcService.attachUserHeaderIfMissing(SystemUser.INSTANCE);
authcService.attachUserIfMissing(SystemUser.INSTANCE);
}
}
}

View File

@ -8,7 +8,7 @@ package org.elasticsearch.shield.transport;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.action.ShieldActionMapper;
import org.elasticsearch.shield.authc.AuthenticationService;
import org.elasticsearch.shield.authc.pki.PkiRealm;
@ -101,8 +101,8 @@ public interface ServerTransportFilter {
}
}
User user = authcService.authenticate(shieldAction, request, null);
authzService.authorize(user, shieldAction, request);
Authentication authentication = authcService.authenticate(shieldAction, request, null);
authzService.authorize(authentication, shieldAction, request);
}
}

View File

@ -5,7 +5,6 @@
*/
package org.elasticsearch.shield.transport;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
@ -24,8 +23,8 @@ public class ShieldClientTransportService extends TransportService {
@Inject
public ShieldClientTransportService(Settings settings, Transport transport, ThreadPool threadPool,
ClusterName clusterName, ClientTransportFilter clientFilter) {
super(settings, transport, threadPool, clusterName);
ClientTransportFilter clientFilter) {
super(settings, transport, threadPool);
this.clientFilter = clientFilter;
}

View File

@ -5,7 +5,6 @@
*/
package org.elasticsearch.shield.transport;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
@ -56,13 +55,12 @@ public class ShieldServerTransportService extends TransportService {
@Inject
public ShieldServerTransportService(Settings settings, Transport transport, ThreadPool threadPool,
ClusterName clusterName,
AuthenticationService authcService,
AuthorizationService authzService,
ShieldActionMapper actionMapper,
ClientTransportFilter clientTransportFilter,
SecurityLicenseState licenseState) {
super(settings, transport, threadPool, clusterName);
super(settings, transport, threadPool);
this.authcService = authcService;
this.authzService = authzService;
this.actionMapper = actionMapper;

View File

@ -260,13 +260,13 @@ public class IPFilter {
updateRules();
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(ALLOW_BOUND_ADDRESSES_SETTING);
settingsModule.registerSetting(IP_FILTER_ENABLED_SETTING);
settingsModule.registerSetting(IP_FILTER_ENABLED_HTTP_SETTING);
settingsModule.registerSetting(HTTP_FILTER_ALLOW_SETTING);
settingsModule.registerSetting(HTTP_FILTER_DENY_SETTING);
settingsModule.registerSetting(TRANSPORT_FILTER_ALLOW_SETTING);
settingsModule.registerSetting(TRANSPORT_FILTER_DENY_SETTING);
public static void addSettings(List<Setting<?>> settings) {
settings.add(ALLOW_BOUND_ADDRESSES_SETTING);
settings.add(IP_FILTER_ENABLED_SETTING);
settings.add(IP_FILTER_ENABLED_HTTP_SETTING);
settings.add(HTTP_FILTER_ALLOW_SETTING);
settings.add(HTTP_FILTER_DENY_SETTING);
settings.add(TRANSPORT_FILTER_ALLOW_SETTING);
settings.add(TRANSPORT_FILTER_DENY_SETTING);
}
}

View File

@ -27,6 +27,7 @@ import org.jboss.netty.handler.ssl.SslHandler;
import javax.net.ssl.SSLEngine;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.http.HttpTransportSettings.SETTING_HTTP_COMPRESSION;
import static org.elasticsearch.shield.Security.setting;
@ -128,10 +129,10 @@ public class ShieldNettyHttpServerTransport extends NettyHttpServerTransport {
}
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(SSL_SETTING);
settingsModule.registerSetting(CLIENT_AUTH_SETTING);
settingsModule.registerSetting(DEPRECATED_SSL_SETTING);
public static void addSettings(List<Setting<?>> settings) {
settings.add(SSL_SETTING);
settings.add(CLIENT_AUTH_SETTING);
settings.add(DEPRECATED_SSL_SETTING);
}
public static void overrideSettings(Settings.Builder settingsBuilder, Settings settings) {

View File

@ -34,6 +34,7 @@ import org.jboss.netty.handler.ssl.SslHandler;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import java.net.InetSocketAddress;
import java.util.List;
import static org.elasticsearch.shield.Security.featureEnabledSetting;
import static org.elasticsearch.shield.Security.setting;
@ -249,17 +250,17 @@ public class ShieldNettyTransport extends NettyTransport {
}
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(SSL_SETTING);
settingsModule.registerSetting(HOSTNAME_VERIFICATION_SETTING);
settingsModule.registerSetting(HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING);
settingsModule.registerSetting(CLIENT_AUTH_SETTING);
settingsModule.registerSetting(PROFILE_SSL_SETTING);
settingsModule.registerSetting(PROFILE_CLIENT_AUTH_SETTING);
public static void addSettings(List<Setting<?>> settingsModule) {
settingsModule.add(SSL_SETTING);
settingsModule.add(HOSTNAME_VERIFICATION_SETTING);
settingsModule.add(HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING);
settingsModule.add(CLIENT_AUTH_SETTING);
settingsModule.add(PROFILE_SSL_SETTING);
settingsModule.add(PROFILE_CLIENT_AUTH_SETTING);
// deprecated transport settings
settingsModule.registerSetting(DEPRECATED_SSL_SETTING);
settingsModule.registerSetting(DEPRECATED_PROFILE_SSL_SETTING);
settingsModule.registerSetting(DEPRECATED_HOSTNAME_VERIFICATION_SETTING);
settingsModule.add(DEPRECATED_SSL_SETTING);
settingsModule.add(DEPRECATED_PROFILE_SSL_SETTING);
settingsModule.add(DEPRECATED_HOSTNAME_VERIFICATION_SETTING);
}
}

View File

@ -12,6 +12,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.shield.user.User.ReservedUser;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -80,8 +81,12 @@ public class AnonymousUser extends ReservedUser {
return roles;
}
public static void registerSettings(SettingsModule settingsModule) {
settingsModule.registerSetting(USERNAME_SETTING);
settingsModule.registerSetting(ROLES_SETTING);
public static List<Setting<?>> getSettings() {
return Arrays.asList();
}
public static void addSettings(List<Setting<?>> settingsList) {
settingsList.add(USERNAME_SETTING);
settingsList.add(ROLES_SETTING);
}
}

View File

@ -12,7 +12,10 @@ import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.action.support.ActionFilterChain;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.shield.SecurityContext;
import org.elasticsearch.shield.action.ShieldActionMapper;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.authc.Authentication.RealmRef;
import org.elasticsearch.shield.user.SystemUser;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.shield.audit.AuditTrail;
@ -62,7 +65,7 @@ public class ShieldActionFilterTests extends ESTestCase {
ThreadPool threadPool = mock(ThreadPool.class);
when(threadPool.getThreadContext()).thenReturn(new ThreadContext(Settings.EMPTY));
filter = new ShieldActionFilter(Settings.EMPTY, authcService, authzService, cryptoService, auditTrail, securityLicenseState,
new ShieldActionMapper(), new HashSet<>(), threadPool);
new ShieldActionMapper(), new HashSet<>(), threadPool, mock(SecurityContext.class));
}
public void testApply() throws Exception {
@ -71,10 +74,11 @@ public class ShieldActionFilterTests extends ESTestCase {
ActionFilterChain chain = mock(ActionFilterChain.class);
Task task = mock(Task.class);
User user = new User("username", "r1", "r2");
when(authcService.authenticate("_action", request, SystemUser.INSTANCE)).thenReturn(user);
Authentication authentication = new Authentication(user, new RealmRef("test", "test", "foo"), null);
when(authcService.authenticate("_action", request, SystemUser.INSTANCE)).thenReturn(authentication);
doReturn(request).when(spy(filter)).unsign(user, "_action", request);
filter.apply(task, "_action", request, listener, chain);
verify(authzService).authorize(user, "_action", request);
verify(authzService).authorize(authentication, "_action", request);
verify(chain).proceed(eq(task), eq("_action"), eq(request), isA(ShieldActionFilter.SigningListener.class));
}
@ -85,8 +89,9 @@ public class ShieldActionFilterTests extends ESTestCase {
RuntimeException exception = new RuntimeException("process-error");
Task task = mock(Task.class);
User user = new User("username", "r1", "r2");
when(authcService.authenticate("_action", request, SystemUser.INSTANCE)).thenReturn(user);
doThrow(exception).when(authzService).authorize(user, "_action", request);
Authentication authentication = new Authentication(user, new RealmRef("test", "test", "foo"), null);
when(authcService.authenticate("_action", request, SystemUser.INSTANCE)).thenReturn(authentication);
doThrow(exception).when(authzService).authorize(authentication, "_action", request);
filter.apply(task, "_action", request, listener, chain);
verify(listener).onFailure(exception);
verifyNoMoreInteractions(chain);
@ -98,12 +103,13 @@ public class ShieldActionFilterTests extends ESTestCase {
ActionFilterChain chain = mock(ActionFilterChain.class);
User user = mock(User.class);
Task task = mock(Task.class);
when(authcService.authenticate("_action", request, SystemUser.INSTANCE)).thenReturn(user);
Authentication authentication = new Authentication(user, new RealmRef("test", "test", "foo"), null);
when(authcService.authenticate("_action", request, SystemUser.INSTANCE)).thenReturn(authentication);
when(cryptoService.signed("signed_scroll_id")).thenReturn(true);
when(cryptoService.unsignAndVerify("signed_scroll_id")).thenReturn("scroll_id");
filter.apply(task, "_action", request, listener, chain);
assertThat(request.scrollId(), equalTo("scroll_id"));
verify(authzService).authorize(user, "_action", request);
verify(authzService).authorize(authentication, "_action", request);
verify(chain).proceed(eq(task), eq("_action"), eq(request), isA(ShieldActionFilter.SigningListener.class));
}
@ -114,7 +120,8 @@ public class ShieldActionFilterTests extends ESTestCase {
IllegalArgumentException sigException = new IllegalArgumentException("bad bad boy");
User user = mock(User.class);
Task task = mock(Task.class);
when(authcService.authenticate("_action", request, SystemUser.INSTANCE)).thenReturn(user);
Authentication authentication = new Authentication(user, new RealmRef("test", "test", "foo"), null);
when(authcService.authenticate("_action", request, SystemUser.INSTANCE)).thenReturn(authentication);
when(cryptoService.signed("scroll_id")).thenReturn(true);
doThrow(sigException).when(cryptoService).unsignAndVerify("scroll_id");
filter.apply(task, "_action", request, listener, chain);

View File

@ -11,15 +11,14 @@ import org.elasticsearch.common.inject.Injector;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.indices.breaker.CircuitBreakerModule;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.node.Node;
import org.elasticsearch.shield.audit.logfile.LoggingAuditTrail;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.threadpool.ThreadPoolModule;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.local.LocalTransport;
@ -36,8 +35,7 @@ public class AuditTrailModuleTests extends ESTestCase {
.put("client.type", "node")
.put(AuditTrailModule.ENABLED_SETTING.getKey(), false)
.build();
SettingsModule settingsModule = new SettingsModule(settings);
settingsModule.registerSetting(AuditTrailModule.ENABLED_SETTING);
SettingsModule settingsModule = new SettingsModule(settings, AuditTrailModule.ENABLED_SETTING);
Injector injector = Guice.createInjector(settingsModule, new AuditTrailModule(settings));
AuditTrail auditTrail = injector.getInstance(AuditTrail.class);
assertThat(auditTrail, is(AuditTrail.NOOP));
@ -58,8 +56,7 @@ public class AuditTrailModuleTests extends ESTestCase {
.build();
ThreadPool pool = new TestThreadPool("testLogFile");
try {
SettingsModule settingsModule = new SettingsModule(settings);
settingsModule.registerSetting(AuditTrailModule.ENABLED_SETTING);
SettingsModule settingsModule = new SettingsModule(settings, AuditTrailModule.ENABLED_SETTING);
Injector injector = Guice.createInjector(
settingsModule,
new NetworkModule(new NetworkService(settings), settings, false, new NamedWriteableRegistry()) {
@ -69,8 +66,11 @@ public class AuditTrailModuleTests extends ESTestCase {
}
},
new AuditTrailModule(settings),
new CircuitBreakerModule(settings),
new ThreadPoolModule(pool),
b -> {
b.bind(CircuitBreakerService.class).toInstance(Node.createCircuitBreakerService(settingsModule.getSettings(),
settingsModule.getClusterSettings()));
b.bind(ThreadPool.class).toInstance(pool);
},
new Version.Module(Version.CURRENT)
);
AuditTrail auditTrail = injector.getInstance(AuditTrail.class);
@ -90,9 +90,7 @@ public class AuditTrailModuleTests extends ESTestCase {
.put(AuditTrailModule.OUTPUTS_SETTING.getKey() , "foo")
.put("client.type", "node")
.build();
SettingsModule settingsModule = new SettingsModule(settings);
settingsModule.registerSetting(AuditTrailModule.ENABLED_SETTING);
settingsModule.registerSetting(AuditTrailModule.OUTPUTS_SETTING);
SettingsModule settingsModule = new SettingsModule(settings, AuditTrailModule.ENABLED_SETTING, AuditTrailModule.OUTPUTS_SETTING);
try {
Guice.createInjector(settingsModule, new AuditTrailModule(settings));
fail("Expect initialization to fail when an unknown audit trail output is configured");

View File

@ -7,7 +7,6 @@ package org.elasticsearch.shield.authc;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.Version;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.Settings;
@ -15,7 +14,8 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.authc.InternalAuthenticationService.AuditableRequest;
import org.elasticsearch.shield.authc.Authentication.RealmRef;
import org.elasticsearch.shield.authc.InternalAuthenticationService.Authenticator;
import org.elasticsearch.shield.SecurityLicenseState.EnabledRealmType;
import org.elasticsearch.shield.user.AnonymousUser;
import org.elasticsearch.shield.user.SystemUser;
@ -32,17 +32,14 @@ import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import static org.elasticsearch.shield.support.Exceptions.authenticationError;
import static org.elasticsearch.test.ShieldTestsUtils.assertAuthenticationException;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
@ -50,11 +47,10 @@ import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
@ -66,9 +62,6 @@ import static org.mockito.Mockito.when;
*/
public class InternalAuthenticationServiceTests extends ESTestCase {
@Rule
public ExpectedException thrown = ExpectedException.none();
InternalAuthenticationService service;
TransportMessage message;
RestRequest restRequest;
@ -88,10 +81,15 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
message = new InternalMessage();
restRequest = new FakeRestRequest();
firstRealm = mock(Realm.class);
when(firstRealm.name()).thenReturn("file");
when(firstRealm.type()).thenReturn("file");
when(firstRealm.name()).thenReturn("file_realm");
secondRealm = mock(Realm.class);
when(secondRealm.name()).thenReturn("second");
Settings settings = Settings.builder().put("path.home", createTempDir()).build();
when(secondRealm.type()).thenReturn("second");
when(secondRealm.name()).thenReturn("second_realm");
Settings settings = Settings.builder()
.put("path.home", createTempDir())
.put("node.name", "authc_test")
.build();
SecurityLicenseState shieldLicenseState = mock(SecurityLicenseState.class);
when(shieldLicenseState.enabledRealmType()).thenReturn(EnabledRealmType.ALL);
when(shieldLicenseState.authenticationAndAuthorizationEnabled()).thenReturn(true);
@ -113,7 +111,8 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
threadContext = new ThreadContext(Settings.EMPTY);
controller = mock(RestController.class);
when(threadPool.getThreadContext()).thenReturn(threadContext);
service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService,
when(cryptoService.sign(any(String.class))).thenReturn("_signed_auth");
service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool, controller);
}
@ -127,17 +126,21 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
when(firstRealm.token(threadContext)).thenReturn(null);
when(secondRealm.token(threadContext)).thenReturn(token);
AuthenticationToken result = service.token(service.newRequest("_action", message));
Authenticator authenticator = service.createAuthenticator("_action", message, null);
AuthenticationToken result = authenticator.extractToken();
assertThat(result, notNullValue());
assertThat(result, is(token));
verifyZeroInteractions(auditTrail);
}
public void testTokenMissing() throws Exception {
AuthenticationToken token = service.token(service.newRequest("_action", message));
Authenticator authenticator = service.createAuthenticator("_action", message, null);
AuthenticationToken token = authenticator.extractToken();
assertThat(token, nullValue());
ElasticsearchSecurityException e = expectThrows(ElasticsearchSecurityException.class, authenticator::handleNullToken);
assertThat(e.getMessage(), containsString("missing authentication token"));
verify(auditTrail).anonymousAccessDenied("_action", message);
verifyNoMoreInteractions(auditTrail);
assertThat(threadContext.getTransient(InternalAuthenticationService.TOKEN_KEY), nullValue());
}
@SuppressWarnings("unchecked")
@ -147,20 +150,20 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
when(firstRealm.authenticate(token)).thenReturn(null); // first fails
when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(user);
if (randomBoolean()) {
when(firstRealm.token(threadContext)).thenReturn(token);
} else {
when(secondRealm.token(threadContext)).thenReturn(token);
}
service = spy(service);
doReturn(token).when(service).token(any(AuditableRequest.class));
when(cryptoService.sign(InternalAuthenticationService.encodeUser(user, null))).thenReturn("_encoded_user");
User result = service.authenticate("_action", message, null);
Authentication result = service.authenticate("_action", message, null);
assertThat(result, notNullValue());
assertThat(result, is(user));
verify(auditTrail).authenticationFailed("file", token, "_action", message);
User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user1, notNullValue());
assertThat(user1, sameInstance(user));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_encoded_user"));
assertThat(result.getUser(), is(user));
assertThat(result.getLookedUpBy(), is(nullValue()));
assertThat(result.getAuthenticatedBy(), is(notNullValue())); // TODO implement equals
verify(auditTrail).authenticationFailed(firstRealm.name(), token, "_action", message);
verify(cryptoService).sign(any(String.class));
assertThreadContextContainsAuthentication(result);
}
public void testAuthenticateFirstNotSupportingSecondSucceeds() throws Exception {
@ -168,36 +171,28 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
when(firstRealm.supports(token)).thenReturn(false);
when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(user);
when(secondRealm.token(threadContext)).thenReturn(token);
service = spy(service);
doReturn(token).when(service).token(any(AuditableRequest.class));
when(cryptoService.sign(InternalAuthenticationService.encodeUser(user, null))).thenReturn("_encoded_user");
User result = service.authenticate("_action", message, null);
Authentication result = service.authenticate("_action", message, null);
assertThat(result, notNullValue());
assertThat(result, is(user));
assertThat(result.getUser(), is(user));
verifyZeroInteractions(auditTrail);
verify(firstRealm, never()).authenticate(token);
User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user1, notNullValue());
assertThat(user1, is((Object) user));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_encoded_user"));
assertThreadContextContainsAuthentication(result);
}
public void testAuthenticateCached() throws Exception {
User user = new User("_username", "r1");
threadContext.putTransient(InternalAuthenticationService.USER_KEY, user);
User result = service.authenticate("_action", message, null);
final Authentication authentication = new Authentication(new User("_username", "r1"), new RealmRef("test", "cached", "foo"), null);
authentication.writeToContext(threadContext, cryptoService, true);
Authentication result = service.authenticate("_action", message, null);
assertThat(result, notNullValue());
assertThat(result, is(user));
assertThat(result, is(authentication));
verifyZeroInteractions(auditTrail);
verifyZeroInteractions(firstRealm);
verifyZeroInteractions(secondRealm);
verifyZeroInteractions(cryptoService);
User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user1, notNullValue());
assertThat(user1, is(user));
verify(cryptoService).sign(any(String.class));
}
public void testAuthenticateNonExistentRestRequestUserThrowsAuthenticationException() throws Exception {
@ -214,36 +209,30 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testTokenRestMissing() throws Exception {
when(firstRealm.token(threadContext)).thenReturn(null);
when(secondRealm.token(threadContext)).thenReturn(null);
AuthenticationToken token = service.token(service.newRequest(restRequest));
Authenticator authenticator = service.createAuthenticator(restRequest);
AuthenticationToken token = authenticator.extractToken();
assertThat(token, nullValue());
}
public void testEncodeDecodeUser() throws Exception {
User user = new User("username", "r1", "r2", "r3");
String text = InternalAuthenticationService.encodeUser(user, null);
User user2 = InternalAuthenticationService.decodeUser(text);
assertThat(user, equalTo(user2));
text = InternalAuthenticationService.encodeUser(SystemUser.INSTANCE, null);
user2 = InternalAuthenticationService.decodeUser(text);
assertThat(SystemUser.INSTANCE, sameInstance(user2));
}
public void testUserHeader() throws Exception {
public void authenticationInContextAndHeader() throws Exception {
User user = new User("_username", "r1");
when(firstRealm.token(threadContext)).thenReturn(token);
when(firstRealm.supports(token)).thenReturn(true);
when(firstRealm.authenticate(token)).thenReturn(user);
when(cryptoService.sign(InternalAuthenticationService.encodeUser(user, null))).thenReturn("_signed_user");
service = spy(service);
AuditableRequest request = service.newRequest("_action", message);
doReturn(token).when(service).token(request);
User result = service.authenticate("_action", message, null);
Authentication result = service.authenticate("_action", message, null);
assertThat(result, notNullValue());
assertThat(result, is(user));
String userStr = threadContext.getHeader(InternalAuthenticationService.USER_KEY);
assertThat(result.getUser(), is(user));
String userStr = threadContext.getHeader(Authentication.AUTHENTICATION_KEY);
assertThat(userStr, notNullValue());
assertThat(userStr, equalTo("_signed_user"));
assertThat(userStr, equalTo("_signed_auth"));
Authentication ctxAuth = threadContext.getTransient(Authentication.AUTHENTICATION_KEY);
assertThat(ctxAuth, is(result));
}
public void testAuthenticateTransportAnonymous() throws Exception {
@ -276,38 +265,24 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
when(firstRealm.token(threadContext)).thenReturn(null);
when(secondRealm.token(threadContext)).thenReturn(null);
User user1 = new User("username", "r1", "r2");
when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user");
User user2 = service.authenticate("_action", message, user1);
assertThat(user1, sameInstance(user2));
User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user3, sameInstance(user2));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user"));
Authentication result = service.authenticate("_action", message, user1);
assertThat(result, notNullValue());
assertThat(result.getUser(), sameInstance(user1));
assertThreadContextContainsAuthentication(result);
}
public void testAuthenticateTransportSuccessNoFallback() throws Exception {
User user1 = new User("username", "r1", "r2");
public void testAuthenticateTransportSuccess() throws Exception {
User user = new User("username", "r1", "r2");
User fallback = randomBoolean() ? SystemUser.INSTANCE : null;
when(firstRealm.token(threadContext)).thenReturn(token);
when(firstRealm.supports(token)).thenReturn(true);
when(firstRealm.authenticate(token)).thenReturn(user1);
when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user");
User user2 = service.authenticate("_action", message, null);
assertThat(user1, sameInstance(user2));
User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user3, sameInstance(user2));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo("_signed_user"));
}
when(firstRealm.authenticate(token)).thenReturn(user);
public void testAuthenticateTransportSuccessWithFallback() throws Exception {
User user1 = new User("username", "r1", "r2");
when(firstRealm.token(threadContext)).thenReturn(token);
when(firstRealm.supports(token)).thenReturn(true);
when(firstRealm.authenticate(token)).thenReturn(user1);
when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user");
User user2 = service.authenticate("_action", message, SystemUser.INSTANCE);
assertThat(user1, sameInstance(user2));
User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user3, sameInstance((Object) user2));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user"));
Authentication result = service.authenticate("_action", message, fallback);
assertThat(result, notNullValue());
assertThat(result.getUser(), sameInstance(user));
assertThreadContextContainsAuthentication(result);
}
public void testAuthenticateRestSuccess() throws Exception {
@ -315,10 +290,10 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
when(firstRealm.token(threadContext)).thenReturn(token);
when(firstRealm.supports(token)).thenReturn(true);
when(firstRealm.authenticate(token)).thenReturn(user1);
User user2 = service.authenticate(restRequest);
assertThat(user1, sameInstance(user2));
User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user3, sameInstance(user2));
Authentication result = service.authenticate(restRequest);
assertThat(result, notNullValue());
assertThat(result.getUser(), sameInstance(user1));
assertThreadContextContainsAuthentication(result);
}
public void testAutheticateTransportContextAndHeader() throws Exception {
@ -326,12 +301,10 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
when(firstRealm.token(threadContext)).thenReturn(token);
when(firstRealm.supports(token)).thenReturn(true);
when(firstRealm.authenticate(token)).thenReturn(user1);
when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user");
User user2 = service.authenticate("_action", message, SystemUser.INSTANCE);
assertThat(user1, sameInstance(user2));
User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user3, sameInstance(user2));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user"));
Authentication authentication = service.authenticate("_action", message, SystemUser.INSTANCE);
assertThat(authentication, notNullValue());
assertThat(authentication.getUser(), sameInstance(user1));
assertThreadContextContainsAuthentication(authentication);
reset(firstRealm);
// checking authentication from the context
@ -341,10 +314,10 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool, controller);
threadContext1.putTransient(InternalAuthenticationService.USER_KEY,
threadContext.getTransient(InternalAuthenticationService.USER_KEY));
User user = service.authenticate("_action", message1, SystemUser.INSTANCE);
assertThat(user, sameInstance(user1));
threadContext1.putTransient(Authentication.AUTHENTICATION_KEY, threadContext.getTransient(Authentication.AUTHENTICATION_KEY));
threadContext1.putHeader(Authentication.AUTHENTICATION_KEY, threadContext.getHeader(Authentication.AUTHENTICATION_KEY));
Authentication ctxAuth = service.authenticate("_action", message1, SystemUser.INSTANCE);
assertThat(ctxAuth, sameInstance(authentication));
verifyZeroInteractions(firstRealm);
reset(firstRealm);
@ -354,8 +327,8 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
when(threadPool.getThreadContext()).thenReturn(threadContext1);
service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool, controller);
threadContext1.putHeader(InternalAuthenticationService.USER_KEY, threadContext.getHeader(InternalAuthenticationService.USER_KEY));
when(cryptoService.unsignAndVerify("_signed_user")).thenReturn(InternalAuthenticationService.encodeUser(user1, null));
threadContext1.putHeader(Authentication.AUTHENTICATION_KEY, threadContext.getHeader(Authentication.AUTHENTICATION_KEY));
when(cryptoService.unsignAndVerify("_signed_auth")).thenReturn(authentication.encode());
BytesStreamOutput output = new BytesStreamOutput();
threadContext1.writeTo(output);
@ -366,12 +339,13 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
when(threadPool.getThreadContext()).thenReturn(threadContext1);
service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool, controller);
user = service.authenticate("_action", new InternalMessage(), SystemUser.INSTANCE);
assertThat(user, equalTo(user1));
Authentication result = service.authenticate("_action", new InternalMessage(), SystemUser.INSTANCE);
assertThat(result, notNullValue());
assertThat(result.getUser(), equalTo(user1));
verifyZeroInteractions(firstRealm);
}
public void testAutheticateTransportContextAndHeaderNoSigning() throws Exception {
public void testAuthenticateTransportContextAndHeaderNoSigning() throws Exception {
Settings settings = Settings.builder().put(InternalAuthenticationService.SIGN_USER_HEADER.getKey(), false).build();
service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool, controller);
@ -380,12 +354,10 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
when(firstRealm.supports(token)).thenReturn(true);
when(firstRealm.token(threadContext)).thenReturn(token);
when(firstRealm.authenticate(token)).thenReturn(user1);
User user2 = service.authenticate("_action", message, SystemUser.INSTANCE);
assertThat(user1, sameInstance(user2));
User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user3, sameInstance(user2));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY),
equalTo((Object) InternalAuthenticationService.encodeUser(user1, null)));
Authentication authentication = service.authenticate("_action", message, SystemUser.INSTANCE);
assertThat(authentication, notNullValue());
assertThat(authentication.getUser(), sameInstance(user1));
assertThreadContextContainsAuthentication(authentication, false);
reset(firstRealm);
// checking authentication from the context
@ -394,17 +366,16 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
when(threadPool.getThreadContext()).thenReturn(threadContext1);
service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool, controller);
threadContext1.putTransient(InternalAuthenticationService.USER_KEY,
threadContext.getTransient(InternalAuthenticationService.USER_KEY));
User user = service.authenticate("_action", message1, SystemUser.INSTANCE);
assertThat(user, sameInstance(user1));
threadContext1.putTransient(Authentication.AUTHENTICATION_KEY, threadContext.getTransient(Authentication.AUTHENTICATION_KEY));
threadContext1.putHeader(Authentication.AUTHENTICATION_KEY, threadContext.getHeader(Authentication.AUTHENTICATION_KEY));
Authentication ctxAuth = service.authenticate("_action", message1, SystemUser.INSTANCE);
assertThat(ctxAuth, sameInstance(authentication));
verifyZeroInteractions(firstRealm);
reset(firstRealm);
// checking authentication from the user header
threadContext1 = new ThreadContext(Settings.EMPTY);
threadContext1.putHeader(InternalAuthenticationService.USER_KEY, threadContext.getHeader(InternalAuthenticationService.USER_KEY));
threadContext1.putHeader(Authentication.AUTHENTICATION_KEY, threadContext.getHeader(Authentication.AUTHENTICATION_KEY));
BytesStreamOutput output = new BytesStreamOutput();
threadContext1.writeTo(output);
@ -415,8 +386,9 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
when(threadPool.getThreadContext()).thenReturn(threadContext1);
service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool, controller);
user = service.authenticate("_action", new InternalMessage(), SystemUser.INSTANCE);
assertThat(user, equalTo(user1));
Authentication result = service.authenticate("_action", new InternalMessage(), SystemUser.INSTANCE);
assertThat(result, notNullValue());
assertThat(result.getUser(), equalTo(user1));
verifyZeroInteractions(firstRealm);
verifyZeroInteractions(cryptoService);
@ -424,8 +396,8 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testAuthenticateTamperedUser() throws Exception {
InternalMessage message = new InternalMessage();
threadContext.putHeader(InternalAuthenticationService.USER_KEY, "_signed_user");
when(cryptoService.unsignAndVerify("_signed_user")).thenThrow(
threadContext.putHeader(Authentication.AUTHENTICATION_KEY, "_signed_auth");
when(cryptoService.unsignAndVerify("_signed_auth")).thenThrow(
randomFrom(new RuntimeException(), new IllegalArgumentException(), new IllegalStateException()));
try {
@ -444,23 +416,26 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
} else {
user = new User("username", "r1", "r2");
}
assertThat(threadContext.getTransient(InternalAuthenticationService.USER_KEY), nullValue());
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), nullValue());
when(cryptoService.sign(InternalAuthenticationService.encodeUser(user, null))).thenReturn("_signed_user");
service.attachUserHeaderIfMissing(user);
User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user1, sameInstance((Object) user));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user"));
assertThat(threadContext.getTransient(Authentication.AUTHENTICATION_KEY), nullValue());
assertThat(threadContext.getHeader(Authentication.AUTHENTICATION_KEY), nullValue());
service.attachUserIfMissing(user);
Authentication authentication = threadContext.getTransient(Authentication.AUTHENTICATION_KEY);
assertThat(authentication, notNullValue());
assertThat(authentication.getUser(), sameInstance((Object) user));
assertThat(authentication.getLookedUpBy(), nullValue());
assertThat(authentication.getAuthenticatedBy().getName(), is("__attach"));
assertThat(authentication.getAuthenticatedBy().getType(), is("__attach"));
assertThat(authentication.getAuthenticatedBy().getNodeName(), is("authc_test"));
assertThat(threadContext.getHeader(Authentication.AUTHENTICATION_KEY), equalTo((Object) "_signed_auth"));
}
public void testAttachIfMissingExists() throws Exception {
User user = new User("username", "r1", "r2");
threadContext.putTransient(InternalAuthenticationService.USER_KEY, user);
threadContext.putHeader(InternalAuthenticationService.USER_KEY, "_signed_user");
service.attachUserHeaderIfMissing(new User("username2", "r3", "r4"));
User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user1, sameInstance(user));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo("_signed_user"));
Authentication authentication = new Authentication(new User("username", "r1", "r2"), new RealmRef("test", "test", "foo"), null);
threadContext.putTransient(Authentication.AUTHENTICATION_KEY, authentication);
threadContext.putHeader(Authentication.AUTHENTICATION_KEY, "_signed_auth");
service.attachUserIfMissing(new User("username2", "r3", "r4"));
assertThreadContextContainsAuthentication(authentication);
}
public void testAnonymousUserRest() throws Exception {
@ -474,16 +449,13 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
AnonymousUser.initialize(settings);
service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService, new DefaultAuthenticationFailureHandler(),
threadPool, controller);
RestRequest request = new FakeRestRequest();
User user = service.authenticate(request);
User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user1, notNullValue());
assertThat(user1, sameInstance((Object) user));
assertThat(user, notNullValue());
assertThat(user.principal(), equalTo(username));
assertThat(user.roles(), arrayContainingInAnyOrder("r1", "r2", "r3"));
Authentication result = service.authenticate(request);
assertThat(result, notNullValue());
assertThat(result.getUser(), sameInstance((Object) AnonymousUser.INSTANCE));
assertThreadContextContainsAuthentication(result);
}
public void testAnonymousUserTransportNoDefaultUser() throws Exception {
@ -493,13 +465,12 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
AnonymousUser.initialize(settings);
service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool, controller);
InternalMessage message = new InternalMessage();
User user = service.authenticate("_action", message, null);
assertThat(user, notNullValue());
assertThat(user.principal(), equalTo(AnonymousUser.DEFAULT_ANONYMOUS_USERNAME));
assertThat(user.roles(), arrayContainingInAnyOrder("r1", "r2", "r3"));
Authentication result = service.authenticate("_action", message, null);
assertThat(result, notNullValue());
assertThat(result.getUser(), sameInstance(AnonymousUser.INSTANCE));
assertThreadContextContainsAuthentication(result);
}
public void testAnonymousUserTransportWithDefaultUser() throws Exception {
@ -512,9 +483,10 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
InternalMessage message = new InternalMessage();
User user = service.authenticate("_action", message, SystemUser.INSTANCE);
assertThat(user, notNullValue());
assertThat(user, sameInstance(SystemUser.INSTANCE));
Authentication result = service.authenticate("_action", message, SystemUser.INSTANCE);
assertThat(result, notNullValue());
assertThat(result.getUser(), sameInstance(SystemUser.INSTANCE));
assertThreadContextContainsAuthentication(result);
}
public void testRealmTokenThrowingException() throws Exception {
@ -638,7 +610,14 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
when(secondRealm.lookupUser("run_as")).thenReturn(new User("looked up user", new String[]{"some role"}));
when(secondRealm.userLookupSupported()).thenReturn(true);
User authenticated = service.authenticate("_action", message, null);
Authentication result;
if (randomBoolean()) {
result = service.authenticate("_action", message, null);
} else {
result = service.authenticate(restRequest);
}
assertThat(result, notNullValue());
User authenticated = result.getUser();
assertThat(SystemUser.is(authenticated), is(false));
assertThat(authenticated.runAs(), is(notNullValue()));
@ -646,29 +625,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
assertThat(authenticated.roles(), arrayContaining("user"));
assertThat(authenticated.runAs().principal(), is("looked up user"));
assertThat(authenticated.runAs().roles(), arrayContaining("some role"));
User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user1, sameInstance(authenticated));
}
public void testRunAsLookupSameRealmRest() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class);
threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as");
when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"}));
when(secondRealm.lookupUser("run_as")).thenReturn(new User("looked up user", new String[]{"some role"}));
when(secondRealm.userLookupSupported()).thenReturn(true);
User authenticated = service.authenticate(restRequest);
assertThat(SystemUser.is(authenticated), is(false));
assertThat(authenticated.runAs(), is(notNullValue()));
assertThat(authenticated.principal(), is("lookup user"));
assertThat(authenticated.roles(), arrayContaining("user"));
assertThat(authenticated.runAs().principal(), is("looked up user"));
assertThat(authenticated.runAs().roles(), arrayContaining("some role"));
User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user1, sameInstance(authenticated));
assertThreadContextContainsAuthentication(result);
}
public void testRunAsLookupDifferentRealm() throws Exception {
@ -681,7 +638,14 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
when(firstRealm.lookupUser("run_as")).thenReturn(new User("looked up user", new String[]{"some role"}));
when(firstRealm.userLookupSupported()).thenReturn(true);
User authenticated = service.authenticate("_action", message, null);
Authentication result;
if (randomBoolean()) {
result = service.authenticate("_action", message, null);
} else {
result = service.authenticate(restRequest);
}
assertThat(result, notNullValue());
User authenticated = result.getUser();
assertThat(SystemUser.is(authenticated), is(false));
assertThat(authenticated.runAs(), is(notNullValue()));
@ -689,74 +653,60 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
assertThat(authenticated.roles(), arrayContaining("user"));
assertThat(authenticated.runAs().principal(), is("looked up user"));
assertThat(authenticated.runAs().roles(), arrayContaining("some role"));
User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user1, sameInstance(authenticated));
}
public void testRunAsLookupDifferentRealmRest() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class);
threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as");
when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"}));
when(firstRealm.lookupUser("run_as")).thenReturn(new User("looked up user", new String[]{"some role"}));
when(firstRealm.userLookupSupported()).thenReturn(true);
User authenticated = service.authenticate(restRequest);
assertThat(SystemUser.is(authenticated), is(false));
assertThat(authenticated.runAs(), is(notNullValue()));
assertThat(authenticated.principal(), is("lookup user"));
assertThat(authenticated.roles(), arrayContaining("user"));
assertThat(authenticated.runAs().principal(), is("looked up user"));
assertThat(authenticated.runAs().roles(), arrayContaining("some role"));
User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(user1, sameInstance(authenticated));
assertThreadContextContainsAuthentication(result);
}
public void testRunAsWithEmptyRunAsUsernameRest() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class);
User user = new User("lookup user", new String[]{"user"});
threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "");
when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"}));
when(secondRealm.authenticate(token)).thenReturn(user);
when(secondRealm.userLookupSupported()).thenReturn(true);
try {
service.authenticate(restRequest);
fail("exception should be thrown");
} catch (ElasticsearchException e) {
verify(auditTrail).authenticationFailed(token, restRequest);
verify(auditTrail).runAsDenied(any(User.class), eq(restRequest));
verifyNoMoreInteractions(auditTrail);
}
}
public void testRunAsWithEmptyRunAsUsername() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class);
User user = new User("lookup user", new String[]{"user"});
threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "");
when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"}));
when(secondRealm.authenticate(token)).thenReturn(user);
when(secondRealm.userLookupSupported()).thenReturn(true);
try {
service.authenticate("_action", message, null);
fail("exception should be thrown");
} catch (ElasticsearchException e) {
verify(auditTrail).authenticationFailed(token, "_action", message);
verify(auditTrail).runAsDenied(any(User.class), eq("_action"), eq(message));
verifyNoMoreInteractions(auditTrail);
}
}
public void testVersionWrittenWithUser() throws Exception {
User user = new User("username", "r1", "r2", "r3");
String text = InternalAuthenticationService.encodeUser(user, null);
StreamInput input = StreamInput.wrap(Base64.getDecoder().decode(text));
Version version = Version.readVersion(input);
assertThat(version, is(Version.CURRENT));
}
private static class InternalMessage extends TransportMessage {
}
void assertThreadContextContainsAuthentication(Authentication authentication) throws IOException {
assertThreadContextContainsAuthentication(authentication, true);
}
void assertThreadContextContainsAuthentication(Authentication authentication, boolean sign) throws IOException {
Authentication contextAuth = threadContext.getTransient(Authentication.AUTHENTICATION_KEY);
assertThat(contextAuth, notNullValue());
assertThat(contextAuth, is(authentication));
if (sign) {
assertThat(threadContext.getHeader(Authentication.AUTHENTICATION_KEY), equalTo((Object) "_signed_auth"));
} else {
assertThat(threadContext.getHeader(Authentication.AUTHENTICATION_KEY), equalTo((Object) authentication.encode()));
}
}
}

View File

@ -56,6 +56,8 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.search.action.SearchTransportService;
import org.elasticsearch.shield.ShieldTemplateService;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.authc.Authentication.RealmRef;
import org.elasticsearch.shield.user.AnonymousUser;
import org.elasticsearch.shield.user.SystemUser;
import org.elasticsearch.shield.user.User;
@ -123,10 +125,10 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
TransportRequest request = mock(TransportRequest.class);
// A failure would throw an exception
internalAuthorizationService.authorize(SystemUser.INSTANCE, "indices:monitor/whatever", request);
internalAuthorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "indices:monitor/whatever", request);
verify(auditTrail).accessGranted(SystemUser.INSTANCE, "indices:monitor/whatever", request);
internalAuthorizationService.authorize(SystemUser.INSTANCE, "internal:whatever", request);
internalAuthorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "internal:whatever", request);
verify(auditTrail).accessGranted(SystemUser.INSTANCE, "internal:whatever", request);
verifyNoMoreInteractions(auditTrail);
}
@ -134,7 +136,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
public void testIndicesActionsAreNotAuthorized() {
TransportRequest request = mock(TransportRequest.class);
try {
internalAuthorizationService.authorize(SystemUser.INSTANCE, "indices:", request);
internalAuthorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "indices:", request);
fail("action beginning with indices should have failed");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e,
@ -147,7 +149,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
public void testClusterAdminActionsAreNotAuthorized() {
TransportRequest request = mock(TransportRequest.class);
try {
internalAuthorizationService.authorize(SystemUser.INSTANCE, "cluster:admin/whatever", request);
internalAuthorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "cluster:admin/whatever", request);
fail("action beginning with cluster:admin/whatever should have failed");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e,
@ -160,7 +162,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
public void testClusterAdminSnapshotStatusActionIsNotAuthorized() {
TransportRequest request = mock(TransportRequest.class);
try {
internalAuthorizationService.authorize(SystemUser.INSTANCE, "cluster:admin/snapshot/status", request);
internalAuthorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "cluster:admin/snapshot/status", request);
fail("action beginning with cluster:admin/snapshot/status should have failed");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [cluster:admin/snapshot/status] is unauthorized for user [" +
@ -174,7 +176,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
TransportRequest request = new SearchRequest();
User user = new User("test user");
try {
internalAuthorizationService.authorize(user, "indices:a", request);
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("user without roles should be denied");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user]"));
@ -187,7 +189,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
TransportRequest request = new SearchRequest();
User user = new User("test user", "non-existent-role");
try {
internalAuthorizationService.authorize(user, "indices:a", request);
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("user with unknown role only should have been denied");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user]"));
@ -202,7 +204,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(rolesStore.role("a_all")).thenReturn(Role.builder("a_role").add(IndexPrivilege.ALL, "a").build());
try {
internalAuthorizationService.authorize(user, "whatever", request);
internalAuthorizationService.authorize(createAuthentication(user), "whatever", request);
fail("non indices and non cluster requests should be denied");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [whatever] is unauthorized for user [test user]"));
@ -217,7 +219,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(rolesStore.role("no_indices")).thenReturn(Role.builder("no_indices").cluster(ClusterPrivilege.action("")).build());
try {
internalAuthorizationService.authorize(user, "indices:a", request);
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("user only has cluster roles so indices requests should fail");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user]"));
@ -231,28 +233,29 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(rolesStore.role("a_all")).thenReturn(Role.builder("a_role").add(IndexPrivilege.ALL, "a").build());
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
internalAuthorizationService.authorize(user, ClearScrollAction.NAME, clearScrollRequest);
internalAuthorizationService.authorize(createAuthentication(user), ClearScrollAction.NAME, clearScrollRequest);
verify(auditTrail).accessGranted(user, ClearScrollAction.NAME, clearScrollRequest);
SearchScrollRequest searchScrollRequest = new SearchScrollRequest();
internalAuthorizationService.authorize(user, SearchScrollAction.NAME, searchScrollRequest);
internalAuthorizationService.authorize(createAuthentication(user), SearchScrollAction.NAME, searchScrollRequest);
verify(auditTrail).accessGranted(user, SearchScrollAction.NAME, searchScrollRequest);
// We have to use a mock request for other Scroll actions as the actual requests are package private to SearchTransportService
TransportRequest request = mock(TransportRequest.class);
internalAuthorizationService.authorize(user, SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME, request);
internalAuthorizationService
.authorize(createAuthentication(user), SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME, request);
internalAuthorizationService.authorize(user, SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME, request);
internalAuthorizationService.authorize(createAuthentication(user), SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME, request);
internalAuthorizationService.authorize(user, SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME, request);
internalAuthorizationService.authorize(createAuthentication(user), SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME, request);
internalAuthorizationService.authorize(user, SearchTransportService.QUERY_SCROLL_ACTION_NAME, request);
internalAuthorizationService.authorize(createAuthentication(user), SearchTransportService.QUERY_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.QUERY_SCROLL_ACTION_NAME, request);
internalAuthorizationService.authorize(user, SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME, request);
internalAuthorizationService.authorize(createAuthentication(user), SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME, request);
verifyNoMoreInteractions(auditTrail);
}
@ -266,7 +269,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(state.metaData()).thenReturn(MetaData.EMPTY_META_DATA);
try {
internalAuthorizationService.authorize(user, "indices:a", request);
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("indices request for b should be denied since there is no such index");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user]"));
@ -287,7 +290,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(state.metaData()).thenReturn(MetaData.EMPTY_META_DATA);
try {
internalAuthorizationService.authorize(user, CreateIndexAction.NAME, request);
internalAuthorizationService.authorize(createAuthentication(user), CreateIndexAction.NAME, request);
fail("indices creation request with alias should be denied since user does not have permission to alias");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e,
@ -308,7 +311,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(MetaData.EMPTY_META_DATA);
internalAuthorizationService.authorize(user, CreateIndexAction.NAME, request);
internalAuthorizationService.authorize(createAuthentication(user), CreateIndexAction.NAME, request);
verify(auditTrail).accessGranted(user, CreateIndexAction.NAME, request);
verifyNoMoreInteractions(auditTrail);
@ -364,7 +367,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(state.metaData()).thenReturn(MetaData.EMPTY_META_DATA);
try {
internalAuthorizationService.authorize(AnonymousUser.INSTANCE, "indices:a", request);
internalAuthorizationService.authorize(createAuthentication(AnonymousUser.INSTANCE), "indices:a", request);
fail("indices request for b should be denied since there is no such index");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e,
@ -395,7 +398,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(state.metaData()).thenReturn(MetaData.EMPTY_META_DATA);
try {
internalAuthorizationService.authorize(anonymousUser, "indices:a", request);
internalAuthorizationService.authorize(createAuthentication(anonymousUser), "indices:a", request);
fail("indices request for b should be denied since there is no such index");
} catch (ElasticsearchSecurityException e) {
assertAuthenticationException(e, containsString("action [indices:a] requires authentication"));
@ -411,7 +414,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
User user = new User("test user", null, new User("run as me", new String[] { "admin" }));
assertThat(user.runAs(), is(notNullValue()));
try {
internalAuthorizationService.authorize(user, "indices:a", request);
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("user without roles should be denied for run as");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user] run as [run as me]"));
@ -431,7 +434,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
.build());
try {
internalAuthorizationService.authorize(user, "indices:a", request);
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("user without roles should be denied for run as");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user] run as [run as me]"));
@ -465,7 +468,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
}
try {
internalAuthorizationService.authorize(user, "indices:a", request);
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("the run as user's role doesn't exist so they should not get authorized");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user] run as [run as me]"));
@ -496,7 +499,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
.add(IndexPrivilege.ALL, "b")
.build());
internalAuthorizationService.authorize(user, "indices:a", request);
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
verify(auditTrail).runAsGranted(user, "indices:a", request);
verify(auditTrail).accessGranted(user, "indices:a", request);
verifyNoMoreInteractions(auditTrail);
@ -533,7 +536,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
String action = requestTuple.v1();
TransportRequest request = requestTuple.v2();
try {
internalAuthorizationService.authorize(user, action, request);
internalAuthorizationService.authorize(createAuthentication(user), action, request);
fail("only the xpack user can execute operation [" + action + "] against the internal index");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [" + action + "] is unauthorized for user [all_access_user]"));
@ -544,12 +547,12 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
// we should allow waiting for the health of the index or any index if the user has this permission
ClusterHealthRequest request = new ClusterHealthRequest(ShieldTemplateService.SECURITY_INDEX_NAME);
internalAuthorizationService.authorize(user, ClusterHealthAction.NAME, request);
internalAuthorizationService.authorize(createAuthentication(user), ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request);
// multiple indices
request = new ClusterHealthRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "foo", "bar");
internalAuthorizationService.authorize(user, ClusterHealthAction.NAME, request);
internalAuthorizationService.authorize(createAuthentication(user), ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request);
}
@ -580,7 +583,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
for (Tuple<String, ? extends TransportRequest> requestTuple : requests) {
String action = requestTuple.v1();
TransportRequest request = requestTuple.v2();
internalAuthorizationService.authorize(user, action, request);
internalAuthorizationService.authorize(createAuthentication(user), action, request);
verify(auditTrail).accessGranted(user, action, request);
}
}
@ -612,8 +615,13 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
for (Tuple<String, TransportRequest> requestTuple : requests) {
String action = requestTuple.v1();
TransportRequest request = requestTuple.v2();
internalAuthorizationService.authorize(XPackUser.INSTANCE, action, request);
internalAuthorizationService.authorize(createAuthentication(XPackUser.INSTANCE), action, request);
verify(auditTrail).accessGranted(XPackUser.INSTANCE, action, request);
}
}
private Authentication createAuthentication(User user) {
RealmRef lookedUpBy = user.runAs() == null ? null : new RealmRef("looked", "up", "by");
return new Authentication(user, new RealmRef("test", "test", "foo"), lookedUpBy);
}
}

View File

@ -19,7 +19,9 @@ import org.elasticsearch.shield.authz.privilege.IndexPrivilege;
import org.elasticsearch.test.ESTestCase;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
@ -72,6 +74,16 @@ public class IndicesPermissionTests extends ESTestCase {
assertThat(permissions.getIndexPermissions("_index").getFields().iterator().next(), equalTo("_field"));
assertThat(permissions.getIndexPermissions("_index").getQueries().size(), equalTo(1));
assertThat(permissions.getIndexPermissions("_index").getQueries().iterator().next(), equalTo(query));
// match all fields
List<String> allFields = randomFrom(Collections.singletonList("*"), Arrays.asList("foo", "*"),
Arrays.asList(randomAsciiOfLengthBetween(1, 10), "*"));
role = Role.builder("_role").add(allFields, query, IndexPrivilege.ALL, "_alias").build();
permissions = role.authorize(SearchAction.NAME, Sets.newHashSet("_alias"), md);
assertThat(permissions.getIndexPermissions("_index"), notNullValue());
assertThat(permissions.getIndexPermissions("_index").getFields(), nullValue());
assertThat(permissions.getIndexPermissions("_index").getQueries().size(), equalTo(1));
assertThat(permissions.getIndexPermissions("_index").getQueries().iterator().next(), equalTo(query));
}
}

View File

@ -36,6 +36,7 @@ import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.SparseFixedBitSet;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
@ -93,7 +94,7 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase {
Collections.emptyMap(), Collections.emptyMap());
SimilarityService similarityService = new SimilarityService(indexSettings, Collections.emptyMap());
mapperService = new MapperService(indexSettings, analysisService, similarityService,
new IndicesModule().getMapperRegistry(), () -> null);
new IndicesModule(new NamedWriteableRegistry()).getMapperRegistry(), () -> null);
ShardId shardId = new ShardId(index, 0);
licenseState = mock(SecurityLicenseState.class);

View File

@ -12,6 +12,14 @@ import org.elasticsearch.client.Client;
import org.elasticsearch.license.plugin.action.get.GetLicenseAction;
import org.elasticsearch.shield.action.user.AuthenticateRequestBuilder;
import org.elasticsearch.shield.action.user.ChangePasswordRequestBuilder;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.authc.Authentication.RealmRef;
import org.elasticsearch.shield.authc.activedirectory.ActiveDirectoryRealm;
import org.elasticsearch.shield.authc.esnative.NativeRealm;
import org.elasticsearch.shield.authc.esnative.ReservedRealm;
import org.elasticsearch.shield.authc.file.FileRealm;
import org.elasticsearch.shield.authc.ldap.LdapRealm;
import org.elasticsearch.shield.authc.pki.PkiRealm;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.shield.action.user.AuthenticateAction;
import org.elasticsearch.shield.action.user.AuthenticateRequest;
@ -28,7 +36,11 @@ import java.util.Iterator;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
/**
* Unit tests for the {@link DefaultRole}
@ -51,9 +63,16 @@ public class DefaultRoleTests extends ESTestCase {
new ChangePasswordRequestBuilder(mock(Client.class)).username(user.principal()).request() :
new AuthenticateRequestBuilder(mock(Client.class)).username(user.principal()).request();
final String action = changePasswordRequest ? ChangePasswordAction.NAME : AuthenticateAction.NAME;
assertThat(request, instanceOf(UserRequest.class));
final Authentication authentication = mock(Authentication.class);
final RealmRef authenticatedBy = mock(RealmRef.class);
when(authentication.getUser()).thenReturn(user);
when(authentication.getRunAsUser()).thenReturn(user);
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
when(authenticatedBy.getType())
.thenReturn(changePasswordRequest ? randomFrom(ReservedRealm.TYPE, NativeRealm.TYPE) : randomAsciiOfLengthBetween(4, 12));
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, user), is(true));
assertThat(request, instanceOf(UserRequest.class));
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, authentication), is(true));
}
public void testDefaultRoleDoesNotAllowNonMatchingUsername() {
@ -64,19 +83,33 @@ public class DefaultRoleTests extends ESTestCase {
new ChangePasswordRequestBuilder(mock(Client.class)).username(username).request() :
new AuthenticateRequestBuilder(mock(Client.class)).username(username).request();
final String action = changePasswordRequest ? ChangePasswordAction.NAME : AuthenticateAction.NAME;
assertThat(request, instanceOf(UserRequest.class));
final Authentication authentication = mock(Authentication.class);
final RealmRef authenticatedBy = mock(RealmRef.class);
when(authentication.getUser()).thenReturn(user);
when(authentication.getRunAsUser()).thenReturn(user);
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
when(authenticatedBy.getType())
.thenReturn(changePasswordRequest ? randomFrom(ReservedRealm.TYPE, NativeRealm.TYPE) : randomAsciiOfLengthBetween(4, 12));
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, user), is(false));
assertThat(request, instanceOf(UserRequest.class));
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, authentication), is(false));
final User user2 = new User("admin", new String[] { "bar" }, user);
when(authentication.getUser()).thenReturn(user2);
when(authentication.getRunAsUser()).thenReturn(user);
final RealmRef lookedUpBy = mock(RealmRef.class);
when(authentication.getLookedUpBy()).thenReturn(lookedUpBy);
when(lookedUpBy.getType())
.thenReturn(changePasswordRequest ? randomFrom(ReservedRealm.TYPE, NativeRealm.TYPE) : randomAsciiOfLengthBetween(4, 12));
// this should still fail since the username is still different
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, authentication), is(false));
if (request instanceof ChangePasswordRequest) {
((ChangePasswordRequest)request).username("joe");
} else {
((AuthenticateRequest)request).username("joe");
}
// run as should not be checked by this role, it is up to the caller to provide the correct user
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, user2), is(false));
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, user), is(true));
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, authentication), is(true));
}
public void testDefaultRoleDoesNotAllowOtherActions() {
@ -84,8 +117,85 @@ public class DefaultRoleTests extends ESTestCase {
final TransportRequest request = mock(TransportRequest.class);
final String action = randomFrom(PutUserAction.NAME, DeleteUserAction.NAME, ClusterHealthAction.NAME, ClusterStateAction.NAME,
ClusterStatsAction.NAME, GetLicenseAction.NAME);
final Authentication authentication = mock(Authentication.class);
final RealmRef authenticatedBy = mock(RealmRef.class);
when(authentication.getUser()).thenReturn(user);
when(authentication.getRunAsUser()).thenReturn(randomBoolean() ? user : new User("runAs"));
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
when(authenticatedBy.getType())
.thenReturn(randomAsciiOfLengthBetween(4, 12));
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, user), is(false));
verifyZeroInteractions(user, request);
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, authentication), is(false));
verifyZeroInteractions(user, request, authentication);
}
public void testDefaultRoleWithRunAsChecksAuthenticatedBy() {
final String username = "joe";
final User runAs = new User(username);
final User user = new User("admin", new String[] { "bar" }, runAs);
final boolean changePasswordRequest = randomBoolean();
final TransportRequest request = changePasswordRequest ?
new ChangePasswordRequestBuilder(mock(Client.class)).username(username).request() :
new AuthenticateRequestBuilder(mock(Client.class)).username(username).request();
final String action = changePasswordRequest ? ChangePasswordAction.NAME : AuthenticateAction.NAME;
final Authentication authentication = mock(Authentication.class);
final RealmRef authenticatedBy = mock(RealmRef.class);
final RealmRef lookedUpBy = mock(RealmRef.class);
when(authentication.getUser()).thenReturn(user);
when(authentication.getRunAsUser()).thenReturn(runAs);
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
when(authentication.getLookedUpBy()).thenReturn(lookedUpBy);
when(lookedUpBy.getType())
.thenReturn(changePasswordRequest ? randomFrom(ReservedRealm.TYPE, NativeRealm.TYPE) : randomAsciiOfLengthBetween(4, 12));
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, authentication), is(true));
when(authentication.getRunAsUser()).thenReturn(user);
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, authentication), is(false));
}
public void testDefaultRoleDoesNotAllowChangePasswordForOtherRealms() {
final User user = new User("joe");
final ChangePasswordRequest request = new ChangePasswordRequestBuilder(mock(Client.class)).username(user.principal()).request();
final String action = ChangePasswordAction.NAME;
final Authentication authentication = mock(Authentication.class);
final RealmRef authenticatedBy = mock(RealmRef.class);
when(authentication.getUser()).thenReturn(user);
when(authentication.getRunAsUser()).thenReturn(user);
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
when(authenticatedBy.getType()).thenReturn(randomFrom(LdapRealm.TYPE, FileRealm.TYPE, ActiveDirectoryRealm.TYPE, PkiRealm.TYPE,
randomAsciiOfLengthBetween(4, 12)));
assertThat(request, instanceOf(UserRequest.class));
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, authentication), is(false));
verify(authenticatedBy).getType();
verify(authentication, times(2)).getRunAsUser();
verify(authentication).getUser();
verify(authentication).getAuthenticatedBy();
verifyNoMoreInteractions(authenticatedBy, authentication);
}
public void testDefaultRoleDoesNotAllowChangePasswordForLookedUpByOtherRealms() {
final User runAs = new User("joe");
final User user = new User("admin", new String[] { "bar" }, runAs);
final ChangePasswordRequest request = new ChangePasswordRequestBuilder(mock(Client.class)).username(runAs.principal()).request();
final String action = ChangePasswordAction.NAME;
final Authentication authentication = mock(Authentication.class);
final RealmRef authenticatedBy = mock(RealmRef.class);
final RealmRef lookedUpBy = mock(RealmRef.class);
when(authentication.getUser()).thenReturn(user);
when(authentication.getRunAsUser()).thenReturn(runAs);
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
when(authentication.getLookedUpBy()).thenReturn(lookedUpBy);
when(lookedUpBy.getType()).thenReturn(randomFrom(LdapRealm.TYPE, FileRealm.TYPE, ActiveDirectoryRealm.TYPE, PkiRealm.TYPE,
randomAsciiOfLengthBetween(4, 12)));
assertThat(request, instanceOf(UserRequest.class));
assertThat(DefaultRole.INSTANCE.cluster().check(action, request, authentication), is(false));
verify(authentication).getLookedUpBy();
verify(authentication, times(2)).getRunAsUser();
verify(authentication).getUser();
verify(lookedUpBy).getType();
verifyNoMoreInteractions(authentication, lookedUpBy, authenticatedBy);
}
}

View File

@ -17,14 +17,14 @@ import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateActio
import org.elasticsearch.action.delete.DeleteAction;
import org.elasticsearch.action.index.IndexAction;
import org.elasticsearch.marvel.action.MonitoringBulkAction;
import org.elasticsearch.shield.user.KibanaUser;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.transport.TransportRequest;
import java.util.Arrays;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.mock;
/**
* Tests for the kibana role
@ -32,15 +32,15 @@ import static org.hamcrest.Matchers.is;
public class KibanaRoleTests extends ESTestCase {
public void testCluster() {
final User user = KibanaUser.INSTANCE;
final TransportRequest request = new TransportRequest.Empty();
assertThat(KibanaRole.INSTANCE.cluster().check(ClusterHealthAction.NAME, request, user), is(true));
assertThat(KibanaRole.INSTANCE.cluster().check(ClusterStateAction.NAME, request, user), is(true));
assertThat(KibanaRole.INSTANCE.cluster().check(ClusterStatsAction.NAME, request, user), is(true));
assertThat(KibanaRole.INSTANCE.cluster().check(MonitoringBulkAction.NAME, request, user), is(true));
assertThat(KibanaRole.INSTANCE.cluster().check(PutIndexTemplateAction.NAME, request, user), is(false));
assertThat(KibanaRole.INSTANCE.cluster().check(ClusterRerouteAction.NAME, request, user), is(false));
assertThat(KibanaRole.INSTANCE.cluster().check(ClusterUpdateSettingsAction.NAME, request, user), is(false));
final Authentication authentication = mock(Authentication.class);
assertThat(KibanaRole.INSTANCE.cluster().check(ClusterHealthAction.NAME, request, authentication), is(true));
assertThat(KibanaRole.INSTANCE.cluster().check(ClusterStateAction.NAME, request, authentication), is(true));
assertThat(KibanaRole.INSTANCE.cluster().check(ClusterStatsAction.NAME, request, authentication), is(true));
assertThat(KibanaRole.INSTANCE.cluster().check(PutIndexTemplateAction.NAME, request, authentication), is(false));
assertThat(KibanaRole.INSTANCE.cluster().check(ClusterRerouteAction.NAME, request, authentication), is(false));
assertThat(KibanaRole.INSTANCE.cluster().check(ClusterUpdateSettingsAction.NAME, request, authentication), is(false));
assertThat(KibanaRole.INSTANCE.cluster().check(MonitoringBulkAction.NAME, request, authentication), is(true));
}
public void testRunAs() {

View File

@ -19,27 +19,27 @@ import org.elasticsearch.action.index.IndexAction;
import org.elasticsearch.action.search.MultiSearchAction;
import org.elasticsearch.action.search.SearchAction;
import org.elasticsearch.marvel.action.MonitoringBulkAction;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.transport.TransportRequest;
import java.util.Arrays;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.mock;
public class KibanaUserRoleTests extends ESTestCase {
public void testCluster() {
final User user = new User("joe");
final Authentication authentication = mock(Authentication.class);
final TransportRequest request = new TransportRequest.Empty();
assertThat(KibanaUserRole.INSTANCE.cluster().check(ClusterHealthAction.NAME, request, user), is(true));
assertThat(KibanaUserRole.INSTANCE.cluster().check(ClusterStateAction.NAME, request, user), is(true));
assertThat(KibanaUserRole.INSTANCE.cluster().check(ClusterStatsAction.NAME, request, user), is(true));
assertThat(KibanaUserRole.INSTANCE.cluster().check(PutIndexTemplateAction.NAME, request, user), is(false));
assertThat(KibanaUserRole.INSTANCE.cluster().check(ClusterRerouteAction.NAME, request, user), is(false));
assertThat(KibanaUserRole.INSTANCE.cluster().check(ClusterUpdateSettingsAction.NAME, request, user), is(false));
assertThat(KibanaUserRole.INSTANCE.cluster().check(MonitoringBulkAction.NAME, request, user), is(false));
assertThat(KibanaUserRole.INSTANCE.cluster().check(ClusterHealthAction.NAME, request, authentication), is(true));
assertThat(KibanaUserRole.INSTANCE.cluster().check(ClusterStateAction.NAME, request, authentication), is(true));
assertThat(KibanaUserRole.INSTANCE.cluster().check(ClusterStatsAction.NAME, request, authentication), is(true));
assertThat(KibanaUserRole.INSTANCE.cluster().check(PutIndexTemplateAction.NAME, request, authentication), is(false));
assertThat(KibanaUserRole.INSTANCE.cluster().check(ClusterRerouteAction.NAME, request, authentication), is(false));
assertThat(KibanaUserRole.INSTANCE.cluster().check(ClusterUpdateSettingsAction.NAME, request, authentication), is(false));
assertThat(KibanaUserRole.INSTANCE.cluster().check(MonitoringBulkAction.NAME, request, authentication), is(false));
}
public void testRunAs() {

View File

@ -20,6 +20,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.shield.action.role.PutRoleAction;
import org.elasticsearch.shield.action.user.PutUserAction;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.authz.accesscontrol.IndicesAccessControl.IndexAccessControl;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.test.ESTestCase;
@ -28,6 +29,8 @@ import org.elasticsearch.transport.TransportRequest;
import java.util.Map;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Tests for the superuser role
@ -36,14 +39,16 @@ public class SuperuserRoleTests extends ESTestCase {
public void testCluster() {
final User user = new User("joe", SuperuserRole.NAME);
final Authentication authentication = mock(Authentication.class);
when(authentication.getUser()).thenReturn(user);
final TransportRequest request = new TransportRequest.Empty();
assertThat(SuperuserRole.INSTANCE.cluster().check(ClusterHealthAction.NAME, request, user), is(true));
assertThat(SuperuserRole.INSTANCE.cluster().check(ClusterUpdateSettingsAction.NAME, request, user), is(true));
assertThat(SuperuserRole.INSTANCE.cluster().check(PutUserAction.NAME, request, user), is(true));
assertThat(SuperuserRole.INSTANCE.cluster().check(PutRoleAction.NAME, request, user), is(true));
assertThat(SuperuserRole.INSTANCE.cluster().check(PutIndexTemplateAction.NAME, request, user), is(true));
assertThat(SuperuserRole.INSTANCE.cluster().check("internal:admin/foo", request, user), is(false));
assertThat(SuperuserRole.INSTANCE.cluster().check(ClusterHealthAction.NAME, request, authentication), is(true));
assertThat(SuperuserRole.INSTANCE.cluster().check(ClusterUpdateSettingsAction.NAME, request, authentication), is(true));
assertThat(SuperuserRole.INSTANCE.cluster().check(PutUserAction.NAME, request, authentication), is(true));
assertThat(SuperuserRole.INSTANCE.cluster().check(PutRoleAction.NAME, request, authentication), is(true));
assertThat(SuperuserRole.INSTANCE.cluster().check(PutIndexTemplateAction.NAME, request, authentication), is(true));
assertThat(SuperuserRole.INSTANCE.cluster().check("internal:admin/foo", request, authentication), is(false));
}
public void testIndices() {

View File

@ -12,7 +12,7 @@ import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestFilterChain;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.authc.AuthenticationService;
import org.elasticsearch.shield.SecurityLicenseState;
import org.elasticsearch.test.ESTestCase;
@ -52,8 +52,8 @@ public class ShieldRestFilterTests extends ESTestCase {
public void testProcess() throws Exception {
RestRequest request = mock(RestRequest.class);
User user = new User("_user", "r1");
when(authcService.authenticate(request)).thenReturn(user);
Authentication authentication = mock(Authentication.class);
when(authcService.authenticate(request)).thenReturn(authentication);
filter.process(request, channel, chain);
verify(chain).continueProcessing(request, channel);
verifyZeroInteractions(channel);

View File

@ -21,6 +21,6 @@ public class ShieldAssertions {
assertThat(e.status(), is(RestStatus.UNAUTHORIZED));
assertThat(e.getHeaderKeys(), hasSize(1));
assertThat(e.getHeader("WWW-Authenticate"), notNullValue());
assertThat(e.getHeader("WWW-Authenticate"), contains("Basic realm=\"" + Security.NAME + "\""));
assertThat(e.getHeader("WWW-Authenticate"), contains("Basic realm=\"" + Security.NAME + "\" charset=\"UTF-8\""));
}
}

View File

@ -30,6 +30,6 @@ public class ClientTransportFilterTests extends ESTestCase {
public void testOutbound() throws Exception {
TransportRequest request = mock(TransportRequest.class);
filter.outbound("_action", request);
verify(authcService).attachUserHeaderIfMissing(SystemUser.INSTANCE);
verify(authcService).attachUserIfMissing(SystemUser.INSTANCE);
}
}

View File

@ -8,7 +8,7 @@ package org.elasticsearch.shield.transport;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.shield.user.User;
import org.elasticsearch.shield.authc.Authentication;
import org.elasticsearch.shield.action.ShieldActionMapper;
import org.elasticsearch.shield.authc.AuthenticationService;
import org.elasticsearch.shield.authz.AuthorizationService;
@ -48,10 +48,10 @@ public class ServerTransportFilterTests extends ESTestCase {
public void testInbound() throws Exception {
TransportRequest request = mock(TransportRequest.class);
User user = mock(User.class);
when(authcService.authenticate("_action", request, null)).thenReturn(user);
Authentication authentication = mock(Authentication.class);
when(authcService.authenticate("_action", request, null)).thenReturn(authentication);
filter.inbound("_action", request, channel);
verify(authzService).authorize(user, "_action", request);
verify(authzService).authorize(authentication, "_action", request);
}
public void testInboundAuthenticationException() throws Exception {
@ -68,9 +68,9 @@ public class ServerTransportFilterTests extends ESTestCase {
public void testInboundAuthorizationException() throws Exception {
TransportRequest request = mock(TransportRequest.class);
User user = mock(User.class);
when(authcService.authenticate("_action", request, null)).thenReturn(user);
doThrow(authorizationError("authz failed")).when(authzService).authorize(user, "_action", request);
Authentication authentication = mock(Authentication.class);
when(authcService.authenticate("_action", request, null)).thenReturn(authentication);
doThrow(authorizationError("authz failed")).when(authzService).authorize(authentication, "_action", request);
try {
filter.inbound("_action", request, channel);
fail("expected filter inbound to throw an authorization exception on authorization error");

View File

@ -116,16 +116,6 @@ public class TransportFilterTests extends ESIntegTestCase {
}
public static class InternalPlugin extends Plugin {
@Override
public String name() {
return "test-transport-filter";
}
@Override
public String description() {
return "";
}
@Override
public Collection<Module> nodeModules() {
return Collections.<Module>singletonList(new TestTransportFilterModule());
@ -289,14 +279,6 @@ public class TransportFilterTests extends ESIntegTestCase {
// Sub class the Shield transport to always inject a mock for testing
public static class InternalPluginServerTransportService extends ShieldServerTransportService {
public static class TestPlugin extends Plugin {
@Override
public String name() {
return "mock-transport-service";
}
@Override
public String description() {
return "a mock transport service for testing";
}
public void onModule(NetworkModule module) {
module.registerTransportService("filter-mock", InternalPluginServerTransportService.class);
}
@ -308,9 +290,9 @@ public class TransportFilterTests extends ESIntegTestCase {
@Inject
public InternalPluginServerTransportService(Settings settings, Transport transport, ThreadPool threadPool,
ClusterName clusterName, AuthenticationService authcService, AuthorizationService authzService,
AuthenticationService authcService, AuthorizationService authzService,
ShieldActionMapper actionMapper, ClientTransportFilter clientTransportFilter) {
super(settings, transport, threadPool, clusterName, authcService, authzService, actionMapper, clientTransportFilter,
super(settings, transport, threadPool, authcService, authzService, actionMapper, clientTransportFilter,
mock(SecurityLicenseState.class));
when(licenseState.authenticationAndAuthorizationEnabled()).thenReturn(true);
}

View File

@ -15,7 +15,9 @@ import org.elasticsearch.shield.ssl.SSLConfiguration;
import org.elasticsearch.xpack.XPackPlugin;
import org.hamcrest.Matcher;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.hamcrest.CoreMatchers.nullValue;
@ -85,13 +87,14 @@ public class SettingsFilterTests extends ESTestCase {
.build();
XPackPlugin xPackPlugin = new XPackPlugin(settings);
SettingsModule settingsModule = new SettingsModule(settings);
List<Setting<?>> settingList = new ArrayList<>();
settingList.add(Setting.simpleString("foo.bar", Setting.Property.NodeScope));
settingList.add(Setting.simpleString("foo.baz", Setting.Property.NodeScope));
settingList.add(Setting.simpleString("bar.baz", Setting.Property.NodeScope));
settingList.add(Setting.simpleString("baz.foo", Setting.Property.NodeScope));
settingList.addAll(xPackPlugin.getSettings());
// custom settings, potentially added by a plugin
settingsModule.registerSetting(Setting.simpleString("foo.bar", Setting.Property.NodeScope));
settingsModule.registerSetting(Setting.simpleString("foo.baz", Setting.Property.NodeScope));
settingsModule.registerSetting(Setting.simpleString("bar.baz", Setting.Property.NodeScope));
settingsModule.registerSetting(Setting.simpleString("baz.foo", Setting.Property.NodeScope));
xPackPlugin.onModule(settingsModule);
SettingsModule settingsModule = new SettingsModule(settings, settingList, xPackPlugin.getSettingsFilter());
Injector injector = Guice.createInjector(settingsModule);
SettingsFilter settingsFilter = injector.getInstance(SettingsFilter.class);

View File

@ -151,7 +151,8 @@ public abstract class ShieldIntegTestCase extends ESIntegTestCase {
// assertThat(nodeInfo.getPlugins().getInfos(), hasSize(2));
Collection<String> pluginNames =
nodeInfo.getPlugins().getPluginInfos().stream().map(p -> p.getName()).collect(Collectors.toList());
assertThat("plugin [" + XPackPlugin.NAME + "] not found in [" + pluginNames + "]", pluginNames, hasItem(XPackPlugin.NAME));
assertThat("plugin [" + xpackPluginClass().getName() + "] not found in [" + pluginNames + "]", pluginNames,
hasItem(xpackPluginClass().getName()));
}
}

View File

@ -44,6 +44,7 @@ indices:admin/refresh
indices:admin/settings/update
indices:admin/shards/search_shards
indices:admin/shrink
indices:admin/rollover
indices:admin/template/delete
indices:admin/template/get
indices:admin/template/put

View File

@ -21,16 +21,19 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexModule;
import org.elasticsearch.license.plugin.Licensing;
import org.elasticsearch.marvel.Monitoring;
import org.elasticsearch.marvel.MonitoringSettings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptModule;
import org.elasticsearch.shield.Security;
import org.elasticsearch.shield.authc.AuthenticationModule;
import org.elasticsearch.threadpool.ExecutorBuilder;
import org.elasticsearch.threadpool.ThreadPoolModule;
import org.elasticsearch.xpack.action.TransportXPackInfoAction;
import org.elasticsearch.xpack.action.TransportXPackUsageAction;
import org.elasticsearch.xpack.action.XPackInfoAction;
import org.elasticsearch.xpack.action.XPackUsageAction;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.common.http.HttpClientModule;
import org.elasticsearch.xpack.common.init.LazyInitializationModule;
import org.elasticsearch.xpack.common.init.LazyInitializationService;
@ -55,7 +58,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class XPackPlugin extends Plugin {
public class XPackPlugin extends Plugin implements ScriptPlugin {
public static final String NAME = "x-pack";
@ -124,14 +127,6 @@ public class XPackPlugin extends Plugin {
}
}
@Override public String name() {
return NAME;
}
@Override public String description() {
return "Elastic X-Pack";
}
// For tests only
public Collection<Class<? extends XPackExtension>> getExtensions() {
return Collections.emptyList();
@ -182,26 +177,39 @@ public class XPackPlugin extends Plugin {
return builder.build();
}
public void onModule(ScriptModule module) {
watcher.onModule(module);
@Override
public ScriptContext.Plugin getCustomScriptContexts() {
return ScriptServiceProxy.INSTANCE;
}
public void onModule(SettingsModule module) {
@Override
public List<Setting<?>> getSettings() {
ArrayList<Setting<?>> settings = new ArrayList<>();
settings.addAll(notification.getSettings());
settings.addAll(security.getSettings());
settings.addAll(MonitoringSettings.getSettings());
settings.addAll(watcher.getSettings());
settings.addAll(graph.getSettings());
settings.addAll(licensing.getSettings());
// we add the `xpack.version` setting to all internal indices
module.registerSetting(Setting.simpleString("index.xpack.version", Setting.Property.IndexScope));
settings.add(Setting.simpleString("index.xpack.version", Setting.Property.IndexScope));
// http settings
module.registerSetting(Setting.simpleString("xpack.http.default_read_timeout", Setting.Property.NodeScope));
module.registerSetting(Setting.simpleString("xpack.http.default_connection_timeout", Setting.Property.NodeScope));
module.registerSetting(Setting.groupSetting("xpack.http.ssl.", Setting.Property.NodeScope));
module.registerSetting(Setting.groupSetting("xpack.http.proxy.", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.http.default_read_timeout", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.http.default_connection_timeout", Setting.Property.NodeScope));
settings.add(Setting.groupSetting("xpack.http.ssl.", Setting.Property.NodeScope));
settings.add(Setting.groupSetting("xpack.http.proxy.", Setting.Property.NodeScope));
return settings;
}
notification.onModule(module);
security.onModule(module);
monitoring.onModule(module);
watcher.onModule(module);
graph.onModule(module);
licensing.onModule(module);
@Override
public List<String> getSettingsFilter() {
List<String> filters = new ArrayList<>();
filters.addAll(notification.getSettingsFilter());
filters.addAll(security.getSettingsFilter());
filters.addAll(MonitoringSettings.getSettingsFilter());
filters.addAll(graph.getSettingsFilter());
return filters;
}
@Override
@ -305,9 +313,9 @@ public class XPackPlugin extends Plugin {
*
* {@code "<feature>.enabled": true | false}
*/
public static void registerFeatureEnabledSettings(SettingsModule settingsModule, String featureName, boolean defaultValue) {
settingsModule.registerSetting(Setting.boolSetting(featureEnabledSetting(featureName), defaultValue, Setting.Property.NodeScope));
settingsModule.registerSetting(Setting.boolSetting(legacyFeatureEnabledSetting(featureName),
public static void addFeatureEnabledSettings(List<Setting<?>> settingsList, String featureName, boolean defaultValue) {
settingsList.add(Setting.boolSetting(featureEnabledSetting(featureName), defaultValue, Setting.Property.NodeScope));
settingsList.add(Setting.boolSetting(legacyFeatureEnabledSetting(featureName),
defaultValue, Setting.Property.NodeScope));
}

View File

@ -36,18 +36,22 @@ public class Notification {
this.transportClient = "transport".equals(settings.get(Client.CLIENT_TYPE_SETTING_S.getKey()));
}
public void onModule(SettingsModule module) {
module.registerSetting(InternalSlackService.SLACK_ACCOUNT_SETTING);
module.registerSetting(InternalEmailService.EMAIL_ACCOUNT_SETTING);
module.registerSetting(InternalHipChatService.HIPCHAT_ACCOUNT_SETTING);
module.registerSetting(InternalPagerDutyService.PAGERDUTY_ACCOUNT_SETTING);
public List<Setting<?>> getSettings() {
return Arrays.asList(InternalSlackService.SLACK_ACCOUNT_SETTING,
InternalEmailService.EMAIL_ACCOUNT_SETTING,
InternalHipChatService.HIPCHAT_ACCOUNT_SETTING,
InternalPagerDutyService.PAGERDUTY_ACCOUNT_SETTING);
}
module.registerSettingsFilter("xpack.notification.email.account.*.smtp.password");
module.registerSettingsFilter("xpack.notification.slack.account.*.url");
module.registerSettingsFilter("xpack.notification.pagerduty.account.*.url");
module.registerSettingsFilter("xpack.notification.pagerduty." + PagerDutyAccount.SERVICE_KEY_SETTING);
module.registerSettingsFilter("xpack.notification.pagerduty.account.*." + PagerDutyAccount.SERVICE_KEY_SETTING);
module.registerSettingsFilter("xpack.notification.hipchat.account.*.auth_token");
public List<String> getSettingsFilter() {
ArrayList<String> settingsFilter = new ArrayList<>();
settingsFilter.add("xpack.notification.email.account.*.smtp.password");
settingsFilter.add("xpack.notification.slack.account.*.url");
settingsFilter.add("xpack.notification.pagerduty.account.*.url");
settingsFilter.add("xpack.notification.pagerduty." + PagerDutyAccount.SERVICE_KEY_SETTING);
settingsFilter.add("xpack.notification.pagerduty.account.*." + PagerDutyAccount.SERVICE_KEY_SETTING);
settingsFilter.add("xpack.notification.hipchat.account.*.auth_token");
return settingsFilter;
}
public Collection<Class<? extends LifecycleComponent>> nodeServices() {

View File

@ -19,12 +19,10 @@ import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.common.util.concurrent.EsExecutors;
import org.elasticsearch.script.ScriptModule;
import org.elasticsearch.threadpool.ExecutorBuilder;
import org.elasticsearch.threadpool.FixedExecutorBuilder;
import org.elasticsearch.threadpool.ThreadPoolModule;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.common.init.LazyInitializationModule;
import org.elasticsearch.xpack.watcher.actions.WatcherActionModule;
@ -140,33 +138,32 @@ public class Watcher {
return Settings.EMPTY;
}
public void onModule(ScriptModule module) {
module.registerScriptContext(ScriptServiceProxy.INSTANCE);
}
public void onModule(SettingsModule module) {
public List<Setting<?>> getSettings() {
List<Setting<?>> settings = new ArrayList<>();
for (TemplateConfig templateConfig : WatcherIndexTemplateRegistry.TEMPLATE_CONFIGS) {
module.registerSetting(templateConfig.getSetting());
settings.add(templateConfig.getSetting());
}
module.registerSetting(INDEX_WATCHER_VERSION_SETTING);
module.registerSetting(INDEX_WATCHER_TEMPLATE_VERSION_SETTING);
module.registerSetting(Setting.intSetting("xpack.watcher.execution.scroll.size", 0, Setting.Property.NodeScope));
module.registerSetting(Setting.intSetting("xpack.watcher.watch.scroll.size", 0, Setting.Property.NodeScope));
module.registerSetting(Setting.boolSetting(XPackPlugin.featureEnabledSetting(Watcher.NAME), true, Setting.Property.NodeScope));
module.registerSetting(ENCRYPT_SENSITIVE_DATA_SETTING);
settings.add(INDEX_WATCHER_VERSION_SETTING);
settings.add(INDEX_WATCHER_TEMPLATE_VERSION_SETTING);
settings.add(Setting.intSetting("xpack.watcher.execution.scroll.size", 0, Setting.Property.NodeScope));
settings.add(Setting.intSetting("xpack.watcher.watch.scroll.size", 0, Setting.Property.NodeScope));
settings.add(Setting.boolSetting(XPackPlugin.featureEnabledSetting(Watcher.NAME), true, Setting.Property.NodeScope));
settings.add(ENCRYPT_SENSITIVE_DATA_SETTING);
module.registerSetting(Setting.simpleString("xpack.watcher.internal.ops.search.default_timeout", Setting.Property.NodeScope));
module.registerSetting(Setting.simpleString("xpack.watcher.internal.ops.bulk.default_timeout", Setting.Property.NodeScope));
module.registerSetting(Setting.simpleString("xpack.watcher.internal.ops.index.default_timeout", Setting.Property.NodeScope));
module.registerSetting(Setting.simpleString("xpack.watcher.execution.default_throttle_period", Setting.Property.NodeScope));
module.registerSetting(Setting.simpleString("xpack.watcher.actions.index.default_timeout", Setting.Property.NodeScope));
module.registerSetting(Setting.simpleString("xpack.watcher.index.rest.direct_access", Setting.Property.NodeScope));
module.registerSetting(Setting.simpleString("xpack.watcher.trigger.schedule.engine", Setting.Property.NodeScope));
module.registerSetting(Setting.simpleString("xpack.watcher.input.search.default_timeout", Setting.Property.NodeScope));
module.registerSetting(Setting.simpleString("xpack.watcher.transform.search.default_timeout", Setting.Property.NodeScope));
module.registerSetting(Setting.simpleString("xpack.watcher.trigger.schedule.ticker.tick_interval", Setting.Property.NodeScope));
module.registerSetting(Setting.simpleString("xpack.watcher.execution.scroll.timeout", Setting.Property.NodeScope));
module.registerSetting(Setting.simpleString("xpack.watcher.start_immediately", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.internal.ops.search.default_timeout", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.internal.ops.bulk.default_timeout", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.internal.ops.index.default_timeout", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.execution.default_throttle_period", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.actions.index.default_timeout", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.index.rest.direct_access", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.trigger.schedule.engine", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.input.search.default_timeout", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.transform.search.default_timeout", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.trigger.schedule.ticker.tick_interval", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.execution.scroll.timeout", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.start_immediately", Setting.Property.NodeScope));
return settings;
}
public List<ExecutorBuilder<?>> getExecutorBuilders(final Settings settings) {
@ -282,4 +279,5 @@ public class Watcher {
"[.watcher-history-YYYY.MM.dd] are allowed to be created", value);
}
}

View File

@ -5,10 +5,9 @@
*/
package org.elasticsearch.script;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.common.text.DefaultTextTemplateEngine;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
@ -21,16 +20,10 @@ public class MockMustacheScriptEngine extends MockScriptEngine {
public static final String NAME = "mustache";
public static class TestPlugin extends MockScriptEngine.TestPlugin {
@Override
public String name() {
return NAME;
public ScriptEngineService getScriptEngineService(Settings settings) {
return new MockMustacheScriptEngine();
}
public void onModule(ScriptModule module) {
module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(MockMustacheScriptEngine.class, NAME, true));
}
}
@Override
@ -51,4 +44,9 @@ public class MockMustacheScriptEngine extends MockScriptEngine {
return super.compile(name, script, params);
}
@Override
public boolean isInlineScriptEnabled() {
return true;
}
}

View File

@ -6,12 +6,13 @@
package org.elasticsearch.script;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.search.lookup.SearchLookup;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
@ -21,26 +22,11 @@ public class SleepScriptEngine implements ScriptEngineService {
public static final String NAME = "sleep";
public static class TestPlugin extends Plugin {
public TestPlugin() {
}
public static class TestPlugin extends Plugin implements ScriptPlugin {
@Override
public String name() {
return NAME;
public ScriptEngineService getScriptEngineService(Settings settings) {
return new SleepScriptEngine();
}
@Override
public String description() {
return "Mock script engine for integration tests";
}
public void onModule(ScriptModule module) {
module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(SleepScriptEngine.class,
SleepScriptEngine.NAME, true));
}
}
@Override
@ -92,4 +78,8 @@ public class SleepScriptEngine implements ScriptEngineService {
.params(Collections.singletonMap("millis", millis)).build();
}
@Override
public boolean isInlineScriptEnabled() {
return true;
}
}

View File

@ -112,19 +112,6 @@ public class ActionErrorIntegrationTests extends AbstractWatcherIntegrationTestC
public static class ErrorActionPlugin extends Plugin {
public ErrorActionPlugin() {
}
@Override
public String name() {
return "error-action";
}
@Override
public String description() {
return name();
}
public void onModule(WatcherActionModule module) {
module.registerAction(ErrorAction.TYPE, ErrorAction.Factory.class);
}

View File

@ -15,6 +15,8 @@ import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import static org.elasticsearch.test.ESIntegTestCase.Scope.TEST;
@ -74,19 +76,12 @@ public class WatcherIndexTemplateRegistryTests extends AbstractWatcherIntegratio
}
public static class SettingTestPlugin extends Plugin {
public String name() {
return "watcher-index-template-registry-settings-plugin";
}
@Override
public String description() {
return "installs a setting this test needs";
}
public static final Setting<String> KEY_1 = new Setting<>("index.key1", "", Function.identity(), Setting.Property.IndexScope);
public void onModule(SettingsModule module) {
module.registerSetting(KEY_1);
@Override
public List<Setting<?>> getSettings() {
return Collections.singletonList(KEY_1);
}
}
}

View File

@ -254,7 +254,7 @@ public final class WatcherTestUtils {
ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
ClusterService clusterService = Mockito.mock(ClusterService.class);
Mockito.when(clusterService.state()).thenReturn(ClusterState.builder(new ClusterName("_name")).build());
return ScriptServiceProxy.of(new ScriptService(settings, new Environment(settings), Collections.emptySet(),
return ScriptServiceProxy.of(new ScriptService(settings, new Environment(settings),
new ResourceWatcherService(settings, tp), scriptEngineRegistry, scriptContextRegistry, scriptSettings),
clusterService);
}