You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2015/11/26 18:59:05 UTC
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/
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) {