six demon bag

Wind, fire, all that kind of thing!

2017-08-07

Generate a Solr Password Hash

Recent versions of Solr allow restricting access via authentication and authorization plugins, for instance the basic authentication plugin. The documentation shows an example security.json that you can upload into Zookeeper (assuming that you're running SolrCloud).


{
    "authentication": {
        "blockUnknown": true,
        "class": "solr.BasicAuthPlugin",
        "credentials": {
            "solr": "IV0EHq1OnNrj6gvRCwvFwTrZ1+z1oBbnQdiVC3otuq0= Ndd7LKvVBAaZIF0QAVi1ekCfAJXr1GGfLtRUXhgrF8c="
        }
    },
    "authorization": {
        "class": "solr.RuleBasedAuthorizationPlugin",
        "permissions": [
            {
                "name": "security-edit",
                "role": "admin"
            }
        ],
        "user-role": {
            "solr": "admin"
        }
    }
}

However, it doesn't explain how exactly the password hash in that JSON document is generated. All it mentions is that it's an SHA256 hash of the password and a salt (the second base64-encoded value in the string above). Instead you're supposed to just upload the file and then change the value via the API.

bin/solr zk cp file:/path/to/security.json zk:/security.json -z localhost:9983
curl --user solr:SolrRocks http://localhost:8983/sorl/admin/authentication \
  -H 'Content-type:application/json' \
  -d '{"set-user":{"solr":"NewPassword"}}'

I don't know about anyone else, but personally I find uploading well-known credentials (for whatever brief period of time) somewhat less than desirable. However, my attempts to replicate the hash calculation by calling sha256sum on various password + salt combinations with or without base64-encoding all failed. The resulting hashes were always considerably longer than the value in the credential string above. So I dug through the Solr source code and identified sha256() in Sha256AuthenticationProvider.java as the function that actually calculates the hash.

I took the code and wrapped it in a standalone application that accepts a password string as its argument and outputs the base64-encoded values of the password hash and the (random) salt used in the calculation.

java -jar SolrPasswordHash.jar NewPassword

Replace the credential string in security.json with the output of the above command before uploading the file into Zookeeper.

Java code:

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
import org.apache.commons.codec.binary.Base64;

public class SolrPasswordHash {
  public static void main (String[] args) {
    if (args.length == 0) {
      System.err.println("Nothing to do.");
      System.exit(1);
    }

    String pw = args[0];
    MessageDigest digest;
    try {
      digest = MessageDigest.getInstance("SHA-256");

      final Random r = new SecureRandom();
      byte[] salt = new byte[32];
      r.nextBytes(salt);

      digest.reset();
      digest.update(salt);
      byte[] btPass = digest.digest(pw.getBytes(StandardCharsets.UTF_8));
      digest.reset();
      btPass = digest.digest(btPass);

      System.out.println(Base64.encodeBase64String(btPass) + " " +
        Base64.encodeBase64String(salt));
      System.exit(0);
    } catch (NoSuchAlgorithmException e) {
      System.err.println("Unknown algorithm: " + e.getMessage());
    }
    System.exit(2);
  }
}

For the base64 encoding the Apache Commons Codec library is required. The source archive contains an Ant build script that will automatically download the current version of that library and then build a jar file. You can also download the pre-compiled jar file if you don't want to build it yourself.

Download

Source code
Jar file

Posted 22:15 [permalink]