mirror of https://github.com/apache/lucene.git
SOLR-13835 HttpSolrCall produces incorrect extra AuditEvent on AuthorizationResponse.PROMPT (#946)
This commit is contained in:
parent
b3d59a7a8b
commit
611c4f960e
|
@ -329,6 +329,8 @@ Bug Fixes
|
||||||
* SOLR-13834: ZkController#getSolrCloudManager() created a new instance of ZkStateReader, thereby causing mismatch in the
|
* SOLR-13834: ZkController#getSolrCloudManager() created a new instance of ZkStateReader, thereby causing mismatch in the
|
||||||
visibility of the cluster state and, as a result, undesired race conditions (Clay Goddard via Ishan Chattopadhyaya)
|
visibility of the cluster state and, as a result, undesired race conditions (Clay Goddard via Ishan Chattopadhyaya)
|
||||||
|
|
||||||
|
* SOLR-13835: HttpSolrCall produces incorrect extra AuditEvent on AuthorizationResponse.PROMPT (janhoy, hossman)
|
||||||
|
|
||||||
Other Changes
|
Other Changes
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.solr.common.SolrException;
|
import org.apache.solr.common.SolrException;
|
||||||
import org.apache.solr.common.cloud.ZkStateReader;
|
import org.apache.solr.common.cloud.ZkStateReader;
|
||||||
|
import org.apache.solr.servlet.SolrRequestParsers;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.slf4j.MDC;
|
import org.slf4j.MDC;
|
||||||
|
@ -129,12 +130,15 @@ public class AuditEvent {
|
||||||
this.solrPort = httpRequest.getLocalPort();
|
this.solrPort = httpRequest.getLocalPort();
|
||||||
this.solrIp = httpRequest.getLocalAddr();
|
this.solrIp = httpRequest.getLocalAddr();
|
||||||
this.clientIp = httpRequest.getRemoteAddr();
|
this.clientIp = httpRequest.getRemoteAddr();
|
||||||
this.resource = httpRequest.getContextPath();
|
this.resource = httpRequest.getPathInfo();
|
||||||
this.httpMethod = httpRequest.getMethod();
|
this.httpMethod = httpRequest.getMethod();
|
||||||
this.httpQueryString = httpRequest.getQueryString();
|
this.httpQueryString = httpRequest.getQueryString();
|
||||||
this.headers = getHeadersFromRequest(httpRequest);
|
this.headers = getHeadersFromRequest(httpRequest);
|
||||||
this.requestUrl = httpRequest.getRequestURL();
|
this.requestUrl = httpRequest.getRequestURL();
|
||||||
this.nodeName = MDC.get(ZkStateReader.NODE_NAME_PROP);
|
this.nodeName = MDC.get(ZkStateReader.NODE_NAME_PROP);
|
||||||
|
SolrRequestParsers.parseQueryString(httpQueryString).forEach(sp -> {
|
||||||
|
this.solrParams.put(sp.getKey(), Arrays.asList(sp.getValue()));
|
||||||
|
});
|
||||||
|
|
||||||
setRequestType(findRequestType());
|
setRequestType(findRequestType());
|
||||||
|
|
||||||
|
@ -459,14 +463,14 @@ public class AuditEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final List<String> ADMIN_PATH_REGEXES = Arrays.asList(
|
private static final List<String> ADMIN_PATH_REGEXES = Arrays.asList(
|
||||||
"^/solr/admin/.*",
|
"^/admin/.*",
|
||||||
"^/api/(c|collections)/$",
|
"^/(____v2|api)/(c|collections)$",
|
||||||
"^/api/(c|collections)/[^/]+/config$",
|
"^/(____v2|api)/(c|collections)/[^/]+/config$",
|
||||||
"^/api/(c|collections)/[^/]+/schema$",
|
"^/(____v2|api)/(c|collections)/[^/]+/schema$",
|
||||||
"^/api/(c|collections)/[^/]+/shards.*",
|
"^/(____v2|api)/(c|collections)/[^/]+/shards.*",
|
||||||
"^/api/cores.*$",
|
"^/(____v2|api)/cores.*$",
|
||||||
"^/api/node$",
|
"^/(____v2|api)/node$",
|
||||||
"^/api/cluster$");
|
"^/(____v2|api)/cluster$");
|
||||||
|
|
||||||
private static final List<String> STREAMING_PATH_REGEXES = Collections.singletonList(".*/stream.*");
|
private static final List<String> STREAMING_PATH_REGEXES = Collections.singletonList(".*/stream.*");
|
||||||
|
|
||||||
|
|
|
@ -474,25 +474,39 @@ public class HttpSolrCall {
|
||||||
AuthorizationContext context = getAuthCtx();
|
AuthorizationContext context = getAuthCtx();
|
||||||
log.debug("AuthorizationContext : {}", context);
|
log.debug("AuthorizationContext : {}", context);
|
||||||
AuthorizationResponse authResponse = cores.getAuthorizationPlugin().authorize(context);
|
AuthorizationResponse authResponse = cores.getAuthorizationPlugin().authorize(context);
|
||||||
if (authResponse.statusCode == AuthorizationResponse.PROMPT.statusCode) {
|
int statusCode = authResponse.statusCode;
|
||||||
|
|
||||||
|
if (statusCode == AuthorizationResponse.PROMPT.statusCode) {
|
||||||
Map<String, String> headers = (Map) getReq().getAttribute(AuthenticationPlugin.class.getName());
|
Map<String, String> headers = (Map) getReq().getAttribute(AuthenticationPlugin.class.getName());
|
||||||
if (headers != null) {
|
if (headers != null) {
|
||||||
for (Map.Entry<String, String> e : headers.entrySet()) response.setHeader(e.getKey(), e.getValue());
|
for (Map.Entry<String, String> e : headers.entrySet()) response.setHeader(e.getKey(), e.getValue());
|
||||||
}
|
}
|
||||||
log.debug("USER_REQUIRED "+req.getHeader("Authorization")+" "+ req.getUserPrincipal());
|
log.debug("USER_REQUIRED "+req.getHeader("Authorization")+" "+ req.getUserPrincipal());
|
||||||
|
sendError(statusCode,
|
||||||
|
"Authentication failed, Response code: " + statusCode);
|
||||||
if (shouldAudit(EventType.REJECTED)) {
|
if (shouldAudit(EventType.REJECTED)) {
|
||||||
cores.getAuditLoggerPlugin().doAudit(new AuditEvent(EventType.REJECTED, req, context));
|
cores.getAuditLoggerPlugin().doAudit(new AuditEvent(EventType.REJECTED, req, context));
|
||||||
}
|
}
|
||||||
|
return RETURN;
|
||||||
}
|
}
|
||||||
if (!(authResponse.statusCode == HttpStatus.SC_ACCEPTED) && !(authResponse.statusCode == HttpStatus.SC_OK)) {
|
if (statusCode == AuthorizationResponse.FORBIDDEN.statusCode) {
|
||||||
log.info("USER_REQUIRED auth header {} context : {} ", req.getHeader("Authorization"), context);
|
log.debug("UNAUTHORIZED auth header {} context : {}, msg: {}", req.getHeader("Authorization"), context, authResponse.getMessage());
|
||||||
sendError(authResponse.statusCode,
|
sendError(statusCode,
|
||||||
"Unauthorized request, Response code: " + authResponse.statusCode);
|
"Unauthorized request, Response code: " + statusCode);
|
||||||
if (shouldAudit(EventType.UNAUTHORIZED)) {
|
if (shouldAudit(EventType.UNAUTHORIZED)) {
|
||||||
cores.getAuditLoggerPlugin().doAudit(new AuditEvent(EventType.UNAUTHORIZED, req, context));
|
cores.getAuditLoggerPlugin().doAudit(new AuditEvent(EventType.UNAUTHORIZED, req, context));
|
||||||
}
|
}
|
||||||
return RETURN;
|
return RETURN;
|
||||||
}
|
}
|
||||||
|
if (!(statusCode == HttpStatus.SC_ACCEPTED) && !(statusCode == HttpStatus.SC_OK)) {
|
||||||
|
log.warn("ERROR {} during authentication: {}", statusCode, authResponse.getMessage());
|
||||||
|
sendError(statusCode,
|
||||||
|
"ERROR during authorization, Response code: " + statusCode);
|
||||||
|
if (shouldAudit(EventType.ERROR)) {
|
||||||
|
cores.getAuditLoggerPlugin().doAudit(new AuditEvent(EventType.ERROR, req, context));
|
||||||
|
}
|
||||||
|
return RETURN;
|
||||||
|
}
|
||||||
if (shouldAudit(EventType.AUTHORIZED)) {
|
if (shouldAudit(EventType.AUTHORIZED)) {
|
||||||
cores.getAuditLoggerPlugin().doAudit(new AuditEvent(EventType.AUTHORIZED, req, context));
|
cores.getAuditLoggerPlugin().doAudit(new AuditEvent(EventType.AUTHORIZED, req, context));
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,6 @@ import static org.apache.solr.client.solrj.request.CollectionAdminRequest.getOve
|
||||||
import static org.apache.solr.security.AuditEvent.EventType.COMPLETED;
|
import static org.apache.solr.security.AuditEvent.EventType.COMPLETED;
|
||||||
import static org.apache.solr.security.AuditEvent.EventType.ERROR;
|
import static org.apache.solr.security.AuditEvent.EventType.ERROR;
|
||||||
import static org.apache.solr.security.AuditEvent.EventType.REJECTED;
|
import static org.apache.solr.security.AuditEvent.EventType.REJECTED;
|
||||||
import static org.apache.solr.security.AuditEvent.EventType.UNAUTHORIZED;
|
|
||||||
import static org.apache.solr.security.AuditEvent.RequestType.ADMIN;
|
import static org.apache.solr.security.AuditEvent.RequestType.ADMIN;
|
||||||
import static org.apache.solr.security.AuditEvent.RequestType.SEARCH;
|
import static org.apache.solr.security.AuditEvent.RequestType.SEARCH;
|
||||||
|
|
||||||
|
@ -184,11 +183,11 @@ public class AuditLoggerIntegrationTest extends SolrCloudAuthTestCase {
|
||||||
CollectionAdminRequest.Create createRequest = CollectionAdminRequest.createCollection("test", 1, 1);
|
CollectionAdminRequest.Create createRequest = CollectionAdminRequest.createCollection("test", 1, 1);
|
||||||
createRequest.setBasicAuthCredentials("solr", "wrongPW");
|
createRequest.setBasicAuthCredentials("solr", "wrongPW");
|
||||||
client.request(createRequest);
|
client.request(createRequest);
|
||||||
fail("Call should fail with 403");
|
fail("Call should fail with 401");
|
||||||
} catch (SolrException ex) {
|
} catch (SolrException ex) {
|
||||||
waitForAuditEventCallbacks(1);
|
waitForAuditEventCallbacks(1);
|
||||||
CallbackReceiver receiver = testHarness.get().receiver;
|
CallbackReceiver receiver = testHarness.get().receiver;
|
||||||
assertAuditEvent(receiver.popEvent(), UNAUTHORIZED, "/admin/collections", ADMIN, null,403);
|
assertAuditEvent(receiver.popEvent(), REJECTED, "/admin/collections", ADMIN, null, 401);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,9 @@ import org.apache.solr.common.params.MapSolrParams;
|
||||||
import org.apache.solr.common.params.ModifiableSolrParams;
|
import org.apache.solr.common.params.ModifiableSolrParams;
|
||||||
import org.apache.solr.common.params.SolrParams;
|
import org.apache.solr.common.params.SolrParams;
|
||||||
import org.apache.solr.common.util.NamedList;
|
import org.apache.solr.common.util.NamedList;
|
||||||
import org.apache.solr.common.util.Utils;
|
|
||||||
import org.apache.solr.common.util.TimeSource;
|
import org.apache.solr.common.util.TimeSource;
|
||||||
|
import org.apache.solr.common.util.Utils;
|
||||||
|
import org.apache.solr.util.LogLevel;
|
||||||
import org.apache.solr.util.SolrCLI;
|
import org.apache.solr.util.SolrCLI;
|
||||||
import org.apache.solr.util.TimeOut;
|
import org.apache.solr.util.TimeOut;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -96,6 +97,7 @@ public class BasicAuthIntegrationTest extends SolrCloudAuthTestCase {
|
||||||
@Test
|
@Test
|
||||||
//commented 9-Aug-2018 @BadApple(bugUrl="https://issues.apache.org/jira/browse/SOLR-12028") // 21-May-2018
|
//commented 9-Aug-2018 @BadApple(bugUrl="https://issues.apache.org/jira/browse/SOLR-12028") // 21-May-2018
|
||||||
// commented out on: 17-Feb-2019 @BadApple(bugUrl="https://issues.apache.org/jira/browse/SOLR-12028") // annotated on: 24-Dec-2018
|
// commented out on: 17-Feb-2019 @BadApple(bugUrl="https://issues.apache.org/jira/browse/SOLR-12028") // annotated on: 24-Dec-2018
|
||||||
|
@LogLevel("org.apache.solr.security=DEBUG")
|
||||||
public void testBasicAuth() throws Exception {
|
public void testBasicAuth() throws Exception {
|
||||||
boolean isUseV2Api = random().nextBoolean();
|
boolean isUseV2Api = random().nextBoolean();
|
||||||
String authcPrefix = "/admin/authentication";
|
String authcPrefix = "/admin/authentication";
|
||||||
|
@ -232,7 +234,7 @@ public class BasicAuthIntegrationTest extends SolrCloudAuthTestCase {
|
||||||
HttpSolrClient.RemoteSolrException e = expectThrows(HttpSolrClient.RemoteSolrException.class, () -> {
|
HttpSolrClient.RemoteSolrException e = expectThrows(HttpSolrClient.RemoteSolrException.class, () -> {
|
||||||
new UpdateRequest().deleteByQuery("*:*").process(aNewClient, COLLECTION);
|
new UpdateRequest().deleteByQuery("*:*").process(aNewClient, COLLECTION);
|
||||||
});
|
});
|
||||||
assertTrue(e.getMessage().contains("Unauthorized request"));
|
assertTrue(e.getMessage(), e.getMessage().contains("Authentication failed"));
|
||||||
} finally {
|
} finally {
|
||||||
aNewClient.close();
|
aNewClient.close();
|
||||||
cluster.stopJettySolrRunner(aNewJetty);
|
cluster.stopJettySolrRunner(aNewJetty);
|
||||||
|
|
Loading…
Reference in New Issue