diff --git a/src/main/java/org/elasticsearch/shield/authc/esusers/tool/ESUsersTool.java b/src/main/java/org/elasticsearch/shield/authc/esusers/tool/ESUsersTool.java index 9bf61e424d7..a7bc41776ca 100644 --- a/src/main/java/org/elasticsearch/shield/authc/esusers/tool/ESUsersTool.java +++ b/src/main/java/org/elasticsearch/shield/authc/esusers/tool/ESUsersTool.java @@ -11,16 +11,19 @@ import org.elasticsearch.common.cli.CliTool; import org.elasticsearch.common.cli.CliToolConfig; import org.elasticsearch.common.cli.Terminal; import org.elasticsearch.common.cli.commons.CommandLine; -import org.elasticsearch.common.collect.Lists; -import org.elasticsearch.common.collect.Maps; -import org.elasticsearch.common.collect.ObjectArrays; -import org.elasticsearch.common.collect.Sets; +import org.elasticsearch.common.collect.*; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; +import org.elasticsearch.shield.User; import org.elasticsearch.shield.authc.esusers.FileUserPasswdStore; import org.elasticsearch.shield.authc.esusers.FileUserRolesStore; import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.SecuredString; +import org.elasticsearch.shield.authz.AuthorizationException; +import org.elasticsearch.shield.authz.AuthorizationService; +import org.elasticsearch.shield.authz.Permission; +import org.elasticsearch.shield.authz.store.FileRolesStore; +import org.elasticsearch.transport.TransportRequest; import java.nio.file.Files; import java.nio.file.Path; @@ -118,6 +121,7 @@ public class ESUsersTool extends CliTool { @Override public ExitStatus execute(Settings settings, Environment env) throws Exception { + verifyRoles(terminal, settings, env, roles); Path file = FileUserPasswdStore.resolveFile(settings, env); Map users = new HashMap<>(FileUserPasswdStore.parseFile(file, null)); if (users.containsKey(username)) { @@ -168,8 +172,6 @@ public class ESUsersTool extends CliTool { char[] passwd = users.remove(username); if (passwd != null) { FileUserPasswdStore.writeFile(users, file); - } else { - terminal.println("Warning: users file [%s] did not contain password entry for user [%s]", file.toAbsolutePath(), username); } } @@ -179,8 +181,6 @@ public class ESUsersTool extends CliTool { String[] roles = userRoles.remove(username); if (roles != null) { FileUserRolesStore.writeFile(userRoles, file); - } else { - terminal.println("Warning: users_roles file [%s] did not contain roles entry for user [%s]", file.toAbsolutePath(), username); } } @@ -311,6 +311,7 @@ public class ESUsersTool extends CliTool { if (userRoles.get(username) != null) { roles.addAll(Arrays.asList(userRoles.get(username))); } + verifyRoles(terminal, settings, env, addRoles); roles.addAll(Arrays.asList(addRoles)); roles.removeAll(Arrays.asList(removeRoles)); @@ -347,6 +348,7 @@ public class ESUsersTool extends CliTool { @Override public ExitStatus execute(Settings settings, Environment env) throws Exception { + ImmutableMap knownRoles = loadRoles(terminal, settings, env); Path userRolesFilePath = FileUserRolesStore.resolveFile(settings, env); Map userRoles = FileUserRolesStore.parseFile(userRolesFilePath, null); Path userFilePath = FileUserPasswdStore.resolveFile(settings, env); @@ -359,13 +361,27 @@ public class ESUsersTool extends CliTool { } if (userRoles.containsKey(username)) { - terminal.println("%-15s: %s", username, Joiner.on(",").useForNull("-").join(userRoles.get(username))); + String[] roles = userRoles.get(username); + Set unknownRoles = Sets.difference(Sets.newHashSet(roles), knownRoles.keySet()); + String[] markedRoles = markUnknownRoles(roles, unknownRoles); + terminal.println("%-15s: %s", username, Joiner.on(",").useForNull("-").join(markedRoles)); + if (!unknownRoles.isEmpty()) { + // at least one role is marked... so printing the legend + Path rolesFile = FileRolesStore.resolveFile(settings, env).toAbsolutePath(); + terminal.println(); + terminal.println(" [*] An unknown role. Please check [%s] to see available roles", rolesFile.toAbsolutePath()); + } } else { terminal.println("%-15s: -", username); } } else { + boolean unknownRolesFound = false; for (Map.Entry entry : userRoles.entrySet()) { - terminal.println("%-15s: %s", entry.getKey(), Joiner.on(",").join(entry.getValue())); + String[] roles = entry.getValue(); + Set unknownRoles = Sets.difference(Sets.newHashSet(roles), knownRoles.keySet()); + String[] markedRoles = markUnknownRoles(roles, unknownRoles); + terminal.println("%-15s: %s", entry.getKey(), Joiner.on(",").join(markedRoles)); + unknownRolesFound = unknownRolesFound || !unknownRoles.isEmpty(); } // list users without roles Set usersWithoutRoles = Sets.newHashSet(users); @@ -374,9 +390,67 @@ public class ESUsersTool extends CliTool { terminal.println("%-15s: -", user); } } + if (unknownRolesFound) { + // at least one role is marked... so printing the legend + Path rolesFile = FileRolesStore.resolveFile(settings, env).toAbsolutePath(); + terminal.println(); + terminal.println(" [*] An unknown role. Please check [%s] to see available roles", rolesFile.toAbsolutePath()); + } } return ExitStatus.OK; } } + + private static ImmutableMap loadRoles(Terminal terminal, Settings settings, Environment env) { + Path rolesFile = FileRolesStore.resolveFile(settings, env); + try { + return FileRolesStore.parseFile(rolesFile, null, new DummyAuthzService()); + } catch (Throwable t) { + // if for some reason, parsing fails (malformatted perhaps) we just warn + terminal.println("Warning: Could not parse [%s] for roles verification. Please revise and fix it. Nonetheless, the user will still be associated with all specified roles", rolesFile.toAbsolutePath()); + } + return null; + } + + private static String[] markUnknownRoles(String[] roles, Set unknownRoles) { + if (unknownRoles.isEmpty()) { + return roles; + } + String[] marked = new String[roles.length]; + for (int i = 0; i < roles.length; i++) { + if (unknownRoles.contains(roles[i])) { + marked[i] = roles[i] + "*"; + } else { + marked[i] = roles[i]; + } + } + return marked; + } + + private static void verifyRoles(Terminal terminal, Settings settings, Environment env, String[] roles) { + ImmutableMap knownRoles = loadRoles(terminal, settings, env); + if (knownRoles == null) { + return; + } + Set unknownRoles = Sets.difference(Sets.newHashSet(roles), knownRoles.keySet()); + if (!unknownRoles.isEmpty()) { + Path rolesFile = FileRolesStore.resolveFile(settings, env); + terminal.println("Warning: The following roles [%s] are unknown. Make sure to add them to the [%s] file. " + + "Nonetheless the user will still be associated with all specified roles", + Strings.collectionToCommaDelimitedString(unknownRoles), rolesFile.toAbsolutePath()); + } + } + + private static class DummyAuthzService implements AuthorizationService { + @Override + public ImmutableList authorizedIndicesAndAliases(User user, String action) { + return ImmutableList.of(); + } + + @Override + public void authorize(User user, String action, TransportRequest request) throws AuthorizationException { + + } + } } \ No newline at end of file diff --git a/src/main/java/org/elasticsearch/shield/authz/Permission.java b/src/main/java/org/elasticsearch/shield/authz/Permission.java index 433c719a64f..f084f70f602 100644 --- a/src/main/java/org/elasticsearch/shield/authz/Permission.java +++ b/src/main/java/org/elasticsearch/shield/authz/Permission.java @@ -46,6 +46,9 @@ public interface Permission { static class Global implements Permission { + final static Predicate clusterActionMatcher = Privilege.Cluster.ALL.predicate(); + final static Predicate indicesActionMatcher = Privilege.Index.ALL.predicate(); + private final Cluster cluster; private final Indices indices; @@ -67,11 +70,11 @@ public interface Permission { } public boolean check(User user, String action, TransportRequest request, MetaData metaData) { - if (cluster != null && cluster.check(user, action, request, metaData)) { - return true; + if (clusterActionMatcher.apply(action)) { + return cluster != null && cluster.check(user, action, request, metaData); } - if (indices != null && indices.check(user, action, request, metaData)) { - return true; + if (indicesActionMatcher.apply(action)) { + return indices != null && indices.check(user, action, request, metaData); } return false; } diff --git a/src/main/java/org/elasticsearch/shield/authz/store/FileRolesStore.java b/src/main/java/org/elasticsearch/shield/authz/store/FileRolesStore.java index 28e34d8e72d..41734e600ba 100644 --- a/src/main/java/org/elasticsearch/shield/authz/store/FileRolesStore.java +++ b/src/main/java/org/elasticsearch/shield/authz/store/FileRolesStore.java @@ -59,7 +59,7 @@ public class FileRolesStore extends AbstractComponent implements RolesStore { public FileRolesStore(Settings settings, Environment env, ResourceWatcherService watcherService, AuthorizationService authzService, Listener listener) { super(settings); - file = resolveFile(componentSettings, env); + file = resolveFile(settings, env); permissions = parseFile(file, logger, authzService); FileWatcher watcher = new FileWatcher(file.getParent().toFile()); watcher.addListener(new FileListener(authzService)); @@ -73,7 +73,7 @@ public class FileRolesStore extends AbstractComponent implements RolesStore { } public static Path resolveFile(Settings settings, Environment env) { - String location = settings.get("files.roles"); + String location = settings.get("shield.authz.store.files.roles"); if (location == null) { return ShieldPlugin.resolveConfigFile(env, "roles.yml"); } diff --git a/src/main/java/org/elasticsearch/shield/plugin/ShieldPlugin.java b/src/main/java/org/elasticsearch/shield/plugin/ShieldPlugin.java index a57f4ed8fe8..93019e01cd0 100644 --- a/src/main/java/org/elasticsearch/shield/plugin/ShieldPlugin.java +++ b/src/main/java/org/elasticsearch/shield/plugin/ShieldPlugin.java @@ -5,11 +5,17 @@ */ package org.elasticsearch.shield.plugin; +import org.elasticsearch.client.support.Headers; import org.elasticsearch.common.collect.ImmutableList; import org.elasticsearch.common.inject.Module; +import org.elasticsearch.common.settings.ImmutableSettings; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.plugins.AbstractPlugin; import org.elasticsearch.shield.ShieldModule; +import org.elasticsearch.shield.ShieldSettingsException; +import org.elasticsearch.shield.authc.support.SecuredString; +import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import java.io.File; import java.nio.file.Path; @@ -22,6 +28,12 @@ public class ShieldPlugin extends AbstractPlugin { public static final String NAME = "shield"; + private final Settings settings; + + public ShieldPlugin(Settings settings) { + this.settings = settings; + } + @Override public String name() { return NAME; @@ -37,6 +49,26 @@ public class ShieldPlugin extends AbstractPlugin { return ImmutableList.>of(ShieldModule.class); } + @Override + public Settings additionalSettings() { + String setting = Headers.PREFIX + "." + UsernamePasswordToken.BASIC_AUTH_HEADER; + if (settings.get(setting) != null) { + return ImmutableSettings.EMPTY; + } + String user = settings.get("shield.user"); + if (user == null) { + return ImmutableSettings.EMPTY; + } + int i = user.indexOf(":"); + if (i < 0 || i == user.length() - 1) { + throw new ShieldSettingsException("Invalid [shield.user] settings. Must be in the form of \":\""); + } + String username = user.substring(0, i); + String password = user.substring(i + 1); + return ImmutableSettings.builder() + .put(setting, UsernamePasswordToken.basicAuthHeaderValue(username, new SecuredString(password.toCharArray()))).build(); + } + public static Path configDir(Environment env) { return new File(env.configFile(), NAME).toPath(); } diff --git a/src/test/java/org/elasticsearch/shield/MultipleIndicesPermissionsTests.java b/src/test/java/org/elasticsearch/shield/MultipleIndicesPermissionsTests.java index f27a24de418..be83b19cc83 100644 --- a/src/test/java/org/elasticsearch/shield/MultipleIndicesPermissionsTests.java +++ b/src/test/java/org/elasticsearch/shield/MultipleIndicesPermissionsTests.java @@ -6,6 +6,7 @@ package org.elasticsearch.shield; import org.elasticsearch.action.index.IndexResponse; +import org.elasticsearch.action.search.MultiSearchResponse; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.Client; import org.elasticsearch.shield.authz.AuthorizationException; @@ -94,5 +95,20 @@ public class MultipleIndicesPermissionsTests extends ShieldIntegrationTest { } catch (AuthorizationException ae) { // expected } + + MultiSearchResponse msearchResponse = client.prepareMultiSearch() + .add(client.prepareSearch("test")) + .add(client.prepareSearch("test1")) + .get(); + MultiSearchResponse.Item[] items = msearchResponse.getResponses(); + assertThat(items.length, is(2)); + assertThat(items[0].isFailure(), is(false)); + searchResponse = items[0].getResponse(); + assertNoFailures(searchResponse); + assertHitCount(searchResponse, 1); + assertThat(items[1].isFailure(), is(false)); + searchResponse = items[1].getResponse(); + assertNoFailures(searchResponse); + assertHitCount(searchResponse, 1); } } diff --git a/src/test/java/org/elasticsearch/shield/PermissionPrecedenceTests.java b/src/test/java/org/elasticsearch/shield/PermissionPrecedenceTests.java new file mode 100644 index 00000000000..19f1718b6fc --- /dev/null +++ b/src/test/java/org/elasticsearch/shield/PermissionPrecedenceTests.java @@ -0,0 +1,126 @@ +/* + * 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; + +import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse; +import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse; +import org.elasticsearch.client.transport.TransportClient; +import org.elasticsearch.cluster.ClusterService; +import org.elasticsearch.cluster.metadata.IndexTemplateMetaData; +import org.elasticsearch.common.settings.ImmutableSettings; +import org.elasticsearch.common.transport.TransportAddress; +import org.elasticsearch.shield.authc.support.SecuredString; +import org.elasticsearch.shield.authc.support.SecuredStringTests; +import org.elasticsearch.shield.authz.AuthorizationException; +import org.elasticsearch.shield.test.ShieldIntegrationTest; +import org.junit.Test; + +import java.util.List; + +import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; +import static org.hamcrest.Matchers.hasSize; + +/** + * This test makes sure that if an action is a cluster action (according to our + * internal categorization in shield, then we apply the cluster priv checks and don't + * fallback on the indices privs at all. In particular, this is useful when we want to treat + * actions that are normally categorized as index actions as cluster actions - for example, + * index template actions. + */ +public class PermissionPrecedenceTests extends ShieldIntegrationTest { + + static final String ROLES = + "admin:\n" + + " cluster: all\n" + + " indices:\n" + + " '*': all\n" + + "\n" + + "user:\n" + + " indices:\n" + + " 'test_*': all\n"; + + static final String USERS = + "admin:{plain}test123\n" + + "user:{plain}test123\n"; + + static final String USERS_ROLES = + "admin:admin\n" + + "user:user\n"; + + @Override + protected String configRole() { + return ROLES; + } + + @Override + protected String configUsers() { + return USERS; + } + + @Override + protected String configUsersRoles() { + return USERS_ROLES; + } + + @Override + protected String getClientUsername() { + return "admin"; + } + + @Override + protected SecuredString getClientPassword() { + return SecuredStringTests.build("test123"); + } + + @Test + public void testDifferetCombinationsOfIndices() throws Exception { + + ClusterService clusterService = internalCluster().getInstance(ClusterService.class); + TransportAddress address = clusterService.localNode().address(); + + TransportClient client = new TransportClient(ImmutableSettings.builder() + .put("cluster.name", internalCluster().getClusterName()) + .put("node.mode", "network") + .put(getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient"))) + .addTransportAddress(address); + + // first lets try with "admin"... all should work + + PutIndexTemplateResponse putResponse = client.admin().indices().preparePutTemplate("template1") + .setTemplate("test_*") + .putHeader("Authorization", basicAuthHeaderValue("admin", SecuredStringTests.build("test123"))) + .get(); + assertAcked(putResponse); + + GetIndexTemplatesResponse getResponse = client.admin().indices().prepareGetTemplates("template1") + .putHeader("Authorization", basicAuthHeaderValue("admin", SecuredStringTests.build("test123"))) + .get(); + List templates = getResponse.getIndexTemplates(); + assertThat(templates, hasSize(1)); + + // now lets try with "user" + + try { + client.admin().indices().preparePutTemplate("template1") + .setTemplate("test_*") + .putHeader("Authorization", basicAuthHeaderValue("user", SecuredStringTests.build("test123"))) + .get(); + fail("expected an authorization exception as template APIs should require cluster ALL permission"); + } catch (AuthorizationException ae) { + // expected; + } + + try { + client.admin().indices().prepareGetTemplates("template1") + .putHeader("Authorization", basicAuthHeaderValue("user", SecuredStringTests.build("test123"))) + .get(); + fail("expected an authorization exception as template APIs should require cluster ALL permission"); + } catch (AuthorizationException ae) { + // expected + } + } +} diff --git a/src/test/java/org/elasticsearch/shield/authc/esusers/tool/ESUsersToolTests.java b/src/test/java/org/elasticsearch/shield/authc/esusers/tool/ESUsersToolTests.java index c6e02e8711d..1f05fa6ee73 100644 --- a/src/test/java/org/elasticsearch/shield/authc/esusers/tool/ESUsersToolTests.java +++ b/src/test/java/org/elasticsearch/shield/authc/esusers/tool/ESUsersToolTests.java @@ -478,9 +478,11 @@ public class ESUsersToolTests extends CliToolTestCase { public void testRoles_Cmd_testNotAddingOrRemovingRolesShowsListingOfRoles() throws Exception { File usersFile = writeFile("admin:hash\nuser:hash"); File usersRoleFile = writeFile("admin: admin\nuser:user\nfoo:user\nbar:user\n"); + File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all\n\nbar:\n cluster: all"); Settings settings = ImmutableSettings.builder() .put("shield.authc.esusers.files.users", usersFile) .put("shield.authc.esusers.files.users_roles", usersRoleFile) + .put("shield.authz.store.files.roles", rolesFile) .build(); CaptureOutputTerminal catchTerminalOutput = new CaptureOutputTerminal(); @@ -495,9 +497,11 @@ public class ESUsersToolTests extends CliToolTestCase { public void testRoles_cmd_testRoleCanBeAddedWhenUserIsNotInRolesFile() throws Exception { File usersFile = writeFile("admin:hash\nuser:hash"); File usersRoleFile = writeFile("admin: admin\n"); + File rolesFile = writeFile("admin:\n cluster: all\n\nmyrole:\n cluster: all"); Settings settings = ImmutableSettings.builder() .put("shield.authc.esusers.files.users", usersFile) .put("shield.authc.esusers.files.users_roles", usersRoleFile) + .put("shield.authz.store.files.roles", rolesFile) .build(); CaptureOutputTerminal catchTerminalOutput = new CaptureOutputTerminal(); @@ -523,8 +527,10 @@ public class ESUsersToolTests extends CliToolTestCase { @Test public void testListUsersAndRoles_Cmd_listAllUsers() throws Exception { File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n"); + File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all\n\nbar:\n cluster: all"); Settings settings = ImmutableSettings.builder() .put("shield.authc.esusers.files.users_roles", usersRoleFile) + .put("shield.authz.store.files.roles", rolesFile) .build(); CaptureOutputTerminal catchTerminalOutput = new CaptureOutputTerminal(); @@ -537,13 +543,34 @@ public class ESUsersToolTests extends CliToolTestCase { assertThat(catchTerminalOutput.getTerminalOutput(), hasItem(allOf(containsString("user"), containsString("user,foo,bar")))); } + @Test + public void testListUsersAndRoles_Cmd_listAllUsers_WithUnknownRoles() throws Exception { + File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n"); + File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all"); + Settings settings = ImmutableSettings.builder() + .put("shield.authc.esusers.files.users_roles", usersRoleFile) + .put("shield.authz.store.files.roles", rolesFile) + .build(); + + CaptureOutputTerminal catchTerminalOutput = new CaptureOutputTerminal(); + ESUsersTool.ListUsersAndRoles cmd = new ESUsersTool.ListUsersAndRoles(catchTerminalOutput, null); + CliTool.ExitStatus status = execute(cmd, settings); + + assertThat(status, is(CliTool.ExitStatus.OK)); + assertThat(catchTerminalOutput.getTerminalOutput(), hasSize(greaterThanOrEqualTo(2))); + assertThat(catchTerminalOutput.getTerminalOutput(), hasItem(containsString("admin"))); + assertThat(catchTerminalOutput.getTerminalOutput(), hasItem(allOf(containsString("user"), containsString("user,foo*,bar*")))); + } + @Test public void testListUsersAndRoles_Cmd_listSingleUser() throws Exception { File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n"); File usersFile = writeFile("admin:{plain}changeme\nuser:{plain}changeme\nno-roles-user:{plain}changeme\n"); + File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all"); Settings settings = ImmutableSettings.builder() .put("shield.authc.esusers.files.users_roles", usersRoleFile) .put("shield.authc.esusers.files.users", usersFile) + .put("shield.authz.store.files.roles", rolesFile) .build(); CaptureOutputTerminal catchTerminalOutput = new CaptureOutputTerminal(); @@ -574,9 +601,11 @@ public class ESUsersToolTests extends CliToolTestCase { public void testListUsersAndRoles_Cmd_testThatUsersWithoutRolesAreListed() throws Exception { File usersFile = writeFile("admin:{plain}changeme\nuser:{plain}changeme\nno-roles-user:{plain}changeme\n"); File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n"); + File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all\n\nbar:\n cluster: all"); Settings settings = ImmutableSettings.builder() .put("shield.authc.esusers.files.users_roles", usersRoleFile) .put("shield.authc.esusers.files.users", usersFile) + .put("shield.authz.store.files.roles", rolesFile) .build(); CaptureOutputTerminal catchTerminalOutput = new CaptureOutputTerminal(); diff --git a/src/test/java/org/elasticsearch/shield/test/ShieldIntegrationTest.java b/src/test/java/org/elasticsearch/shield/test/ShieldIntegrationTest.java index d2825fa077f..e037b4790cd 100644 --- a/src/test/java/org/elasticsearch/shield/test/ShieldIntegrationTest.java +++ b/src/test/java/org/elasticsearch/shield/test/ShieldIntegrationTest.java @@ -63,19 +63,20 @@ public abstract class ShieldIntegrationTest extends ElasticsearchIntegrationTest File folder = newFolder(); ImmutableSettings.Builder builder = ImmutableSettings.builder() - .put("request.headers.Authorization", basicAuthHeaderValue(getClientUsername(), getClientPassword())) .put("discovery.zen.ping.multicast.enabled", false) .put("discovery.type", "zen") .put("node.mode", "network") .put("plugin.types", ShieldPlugin.class.getName()) - .put("shield.authc.esusers.files.users", writeFile(folder, "users", CONFIG_STANDARD_USER)) - .put("shield.authc.esusers.files.users_roles", writeFile(folder, "users_roles", CONFIG_STANDARD_USER_ROLES)) + .put("shield.authc.esusers.files.users", writeFile(folder, "users", configUsers())) + .put("shield.authc.esusers.files.users_roles", writeFile(folder, "users_roles", configUsersRoles())) .put("shield.authz.store.files.roles", writeFile(folder, "roles.yml", configRole())) .put("shield.transport.n2n.ip_filter.file", writeFile(folder, "ip_filter.yml", CONFIG_IPFILTER_ALLOW_ALL)) .put(getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks", "testnode")) .put("shield.audit.enabled", true) .put("plugins.load_classpath_plugins", false); + setUser(builder); + if (OsUtils.MAC) { builder.put("network.host", randomBoolean() ? "127.0.0.1" : "::1"); } @@ -87,15 +88,34 @@ public abstract class ShieldIntegrationTest extends ElasticsearchIntegrationTest return CONFIG_ROLE_ALLOW_ALL; } + protected String configUsers() { + return CONFIG_STANDARD_USER; + } + + protected String configUsersRoles() { + return CONFIG_STANDARD_USER_ROLES; + } + @Override protected Settings transportClientSettings() { - return ImmutableSettings.builder() + ImmutableSettings.Builder builder = ImmutableSettings.builder() .put("request.headers.Authorization", basicAuthHeaderValue(getClientUsername(), getClientPassword())) .put(TransportModule.TRANSPORT_TYPE_KEY, NettySecuredTransport.class.getName()) .put("plugins." + PluginsService.LOAD_PLUGIN_FROM_CLASSPATH, false) .put("node.mode", "network") - .put(getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient")) - .build(); + .put(getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient")); + + setUser(builder); + + return builder.build(); + } + + protected void setUser(ImmutableSettings.Builder settings) { + if (randomBoolean()) { + settings.put("request.headers.Authorization", basicAuthHeaderValue(getClientUsername(), getClientPassword())); + } else { + settings.put("shield.user", getClientUsername() + ":" + new String(getClientPassword().internalChars())); + } } protected String writeFile(File folder, String name, String content) {