From 8d8baffe2421c676ce57092ffe513cbe96bfde86 Mon Sep 17 00:00:00 2001 From: Jay Modi Date: Thu, 14 Sep 2017 08:09:14 -0600 Subject: [PATCH] Add specific client and user for security index access (elastic/x-pack-elasticsearch#2492) This change removes security index access from the xpack user by creating its own specific role and adds a xpack security user that maintains the superuser role so that it can perform all operations necessary for security. Original commit: elastic/x-pack-elasticsearch@ad906bc9135771101845c775658f3c0691919233 --- .../org/elasticsearch/xpack/XPackPlugin.java | 4 +- .../xpack/security/InternalClient.java | 9 ++- .../security/InternalSecurityClient.java | 23 +++++++ .../xpack/security/Security.java | 4 +- .../security/SecurityLifecycleService.java | 2 +- .../security/audit/index/IndexAuditTrail.java | 3 +- .../security/authc/ExpiredTokenRemover.java | 5 +- .../xpack/security/authc/TokenService.java | 5 +- .../authc/esnative/NativeUsersStore.java | 5 +- .../mapper/NativeRoleMappingStore.java | 5 +- .../security/authz/AuthorizationService.java | 8 ++- .../authz/store/NativeRolesStore.java | 5 +- .../authz/store/ReservedRolesStore.java | 3 +- .../support/IndexLifecycleManager.java | 5 +- .../xpack/security/user/User.java | 5 ++ .../security/user/XPackSecurityUser.java | 38 ++++++++++++ .../xpack/security/user/XPackUser.java | 13 +++- .../elasticsearch/xpack/upgrade/Upgrade.java | 7 ++- .../test/SecurityIntegTestCase.java | 6 ++ .../SecurityLifecycleServiceTests.java | 4 +- .../xpack/security/SecurityTests.java | 4 +- .../security/audit/index/AuditTrailTests.java | 2 +- .../index/IndexAuditTrailMutedTests.java | 5 +- .../audit/index/IndexAuditTrailTests.java | 2 +- .../IndexAuditTrailUpdateMappingTests.java | 2 +- .../authc/AuthenticationServiceTests.java | 3 +- .../security/authc/TokenAuthIntegTests.java | 6 +- .../security/authc/TokenServiceTests.java | 5 +- .../authc/esnative/NativeUsersStoreTests.java | 5 +- .../mapper/NativeUserRoleMapperTests.java | 3 +- .../authz/AuthorizationServiceTests.java | 61 ++++++++----------- .../authz/IndicesAndAliasesResolverTests.java | 14 ++++- .../authz/store/NativeRolesStoreTests.java | 3 +- .../authz/store/ReservedRolesStoreTests.java | 2 + .../support/IndexLifecycleManagerTests.java | 3 +- 35 files changed, 197 insertions(+), 82 deletions(-) create mode 100644 plugin/src/main/java/org/elasticsearch/xpack/security/InternalSecurityClient.java create mode 100644 plugin/src/main/java/org/elasticsearch/xpack/security/user/XPackSecurityUser.java diff --git a/plugin/src/main/java/org/elasticsearch/xpack/XPackPlugin.java b/plugin/src/main/java/org/elasticsearch/xpack/XPackPlugin.java index 8f6ffa1f78b..172c5683ad1 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/XPackPlugin.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/XPackPlugin.java @@ -283,7 +283,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I components.add(licenseState); try { - components.addAll(security.createComponents(internalClient, threadPool, clusterService, resourceWatcherService, + components.addAll(security.createComponents(client, threadPool, clusterService, resourceWatcherService, extensionsService.getExtensions())); } catch (final Exception e) { throw new IllegalStateException("security initialization failed", e); @@ -319,7 +319,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I components.addAll(logstash.createComponents(internalClient, clusterService)); - components.addAll(upgrade.createComponents(internalClient, clusterService, threadPool, resourceWatcherService, + components.addAll(upgrade.createComponents(client, clusterService, threadPool, resourceWatcherService, scriptService, xContentRegistry)); // just create the reloader as it will pull all of the loaded ssl configurations and start watching them diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/InternalClient.java b/plugin/src/main/java/org/elasticsearch/xpack/security/InternalClient.java index d45c85bacb1..dd272c16fd0 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/InternalClient.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/InternalClient.java @@ -27,6 +27,7 @@ import org.elasticsearch.search.SearchHit; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.security.authc.Authentication; +import org.elasticsearch.xpack.security.user.User; import org.elasticsearch.xpack.security.user.XPackUser; import java.io.IOException; @@ -48,15 +49,21 @@ public class InternalClient extends FilterClient { private final String nodeName; private final boolean securityEnabled; + private final User user; /** * Constructs an InternalClient. * If security is enabled the client is secure. Otherwise this client is a passthrough. */ public InternalClient(Settings settings, ThreadPool threadPool, Client in) { + this(settings, threadPool, in, XPackUser.INSTANCE); + } + + InternalClient(Settings settings, ThreadPool threadPool, Client in, User user) { super(settings, threadPool, in); this.nodeName = Node.NODE_NAME_SETTING.get(settings); this.securityEnabled = XPackSettings.SECURITY_ENABLED.get(settings); + this.user = user; } @Override @@ -80,7 +87,7 @@ public class InternalClient extends FilterClient { protected void processContext(ThreadContext threadContext) { try { - Authentication authentication = new Authentication(XPackUser.INSTANCE, + Authentication authentication = new Authentication(user, new Authentication.RealmRef("__attach", "__attach", nodeName), null); authentication.writeToContext(threadContext); } catch (IOException ioe) { diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/InternalSecurityClient.java b/plugin/src/main/java/org/elasticsearch/xpack/security/InternalSecurityClient.java new file mode 100644 index 00000000000..e9e215615af --- /dev/null +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/InternalSecurityClient.java @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.security; + +import org.elasticsearch.client.Client; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.xpack.security.user.XPackSecurityUser; + +/** + * A special filter client for internal usage by security to modify the security index. + * + * The {@link XPackSecurityUser} user is added to the execution context before each action is executed. + */ +public class InternalSecurityClient extends InternalClient { + + public InternalSecurityClient(Settings settings, ThreadPool threadPool, Client in) { + super(settings, threadPool, in, XPackSecurityUser.INSTANCE); + } +} diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java b/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java index dd9de5bc2ae..12b9fdc4379 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -14,6 +14,7 @@ import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.support.ActionFilter; import org.elasticsearch.action.support.DestructiveOperations; import org.elasticsearch.bootstrap.BootstrapCheck; +import org.elasticsearch.client.Client; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.LocalNodeMasterListener; import org.elasticsearch.cluster.NamedDiff; @@ -295,12 +296,13 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin, Clus return modules; } - public Collection createComponents(InternalClient client, ThreadPool threadPool, ClusterService clusterService, + public Collection createComponents(Client nodeClient, ThreadPool threadPool, ClusterService clusterService, ResourceWatcherService resourceWatcherService, List extensions) throws Exception { if (enabled == false) { return Collections.emptyList(); } + final InternalSecurityClient client = new InternalSecurityClient(settings, threadPool, nodeClient); threadContext.set(threadPool.getThreadContext()); List components = new ArrayList<>(); securityContext.set(new SecurityContext(settings, threadPool.getThreadContext())); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java b/plugin/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java index d7a3ac1781e..72df14cc19f 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java @@ -57,7 +57,7 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust private final IndexLifecycleManager securityIndex; public SecurityLifecycleService(Settings settings, ClusterService clusterService, - ThreadPool threadPool, InternalClient client, + ThreadPool threadPool, InternalSecurityClient client, @Nullable IndexAuditTrail indexAuditTrail) { super(settings); this.settings = settings; diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java b/plugin/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java index e89031f7cff..70403c5e258 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java @@ -48,6 +48,7 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportMessage; import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.audit.AuditLevel; import org.elasticsearch.xpack.security.audit.AuditTrail; import org.elasticsearch.xpack.security.authc.AuthenticationToken; @@ -177,7 +178,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl return NAME; } - public IndexAuditTrail(Settings settings, InternalClient client, ThreadPool threadPool, ClusterService clusterService) { + public IndexAuditTrail(Settings settings, InternalSecurityClient client, ThreadPool threadPool, ClusterService clusterService) { super(settings); this.threadPool = threadPool; this.clusterService = clusterService; diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/ExpiredTokenRemover.java b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/ExpiredTokenRemover.java index 455e5491ccc..2f9145da1f6 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/ExpiredTokenRemover.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/ExpiredTokenRemover.java @@ -18,6 +18,7 @@ import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool.Names; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.SecurityLifecycleService; import java.time.Instant; @@ -30,12 +31,12 @@ import static org.elasticsearch.action.support.TransportActions.isShardNotAvaila */ final class ExpiredTokenRemover extends AbstractRunnable { - private final InternalClient client; + private final InternalSecurityClient client; private final AtomicBoolean inProgress = new AtomicBoolean(false); private final Logger logger; private final TimeValue timeout; - ExpiredTokenRemover(Settings settings, InternalClient internalClient) { + ExpiredTokenRemover(Settings settings, InternalSecurityClient internalClient) { this.client = internalClient; this.logger = Loggers.getLogger(getClass(), settings); this.timeout = TokenService.DELETE_TIMEOUT.get(settings); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/TokenService.java b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/TokenService.java index 3228574c169..ee2943a8bfd 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/TokenService.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/TokenService.java @@ -50,6 +50,7 @@ import org.elasticsearch.rest.RestStatus; import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.SecurityLifecycleService; import javax.crypto.Cipher; @@ -132,7 +133,7 @@ public final class TokenService extends AbstractComponent { private final Clock clock; private final TimeValue expirationDelay; private final TimeValue deleteInterval; - private final InternalClient internalClient; + private final InternalSecurityClient internalClient; private final SecurityLifecycleService lifecycleService; private final ExpiredTokenRemover expiredTokenRemover; private final boolean enabled; @@ -148,7 +149,7 @@ public final class TokenService extends AbstractComponent { * @param clock the clock that will be used for comparing timestamps * @param internalClient the client to use when checking for revocations */ - public TokenService(Settings settings, Clock clock, InternalClient internalClient, + public TokenService(Settings settings, Clock clock, InternalSecurityClient internalClient, SecurityLifecycleService lifecycleService, ClusterService clusterService) throws GeneralSecurityException { super(settings); byte[] saltArr = new byte[SALT_BYTES]; diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStore.java b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStore.java index 0269bd4a13b..715cfbcec73 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStore.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStore.java @@ -36,6 +36,7 @@ import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheRequest; import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheResponse; @@ -73,12 +74,12 @@ public class NativeUsersStore extends AbstractComponent { private final Hasher hasher = Hasher.BCRYPT; - private final InternalClient client; + private final InternalSecurityClient client; private final boolean isTribeNode; private volatile SecurityLifecycleService securityLifecycleService; - public NativeUsersStore(Settings settings, InternalClient client, SecurityLifecycleService securityLifecycleService) { + public NativeUsersStore(Settings settings, InternalSecurityClient client, SecurityLifecycleService securityLifecycleService) { super(settings); this.client = client; this.isTribeNode = XPackPlugin.isTribeNode(settings); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStore.java b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStore.java index 3814d1d5f68..36fdc3e7816 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStore.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStore.java @@ -38,6 +38,7 @@ import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.action.rolemapping.DeleteRoleMappingRequest; import org.elasticsearch.xpack.security.action.rolemapping.PutRoleMappingRequest; @@ -70,12 +71,12 @@ public class NativeRoleMappingStore extends AbstractComponent implements UserRol private static final String SECURITY_GENERIC_TYPE = "doc"; - private final InternalClient client; + private final InternalSecurityClient client; private final boolean isTribeNode; private final SecurityLifecycleService securityLifecycleService; private final List realmsToRefresh = new CopyOnWriteArrayList<>(); - public NativeRoleMappingStore(Settings settings, InternalClient client, SecurityLifecycleService securityLifecycleService) { + public NativeRoleMappingStore(Settings settings, InternalSecurityClient client, SecurityLifecycleService securityLifecycleService) { super(settings); this.client = client; this.isTribeNode = XPackPlugin.isTribeNode(settings); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java b/plugin/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java index ffde645f299..52b650e952f 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java @@ -68,6 +68,7 @@ import org.elasticsearch.xpack.security.support.Automatons; import org.elasticsearch.xpack.security.user.AnonymousUser; import org.elasticsearch.xpack.security.user.SystemUser; import org.elasticsearch.xpack.security.user.User; +import org.elasticsearch.xpack.security.user.XPackSecurityUser; import org.elasticsearch.xpack.security.user.XPackUser; import static org.elasticsearch.xpack.security.Security.setting; @@ -290,7 +291,6 @@ public class AuthorizationService extends AbstractComponent { throw denial(authentication, action, request); } else if (indicesAccessControl.getIndexPermissions(SecurityLifecycleService.SECURITY_INDEX_NAME) != null && indicesAccessControl.getIndexPermissions(SecurityLifecycleService.SECURITY_INDEX_NAME).isGranted() - && XPackUser.is(authentication.getUser()) == false && MONITOR_INDEX_PREDICATE.test(action) == false && isSuperuser(authentication.getUser()) == false) { // only the XPackUser is allowed to work with this index, but we should allow indices monitoring actions through for debugging @@ -392,7 +392,11 @@ public class AuthorizationService extends AbstractComponent { " roles"); } if (XPackUser.is(user)) { - assert XPackUser.INSTANCE.roles().length == 1 && ReservedRolesStore.SUPERUSER_ROLE.name().equals(XPackUser.INSTANCE.roles()[0]); + assert XPackUser.INSTANCE.roles().length == 1; + roleActionListener.onResponse(XPackUser.ROLE); + return; + } + if (XPackSecurityUser.is(user)) { roleActionListener.onResponse(ReservedRolesStore.SUPERUSER_ROLE); return; } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java b/plugin/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java index 3bec9ec7667..b8109b2cbef 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java @@ -38,6 +38,7 @@ import org.elasticsearch.license.LicenseUtils; import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.action.role.ClearRolesCacheRequest; import org.elasticsearch.xpack.security.action.role.ClearRolesCacheResponse; @@ -79,14 +80,14 @@ public class NativeRolesStore extends AbstractComponent { TimeValue.timeValueMinutes(20), Property.NodeScope, Property.Deprecated); private static final String ROLE_DOC_TYPE = "doc"; - private final InternalClient client; + private final InternalSecurityClient client; private final XPackLicenseState licenseState; private final boolean isTribeNode; private SecurityClient securityClient; private final SecurityLifecycleService securityLifecycleService; - public NativeRolesStore(Settings settings, InternalClient client, XPackLicenseState licenseState, + public NativeRolesStore(Settings settings, InternalSecurityClient client, XPackLicenseState licenseState, SecurityLifecycleService securityLifecycleService) { super(settings); this.client = client; diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStore.java b/plugin/src/main/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStore.java index 585176f6c62..6967394bf85 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStore.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStore.java @@ -12,6 +12,7 @@ import org.elasticsearch.xpack.security.authz.permission.Role; import org.elasticsearch.xpack.security.support.MetadataUtils; import org.elasticsearch.xpack.security.user.KibanaUser; import org.elasticsearch.xpack.security.user.SystemUser; +import org.elasticsearch.xpack.security.user.XPackUser; import org.elasticsearch.xpack.watcher.execution.TriggeredWatchStore; import org.elasticsearch.xpack.watcher.history.HistoryStore; import org.elasticsearch.xpack.watcher.watch.Watch; @@ -126,7 +127,7 @@ public class ReservedRolesStore { } public static boolean isReserved(String role) { - return RESERVED_ROLES.containsKey(role) || SystemUser.ROLE_NAME.equals(role); + return RESERVED_ROLES.containsKey(role) || SystemUser.ROLE_NAME.equals(role) || XPackUser.ROLE_NAME.equals(role); } } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/support/IndexLifecycleManager.java b/plugin/src/main/java/org/elasticsearch/xpack/security/support/IndexLifecycleManager.java index 8cb5282a140..eee1ae4d700 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/support/IndexLifecycleManager.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/support/IndexLifecycleManager.java @@ -38,6 +38,7 @@ import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.template.TemplateUtils; import org.elasticsearch.xpack.upgrade.IndexUpgradeCheck; @@ -58,7 +59,7 @@ public class IndexLifecycleManager extends AbstractComponent { private final String indexName; private final String templateName; - private final InternalClient client; + private final InternalSecurityClient client; private final List> indexHealthChangeListeners = new CopyOnWriteArrayList<>(); @@ -70,7 +71,7 @@ public class IndexLifecycleManager extends AbstractComponent { private volatile boolean mappingIsUpToDate; private volatile Version mappingVersion; - public IndexLifecycleManager(Settings settings, InternalClient client, String indexName, String templateName) { + public IndexLifecycleManager(Settings settings, InternalSecurityClient client, String indexName, String templateName) { super(settings); this.client = client; this.indexName = indexName; diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/user/User.java b/plugin/src/main/java/org/elasticsearch/xpack/security/user/User.java index f67464c1910..1fecc61aa75 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/user/User.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/user/User.java @@ -184,6 +184,8 @@ public class User implements ToXContentObject { return SystemUser.INSTANCE; } else if (XPackUser.is(username)) { return XPackUser.INSTANCE; + } else if (XPackSecurityUser.is(username)) { + return XPackSecurityUser.INSTANCE; } throw new IllegalStateException("user [" + username + "] is not an internal user"); } @@ -214,6 +216,9 @@ public class User implements ToXContentObject { } else if (XPackUser.is(user)) { output.writeBoolean(true); output.writeString(XPackUser.NAME); + } else if (XPackSecurityUser.is(user)) { + output.writeBoolean(true); + output.writeString(XPackSecurityUser.NAME); } else { if (user.authenticatedUser == null) { // no backcompat necessary, since there is no inner user diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/user/XPackSecurityUser.java b/plugin/src/main/java/org/elasticsearch/xpack/security/user/XPackSecurityUser.java new file mode 100644 index 00000000000..b4c0cc790e9 --- /dev/null +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/user/XPackSecurityUser.java @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.security.user; + +/** + * internal user that manages xpack security. Has all cluster/indices permissions. + */ +public class XPackSecurityUser extends User { + + public static final String NAME = "_xpack_security"; + public static final XPackSecurityUser INSTANCE = new XPackSecurityUser(); + private static final String ROLE_NAME = "superuser"; + + private XPackSecurityUser() { + super(NAME, ROLE_NAME); + } + + @Override + public boolean equals(Object o) { + return INSTANCE == o; + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + public static boolean is(User user) { + return INSTANCE.equals(user); + } + + public static boolean is(String principal) { + return NAME.equals(principal); + } +} diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/user/XPackUser.java b/plugin/src/main/java/org/elasticsearch/xpack/security/user/XPackUser.java index 2f95cd9998d..56b5ecce224 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/user/XPackUser.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/user/XPackUser.java @@ -5,13 +5,22 @@ */ package org.elasticsearch.xpack.security.user; +import org.elasticsearch.xpack.security.authz.RoleDescriptor; +import org.elasticsearch.xpack.security.authz.permission.Role; +import org.elasticsearch.xpack.security.support.MetadataUtils; + /** - * XPack internal user that manages xpack. Has all cluster/indices permissions for x-pack to operate. + * XPack internal user that manages xpack. Has all cluster/indices permissions for x-pack to operate excluding security permissions. */ public class XPackUser extends User { public static final String NAME = "_xpack"; - private static final String ROLE_NAME = "superuser"; + public static final String ROLE_NAME = NAME; + public static final Role ROLE = Role.builder(new RoleDescriptor(ROLE_NAME, new String[] { "all" }, + new RoleDescriptor.IndicesPrivileges[] { + RoleDescriptor.IndicesPrivileges.builder().indices("/@&~(\\.security*)/").privileges("all").build()}, + new String[] { "*" }, + MetadataUtils.DEFAULT_RESERVED_METADATA), null).build(); public static final XPackUser INSTANCE = new XPackUser(); private XPackUser() { diff --git a/plugin/src/main/java/org/elasticsearch/xpack/upgrade/Upgrade.java b/plugin/src/main/java/org/elasticsearch/xpack/upgrade/Upgrade.java index 8868047d107..627082f8bc5 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/upgrade/Upgrade.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/upgrade/Upgrade.java @@ -8,6 +8,7 @@ package org.elasticsearch.xpack.upgrade; import org.elasticsearch.Version; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.client.Client; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.node.DiscoveryNodes; @@ -24,6 +25,7 @@ import org.elasticsearch.script.ScriptService; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.upgrade.actions.IndexUpgradeAction; import org.elasticsearch.xpack.upgrade.actions.IndexUpgradeInfoAction; import org.elasticsearch.xpack.upgrade.rest.RestIndexUpgradeAction; @@ -53,12 +55,13 @@ public class Upgrade implements ActionPlugin { this.upgradeCheckFactories = new ArrayList<>(); } - public Collection createComponents(InternalClient internalClient, ClusterService clusterService, ThreadPool threadPool, + public Collection createComponents(Client client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, ScriptService scriptService, NamedXContentRegistry xContentRegistry) { + final InternalSecurityClient internalSecurityClient = new InternalSecurityClient(settings, threadPool, client); List upgradeChecks = new ArrayList<>(upgradeCheckFactories.size()); for (BiFunction checkFactory : upgradeCheckFactories) { - upgradeChecks.add(checkFactory.apply(internalClient, clusterService)); + upgradeChecks.add(checkFactory.apply(internalSecurityClient, clusterService)); } return Collections.singletonList(new IndexUpgradeService(settings, Collections.unmodifiableList(upgradeChecks))); } diff --git a/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java b/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java index 20ab893812d..3d3e378d5eb 100644 --- a/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java +++ b/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java @@ -35,6 +35,7 @@ import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.ml.MachineLearning; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.client.SecurityClient; import org.junit.AfterClass; @@ -438,6 +439,11 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase { return internalCluster().getInstance(InternalClient.class); } + protected InternalSecurityClient internalSecurityClient() { + Client client = client(); + return new InternalSecurityClient(client.settings(), client.threadPool(), client); + } + protected SecurityClient securityClient() { return securityClient(client()); } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityLifecycleServiceTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityLifecycleServiceTests.java index 8e121c861b6..242d5134331 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityLifecycleServiceTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityLifecycleServiceTests.java @@ -64,7 +64,7 @@ public class SecurityLifecycleServiceTests extends ESTestCase { threadPool = new TestThreadPool("security template service tests"); transportClient = new MockTransportClient(Settings.EMPTY); - class IClient extends InternalClient { + class IClient extends InternalSecurityClient { IClient(Client transportClient) { super(Settings.EMPTY, null, transportClient); } @@ -79,7 +79,7 @@ public class SecurityLifecycleServiceTests extends ESTestCase { } } - InternalClient client = new IClient(transportClient); + InternalSecurityClient client = new IClient(transportClient); securityLifecycleService = new SecurityLifecycleService(Settings.EMPTY, clusterService, threadPool, client, mock(IndexAuditTrail.class)); listeners = new CopyOnWriteArrayList<>(); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java index d0c4095a3dd..768a4e3e346 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java @@ -77,9 +77,9 @@ public class SecurityTests extends ESTestCase { allowedSettings.addAll(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); ClusterSettings clusterSettings = new ClusterSettings(settings, allowedSettings); when(clusterService.getClusterSettings()).thenReturn(clusterSettings); - InternalClient client = new InternalClient(Settings.EMPTY, threadPool, mock(Client.class)); when(threadPool.relativeTimeInMillis()).thenReturn(1L); - return security.createComponents(client, threadPool, clusterService, mock(ResourceWatcherService.class), Arrays.asList(extensions)); + return security.createComponents(mock(Client.class), threadPool, clusterService, mock(ResourceWatcherService.class), + Arrays.asList(extensions)); } private T findComponent(Class type, Collection components) { diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java index 7b57b1825c6..2227c17c58e 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java @@ -141,7 +141,7 @@ public class AuditTrailTests extends SecurityIntegTestCase { return eventsRef.get(); } private Collection> getAuditEvents() throws Exception { - final InternalClient client = internalClient(); + final InternalClient client = internalSecurityClient(); DateTime now = new DateTime(DateTimeZone.UTC); String indexName = IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now, IndexNameResolver.Rollover.DAILY); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailMutedTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailMutedTests.java index fd685b33db0..7d2eb216249 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailMutedTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailMutedTests.java @@ -27,6 +27,7 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.MockTransportClient; import org.elasticsearch.transport.TransportMessage; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail.State; import org.elasticsearch.xpack.security.authc.AuthenticationToken; import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule; @@ -42,7 +43,7 @@ import static org.mockito.Mockito.when; public class IndexAuditTrailMutedTests extends ESTestCase { - private InternalClient client; + private InternalSecurityClient client; private TransportClient transportClient; private ThreadPool threadPool; private ClusterService clusterService; @@ -61,7 +62,7 @@ public class IndexAuditTrailMutedTests extends ESTestCase { threadPool = new TestThreadPool("index audit trail tests"); transportClient = new MockTransportClient(Settings.EMPTY); clientCalled = new AtomicBoolean(false); - class IClient extends InternalClient { + class IClient extends InternalSecurityClient { IClient(Client transportClient){ super(Settings.EMPTY, threadPool, transportClient); } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java index cbaf1f5aab6..0943f19ef1e 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java @@ -295,7 +295,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase { when(nodes.isLocalNodeElectedMaster()).thenReturn(true); threadPool = new TestThreadPool("index audit trail tests"); enqueuedMessage = new SetOnce<>(); - auditor = new IndexAuditTrail(settings, internalClient(), threadPool, clusterService) { + auditor = new IndexAuditTrail(settings, internalSecurityClient(), threadPool, clusterService) { @Override void enqueue(Message message, String type) { enqueuedMessage.set(message); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailUpdateMappingTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailUpdateMappingTests.java index 9bad1d5c10b..9e7a98ce0e1 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailUpdateMappingTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailUpdateMappingTests.java @@ -50,7 +50,7 @@ public class IndexAuditTrailUpdateMappingTests extends SecurityIntegTestCase { when(localNode.getHostAddress()).thenReturn(buildNewFakeTransportAddress().toString()); ClusterService clusterService = mock(ClusterService.class); when(clusterService.localNode()).thenReturn(localNode); - auditor = new IndexAuditTrail(settings, internalClient(), threadPool, clusterService); + auditor = new IndexAuditTrail(settings, internalSecurityClient(), threadPool, clusterService); // before starting we add an event auditor.authenticationFailed(new FakeRestRequest()); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java index 96592d47b55..0aade415557 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java @@ -48,6 +48,7 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportMessage; import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.audit.AuditTrailService; import org.elasticsearch.xpack.security.authc.Authentication.RealmRef; @@ -135,7 +136,7 @@ public class AuthenticationServiceTests extends ESTestCase { threadPool = new ThreadPool(settings, new FixedExecutorBuilder(settings, TokenService.THREAD_POOL_NAME, 1, 1000, "xpack.security.authc.token.thread_pool")); threadContext = threadPool.getThreadContext(); - InternalClient internalClient = new InternalClient(Settings.EMPTY, threadPool, client); + InternalSecurityClient internalClient = new InternalSecurityClient(Settings.EMPTY, threadPool, client); lifecycleService = mock(SecurityLifecycleService.class); ClusterService clusterService = new ClusterService(settings, new ClusterSettings(settings, ClusterSettings .BUILT_IN_CLUSTER_SETTINGS), threadPool, Collections.emptyMap()); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenAuthIntegTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenAuthIntegTests.java index e5df63c1429..8706c9dd48b 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenAuthIntegTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenAuthIntegTests.java @@ -56,7 +56,7 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase { } public void testTokenServiceBootstrapOnNodeJoin() throws Exception { - final Client client = internalClient(); + final Client client = internalSecurityClient(); SecurityClient securityClient = new SecurityClient(client); CreateTokenResponse response = securityClient.prepareCreateToken() .setGrantType("password") @@ -84,7 +84,7 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase { public void testTokenServiceCanRotateKeys() throws Exception { - final Client client = internalClient(); + final Client client = internalSecurityClient(); SecurityClient securityClient = new SecurityClient(client); CreateTokenResponse response = securityClient.prepareCreateToken() .setGrantType("password") @@ -116,7 +116,7 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase { } public void testExpiredTokensDeletedAfterExpiration() throws Exception { - final Client client = internalClient(); + final Client client = internalSecurityClient(); SecurityClient securityClient = new SecurityClient(client); CreateTokenResponse response = securityClient.prepareCreateToken() .setGrantType("password") diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java index 31e8e1d924e..a973e3e1492 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java @@ -24,6 +24,7 @@ import org.elasticsearch.threadpool.FixedExecutorBuilder; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.authc.Authentication.RealmRef; import org.elasticsearch.xpack.security.authc.TokenService.BytesKey; @@ -49,7 +50,7 @@ import static org.mockito.Mockito.when; public class TokenServiceTests extends ESTestCase { - private InternalClient internalClient; + private InternalSecurityClient internalClient; private static ThreadPool threadPool; private static final Settings settings = Settings.builder().put(Node.NODE_NAME_SETTING.getKey(), "TokenServiceTests") .put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build(); @@ -63,7 +64,7 @@ public class TokenServiceTests extends ESTestCase { @Before public void setupClient() throws GeneralSecurityException { client = mock(Client.class); - internalClient = new InternalClient(settings, threadPool, client); + internalClient = new InternalSecurityClient(settings, threadPool, client); lifecycleService = mock(SecurityLifecycleService.class); when(lifecycleService.isSecurityIndexWriteable()).thenReturn(true); doAnswer(invocationOnMock -> { diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStoreTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStoreTests.java index b75c314a23b..c92e2640b36 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStoreTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStoreTests.java @@ -29,6 +29,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.get.GetResult; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.authc.AuthenticationResult; import org.elasticsearch.xpack.security.authc.support.Hasher; @@ -54,12 +55,12 @@ public class NativeUsersStoreTests extends ESTestCase { private static final String PASSWORD_FIELD = User.Fields.PASSWORD.getPreferredName(); private static final String BLANK_PASSWORD = ""; - private InternalClient internalClient; + private InternalSecurityClient internalClient; private final List>> requests = new CopyOnWriteArrayList<>(); @Before public void setupMocks() { - internalClient = new InternalClient(Settings.EMPTY, null, null) { + internalClient = new InternalSecurityClient(Settings.EMPTY, null, null) { @Override protected < diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeUserRoleMapperTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeUserRoleMapperTests.java index 39f5146f8ca..819b4f6ab1c 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeUserRoleMapperTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeUserRoleMapperTests.java @@ -17,6 +17,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.authc.RealmConfig; import org.elasticsearch.xpack.security.authc.support.UserRoleMapper; @@ -53,7 +54,7 @@ public class NativeUserRoleMapperTests extends ESTestCase { Collections.singletonList(FieldPredicate.create("cn=mutants,ou=groups,ou=dept_h,o=forces,dc=gc,dc=ca"))), Arrays.asList("mutants"), Collections.emptyMap(), false); - final InternalClient client = mock(InternalClient.class); + final InternalSecurityClient client = mock(InternalSecurityClient.class); final SecurityLifecycleService lifecycleService = mock(SecurityLifecycleService.class); when(lifecycleService.isSecurityIndexAvailable()).thenReturn(true); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java index f40f215e0a3..71aad327267 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java @@ -715,7 +715,7 @@ public class AuthorizationServiceTests extends ESTestCase { } } - public void testXPackUserAndSuperusersCanExecuteOperationAgainstSecurityIndex() { + public void testSuperusersCanExecuteOperationAgainstSecurityIndex() { final User superuser = new User("custom_admin", ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName()); roleMap.put(ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName(), ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR); ClusterState state = mock(ClusterState.class); @@ -726,37 +726,35 @@ public class AuthorizationServiceTests extends ESTestCase { .numberOfShards(1).numberOfReplicas(0).build(), true) .build()); - for (User user : Arrays.asList(XPackUser.INSTANCE, superuser)) { - List> requests = new ArrayList<>(); - requests.add(new Tuple<>(DeleteAction.NAME, new DeleteRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "type", "id"))); - requests.add(new Tuple<>(BulkAction.NAME + "[s]", - createBulkShardRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, DeleteRequest::new))); - requests.add(new Tuple<>(UpdateAction.NAME, new UpdateRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "type", "id"))); - requests.add(new Tuple<>(IndexAction.NAME, new IndexRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "type", "id"))); - requests.add(new Tuple<>(BulkAction.NAME + "[s]", - createBulkShardRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, IndexRequest::new))); - requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(SecurityLifecycleService.SECURITY_INDEX_NAME))); - requests.add(new Tuple<>(TermVectorsAction.NAME, - new TermVectorsRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "type", "id"))); - requests.add(new Tuple<>(GetAction.NAME, new GetRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "type", "id"))); - requests.add(new Tuple<>(TermVectorsAction.NAME, - new TermVectorsRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "type", "id"))); - requests.add(new Tuple<>(IndicesAliasesAction.NAME, new IndicesAliasesRequest() - .addAliasAction(AliasActions.add().alias("security_alias").index(SecurityLifecycleService.SECURITY_INDEX_NAME)))); - requests.add(new Tuple<>(ClusterHealthAction.NAME, new ClusterHealthRequest(SecurityLifecycleService.SECURITY_INDEX_NAME))); - requests.add(new Tuple<>(ClusterHealthAction.NAME, - new ClusterHealthRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "foo", "bar"))); + List> requests = new ArrayList<>(); + requests.add(new Tuple<>(DeleteAction.NAME, new DeleteRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(BulkAction.NAME + "[s]", + createBulkShardRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, DeleteRequest::new))); + requests.add(new Tuple<>(UpdateAction.NAME, new UpdateRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(IndexAction.NAME, new IndexRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(BulkAction.NAME + "[s]", + createBulkShardRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, IndexRequest::new))); + requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(SecurityLifecycleService.SECURITY_INDEX_NAME))); + requests.add(new Tuple<>(TermVectorsAction.NAME, + new TermVectorsRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(GetAction.NAME, new GetRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(TermVectorsAction.NAME, + new TermVectorsRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(IndicesAliasesAction.NAME, new IndicesAliasesRequest() + .addAliasAction(AliasActions.add().alias("security_alias").index(SecurityLifecycleService.SECURITY_INDEX_NAME)))); + requests.add(new Tuple<>(ClusterHealthAction.NAME, new ClusterHealthRequest(SecurityLifecycleService.SECURITY_INDEX_NAME))); + requests.add(new Tuple<>(ClusterHealthAction.NAME, + new ClusterHealthRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "foo", "bar"))); - for (Tuple requestTuple : requests) { - String action = requestTuple.v1(); - TransportRequest request = requestTuple.v2(); - authorize(createAuthentication(user), action, request); - verify(auditTrail).accessGranted(user, action, request); - } + for (Tuple requestTuple : requests) { + String action = requestTuple.v1(); + TransportRequest request = requestTuple.v2(); + authorize(createAuthentication(superuser), action, request); + verify(auditTrail).accessGranted(superuser, action, request); } } - public void testXPackUserAndSuperusersCanExecuteOperationAgainstSecurityIndexWithWildcard() { + public void testSuperusersCanExecuteOperationAgainstSecurityIndexWithWildcard() { final User superuser = new User("custom_admin", ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName()); roleMap.put(ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName(), ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR); ClusterState state = mock(ClusterState.class); @@ -769,11 +767,6 @@ public class AuthorizationServiceTests extends ESTestCase { String action = SearchAction.NAME; SearchRequest request = new SearchRequest("_all"); - authorize(createAuthentication(XPackUser.INSTANCE), action, request); - verify(auditTrail).accessGranted(XPackUser.INSTANCE, action, request); - assertThat(request.indices(), arrayContaining(".security")); - - request = new SearchRequest("_all"); authorize(createAuthentication(superuser), action, request); verify(auditTrail).accessGranted(superuser, action, request); assertThat(request.indices(), arrayContaining(".security")); @@ -1073,7 +1066,7 @@ public class AuthorizationServiceTests extends ESTestCase { PlainActionFuture rolesFuture = new PlainActionFuture<>(); authorizationService.roles(XPackUser.INSTANCE, rolesFuture); final Role roles = rolesFuture.actionGet(); - assertThat(roles, equalTo(ReservedRolesStore.SUPERUSER_ROLE)); + assertThat(roles, equalTo(XPackUser.ROLE)); verifyZeroInteractions(rolesStore); } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authz/IndicesAndAliasesResolverTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authz/IndicesAndAliasesResolverTests.java index b703c1cfe95..8ad435db957 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authz/IndicesAndAliasesResolverTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authz/IndicesAndAliasesResolverTests.java @@ -69,6 +69,7 @@ import org.elasticsearch.xpack.security.authz.store.ReservedRolesStore; import org.elasticsearch.xpack.security.test.SecurityTestUtils; import org.elasticsearch.xpack.security.user.AnonymousUser; import org.elasticsearch.xpack.security.user.User; +import org.elasticsearch.xpack.security.user.XPackSecurityUser; import org.elasticsearch.xpack.security.user.XPackUser; import org.junit.Before; @@ -1191,22 +1192,29 @@ public class IndicesAndAliasesResolverTests extends ESTestCase { } } - public void testXPackUserHasAccessToSecurityIndex() { + public void testXPackSecurityUserHasAccessToSecurityIndex() { SearchRequest request = new SearchRequest(); { - final AuthorizedIndices authorizedIndices = buildAuthorizedIndices(XPackUser.INSTANCE, SearchAction.NAME); + final AuthorizedIndices authorizedIndices = buildAuthorizedIndices(XPackSecurityUser.INSTANCE, SearchAction.NAME); List indices = resolveIndices(request, authorizedIndices).getLocal(); assertThat(indices, hasItem(SecurityLifecycleService.SECURITY_INDEX_NAME)); } { IndicesAliasesRequest aliasesRequest = new IndicesAliasesRequest(); aliasesRequest.addAliasAction(AliasActions.add().alias("security_alias").index(SecurityLifecycleService.SECURITY_INDEX_NAME)); - final AuthorizedIndices authorizedIndices = buildAuthorizedIndices(XPackUser.INSTANCE, IndicesAliasesAction.NAME); + final AuthorizedIndices authorizedIndices = buildAuthorizedIndices(XPackSecurityUser.INSTANCE, IndicesAliasesAction.NAME); List indices = resolveIndices(aliasesRequest, authorizedIndices).getLocal(); assertThat(indices, hasItem(SecurityLifecycleService.SECURITY_INDEX_NAME)); } } + public void testXPackUserDoesNotHaveAccessToSecurityIndex() { + SearchRequest request = new SearchRequest(); + final AuthorizedIndices authorizedIndices = buildAuthorizedIndices(XPackUser.INSTANCE, SearchAction.NAME); + List indices = resolveIndices(request, authorizedIndices).getLocal(); + assertThat(indices, not(hasItem(SecurityLifecycleService.SECURITY_INDEX_NAME))); + } + public void testNonXPackUserAccessingSecurityIndex() { User allAccessUser = new User("all_access", "all_access"); roleMap.put("all_access", new RoleDescriptor("all_access", new String[] { "all" }, diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStoreTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStoreTests.java index f51abbb4c54..e78a2301ff9 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStoreTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStoreTests.java @@ -38,6 +38,7 @@ import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.action.role.PutRoleRequest; import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail; @@ -184,7 +185,7 @@ public class NativeRolesStoreTests extends ESTestCase { } public void testPutOfRoleWithFlsDlsUnlicensed() throws IOException { - final InternalClient internalClient = mock(InternalClient.class); + final InternalSecurityClient internalClient = mock(InternalSecurityClient.class); final ClusterService clusterService = mock(ClusterService.class); final XPackLicenseState licenseState = mock(XPackLicenseState.class); final AtomicBoolean methodCalled = new AtomicBoolean(false); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStoreTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStoreTests.java index d1741ca2b0e..438d3498940 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStoreTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStoreTests.java @@ -80,6 +80,7 @@ import org.elasticsearch.xpack.security.authz.accesscontrol.IndicesAccessControl import org.elasticsearch.xpack.security.authz.permission.FieldPermissionsCache; import org.elasticsearch.xpack.security.authz.permission.Role; import org.elasticsearch.xpack.security.user.SystemUser; +import org.elasticsearch.xpack.security.user.XPackUser; import org.elasticsearch.xpack.watcher.execution.TriggeredWatchStore; import org.elasticsearch.xpack.watcher.history.HistoryStore; import org.elasticsearch.xpack.watcher.transport.actions.ack.AckWatchAction; @@ -123,6 +124,7 @@ public class ReservedRolesStoreTests extends ESTestCase { assertThat(ReservedRolesStore.isReserved("watcher_user"), is(true)); assertThat(ReservedRolesStore.isReserved("watcher_admin"), is(true)); assertThat(ReservedRolesStore.isReserved("kibana_dashboard_only_user"), is(true)); + assertThat(ReservedRolesStore.isReserved(XPackUser.ROLE_NAME), is(true)); } public void testIngestAdminRole() { diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/support/IndexLifecycleManagerTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/support/IndexLifecycleManagerTests.java index dbb4d74b20c..731325dfd42 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/support/IndexLifecycleManagerTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/support/IndexLifecycleManagerTests.java @@ -45,6 +45,7 @@ import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.security.InternalSecurityClient; import org.elasticsearch.xpack.security.test.SecurityTestUtils; import org.elasticsearch.xpack.template.TemplateUtils; import org.hamcrest.Matchers; @@ -71,7 +72,7 @@ public class IndexLifecycleManagerTests extends ESTestCase { when(threadPool.getThreadContext()).thenReturn(new ThreadContext(Settings.EMPTY)); actions = new LinkedHashMap<>(); - final InternalClient client = new InternalClient(Settings.EMPTY, threadPool, mockClient) { + final InternalSecurityClient client = new InternalSecurityClient(Settings.EMPTY, threadPool, mockClient) { @Override protected