Added user authentication on rest requests
The authc service will now authenticate the user on the rest layer as well, meaning there will only be a single authentication process no matter what is then entry point to ES (for example, if a rest handler executes two internal requests... like some of the _cat APIs, there'll still be a single authentication process) In addition, the audit logs will now log REST authentication failures such that the remote address and the rest endpoint will show up in the logs as well. Original commit: elastic/x-pack-elasticsearch@07af440147
This commit is contained in:
parent
bd38b5237c
commit
637a9e773c
|
@ -51,7 +51,7 @@ public class SecurityFilter extends AbstractComponent {
|
|||
this.auditTrail = auditTrail;
|
||||
}
|
||||
|
||||
User process(String action, TransportRequest request) {
|
||||
User authenticateAndAuthorize(String action, TransportRequest request) {
|
||||
|
||||
// if the action is a system action, we'll fall back on the system user, otherwise we
|
||||
// won't fallback on any user and an authentication exception will be thrown
|
||||
|
@ -63,6 +63,11 @@ public class SecurityFilter extends AbstractComponent {
|
|||
return user;
|
||||
}
|
||||
|
||||
User authenticate(RestRequest request) {
|
||||
AuthenticationToken token = authcService.token(request);
|
||||
return authcService.authenticate(request, token);
|
||||
}
|
||||
|
||||
<Request extends ActionRequest> Request unsign(User user, String action, Request request) {
|
||||
|
||||
try {
|
||||
|
@ -124,7 +129,7 @@ public class SecurityFilter extends AbstractComponent {
|
|||
|
||||
@Override
|
||||
public void process(RestRequest request, RestChannel channel, RestFilterChain filterChain) throws Exception {
|
||||
filter.authcService.extractAndRegisterToken(request);
|
||||
filter.authenticate(request);
|
||||
filterChain.continueProcessing(request, channel);
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +145,7 @@ public class SecurityFilter extends AbstractComponent {
|
|||
|
||||
@Override
|
||||
public void inboundRequest(String action, TransportRequest request) {
|
||||
filter.process(action, request);
|
||||
filter.authenticateAndAuthorize(action, request);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,7 +161,7 @@ public class SecurityFilter extends AbstractComponent {
|
|||
@Override
|
||||
public void apply(String action, ActionRequest request, ActionListener listener, ActionFilterChain chain) {
|
||||
try {
|
||||
User user = filter.process(action, request);
|
||||
User user = filter.authenticateAndAuthorize(action, request);
|
||||
request = filter.unsign(user, action, request);
|
||||
chain.proceed(action, request, new SigningListener(user, action, filter, listener));
|
||||
} catch (Throwable t) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.shield.audit;
|
||||
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.shield.User;
|
||||
import org.elasticsearch.shield.authc.AuthenticationToken;
|
||||
import org.elasticsearch.transport.TransportMessage;
|
||||
|
@ -32,10 +33,18 @@ public interface AuditTrail {
|
|||
public void authenticationFailed(AuthenticationToken token, String action, TransportMessage<?> message) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticationFailed(AuthenticationToken token, RestRequest request) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticationFailed(String realm, AuthenticationToken token, String action, TransportMessage<?> message) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticationFailed(String realm, AuthenticationToken token, RestRequest request) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accessGranted(User user, String action, TransportMessage<?> message) {
|
||||
}
|
||||
|
@ -55,8 +64,12 @@ public interface AuditTrail {
|
|||
|
||||
void authenticationFailed(AuthenticationToken token, String action, TransportMessage<?> message);
|
||||
|
||||
void authenticationFailed(AuthenticationToken token, RestRequest request);
|
||||
|
||||
void authenticationFailed(String realm, AuthenticationToken token, String action, TransportMessage<?> message);
|
||||
|
||||
void authenticationFailed(String realm, AuthenticationToken token, RestRequest request);
|
||||
|
||||
void accessGranted(User user, String action, TransportMessage<?> message);
|
||||
|
||||
void accessDenied(User user, String action, TransportMessage<?> message);
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.elasticsearch.shield.audit;
|
|||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.shield.User;
|
||||
import org.elasticsearch.shield.authc.AuthenticationToken;
|
||||
import org.elasticsearch.transport.TransportMessage;
|
||||
|
@ -54,6 +55,20 @@ public class AuditTrailService extends AbstractComponent implements AuditTrail {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticationFailed(AuthenticationToken token, RestRequest request) {
|
||||
for (AuditTrail auditTrail : auditTrails) {
|
||||
auditTrail.authenticationFailed(token, request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticationFailed(String realm, AuthenticationToken token, RestRequest request) {
|
||||
for (AuditTrail auditTrail : auditTrails) {
|
||||
auditTrail.authenticationFailed(realm, token, request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accessGranted(User user, String action, TransportMessage<?> message) {
|
||||
for (AuditTrail auditTrail : auditTrails) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.elasticsearch.common.inject.Inject;
|
|||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.shield.User;
|
||||
import org.elasticsearch.shield.audit.AuditTrail;
|
||||
import org.elasticsearch.shield.authc.AuthenticationToken;
|
||||
|
@ -56,6 +57,15 @@ public class LoggingAuditTrail implements AuditTrail {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticationFailed(AuthenticationToken token, RestRequest request) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("AUTHENTICATION_FAILED\thost=[{}], URI=[{}], principal=[{}], request=[{}]", request.getRemoteAddress(), request.uri(), token.principal(), request);
|
||||
} else {
|
||||
logger.error("AUTHENTICATION_FAILED\thost=[{}], URI=[{}], principal=[{}]", request.getRemoteAddress(), request.uri(), token.principal());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticationFailed(String realm, AuthenticationToken token, String action, TransportMessage<?> message) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
|
@ -63,6 +73,13 @@ public class LoggingAuditTrail implements AuditTrail {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticationFailed(String realm, AuthenticationToken token, RestRequest request) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("AUTHENTICATION_FAILED[{}]\thost=[{}], URI=[{}], principal=[{}], request=[{}]", realm, request.getRemoteAddress(), request.uri(), token.principal(), request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accessGranted(User user, String action, TransportMessage<?> message) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
|
|
@ -18,7 +18,7 @@ public interface AuthenticationService {
|
|||
* Extracts an authentication token from the given rest request and if found registers it on
|
||||
* the request. If not found, an {@link AuthenticationException} is thrown.
|
||||
*/
|
||||
void extractAndRegisterToken(RestRequest request) throws AuthenticationException;
|
||||
AuthenticationToken token(RestRequest request) throws AuthenticationException;
|
||||
|
||||
/**
|
||||
* Extracts the authenticate token from the given message. If no recognized auth token is associated
|
||||
|
@ -49,4 +49,18 @@ public interface AuthenticationService {
|
|||
*/
|
||||
User authenticate(String action, TransportMessage<?> message, AuthenticationToken token) throws AuthenticationException;
|
||||
|
||||
/**
|
||||
* Authenticates the user associated with the given request based on the given authentication token.
|
||||
*
|
||||
* On successful authentication, the {@link org.elasticsearch.shield.User user} that is associated
|
||||
* with the request (i.e. that is associated with the token's {@link AuthenticationToken#principal() principal})
|
||||
* will be returned. If authentication fails, an {@link AuthenticationException} will be thrown.
|
||||
*
|
||||
* @param request The executed request
|
||||
* @param token The authentication token associated with the given request (must not be {@code null})
|
||||
* @return The authenticated User
|
||||
* @throws AuthenticationException If no user could be authenticated (can either be due to missing
|
||||
* supported authentication token, or simply due to bad credentials.
|
||||
*/
|
||||
User authenticate(RestRequest request, AuthenticationToken token) throws AuthenticationException;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.shield.authc;
|
||||
|
||||
import org.elasticsearch.common.ContextHolder;
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.inject.internal.Nullable;
|
||||
|
@ -35,12 +36,12 @@ public class InternalAuthenticationService extends AbstractComponent implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void extractAndRegisterToken(RestRequest request) throws AuthenticationException {
|
||||
public AuthenticationToken token(RestRequest request) throws AuthenticationException {
|
||||
for (Realm realm : realms) {
|
||||
AuthenticationToken token = realm.token(request);
|
||||
if (token != null) {
|
||||
request.putInContext(TOKEN_CTX_KEY, token);
|
||||
return;
|
||||
return token;
|
||||
}
|
||||
}
|
||||
throw new AuthenticationException("Missing authentication token");
|
||||
|
@ -120,6 +121,29 @@ public class InternalAuthenticationService extends AbstractComponent implements
|
|||
} finally {
|
||||
token.clearCredentials();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public User authenticate(RestRequest request, AuthenticationToken token) throws AuthenticationException {
|
||||
assert token != null : "cannot authenticate null tokens";
|
||||
try {
|
||||
for (Realm realm : realms) {
|
||||
if (realm.supports(token)) {
|
||||
User user = realm.authenticate(token);
|
||||
if (user != null) {
|
||||
request.putInContext(USER_CTX_KEY, user);
|
||||
return user;
|
||||
} else if (auditTrail != null) {
|
||||
auditTrail.authenticationFailed(realm.type(), token, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auditTrail != null) {
|
||||
auditTrail.authenticationFailed(token, request);
|
||||
}
|
||||
throw new AuthenticationException("Unable to authenticate user for request");
|
||||
} finally {
|
||||
token.clearCredentials();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ import org.junit.Before;
|
|||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.internal.stubbing.answers.DoesNothing;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
|
@ -66,7 +65,7 @@ public class SecurityFilterTests extends ElasticsearchTestCase {
|
|||
User user = new User.Simple("_username", "r1");
|
||||
when(authcService.token("_action", request, null)).thenReturn(token);
|
||||
when(authcService.authenticate("_action", request, token)).thenReturn(user);
|
||||
filter.process("_action", request);
|
||||
filter.authenticateAndAuthorize("_action", request);
|
||||
verify(authzService).authorize(user, "_action", request);
|
||||
}
|
||||
|
||||
|
@ -77,7 +76,7 @@ public class SecurityFilterTests extends ElasticsearchTestCase {
|
|||
User user = new User.Simple("_username", "r1");
|
||||
when(authcService.token("internal:_action", request, SystemRealm.TOKEN)).thenReturn(token);
|
||||
when(authcService.authenticate("internal:_action", request, token)).thenReturn(user);
|
||||
filter.process("internal:_action", request);
|
||||
filter.authenticateAndAuthorize("internal:_action", request);
|
||||
verify(authzService).authorize(user, "internal:_action", request);
|
||||
}
|
||||
|
||||
|
@ -89,7 +88,18 @@ public class SecurityFilterTests extends ElasticsearchTestCase {
|
|||
AuthenticationToken token = mock(AuthenticationToken.class);
|
||||
when(authcService.token("_action", request, null)).thenReturn(token);
|
||||
when(authcService.authenticate("_action", request, token)).thenThrow(new AuthenticationException("failed authc"));
|
||||
filter.process("_action", request);
|
||||
filter.authenticateAndAuthorize("_action", request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcess_Rest_AuthenticationFails_Authenticate() throws Exception {
|
||||
thrown.expect(AuthenticationException.class);
|
||||
thrown.expectMessage("failed authc");
|
||||
RestRequest request = mock(RestRequest.class);
|
||||
AuthenticationToken token = mock(AuthenticationToken.class);
|
||||
when(authcService.token(request)).thenReturn(token);
|
||||
when(authcService.authenticate(request, token)).thenThrow(new AuthenticationException("failed authc"));
|
||||
filter.authenticate(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -98,9 +108,19 @@ public class SecurityFilterTests extends ElasticsearchTestCase {
|
|||
thrown.expectMessage("failed authc");
|
||||
TransportRequest request = new InternalRequest();
|
||||
when(authcService.token("_action", request, null)).thenThrow(new AuthenticationException("failed authc"));
|
||||
filter.process("_action", request);
|
||||
filter.authenticateAndAuthorize("_action", request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcess_Rest_AuthenticationFails_NoToken() throws Exception {
|
||||
thrown.expect(AuthenticationException.class);
|
||||
thrown.expectMessage("failed authc");
|
||||
RestRequest request = mock(RestRequest.class);
|
||||
when(authcService.token(request)).thenThrow(new AuthenticationException("failed authc"));
|
||||
filter.authenticate(request);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testProcess_AuthorizationFails() throws Exception {
|
||||
thrown.expect(AuthorizationException.class);
|
||||
|
@ -111,7 +131,7 @@ public class SecurityFilterTests extends ElasticsearchTestCase {
|
|||
when(authcService.token("_action", request, null)).thenReturn(token);
|
||||
when(authcService.authenticate("_action", request, token)).thenReturn(user);
|
||||
doThrow(new AuthorizationException("failed authz")).when(authzService).authorize(user, "_action", request);
|
||||
filter.process("_action", request);
|
||||
filter.authenticateAndAuthorize("_action", request);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -120,7 +140,7 @@ public class SecurityFilterTests extends ElasticsearchTestCase {
|
|||
SecurityFilter.Transport transport = new SecurityFilter.Transport(filter);
|
||||
InternalRequest request = new InternalRequest();
|
||||
transport.inboundRequest("_action", request);
|
||||
verify(filter).process("_action", request);
|
||||
verify(filter).authenticateAndAuthorize("_action", request);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -130,7 +150,7 @@ public class SecurityFilterTests extends ElasticsearchTestCase {
|
|||
filter = mock(SecurityFilter.class);
|
||||
SecurityFilter.Transport transport = new SecurityFilter.Transport(filter);
|
||||
InternalRequest request = new InternalRequest();
|
||||
doThrow(new RuntimeException("process-error")).when(filter).process("_action", request);
|
||||
doThrow(new RuntimeException("process-error")).when(filter).authenticateAndAuthorize("_action", request);
|
||||
transport.inboundRequest("_action", request);
|
||||
}
|
||||
|
||||
|
@ -143,7 +163,7 @@ public class SecurityFilterTests extends ElasticsearchTestCase {
|
|||
ActionFilterChain chain = mock(ActionFilterChain.class);
|
||||
when(filter.unsign(any(User.class), eq("_action"), eq(request))).thenReturn(request);
|
||||
action.apply("_action", request, listener, chain);
|
||||
verify(filter).process("_action", request);
|
||||
verify(filter).authenticateAndAuthorize("_action", request);
|
||||
verify(chain).proceed(eq("_action"), eq(request), isA(SecurityFilter.SigningListener.class));
|
||||
}
|
||||
|
||||
|
@ -155,7 +175,7 @@ public class SecurityFilterTests extends ElasticsearchTestCase {
|
|||
ActionListener listener = mock(ActionListener.class);
|
||||
ActionFilterChain chain = mock(ActionFilterChain.class);
|
||||
RuntimeException exception = new RuntimeException("process-error");
|
||||
doThrow(exception).when(filter).process("_action", request);
|
||||
doThrow(exception).when(filter).authenticateAndAuthorize("_action", request);
|
||||
action.apply("_action", request, listener, chain);
|
||||
verify(listener).onFailure(exception);
|
||||
verifyNoMoreInteractions(chain);
|
||||
|
@ -187,7 +207,7 @@ public class SecurityFilterTests extends ElasticsearchTestCase {
|
|||
RestChannel channel = mock(RestChannel.class);
|
||||
RestFilterChain chain = mock(RestFilterChain.class);
|
||||
rest.process(request, channel, chain);
|
||||
verify(authcService).extractAndRegisterToken(request);
|
||||
verify(authcService).token(request);
|
||||
verify(restController).registerFilter(rest);
|
||||
}
|
||||
|
||||
|
@ -200,7 +220,7 @@ public class SecurityFilterTests extends ElasticsearchTestCase {
|
|||
RestRequest request = mock(RestRequest.class);
|
||||
RestChannel channel = mock(RestChannel.class);
|
||||
RestFilterChain chain = mock(RestFilterChain.class);
|
||||
doThrow(exception).when(authcService).extractAndRegisterToken(request);
|
||||
doThrow(exception).when(authcService).token(request);
|
||||
rest.process(request, channel, chain);
|
||||
verify(restController).registerFilter(rest);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.shield.audit;
|
|||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.shield.User;
|
||||
import org.elasticsearch.shield.authc.AuthenticationToken;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
|
@ -17,6 +18,7 @@ import org.junit.Test;
|
|||
import java.util.Set;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockingDetails;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
|
@ -29,6 +31,7 @@ public class AuditTrailServiceTests extends ElasticsearchTestCase {
|
|||
|
||||
private AuthenticationToken token;
|
||||
private TransportMessage message;
|
||||
private RestRequest restRequest;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
|
@ -40,6 +43,7 @@ public class AuditTrailServiceTests extends ElasticsearchTestCase {
|
|||
service = new AuditTrailService(ImmutableSettings.EMPTY, auditTrails);
|
||||
token = mock(AuthenticationToken.class);
|
||||
message = mock(TransportMessage.class);
|
||||
restRequest = mock(RestRequest.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -50,6 +54,14 @@ public class AuditTrailServiceTests extends ElasticsearchTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationFailed_Rest() throws Exception {
|
||||
service.authenticationFailed(token, restRequest);
|
||||
for (AuditTrail auditTrail : auditTrails) {
|
||||
verify(auditTrail).authenticationFailed(token, restRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationFailed_Realm() throws Exception {
|
||||
service.authenticationFailed("_realm", token, "_action", message);
|
||||
|
@ -58,6 +70,14 @@ public class AuditTrailServiceTests extends ElasticsearchTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationFailed_Rest_Realm() throws Exception {
|
||||
service.authenticationFailed("_realm", token, restRequest);
|
||||
for (AuditTrail auditTrail : auditTrails) {
|
||||
verify(auditTrail).authenticationFailed("_realm", token, restRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnonymousAccess() throws Exception {
|
||||
service.anonymousAccess("_action", message);
|
||||
|
|
|
@ -6,17 +6,21 @@
|
|||
package org.elasticsearch.shield.audit.logfile;
|
||||
|
||||
import org.elasticsearch.common.transport.LocalTransportAddress;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.shield.User;
|
||||
import org.elasticsearch.shield.authc.AuthenticationToken;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.elasticsearch.transport.TransportMessage;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.shield.audit.logfile.CapturingLogger.Level;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -63,6 +67,29 @@ public class LoggingAuditTrailTests extends ElasticsearchTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationFailed_Rest() throws Exception {
|
||||
for (Level level : Level.values()) {
|
||||
RestRequest request = mock(RestRequest.class);
|
||||
when(request.getRemoteAddress()).thenReturn(new InetSocketAddress("_hostname", 9200));
|
||||
when(request.uri()).thenReturn("_uri");
|
||||
when(request.toString()).thenReturn("rest_request");
|
||||
CapturingLogger logger = new CapturingLogger(level);
|
||||
LoggingAuditTrail auditTrail = new LoggingAuditTrail(logger);
|
||||
auditTrail.authenticationFailed(new MockToken(), request);
|
||||
switch (level) {
|
||||
case ERROR:
|
||||
case WARN:
|
||||
case INFO:
|
||||
assertMsg(logger, Level.ERROR, "AUTHENTICATION_FAILED\thost=[_hostname:9200], URI=[_uri], principal=[_principal]");
|
||||
break;
|
||||
case DEBUG:
|
||||
case TRACE:
|
||||
assertMsg(logger, Level.DEBUG, "AUTHENTICATION_FAILED\thost=[_hostname:9200], URI=[_uri], principal=[_principal], request=[rest_request]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationFailed_Realm() throws Exception {
|
||||
for (Level level : Level.values()) {
|
||||
|
@ -82,6 +109,29 @@ public class LoggingAuditTrailTests extends ElasticsearchTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationFailed_Realm_Rest() throws Exception {
|
||||
for (Level level : Level.values()) {
|
||||
RestRequest request = mock(RestRequest.class);
|
||||
when(request.getRemoteAddress()).thenReturn(new InetSocketAddress("_hostname", 9200));
|
||||
when(request.uri()).thenReturn("_uri");
|
||||
when(request.toString()).thenReturn("rest_request");
|
||||
CapturingLogger logger = new CapturingLogger(level);
|
||||
LoggingAuditTrail auditTrail = new LoggingAuditTrail(logger);
|
||||
auditTrail.authenticationFailed("_realm", new MockToken(), request);
|
||||
switch (level) {
|
||||
case ERROR:
|
||||
case WARN:
|
||||
case INFO:
|
||||
case DEBUG:
|
||||
assertEmptyLog(logger);
|
||||
break;
|
||||
case TRACE:
|
||||
assertMsg(logger, Level.TRACE, "AUTHENTICATION_FAILED[_realm]\thost=[_hostname:9200], URI=[_uri], principal=[_principal], request=[rest_request]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessGranted() throws Exception {
|
||||
for (Level level : Level.values()) {
|
||||
|
@ -144,6 +194,7 @@ public class LoggingAuditTrailTests extends ElasticsearchTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private static class MockToken implements AuthenticationToken {
|
||||
@Override
|
||||
public String principal() {
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
*/
|
||||
package org.elasticsearch.shield.authc;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.shield.User;
|
||||
|
@ -16,6 +18,8 @@ import org.junit.Rule;
|
|||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.shield.test.ShieldAssertions.assertContainsWWWAuthenticateHeader;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
@ -41,7 +45,7 @@ public class InternalAuthenticationServiceTests extends ElasticsearchTestCase {
|
|||
public void init() throws Exception {
|
||||
token = mock(AuthenticationToken.class);
|
||||
message = new InternalMessage();
|
||||
restRequest = mock(RestRequest.class);
|
||||
restRequest = new InternalRestRequest();
|
||||
firstRealm = mock(Realm.class);
|
||||
when(firstRealm.type()).thenReturn("first");
|
||||
secondRealm = mock(Realm.class);
|
||||
|
@ -161,24 +165,93 @@ public class InternalAuthenticationServiceTests extends ElasticsearchTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testExtractAndRegisterToken_Exists() throws Exception {
|
||||
public void testToken_Rest_Exists() throws Exception {
|
||||
AuthenticationToken token = mock(AuthenticationToken.class);
|
||||
when(firstRealm.token(restRequest)).thenReturn(null);
|
||||
when(secondRealm.token(restRequest)).thenReturn(token);
|
||||
service.extractAndRegisterToken(restRequest);
|
||||
AuthenticationToken foundToken = service.token(restRequest);
|
||||
assertThat(foundToken, is(token));
|
||||
assertThat(restRequest.getFromContext(InternalAuthenticationService.TOKEN_CTX_KEY), equalTo((Object) token));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVerifyToken_Missing() throws Exception {
|
||||
public void testToken_Rest_Missing() throws Exception {
|
||||
thrown.expect(AuthenticationException.class);
|
||||
thrown.expectMessage("Missing authentication token");
|
||||
when(firstRealm.token(restRequest)).thenReturn(null);
|
||||
when(secondRealm.token(restRequest)).thenReturn(null);
|
||||
service.extractAndRegisterToken(restRequest);
|
||||
service.token(restRequest);
|
||||
}
|
||||
|
||||
private static class InternalMessage extends TransportMessage<InternalMessage> {
|
||||
}
|
||||
|
||||
private static class InternalRestRequest extends RestRequest {
|
||||
|
||||
@Override
|
||||
public Method method() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uri() {
|
||||
return "_uri";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String rawPath() {
|
||||
return "_path";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contentUnsafe() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BytesReference content() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String header(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Map.Entry<String, String>> headers() {
|
||||
return ImmutableMap.<String, String>of().entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasParam(String key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String param(String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> params() {
|
||||
return ImmutableMap.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String param(String key, String defaultValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "rest_request";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue