From e744f7977e87462d47d7bead3c767824bd655236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 23 Jan 2020 14:51:36 +0100 Subject: [PATCH] SOLR-14196: AdminUI login not working for JWTAuth when blockUnknown=false (#1190) --- solr/CHANGES.txt | 2 ++ .../apache/solr/security/JWTAuthPlugin.java | 21 +++++++++++--- ...plugin_jwk_security_blockUnknownFalse.json | 28 +++++++++++++++++++ .../JWTAuthPluginIntegrationTest.java | 22 +++++++++++++++ 4 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 solr/core/src/test-files/solr/security/jwt_plugin_jwk_security_blockUnknownFalse.json diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 0d7ac39b664..c3eef14ca6f 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -238,6 +238,8 @@ Bug Fixes an inability to assign a node based on existing autoscaling policy resulted in a server error instead of a bad request. (Andras Salamon, Kevin Risden, shalin) +* SOLR-14196: AdminUI login not working for JWTAuth when blockUnknown=false (janhoy) + Other Changes --------------------- diff --git a/solr/core/src/java/org/apache/solr/security/JWTAuthPlugin.java b/solr/core/src/java/org/apache/solr/security/JWTAuthPlugin.java index e642751e2e5..e073eacb421 100644 --- a/solr/core/src/java/org/apache/solr/security/JWTAuthPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/JWTAuthPlugin.java @@ -338,6 +338,7 @@ public class JWTAuthPlugin extends AuthenticationPlugin implements SpecProvider, if (log.isDebugEnabled()) log.debug("Unknown user, but allow due to {}=false", PARAM_BLOCK_UNKNOWN); numPassThrough.inc(); + request.setAttribute(AuthenticationPlugin.class.getName(), getPromptHeaders(null, null)); filterChain.doFilter(request, response); return true; @@ -536,16 +537,28 @@ public class JWTAuthPlugin extends AuthenticationPlugin implements SpecProvider, private enum BearerWwwAuthErrorCode { invalid_request, invalid_token, insufficient_scope} private void authenticationFailure(HttpServletResponse response, String message, int httpCode, BearerWwwAuthErrorCode responseError) throws IOException { + getPromptHeaders(responseError, message).forEach(response::setHeader); + response.sendError(httpCode, message); + log.info("JWT Authentication attempt failed: {}", message); + } + + /** + * Generate proper response prompt headers + * @param responseError standardized error code. Set to 'null' to generate WWW-Authenticate header with no error + * @param message custom message string to return in www-authenticate, or null if no error + * @return map of headers to add to response + */ + private Map getPromptHeaders(BearerWwwAuthErrorCode responseError, String message) { + Map headers = new HashMap<>(); List wwwAuthParams = new ArrayList<>(); wwwAuthParams.add("Bearer realm=\"" + realm + "\""); if (responseError != null) { wwwAuthParams.add("error=\"" + responseError + "\""); wwwAuthParams.add("error_description=\"" + message + "\""); } - response.addHeader(HttpHeaders.WWW_AUTHENTICATE, String.join(", ", wwwAuthParams)); - response.addHeader(AuthenticationPlugin.HTTP_HEADER_X_SOLR_AUTHDATA, generateAuthDataHeader()); - response.sendError(httpCode, message); - log.info("JWT Authentication attempt failed: {}", message); + headers.put(HttpHeaders.WWW_AUTHENTICATE, String.join(", ", wwwAuthParams)); + headers.put(AuthenticationPlugin.HTTP_HEADER_X_SOLR_AUTHDATA, generateAuthDataHeader()); + return headers; } protected String generateAuthDataHeader() { diff --git a/solr/core/src/test-files/solr/security/jwt_plugin_jwk_security_blockUnknownFalse.json b/solr/core/src/test-files/solr/security/jwt_plugin_jwk_security_blockUnknownFalse.json new file mode 100644 index 00000000000..ef5bcdeea4a --- /dev/null +++ b/solr/core/src/test-files/solr/security/jwt_plugin_jwk_security_blockUnknownFalse.json @@ -0,0 +1,28 @@ +{ + "authentication": { + "class": "solr.JWTAuthPlugin", + "blockUnknown": false, + "jwk": { + "kty": "RSA", + "e": "AQAB", + "use": "sig", + "kid": "test", + "alg": "RS256", + "n": "jeyrvOaZrmKWjyNXt0myAc_pJ1hNt3aRupExJEx1ewPaL9J9HFgSCjMrYxCB1ETO1NDyZ3nSgjZis-jHHDqBxBjRdq_t1E2rkGFaYbxAyKt220Pwgme_SFTB9MXVrFQGkKyjmQeVmOmV6zM3KK8uMdKQJ4aoKmwBcF5Zg7EZdDcKOFgpgva1Jq-FlEsaJ2xrYDYo3KnGcOHIt9_0NQeLsqZbeWYLxYni7uROFncXYV5FhSJCeR4A_rrbwlaCydGxE0ToC_9HNYibUHlkJjqyUhAgORCbNS8JLCJH8NUi5sDdIawK9GTSyvsJXZ-QHqo4cMUuxWV5AJtaRGghuMUfqQ" + }, + "realm": "my-solr-jwt-blockunknown-false", + "adminUiScope": "solr:admin", + "authorizationEndpoint": "http://acmepaymentscorp/oauth/auz/authorize", + "clientId": "solr-cluster" + }, + "authorization": { + "class": "solr.RuleBasedAuthorizationPlugin", + "permissions": [{ + "name": "all", + "role": "*" + }], + "user-role": { + "solr": "solr-admin" + } + } +} \ No newline at end of file diff --git a/solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java b/solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java index 76d3de458a2..b35ed89cc57 100644 --- a/solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java @@ -145,6 +145,28 @@ public class JWTAuthPluginIntegrationTest extends SolrCloudAuthTestCase { " \"client_id\":\"solr-cluster\"}", authData); } + @Test + public void infoRequestValidateXSolrAuthHeadersBlockUnknownFalse() throws Exception { + // Re-configure cluster with other security.json, see https://issues.apache.org/jira/browse/SOLR-14196 + shutdownCluster(); + configureCluster(NUM_SERVERS)// nodes + .withSecurityJson(TEST_PATH().resolve("security").resolve("jwt_plugin_jwk_security_blockUnknownFalse.json")) + .addConfig("conf1", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf")) + .withDefaultClusterProperty("useLegacyReplicaAssignment", "false") + .configure(); + baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); + + Map headers = getHeaders(baseUrl + "/admin/info/system", null); + assertEquals("Should have received 401 code", "401", headers.get("code")); + assertEquals("Bearer realm=\"my-solr-jwt-blockunknown-false\"", headers.get("WWW-Authenticate")); + String authData = new String(Base64.base64ToByteArray(headers.get("X-Solr-AuthData")), UTF_8); + assertEquals("{\n" + + " \"scope\":\"solr:admin\",\n" + + " \"redirect_uris\":[],\n" + + " \"authorizationEndpoint\":\"http://acmepaymentscorp/oauth/auz/authorize\",\n" + + " \"client_id\":\"solr-cluster\"}", authData); + } + @Test public void testMetrics() throws Exception { boolean isUseV2Api = random().nextBoolean();