Merge branch 'master' into feature/account-settings
Original commit: elastic/x-pack-elasticsearch@6942ae6cb2
This commit is contained in:
commit
f5d8a7c4e6
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.*");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -20,4 +20,4 @@
|
|||
"enabled": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,6 +136,9 @@
|
|||
},
|
||||
"used_in_bytes": {
|
||||
"type": "float"
|
||||
},
|
||||
"size_limit": {
|
||||
"type": "float"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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\""));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue