lucene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From no...@apache.org
Subject svn commit: r1716751 - in /lucene/dev/branches/lucene_solr_5_4/solr: ./ core/ core/src/java/org/apache/solr/security/ core/src/java/org/apache/solr/servlet/ core/src/java/org/apache/solr/util/ core/src/test/org/apache/solr/security/
Date Thu, 26 Nov 2015 17:59:05 GMT
Author: noble
Date: Thu Nov 26 17:59:05 2015
New Revision: 1716751

URL: http://svn.apache.org/viewvc?rev=1716751&view=rev
Log:
SOLR-8326: If BasicAuth enabled, inter node requests fail after node restart

Modified:
    lucene/dev/branches/lucene_solr_5_4/solr/   (props changed)
    lucene/dev/branches/lucene_solr_5_4/solr/CHANGES.txt   (contents, props changed)
    lucene/dev/branches/lucene_solr_5_4/solr/core/   (props changed)
    lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
    lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
    lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/util/CryptoKeys.java
    lucene/dev/branches/lucene_solr_5_4/solr/core/src/test/org/apache/solr/security/TestPKIAuthenticationPlugin.java

Modified: lucene/dev/branches/lucene_solr_5_4/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene_solr_5_4/solr/CHANGES.txt?rev=1716751&r1=1716750&r2=1716751&view=diff
==============================================================================
--- lucene/dev/branches/lucene_solr_5_4/solr/CHANGES.txt (original)
+++ lucene/dev/branches/lucene_solr_5_4/solr/CHANGES.txt Thu Nov 26 17:59:05 2015
@@ -275,6 +275,8 @@ Bug Fixes
 * SOLR-8341: Fix JSON Facet API excludeTags when specified in the
   form of domain:{excludeTags:mytag} (yonik)
 
+* SOLR-8326: If BasicAuth enabled, inter node requests fail after node restart (noble, Anshum
Gupta)
+
 
 Optimizations
 ----------------------

Modified: lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java?rev=1716751&r1=1716750&r2=1716751&view=diff
==============================================================================
--- lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
(original)
+++ lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
Thu Nov 26 17:59:05 2015
@@ -24,8 +24,6 @@ import javax.servlet.http.HttpServletReq
 import javax.servlet.http.HttpServletRequestWrapper;
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.security.InvalidKeyException;
 import java.security.Principal;
 import java.security.PublicKey;
 import java.util.List;
@@ -58,13 +56,15 @@ import org.apache.solr.util.CryptoKeys;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 
 public class PKIAuthenticationPlugin extends AuthenticationPlugin implements HttpClientInterceptorPlugin
{
-  static final Logger log = LoggerFactory.getLogger(PKIAuthenticationPlugin.class);
+  static private final Logger log = LoggerFactory.getLogger(PKIAuthenticationPlugin.class);
   private final Map<String, PublicKey> keyCache = new ConcurrentHashMap<>();
-  private CryptoKeys.RSAKeyPair keyPair = new CryptoKeys.RSAKeyPair();
+  private final CryptoKeys.RSAKeyPair keyPair = new CryptoKeys.RSAKeyPair();
   private final CoreContainer cores;
-  private int maxValidity = 5000;
+  private final int MAX_VALIDITY = 5000;
   private final String myNodeName;
 
   private boolean interceptorRegistered = false;
@@ -99,6 +99,7 @@ public class PKIAuthenticationPlugin ext
     long receivedTime = System.currentTimeMillis();
     String header = ((HttpServletRequest) request).getHeader(HEADER);
     if (header == null) {
+      //this must not happen
       log.error("No SolrAuth header present");
       filterChain.doFilter(request, response);
       return;
@@ -106,40 +107,29 @@ public class PKIAuthenticationPlugin ext
 
     List<String> authInfo = StrUtils.splitWS(header, false);
     if (authInfo.size() < 2) {
-      log.error("Invalid SolrAuth Header");
+      log.error("Invalid SolrAuth Header {}", header);
+      filterChain.doFilter(request, response);
       return;
     }
 
     String nodeName = authInfo.get(0);
     String cipher = authInfo.get(1);
 
-    byte[] decipher = decipherData(nodeName, cipher);
+    PKIHeaderData decipher = decipherHeader(nodeName, cipher);
     if (decipher == null) {
+      log.error("Could not decipher a header {} . No principal set", header);
+      filterChain.doFilter(request, response);
       return;
     }
-
-    String s = new String(decipher, StandardCharsets.UTF_8).trim();
-    List<String> pcs = StrUtils.splitWS(s, false);
-    if (pcs.size() < 2) {
-      return;
-    }
-
-    final String userName = pcs.get(0);
-    String timeStr = pcs.get(1);
-    try {
-      long timeMillis = Long.parseLong(timeStr);
-      if ((receivedTime - timeMillis) > maxValidity) {
+    if ((receivedTime - decipher.timestamp) > MAX_VALIDITY) {
         log.error("Invalid key ");
         filterChain.doFilter(request, response);
         return;
-      }
-    } catch (NumberFormatException e) {
-      log.error("Invalid time " + timeStr, e);
-      return;
     }
-    final Principal principal = "$".equals(userName) ?
+
+    final Principal principal = "$".equals(decipher.userName) ?
         SU :
-        new BasicUserPrincipal(userName);
+        new BasicUserPrincipal(decipher.userName);
 
     filterChain.doFilter(getWrapper((HttpServletRequest) request, principal), response);
   }
@@ -153,48 +143,69 @@ public class PKIAuthenticationPlugin ext
     };
   }
 
-  private byte[] decipherData(String nodeName, String cipherBase64) {
-    boolean freshKey = false;
+  public static class PKIHeaderData {
+    String userName;
+    long timestamp;
+  }
+
+  private PKIHeaderData decipherHeader(String nodeName, String cipherBase64) {
     PublicKey key = keyCache.get(nodeName);
     if (key == null) {
+      log.debug("No key available for node : {} fetching now ", nodeName);
       key = getRemotePublicKey(nodeName);
-      freshKey = true;
+      log.debug("public key obtained {} ", key);
     }
 
-    try {
-      return CryptoKeys.decryptRSA(Base64.base64ToByteArray(cipherBase64), key);
-    } catch (InvalidKeyException e) {
-      if (!freshKey) {
-        key = getRemotePublicKey(nodeName);
-        if (key == null) {
-          return null;
-        }
-        try {
-          return CryptoKeys.decryptRSA(Base64.base64ToByteArray(cipherBase64), key);
-        } catch (Exception e1) {
-          log.error("Error decrypting");
-          return null;
-        }
-      }
+    PKIHeaderData header = parseCipher(cipherBase64, key);
+    if (header == null) {
+      log.warn("Failed to decrypt header, trying after refreshing the key ");
+      key = getRemotePublicKey(nodeName);
+      return parseCipher(cipherBase64, key);
+    } else {
+      return header;
+    }
+  }
 
+  private static  PKIHeaderData parseCipher(String cipher, PublicKey key) {
+    byte[] bytes;
+    try {
+      bytes = CryptoKeys.decryptRSA(Base64.base64ToByteArray(cipher), key);
     } catch (Exception e) {
-      log.error("Error decrypting");
+      log.error("Decryption failed , key must be wrong", e);
+      return null;
+    }
+    String s = new String(bytes, UTF_8).trim();
+    String[] ss = s.split(" ");
+    if (ss.length < 2) {
+      log.warn("Invalid cipher {} deciphered data {}", cipher, s);
+      return null;
+    }
+    PKIHeaderData headerData = new PKIHeaderData();
+    try {
+      headerData.timestamp = Long.parseLong(ss[1]);
+      headerData.userName = ss[0];
+      log.debug("Successfully decrypted header {} {}", headerData.userName, headerData.timestamp);
+      return headerData;
+    } catch (NumberFormatException e) {
+      log.warn("Invalid cipher {}", cipher);
       return null;
     }
-
-    return null;
   }
 
   PublicKey getRemotePublicKey(String nodename) {
     String url = cores.getZkController().getZkStateReader().getBaseUrlForNodeName(nodename);
     try {
-      HttpResponse rsp = cores.getUpdateShardHandler().getHttpClient().execute(new HttpGet(url
+ PATH + "?wt=json&omitHeader=true"));
+      String uri = url + PATH + "?wt=json&omitHeader=true";
+      log.debug("Fetching fresh public key from : {}",uri);
+      HttpResponse rsp = cores.getUpdateShardHandler().getHttpClient().execute(new HttpGet(uri));
       byte[] bytes = EntityUtils.toByteArray(rsp.getEntity());
       Map m = (Map) Utils.fromJSON(bytes);
       String key = (String) m.get("key");
       if (key == null) {
         log.error("No key available from " + url + PATH);
         return null;
+      } else {
+        log.info("New Key obtained from  node: {} / {}", nodename, key);
       }
       PublicKey pubKey = CryptoKeys.deserializeX509PublicKey(key);
       keyCache.put(nodename, pubKey);
@@ -228,9 +239,7 @@ public class PKIAuthenticationPlugin ext
   }
 
   public boolean needsAuthorization(HttpServletRequest req) {
-    if (req.getUserPrincipal() == SU) return false;
-
-    return true;
+    return req.getUserPrincipal() != SU;
   }
 
   private class HttpHeaderClientConfigurer extends HttpClientConfigurer implements
@@ -247,13 +256,12 @@ public class PKIAuthenticationPlugin ext
       if (disabled()) return;
       setHeader(httpRequest);
     }
-
   }
 
   @SuppressForbidden(reason = "Needs currentTimeMillis to set current time in header")
   void setHeader(HttpRequest httpRequest) {
     SolrRequestInfo reqInfo = getRequestInfo();
-    String usr = null;
+    String usr;
     if (reqInfo != null) {
       Principal principal = reqInfo.getReq().getUserPrincipal();
       if (principal == null) {
@@ -275,7 +283,7 @@ public class PKIAuthenticationPlugin ext
 
     String s = usr + " " + System.currentTimeMillis();
 
-    byte[] payload = s.getBytes(StandardCharsets.UTF_8);
+    byte[] payload = s.getBytes(UTF_8);
     byte[] payloadCipher = keyPair.encrypt(ByteBuffer.wrap(payload));
     String base64Cipher = Base64.byteArrayToBase64(payloadCipher);
     httpRequest.setHeader(HEADER, myNodeName + " " + base64Cipher);

Modified: lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java?rev=1716751&r1=1716750&r2=1716751&view=diff
==============================================================================
--- lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
(original)
+++ lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
Thu Nov 26 17:59:05 2015
@@ -414,7 +414,7 @@ public class HttpSolrCall {
         */
       if (cores.getAuthorizationPlugin() != null && shouldAuthorize()) {
         AuthorizationContext context = getAuthCtx();
-        log.info(context.toString());
+        log.debug("AuthorizationContext : {}", context);
         AuthorizationResponse authResponse = cores.getAuthorizationPlugin().authorize(context);
         if (authResponse.statusCode == AuthorizationResponse.PROMPT.statusCode) {
           Map<String, String> headers = (Map) getReq().getAttribute(AuthenticationPlugin.class.getName());

Modified: lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/util/CryptoKeys.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/util/CryptoKeys.java?rev=1716751&r1=1716750&r2=1716751&view=diff
==============================================================================
--- lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/util/CryptoKeys.java
(original)
+++ lucene/dev/branches/lucene_solr_5_4/solr/core/src/java/org/apache/solr/util/CryptoKeys.java
Thu Nov 26 17:59:05 2015
@@ -307,6 +307,10 @@ public final class CryptoKeys {
       return pubKeyStr;
     }
 
+    public PublicKey getPublicKey() {
+      return publicKey;
+    }
+
     public byte[] encrypt(ByteBuffer buffer) {
       try {
         Cipher rsaCipher = Cipher.getInstance("RSA/ECB/nopadding");

Modified: lucene/dev/branches/lucene_solr_5_4/solr/core/src/test/org/apache/solr/security/TestPKIAuthenticationPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene_solr_5_4/solr/core/src/test/org/apache/solr/security/TestPKIAuthenticationPlugin.java?rev=1716751&r1=1716750&r2=1716751&view=diff
==============================================================================
--- lucene/dev/branches/lucene_solr_5_4/solr/core/src/test/org/apache/solr/security/TestPKIAuthenticationPlugin.java
(original)
+++ lucene/dev/branches/lucene_solr_5_4/solr/core/src/test/org/apache/solr/security/TestPKIAuthenticationPlugin.java
Thu Nov 26 17:59:05 2015
@@ -88,7 +88,9 @@ public class TestPKIAuthenticationPlugin
         return principal.get();
       }
     };
-    mock.remoteKeys.put(nodeName, CryptoKeys.deserializeX509PublicKey(mock.getPublicKey()));
+    final PublicKey  correctKey = CryptoKeys.deserializeX509PublicKey(mock.getPublicKey());
+    mock.remoteKeys.put(nodeName, correctKey);
+
     principal.set(new BasicUserPrincipal("solr"));
     mock.solrRequestInfo = new SolrRequestInfo(localSolrQueryRequest, new SolrQueryResponse());
     BasicHttpRequest request = new BasicHttpRequest("GET", "http://localhost:56565");
@@ -136,6 +138,27 @@ public class TestPKIAuthenticationPlugin
     assertNotNull(wrappedRequestByFilter.get());
     assertEquals("$", ((HttpServletRequest) wrappedRequestByFilter.get()).getUserPrincipal().getName());
 
+
+
+    MockPKIAuthenticationPlugin mock1 = new MockPKIAuthenticationPlugin(null, nodeName) {
+      int called = 0;
+      @Override
+      PublicKey getRemotePublicKey(String nodename) {
+        try {
+          return called == 0 ? new CryptoKeys.RSAKeyPair().getPublicKey() : correctKey;
+        } finally {
+          called++;
+        }
+      }
+    };
+
+    mock1.doAuthenticate(mockReq, null,filterChain );
+    assertNotNull(wrappedRequestByFilter.get());
+    assertEquals("$", ((HttpServletRequest) wrappedRequestByFilter.get()).getUserPrincipal().getName());
+
+
+
+
   }
 
   private HttpServletRequest createMockRequest(final AtomicReference<Header> header)
{



Mime
View raw message