|
@@ -7,6 +7,7 @@ package org.elasticsearch.xpack.security.rest;
|
|
|
|
|
|
import com.nimbusds.jose.util.StandardCharset;
|
|
|
import org.apache.lucene.util.SetOnce;
|
|
|
+import org.elasticsearch.ElasticsearchException;
|
|
|
import org.elasticsearch.action.ActionListener;
|
|
|
import org.elasticsearch.client.node.NodeClient;
|
|
|
import org.elasticsearch.common.bytes.BytesArray;
|
|
@@ -22,6 +23,7 @@ import org.elasticsearch.rest.BytesRestResponse;
|
|
|
import org.elasticsearch.rest.RestChannel;
|
|
|
import org.elasticsearch.rest.RestHandler;
|
|
|
import org.elasticsearch.rest.RestRequest;
|
|
|
+import org.elasticsearch.rest.RestResponse;
|
|
|
import org.elasticsearch.rest.RestStatus;
|
|
|
import org.elasticsearch.test.ESTestCase;
|
|
|
import org.elasticsearch.test.SecuritySettingsSourceField;
|
|
@@ -44,6 +46,9 @@ import java.util.Set;
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
|
|
import static org.elasticsearch.xpack.core.security.support.Exceptions.authenticationError;
|
|
|
+import static org.hamcrest.Matchers.containsString;
|
|
|
+import static org.hamcrest.Matchers.is;
|
|
|
+import static org.hamcrest.Matchers.not;
|
|
|
import static org.hamcrest.Matchers.notNullValue;
|
|
|
import static org.hamcrest.Matchers.sameInstance;
|
|
|
import static org.mockito.Matchers.any;
|
|
@@ -141,21 +146,52 @@ public class SecurityRestFilterTests extends ESTestCase {
|
|
|
verifyZeroInteractions(channel, authcService);
|
|
|
}
|
|
|
|
|
|
- public void testProcessAuthenticationError() throws Exception {
|
|
|
- RestRequest request = mock(RestRequest.class);
|
|
|
- Exception exception = authenticationError("failed authc");
|
|
|
+ public void testProcessAuthenticationFailedNoTrace() throws Exception {
|
|
|
+ filter = new SecurityRestFilter(licenseState, threadContext, authcService, secondaryAuthenticator, restHandler, false);
|
|
|
+ testProcessAuthenticationFailed(randomBoolean() ? authenticationError("failed authn") : authenticationError("failed authn with " +
|
|
|
+ "cause", new ElasticsearchException("cause")), RestStatus.UNAUTHORIZED, true, true, false);
|
|
|
+ testProcessAuthenticationFailed(randomBoolean() ? authenticationError("failed authn") : authenticationError("failed authn with " +
|
|
|
+ "cause", new ElasticsearchException("cause")), RestStatus.UNAUTHORIZED, true, false, false);
|
|
|
+ testProcessAuthenticationFailed(randomBoolean() ? authenticationError("failed authn") : authenticationError("failed authn with " +
|
|
|
+ "cause", new ElasticsearchException("cause")), RestStatus.UNAUTHORIZED, false, true, false);
|
|
|
+ testProcessAuthenticationFailed(randomBoolean() ? authenticationError("failed authn") : authenticationError("failed authn with " +
|
|
|
+ "cause", new ElasticsearchException("cause")), RestStatus.UNAUTHORIZED, false, false, false);
|
|
|
+ testProcessAuthenticationFailed(new ElasticsearchException("dummy"), RestStatus.INTERNAL_SERVER_ERROR, false, false, false);
|
|
|
+ testProcessAuthenticationFailed(new IllegalArgumentException("dummy"), RestStatus.BAD_REQUEST, true, false, false);
|
|
|
+ testProcessAuthenticationFailed(new ElasticsearchException("dummy"), RestStatus.INTERNAL_SERVER_ERROR, false, true, false);
|
|
|
+ testProcessAuthenticationFailed(new IllegalArgumentException("dummy"), RestStatus.BAD_REQUEST, true, true, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void testProcessAuthenticationFailed(Exception authnException, RestStatus expectedRestStatus, boolean errorTrace,
|
|
|
+ boolean detailedErrorsEnabled, boolean traceExists) throws Exception {
|
|
|
+ RestRequest request;
|
|
|
+ if (errorTrace != !ElasticsearchException.REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT || randomBoolean()) {
|
|
|
+ request = new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY)
|
|
|
+ .withParams(Map.of("error_trace", Boolean.toString(errorTrace))).build();
|
|
|
+ } else {
|
|
|
+ // sometimes do not fill in the default value
|
|
|
+ request = new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY).build();
|
|
|
+ }
|
|
|
doAnswer((i) -> {
|
|
|
ActionListener callback =
|
|
|
(ActionListener) i.getArguments()[1];
|
|
|
- callback.onFailure(exception);
|
|
|
+ callback.onFailure(authnException);
|
|
|
return Void.TYPE;
|
|
|
}).when(authcService).authenticate(eq(request), any(ActionListener.class));
|
|
|
+ RestChannel channel = mock(RestChannel.class);
|
|
|
+ when(channel.detailedErrorsEnabled()).thenReturn(detailedErrorsEnabled);
|
|
|
when(channel.request()).thenReturn(request);
|
|
|
when(channel.newErrorBuilder()).thenReturn(JsonXContent.contentBuilder());
|
|
|
filter.handleRequest(request, channel, null);
|
|
|
ArgumentCaptor<BytesRestResponse> response = ArgumentCaptor.forClass(BytesRestResponse.class);
|
|
|
verify(channel).sendResponse(response.capture());
|
|
|
- assertEquals(RestStatus.UNAUTHORIZED, response.getValue().status());
|
|
|
+ RestResponse restResponse = response.getValue();
|
|
|
+ assertThat(restResponse.status(), is(expectedRestStatus));
|
|
|
+ if (traceExists) {
|
|
|
+ assertThat(restResponse.content().utf8ToString(), containsString(ElasticsearchException.STACK_TRACE));
|
|
|
+ } else {
|
|
|
+ assertThat(restResponse.content().utf8ToString(), not(containsString(ElasticsearchException.STACK_TRACE)));
|
|
|
+ }
|
|
|
verifyZeroInteractions(restHandler);
|
|
|
}
|
|
|
|