|
@@ -7,10 +7,8 @@
|
|
|
|
|
|
package org.elasticsearch.xpack.security.profile;
|
|
|
|
|
|
-import org.apache.logging.log4j.Level;
|
|
|
-import org.apache.logging.log4j.LogManager;
|
|
|
-import org.apache.logging.log4j.Logger;
|
|
|
import org.elasticsearch.ElasticsearchException;
|
|
|
+import org.elasticsearch.ResourceNotFoundException;
|
|
|
import org.elasticsearch.Version;
|
|
|
import org.elasticsearch.action.ActionListener;
|
|
|
import org.elasticsearch.action.bulk.BulkAction;
|
|
@@ -37,9 +35,9 @@ import org.elasticsearch.cluster.service.ClusterService;
|
|
|
import org.elasticsearch.common.Strings;
|
|
|
import org.elasticsearch.common.bytes.BytesArray;
|
|
|
import org.elasticsearch.common.hash.MessageDigests;
|
|
|
-import org.elasticsearch.common.logging.Loggers;
|
|
|
import org.elasticsearch.common.settings.Settings;
|
|
|
import org.elasticsearch.common.unit.Fuzziness;
|
|
|
+import org.elasticsearch.common.util.set.Sets;
|
|
|
import org.elasticsearch.core.Tuple;
|
|
|
import org.elasticsearch.index.get.GetResult;
|
|
|
import org.elasticsearch.index.query.BoolQueryBuilder;
|
|
@@ -52,7 +50,6 @@ import org.elasticsearch.search.sort.ScoreSortBuilder;
|
|
|
import org.elasticsearch.search.sort.SortOrder;
|
|
|
import org.elasticsearch.tasks.TaskId;
|
|
|
import org.elasticsearch.test.ESTestCase;
|
|
|
-import org.elasticsearch.test.MockLogAppender;
|
|
|
import org.elasticsearch.test.VersionUtils;
|
|
|
import org.elasticsearch.threadpool.FixedExecutorBuilder;
|
|
|
import org.elasticsearch.threadpool.TestThreadPool;
|
|
@@ -87,7 +84,6 @@ import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.Set;
|
|
|
-import java.util.TreeSet;
|
|
|
import java.util.concurrent.ExecutionException;
|
|
|
import java.util.function.Consumer;
|
|
|
import java.util.stream.Collectors;
|
|
@@ -102,7 +98,6 @@ import static org.elasticsearch.xpack.security.Security.SECURITY_CRYPTO_THREAD_P
|
|
|
import static org.elasticsearch.xpack.security.support.SecuritySystemIndices.SECURITY_PROFILE_ALIAS;
|
|
|
import static org.hamcrest.Matchers.anEmptyMap;
|
|
|
import static org.hamcrest.Matchers.arrayWithSize;
|
|
|
-import static org.hamcrest.Matchers.containsInAnyOrder;
|
|
|
import static org.hamcrest.Matchers.containsString;
|
|
|
import static org.hamcrest.Matchers.empty;
|
|
|
import static org.hamcrest.Matchers.equalTo;
|
|
@@ -271,29 +266,29 @@ public class ProfileServiceTests extends ESTestCase {
|
|
|
@SuppressWarnings("unchecked")
|
|
|
public void testGetProfileSubjectsNoIndex() throws Exception {
|
|
|
when(profileIndex.indexExists()).thenReturn(false);
|
|
|
- PlainActionFuture<ProfileService.MultiProfileSubjectResponse> future = new PlainActionFuture<>();
|
|
|
+ PlainActionFuture<ResultsAndErrors<Map.Entry<String, Subject>>> future = new PlainActionFuture<>();
|
|
|
profileService.getProfileSubjects(randomList(1, 5, () -> randomAlphaOfLength(20)), future);
|
|
|
- ProfileService.MultiProfileSubjectResponse multiProfileSubjectResponse = future.get();
|
|
|
- assertThat(multiProfileSubjectResponse.profileUidToSubject().size(), is(0));
|
|
|
- assertThat(multiProfileSubjectResponse.failureProfileUids().size(), is(0));
|
|
|
+ ResultsAndErrors<Map.Entry<String, Subject>> resultsAndErrors = future.get();
|
|
|
+ assertThat(resultsAndErrors.results().size(), is(0));
|
|
|
+ assertThat(resultsAndErrors.errors().size(), is(0));
|
|
|
when(profileIndex.indexExists()).thenReturn(true);
|
|
|
ElasticsearchException unavailableException = new ElasticsearchException("mock profile index unavailable");
|
|
|
when(profileIndex.isAvailable()).thenReturn(false);
|
|
|
when(profileIndex.getUnavailableReason()).thenReturn(unavailableException);
|
|
|
- PlainActionFuture<ProfileService.MultiProfileSubjectResponse> future2 = new PlainActionFuture<>();
|
|
|
+ PlainActionFuture<ResultsAndErrors<Map.Entry<String, Subject>>> future2 = new PlainActionFuture<>();
|
|
|
profileService.getProfileSubjects(randomList(1, 5, () -> randomAlphaOfLength(20)), future2);
|
|
|
ExecutionException e = expectThrows(ExecutionException.class, () -> future2.get());
|
|
|
assertThat(e.getCause(), is(unavailableException));
|
|
|
- PlainActionFuture<ProfileService.MultiProfileSubjectResponse> future3 = new PlainActionFuture<>();
|
|
|
+ PlainActionFuture<ResultsAndErrors<Map.Entry<String, Subject>>> future3 = new PlainActionFuture<>();
|
|
|
profileService.getProfileSubjects(List.of(), future3);
|
|
|
- multiProfileSubjectResponse = future3.get();
|
|
|
- assertThat(multiProfileSubjectResponse.profileUidToSubject().size(), is(0));
|
|
|
- assertThat(multiProfileSubjectResponse.failureProfileUids().size(), is(0));
|
|
|
+ resultsAndErrors = future3.get();
|
|
|
+ assertThat(resultsAndErrors.results().size(), is(0));
|
|
|
+ assertThat(resultsAndErrors.errors().size(), is(0));
|
|
|
verify(profileIndex, never()).checkIndexVersionThenExecute(any(Consumer.class), any(Runnable.class));
|
|
|
}
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
- public void testGetProfileSubjectsWithMissingNoFailures() throws Exception {
|
|
|
+ public void testGetProfileSubjectsWithMissingUids() throws Exception {
|
|
|
final Collection<String> allProfileUids = randomList(1, 5, () -> randomAlphaOfLength(20));
|
|
|
final Collection<String> missingProfileUids = randomSubsetOf(allProfileUids);
|
|
|
doAnswer(invocation -> {
|
|
@@ -338,14 +333,19 @@ public class ProfileServiceTests extends ESTestCase {
|
|
|
return null;
|
|
|
}).when(client).execute(eq(MultiGetAction.INSTANCE), any(MultiGetRequest.class), anyActionListener());
|
|
|
|
|
|
- final PlainActionFuture<ProfileService.MultiProfileSubjectResponse> future = new PlainActionFuture<>();
|
|
|
+ final PlainActionFuture<ResultsAndErrors<Map.Entry<String, Subject>>> future = new PlainActionFuture<>();
|
|
|
profileService.getProfileSubjects(allProfileUids, future);
|
|
|
|
|
|
- ProfileService.MultiProfileSubjectResponse multiProfileSubjectResponse = future.get();
|
|
|
+ ResultsAndErrors<Map.Entry<String, Subject>> resultsAndErrors = future.get();
|
|
|
verify(profileIndex).checkIndexVersionThenExecute(any(Consumer.class), any(Runnable.class));
|
|
|
- assertThat(multiProfileSubjectResponse.failureProfileUids().isEmpty(), is(true));
|
|
|
- assertThat(multiProfileSubjectResponse.profileUidToSubject().size(), is(allProfileUids.size() - missingProfileUids.size()));
|
|
|
- for (Map.Entry<String, Subject> profileIdAndSubject : multiProfileSubjectResponse.profileUidToSubject().entrySet()) {
|
|
|
+ assertThat(resultsAndErrors.errors().size(), equalTo(missingProfileUids.size()));
|
|
|
+ resultsAndErrors.errors().forEach((uid, e) -> {
|
|
|
+ assertThat(missingProfileUids, hasItem(uid));
|
|
|
+ assertThat(e, instanceOf(ResourceNotFoundException.class));
|
|
|
+ });
|
|
|
+
|
|
|
+ assertThat(resultsAndErrors.results().size(), is(allProfileUids.size() - missingProfileUids.size()));
|
|
|
+ for (Map.Entry<String, Subject> profileIdAndSubject : resultsAndErrors.results()) {
|
|
|
assertThat(allProfileUids, hasItem(profileIdAndSubject.getKey()));
|
|
|
assertThat(missingProfileUids, not(hasItem(profileIdAndSubject.getKey())));
|
|
|
assertThat(profileIdAndSubject.getValue().getUser().principal(), is("foo_username_" + profileIdAndSubject.getKey()));
|
|
@@ -366,29 +366,13 @@ public class ProfileServiceTests extends ESTestCase {
|
|
|
listener.onFailure(mGetException);
|
|
|
return null;
|
|
|
}).when(client).execute(eq(MultiGetAction.INSTANCE), any(MultiGetRequest.class), anyActionListener());
|
|
|
- final PlainActionFuture<ProfileService.MultiProfileSubjectResponse> future = new PlainActionFuture<>();
|
|
|
+ final PlainActionFuture<ResultsAndErrors<Map.Entry<String, Subject>>> future = new PlainActionFuture<>();
|
|
|
profileService.getProfileSubjects(randomList(1, 5, () -> randomAlphaOfLength(20)), future);
|
|
|
ExecutionException e = expectThrows(ExecutionException.class, () -> future.get());
|
|
|
assertThat(e.getCause(), is(mGetException));
|
|
|
- final Collection<String> missingProfileUids = randomList(1, 5, () -> randomAlphaOfLength(20));
|
|
|
- final Collection<String> errorProfileUids = randomSubsetOf(missingProfileUids);
|
|
|
- final MockLogAppender mockLogAppender = new MockLogAppender();
|
|
|
- if (false == errorProfileUids.isEmpty()) {
|
|
|
- mockLogAppender.addExpectation(
|
|
|
- new MockLogAppender.SeenEventExpectation(
|
|
|
- "message",
|
|
|
- "org.elasticsearch.xpack.security.profile.ProfileService",
|
|
|
- Level.DEBUG,
|
|
|
- "Failed to retrieve profiles "
|
|
|
- + missingProfileUids.stream()
|
|
|
- .filter(v -> errorProfileUids.contains(v))
|
|
|
- .collect(Collectors.toCollection(TreeSet::new))
|
|
|
- )
|
|
|
- );
|
|
|
- }
|
|
|
- mockLogAppender.start();
|
|
|
- final Logger logger = LogManager.getLogger(ProfileService.class);
|
|
|
- Loggers.setLevel(logger, Level.DEBUG);
|
|
|
+ final Collection<String> allProfileUids = randomList(1, 5, () -> randomAlphaOfLength(20));
|
|
|
+ final Collection<String> errorProfileUids = randomSubsetOf(allProfileUids);
|
|
|
+ final Collection<String> missingProfileUids = Sets.difference(Set.copyOf(allProfileUids), Set.copyOf(errorProfileUids));
|
|
|
doAnswer(invocation -> {
|
|
|
assertThat(
|
|
|
threadPool.getThreadContext().getTransient(ACTION_ORIGIN_TRANSIENT_NAME),
|
|
@@ -416,19 +400,15 @@ public class ProfileServiceTests extends ESTestCase {
|
|
|
return null;
|
|
|
}).when(client).execute(eq(MultiGetAction.INSTANCE), any(MultiGetRequest.class), anyActionListener());
|
|
|
|
|
|
- try {
|
|
|
- Loggers.addAppender(logger, mockLogAppender);
|
|
|
- final PlainActionFuture<ProfileService.MultiProfileSubjectResponse> future2 = new PlainActionFuture<>();
|
|
|
- profileService.getProfileSubjects(missingProfileUids, future2);
|
|
|
-
|
|
|
- ProfileService.MultiProfileSubjectResponse multiProfileSubjectResponse = future2.get();
|
|
|
- assertThat(multiProfileSubjectResponse.profileUidToSubject().isEmpty(), is(true));
|
|
|
- assertThat(multiProfileSubjectResponse.failureProfileUids(), containsInAnyOrder(errorProfileUids.toArray(String[]::new)));
|
|
|
- mockLogAppender.assertAllExpectationsMatched();
|
|
|
- } finally {
|
|
|
- Loggers.removeAppender(logger, mockLogAppender);
|
|
|
- mockLogAppender.stop();
|
|
|
- }
|
|
|
+ final PlainActionFuture<ResultsAndErrors<Map.Entry<String, Subject>>> future2 = new PlainActionFuture<>();
|
|
|
+ profileService.getProfileSubjects(allProfileUids, future2);
|
|
|
+
|
|
|
+ ResultsAndErrors<Map.Entry<String, Subject>> resultsAndErrors = future2.get();
|
|
|
+ assertThat(resultsAndErrors.results().isEmpty(), is(true));
|
|
|
+ assertThat(resultsAndErrors.errors().size(), equalTo(allProfileUids.size()));
|
|
|
+ assertThat(resultsAndErrors.errors().keySet(), equalTo(Set.copyOf(allProfileUids)));
|
|
|
+ missingProfileUids.forEach(uid -> assertThat(resultsAndErrors.errors().get(uid), instanceOf(ResourceNotFoundException.class)));
|
|
|
+ errorProfileUids.forEach(uid -> assertThat(resultsAndErrors.errors().get(uid), instanceOf(ElasticsearchException.class)));
|
|
|
}
|
|
|
|
|
|
public void testActivateProfileShouldFailIfSubjectTypeIsNotUser() {
|