mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-25 06:16:40 +00:00
Anonymous roles resolution and user role deduplication are now performed during authentication instead of authorization. The change ensures: * If anonymous access is enabled, user will be able to see the anonymous roles added in the roles field in the /_security/_authenticate response. * Any duplication in user roles are removed and will not show in the above authenticate response. * In any other case, the response is unchanged. It also introduces a behaviour change: the anonymous role resolution is now authentication node specific, previously it was authorization node specific. Details can be found at #47195 (comment)
This commit is contained in:
parent
006e00ed0a
commit
84a2f1adf2
@ -46,4 +46,4 @@ public class AuthenticateResponse extends ActionResponse {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -119,6 +119,10 @@ public class User implements ToXContentObject {
|
||||
return authenticatedUser != null;
|
||||
}
|
||||
|
||||
public User withRoles(String[] newRoles) {
|
||||
return new User(username, newRoles, fullName, email, metadata, enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
@ -24,7 +24,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
@ -126,7 +126,7 @@ public class EnableSecurityOnBasicLicenseIT extends ESRestTestCase {
|
||||
final Map<String, Object> auth = getAsMap("/_security/_authenticate");
|
||||
// From file realm, configured in build.gradle
|
||||
assertThat(ObjectPath.evaluate(auth, "username"), equalTo("security_test_user"));
|
||||
assertThat(ObjectPath.evaluate(auth, "roles"), contains("security_test_role"));
|
||||
assertThat(ObjectPath.evaluate(auth, "roles"), containsInAnyOrder("security_test_role", "anonymous"));
|
||||
}
|
||||
|
||||
private void checkAllowedWrite(String indexName) throws IOException {
|
||||
|
@ -49,11 +49,14 @@ import org.elasticsearch.xpack.security.authc.support.RealmUserLookup;
|
||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
@ -656,7 +659,8 @@ public class AuthenticationService {
|
||||
logger.debug("user [{}] is disabled. failing authentication", finalUser);
|
||||
listener.onFailure(request.authenticationFailed(authenticationToken));
|
||||
} else {
|
||||
final Authentication finalAuth = new Authentication(finalUser, authenticatedBy, lookedupBy);
|
||||
final Authentication finalAuth = new Authentication(
|
||||
maybeConsolidateRolesForUser(finalUser), authenticatedBy, lookedupBy);
|
||||
writeAuthToContext(finalAuth);
|
||||
}
|
||||
}
|
||||
@ -689,6 +693,33 @@ public class AuthenticationService {
|
||||
private void authenticateToken(AuthenticationToken token) {
|
||||
this.consumeToken(token);
|
||||
}
|
||||
|
||||
private User maybeConsolidateRolesForUser(User user) {
|
||||
if (User.isInternal(user)) {
|
||||
return user;
|
||||
} else if (isAnonymousUserEnabled && anonymousUser.equals(user) == false) {
|
||||
if (anonymousUser.roles().length == 0) {
|
||||
throw new IllegalStateException("anonymous is only enabled when the anonymous user has roles");
|
||||
}
|
||||
User userWithMergedRoles = user.withRoles(mergeRoles(user.roles(), anonymousUser.roles()));
|
||||
if (user.isRunAs()) {
|
||||
final User authUserWithMergedRoles = user.authenticatedUser().withRoles(
|
||||
mergeRoles(user.authenticatedUser().roles(), anonymousUser.roles()));
|
||||
userWithMergedRoles = new User(userWithMergedRoles, authUserWithMergedRoles);
|
||||
}
|
||||
return userWithMergedRoles;
|
||||
} else {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
private String[] mergeRoles(String[] existingRoles, String[] otherRoles) {
|
||||
Set<String> roles = new LinkedHashSet<>(Arrays.asList(existingRoles));
|
||||
if (otherRoles != null) {
|
||||
Collections.addAll(roles, otherRoles);
|
||||
}
|
||||
return roles.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
|
||||
abstract static class AuditableRequest {
|
||||
|
@ -24,21 +24,21 @@ import static org.elasticsearch.xpack.security.support.SecurityIndexManager.isMo
|
||||
*/
|
||||
public class NativeRealm extends CachingUsernamePasswordRealm {
|
||||
|
||||
private final NativeUsersStore userStore;
|
||||
private final NativeUsersStore usersStore;
|
||||
|
||||
public NativeRealm(RealmConfig config, NativeUsersStore usersStore, ThreadPool threadPool) {
|
||||
super(config, threadPool);
|
||||
this.userStore = usersStore;
|
||||
this.usersStore = usersStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLookupUser(String username, ActionListener<User> listener) {
|
||||
userStore.getUser(username, listener);
|
||||
usersStore.getUser(username, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
|
||||
userStore.verifyPassword(token.principal(), token.credentials(), listener);
|
||||
usersStore.verifyPassword(token.principal(), token.credentials(), listener);
|
||||
}
|
||||
|
||||
public void onSecurityIndexStateChange(SecurityIndexManager.State previousState, SecurityIndexManager.State currentState) {
|
||||
@ -50,7 +50,7 @@ public class NativeRealm extends CachingUsernamePasswordRealm {
|
||||
@Override
|
||||
public void usageStats(ActionListener<Map<String, Object>> listener) {
|
||||
super.usageStats(ActionListener.wrap(stats ->
|
||||
userStore.getUserCount(ActionListener.wrap(size -> {
|
||||
usersStore.getUserCount(ActionListener.wrap(size -> {
|
||||
stats.put("size", size);
|
||||
listener.onResponse(stats);
|
||||
}, listener::onFailure))
|
||||
|
@ -57,6 +57,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
@ -646,7 +647,7 @@ public class NativeUsersStore {
|
||||
final String username = id.substring(USER_DOC_TYPE.length() + 1);
|
||||
try {
|
||||
String password = (String) sourceMap.get(Fields.PASSWORD.getPreferredName());
|
||||
String[] roles = ((List<String>) sourceMap.get(Fields.ROLES.getPreferredName())).toArray(Strings.EMPTY_ARRAY);
|
||||
String[] roles = new LinkedHashSet<>((List<String>)sourceMap.get(Fields.ROLES.getPreferredName())).toArray(Strings.EMPTY_ARRAY);
|
||||
String fullName = (String) sourceMap.get(Fields.FULL_NAME.getPreferredName());
|
||||
String email = (String) sourceMap.get(Fields.EMAIL.getPreferredName());
|
||||
Boolean enabled = (Boolean) sourceMap.get(Fields.ENABLED.getPreferredName());
|
||||
|
@ -30,6 +30,7 @@ import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@ -164,7 +165,7 @@ public class FileUserRolesStore {
|
||||
|
||||
Map<String, String[]> usersRoles = new HashMap<>();
|
||||
for (Map.Entry<String, List<String>> entry : userToRoles.entrySet()) {
|
||||
usersRoles.put(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]));
|
||||
usersRoles.put(entry.getKey(), new LinkedHashSet<>(entry.getValue()).toArray(new String[0]));
|
||||
}
|
||||
|
||||
logger.debug("parsed [{}] user to role mappings from file [{}]", usersRoles.size(), path.toAbsolutePath());
|
||||
|
@ -60,11 +60,8 @@ import org.elasticsearch.xpack.core.security.authz.privilege.ApplicationPrivileg
|
||||
import org.elasticsearch.xpack.core.security.authz.privilege.ClusterPrivilegeResolver;
|
||||
import org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege;
|
||||
import org.elasticsearch.xpack.core.security.user.AnonymousUser;
|
||||
import org.elasticsearch.xpack.core.security.user.AsyncSearchUser;
|
||||
import org.elasticsearch.xpack.core.security.user.SystemUser;
|
||||
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.audit.AuditLevel;
|
||||
import org.elasticsearch.xpack.security.audit.AuditTrail;
|
||||
import org.elasticsearch.xpack.security.audit.AuditTrailService;
|
||||
@ -173,7 +170,7 @@ public class AuthorizationService {
|
||||
if (auditId == null) {
|
||||
// We would like to assert that there is an existing request-id, but if this is a system action, then that might not be
|
||||
// true because the request-id is generated during authentication
|
||||
if (isInternalUser(authentication.getUser()) != false) {
|
||||
if (User.isInternal(authentication.getUser()) != false) {
|
||||
auditId = AuditUtil.getOrGenerateRequestId(threadContext);
|
||||
} else {
|
||||
auditTrailService.get().tamperedRequest(null, authentication.getUser(), action, originalRequest);
|
||||
@ -368,7 +365,7 @@ public class AuthorizationService {
|
||||
private AuthorizationEngine getAuthorizationEngineForUser(final User user) {
|
||||
if (rbacEngine != authorizationEngine && licenseState.isSecurityEnabled() &&
|
||||
licenseState.isAllowed(Feature.SECURITY_AUTHORIZATION_ENGINE)) {
|
||||
if (ClientReservedRealm.isReserved(user.principal(), settings) || isInternalUser(user)) {
|
||||
if (ClientReservedRealm.isReserved(user.principal(), settings) || User.isInternal(user)) {
|
||||
return rbacEngine;
|
||||
} else {
|
||||
return authorizationEngine;
|
||||
@ -419,10 +416,6 @@ public class AuthorizationService {
|
||||
return request;
|
||||
}
|
||||
|
||||
private boolean isInternalUser(User user) {
|
||||
return SystemUser.is(user) || XPackUser.is(user) || XPackSecurityUser.is(user) || AsyncSearchUser.is(user);
|
||||
}
|
||||
|
||||
private void authorizeRunAs(final RequestInfo requestInfo, final AuthorizationInfo authzInfo,
|
||||
final ActionListener<AuthorizationResult> listener) {
|
||||
final Authentication authentication = requestInfo.getAuthentication();
|
||||
|
@ -44,7 +44,6 @@ import org.elasticsearch.xpack.core.security.authz.store.ReservedRolesStore;
|
||||
import org.elasticsearch.xpack.core.security.authz.store.RoleRetrievalResult;
|
||||
import org.elasticsearch.xpack.core.security.support.CacheIteratorHelper;
|
||||
import org.elasticsearch.xpack.core.security.support.MetadataUtils;
|
||||
import org.elasticsearch.xpack.core.security.user.AnonymousUser;
|
||||
import org.elasticsearch.xpack.core.security.user.AsyncSearchUser;
|
||||
import org.elasticsearch.xpack.core.security.user.SystemUser;
|
||||
import org.elasticsearch.xpack.core.security.user.User;
|
||||
@ -101,9 +100,7 @@ public class CompositeRolesStore {
|
||||
private final DocumentSubsetBitsetCache dlsBitsetCache;
|
||||
private final ThreadContext threadContext;
|
||||
private final AtomicLong numInvalidation = new AtomicLong();
|
||||
private final AnonymousUser anonymousUser;
|
||||
private final ApiKeyService apiKeyService;
|
||||
private final boolean isAnonymousEnabled;
|
||||
private final List<BiConsumer<Set<String>, ActionListener<RoleRetrievalResult>>> builtInRoleProviders;
|
||||
private final List<BiConsumer<Set<String>, ActionListener<RoleRetrievalResult>>> allRoleProviders;
|
||||
|
||||
@ -146,8 +143,6 @@ public class CompositeRolesStore {
|
||||
allList.addAll(rolesProviders);
|
||||
this.allRoleProviders = Collections.unmodifiableList(allList);
|
||||
}
|
||||
this.anonymousUser = new AnonymousUser(settings);
|
||||
this.isAnonymousEnabled = AnonymousUser.isAnonymousEnabled(settings);
|
||||
}
|
||||
|
||||
public void roles(Set<String> roleNames, ActionListener<Role> roleActionListener) {
|
||||
@ -237,13 +232,6 @@ public class CompositeRolesStore {
|
||||
}, roleActionListener::onFailure));
|
||||
} else {
|
||||
Set<String> roleNames = new HashSet<>(Arrays.asList(user.roles()));
|
||||
if (isAnonymousEnabled && anonymousUser.equals(user) == false) {
|
||||
if (anonymousUser.roles().length == 0) {
|
||||
throw new IllegalStateException("anonymous is only enabled when the anonymous user has roles");
|
||||
}
|
||||
Collections.addAll(roleNames, anonymousUser.roles());
|
||||
}
|
||||
|
||||
if (roleNames.isEmpty()) {
|
||||
roleActionListener.onResponse(Role.EMPTY);
|
||||
} else if (roleNames.contains(ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName())) {
|
||||
|
@ -74,8 +74,11 @@ import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken
|
||||
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.EmptyAuthorizationInfo;
|
||||
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
|
||||
import org.elasticsearch.xpack.core.security.user.AnonymousUser;
|
||||
import org.elasticsearch.xpack.core.security.user.AsyncSearchUser;
|
||||
import org.elasticsearch.xpack.core.security.user.SystemUser;
|
||||
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.audit.AuditTrail;
|
||||
import org.elasticsearch.xpack.security.audit.AuditTrailService;
|
||||
import org.elasticsearch.xpack.security.audit.AuditUtil;
|
||||
@ -108,6 +111,7 @@ import static org.elasticsearch.test.TestMatchers.throwableWithMessage;
|
||||
import static org.elasticsearch.xpack.core.security.support.Exceptions.authenticationError;
|
||||
import static org.elasticsearch.xpack.security.authc.TokenServiceTests.mockGetTokenFromId;
|
||||
import static org.hamcrest.Matchers.arrayContaining;
|
||||
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.emptyOrNullString;
|
||||
@ -902,6 +906,48 @@ public class AuthenticationServiceTests extends ESTestCase {
|
||||
assertThreadContextContainsAuthentication(result);
|
||||
}
|
||||
|
||||
public void testInheritAnonymousUserRoles() {
|
||||
Settings settings = Settings.builder()
|
||||
.putList(AnonymousUser.ROLES_SETTING.getKey(), "r3", "r4", "r5")
|
||||
.build();
|
||||
final AnonymousUser anonymousUser = new AnonymousUser(settings);
|
||||
service = new AuthenticationService(settings, realms, auditTrailService,
|
||||
new DefaultAuthenticationFailureHandler(Collections.emptyMap()),
|
||||
threadPool, anonymousUser, tokenService, apiKeyService);
|
||||
User user1 = new User("username", "r1", "r2", "r3");
|
||||
when(firstRealm.token(threadContext)).thenReturn(token);
|
||||
when(firstRealm.supports(token)).thenReturn(true);
|
||||
mockAuthenticate(firstRealm, token, user1);
|
||||
// this call does not actually go async
|
||||
final AtomicBoolean completed = new AtomicBoolean(false);
|
||||
service.authenticate(restRequest, true, ActionListener.wrap(authentication -> {
|
||||
assertThat(authentication.getUser().roles(), arrayContainingInAnyOrder("r1", "r2", "r3", "r4", "r5"));
|
||||
setCompletedToTrue(completed);
|
||||
}, this::logAndFail));
|
||||
assertTrue(completed.get());
|
||||
}
|
||||
|
||||
public void testSystemUsersDoNotInheritAnonymousRoles() {
|
||||
Settings settings = Settings.builder()
|
||||
.putList(AnonymousUser.ROLES_SETTING.getKey(), "r3", "r4", "r5")
|
||||
.build();
|
||||
final AnonymousUser anonymousUser = new AnonymousUser(settings);
|
||||
service = new AuthenticationService(settings, realms, auditTrailService,
|
||||
new DefaultAuthenticationFailureHandler(Collections.emptyMap()),
|
||||
threadPool, anonymousUser, tokenService, apiKeyService);
|
||||
when(firstRealm.token(threadContext)).thenReturn(token);
|
||||
when(firstRealm.supports(token)).thenReturn(true);
|
||||
final User sysUser = randomFrom(SystemUser.INSTANCE, XPackUser.INSTANCE, XPackSecurityUser.INSTANCE, AsyncSearchUser.INSTANCE);
|
||||
mockAuthenticate(firstRealm, token, sysUser);
|
||||
// this call does not actually go async
|
||||
final AtomicBoolean completed = new AtomicBoolean(false);
|
||||
service.authenticate(restRequest, true, ActionListener.wrap(authentication -> {
|
||||
assertThat(authentication.getUser().roles(), equalTo(sysUser.roles()));
|
||||
setCompletedToTrue(completed);
|
||||
}, this::logAndFail));
|
||||
assertTrue(completed.get());
|
||||
}
|
||||
|
||||
public void testRealmTokenThrowingException() throws Exception {
|
||||
final String reqId = AuditUtil.getOrGenerateRequestId(threadContext);
|
||||
when(firstRealm.token(threadContext)).thenThrow(authenticationError("realm doesn't like tokens"));
|
||||
|
@ -53,6 +53,7 @@ import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@ -156,6 +157,21 @@ public class NativeUsersStoreTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testVerifyUserWithIncorrectPassword() throws Exception {
|
||||
final NativeUsersStore nativeUsersStore = startNativeUsersStore();
|
||||
final String username = randomAlphaOfLengthBetween(4, 12);
|
||||
final SecureString password = new SecureString(randomAlphaOfLengthBetween(12, 16).toCharArray());
|
||||
final List<String> roles = randomList(1, 4, () -> randomAlphaOfLength(12));
|
||||
roles.add(randomIntBetween(0, roles.size()), roles.get(0));
|
||||
|
||||
final PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
|
||||
nativeUsersStore.verifyPassword(username, password, future);
|
||||
respondToGetUserRequest(username, password, roles.toArray(new String[0]));
|
||||
|
||||
final AuthenticationResult result = future.get();
|
||||
assertThat(result.getUser().roles(), arrayContainingInAnyOrder(roles.stream().distinct().toArray()));
|
||||
}
|
||||
|
||||
public void testDeduplicateUserRoles() throws Exception {
|
||||
final NativeUsersStore nativeUsersStore = startNativeUsersStore();
|
||||
final String username = randomAlphaOfLengthBetween(4, 12);
|
||||
final SecureString correctPassword = new SecureString(randomAlphaOfLengthBetween(12, 16).toCharArray());
|
||||
|
@ -56,7 +56,6 @@ import org.elasticsearch.xpack.core.security.authz.store.ReservedRolesStore;
|
||||
import org.elasticsearch.xpack.core.security.authz.store.RoleRetrievalResult;
|
||||
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
|
||||
import org.elasticsearch.xpack.core.security.support.MetadataUtils;
|
||||
import org.elasticsearch.xpack.core.security.user.AnonymousUser;
|
||||
import org.elasticsearch.xpack.core.security.user.AsyncSearchUser;
|
||||
import org.elasticsearch.xpack.core.security.user.SystemUser;
|
||||
import org.elasticsearch.xpack.core.security.user.User;
|
||||
@ -91,7 +90,6 @@ import static org.elasticsearch.mock.orig.Mockito.verifyNoMoreInteractions;
|
||||
import static org.hamcrest.Matchers.anyOf;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
@ -904,43 +902,6 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||
assertEquals(Role.EMPTY, roles);
|
||||
}
|
||||
|
||||
public void testAnonymousUserEnabledRoleAdded() {
|
||||
Settings settings = Settings.builder()
|
||||
.put(SECURITY_ENABLED_SETTINGS)
|
||||
.put(AnonymousUser.ROLES_SETTING.getKey(), "anonymous_user_role")
|
||||
.build();
|
||||
final FileRolesStore fileRolesStore = mock(FileRolesStore.class);
|
||||
doCallRealMethod().when(fileRolesStore).accept(any(Set.class), any(ActionListener.class));
|
||||
final NativeRolesStore nativeRolesStore = mock(NativeRolesStore.class);
|
||||
doCallRealMethod().when(nativeRolesStore).accept(any(Set.class), any(ActionListener.class));
|
||||
doAnswer(invocationOnMock -> {
|
||||
Set<String> names = (Set<String>) invocationOnMock.getArguments()[0];
|
||||
if (names.size() == 1 && names.contains("anonymous_user_role")) {
|
||||
RoleDescriptor rd = new RoleDescriptor("anonymous_user_role", null, null, null);
|
||||
return Collections.singleton(rd);
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}).
|
||||
when(fileRolesStore).roleDescriptors(anySetOf(String.class));
|
||||
doAnswer((invocationOnMock) -> {
|
||||
ActionListener<RoleRetrievalResult> callback = (ActionListener<RoleRetrievalResult>) invocationOnMock.getArguments()[1];
|
||||
callback.onResponse(RoleRetrievalResult.failure(new RuntimeException("intentionally failed!")));
|
||||
return null;
|
||||
}).when(nativeRolesStore).getRoleDescriptors(isA(Set.class), any(ActionListener.class));
|
||||
final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
|
||||
|
||||
final CompositeRolesStore compositeRolesStore = buildCompositeRolesStore(settings, fileRolesStore, nativeRolesStore,
|
||||
reservedRolesStore, mock(NativePrivilegeStore.class), null, mock(ApiKeyService.class), null, null);
|
||||
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
||||
|
||||
PlainActionFuture<Role> rolesFuture = new PlainActionFuture<>();
|
||||
final User user = new User("no role user");
|
||||
Authentication auth = new Authentication(user, new RealmRef("name", "type", "node"), null);
|
||||
compositeRolesStore.getRoles(user, auth, rolesFuture);
|
||||
final Role roles = rolesFuture.actionGet();
|
||||
assertThat(Arrays.asList(roles.names()), hasItem("anonymous_user_role"));
|
||||
}
|
||||
|
||||
public void testDoesNotUseRolesStoreForXPacAndAsyncSearchUser() {
|
||||
final FileRolesStore fileRolesStore = mock(FileRolesStore.class);
|
||||
doCallRealMethod().when(fileRolesStore).accept(any(Set.class), any(ActionListener.class));
|
||||
|
@ -23,6 +23,7 @@ import java.util.List;
|
||||
|
||||
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
@ -66,8 +67,14 @@ public class RestAuthenticateActionTests extends SecurityIntegTestCase {
|
||||
assertThat(objectPath.evaluate("lookup_realm.name").toString(), equalTo("file"));
|
||||
assertThat(objectPath.evaluate("lookup_realm.type").toString(), equalTo("file"));
|
||||
List<String> roles = objectPath.evaluate("roles");
|
||||
assertThat(roles.size(), is(1));
|
||||
assertThat(roles, contains(SecuritySettingsSource.TEST_ROLE));
|
||||
|
||||
if (anonymousEnabled) {
|
||||
assertThat(roles.size(), is(2));
|
||||
assertThat(roles, containsInAnyOrder(SecuritySettingsSource.TEST_ROLE, "foo"));
|
||||
} else {
|
||||
assertThat(roles.size(), is(1));
|
||||
assertThat(roles, contains(SecuritySettingsSource.TEST_ROLE));
|
||||
}
|
||||
}
|
||||
|
||||
public void testAuthenticateApiWithoutAuthentication() throws Exception {
|
||||
@ -80,7 +87,7 @@ public class RestAuthenticateActionTests extends SecurityIntegTestCase {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> roles = (List<String>) objectPath.evaluate("roles");
|
||||
assertThat(roles.size(), is(2));
|
||||
assertThat(roles, contains(SecuritySettingsSource.TEST_ROLE, "foo"));
|
||||
assertThat(roles, containsInAnyOrder(SecuritySettingsSource.TEST_ROLE, "foo"));
|
||||
} else {
|
||||
fail("request should have failed");
|
||||
}
|
||||
|
@ -4,4 +4,6 @@ role2: user1,user2
|
||||
role3: user1, user2 , user3
|
||||
role4: period.user
|
||||
# another comment line
|
||||
# and another one
|
||||
# and another one
|
||||
# Test duplicated roles
|
||||
role1: user1
|
||||
|
Loading…
x
Reference in New Issue
Block a user