This is an automated email from the ASF dual-hosted git repository.

epugh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git

commit 0d381da4036c98df78f1cfd86a74ccad34cd5f0b
Author: Jan Høydahl <[email protected]>
AuthorDate: Tue Feb 8 22:28:22 2022 +0100

    SOLR-15907 Apply spotless only on JWT classes (#616)
---
 .../org/apache/solr/security/JWTAuthPlugin.java    | 493 +++++++++++++--------
 .../org/apache/solr/security/JWTIssuerConfig.java  | 131 ++++--
 .../org/apache/solr/security/JWTPrincipal.java     |  31 +-
 .../solr/security/JWTPrincipalWithUserRoles.java   |  37 +-
 .../solr/security/JWTVerificationkeyResolver.java  |  76 ++--
 .../security/JWTAuthPluginIntegrationTest.java     | 314 +++++++------
 .../apache/solr/security/JWTAuthPluginTest.java    | 218 ++++++---
 .../apache/solr/security/JWTIssuerConfigTest.java  | 117 +++--
 .../security/JWTVerificationkeyResolverTest.java   |  68 ++-
 9 files changed, 928 insertions(+), 557 deletions(-)

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 99531b6..ab040bc 100644
--- a/solr/core/src/java/org/apache/solr/security/JWTAuthPlugin.java
+++ b/solr/core/src/java/org/apache/solr/security/JWTAuthPlugin.java
@@ -17,6 +17,34 @@
 package org.apache.solr.security;
 
 import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.invoke.MethodHandles;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.Principal;
+import java.security.cert.X509Certificate;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import javax.servlet.FilterChain;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import org.apache.commons.io.IOUtils;
 import org.apache.http.HttpHeaders;
 import org.apache.http.HttpRequest;
@@ -45,39 +73,9 @@ import org.jose4j.lang.JoseException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.servlet.FilterChain;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.invoke.MethodHandles;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.security.Principal;
-import java.security.cert.X509Certificate;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Base64;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-/**
- * Authenticaion plugin that finds logged in user by validating the signature 
of a JWT token
- */
-public class JWTAuthPlugin extends AuthenticationPlugin implements 
SpecProvider, ConfigEditablePlugin {
+/** Authenticaion plugin that finds logged in user by validating the signature 
of a JWT token */
+public class JWTAuthPlugin extends AuthenticationPlugin
+    implements SpecProvider, ConfigEditablePlugin {
   private static final Logger log = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
   private static final String PARAM_BLOCK_UNKNOWN = "blockUnknown";
   private static final String PARAM_REQUIRE_ISSUER = "requireIss";
@@ -104,15 +102,31 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
   @Deprecated(since = "9.0") // Remove in 10.0
   private static final String PARAM_ALG_WHITELIST = "algWhitelist";
 
-  private static final Set<String> PROPS = ImmutableSet.of(PARAM_BLOCK_UNKNOWN,
-      PARAM_PRINCIPAL_CLAIM, PARAM_REQUIRE_EXPIRATIONTIME, PARAM_ALG_ALLOWLIST,
-      PARAM_JWK_CACHE_DURATION, PARAM_CLAIMS_MATCH, PARAM_SCOPE, PARAM_REALM, 
PARAM_ROLES_CLAIM,
-      PARAM_ADMINUI_SCOPE, PARAM_REDIRECT_URIS, PARAM_REQUIRE_ISSUER, 
PARAM_ISSUERS,
-      PARAM_TRUSTED_CERTS_FILE, PARAM_TRUSTED_CERTS,
-      // These keys are supported for now to enable PRIMARY issuer config 
through top-level keys
-      JWTIssuerConfig.PARAM_JWKS_URL, JWTIssuerConfig.PARAM_JWK, 
JWTIssuerConfig.PARAM_ISSUER,
-      JWTIssuerConfig.PARAM_CLIENT_ID, JWTIssuerConfig.PARAM_WELL_KNOWN_URL, 
JWTIssuerConfig.PARAM_AUDIENCE,
-      JWTIssuerConfig.PARAM_AUTHORIZATION_ENDPOINT);
+  private static final Set<String> PROPS =
+      ImmutableSet.of(
+          PARAM_BLOCK_UNKNOWN,
+          PARAM_PRINCIPAL_CLAIM,
+          PARAM_REQUIRE_EXPIRATIONTIME,
+          PARAM_ALG_ALLOWLIST,
+          PARAM_JWK_CACHE_DURATION,
+          PARAM_CLAIMS_MATCH,
+          PARAM_SCOPE,
+          PARAM_REALM,
+          PARAM_ROLES_CLAIM,
+          PARAM_ADMINUI_SCOPE,
+          PARAM_REDIRECT_URIS,
+          PARAM_REQUIRE_ISSUER,
+          PARAM_ISSUERS,
+          PARAM_TRUSTED_CERTS_FILE,
+          PARAM_TRUSTED_CERTS,
+          // These keys are supported for now to enable PRIMARY issuer config 
through top-level keys
+          JWTIssuerConfig.PARAM_JWKS_URL,
+          JWTIssuerConfig.PARAM_JWK,
+          JWTIssuerConfig.PARAM_ISSUER,
+          JWTIssuerConfig.PARAM_CLIENT_ID,
+          JWTIssuerConfig.PARAM_WELL_KNOWN_URL,
+          JWTIssuerConfig.PARAM_AUDIENCE,
+          JWTIssuerConfig.PARAM_AUTHORIZATION_ENDPOINT);
 
   private JwtConsumer jwtConsumer;
   private boolean requireExpirationTime;
@@ -133,9 +147,7 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
   String realm;
   private final CoreContainer coreContainer;
 
-  /**
-   * Initialize plugin
-   */
+  /** Initialize plugin */
   public JWTAuthPlugin() {
     this(null);
   }
@@ -149,23 +161,34 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
   public void init(Map<String, Object> pluginConfig) {
     this.pluginConfig = pluginConfig;
     this.issuerConfigs = null;
-    List<String> unknownKeys = pluginConfig.keySet().stream().filter(k -> 
!PROPS.contains(k)).collect(Collectors.toList());
+    List<String> unknownKeys =
+        pluginConfig.keySet().stream().filter(k -> 
!PROPS.contains(k)).collect(Collectors.toList());
     unknownKeys.remove("class");
     unknownKeys.remove("");
     if (!unknownKeys.isEmpty()) {
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Invalid 
JwtAuth configuration parameter " + unknownKeys);
-    }
-
-    blockUnknown = 
Boolean.parseBoolean(String.valueOf(pluginConfig.getOrDefault(PARAM_BLOCK_UNKNOWN,
 false)));
-    requireIssuer = 
Boolean.parseBoolean(String.valueOf(pluginConfig.getOrDefault(PARAM_REQUIRE_ISSUER,
 "true")));
-    requireExpirationTime = 
Boolean.parseBoolean(String.valueOf(pluginConfig.getOrDefault(PARAM_REQUIRE_EXPIRATIONTIME,
 "true")));
+      throw new SolrException(
+          SolrException.ErrorCode.SERVER_ERROR,
+          "Invalid JwtAuth configuration parameter " + unknownKeys);
+    }
+
+    blockUnknown =
+        
Boolean.parseBoolean(String.valueOf(pluginConfig.getOrDefault(PARAM_BLOCK_UNKNOWN,
 false)));
+    requireIssuer =
+        Boolean.parseBoolean(
+            String.valueOf(pluginConfig.getOrDefault(PARAM_REQUIRE_ISSUER, 
"true")));
+    requireExpirationTime =
+        Boolean.parseBoolean(
+            
String.valueOf(pluginConfig.getOrDefault(PARAM_REQUIRE_EXPIRATIONTIME, 
"true")));
     principalClaim = (String) pluginConfig.getOrDefault(PARAM_PRINCIPAL_CLAIM, 
"sub");
 
     rolesClaim = (String) pluginConfig.get(PARAM_ROLES_CLAIM);
     algAllowlist = (List<String>) pluginConfig.get(PARAM_ALG_ALLOWLIST);
     // TODO: Remove deprecated warning in Solr 10.0
-    if ((algAllowlist == null || algAllowlist.isEmpty()) && 
pluginConfig.containsKey(PARAM_ALG_WHITELIST)) {
-      log.warn("Found use of deprecated parameter algWhitelist. Please use {} 
instead.", PARAM_ALG_ALLOWLIST);
+    if ((algAllowlist == null || algAllowlist.isEmpty())
+        && pluginConfig.containsKey(PARAM_ALG_WHITELIST)) {
+      log.warn(
+          "Found use of deprecated parameter algWhitelist. Please use {} 
instead.",
+          PARAM_ALG_ALLOWLIST);
       algAllowlist = (List<String>) pluginConfig.get(PARAM_ALG_WHITELIST);
     }
     realm = (String) pluginConfig.getOrDefault(PARAM_REALM, 
DEFAULT_AUTH_REALM);
@@ -188,7 +211,13 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
     String trustedCertsFile = (String) 
pluginConfig.get(PARAM_TRUSTED_CERTS_FILE);
     String trustedCerts = (String) pluginConfig.get(PARAM_TRUSTED_CERTS);
     if (trustedCertsFile != null && trustedCerts != null) {
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Found 
both " + PARAM_TRUSTED_CERTS_FILE + " and " + PARAM_TRUSTED_CERTS + ", please 
use only one");
+      throw new SolrException(
+          SolrException.ErrorCode.SERVER_ERROR,
+          "Found both "
+              + PARAM_TRUSTED_CERTS_FILE
+              + " and "
+              + PARAM_TRUSTED_CERTS
+              + ", please use only one");
     }
     if (trustedCertsFile != null) {
       try {
@@ -199,7 +228,8 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
         trustedCertsStream = Files.newInputStream(trustedCertsPath);
         log.info("Reading trustedCerts from file {}", trustedCertsFile);
       } catch (IOException e) {
-        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Failed 
to read file " + trustedCertsFile, e);
+        throw new SolrException(
+            SolrException.ErrorCode.SERVER_ERROR, "Failed to read file " + 
trustedCertsFile, e);
       }
     }
     if (trustedCerts != null) {
@@ -210,19 +240,23 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
       trustedSslCerts = CryptoKeys.parseX509Certs(trustedCertsStream);
     }
 
-    long jwkCacheDuration = Long.parseLong((String) 
pluginConfig.getOrDefault(PARAM_JWK_CACHE_DURATION, "3600"));
+    long jwkCacheDuration =
+        Long.parseLong((String) 
pluginConfig.getOrDefault(PARAM_JWK_CACHE_DURATION, "3600"));
 
-    JWTIssuerConfig.setHttpsJwksFactory(new JWTIssuerConfig.HttpsJwksFactory(
-        jwkCacheDuration, DEFAULT_REFRESH_REPRIEVE_THRESHOLD, 
trustedSslCerts));
+    JWTIssuerConfig.setHttpsJwksFactory(
+        new JWTIssuerConfig.HttpsJwksFactory(
+            jwkCacheDuration, DEFAULT_REFRESH_REPRIEVE_THRESHOLD, 
trustedSslCerts));
 
     issuerConfigs = new ArrayList<>();
 
     // Try to parse an issuer from top level config, and add first (primary 
issuer)
     Optional<JWTIssuerConfig> topLevelIssuer = 
parseIssuerFromTopLevelConfig(pluginConfig);
-    topLevelIssuer.ifPresent(ic -> {
-      issuerConfigs.add(ic);
-      log.warn("JWTAuthPlugin issuer is configured using top-level 
configuration keys. Please consider using the 'issuers' array instead.");
-    });
+    topLevelIssuer.ifPresent(
+        ic -> {
+          issuerConfigs.add(ic);
+          log.warn(
+              "JWTAuthPlugin issuer is configured using top-level 
configuration keys. Please consider using the 'issuers' array instead.");
+        });
 
     // Add issuers from 'issuers' key
     issuerConfigs.addAll(parseIssuers(pluginConfig));
@@ -232,12 +266,14 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
       adminUiScope = (String) pluginConfig.get(PARAM_ADMINUI_SCOPE);
       if (adminUiScope == null && requiredScopes.size() > 0) {
         adminUiScope = requiredScopes.get(0);
-        log.warn("No adminUiScope given, using first scope in 'scope' list as 
required scope for accessing Admin UI");
+        log.warn(
+            "No adminUiScope given, using first scope in 'scope' list as 
required scope for accessing Admin UI");
       }
 
       if (adminUiScope == null) {
         adminUiScope = "solr";
-        log.info("No adminUiScope provided, fallback to 'solr' as required 
scope for Admin UI login may not work");
+        log.info(
+            "No adminUiScope provided, fallback to 'solr' as required scope 
for Admin UI login may not work");
       }
 
       Object redirectUrisObj = pluginConfig.get(PARAM_REDIRECT_URIS);
@@ -259,15 +295,18 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
   @SuppressWarnings("unchecked")
   private Optional<JWTIssuerConfig> parseIssuerFromTopLevelConfig(Map<String, 
Object> conf) {
     try {
-      JWTIssuerConfig primary = new JWTIssuerConfig(PRIMARY_ISSUER)
-          .setIss((String) conf.get(JWTIssuerConfig.PARAM_ISSUER))
-          .setAud((String) conf.get(JWTIssuerConfig.PARAM_AUDIENCE))
-          .setJwksUrl(conf.get(JWTIssuerConfig.PARAM_JWKS_URL))
-          .setAuthorizationEndpoint((String) 
conf.get(JWTIssuerConfig.PARAM_AUTHORIZATION_ENDPOINT))
-          .setClientId((String) conf.get(JWTIssuerConfig.PARAM_CLIENT_ID))
-          .setWellKnownUrl((String) 
conf.get(JWTIssuerConfig.PARAM_WELL_KNOWN_URL));
+      JWTIssuerConfig primary =
+          new JWTIssuerConfig(PRIMARY_ISSUER)
+              .setIss((String) conf.get(JWTIssuerConfig.PARAM_ISSUER))
+              .setAud((String) conf.get(JWTIssuerConfig.PARAM_AUDIENCE))
+              .setJwksUrl(conf.get(JWTIssuerConfig.PARAM_JWKS_URL))
+              .setAuthorizationEndpoint(
+                  (String) 
conf.get(JWTIssuerConfig.PARAM_AUTHORIZATION_ENDPOINT))
+              .setClientId((String) conf.get(JWTIssuerConfig.PARAM_CLIENT_ID))
+              .setWellKnownUrl((String) 
conf.get(JWTIssuerConfig.PARAM_WELL_KNOWN_URL));
       if (conf.get(JWTIssuerConfig.PARAM_JWK) != null) {
-        primary.setJsonWebKeySet(JWTIssuerConfig.parseJwkSet((Map<String, 
Object>) conf.get(JWTIssuerConfig.PARAM_JWK)));
+        primary.setJsonWebKeySet(
+            JWTIssuerConfig.parseJwkSet((Map<String, Object>) 
conf.get(JWTIssuerConfig.PARAM_JWK)));
       }
       if (primary.isValid()) {
         log.debug("Found issuer in top level config");
@@ -279,13 +318,16 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
         return Optional.empty();
       }
     } catch (JoseException je) {
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Failed 
parsing issuer from top level config", je);
+      throw new SolrException(
+          SolrException.ErrorCode.SERVER_ERROR, "Failed parsing issuer from 
top level config", je);
     }
   }
 
   /**
-   * Fetch the primary issuer to be used for Admin UI authentication. Callers 
of this method must ensure that at least
-   * one issuer is configured. The primary issuer is defined as the first 
issuer configured in the list.
+   * Fetch the primary issuer to be used for Admin UI authentication. Callers 
of this method must
+   * ensure that at least one issuer is configured. The primary issuer is 
defined as the first
+   * issuer configured in the list.
+   *
    * @return JWTIssuerConfig object for the primary issuer
    */
   JWTIssuerConfig getPrimaryIssuer() {
@@ -297,6 +339,7 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
 
   /**
    * Initialize optional additional issuers configured in 'issuers' config map
+   *
    * @param pluginConfig the main config object
    * @return a list of parsed {@link JWTIssuerConfig} objects
    */
@@ -304,64 +347,80 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
   List<JWTIssuerConfig> parseIssuers(Map<String, Object> pluginConfig) {
     List<JWTIssuerConfig> configs = new ArrayList<>();
     try {
-      List<Map<String, Object>> issuers = (List<Map<String, Object>>) 
pluginConfig.get(PARAM_ISSUERS);
+      List<Map<String, Object>> issuers =
+          (List<Map<String, Object>>) pluginConfig.get(PARAM_ISSUERS);
       if (issuers != null) {
-        issuers.forEach(issuerConf -> {
-          JWTIssuerConfig ic = new JWTIssuerConfig(issuerConf);
-          ic.setTrustedCerts(trustedSslCerts);
-          ic.init();
-          configs.add(ic);
-          if (log.isDebugEnabled()) {
-            log.debug("Found issuer with name {} and issuerId {}", 
ic.getName(), ic.getIss());
-          }
-        });
+        issuers.forEach(
+            issuerConf -> {
+              JWTIssuerConfig ic = new JWTIssuerConfig(issuerConf);
+              ic.setTrustedCerts(trustedSslCerts);
+              ic.init();
+              configs.add(ic);
+              if (log.isDebugEnabled()) {
+                log.debug("Found issuer with name {} and issuerId {}", 
ic.getName(), ic.getIss());
+              }
+            });
       }
       return configs;
-    } catch(ClassCastException cce) {
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Parameter 
" + PARAM_ISSUERS + " has wrong format.", cce);
+    } catch (ClassCastException cce) {
+      throw new SolrException(
+          SolrException.ErrorCode.SERVER_ERROR,
+          "Parameter " + PARAM_ISSUERS + " has wrong format.",
+          cce);
     }
   }
 
-  /**
-   * Main authentication method that looks for correct JWT token in the 
Authorization header
-   */
+  /** Main authentication method that looks for correct JWT token in the 
Authorization header */
   @Override
-  public boolean doAuthenticate(HttpServletRequest request, 
HttpServletResponse response, FilterChain filterChain) throws Exception {
+  public boolean doAuthenticate(
+      HttpServletRequest request, HttpServletResponse response, FilterChain 
filterChain)
+      throws Exception {
     String header = request.getHeader(HttpHeaders.AUTHORIZATION);
 
     if (jwtConsumer == null) {
       if (header == null && !blockUnknown) {
-        log.info("JWTAuth not configured, but allowing anonymous access since 
{}==false", PARAM_BLOCK_UNKNOWN);
+        log.info(
+            "JWTAuth not configured, but allowing anonymous access since 
{}==false",
+            PARAM_BLOCK_UNKNOWN);
         numPassThrough.inc();
         filterChain.doFilter(request, response);
         return true;
       }
       // Retry config
       if 
(lastInitTime.plusSeconds(RETRY_INIT_DELAY_SECONDS).isAfter(Instant.now())) {
-        log.info("Retrying JWTAuthPlugin initialization (retry delay={}s)", 
RETRY_INIT_DELAY_SECONDS);
+        log.info(
+            "Retrying JWTAuthPlugin initialization (retry delay={}s)", 
RETRY_INIT_DELAY_SECONDS);
         init(pluginConfig);
       }
       if (jwtConsumer == null) {
         log.warn("JWTAuth not configured");
         numErrors.mark();
-        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "JWTAuth 
plugin not correctly configured");
+        throw new SolrException(
+            SolrException.ErrorCode.SERVER_ERROR, "JWTAuth plugin not 
correctly configured");
       }
     }
 
     JWTAuthenticationResponse authResponse = authenticate(header);
-    String exceptionMessage = authResponse.getJwtException() != null ? 
authResponse.getJwtException().getMessage() : "";
+    String exceptionMessage =
+        authResponse.getJwtException() != null ? 
authResponse.getJwtException().getMessage() : "";
     if (AuthCode.SIGNATURE_INVALID.equals(authResponse.getAuthCode())) {
       String issuer = jwtConsumer.processToClaims(header).getIssuer();
       if (issuer != null) {
-        Optional<JWTIssuerConfig> issuerConfig = 
issuerConfigs.stream().filter(ic -> issuer.equals(ic.getIss())).findFirst();
+        Optional<JWTIssuerConfig> issuerConfig =
+            issuerConfigs.stream().filter(ic -> 
issuer.equals(ic.getIss())).findFirst();
         if (issuerConfig.isPresent() && issuerConfig.get().usesHttpsJwk()) {
-          log.info("Signature validation failed for issuer {}. Refreshing JWKs 
from IdP before trying again: {}",
-              issuer, exceptionMessage);
+          log.info(
+              "Signature validation failed for issuer {}. Refreshing JWKs from 
IdP before trying again: {}",
+              issuer,
+              exceptionMessage);
           for (HttpsJwks httpsJwks : issuerConfig.get().getHttpsJwks()) {
             httpsJwks.refresh();
           }
           authResponse = authenticate(header); // Retry
-          exceptionMessage = authResponse.getJwtException() != null ? 
authResponse.getJwtException().getMessage() : "";
+          exceptionMessage =
+              authResponse.getJwtException() != null
+                  ? authResponse.getJwtException().getMessage()
+                  : "";
         }
       }
     }
@@ -372,10 +431,13 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
         request = wrapWithPrincipal(request, principal);
         if (!(principal instanceof JWTPrincipal)) {
           numErrors.mark();
-          throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, 
"JWTAuth plugin says AUTHENTICATED but no token extracted");
+          throw new SolrException(
+              SolrException.ErrorCode.SERVER_ERROR,
+              "JWTAuth plugin says AUTHENTICATED but no token extracted");
         }
-        if (log.isDebugEnabled())
+        if (log.isDebugEnabled()) {
           log.debug("Authentication SUCCESS");
+        }
         numAuthenticated.inc();
         filterChain.doFilter(request, response);
         return true;
@@ -390,9 +452,16 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
 
       case AUTZ_HEADER_PROBLEM:
       case JWT_PARSE_ERROR:
-        log.warn("Authentication failed. {}, {}", authResponse.getAuthCode(), 
authResponse.getAuthCode().getMsg());
+        log.warn(
+            "Authentication failed. {}, {}",
+            authResponse.getAuthCode(),
+            authResponse.getAuthCode().getMsg());
         numErrors.mark();
-        authenticationFailure(response, authResponse.getAuthCode().getMsg(), 
HttpServletResponse.SC_BAD_REQUEST, BearerWwwAuthErrorCode.invalid_request);
+        authenticationFailure(
+            response,
+            authResponse.getAuthCode().getMsg(),
+            HttpServletResponse.SC_BAD_REQUEST,
+            BearerWwwAuthErrorCode.invalid_request);
         return false;
 
       case CLAIM_MISMATCH:
@@ -401,24 +470,40 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
       case PRINCIPAL_MISSING:
         log.warn("Authentication failed. {}, {}", authResponse.getAuthCode(), 
exceptionMessage);
         numWrongCredentials.inc();
-        authenticationFailure(response, authResponse.getAuthCode().getMsg(), 
HttpServletResponse.SC_UNAUTHORIZED, BearerWwwAuthErrorCode.invalid_token);
+        authenticationFailure(
+            response,
+            authResponse.getAuthCode().getMsg(),
+            HttpServletResponse.SC_UNAUTHORIZED,
+            BearerWwwAuthErrorCode.invalid_token);
         return false;
 
       case SIGNATURE_INVALID:
         log.warn("Signature validation failed: {}", exceptionMessage);
         numWrongCredentials.inc();
-        authenticationFailure(response, authResponse.getAuthCode().getMsg(), 
HttpServletResponse.SC_UNAUTHORIZED, BearerWwwAuthErrorCode.invalid_token);
+        authenticationFailure(
+            response,
+            authResponse.getAuthCode().getMsg(),
+            HttpServletResponse.SC_UNAUTHORIZED,
+            BearerWwwAuthErrorCode.invalid_token);
         return false;
 
       case SCOPE_MISSING:
         numWrongCredentials.inc();
-        authenticationFailure(response, authResponse.getAuthCode().getMsg(), 
HttpServletResponse.SC_UNAUTHORIZED, BearerWwwAuthErrorCode.insufficient_scope);
+        authenticationFailure(
+            response,
+            authResponse.getAuthCode().getMsg(),
+            HttpServletResponse.SC_UNAUTHORIZED,
+            BearerWwwAuthErrorCode.insufficient_scope);
         return false;
 
       case NO_AUTZ_HEADER:
       default:
         numMissingCredentials.inc();
-        authenticationFailure(response, authResponse.getAuthCode().getMsg(), 
HttpServletResponse.SC_UNAUTHORIZED, null);
+        authenticationFailure(
+            response,
+            authResponse.getAuthCode().getMsg(),
+            HttpServletResponse.SC_UNAUTHORIZED,
+            null);
         return false;
     }
   }
@@ -438,25 +523,38 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
             JwtClaims jwtClaims = jwtConsumer.processToClaims(jwtCompact);
             String principal = jwtClaims.getStringClaimValue(principalClaim);
             if (principal == null || principal.isEmpty()) {
-              return new JWTAuthenticationResponse(AuthCode.PRINCIPAL_MISSING, 
"Cannot identify principal from JWT. Required claim " + principalClaim + " 
missing. Cannot authenticate");
+              return new JWTAuthenticationResponse(
+                  AuthCode.PRINCIPAL_MISSING,
+                  "Cannot identify principal from JWT. Required claim "
+                      + principalClaim
+                      + " missing. Cannot authenticate");
             }
             if (claimsMatchCompiled != null) {
               for (Map.Entry<String, Pattern> entry : 
claimsMatchCompiled.entrySet()) {
                 String claim = entry.getKey();
                 if (jwtClaims.hasClaim(claim)) {
                   if 
(!entry.getValue().matcher(jwtClaims.getStringClaimValue(claim)).matches()) {
-                    return new 
JWTAuthenticationResponse(AuthCode.CLAIM_MISMATCH,
-                        "Claim " + claim + "=" + 
jwtClaims.getStringClaimValue(claim)
-                            + " does not match required regular expression " + 
entry.getValue().pattern());
+                    return new JWTAuthenticationResponse(
+                        AuthCode.CLAIM_MISMATCH,
+                        "Claim "
+                            + claim
+                            + "="
+                            + jwtClaims.getStringClaimValue(claim)
+                            + " does not match required regular expression "
+                            + entry.getValue().pattern());
                   }
                 } else {
-                  return new 
JWTAuthenticationResponse(AuthCode.CLAIM_MISMATCH, "Claim " + claim + " is 
required but does not exist in JWT");
+                  return new JWTAuthenticationResponse(
+                      AuthCode.CLAIM_MISMATCH,
+                      "Claim " + claim + " is required but does not exist in 
JWT");
                 }
               }
             }
             if (!requiredScopes.isEmpty() && !jwtClaims.hasClaim(CLAIM_SCOPE)) 
{
               // Fail if we require scopes but they don't exist
-              return new JWTAuthenticationResponse(AuthCode.CLAIM_MISMATCH, 
"Claim " + CLAIM_SCOPE + " is required but does not exist in JWT");
+              return new JWTAuthenticationResponse(
+                  AuthCode.CLAIM_MISMATCH,
+                  "Claim " + CLAIM_SCOPE + " is required but does not exist in 
JWT");
             }
 
             // Find scopes for user
@@ -471,7 +569,12 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
               // Validate that at least one of the required scopes are present 
in the scope claim
               if (!requiredScopes.isEmpty()) {
                 if (scopes.stream().noneMatch(requiredScopes::contains)) {
-                  return new JWTAuthenticationResponse(AuthCode.SCOPE_MISSING, 
"Claim " + CLAIM_SCOPE + " does not contain any of the required scopes: " + 
requiredScopes);
+                  return new JWTAuthenticationResponse(
+                      AuthCode.SCOPE_MISSING,
+                      "Claim "
+                          + CLAIM_SCOPE
+                          + " does not contain any of the required scopes: "
+                          + requiredScopes);
                 }
               }
             }
@@ -479,11 +582,13 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
             // Determine roles of user, either from 'rolesClaim' or from 
'scope' as parsed above
             final Set<String> finalRoles = new HashSet<>();
             if (rolesClaim == null) {
-              // Pass scopes with principal to signal to any Authorization 
plugins that user has some verified role claims
+              // Pass scopes with principal to signal to any Authorization 
plugins that user has
+              // some verified role claims
               finalRoles.addAll(scopes);
               finalRoles.remove("openid"); // Remove standard scope
             } else {
-              // Pull roles from separate claim, either as whitespace 
separated list or as JSON array
+              // Pull roles from separate claim, either as whitespace 
separated list or as JSON
+              // array
               Object rolesObj = jwtClaims.getClaimValue(rolesClaim);
               if (rolesObj != null) {
                 if (rolesObj instanceof String) {
@@ -494,32 +599,46 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
               }
             }
             if (finalRoles.size() > 0) {
-              return new JWTAuthenticationResponse(AuthCode.AUTHENTICATED, new 
JWTPrincipalWithUserRoles(principal, jwtCompact, jwtClaims.getClaimsMap(), 
finalRoles));
+              return new JWTAuthenticationResponse(
+                  AuthCode.AUTHENTICATED,
+                  new JWTPrincipalWithUserRoles(
+                      principal, jwtCompact, jwtClaims.getClaimsMap(), 
finalRoles));
             } else {
-              return new JWTAuthenticationResponse(AuthCode.AUTHENTICATED, new 
JWTPrincipal(principal, jwtCompact, jwtClaims.getClaimsMap()));
+              return new JWTAuthenticationResponse(
+                  AuthCode.AUTHENTICATED,
+                  new JWTPrincipal(principal, jwtCompact, 
jwtClaims.getClaimsMap()));
             }
           } catch (InvalidJwtSignatureException ise) {
             return new JWTAuthenticationResponse(AuthCode.SIGNATURE_INVALID, 
ise);
           } catch (InvalidJwtException e) {
             // Whether or not the JWT has expired being one common reason for 
invalidity
             if (e.hasExpired()) {
-              return new JWTAuthenticationResponse(AuthCode.JWT_EXPIRED, 
"Authentication failed due to expired JWT token. Expired at " + 
e.getJwtContext().getJwtClaims().getExpirationTime());
+              return new JWTAuthenticationResponse(
+                  AuthCode.JWT_EXPIRED,
+                  "Authentication failed due to expired JWT token. Expired at "
+                      + e.getJwtContext().getJwtClaims().getExpirationTime());
             }
-            if (e.getCause() != null && e.getCause() instanceof JoseException 
&& e.getCause().getMessage().contains("Invalid JOSE Compact Serialization")) {
-              return new JWTAuthenticationResponse(AuthCode.JWT_PARSE_ERROR, 
e.getCause().getMessage());
+            if (e.getCause() != null
+                && e.getCause() instanceof JoseException
+                && e.getCause().getMessage().contains("Invalid JOSE Compact 
Serialization")) {
+              return new JWTAuthenticationResponse(
+                  AuthCode.JWT_PARSE_ERROR, e.getCause().getMessage());
             }
             return new 
JWTAuthenticationResponse(AuthCode.JWT_VALIDATION_EXCEPTION, e);
           }
         } catch (MalformedClaimException e) {
-          return new JWTAuthenticationResponse(AuthCode.JWT_PARSE_ERROR, 
"Malformed claim, error was: " + e.getMessage());
+          return new JWTAuthenticationResponse(
+              AuthCode.JWT_PARSE_ERROR, "Malformed claim, error was: " + 
e.getMessage());
         }
       } else {
-        return new JWTAuthenticationResponse(AuthCode.AUTZ_HEADER_PROBLEM, 
"Authorization header is not in correct format");
+        return new JWTAuthenticationResponse(
+            AuthCode.AUTZ_HEADER_PROBLEM, "Authorization header is not in 
correct format");
       }
     } else {
       // No Authorization header
       if (blockUnknown) {
-        return new JWTAuthenticationResponse(AuthCode.NO_AUTZ_HEADER, "Missing 
Authorization header");
+        return new JWTAuthenticationResponse(
+            AuthCode.NO_AUTZ_HEADER, "Missing Authorization header");
       } else {
         log.debug("No user authenticated, but blockUnknown=false, so letting 
request through");
         return new JWTAuthenticationResponse(AuthCode.PASS_THROUGH);
@@ -539,23 +658,36 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
   }
 
   private void initConsumer() {
-    JwtConsumerBuilder jwtConsumerBuilder = new JwtConsumerBuilder()
-        .setAllowedClockSkewInSeconds(30); // allow some leeway in validating 
time based claims to account for clock skew
-    String[] issuers = 
issuerConfigs.stream().map(JWTIssuerConfig::getIss).filter(Objects::nonNull).toArray(String[]::new);
+    JwtConsumerBuilder jwtConsumerBuilder =
+        new JwtConsumerBuilder()
+            .setAllowedClockSkewInSeconds(
+                30); // allow some leeway in validating time based claims to 
account for clock skew
+    String[] issuers =
+        issuerConfigs.stream()
+            .map(JWTIssuerConfig::getIss)
+            .filter(Objects::nonNull)
+            .toArray(String[]::new);
     if (issuers.length > 0) {
-      jwtConsumerBuilder.setExpectedIssuers(requireIssuer, issuers); // whom 
the JWT needs to have been issued by
-    }
-    String[] audiences = 
issuerConfigs.stream().map(JWTIssuerConfig::getAud).filter(Objects::nonNull).toArray(String[]::new);
+      jwtConsumerBuilder.setExpectedIssuers(
+          requireIssuer, issuers); // whom the JWT needs to have been issued by
+    }
+    String[] audiences =
+        issuerConfigs.stream()
+            .map(JWTIssuerConfig::getAud)
+            .filter(Objects::nonNull)
+            .toArray(String[]::new);
     if (audiences.length > 0) {
       jwtConsumerBuilder.setExpectedAudience(audiences); // to whom the JWT is 
intended for
     } else {
       jwtConsumerBuilder.setSkipDefaultAudienceValidation();
     }
-    if (requireExpirationTime)
-      jwtConsumerBuilder.setRequireExpirationTime();
+    if (requireExpirationTime) jwtConsumerBuilder.setRequireExpirationTime();
     if (algAllowlist != null)
-      jwtConsumerBuilder.setJwsAlgorithmConstraints( // only allow the 
expected signature algorithm(s) in the given context
-          new AlgorithmConstraints(AlgorithmConstraints.ConstraintType.PERMIT, 
algAllowlist.toArray(new String[0])));
+      jwtConsumerBuilder
+          .setJwsAlgorithmConstraints( // only allow the expected signature 
algorithm(s) in the
+              // given context
+              new AlgorithmConstraints(
+                  AlgorithmConstraints.ConstraintType.PERMIT, 
algAllowlist.toArray(new String[0])));
     jwtConsumerBuilder.setVerificationKeyResolver(verificationKeyResolver);
     jwtConsumer = jwtConsumerBuilder.build(); // create the JwtConsumer 
instance
   }
@@ -571,11 +703,10 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
   }
 
   /**
-   * Operate the commands on the latest conf and return a new conf object
-   * If there are errors in the commands , throw a SolrException. return a null
-   * if no changes are to be made as a result of this edit. It is the 
responsibility
-   * of the implementation to ensure that the returned config is valid . The 
framework
-   * does no validation of the data
+   * Operate the commands on the latest conf and return a new conf object If 
there are errors in the
+   * commands , throw a SolrException. return a null if no changes are to be 
made as a result of
+   * this edit. It is the responsibility of the implementation to ensure that 
the returned config is
+   * valid . The framework does no validation of the data
    *
    * @param latestConf latest version of config
    * @param commands the list of command operations to perform
@@ -598,9 +729,18 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
     return latestConf;
   }
 
-  private enum BearerWwwAuthErrorCode { invalid_request, invalid_token, 
insufficient_scope}
+  private enum BearerWwwAuthErrorCode {
+    invalid_request,
+    invalid_token,
+    insufficient_scope
+  }
 
-  private void authenticationFailure(HttpServletResponse response, String 
message, int httpCode, BearerWwwAuthErrorCode responseError) throws IOException 
{
+  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);
@@ -608,12 +748,15 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
 
   /**
    * Generate proper response prompt headers
-   * @param responseError standardized error code. Set to 'null' to generate 
WWW-Authenticate header with no error
+   *
+   * @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<String, String> getPromptHeaders(BearerWwwAuthErrorCode 
responseError, String message) {
-    Map<String,String> headers = new HashMap<>();
+  private Map<String, String> getPromptHeaders(
+      BearerWwwAuthErrorCode responseError, String message) {
+    Map<String, String> headers = new HashMap<>();
     List<String> wwwAuthParams = new ArrayList<>();
     wwwAuthParams.add("Bearer realm=\"" + realm + "\"");
     if (responseError != null) {
@@ -627,8 +770,9 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
 
   protected String generateAuthDataHeader() {
     JWTIssuerConfig primaryIssuer = getPrimaryIssuer();
-    Map<String,Object> data = new HashMap<>();
-    data.put(JWTIssuerConfig.PARAM_AUTHORIZATION_ENDPOINT, 
primaryIssuer.getAuthorizationEndpoint());
+    Map<String, Object> data = new HashMap<>();
+    data.put(
+        JWTIssuerConfig.PARAM_AUTHORIZATION_ENDPOINT, 
primaryIssuer.getAuthorizationEndpoint());
     data.put("client_id", primaryIssuer.getClientId());
     data.put("scope", adminUiScope);
     data.put("redirect_uris", redirectUris);
@@ -636,78 +780,80 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
     return 
Base64.getEncoder().encodeToString(headerJson.getBytes(StandardCharsets.UTF_8));
   }
 
-  /**
-   * Response for authentication attempt
-   */
+  /** Response for authentication attempt */
   static class JWTAuthenticationResponse {
     private final Principal principal;
     private String errorMessage;
     private final AuthCode authCode;
     private InvalidJwtException jwtException;
-  
+
     enum AuthCode {
-      PASS_THROUGH("No user, pass through"),             // Returned when no 
user authentication but block_unknown=false 
-      AUTHENTICATED("Authenticated"),                    // Returned when 
authentication OK 
-      PRINCIPAL_MISSING("No principal in JWT"),          // JWT token does not 
contain necessary principal (typically sub)  
-      JWT_PARSE_ERROR("Invalid JWT"),                    // Problems with 
parsing the JWT itself 
-      AUTZ_HEADER_PROBLEM("Wrong header"),               // The Authorization 
header exists but is not correct 
-      NO_AUTZ_HEADER("Require authentication"),          // The Authorization 
header is missing 
-      JWT_EXPIRED("JWT token expired"),                  // JWT token has 
expired 
-      CLAIM_MISMATCH("Required JWT claim missing"),      // Some required 
claims are missing or wrong 
-      JWT_VALIDATION_EXCEPTION("JWT validation failed"), // The JWT parser 
failed validation. More details in exception
-      SCOPE_MISSING("Required scope missing in JWT"),    // None of the 
required scopes were present in JWT
-      SIGNATURE_INVALID("Signature invalid");            // Validation of JWT 
signature failed
+      PASS_THROUGH(
+          "No user, pass through"), // Returned when no user authentication 
but block_unknown=false
+      AUTHENTICATED("Authenticated"), // Returned when authentication OK
+      PRINCIPAL_MISSING(
+          "No principal in JWT"), // JWT token does not contain necessary 
principal (typically sub)
+      JWT_PARSE_ERROR("Invalid JWT"), // Problems with parsing the JWT itself
+      AUTZ_HEADER_PROBLEM("Wrong header"), // The Authorization header exists 
but is not correct
+      NO_AUTZ_HEADER("Require authentication"), // The Authorization header is 
missing
+      JWT_EXPIRED("JWT token expired"), // JWT token has expired
+      CLAIM_MISMATCH("Required JWT claim missing"), // Some required claims 
are missing or wrong
+      JWT_VALIDATION_EXCEPTION(
+          "JWT validation failed"), // The JWT parser failed validation. More 
details in exception
+      SCOPE_MISSING(
+          "Required scope missing in JWT"), // None of the required scopes 
were present in JWT
+      SIGNATURE_INVALID("Signature invalid"); // Validation of JWT signature 
failed
 
       public String getMsg() {
         return msg;
       }
-  
+
       private final String msg;
-  
+
       AuthCode(String msg) {
         this.msg = msg;
       }
     }
-  
+
     JWTAuthenticationResponse(AuthCode authCode, InvalidJwtException e) {
       this.authCode = authCode;
       this.jwtException = e;
       principal = null;
       this.errorMessage = e.getMessage();
     }
-    
+
     JWTAuthenticationResponse(AuthCode authCode, String errorMessage) {
       this.authCode = authCode;
       this.errorMessage = errorMessage;
       principal = null;
     }
-  
+
     JWTAuthenticationResponse(AuthCode authCode, Principal principal) {
       this.authCode = authCode;
       this.principal = principal;
     }
-    
+
     JWTAuthenticationResponse(AuthCode authCode) {
       this.authCode = authCode;
       principal = null;
     }
-  
+
     boolean isAuthenticated() {
       return authCode.equals(AuthCode.AUTHENTICATED);
     }
-  
+
     public Principal getPrincipal() {
       return principal;
     }
-  
+
     String getErrorMessage() {
       return errorMessage;
     }
-  
+
     InvalidJwtException getJwtException() {
       return jwtException;
     }
-  
+
     AuthCode getAuthCode() {
       return authCode;
     }
@@ -743,6 +889,7 @@ public class JWTAuthPlugin extends AuthenticationPlugin 
implements SpecProvider,
 
   /**
    * Lookup issuer config by its name
+   *
    * @param name name property of config
    * @return issuer config object or null if not found
    */
diff --git a/solr/core/src/java/org/apache/solr/security/JWTIssuerConfig.java 
b/solr/core/src/java/org/apache/solr/security/JWTIssuerConfig.java
index c7e67bf..11b4115 100644
--- a/solr/core/src/java/org/apache/solr/security/JWTIssuerConfig.java
+++ b/solr/core/src/java/org/apache/solr/security/JWTIssuerConfig.java
@@ -18,18 +18,6 @@
 package org.apache.solr.security;
 
 import com.google.common.annotations.VisibleForTesting;
-import org.apache.commons.io.IOUtils;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.util.Utils;
-import org.jose4j.http.Get;
-import org.jose4j.http.SimpleResponse;
-import org.jose4j.jwk.HttpsJwks;
-import org.jose4j.jwk.JsonWebKey;
-import org.jose4j.jwk.JsonWebKeySet;
-import org.jose4j.lang.JoseException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -46,10 +34,19 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
+import org.apache.commons.io.IOUtils;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.util.Utils;
+import org.jose4j.http.Get;
+import org.jose4j.http.SimpleResponse;
+import org.jose4j.jwk.HttpsJwks;
+import org.jose4j.jwk.JsonWebKey;
+import org.jose4j.jwk.JsonWebKeySet;
+import org.jose4j.lang.JoseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-/**
- * Holds information about an IdP (issuer), such as issuer ID, JWK url(s), 
keys etc
- */
+/** Holds information about an IdP (issuer), such as issuer ID, JWK url(s), 
keys etc */
 public class JWTIssuerConfig {
   private static final Logger log = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
   static final String PARAM_ISS_NAME = "name";
@@ -61,8 +58,7 @@ public class JWTIssuerConfig {
   static final String PARAM_AUTHORIZATION_ENDPOINT = "authorizationEndpoint";
   static final String PARAM_CLIENT_ID = "clientId";
 
-  private static HttpsJwksFactory httpsJwksFactory =
-      new HttpsJwksFactory(3600, 5000);
+  private static HttpsJwksFactory httpsJwksFactory = new 
HttpsJwksFactory(3600, 5000);
   private String iss;
   private String aud;
   private JsonWebKeySet jsonWebKeySet;
@@ -75,12 +71,14 @@ public class JWTIssuerConfig {
   private String authorizationEndpoint;
   private Collection<X509Certificate> trustedCerts;
 
-  public static boolean ALLOW_OUTBOUND_HTTP = 
Boolean.parseBoolean(System.getProperty("solr.auth.jwt.allowOutboundHttp", 
"false"));
-  public static final String ALLOW_OUTBOUND_HTTP_ERR_MSG = "HTTPS required for 
IDP communication. Please use SSL or start your nodes with 
-Dsolr.auth.jwt.allowOutboundHttp=true to allow HTTP for test purposes.";
+  public static boolean ALLOW_OUTBOUND_HTTP =
+      
Boolean.parseBoolean(System.getProperty("solr.auth.jwt.allowOutboundHttp", 
"false"));
+  public static final String ALLOW_OUTBOUND_HTTP_ERR_MSG =
+      "HTTPS required for IDP communication. Please use SSL or start your 
nodes with -Dsolr.auth.jwt.allowOutboundHttp=true to allow HTTP for test 
purposes.";
 
   /**
-   * Create config for further configuration with setters, builder style.
-   * Once all values are set, call {@link #init()} before further use
+   * Create config for further configuration with setters, builder style. Once 
all values are set,
+   * call {@link #init()} before further use
    *
    * @param name a unique name for this issuer
    */
@@ -98,8 +96,9 @@ public class JWTIssuerConfig {
   }
 
   /**
-   * Call this to validate and initialize an object which is populated with 
setters.
-   * Init will fetch wellKnownUrl if relevant
+   * Call this to validate and initialize an object which is populated with 
setters. Init will fetch
+   * wellKnownUrl if relevant
+   *
    * @throws SolrException if issuer is missing
    */
   public void init() {
@@ -110,7 +109,9 @@ public class JWTIssuerConfig {
       try {
         wellKnownDiscoveryConfig = fetchWellKnown(new URL(wellKnownUrl));
       } catch (MalformedURLException e) {
-        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Wrong 
URL given for well-known endpoint " + wellKnownUrl);
+        throw new SolrException(
+            SolrException.ErrorCode.SERVER_ERROR,
+            "Wrong URL given for well-known endpoint " + wellKnownUrl);
       }
       if (iss == null) {
         iss = wellKnownDiscoveryConfig.getIssuer();
@@ -123,12 +124,15 @@ public class JWTIssuerConfig {
       }
     }
     if (iss == null && usesHttpsJwk() && 
!JWTAuthPlugin.PRIMARY_ISSUER.equals(name)) {
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Missing 
required config 'iss' for issuer " + getName());
+      throw new SolrException(
+          SolrException.ErrorCode.SERVER_ERROR,
+          "Missing required config 'iss' for issuer " + getName());
     }
   }
 
   /**
    * Parses configuration for one IssuerConfig and sets all variables found
+   *
    * @throws SolrException if unknown parameter names found in config
    */
   protected void parseConfigMap(Map<String, Object> configMap) {
@@ -153,12 +157,15 @@ public class JWTIssuerConfig {
     conf.remove(PARAM_AUTHORIZATION_ENDPOINT);
 
     if (!conf.isEmpty()) {
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown 
configuration key " + conf.keySet() + " for issuer " + name);
+      throw new SolrException(
+          SolrException.ErrorCode.SERVER_ERROR,
+          "Unknown configuration key " + conf.keySet() + " for issuer " + 
name);
     }
   }
 
   /**
    * Setter that takes a jwk config object, parses it into a {@link 
JsonWebKeySet} and sets it
+   *
    * @param jwksObject the config object to parse
    */
   @SuppressWarnings("unchecked")
@@ -168,7 +175,10 @@ public class JWTIssuerConfig {
         jsonWebKeySet = parseJwkSet((Map<String, Object>) jwksObject);
       }
     } catch (JoseException e) {
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Failed 
parsing parameter 'jwk' for issuer " + getName(), e);
+      throw new SolrException(
+          SolrException.ErrorCode.SERVER_ERROR,
+          "Failed parsing parameter 'jwk' for issuer " + getName(),
+          e);
     }
   }
 
@@ -228,6 +238,7 @@ public class JWTIssuerConfig {
 
   /**
    * Setter that converts from String or List into a list
+   *
    * @param jwksUrlListOrString object that should be either string or list
    * @return this for builder pattern
    * @throws SolrException if wrong type
@@ -236,10 +247,11 @@ public class JWTIssuerConfig {
   public JWTIssuerConfig setJwksUrl(Object jwksUrlListOrString) {
     if (jwksUrlListOrString instanceof String)
       this.jwksUrl = Collections.singletonList((String) jwksUrlListOrString);
-    else if (jwksUrlListOrString instanceof List)
-      this.jwksUrl = (List<String>) jwksUrlListOrString;
+    else if (jwksUrlListOrString instanceof List) this.jwksUrl = 
(List<String>) jwksUrlListOrString;
     else if (jwksUrlListOrString != null)
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Parameter 
" + PARAM_JWKS_URL + " must be either List or String");
+      throw new SolrException(
+          SolrException.ErrorCode.SERVER_ERROR,
+          "Parameter " + PARAM_JWKS_URL + " must be either List or String");
     return this;
   }
 
@@ -252,6 +264,7 @@ public class JWTIssuerConfig {
 
   /**
    * Set the factory to use when creating HttpsJwks objects
+   *
    * @param httpsJwksFactory factory with custom settings
    */
   public static void setHttpsJwksFactory(HttpsJwksFactory httpsJwksFactory) {
@@ -269,6 +282,7 @@ public class JWTIssuerConfig {
 
   /**
    * Check if the issuer is backed by HttpsJwk url(s)
+   *
    * @return true if keys are fetched over https
    */
   public boolean usesHttpsJwk() {
@@ -306,8 +320,8 @@ public class JWTIssuerConfig {
     return this;
   }
 
-  public Map<String,Object> asConfig() {
-    HashMap<String,Object> config = new HashMap<>();
+  public Map<String, Object> asConfig() {
+    HashMap<String, Object> config = new HashMap<>();
     putIfNotNull(config, PARAM_ISS_NAME, name);
     putIfNotNull(config, PARAM_ISSUER, iss);
     putIfNotNull(config, PARAM_AUDIENCE, aud);
@@ -329,6 +343,7 @@ public class JWTIssuerConfig {
 
   /**
    * Validates that this config has a name and either jwksUrl, wellkKownUrl or 
jwk
+   *
    * @return true if a configuration is found and is valid, otherwise false
    * @throws SolrException if configuration is present but wrong
    */
@@ -337,11 +352,18 @@ public class JWTIssuerConfig {
     jwkConfigured += jwksUrl != null ? 2 : 0;
     jwkConfigured += jsonWebKeySet != null ? 2 : 0;
     if (jwkConfigured > 3) {
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, 
"JWTAuthPlugin needs to configure exactly one of " +
-          PARAM_WELL_KNOWN_URL + ", " + PARAM_JWKS_URL + " and " + PARAM_JWK);
+      throw new SolrException(
+          SolrException.ErrorCode.SERVER_ERROR,
+          "JWTAuthPlugin needs to configure exactly one of "
+              + PARAM_WELL_KNOWN_URL
+              + ", "
+              + PARAM_JWKS_URL
+              + " and "
+              + PARAM_JWK);
     }
     if (jwkConfigured > 0 && name == null) {
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+      throw new SolrException(
+          SolrException.ErrorCode.SERVER_ERROR,
           "Parameter 'name' is required for issuer configurations");
     }
     return jwkConfigured > 0;
@@ -356,9 +378,7 @@ public class JWTIssuerConfig {
     return this.trustedCerts;
   }
 
-  /**
-   *
-   */
+  /** */
   static class HttpsJwksFactory {
     private final long jwkCacheDuration;
     private final long refreshReprieveThreshold;
@@ -369,7 +389,10 @@ public class JWTIssuerConfig {
       this.refreshReprieveThreshold = refreshReprieveThreshold;
     }
 
-    public HttpsJwksFactory(long jwkCacheDuration, long 
refreshReprieveThreshold, Collection<X509Certificate> trustedCerts) {
+    public HttpsJwksFactory(
+        long jwkCacheDuration,
+        long refreshReprieveThreshold,
+        Collection<X509Certificate> trustedCerts) {
       this.jwkCacheDuration = jwkCacheDuration;
       this.refreshReprieveThreshold = refreshReprieveThreshold;
       this.trustedCerts = trustedCerts;
@@ -386,7 +409,9 @@ public class JWTIssuerConfig {
         jwksUrl = new URL(url);
         checkAllowOutboundHttpConnections(PARAM_JWKS_URL, jwksUrl);
       } catch (MalformedURLException e) {
-        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Url " + 
url + " configured in " + PARAM_JWKS_URL + " is not a valid URL");
+        throw new SolrException(
+            SolrException.ErrorCode.SERVER_ERROR,
+            "Url " + url + " configured in " + PARAM_JWKS_URL + " is not a 
valid URL");
       }
       HttpsJwks httpsJkws = new HttpsJwks(url);
       httpsJkws.setDefaultCacheDuration(jwkCacheDuration);
@@ -408,8 +433,8 @@ public class JWTIssuerConfig {
   }
 
   /**
-   * Config object for a OpenId Connect well-known config
-   * Typically exposed through /.well-known/openid-configuration endpoint
+   * Config object for a OpenId Connect well-known config Typically exposed 
through
+   * /.well-known/openid-configuration endpoint
    */
   public static class WellKnownDiscoveryConfig {
     private final Map<String, Object> securityConf;
@@ -424,14 +449,19 @@ public class JWTIssuerConfig {
 
     /**
      * Fetch well-known config from a URL, with optional list of trusted 
certificates
+     *
      * @param url the url to fetch
-     * @param trustedCerts optional list of trusted SSL certs. May be null to 
fall-back to Java's defaults
+     * @param trustedCerts optional list of trusted SSL certs. May be null to 
fall-back to Java's
+     *     defaults
      * @return an instance of WellKnownDiscoveryConfig object
      */
-    public static WellKnownDiscoveryConfig parse(URL url, 
Collection<X509Certificate> trustedCerts) {
+    public static WellKnownDiscoveryConfig parse(
+        URL url, Collection<X509Certificate> trustedCerts) {
       try {
         if (!Arrays.asList("https", "file", 
"http").contains(url.getProtocol())) {
-          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, 
"Well-known config URL must be one of HTTPS or HTTP or file");
+          throw new SolrException(
+              SolrException.ErrorCode.BAD_REQUEST,
+              "Well-known config URL must be one of HTTPS or HTTP or file");
         }
         checkAllowOutboundHttpConnections(PARAM_WELL_KNOWN_URL, url);
 
@@ -449,7 +479,10 @@ public class JWTIssuerConfig {
           return parse(IOUtils.toInputStream(resp.getBody(), 
StandardCharsets.UTF_8));
         }
       } catch (IOException e) {
-        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, 
"Well-known config could not be read from url " + url, e);
+        throw new SolrException(
+            SolrException.ErrorCode.SERVER_ERROR,
+            "Well-known config could not be read from url " + url,
+            e);
       }
     }
 
@@ -463,7 +496,6 @@ public class JWTIssuerConfig {
       return new WellKnownDiscoveryConfig((Map<String, Object>) 
Utils.fromJSON(configStream));
     }
 
-
     public String getJwksUrl() {
       return (String) securityConf.get("jwks_uri");
     }
@@ -498,9 +530,10 @@ public class JWTIssuerConfig {
   public static void checkAllowOutboundHttpConnections(String parameterName, 
URL url) {
     if ("http".equalsIgnoreCase(url.getProtocol())) {
       if (!ALLOW_OUTBOUND_HTTP) {
-        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, 
parameterName + " is using http protocol. " + ALLOW_OUTBOUND_HTTP_ERR_MSG);
+        throw new SolrException(
+            SolrException.ErrorCode.BAD_REQUEST,
+            parameterName + " is using http protocol. " + 
ALLOW_OUTBOUND_HTTP_ERR_MSG);
       }
     }
   }
- 
 }
diff --git a/solr/core/src/java/org/apache/solr/security/JWTPrincipal.java 
b/solr/core/src/java/org/apache/solr/security/JWTPrincipal.java
index 810e49c..a779fad 100644
--- a/solr/core/src/java/org/apache/solr/security/JWTPrincipal.java
+++ b/solr/core/src/java/org/apache/solr/security/JWTPrincipal.java
@@ -20,24 +20,22 @@ package org.apache.solr.security;
 import java.security.Principal;
 import java.util.Map;
 import java.util.Objects;
-
 import org.apache.http.util.Args;
 
-/**
- * Principal object that carries JWT token and claims for authenticated user.
- */
+/** Principal object that carries JWT token and claims for authenticated user. 
*/
 public class JWTPrincipal implements Principal {
   final String username;
   String token;
-  Map<String,Object> claims;
+  Map<String, Object> claims;
 
   /**
    * User principal with user name as well as one or more roles that he/she 
belong to
+   *
    * @param username string with user name for user
    * @param token compact string representation of JWT token
    * @param claims list of verified JWT claims as a map
    */
-  public JWTPrincipal(final String username, String token, Map<String,Object> 
claims) {
+  public JWTPrincipal(final String username, String token, Map<String, Object> 
claims) {
     super();
     Args.notNull(username, "User name");
     Args.notNull(token, "JWT token");
@@ -65,9 +63,9 @@ public class JWTPrincipal implements Principal {
     if (this == o) return true;
     if (o == null || getClass() != o.getClass()) return false;
     JWTPrincipal that = (JWTPrincipal) o;
-    return Objects.equals(username, that.username) &&
-        Objects.equals(token, that.token) &&
-        Objects.equals(claims, that.claims);
+    return Objects.equals(username, that.username)
+        && Objects.equals(token, that.token)
+        && Objects.equals(claims, that.claims);
   }
 
   @Override
@@ -77,10 +75,15 @@ public class JWTPrincipal implements Principal {
 
   @Override
   public String toString() {
-    return "JWTPrincipal{" +
-        "username='" + username + '\'' +
-        ", token='" + "*****" + '\'' +
-        ", claims=" + claims +
-        '}';
+    return "JWTPrincipal{"
+        + "username='"
+        + username
+        + '\''
+        + ", token='"
+        + "*****"
+        + '\''
+        + ", claims="
+        + claims
+        + '}';
   }
 }
diff --git 
a/solr/core/src/java/org/apache/solr/security/JWTPrincipalWithUserRoles.java 
b/solr/core/src/java/org/apache/solr/security/JWTPrincipalWithUserRoles.java
index 850dc1f..856e6c2 100644
--- a/solr/core/src/java/org/apache/solr/security/JWTPrincipalWithUserRoles.java
+++ b/solr/core/src/java/org/apache/solr/security/JWTPrincipalWithUserRoles.java
@@ -20,27 +20,25 @@ package org.apache.solr.security;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
-
 import org.apache.http.util.Args;
 
 /**
- * JWT principal that contains username, token, claims and a list of roles the 
user has, 
- * so one can keep track of user-role mappings in an Identity Server external 
to Solr and 
- * pass the information to Solr in a signed JWT token. The role information 
can then be used to authorize
- * requests without the need to maintain or lookup what roles each user 
belongs to.
+ * JWT principal that contains username, token, claims and a list of roles the 
user has, so one can
+ * keep track of user-role mappings in an Identity Server external to Solr and 
pass the information
+ * to Solr in a signed JWT token. The role information can then be used to 
authorize requests
+ * without the need to maintain or lookup what roles each user belongs to.
  */
 public class JWTPrincipalWithUserRoles extends JWTPrincipal implements 
VerifiedUserRoles {
   private final Set<String> roles;
 
-  public JWTPrincipalWithUserRoles(final String username, String token, 
Map<String,Object> claims, Set<String> roles) {
+  public JWTPrincipalWithUserRoles(
+      final String username, String token, Map<String, Object> claims, 
Set<String> roles) {
     super(username, token, claims);
     Args.notNull(roles, "User roles");
     this.roles = roles;
   }
 
-  /**
-   * Gets the list of roles
-   */
+  /** Gets the list of roles */
   @Override
   public Set<String> getVerifiedRoles() {
     return roles;
@@ -48,8 +46,7 @@ public class JWTPrincipalWithUserRoles extends JWTPrincipal 
implements VerifiedU
 
   @Override
   public boolean equals(Object o) {
-    if (!(o instanceof JWTPrincipalWithUserRoles))
-      return false;
+    if (!(o instanceof JWTPrincipalWithUserRoles)) return false;
     JWTPrincipalWithUserRoles that = (JWTPrincipalWithUserRoles) o;
     return super.equals(o) && roles.equals(that.roles);
   }
@@ -61,11 +58,17 @@ public class JWTPrincipalWithUserRoles extends JWTPrincipal 
implements VerifiedU
 
   @Override
   public String toString() {
-    return "JWTPrincipalWithUserRoles{" +
-        "username='" + username + '\'' +
-        ", token='" + "*****" + '\'' +
-        ", claims=" + claims +
-        ", roles=" + roles +
-        '}';
+    return "JWTPrincipalWithUserRoles{"
+        + "username='"
+        + username
+        + '\''
+        + ", token='"
+        + "*****"
+        + '\''
+        + ", claims="
+        + claims
+        + ", roles="
+        + roles
+        + '}';
   }
 }
diff --git 
a/solr/core/src/java/org/apache/solr/security/JWTVerificationkeyResolver.java 
b/solr/core/src/java/org/apache/solr/security/JWTVerificationkeyResolver.java
index f3a9c8c..08e5cb5 100644
--- 
a/solr/core/src/java/org/apache/solr/security/JWTVerificationkeyResolver.java
+++ 
b/solr/core/src/java/org/apache/solr/security/JWTVerificationkeyResolver.java
@@ -26,7 +26,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
+import javax.net.ssl.SSLHandshakeException;
 import org.apache.solr.common.SolrException;
 import org.jose4j.jwk.HttpsJwks;
 import org.jose4j.jwk.JsonWebKey;
@@ -42,18 +42,18 @@ import org.jose4j.lang.UnresolvableKeyException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.net.ssl.SSLHandshakeException;
-
 /**
- * Resolves jws signature verification keys from a set of {@link 
JWTIssuerConfig} objects, which
- * may represent any valid configuration in Solr's security.json, i.e. static 
list of JWKs
- * or keys retrieved from HTTPs JWK endpoints.
+ * Resolves jws signature verification keys from a set of {@link 
JWTIssuerConfig} objects, which may
+ * represent any valid configuration in Solr's security.json, i.e. static list 
of JWKs or keys
+ * retrieved from HTTPs JWK endpoints.
  *
- * This implementation maintains a map of issuers, each with its own list of 
{@link JsonWebKey},
- * and resolves correct key from correct issuer similar to 
HttpsJwksVerificationKeyResolver.
- * If issuer claim is not required, we will select the first IssuerConfig if 
there is exactly one such config.
+ * <p>This implementation maintains a map of issuers, each with its own list 
of {@link JsonWebKey},
+ * and resolves correct key from correct issuer similar to 
HttpsJwksVerificationKeyResolver. If
+ * issuer claim is not required, we will select the first IssuerConfig if 
there is exactly one such
+ * config.
  *
- * If a key is not found, and issuer is backed by HTTPsJWKs, we attempt one 
cache refresh before failing.
+ * <p>If a key is not found, and issuer is backed by HTTPsJWKs, we attempt one 
cache refresh before
+ * failing.
  */
 public class JWTVerificationkeyResolver implements VerificationKeyResolver {
   private static final Logger log = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -65,18 +65,22 @@ public class JWTVerificationkeyResolver implements 
VerificationKeyResolver {
 
   /**
    * Resolves key from a JWKs from one or more IssuerConfigs
+   *
    * @param issuerConfigs Collection of configuration objects for the issuer(s)
    * @param requireIssuer if true, will require 'iss' claim on jws
    */
-  public JWTVerificationkeyResolver(Collection<JWTIssuerConfig> issuerConfigs, 
boolean requireIssuer) {
+  public JWTVerificationkeyResolver(
+      Collection<JWTIssuerConfig> issuerConfigs, boolean requireIssuer) {
     this.requireIssuer = requireIssuer;
-    issuerConfigs.forEach(ic -> {
-      this.issuerConfigs.put(ic.getIss(), ic);
-    });
+    issuerConfigs.forEach(
+        ic -> {
+          this.issuerConfigs.put(ic.getIss(), ic);
+        });
   }
 
   @Override
-  public Key resolveKey(JsonWebSignature jws, List<JsonWebStructure> 
nestingContext) throws UnresolvableKeyException {
+  public Key resolveKey(JsonWebSignature jws, List<JsonWebStructure> 
nestingContext)
+      throws UnresolvableKeyException {
     JsonWebKey theChosenOne;
     List<JsonWebKey> jsonWebKeys = new ArrayList<>();
 
@@ -90,19 +94,23 @@ public class JWTVerificationkeyResolver implements 
VerificationKeyResolver {
         } else if (issuerConfigs.size() == 1) {
           issuerConfig = issuerConfigs.values().iterator().next();
         } else {
-          throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+          throw new SolrException(
+              SolrException.ErrorCode.SERVER_ERROR,
               "Signature verifiction not supported for multiple issuers 
without 'iss' claim in token.");
         }
       } else {
         issuerConfig = issuerConfigs.get(tokenIssuer);
         if (issuerConfig == null) {
           if (issuerConfigs.size() > 1) {
-            throw new UnresolvableKeyException("No issuers configured for 
iss='" + tokenIssuer + "', cannot validate signature");
+            throw new UnresolvableKeyException(
+                "No issuers configured for iss='" + tokenIssuer + "', cannot 
validate signature");
           } else if (issuerConfigs.size() == 1) {
             issuerConfig = issuerConfigs.values().iterator().next();
-            log.debug("No issuer matching token's iss claim, but exactly one 
configured, selecting that one");
+            log.debug(
+                "No issuer matching token's iss claim, but exactly one 
configured, selecting that one");
           } else {
-            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+            throw new SolrException(
+                SolrException.ErrorCode.SERVER_ERROR,
                 "Signature verifiction failed due to no configured issuer with 
id " + tokenIssuer);
           }
         }
@@ -115,8 +123,12 @@ public class JWTVerificationkeyResolver implements 
VerificationKeyResolver {
           try {
             jsonWebKeys.addAll(hjwks.getJsonWebKeys());
           } catch (SSLHandshakeException e) {
-            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
-                "Failed to connect with " + hjwks.getLocation() + ", do you 
have the correct SSL certificate configured?", e);
+            throw new SolrException(
+                SolrException.ErrorCode.SERVER_ERROR,
+                "Failed to connect with "
+                    + hjwks.getLocation()
+                    + ", do you have the correct SSL certificate configured?",
+                e);
           }
         }
       } else {
@@ -127,8 +139,11 @@ public class JWTVerificationkeyResolver implements 
VerificationKeyResolver {
       theChosenOne = verificationJwkSelector.select(jws, jsonWebKeys);
       if (theChosenOne == null && issuerConfig.usesHttpsJwk()) {
         if (log.isDebugEnabled()) {
-          log.debug("Refreshing JWKs from all {} locations, as no suitable 
verification key for JWS w/ header {} was found in {}",
-              issuerConfig.getHttpsJwks().size(), 
jws.getHeaders().getFullHeaderAsJsonString(), jsonWebKeys);
+          log.debug(
+              "Refreshing JWKs from all {} locations, as no suitable 
verification key for JWS w/ header {} was found in {}",
+              issuerConfig.getHttpsJwks().size(),
+              jws.getHeaders().getFullHeaderAsJsonString(),
+              jsonWebKeys);
         }
 
         jsonWebKeys.clear();
@@ -140,16 +155,23 @@ public class JWTVerificationkeyResolver implements 
VerificationKeyResolver {
       }
     } catch (JoseException | IOException | InvalidJwtException | 
MalformedClaimException e) {
       StringBuilder sb = new StringBuilder();
-      sb.append("Unable to find a suitable verification key for JWS w/ header 
").append(jws.getHeaders().getFullHeaderAsJsonString());
-      sb.append(" due to an unexpected exception (").append(e).append(") while 
obtaining or using keys from source ");
+      sb.append("Unable to find a suitable verification key for JWS w/ header 
")
+          .append(jws.getHeaders().getFullHeaderAsJsonString());
+      sb.append(" due to an unexpected exception (")
+          .append(e)
+          .append(") while obtaining or using keys from source ");
       sb.append(keysSource);
       throw new UnresolvableKeyException(sb.toString(), e);
     }
 
     if (theChosenOne == null) {
       StringBuilder sb = new StringBuilder();
-      sb.append("Unable to find a suitable verification key for JWS w/ header 
").append(jws.getHeaders().getFullHeaderAsJsonString());
-      sb.append(" from ").append(jsonWebKeys.size()).append(" keys from source 
").append(keysSource);
+      sb.append("Unable to find a suitable verification key for JWS w/ header 
")
+          .append(jws.getHeaders().getFullHeaderAsJsonString());
+      sb.append(" from ")
+          .append(jsonWebKeys.size())
+          .append(" keys from source ")
+          .append(keysSource);
       throw new UnresolvableKeyException(sb.toString());
     }
 
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 6c4de6d..434469b 100644
--- 
a/solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java
+++ 
b/solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java
@@ -16,6 +16,31 @@
  */
 package org.apache.solr.security;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.KeyStore;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
 import no.nav.security.mock.oauth2.MockOAuth2Server;
 import no.nav.security.mock.oauth2.OAuth2Config;
 import no.nav.security.mock.oauth2.http.MockWebServerWrapper;
@@ -52,38 +77,13 @@ import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManagerFactory;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.security.KeyStore;
-import java.util.Base64;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
 /**
  * Validate that JWT token authentication works in a real cluster.
- * <p> 
- * TODO: Test also using SolrJ as client. But that requires a way to set 
Authorization header on request, see SOLR-13070<br>
- *       This is also the reason we use {@link 
org.apache.solr.SolrTestCaseJ4.SuppressSSL} annotation, since we use 
HttpUrlConnection
- * </p>
+ *
+ * <p>TODO: Test also using SolrJ as client. But that requires a way to set 
Authorization header on
+ * request, see SOLR-13070<br>
+ * This is also the reason we use {@link 
org.apache.solr.SolrTestCaseJ4.SuppressSSL} annotation,
+ * since we use HttpUrlConnection
  */
 @SolrTestCaseJ4.SuppressSSL
 public class JWTAuthPluginIntegrationTest extends SolrCloudAuthTestCase {
@@ -100,15 +100,18 @@ public class JWTAuthPluginIntegrationTest extends 
SolrCloudAuthTestCase {
   @BeforeClass
   public static void beforeClass() throws Exception {
     // Setup an OAuth2 mock server with SSL
-    Path p12Cert = 
SolrTestCaseJ4.TEST_PATH().resolve("security").resolve("jwt_plugin_idp_certs.p12");
+    Path p12Cert =
+        
SolrTestCaseJ4.TEST_PATH().resolve("security").resolve("jwt_plugin_idp_certs.p12");
     pemFilePath = 
SolrTestCaseJ4.TEST_PATH().resolve("security").resolve("jwt_plugin_idp_cert.pem");
-    wrongPemFilePath = 
SolrTestCaseJ4.TEST_PATH().resolve("security").resolve("jwt_plugin_idp_wrongcert.pem");
+    wrongPemFilePath =
+        
SolrTestCaseJ4.TEST_PATH().resolve("security").resolve("jwt_plugin_idp_wrongcert.pem");
 
-    mockOAuth2Server = createMockOAuthServer(p12Cert,"secret");
+    mockOAuth2Server = createMockOAuthServer(p12Cert, "secret");
     mockOAuth2Server.start();
-    mockOAuthToken = mockOAuth2Server.issueToken("default",
-        "myClientId",
-        new DefaultOAuth2TokenCallback()).serialize();
+    mockOAuthToken =
+        mockOAuth2Server
+            .issueToken("default", "myClientId", new 
DefaultOAuth2TokenCallback())
+            .serialize();
     initStaticJwt();
   }
 
@@ -160,29 +163,35 @@ public class JWTAuthPluginIntegrationTest extends 
SolrCloudAuthTestCase {
     assertEquals("Should have received 401 code", "401", headers.get("code"));
     assertEquals("Bearer realm=\"my-solr-jwt\"", 
headers.get("WWW-Authenticate"));
     String authData = new 
String(Base64.getDecoder().decode(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);
+    assertEquals(
+        "{\n"
+            + "  \"scope\":\"solr:admin\",\n"
+            + "  \"redirect_uris\":[],\n"
+            + "  
\"authorizationEndpoint\":\"http://acmepaymentscorp/oauth/auz/authorize\",\n";
+            + "  \"client_id\":\"solr-cluster\"}",
+        authData);
     myCluster.shutdown();
   }
 
   @Test
   public void infoRequestValidateXSolrAuthHeadersBlockUnknownFalse() throws 
Exception {
     // https://issues.apache.org/jira/browse/SOLR-14196
-    MiniSolrCloudCluster myCluster = 
configureClusterStaticKeys("jwt_plugin_jwk_security_blockUnknownFalse.json");
+    MiniSolrCloudCluster myCluster =
+        
configureClusterStaticKeys("jwt_plugin_jwk_security_blockUnknownFalse.json");
     String baseUrl = 
myCluster.getRandomJetty(random()).getBaseUrl().toString();
 
     Map<String, String> 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"));
+    assertEquals(
+        "Bearer realm=\"my-solr-jwt-blockunknown-false\"", 
headers.get("WWW-Authenticate"));
     String authData = new 
String(Base64.getDecoder().decode(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);
+    assertEquals(
+        "{\n"
+            + "  \"scope\":\"solr:admin\",\n"
+            + "  \"redirect_uris\":[],\n"
+            + "  
\"authorizationEndpoint\":\"http://acmepaymentscorp/oauth/auz/authorize\",\n";
+            + "  \"client_id\":\"solr-cluster\"}",
+        authData);
     myCluster.shutdown();
   }
 
@@ -193,28 +202,29 @@ public class JWTAuthPluginIntegrationTest extends 
SolrCloudAuthTestCase {
 
     boolean isUseV2Api = random().nextBoolean();
     String authcPrefix = "/admin/authentication";
-    if(isUseV2Api){
+    if (isUseV2Api) {
       authcPrefix = "/____v2/cluster/security/authentication";
     }
     String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString();
     CloseableHttpClient cl = HttpClientUtil.createClient(null);
-    
+
     createCollection(cluster, COLLECTION);
-    
+
     // Missing token
     getAndFail(baseUrl + "/" + COLLECTION + "/query?q=*:*", null);
     assertAuthMetricsMinimums(2, 1, 0, 0, 1, 0);
     executeCommand(baseUrl + authcPrefix, cl, "{set-property : { blockUnknown: 
false}}", jws);
-    verifySecurityStatus(cl, baseUrl + authcPrefix, 
"authentication/blockUnknown", "false", 20, jws);
+    verifySecurityStatus(
+        cl, baseUrl + authcPrefix, "authentication/blockUnknown", "false", 20, 
jws);
     // Pass through
     verifySecurityStatus(cl, baseUrl + "/admin/info/key", "key", 
NOT_NULL_PREDICATE, 20);
-    // Now succeeds since blockUnknown=false 
+    // Now succeeds since blockUnknown=false
     get(baseUrl + "/" + COLLECTION + "/query?q=*:*", null);
     executeCommand(baseUrl + authcPrefix, cl, "{set-property : { blockUnknown: 
true}}", null);
     verifySecurityStatus(cl, baseUrl + authcPrefix, 
"authentication/blockUnknown", "true", 20, jws);
 
     assertAuthMetricsMinimums(9, 4, 4, 0, 1, 0);
-    
+
     // Wrong Credentials
     getAndFail(baseUrl + "/" + COLLECTION + "/query?q=*:*", 
jwtTokenWrongSignature);
     assertAuthMetricsMinimums(10, 4, 4, 1, 1, 0);
@@ -227,7 +237,11 @@ public class JWTAuthPluginIntegrationTest extends 
SolrCloudAuthTestCase {
     // Now update three documents
     assertAuthMetricsMinimums(1, 1, 0, 0, 0, 0);
     assertPkiAuthMetricsMinimums(2, 2, 0, 0, 0, 0);
-    Pair<String,Integer> result = post(baseUrl + "/" + COLLECTION + 
"/update?commit=true", "[{\"id\" : \"1\"}, {\"id\": \"2\"}, {\"id\": \"3\"}]", 
jwtStaticTestToken);
+    Pair<String, Integer> result =
+        post(
+            baseUrl + "/" + COLLECTION + "/update?commit=true",
+            "[{\"id\" : \"1\"}, {\"id\": \"2\"}, {\"id\": \"3\"}]",
+            jwtStaticTestToken);
     assertEquals(Integer.valueOf(200), result.second());
     assertAuthMetricsMinimums(4, 4, 0, 0, 0, 0);
     assertPkiAuthMetricsMinimums(2, 2, 0, 0, 0, 0);
@@ -243,7 +257,11 @@ public class JWTAuthPluginIntegrationTest extends 
SolrCloudAuthTestCase {
     assertAuthMetricsMinimums(10, 10, 0, 0, 0, 0);
 
     // Delete
-    assertEquals(200, get(baseUrl + "/admin/collections?action=DELETE&name=" + 
COLLECTION, jwtStaticTestToken).second().intValue());
+    assertEquals(
+        200,
+        get(baseUrl + "/admin/collections?action=DELETE&name=" + COLLECTION, 
jwtStaticTestToken)
+            .second()
+            .intValue());
     assertAuthMetricsMinimums(11, 11, 0, 0, 0, 0);
     assertPkiAuthMetricsMinimums(4, 4, 0, 0, 0, 0);
 
@@ -252,25 +270,31 @@ public class JWTAuthPluginIntegrationTest extends 
SolrCloudAuthTestCase {
 
   /**
    * Configure solr cluster with a security.json talking to MockOAuth2 server
+   *
    * @param numNodes number of nodes in cluster
    * @param pemFilePath path to PEM file for SSL cert to trust for OAuth2 
server
    * @param timeoutMs how long to wait until the new security.json is applied 
to the cluster
    * @return an instance of the created cluster that the test can talk to
    */
   @SuppressWarnings("BusyWait")
-  private MiniSolrCloudCluster configureClusterMockOauth(int numNodes, Path 
pemFilePath, long timeoutMs) throws Exception {
-    MiniSolrCloudCluster myCluster = configureCluster(numNodes)// nodes
-        .addConfig("conf1", 
TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
-        .withDefaultClusterProperty("useLegacyReplicaAssignment", "false")
-        .build();
+  private MiniSolrCloudCluster configureClusterMockOauth(
+      int numNodes, Path pemFilePath, long timeoutMs) throws Exception {
+    MiniSolrCloudCluster myCluster =
+        configureCluster(numNodes) // nodes
+            .addConfig(
+                "conf1", 
TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
+            .withDefaultClusterProperty("useLegacyReplicaAssignment", "false")
+            .build();
     String securityJson = createMockOAuthSecurityJson(pemFilePath);
-    myCluster.getZkClient().setData("/security.json", 
securityJson.getBytes(Charset.defaultCharset()), true);
+    myCluster
+        .getZkClient()
+        .setData("/security.json", 
securityJson.getBytes(Charset.defaultCharset()), true);
     RTimer timer = new RTimer();
     do { // Wait timeoutMs time for the security.json change to take effect
       Thread.sleep(200);
       if (timer.getTime() > timeoutMs) {
         myCluster.shutdown();
-        throw new Exception("Custom 'security.json' not applied in " + 
timeoutMs +"ms");
+        throw new Exception("Custom 'security.json' not applied in " + 
timeoutMs + "ms");
       }
     } while 
(myCluster.getJettySolrRunner(0).getCoreContainer().getAuthenticationPlugin() 
== null);
     myCluster.waitForAllNodes(10);
@@ -279,33 +303,36 @@ public class JWTAuthPluginIntegrationTest extends 
SolrCloudAuthTestCase {
 
   /**
    * Configure solr cluster with a security.json made for static keys
+   *
    * @param securityJsonFilename file name of test json, relative to 
test-files/solr/security
    * @return an instance of the created cluster that the test can talk to
    */
-  private MiniSolrCloudCluster configureClusterStaticKeys(String 
securityJsonFilename) throws Exception {
-    MiniSolrCloudCluster myCluster = configureCluster(2)// nodes
-        
.withSecurityJson(TEST_PATH().resolve("security").resolve(securityJsonFilename))
-        .addConfig("conf1", 
TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
-        .withDefaultClusterProperty("useLegacyReplicaAssignment", "false")
-        .build();
+  private MiniSolrCloudCluster configureClusterStaticKeys(String 
securityJsonFilename)
+      throws Exception {
+    MiniSolrCloudCluster myCluster =
+        configureCluster(2) // nodes
+            
.withSecurityJson(TEST_PATH().resolve("security").resolve(securityJsonFilename))
+            .addConfig(
+                "conf1", 
TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
+            .withDefaultClusterProperty("useLegacyReplicaAssignment", "false")
+            .build();
 
     myCluster.waitForAllNodes(10);
     return myCluster;
   }
 
-  /**
-   * Initialize some static JWT keys
-   */
+  /** Initialize some static JWT keys */
   private static void initStaticJwt() throws Exception {
-    String jwkJSON = "{\n" +
-        "  \"kty\": \"RSA\",\n" +
-        "  \"d\": 
\"i6pyv2z3o-MlYytWsOr3IE1olu2RXZBzjPRBNgWAP1TlLNaphHEvH5aHhe_CtBAastgFFMuP29CFhaL3_tGczkvWJkSveZQN2AHWHgRShKgoSVMspkhOt3Ghha4CvpnZ9BnQzVHnaBnHDTTTfVgXz7P1ZNBhQY4URG61DKIF-JSSClyh1xKuMoJX0lILXDYGGcjVTZL_hci4IXPPTpOJHV51-pxuO7WU5M9252UYoiYyCJ56ai8N49aKIMsqhdGuO4aWUwsGIW4oQpjtce5eEojCprYl-9rDhTwLAFoBtjy6LvkqlR2Ae5dKZYpStljBjK8PJrBvWZjXAEMDdQ8PuQ\",\n"
 +
-        "  \"e\": \"AQAB\",\n" +
-        "  \"use\": \"sig\",\n" +
-        "  \"kid\": \"test\",\n" +
-        "  \"alg\": \"RS256\",\n" +
-        "  \"n\": 
\"jeyrvOaZrmKWjyNXt0myAc_pJ1hNt3aRupExJEx1ewPaL9J9HFgSCjMrYxCB1ETO1NDyZ3nSgjZis-jHHDqBxBjRdq_t1E2rkGFaYbxAyKt220Pwgme_SFTB9MXVrFQGkKyjmQeVmOmV6zM3KK8uMdKQJ4aoKmwBcF5Zg7EZdDcKOFgpgva1Jq-FlEsaJ2xrYDYo3KnGcOHIt9_0NQeLsqZbeWYLxYni7uROFncXYV5FhSJCeR4A_rrbwlaCydGxE0ToC_9HNYibUHlkJjqyUhAgORCbNS8JLCJH8NUi5sDdIawK9GTSyvsJXZ-QHqo4cMUuxWV5AJtaRGghuMUfqQ\"\n"
 +
-        "}";
+    String jwkJSON =
+        "{\n"
+            + "  \"kty\": \"RSA\",\n"
+            + "  \"d\": 
\"i6pyv2z3o-MlYytWsOr3IE1olu2RXZBzjPRBNgWAP1TlLNaphHEvH5aHhe_CtBAastgFFMuP29CFhaL3_tGczkvWJkSveZQN2AHWHgRShKgoSVMspkhOt3Ghha4CvpnZ9BnQzVHnaBnHDTTTfVgXz7P1ZNBhQY4URG61DKIF-JSSClyh1xKuMoJX0lILXDYGGcjVTZL_hci4IXPPTpOJHV51-pxuO7WU5M9252UYoiYyCJ56ai8N49aKIMsqhdGuO4aWUwsGIW4oQpjtce5eEojCprYl-9rDhTwLAFoBtjy6LvkqlR2Ae5dKZYpStljBjK8PJrBvWZjXAEMDdQ8PuQ\",\n"
+            + "  \"e\": \"AQAB\",\n"
+            + "  \"use\": \"sig\",\n"
+            + "  \"kid\": \"test\",\n"
+            + "  \"alg\": \"RS256\",\n"
+            + "  \"n\": 
\"jeyrvOaZrmKWjyNXt0myAc_pJ1hNt3aRupExJEx1ewPaL9J9HFgSCjMrYxCB1ETO1NDyZ3nSgjZis-jHHDqBxBjRdq_t1E2rkGFaYbxAyKt220Pwgme_SFTB9MXVrFQGkKyjmQeVmOmV6zM3KK8uMdKQJ4aoKmwBcF5Zg7EZdDcKOFgpgva1Jq-FlEsaJ2xrYDYo3KnGcOHIt9_0NQeLsqZbeWYLxYni7uROFncXYV5FhSJCeR4A_rrbwlaCydGxE0ToC_9HNYibUHlkJjqyUhAgORCbNS8JLCJH8NUi5sDdIawK9GTSyvsJXZ-QHqo4cMUuxWV5AJtaRGghuMUfqQ\"\n"
+            + "}";
 
     PublicJsonWebKey jwk = RsaJsonWebKey.Factory.newPublicJwk(jwkJSON);
     JwtClaims claims = JWTAuthPluginTest.generateClaims();
@@ -331,30 +358,32 @@ public class JWTAuthPluginIntegrationTest extends 
SolrCloudAuthTestCase {
     try {
       get(url, token);
       fail("Request to " + url + " with token " + token + " should have 
failed");
-    } catch(Exception e) { /* Fall through */ }
+    } catch (Exception e) {
+      /* Fall through */
+    }
   }
-  
+
   private Pair<String, Integer> get(String url, String token) throws 
IOException {
     URL createUrl = new URL(url);
     HttpURLConnection createConn = (HttpURLConnection) 
createUrl.openConnection();
-    if (token != null)
-      createConn.setRequestProperty("Authorization", "Bearer " + token);
-    BufferedReader br2 = new BufferedReader(new 
InputStreamReader((InputStream) createConn.getContent(), 
StandardCharsets.UTF_8));
+    if (token != null) createConn.setRequestProperty("Authorization", "Bearer 
" + token);
+    BufferedReader br2 =
+        new BufferedReader(
+            new InputStreamReader((InputStream) createConn.getContent(), 
StandardCharsets.UTF_8));
     String result = br2.lines().collect(Collectors.joining("\n"));
     int code = createConn.getResponseCode();
     createConn.disconnect();
     return new Pair<>(result, code);
   }
 
-  private Map<String,String> getHeaders(String url, String token) throws 
IOException {
+  private Map<String, String> getHeaders(String url, String token) throws 
IOException {
     URL createUrl = new URL(url);
     HttpURLConnection conn = (HttpURLConnection) createUrl.openConnection();
-    if (token != null)
-      conn.setRequestProperty("Authorization", "Bearer " + token);
+    if (token != null) conn.setRequestProperty("Authorization", "Bearer " + 
token);
     conn.connect();
     int code = conn.getResponseCode();
     Map<String, String> result = new HashMap<>();
-    conn.getHeaderFields().forEach((k,v) -> result.put(k, v.get(0)));
+    conn.getHeaderFields().forEach((k, v) -> result.put(k, v.get(0)));
     result.put("code", String.valueOf(code));
     conn.disconnect();
     return result;
@@ -365,8 +394,7 @@ public class JWTAuthPluginIntegrationTest extends 
SolrCloudAuthTestCase {
     HttpURLConnection con = (HttpURLConnection) createUrl.openConnection();
     con.setRequestMethod("POST");
     con.setRequestProperty(HttpHeaders.CONTENT_TYPE, 
ContentType.APPLICATION_JSON.getMimeType());
-    if (token != null)
-      con.setRequestProperty("Authorization", "Bearer " + token);
+    if (token != null) con.setRequestProperty("Authorization", "Bearer " + 
token);
 
     con.setDoOutput(true);
     OutputStream os = con.getOutputStream();
@@ -375,75 +403,97 @@ public class JWTAuthPluginIntegrationTest extends 
SolrCloudAuthTestCase {
     os.close();
 
     con.connect();
-    BufferedReader br2 = new BufferedReader(new 
InputStreamReader((InputStream) con.getContent(), StandardCharsets.UTF_8));
+    BufferedReader br2 =
+        new BufferedReader(
+            new InputStreamReader((InputStream) con.getContent(), 
StandardCharsets.UTF_8));
     String result = br2.lines().collect(Collectors.joining("\n"));
     int code = con.getResponseCode();
     con.disconnect();
     return new Pair<>(result, code);
   }
 
-  private void createCollection(MiniSolrCloudCluster myCluster, String 
collectionName) throws IOException {
+  private void createCollection(MiniSolrCloudCluster myCluster, String 
collectionName)
+      throws IOException {
     String baseUrl = 
myCluster.getRandomJetty(random()).getBaseUrl().toString();
-    assertEquals(200, get(baseUrl + "/admin/collections?action=CREATE&name=" + 
collectionName + "&numShards=2", jwtStaticTestToken).second().intValue());
+    assertEquals(
+        200,
+        get(
+                baseUrl
+                    + "/admin/collections?action=CREATE&name="
+                    + collectionName
+                    + "&numShards=2",
+                jwtStaticTestToken)
+            .second()
+            .intValue());
     myCluster.waitForActiveCollection(collectionName, 2, 2);
   }
 
   private void executeCommand(String url, HttpClient cl, String payload, 
JsonWebSignature jws)
-    throws Exception {
-    
+      throws Exception {
+
     // HACK: work around for SOLR-13464...
     //
     // note the authz/authn objects in use on each node before executing the 
command,
     // then wait until we see new objects on every node *after* executing the 
command
     // before returning...
-    final Set<Map.Entry<String,Object>> initialPlugins
-      = getAuthPluginsInUseForCluster(url).entrySet();
-    
+    final Set<Map.Entry<String, Object>> initialPlugins =
+        getAuthPluginsInUseForCluster(url).entrySet();
+
     HttpPost httpPost;
     HttpResponse r;
     httpPost = new HttpPost(url);
-    if (jws != null)
-      setAuthorizationHeader(httpPost, "Bearer " + 
jws.getCompactSerialization());
+    if (jws != null) setAuthorizationHeader(httpPost, "Bearer " + 
jws.getCompactSerialization());
     httpPost.setEntity(new ByteArrayEntity(payload.getBytes(UTF_8)));
     httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
     r = cl.execute(httpPost);
     String response = IOUtils.toString(r.getEntity().getContent(), 
StandardCharsets.UTF_8);
-    assertEquals("Non-200 response code. Response was " + response, 200, 
r.getStatusLine().getStatusCode());
+    assertEquals(
+        "Non-200 response code. Response was " + response, 200, 
r.getStatusLine().getStatusCode());
     assertFalse("Response contained errors: " + response, 
response.contains("errorMessages"));
     Utils.consumeFully(r.getEntity());
 
     // HACK (continued)...
     final TimeOut timeout = new TimeOut(30, TimeUnit.SECONDS, 
TimeSource.NANO_TIME);
-    timeout.waitFor("core containers never fully updated their auth plugins",
-                    () -> {
-                      final Set<Map.Entry<String,Object>> tmpSet
-                        = getAuthPluginsInUseForCluster(url).entrySet();
-                      tmpSet.retainAll(initialPlugins);
-                      return tmpSet.isEmpty();
-                    });
-    
+    timeout.waitFor(
+        "core containers never fully updated their auth plugins",
+        () -> {
+          final Set<Map.Entry<String, Object>> tmpSet =
+              getAuthPluginsInUseForCluster(url).entrySet();
+          tmpSet.retainAll(initialPlugins);
+          return tmpSet.isEmpty();
+        });
   }
 
   /**
-   * Creates a security.json string which points to the MockOAuth server using 
it's well-known URL and trusting its SSL
+   * Creates a security.json string which points to the MockOAuth server using 
it's well-known URL
+   * and trusting its SSL
    */
   private static String createMockOAuthSecurityJson(Path pemFilePath) throws 
IOException {
-    String wellKnown = mockOAuth2Server.wellKnownUrl("default").toString()
-        .replace(".localdomain", ""); // Use only 'localhost' to match our SSL 
cert
-    String pemCert = 
CryptoKeys.extractCertificateFromPem(Files.readString(pemFilePath))
-        .replaceAll("\n", "\\\\n"); // Use literal \n to play well with JSON
-    return "{\n" +
-        "  \"authentication\" : {\n" +
-        "    \"class\": \"solr.JWTAuthPlugin\",\n" +
-        "    \"wellKnownUrl\": \"" + wellKnown + "\",\n" +
-        "    \"blockUnknown\": true\n" +
-        "    \"trustedCerts\": \"" + pemCert + "\"\n" +
-        "  }\n" +
-        "}";
+    String wellKnown =
+        mockOAuth2Server
+            .wellKnownUrl("default")
+            .toString()
+            .replace(".localdomain", ""); // Use only 'localhost' to match our 
SSL cert
+    String pemCert =
+        CryptoKeys.extractCertificateFromPem(Files.readString(pemFilePath))
+            .replaceAll("\n", "\\\\n"); // Use literal \n to play well with 
JSON
+    return "{\n"
+        + "  \"authentication\" : {\n"
+        + "    \"class\": \"solr.JWTAuthPlugin\",\n"
+        + "    \"wellKnownUrl\": \""
+        + wellKnown
+        + "\",\n"
+        + "    \"blockUnknown\": true\n"
+        + "    \"trustedCerts\": \""
+        + pemCert
+        + "\"\n"
+        + "  }\n"
+        + "}";
   }
 
   /**
    * Create and return a MockOAuth2Server with given SSL certificate
+   *
    * @param p12CertPath path to a p12 certificate store
    * @param secretKeyPass password to secret key
    */
@@ -451,20 +501,26 @@ public class JWTAuthPluginIntegrationTest extends 
SolrCloudAuthTestCase {
     try {
       final KeyStore keystore = KeyStore.getInstance("pkcs12");
       keystore.load(Files.newInputStream(p12CertPath), 
secretKeyPass.toCharArray());
-      final KeyManagerFactory keyManagerFactory = 
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+      final KeyManagerFactory keyManagerFactory =
+          
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
       keyManagerFactory.init(keystore, secretKeyPass.toCharArray());
-      final TrustManagerFactory trustManagerFactory = 
TrustManagerFactory.getInstance(
-          TrustManagerFactory.getDefaultAlgorithm());
+      final TrustManagerFactory trustManagerFactory =
+          
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
       trustManagerFactory.init(keystore);
 
       MockWebServerWrapper mockWebServerWrapper = new MockWebServerWrapper();
       MockWebServer mockWebServer = mockWebServerWrapper.getMockWebServer();
       SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
-      sslContext.init(keyManagerFactory.getKeyManagers(), 
/*trustManagerFactory.getTrustManagers()*/ null, null);
+      sslContext.init(
+          keyManagerFactory.getKeyManagers(), 
/*trustManagerFactory.getTrustManagers()*/
+          null,
+          null);
       SSLSocketFactory sf = sslContext.getSocketFactory();
       mockWebServer.useHttps(sf, false);
 
-      OAuth2Config config = new OAuth2Config(false, new OAuth2TokenProvider(), 
Collections.emptySet(), mockWebServerWrapper);
+      OAuth2Config config =
+          new OAuth2Config(
+              false, new OAuth2TokenProvider(), Collections.emptySet(), 
mockWebServerWrapper);
       return new MockOAuth2Server(config);
     } catch (Exception e) {
       throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Failed 
initializing SSL", e);
diff --git a/solr/core/src/test/org/apache/solr/security/JWTAuthPluginTest.java 
b/solr/core/src/test/org/apache/solr/security/JWTAuthPluginTest.java
index 3735d0a..2e1c241 100644
--- a/solr/core/src/test/org/apache/solr/security/JWTAuthPluginTest.java
+++ b/solr/core/src/test/org/apache/solr/security/JWTAuthPluginTest.java
@@ -16,22 +16,7 @@
  */
 package org.apache.solr.security;
 
-import org.apache.commons.io.IOUtils;
-import org.apache.solr.SolrTestCaseJ4;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.util.Utils;
-import org.apache.solr.util.CryptoKeys;
-import org.jose4j.jwk.RsaJsonWebKey;
-import org.jose4j.jwk.RsaJwkGenerator;
-import org.jose4j.jws.AlgorithmIdentifiers;
-import org.jose4j.jws.JsonWebSignature;
-import org.jose4j.jwt.JwtClaims;
-import org.jose4j.keys.BigEndianBigInteger;
-import org.jose4j.lang.JoseException;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
+import static 
org.apache.solr.security.JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.*;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -49,8 +34,22 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
-import static 
org.apache.solr.security.JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.*;
+import org.apache.commons.io.IOUtils;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.util.Utils;
+import org.apache.solr.util.CryptoKeys;
+import org.jose4j.jwk.RsaJsonWebKey;
+import org.jose4j.jwk.RsaJwkGenerator;
+import org.jose4j.jws.AlgorithmIdentifiers;
+import org.jose4j.jws.JsonWebSignature;
+import org.jose4j.jwt.JwtClaims;
+import org.jose4j.keys.BigEndianBigInteger;
+import org.jose4j.lang.JoseException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
 
 @SuppressWarnings("unchecked")
 public class JWTAuthPluginTest extends SolrTestCaseJ4 {
@@ -65,20 +64,25 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
   static HashMap<String, Object> testJwk;
 
   static {
-    // Generate an RSA key pair, which will be used for signing and 
verification of the JWT, wrapped in a JWK
+    // Generate an RSA key pair, which will be used for signing and 
verification of the JWT, wrapped
+    // in a JWK
     try {
       rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
       rsaJsonWebKey.setKeyId("k1");
 
       testJwk = new HashMap<>();
       testJwk.put("kty", rsaJsonWebKey.getKeyType());
-      testJwk.put("e", 
BigEndianBigInteger.toBase64Url(rsaJsonWebKey.getRsaPublicKey().getPublicExponent()));
+      testJwk.put(
+          "e",
+          
BigEndianBigInteger.toBase64Url(rsaJsonWebKey.getRsaPublicKey().getPublicExponent()));
       testJwk.put("use", rsaJsonWebKey.getUse());
       testJwk.put("kid", rsaJsonWebKey.getKeyId());
       testJwk.put("alg", rsaJsonWebKey.getAlgorithm());
-      testJwk.put("n", 
BigEndianBigInteger.toBase64Url(rsaJsonWebKey.getRsaPublicKey().getModulus()));
+      testJwk.put(
+          "n", 
BigEndianBigInteger.toBase64Url(rsaJsonWebKey.getRsaPublicKey().getModulus()));
 
-      trustedPemCert = 
Files.readString(TEST_PATH().resolve("security").resolve("jwt_plugin_idp_cert.pem"));
+      trustedPemCert =
+          
Files.readString(TEST_PATH().resolve("security").resolve("jwt_plugin_idp_cert.pem"));
     } catch (JoseException | IOException e) {
       fail("Failed static initialization: " + e.getMessage());
     }
@@ -107,21 +111,26 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
 
   protected static JwtClaims generateClaims() {
     JwtClaims claims = new JwtClaims();
-    claims.setIssuer("IDServer");  // who creates the token and signs it
+    claims.setIssuer("IDServer"); // who creates the token and signs it
     claims.setAudience("Solr"); // to whom the token is intended to be sent
-    claims.setExpirationTimeMinutesInTheFuture(10); // time when the token 
will expire (10 minutes from now)
+    claims.setExpirationTimeMinutesInTheFuture(
+        10); // time when the token will expire (10 minutes from now)
     claims.setGeneratedJwtId(); // a unique identifier for the token
-    claims.setIssuedAtToNow();  // when the token was issued/created (now)
-    claims.setNotBeforeMinutesInThePast(2); // time before which the token is 
not yet valid (2 minutes ago)
+    claims.setIssuedAtToNow(); // when the token was issued/created (now)
+    claims.setNotBeforeMinutesInThePast(
+        2); // time before which the token is not yet valid (2 minutes ago)
     claims.setSubject("solruser"); // the subject/principal is whom the token 
is about
     claims.setStringClaim("scope", "solr:read");
-    claims.setClaim("name", "Solr User"); // additional claims/attributes 
about the subject can be added
-    claims.setClaim("customPrincipal", "custom"); // additional 
claims/attributes about the subject can be added
+    claims.setClaim(
+        "name", "Solr User"); // additional claims/attributes about the 
subject can be added
+    claims.setClaim(
+        "customPrincipal", "custom"); // additional claims/attributes about 
the subject can be added
     claims.setClaim("claim1", "foo"); // additional claims/attributes about 
the subject can be added
     claims.setClaim("claim2", "bar"); // additional claims/attributes about 
the subject can be added
     claims.setClaim("claim3", "foo"); // additional claims/attributes about 
the subject can be added
     List<String> roles = Arrays.asList("group-one", "other-group", 
"group-three");
-    claims.setStringListClaim("roles", roles); // multi-valued claims work too 
and will end up as a JSON array
+    claims.setStringListClaim(
+        "roles", roles); // multi-valued claims work too and will end up as a 
JSON array
     return claims;
   }
 
@@ -162,7 +171,7 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
   public void initFromSecurityJSONLocalJWK() throws Exception {
     Path securityJson = 
TEST_PATH().resolve("security").resolve("jwt_plugin_jwk_security.json");
     InputStream is = Files.newInputStream(securityJson);
-    Map<String,Object> securityConf = (Map<String, Object>) Utils.fromJSON(is);
+    Map<String, Object> securityConf = (Map<String, Object>) 
Utils.fromJSON(is);
     Map<String, Object> authConf = (Map<String, Object>) 
securityConf.get("authentication");
     plugin.init(authConf);
   }
@@ -171,12 +180,14 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
   public void initFromSecurityJSONUrlJwk() throws Exception {
     Path securityJson = 
TEST_PATH().resolve("security").resolve("jwt_plugin_jwk_url_security.json");
     InputStream is = Files.newInputStream(securityJson);
-    Map<String,Object> securityConf = (Map<String, Object>) Utils.fromJSON(is);
+    Map<String, Object> securityConf = (Map<String, Object>) 
Utils.fromJSON(is);
     Map<String, Object> authConf = (Map<String, Object>) 
securityConf.get("authentication");
     plugin.init(authConf);
 
     JWTAuthPlugin.JWTAuthenticationResponse resp = 
plugin.authenticate(testHeader);
-    
assertEquals(JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
 resp.getAuthCode());
+    assertEquals(
+        
JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
+        resp.getAuthCode());
     assertTrue(resp.getJwtException().getMessage().contains("Connection 
refused"));
   }
 
@@ -201,7 +212,9 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
   @Test
   public void initWithJwksUrlArray() {
     HashMap<String, Object> authConf = new HashMap<>();
-    authConf.put("jwksUrl", Arrays.asList("https://127.0.0.1:9999/foo.jwk";, 
"https://127.0.0.1:9999/foo2.jwk";));
+    authConf.put(
+        "jwksUrl",
+        Arrays.asList("https://127.0.0.1:9999/foo.jwk";, 
"https://127.0.0.1:9999/foo2.jwk";));
     authConf.put("iss", "myIssuer");
     plugin = new JWTAuthPlugin();
     plugin.init(authConf);
@@ -213,18 +226,21 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
   public void authenticateOk() {
     JWTAuthPlugin.JWTAuthenticationResponse resp = 
plugin.authenticate(testHeader);
     assertTrue(resp.isAuthenticated());
-    assertEquals("custom", resp.getPrincipal().getName()); // principalClaim = 
customPrincipal, not sub here
+    assertEquals(
+        "custom", resp.getPrincipal().getName()); // principalClaim = 
customPrincipal, not sub here
   }
 
   @Test
   public void authFailedMissingSubject() {
-    minimalConfig.put("principalClaim","sub");  // minimalConfig has no 
subject specified
+    minimalConfig.put("principalClaim", "sub"); // minimalConfig has no 
subject specified
     plugin.init(minimalConfig);
     JWTAuthPlugin.JWTAuthenticationResponse resp = 
plugin.authenticate(testHeader);
     assertFalse(resp.isAuthenticated());
-    
assertEquals(JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
 resp.getAuthCode());
+    assertEquals(
+        
JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
+        resp.getAuthCode());
 
-    testConfig.put("principalClaim","sub");  // testConfig has subject = 
solruser
+    testConfig.put("principalClaim", "sub"); // testConfig has subject = 
solruser
     plugin.init(testConfig);
     resp = plugin.authenticate(testHeader);
     assertTrue(resp.isAuthenticated());
@@ -236,7 +252,9 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
     plugin.init(testConfig);
     JWTAuthPlugin.JWTAuthenticationResponse resp = 
plugin.authenticate(testHeader);
     assertFalse(resp.isAuthenticated());
-    
assertEquals(JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
 resp.getAuthCode());
+    assertEquals(
+        
JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
+        resp.getAuthCode());
 
     testConfig.put("iss", "IDServer");
     plugin.init(testConfig);
@@ -250,7 +268,9 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
     plugin.init(testConfig);
     JWTAuthPlugin.JWTAuthenticationResponse resp = 
plugin.authenticate(testHeader);
     assertFalse(resp.isAuthenticated());
-    
assertEquals(JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
 resp.getAuthCode());
+    assertEquals(
+        
JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
+        resp.getAuthCode());
 
     testConfig.put("aud", "Solr");
     plugin.init(testConfig);
@@ -269,7 +289,8 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
     plugin.init(testConfig);
     resp = plugin.authenticate(testHeader);
     assertFalse(resp.isAuthenticated());
-    
assertEquals(JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.PRINCIPAL_MISSING,
 resp.getAuthCode());
+    assertEquals(
+        JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.PRINCIPAL_MISSING, 
resp.getAuthCode());
   }
 
   @Test
@@ -289,13 +310,15 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
     shouldMatch.put("claim9", "NA");
     plugin.init(testConfig);
     resp = plugin.authenticate(testHeader);
-    
assertEquals(JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.CLAIM_MISMATCH, 
resp.getAuthCode());
+    assertEquals(
+        JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.CLAIM_MISMATCH, 
resp.getAuthCode());
 
     // Required claim does not match regex
     shouldMatch.clear();
     shouldMatch.put("claim1", "NA");
     resp = plugin.authenticate(testHeader);
-    
assertEquals(JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.CLAIM_MISMATCH, 
resp.getAuthCode());
+    assertEquals(
+        JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.CLAIM_MISMATCH, 
resp.getAuthCode());
   }
 
   @Test
@@ -310,14 +333,18 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
     testConfig.put("requireExp", true);
     plugin.init(testConfig);
     resp = plugin.authenticate(slimHeader);
-    
assertEquals(JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
 resp.getAuthCode());
+    assertEquals(
+        
JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
+        resp.getAuthCode());
     testConfig.put("requireExp", false);
 
     // Missing issuer claim
     testConfig.put("requireIss", true);
     plugin.init(testConfig);
     resp = plugin.authenticate(slimHeader);
-    
assertEquals(JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
 resp.getAuthCode());
+    assertEquals(
+        
JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
+        resp.getAuthCode());
   }
 
   @Test
@@ -325,7 +352,9 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
     testConfig.put("algAllowlist", Arrays.asList("PS384", "PS512"));
     plugin.init(testConfig);
     JWTAuthPlugin.JWTAuthenticationResponse resp = 
plugin.authenticate(testHeader);
-    
assertEquals(JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
 resp.getAuthCode());
+    assertEquals(
+        
JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.JWT_VALIDATION_EXCEPTION,
+        resp.getAuthCode());
     assertTrue(resp.getErrorMessage().contains("not a permitted algorithm"));
   }
 
@@ -339,7 +368,7 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
     // When 'rolesClaim' is not defined in config, then all scopes are 
registered as roles
     Principal principal = resp.getPrincipal();
     assertTrue(principal instanceof VerifiedUserRoles);
-    Set<String> roles = ((VerifiedUserRoles)principal).getVerifiedRoles();
+    Set<String> roles = ((VerifiedUserRoles) principal).getVerifiedRoles();
     assertEquals(1, roles.size());
     assertTrue(roles.contains("solr:read"));
   }
@@ -354,7 +383,7 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
     // When 'rolesClaim' is defined in config, then roles from that claim are 
used instead of claims
     Principal principal = resp.getPrincipal();
     assertTrue(principal instanceof VerifiedUserRoles);
-    Set<String> roles = ((VerifiedUserRoles)principal).getVerifiedRoles();
+    Set<String> roles = ((VerifiedUserRoles) principal).getVerifiedRoles();
     assertEquals(3, roles.size());
     assertTrue(roles.contains("group-one"));
     assertTrue(roles.contains("other-group"));
@@ -397,7 +426,13 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
 
   @Test
   public void wellKnownConfigNoHeaderPassThrough() {
-    String wellKnownUrl = 
TEST_PATH().resolve("security").resolve("jwt_well-known-config.json").toAbsolutePath().toUri().toString();
+    String wellKnownUrl =
+        TEST_PATH()
+            .resolve("security")
+            .resolve("jwt_well-known-config.json")
+            .toAbsolutePath()
+            .toUri()
+            .toString();
     testConfig.put("wellKnownUrl", wellKnownUrl);
     testConfig.remove("jwk");
     plugin.init(testConfig);
@@ -407,7 +442,13 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
 
   @Test
   public void defaultRealm() {
-    String wellKnownUrl = 
TEST_PATH().resolve("security").resolve("jwt_well-known-config.json").toAbsolutePath().toUri().toString();
+    String wellKnownUrl =
+        TEST_PATH()
+            .resolve("security")
+            .resolve("jwt_well-known-config.json")
+            .toAbsolutePath()
+            .toUri()
+            .toString();
     testConfig.put("wellKnownUrl", wellKnownUrl);
     testConfig.remove("jwk");
     plugin.init(testConfig);
@@ -416,7 +457,13 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
 
   @Test
   public void configureRealm() {
-    String wellKnownUrl = 
TEST_PATH().resolve("security").resolve("jwt_well-known-config.json").toAbsolutePath().toUri().toString();
+    String wellKnownUrl =
+        TEST_PATH()
+            .resolve("security")
+            .resolve("jwt_well-known-config.json")
+            .toAbsolutePath()
+            .toUri()
+            .toString();
     testConfig.put("wellKnownUrl", wellKnownUrl);
     testConfig.remove("jwk");
     testConfig.put("realm", "myRealm");
@@ -437,20 +484,29 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
     testConfig.put("clientId", "solr-cluster");
     plugin.init(testConfig);
     String headerBase64 = plugin.generateAuthDataHeader();
-    String headerJson = new String(Base64.getDecoder().decode(headerBase64), 
StandardCharsets.UTF_8);
-    Map<String,String> parsed = (Map<String, String>) 
Utils.fromJSONString(headerJson);
+    String headerJson =
+        new String(Base64.getDecoder().decode(headerBase64), 
StandardCharsets.UTF_8);
+    Map<String, String> parsed = (Map<String, String>) 
Utils.fromJSONString(headerJson);
     assertEquals("solr:admin", parsed.get("scope"));
-    assertEquals("http://acmepaymentscorp/oauth/auz/authorize";, 
parsed.get("authorizationEndpoint"));
+    assertEquals(
+        "http://acmepaymentscorp/oauth/auz/authorize";, 
parsed.get("authorizationEndpoint"));
     assertEquals("solr-cluster", parsed.get("client_id"));
   }
 
   @Test
   public void initWithTwoIssuers() {
     HashMap<String, Object> authConf = new HashMap<>();
-    JWTIssuerConfig iss1 = new 
JWTIssuerConfig("iss1").setIss("1").setAud("aud1")
-        .setJwksUrl("https://127.0.0.1:9999/foo.jwk";);
-    JWTIssuerConfig iss2 = new 
JWTIssuerConfig("iss2").setIss("2").setAud("aud2")
-        .setJwksUrl(Arrays.asList("https://127.0.0.1:9999/foo.jwk";, 
"https://127.0.0.1:9999/foo2.jwk";));
+    JWTIssuerConfig iss1 =
+        new JWTIssuerConfig("iss1")
+            .setIss("1")
+            .setAud("aud1")
+            .setJwksUrl("https://127.0.0.1:9999/foo.jwk";);
+    JWTIssuerConfig iss2 =
+        new JWTIssuerConfig("iss2")
+            .setIss("2")
+            .setAud("aud2")
+            .setJwksUrl(
+                Arrays.asList("https://127.0.0.1:9999/foo.jwk";, 
"https://127.0.0.1:9999/foo2.jwk";));
     authConf.put("issuers", Arrays.asList(iss1.asConfig(), iss2.asConfig()));
     plugin = new JWTAuthPlugin();
     plugin.init(authConf);
@@ -469,11 +525,16 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
   @Test
   public void initWithToplevelAndIssuersCombined() {
     HashMap<String, Object> authConf = new HashMap<>();
-    JWTIssuerConfig iss1 = new 
JWTIssuerConfig("iss1").setIss("1").setAud("aud1")
-        .setJwksUrl("https://127.0.0.1:9999/foo.jwk";);
+    JWTIssuerConfig iss1 =
+        new JWTIssuerConfig("iss1")
+            .setIss("1")
+            .setAud("aud1")
+            .setJwksUrl("https://127.0.0.1:9999/foo.jwk";);
     authConf.put("issuers", Collections.singletonList(iss1.asConfig()));
     authConf.put("aud", "aud2");
-    authConf.put("jwksUrl", Arrays.asList("https://127.0.0.1:9999/foo.jwk";, 
"https://127.0.0.1:9999/foo2.jwk";));
+    authConf.put(
+        "jwksUrl",
+        Arrays.asList("https://127.0.0.1:9999/foo.jwk";, 
"https://127.0.0.1:9999/foo2.jwk";));
 
     plugin = new JWTAuthPlugin();
     plugin.init(authConf);
@@ -497,7 +558,9 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
   public void initWithTrustedCertsFile() {
     HashMap<String, Object> authConf = new HashMap<>();
     authConf.put("jwksUrl", "https://127.0.0.1:9999/foo.jwk";);
-    authConf.put("trustedCertsFile", 
TEST_PATH().resolve("security").resolve("jwt_plugin_idp_cert.pem").toString());
+    authConf.put(
+        "trustedCertsFile",
+        
TEST_PATH().resolve("security").resolve("jwt_plugin_idp_cert.pem").toString());
     plugin = new JWTAuthPlugin();
     plugin.init(authConf);
     assertEquals(2, plugin.getIssuerConfigs().get(0).getTrustedCerts().size());
@@ -516,7 +579,9 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
   public void initWithInvalidTrustedCertsFile() {
     HashMap<String, Object> authConf = new HashMap<>();
     authConf.put("jwksUrl", "https://127.0.0.1:9999/foo.jwk";);
-    authConf.put("trustedCertsFile", 
TEST_PATH().resolve("security").resolve("jwt_plugin_idp_invalidcert.pem").toString());
+    authConf.put(
+        "trustedCertsFile",
+        
TEST_PATH().resolve("security").resolve("jwt_plugin_idp_invalidcert.pem").toString());
     plugin = new JWTAuthPlugin();
     expectThrows(SolrException.class, () -> plugin.init(authConf));
   }
@@ -528,9 +593,11 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
     authConf.put("trustedCerts", trustedPemCert);
     authConf.put("trustedCertsFile", "/path/to/cert.pem");
     plugin = new JWTAuthPlugin();
-    expectThrows(SolrException.class, () -> {
-      plugin.init(authConf);
-    });
+    expectThrows(
+        SolrException.class,
+        () -> {
+          plugin.init(authConf);
+        });
   }
 
   @Test
@@ -542,18 +609,23 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
 
   @Test
   public void parseInvalidPemToX509() {
-    expectThrows(SolrException.class, CertificateException.class, () -> {
-      CryptoKeys.parseX509Certs(IOUtils.toInputStream(
-          "-----BEGIN CERTIFICATE-----\n" +
-              "foo\n" +
-              "-----END CERTIFICATE-----\n", StandardCharsets.UTF_8));
-    });
+    expectThrows(
+        SolrException.class,
+        CertificateException.class,
+        () -> {
+          CryptoKeys.parseX509Certs(
+              IOUtils.toInputStream(
+                  "-----BEGIN CERTIFICATE-----\n" + "foo\n" + "-----END 
CERTIFICATE-----\n",
+                  StandardCharsets.UTF_8));
+        });
   }
 
   @Test
   public void extractCertificate() throws IOException {
-    Path pemFilePath = 
SolrTestCaseJ4.TEST_PATH().resolve("security").resolve("jwt_plugin_idp_cert.pem");
+    Path pemFilePath =
+        
SolrTestCaseJ4.TEST_PATH().resolve("security").resolve("jwt_plugin_idp_cert.pem");
     String cert = 
CryptoKeys.extractCertificateFromPem(Files.readString(pemFilePath));
-    assertEquals(2, CryptoKeys.parseX509Certs(IOUtils.toInputStream(cert, 
StandardCharsets.UTF_8)).size());
+    assertEquals(
+        2, CryptoKeys.parseX509Certs(IOUtils.toInputStream(cert, 
StandardCharsets.UTF_8)).size());
   }
 }
diff --git 
a/solr/core/src/test/org/apache/solr/security/JWTIssuerConfigTest.java 
b/solr/core/src/test/org/apache/solr/security/JWTIssuerConfigTest.java
index 9e9a4ca..f15f4e4 100644
--- a/solr/core/src/test/org/apache/solr/security/JWTIssuerConfigTest.java
+++ b/solr/core/src/test/org/apache/solr/security/JWTIssuerConfigTest.java
@@ -29,7 +29,6 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-
 import org.apache.commons.lang3.StringUtils;
 import org.apache.solr.SolrTestCase;
 import org.apache.solr.common.SolrException;
@@ -47,31 +46,33 @@ public class JWTIssuerConfigTest extends SolrTestCase {
   @Before
   public void setUp() throws Exception {
     super.setUp();
-    testIssuer = new JWTIssuerConfig("name")
-        .setJwksUrl("https://issuer/path";)
-        .setIss("issuer")
-        .setAud("audience")
-        .setClientId("clientid")
-        .setWellKnownUrl("wellknown")
-        .setAuthorizationEndpoint("https://issuer/authz";);
+    testIssuer =
+        new JWTIssuerConfig("name")
+            .setJwksUrl("https://issuer/path";)
+            .setIss("issuer")
+            .setAud("audience")
+            .setClientId("clientid")
+            .setWellKnownUrl("wellknown")
+            .setAuthorizationEndpoint("https://issuer/authz";);
 
     testIssuerConfigMap = testIssuer.asConfig();
 
-    testIssuerJson = "{\n" +
-        "  \"aud\":\"audience\",\n" +
-        "  \"wellKnownUrl\":\"wellknown\",\n" +
-        "  \"clientId\":\"clientid\",\n" +
-        "  \"jwksUrl\":[\"https://issuer/path\"],\n"; +
-        "  \"name\":\"name\",\n" +
-        "  \"iss\":\"issuer\",\n" +
-        "  \"authorizationEndpoint\":\"https://issuer/authz\"}";;
+    testIssuerJson =
+        "{\n"
+            + "  \"aud\":\"audience\",\n"
+            + "  \"wellKnownUrl\":\"wellknown\",\n"
+            + "  \"clientId\":\"clientid\",\n"
+            + "  \"jwksUrl\":[\"https://issuer/path\"],\n";
+            + "  \"name\":\"name\",\n"
+            + "  \"iss\":\"issuer\",\n"
+            + "  \"authorizationEndpoint\":\"https://issuer/authz\"}";;
   }
-  
+
   @After
   public void tearDown() throws Exception {
     super.tearDown();
     JWTIssuerConfig.ALLOW_OUTBOUND_HTTP = false;
-  }  
+  }
 
   @Test
   public void parseConfigMap() {
@@ -134,28 +135,31 @@ public class JWTIssuerConfigTest extends SolrTestCase {
 
   @Test
   public void jwksUrlwithHttpBehaviors() {
-    
+
     HashMap<String, Object> issuerConfigMap = new HashMap<>();
     issuerConfigMap.put("name", "myName");
     issuerConfigMap.put("iss", "myIss");
     issuerConfigMap.put("jwksUrl", "http://host/jwk";);
 
     JWTIssuerConfig issuerConfig = new JWTIssuerConfig(issuerConfigMap);
-    
+
     SolrException e = expectThrows(SolrException.class, () -> 
issuerConfig.getHttpsJwks());
     assertEquals(400, e.code());
-    assertEquals("jwksUrl is using http protocol. HTTPS required for IDP 
communication. Please use SSL or start your nodes with 
-Dsolr.auth.jwt.allowOutboundHttp=true to allow HTTP for test purposes.", 
e.getMessage());
-    
+    assertEquals(
+        "jwksUrl is using http protocol. HTTPS required for IDP communication. 
Please use SSL or start your nodes with -Dsolr.auth.jwt.allowOutboundHttp=true 
to allow HTTP for test purposes.",
+        e.getMessage());
+
     JWTIssuerConfig.ALLOW_OUTBOUND_HTTP = true;
 
     assertEquals(1, issuerConfig.getHttpsJwks().size());
-    assertEquals("http://host/jwk";, 
issuerConfig.getHttpsJwks().get(0).getLocation());    
+    assertEquals("http://host/jwk";, 
issuerConfig.getHttpsJwks().get(0).getLocation());
   }
-  
+
   @Test
   public void wellKnownConfigFromInputstream() throws IOException {
     Path configJson = 
TEST_PATH().resolve("security").resolve("jwt_well-known-config.json");
-    JWTIssuerConfig.WellKnownDiscoveryConfig config = 
JWTIssuerConfig.WellKnownDiscoveryConfig.parse(Files.newInputStream(configJson));
+    JWTIssuerConfig.WellKnownDiscoveryConfig config =
+        
JWTIssuerConfig.WellKnownDiscoveryConfig.parse(Files.newInputStream(configJson));
     assertEquals("https://acmepaymentscorp/oauth/jwks";, config.getJwksUrl());
   }
 
@@ -163,32 +167,67 @@ public class JWTIssuerConfigTest extends SolrTestCase {
   public void wellKnownConfigFromString() throws IOException {
     Path configJson = 
TEST_PATH().resolve("security").resolve("jwt_well-known-config.json");
     String configString = StringUtils.join(Files.readAllLines(configJson), 
"\n");
-    JWTIssuerConfig.WellKnownDiscoveryConfig config = 
JWTIssuerConfig.WellKnownDiscoveryConfig.parse(configString, 
StandardCharsets.UTF_8);
+    JWTIssuerConfig.WellKnownDiscoveryConfig config =
+        JWTIssuerConfig.WellKnownDiscoveryConfig.parse(configString, 
StandardCharsets.UTF_8);
     assertEquals("https://acmepaymentscorp/oauth/jwks";, config.getJwksUrl());
     assertEquals("http://acmepaymentscorp";, config.getIssuer());
     assertEquals("http://acmepaymentscorp/oauth/auz/authorize";, 
config.getAuthorizationEndpoint());
-    assertEquals(Arrays.asList("READ", "WRITE", "DELETE", "openid", "scope", 
"profile", "email", "address", "phone"), config.getScopesSupported());
-    assertEquals(Arrays.asList("code", "code id_token", "code token", "code 
id_token token", "token", "id_token", "id_token token"), 
config.getResponseTypesSupported());
+    assertEquals(
+        Arrays.asList(
+            "READ", "WRITE", "DELETE", "openid", "scope", "profile", "email", 
"address", "phone"),
+        config.getScopesSupported());
+    assertEquals(
+        Arrays.asList(
+            "code",
+            "code id_token",
+            "code token",
+            "code id_token token",
+            "token",
+            "id_token",
+            "id_token token"),
+        config.getResponseTypesSupported());
   }
 
   @Test
   public void wellKnownConfigWithHttpBehaviors() {
-    SolrException e = expectThrows(SolrException.class, () -> 
JWTIssuerConfig.WellKnownDiscoveryConfig.parse("http://127.0.0.1:45678/.well-known/config";));
+    SolrException e =
+        expectThrows(
+            SolrException.class,
+            () ->
+                JWTIssuerConfig.WellKnownDiscoveryConfig.parse(
+                    "http://127.0.0.1:45678/.well-known/config";));
     assertEquals(400, e.code());
-    assertEquals("wellKnownUrl is using http protocol. HTTPS required for IDP 
communication. Please use SSL or start your nodes with 
-Dsolr.auth.jwt.allowOutboundHttp=true to allow HTTP for test purposes.", 
e.getMessage());
-    
+    assertEquals(
+        "wellKnownUrl is using http protocol. HTTPS required for IDP 
communication. Please use SSL or start your nodes with 
-Dsolr.auth.jwt.allowOutboundHttp=true to allow HTTP for test purposes.",
+        e.getMessage());
+
     JWTIssuerConfig.ALLOW_OUTBOUND_HTTP = true;
-    
-    e = expectThrows(SolrException.class, () -> 
JWTIssuerConfig.WellKnownDiscoveryConfig.parse("http://127.0.0.1:45678/.well-known/config";));
+
+    e =
+        expectThrows(
+            SolrException.class,
+            () ->
+                JWTIssuerConfig.WellKnownDiscoveryConfig.parse(
+                    "http://127.0.0.1:45678/.well-known/config";));
     assertEquals(500, e.code());
-    // We open a connection in the code path to a server that doesn't exist, 
which causes this.  Should really be mocked.
-    assertEquals("Well-known config could not be read from url 
http://127.0.0.1:45678/.well-known/config";, e.getMessage());
+    // We open a connection in the code path to a server that doesn't exist, 
which causes this.
+    // Should really be mocked.
+    assertEquals(
+        "Well-known config could not be read from url 
http://127.0.0.1:45678/.well-known/config";,
+        e.getMessage());
   }
-  
+
   @Test
   public void wellKnownConfigNotReachable() {
-    SolrException e = expectThrows(SolrException.class, () -> 
JWTIssuerConfig.WellKnownDiscoveryConfig.parse("https://127.0.0.1:45678/.well-known/config";));
+    SolrException e =
+        expectThrows(
+            SolrException.class,
+            () ->
+                JWTIssuerConfig.WellKnownDiscoveryConfig.parse(
+                    "https://127.0.0.1:45678/.well-known/config";));
     assertEquals(500, e.code());
-    assertEquals("Well-known config could not be read from url 
https://127.0.0.1:45678/.well-known/config";, e.getMessage());
+    assertEquals(
+        "Well-known config could not be read from url 
https://127.0.0.1:45678/.well-known/config";,
+        e.getMessage());
   }
-}
\ No newline at end of file
+}
diff --git 
a/solr/core/src/test/org/apache/solr/security/JWTVerificationkeyResolverTest.java
 
b/solr/core/src/test/org/apache/solr/security/JWTVerificationkeyResolverTest.java
index 8ee5bcd..c24b9d8 100644
--- 
a/solr/core/src/test/org/apache/solr/security/JWTVerificationkeyResolverTest.java
+++ 
b/solr/core/src/test/org/apache/solr/security/JWTVerificationkeyResolverTest.java
@@ -17,10 +17,14 @@
 
 package org.apache.solr.security;
 
+import static java.util.Arrays.asList;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
-
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.security.JWTIssuerConfig.HttpsJwksFactory;
 import org.jose4j.jwk.HttpsJwks;
@@ -38,26 +42,15 @@ import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
-import static java.util.Arrays.asList;
-import static org.mockito.ArgumentMatchers.anyList;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.when;
-
-/**
- * Tests the multi jwks resolver that can fetch keys from multiple JWKs
- */
+/** Tests the multi jwks resolver that can fetch keys from multiple JWKs */
 public class JWTVerificationkeyResolverTest extends SolrTestCaseJ4 {
   private JWTVerificationkeyResolver resolver;
 
-  @Rule
-  public MockitoRule mockitoRule = MockitoJUnit.rule();
+  @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
 
-  @Mock
-  private HttpsJwks firstJwkList;
-  @Mock
-  private HttpsJwks secondJwkList;
-  @Mock
-  private HttpsJwksFactory httpsJwksFactory;
+  @Mock private HttpsJwks firstJwkList;
+  @Mock private HttpsJwks secondJwkList;
+  @Mock private HttpsJwksFactory httpsJwksFactory;
 
   private KeyHolder k1;
   private KeyHolder k2;
@@ -77,19 +70,25 @@ public class JWTVerificationkeyResolverTest extends 
SolrTestCaseJ4 {
     k5 = new KeyHolder("k5");
 
     when(firstJwkList.getJsonWebKeys()).thenReturn(asList(k1.getJwk(), 
k2.getJwk()));
-    doAnswer(invocation -> {
-      keysToReturnFromSecondJwk = refreshSequenceForSecondJwk.next();
-      System.out.println("Refresh called, next to return is " + 
keysToReturnFromSecondJwk);
-      return null;
-    }).when(secondJwkList).refresh();
-    when(secondJwkList.getJsonWebKeys()).then(inv -> {
-      if (keysToReturnFromSecondJwk == null)
-        keysToReturnFromSecondJwk = refreshSequenceForSecondJwk.next();
-      return keysToReturnFromSecondJwk;
-    });
+    doAnswer(
+            invocation -> {
+              keysToReturnFromSecondJwk = refreshSequenceForSecondJwk.next();
+              System.out.println("Refresh called, next to return is " + 
keysToReturnFromSecondJwk);
+              return null;
+            })
+        .when(secondJwkList)
+        .refresh();
+    when(secondJwkList.getJsonWebKeys())
+        .then(
+            inv -> {
+              if (keysToReturnFromSecondJwk == null)
+                keysToReturnFromSecondJwk = refreshSequenceForSecondJwk.next();
+              return keysToReturnFromSecondJwk;
+            });
     
when(httpsJwksFactory.createList(anyList())).thenReturn(asList(firstJwkList, 
secondJwkList));
 
-    JWTIssuerConfig issuerConfig = new 
JWTIssuerConfig("primary").setIss("foo").setJwksUrl(asList("url1", "url2"));
+    JWTIssuerConfig issuerConfig =
+        new JWTIssuerConfig("primary").setIss("foo").setJwksUrl(asList("url1", 
"url2"));
     JWTIssuerConfig.setHttpsJwksFactory(httpsJwksFactory);
     resolver = new JWTVerificationkeyResolver(Arrays.asList(issuerConfig), 
true);
 
@@ -98,9 +97,8 @@ public class JWTVerificationkeyResolverTest extends 
SolrTestCaseJ4 {
 
   @Test
   public void findKeyFromFirstList() throws JoseException {
-    refreshSequenceForSecondJwk = asList(
-        asList(k3.getJwk(), k4.getJwk()),
-        asList(k5.getJwk())).iterator();
+    refreshSequenceForSecondJwk =
+        asList(asList(k3.getJwk(), k4.getJwk()), 
asList(k5.getJwk())).iterator();
     resolver.resolveKey(k1.getJws(), null);
     resolver.resolveKey(k2.getJws(), null);
     resolver.resolveKey(k3.getJws(), null);
@@ -111,10 +109,8 @@ public class JWTVerificationkeyResolverTest extends 
SolrTestCaseJ4 {
 
   @Test(expected = UnresolvableKeyException.class)
   public void notFoundKey() throws JoseException {
-    refreshSequenceForSecondJwk = asList(
-        asList(k3.getJwk()),
-        asList(k4.getJwk()),
-        asList(k5.getJwk())).iterator();
+    refreshSequenceForSecondJwk =
+        asList(asList(k3.getJwk()), asList(k4.getJwk()), 
asList(k5.getJwk())).iterator();
     // Will not find key since first refresh returns k4, and we only try one 
refresh.
     resolver.resolveKey(k5.getJws(), null);
   }
@@ -153,4 +149,4 @@ public class JWTVerificationkeyResolverTest extends 
SolrTestCaseJ4 {
       return rsaJsonWebKey;
     }
   }
-}
\ No newline at end of file
+}

Reply via email to