Просмотр исходного кода

Refactor: Define internal users in a single place (#95649)

This commit refactors the way Internal Users are accessed so that there
is a single class (`InternalUsers`) that defines the complete set of
internal users, their names and their role descriptors (if any).

This means that there is a single places to change when adding a new
Internal User (along with the creation of the user itself)

Relates: #95506
Tim Vernum 2 лет назад
Родитель
Сommit
401413fa3d

+ 3 - 36
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java

@@ -34,13 +34,8 @@ import org.elasticsearch.xpack.core.security.authc.service.ServiceAccountSetting
 import org.elasticsearch.xpack.core.security.authc.support.AuthenticationContextSerializer;
 import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
 import org.elasticsearch.xpack.core.security.user.AnonymousUser;
-import org.elasticsearch.xpack.core.security.user.AsyncSearchUser;
-import org.elasticsearch.xpack.core.security.user.CrossClusterAccessUser;
-import org.elasticsearch.xpack.core.security.user.SecurityProfileUser;
-import org.elasticsearch.xpack.core.security.user.SystemUser;
+import org.elasticsearch.xpack.core.security.user.InternalUsers;
 import org.elasticsearch.xpack.core.security.user.User;
-import org.elasticsearch.xpack.core.security.user.XPackSecurityUser;
-import org.elasticsearch.xpack.core.security.user.XPackUser;
 
 import java.io.IOException;
 import java.io.UncheckedIOException;
@@ -1473,20 +1468,7 @@ public final class Authentication implements ToXContentObject {
             final boolean isInternalUser = input.readBoolean();
             final String username = input.readString();
             if (isInternalUser) {
-                if (SystemUser.NAME.equals(username)) {
-                    return SystemUser.INSTANCE;
-                } else if (XPackUser.NAME.equals(username)) {
-                    return XPackUser.INSTANCE;
-                } else if (XPackSecurityUser.NAME.equals(username)) {
-                    return XPackSecurityUser.INSTANCE;
-                } else if (SecurityProfileUser.NAME.equals(username)) {
-                    return SecurityProfileUser.INSTANCE;
-                } else if (AsyncSearchUser.NAME.equals(username)) {
-                    return AsyncSearchUser.INSTANCE;
-                } else if (CrossClusterAccessUser.NAME.equals(username)) {
-                    return CrossClusterAccessUser.INSTANCE;
-                }
-                throw new IllegalStateException("username [" + username + "] does not match any internal user");
+                return InternalUsers.getUser(username);
             }
             String[] roles = input.readStringArray();
             Map<String, Object> metadata = input.readMap();
@@ -1499,22 +1481,7 @@ public final class Authentication implements ToXContentObject {
         private static void writeInternalUser(User user, StreamOutput output) throws IOException {
             assert User.isInternal(user);
             output.writeBoolean(true);
-            if (SystemUser.is(user)) {
-                output.writeString(SystemUser.NAME);
-            } else if (XPackUser.is(user)) {
-                output.writeString(XPackUser.NAME);
-            } else if (XPackSecurityUser.is(user)) {
-                output.writeString(XPackSecurityUser.NAME);
-            } else if (SecurityProfileUser.is(user)) {
-                output.writeString(SecurityProfileUser.NAME);
-            } else if (AsyncSearchUser.is(user)) {
-                output.writeString(AsyncSearchUser.NAME);
-            } else if (CrossClusterAccessUser.is(user)) {
-                output.writeString(CrossClusterAccessUser.NAME);
-            } else {
-                assert false;
-                throw new IllegalStateException("user [" + user + "] is not internal");
-            }
+            output.writeString(InternalUsers.getInternalUserName(user));
         }
     }
 }

+ 99 - 0
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/InternalUsers.java

@@ -0,0 +1,99 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.core.security.user;
+
+import org.elasticsearch.core.Nullable;
+import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+public class InternalUsers {
+
+    private record UserInstance(User user, @Nullable RoleDescriptor role, Predicate<User> isUserPredicate) {
+        private UserInstance {
+            // Check that the parameters align
+            assert User.isInternal(user) : "User " + user + " is not internal";
+            // The role descriptor should match the user name as well
+            assert role == null || user.principal().equals(role.getName())
+                : "Internal user " + user + " should have a role named [" + user.principal() + "] but was [" + role.getName() + "]";
+            // : The user object should match as an instance of the user.
+            assert isUserPredicate.test(user) : "User " + user + " does not match provided predicate";
+        }
+
+        public boolean is(User u) {
+            return isUserPredicate.test(u);
+        }
+    }
+
+    private static final Map<String, UserInstance> INTERNAL_USERS = new HashMap<>();
+    static {
+        defineUser(
+            SystemUser.NAME,
+            SystemUser.INSTANCE,
+            null /* SystemUser relies on a simple action predicate rather than a role descriptor */,
+            SystemUser::is
+        );
+        defineUser(XPackUser.NAME, XPackUser.INSTANCE, XPackUser.ROLE_DESCRIPTOR, XPackUser::is);
+        defineUser(XPackSecurityUser.NAME, XPackSecurityUser.INSTANCE, XPackSecurityUser.ROLE_DESCRIPTOR, XPackSecurityUser::is);
+        defineUser(SecurityProfileUser.NAME, SecurityProfileUser.INSTANCE, SecurityProfileUser.ROLE_DESCRIPTOR, SecurityProfileUser::is);
+        defineUser(AsyncSearchUser.NAME, AsyncSearchUser.INSTANCE, AsyncSearchUser.ROLE_DESCRIPTOR, AsyncSearchUser::is);
+        defineUser(
+            CrossClusterAccessUser.NAME,
+            CrossClusterAccessUser.INSTANCE,
+            null /* CrossClusterAccessUser has a role descriptor, but it should never be resolved by this class */,
+            CrossClusterAccessUser::is
+        );
+    }
+
+    private static void defineUser(String name, User user, @Nullable RoleDescriptor roleDescriptor, Predicate<User> predicate) {
+        assert name.equals(user.principal())
+            : "User " + user + " has a principal [" + user.principal() + "] that does not match the provided name [" + name + "]";
+        INTERNAL_USERS.put(name, new UserInstance(user, roleDescriptor, predicate));
+    }
+
+    private static UserInstance findInternalUser(User user) {
+        final UserInstance instance = INTERNAL_USERS.get(user.principal());
+        if (instance != null && instance.is(user)) {
+            return instance;
+        }
+        throw new IllegalStateException("user [" + user + "] is not internal");
+    }
+
+    public static User getUser(String username) {
+        final UserInstance instance = INTERNAL_USERS.get(username);
+        if (instance == null) {
+            throw new IllegalStateException("user [" + username + "] is not internal");
+        }
+        return instance.user;
+    }
+
+    public static String getInternalUserName(User user) {
+        assert User.isInternal(user);
+        return findInternalUser(user).user.principal();
+    }
+
+    public static RoleDescriptor getRoleDescriptor(User user) {
+        assert User.isInternal(user);
+        UserInstance instance = findInternalUser(user);
+        if (instance.role == null) {
+            throw new IllegalArgumentException("should never try to get the roles for internal user [" + user.principal() + "]");
+        }
+        return instance.role;
+    }
+
+    public static Map<String, RoleDescriptor> getRoleDescriptors() {
+        return INTERNAL_USERS.values()
+            .stream()
+            .filter(instance -> instance.role != null)
+            .collect(Collectors.toMap(instance -> instance.user().principal(), UserInstance::role));
+    }
+
+}

+ 1 - 0
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/User.java

@@ -148,6 +148,7 @@ public class User implements ToXContentObject {
     }
 
     public static boolean isInternal(User user) {
+        // TODO : Drop this method and rely entirely on the InternalUsers class
         return SystemUser.is(user)
             || XPackUser.is(user)
             || XPackSecurityUser.is(user)

+ 67 - 0
x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/user/InternalUsersTests.java

@@ -0,0 +1,67 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.core.security.user;
+
+import org.elasticsearch.test.ESTestCase;
+
+import static org.elasticsearch.test.TestMatchers.throwableWithMessage;
+import static org.hamcrest.Matchers.is;
+
+public class InternalUsersTests extends ESTestCase {
+
+    public void testSystemUser() {
+        assertThat(InternalUsers.getUser("_system"), is(SystemUser.INSTANCE));
+        assertThat(InternalUsers.getInternalUserName(SystemUser.INSTANCE), is("_system"));
+        final IllegalArgumentException e = expectThrows(
+            IllegalArgumentException.class,
+            () -> InternalUsers.getRoleDescriptor(SystemUser.INSTANCE)
+        );
+        assertThat(e, throwableWithMessage("should never try to get the roles for internal user [_system]"));
+    }
+
+    public void testXPackUser() {
+        assertThat(InternalUsers.getUser("_xpack"), is(XPackUser.INSTANCE));
+        assertThat(InternalUsers.getInternalUserName(XPackUser.INSTANCE), is("_xpack"));
+        assertThat(InternalUsers.getRoleDescriptor(XPackUser.INSTANCE), is(XPackUser.ROLE_DESCRIPTOR));
+    }
+
+    public void testXPackSecurityUser() {
+        assertThat(InternalUsers.getUser("_xpack_security"), is(XPackSecurityUser.INSTANCE));
+        assertThat(InternalUsers.getInternalUserName(XPackSecurityUser.INSTANCE), is("_xpack_security"));
+        assertThat(InternalUsers.getRoleDescriptor(XPackSecurityUser.INSTANCE), is(XPackSecurityUser.ROLE_DESCRIPTOR));
+    }
+
+    public void testSecurityProfileUser() {
+        assertThat(InternalUsers.getUser("_security_profile"), is(SecurityProfileUser.INSTANCE));
+        assertThat(InternalUsers.getInternalUserName(SecurityProfileUser.INSTANCE), is("_security_profile"));
+        assertThat(InternalUsers.getRoleDescriptor(SecurityProfileUser.INSTANCE), is(SecurityProfileUser.ROLE_DESCRIPTOR));
+    }
+
+    public void testAsyncSearchUser() {
+        assertThat(InternalUsers.getUser("_async_search"), is(AsyncSearchUser.INSTANCE));
+        assertThat(InternalUsers.getInternalUserName(AsyncSearchUser.INSTANCE), is("_async_search"));
+        assertThat(InternalUsers.getRoleDescriptor(AsyncSearchUser.INSTANCE), is(AsyncSearchUser.ROLE_DESCRIPTOR));
+    }
+
+    public void testCrossClusterAccessUser() {
+        assertThat(InternalUsers.getUser("_cross_cluster_access"), is(CrossClusterAccessUser.INSTANCE));
+        assertThat(InternalUsers.getInternalUserName(CrossClusterAccessUser.INSTANCE), is("_cross_cluster_access"));
+        final IllegalArgumentException e = expectThrows(
+            IllegalArgumentException.class,
+            () -> InternalUsers.getRoleDescriptor(CrossClusterAccessUser.INSTANCE)
+        );
+        assertThat(e, throwableWithMessage("should never try to get the roles for internal user [_cross_cluster_access]"));
+    }
+
+    public void testRegularUser() {
+        var username = randomAlphaOfLengthBetween(4, 12);
+        expectThrows(IllegalStateException.class, () -> InternalUsers.getUser(username));
+        // Can't test other methods because they have an assert that the provided user is internal
+    }
+
+}

+ 27 - 90
x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java

@@ -46,13 +46,8 @@ import org.elasticsearch.xpack.core.security.authz.store.RoleReferenceIntersecti
 import org.elasticsearch.xpack.core.security.authz.store.RolesRetrievalResult;
 import org.elasticsearch.xpack.core.security.support.CacheIteratorHelper;
 import org.elasticsearch.xpack.core.security.user.AnonymousUser;
-import org.elasticsearch.xpack.core.security.user.AsyncSearchUser;
-import org.elasticsearch.xpack.core.security.user.CrossClusterAccessUser;
-import org.elasticsearch.xpack.core.security.user.SecurityProfileUser;
-import org.elasticsearch.xpack.core.security.user.SystemUser;
+import org.elasticsearch.xpack.core.security.user.InternalUsers;
 import org.elasticsearch.xpack.core.security.user.User;
-import org.elasticsearch.xpack.core.security.user.XPackSecurityUser;
-import org.elasticsearch.xpack.core.security.user.XPackUser;
 import org.elasticsearch.xpack.security.authc.ApiKeyService;
 import org.elasticsearch.xpack.security.authc.service.ServiceAccountService;
 import org.elasticsearch.xpack.security.support.SecurityIndexManager;
@@ -105,10 +100,7 @@ public class CompositeRolesStore {
     private final AtomicLong numInvalidation = new AtomicLong();
     private final RoleDescriptorStore roleReferenceResolver;
     private final Role superuserRole;
-    private final Role xpackSecurityRole;
-    private final Role securityProfileRole;
-    private final Role xpackUserRole;
-    private final Role asyncSearchUserRole;
+    private final Map<String, Role> internalUserRoles;
     private final RestrictedIndices restrictedIndices;
 
     public CompositeRolesStore(
@@ -159,23 +151,15 @@ public class CompositeRolesStore {
             fieldPermissionsCache,
             this.restrictedIndices
         );
-        this.xpackSecurityRole = Role.buildFromRoleDescriptor(
-            XPackSecurityUser.ROLE_DESCRIPTOR,
-            fieldPermissionsCache,
-            this.restrictedIndices
-        );
-        this.securityProfileRole = Role.buildFromRoleDescriptor(
-            SecurityProfileUser.ROLE_DESCRIPTOR,
-            fieldPermissionsCache,
-            this.restrictedIndices
-        );
-        this.xpackUserRole = Role.buildFromRoleDescriptor(XPackUser.ROLE_DESCRIPTOR, fieldPermissionsCache, this.restrictedIndices);
-        this.asyncSearchUserRole = Role.buildFromRoleDescriptor(
-            AsyncSearchUser.ROLE_DESCRIPTOR,
-            fieldPermissionsCache,
-            this.restrictedIndices
-        );
-
+        this.internalUserRoles = InternalUsers.getRoleDescriptors()
+            .entrySet()
+            .stream()
+            .collect(
+                Collectors.toMap(
+                    Map.Entry::getKey,
+                    e -> Role.buildFromRoleDescriptor(e.getValue(), fieldPermissionsCache, this.restrictedIndices)
+                )
+            );
         this.roleReferenceResolver = new RoleDescriptorStore(
             roleProviders,
             apiKeyService,
@@ -226,31 +210,22 @@ public class CompositeRolesStore {
         // method.
         // The other internal users have directly assigned roles that are handled with special cases here
         final User user = subject.getUser();
-        if (SystemUser.is(user)) {
-            throw new IllegalArgumentException(
-                "the user [" + user.principal() + "] is the system user and we should never try to get its roles"
-            );
-        }
-        if (CrossClusterAccessUser.is(user)) {
-            throw new IllegalArgumentException(
-                "the user [" + user.principal() + "] is the cross cluster access user and we should never try to get its roles"
-            );
-        }
-        if (XPackUser.is(user)) {
-            return xpackUserRole;
-        }
-        if (XPackSecurityUser.is(user)) {
-            return xpackSecurityRole;
-        }
-        if (SecurityProfileUser.is(user)) {
-            return securityProfileRole;
-        }
-        if (AsyncSearchUser.is(user)) {
-            return asyncSearchUserRole;
+        if (User.isInternal(user)) {
+            return getInternalUserRole(user);
         }
         return null;
     }
 
+    // Accessible for testing
+    protected Role getInternalUserRole(User user) {
+        String name = InternalUsers.getInternalUserName(user);
+        final Role role = this.internalUserRoles.get(name);
+        if (role == null) {
+            throw new IllegalArgumentException("the internal user [" + user.principal() + "] should never have its roles resolved");
+        }
+        return role;
+    }
+
     public void buildRoleFromRoleReference(RoleReference roleReference, ActionListener<Role> roleActionListener) {
         final RoleKey roleKey = roleReference.id();
         if (roleKey == RoleKey.ROLE_KEY_SUPERUSER) {
@@ -319,26 +294,6 @@ public class CompositeRolesStore {
         return roleReferenceResolver;
     }
 
-    // for testing
-    Role getXpackUserRole() {
-        return xpackUserRole;
-    }
-
-    // for testing
-    Role getAsyncSearchUserRole() {
-        return asyncSearchUserRole;
-    }
-
-    // for testing
-    Role getXpackSecurityRole() {
-        return xpackSecurityRole;
-    }
-
-    // for testing
-    Role getSecurityProfileRole() {
-        return securityProfileRole;
-    }
-
     private void buildThenMaybeCacheRole(
         RoleKey roleKey,
         Collection<RoleDescriptor> roleDescriptors,
@@ -402,29 +357,11 @@ public class CompositeRolesStore {
     // Package private for testing
     static Optional<RoleDescriptor> tryGetRoleDescriptorForInternalUser(Subject subject) {
         final User user = subject.getUser();
-        if (SystemUser.is(user)) {
-            throw new IllegalArgumentException(
-                "the user [" + user.principal() + "] is the system user and we should never try to get its role descriptors"
-            );
-        }
-        if (CrossClusterAccessUser.is(user)) {
-            throw new IllegalArgumentException(
-                "the user [" + user.principal() + "] is the cross cluster access user and we should never try to get its role descriptors"
-            );
-        }
-        if (XPackUser.is(user)) {
-            return Optional.of(XPackUser.ROLE_DESCRIPTOR);
-        }
-        if (XPackSecurityUser.is(user)) {
-            return Optional.of(XPackSecurityUser.ROLE_DESCRIPTOR);
-        }
-        if (SecurityProfileUser.is(user)) {
-            return Optional.of(SecurityProfileUser.ROLE_DESCRIPTOR);
-        }
-        if (AsyncSearchUser.is(user)) {
-            return Optional.of(AsyncSearchUser.ROLE_DESCRIPTOR);
+        if (User.isInternal(user)) {
+            return Optional.of(InternalUsers.getRoleDescriptor(user));
+        } else {
+            return Optional.empty();
         }
-        return Optional.empty();
     }
 
     public static void buildRoleFromDescriptors(

+ 27 - 37
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java

@@ -94,6 +94,7 @@ import org.elasticsearch.xpack.core.security.test.TestRestrictedIndices;
 import org.elasticsearch.xpack.core.security.user.AnonymousUser;
 import org.elasticsearch.xpack.core.security.user.AsyncSearchUser;
 import org.elasticsearch.xpack.core.security.user.CrossClusterAccessUser;
+import org.elasticsearch.xpack.core.security.user.InternalUsers;
 import org.elasticsearch.xpack.core.security.user.SecurityProfileUser;
 import org.elasticsearch.xpack.core.security.user.SystemUser;
 import org.elasticsearch.xpack.core.security.user.User;
@@ -1702,18 +1703,17 @@ public class CompositeRolesStoreTests extends ESTestCase {
         );
         verify(fileRolesStore).addListener(anyConsumer()); // adds a listener in ctor
 
-        for (var userAndRole : List.of(
-            new Tuple<>(XPackUser.INSTANCE, compositeRolesStore.getXpackUserRole()),
-            new Tuple<>(AsyncSearchUser.INSTANCE, compositeRolesStore.getAsyncSearchUserRole()),
-            new Tuple<>(XPackSecurityUser.INSTANCE, compositeRolesStore.getXpackSecurityRole()),
-            new Tuple<>(SecurityProfileUser.INSTANCE, compositeRolesStore.getSecurityProfileRole())
+        for (var internalUser : List.of(
+            XPackUser.INSTANCE,
+            AsyncSearchUser.INSTANCE,
+            XPackSecurityUser.INSTANCE,
+            SecurityProfileUser.INSTANCE
         )) {
-            User internalUser = userAndRole.v1();
+            Role expectedRole = compositeRolesStore.getInternalUserRole(internalUser);
             Subject subject = new Subject(internalUser, new RealmRef("name", "type", "node"));
             PlainActionFuture<Role> rolesFuture = new PlainActionFuture<>();
             compositeRolesStore.getRole(subject, rolesFuture);
             Role roles = rolesFuture.actionGet();
-            Role expectedRole = userAndRole.v2();
 
             assertThat(roles, equalTo(expectedRole));
             assertThat(effectiveRoleDescriptors.get(), is(nullValue()));
@@ -1741,19 +1741,22 @@ public class CompositeRolesStoreTests extends ESTestCase {
         assertThat(role.application().getApplicationNames(), empty());
         assertThat(role.cluster().privileges(), empty());
         assertThat(role.indices(), is(IndicesPermission.NONE));
-        assertThat(
-            role,
-            not(
-                is(
-                    oneOf(
-                        compositeRolesStore.getAsyncSearchUserRole(),
-                        compositeRolesStore.getSecurityProfileRole(),
-                        compositeRolesStore.getXpackUserRole(),
-                        compositeRolesStore.getXpackSecurityRole()
-                    )
-                )
-            )
-        );
+
+        final User internalUser = InternalUsers.getUser(roleName);
+        assertThat(internalUser, notNullValue());
+        if (InternalUsers.getRoleDescriptors().containsKey(internalUser.principal())) {
+            Role internalRole = compositeRolesStore.getInternalUserRole(internalUser);
+            assertThat(internalRole, notNullValue());
+            assertThat(role, not(internalRole));
+        }
+
+        final Role[] internalRoles = InternalUsers.getRoleDescriptors()
+            .keySet()
+            .stream()
+            .map(InternalUsers::getUser)
+            .map(compositeRolesStore::getInternalUserRole)
+            .toArray(Role[]::new);
+        assertThat(role, not(is(oneOf(internalRoles))));
     }
 
     public void testGetRolesForSystemUserThrowsException() {
@@ -1792,7 +1795,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
             )
         );
         assertThat(effectiveRoleDescriptors.get(), is(nullValue()));
-        assertEquals("the user [_system] is the system user and we should never try to get its roles", iae.getMessage());
+        assertEquals("the internal user [_system] should never have its roles resolved", iae.getMessage());
     }
 
     public void testGetRolesForCrossClusterAccessUserThrowsException() {
@@ -1831,10 +1834,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
             )
         );
         assertThat(effectiveRoleDescriptors.get(), is(nullValue()));
-        assertEquals(
-            "the user [_cross_cluster_access] is the cross cluster access user and we should never try to get its roles",
-            iae.getMessage()
-        );
+        assertEquals("the internal user [_cross_cluster_access] should never have its roles resolved", iae.getMessage());
     }
 
     public void testApiKeyAuthUsesApiKeyService() throws Exception {
@@ -2515,24 +2515,14 @@ public class CompositeRolesStoreTests extends ESTestCase {
             IllegalArgumentException.class,
             () -> compositeRolesStore.getRoleDescriptorsList(subject, new PlainActionFuture<>())
         );
-        assertThat(
-            e1.getMessage(),
-            equalTo("the user [" + SystemUser.NAME + "] is the system user and we should never try to get its role descriptors")
-        );
+        assertThat(e1.getMessage(), equalTo("should never try to get the roles for internal user [" + SystemUser.NAME + "]"));
 
         when(subject.getUser()).thenReturn(CrossClusterAccessUser.INSTANCE);
         final IllegalArgumentException e2 = expectThrows(
             IllegalArgumentException.class,
             () -> compositeRolesStore.getRoleDescriptorsList(subject, new PlainActionFuture<>())
         );
-        assertThat(
-            e2.getMessage(),
-            equalTo(
-                "the user ["
-                    + CrossClusterAccessUser.NAME
-                    + "] is the cross cluster access user and we should never try to get its role descriptors"
-            )
-        );
+        assertThat(e2.getMessage(), equalTo("should never try to get the roles for internal user [" + CrossClusterAccessUser.NAME + "]"));
 
         for (var userAndDescriptor : List.of(
             new Tuple<>(XPackUser.INSTANCE, XPackUser.ROLE_DESCRIPTOR),