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

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


The following commit(s) were added to refs/heads/branch_9x by this push:
     new f74b5e85e02 SOLR-16720: Defer PKI header creation to send-time (#1666)
f74b5e85e02 is described below

commit f74b5e85e0274ec9b6460f111bbc0af2d8e17228
Author: Alex <[email protected]>
AuthorDate: Fri May 26 08:29:44 2023 -0700

    SOLR-16720: Defer PKI header creation to send-time (#1666)
---
 .../solr/security/PKIAuthenticationPlugin.java     | 74 ++++++++++++++--------
 1 file changed, 48 insertions(+), 26 deletions(-)

diff --git 
a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java 
b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
index 6a005559f9b..cfd4436dac7 100644
--- a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
+++ b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
@@ -368,6 +368,8 @@ public class PKIAuthenticationPlugin extends 
AuthenticationPlugin
   public void setup(Http2SolrClient client) {
     final HttpListenerFactory.RequestResponseListener listener =
         new HttpListenerFactory.RequestResponseListener() {
+          private static final String CACHED_REQUEST_USER_KEY = 
"cachedRequestUser";
+
           @Override
           public void onQueued(Request request) {
             log.trace("onQueued: {}", request);
@@ -379,11 +381,12 @@ public class PKIAuthenticationPlugin extends 
AuthenticationPlugin
               if (log.isDebugEnabled()) {
                 log.debug("{} secures this internode request", 
this.getClass().getSimpleName());
               }
-              if ("v1".equals(System.getProperty(SEND_VERSION))) {
-                generateToken().ifPresent(s -> request.header(HEADER, s));
-              } else {
-                generateTokenV2().ifPresent(s -> request.header(HEADER_V2, s));
-              }
+
+              // The onBegin hook below (potentially) runs in a separate Jetty 
thread than was
+              // used to submit the request.  While we're still in the 
submitting thread, fetch
+              // the user information from the SolrRequestInfo thread local 
and cache it on the
+              // Request so it can be accessed accurately in onBegin
+              cachePreFetchedUserOnJettyRequest(request);
             } else {
               if (log.isDebugEnabled()) {
                 log.debug(
@@ -392,6 +395,31 @@ public class PKIAuthenticationPlugin extends 
AuthenticationPlugin
               }
             }
           }
+
+          @Override
+          public void onBegin(Request request) {
+            log.trace("onBegin: {}", request);
+
+            final Optional<String> preFetchedUser = 
getUserFromJettyRequest(request);
+            if ("v1".equals(System.getProperty(SEND_VERSION))) {
+              preFetchedUser
+                  .map(PKIAuthenticationPlugin.this::generateToken)
+                  .ifPresent(token -> request.header(HEADER, token));
+            } else {
+              preFetchedUser
+                  .map(PKIAuthenticationPlugin.this::generateTokenV2)
+                  .ifPresent(token -> request.header(HEADER_V2, token));
+            }
+          }
+
+          private void cachePreFetchedUserOnJettyRequest(Request request) {
+            getUser().ifPresent(user -> 
request.attribute(CACHED_REQUEST_USER_KEY, user));
+          }
+
+          private Optional<String> getUserFromJettyRequest(Request request) {
+            return Optional.ofNullable(
+                (String) request.getAttributes().get(CACHED_REQUEST_USER_KEY));
+          }
         };
     client.addListenerFactory(() -> listener);
   }
@@ -432,7 +460,7 @@ public class PKIAuthenticationPlugin extends 
AuthenticationPlugin
     }
   }
 
-  private String getUser() {
+  private Optional<String> getUser() {
     SolrRequestInfo reqInfo = getRequestInfo();
     if (reqInfo != null && !reqInfo.useServerToken()) {
       Principal principal = reqInfo.getUserPrincipal();
@@ -440,57 +468,51 @@ public class PKIAuthenticationPlugin extends 
AuthenticationPlugin
         log.debug("generateToken: principal is null");
         // this had a request but not authenticated
         // so we don't not need to set a principal
-        return null;
+        return Optional.empty();
       } else {
         assert principal.getName() != null;
-        return principal.getName();
+        return Optional.of(principal.getName());
       }
     } else {
       if (!isSolrThread()) {
         // if this is not running inside a Solr threadpool (as in testcases)
         // then no need to add any header
         log.debug("generateToken: not a solr (server) thread");
-        return null;
+        return Optional.empty();
       }
       // this request seems to be originated from Solr itself
-      return "$"; // special name to denote the user is the node itself
+      return Optional.of(NODE_IS_USER); // special name to denote the user is 
the node itself
     }
   }
 
   @SuppressForbidden(reason = "Needs currentTimeMillis to set current time in 
header")
-  private Optional<String> generateToken() {
-    String usr = getUser();
-    if (usr == null) {
-      return Optional.empty();
-    }
-
+  private String generateToken(String usr) {
+    assert usr != null;
     String s = usr + " " + System.currentTimeMillis();
     byte[] payload = s.getBytes(UTF_8);
     byte[] payloadCipher = 
publicKeyHandler.getKeyPair().encrypt(ByteBuffer.wrap(payload));
     String base64Cipher = Base64.getEncoder().encodeToString(payloadCipher);
     log.trace("generateToken: usr={} token={}", usr, base64Cipher);
-    return Optional.of(myNodeName + " " + base64Cipher);
+    return myNodeName + " " + base64Cipher;
   }
 
-  private Optional<String> generateTokenV2() {
-    String user = getUser();
-    if (user == null) {
-      return Optional.empty();
-    }
-
+  private String generateTokenV2(String user) {
+    assert user != null;
     String s = myNodeName + " " + user + " " + Instant.now().toEpochMilli();
 
     byte[] payload = s.getBytes(UTF_8);
     byte[] signature = publicKeyHandler.getKeyPair().signSha256(payload);
     String base64Signature = Base64.getEncoder().encodeToString(signature);
-    return Optional.of(s + " " + base64Signature);
+    return s + " " + base64Signature;
   }
 
   void setHeader(HttpRequest httpRequest) {
     if ("v1".equals(System.getProperty(SEND_VERSION))) {
-      generateToken().ifPresent(s -> httpRequest.setHeader(HEADER, s));
+      getUser().map(this::generateToken).ifPresent(token -> 
httpRequest.setHeader(HEADER, token));
     } else {
-      generateTokenV2().ifPresent(s -> httpRequest.setHeader(HEADER_V2, s));
+      getUser()
+          .map(this::generateTokenV2)
+          .ifPresent(token -> httpRequest.setHeader(HEADER_V2, token));
     }
   }
 

Reply via email to