You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@lucene.apache.org by Chris Hostetter <ho...@fucit.org> on 2015/05/07 18:47:57 UTC

Re: svn commit: r1678195 - in /lucene/dev/trunk/solr: ./ contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/ contrib/dataimporthandler/src/test/org/apache/solr/handler/dataimport/ core/src/java/org/apache/solr/util/

This violates "ant precommit" because of forbidden API (default charset) 
problems.



: Date: Thu, 07 May 2015 13:33:23 -0000
: From: noble@apache.org
: Reply-To: dev@lucene.apache.org
: To: commits@lucene.apache.org
: Subject: svn commit: r1678195 - in /lucene/dev/trunk/solr: ./
:     contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/
:     contrib/dataimporthandler/src/test/org/apache/solr/handler/dataimport/
:     core/src/java/org/apache/solr/util/
: 
: Author: noble
: Date: Thu May  7 13:33:23 2015
: New Revision: 1678195
: 
: URL: http://svn.apache.org/r1678195
: Log:
: SOLR-4392: Make it possible to specify AES encrypted password in dataconfig.xml
: 
: Modified:
:     lucene/dev/trunk/solr/CHANGES.txt
:     lucene/dev/trunk/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/JdbcDataSource.java
:     lucene/dev/trunk/solr/contrib/dataimporthandler/src/test/org/apache/solr/handler/dataimport/TestJdbcDataSource.java
:     lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CryptoKeys.java
: 
: Modified: lucene/dev/trunk/solr/CHANGES.txt
: URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1678195&r1=1678194&r2=1678195&view=diff
: ==============================================================================
: --- lucene/dev/trunk/solr/CHANGES.txt (original)
: +++ lucene/dev/trunk/solr/CHANGES.txt Thu May  7 13:33:23 2015
: @@ -169,6 +169,8 @@ New Features
:  
:  * SOLR-6220: Rule Based Replica Assignment during collection creation (Noble Paul)
:  
: +* SOLR-4392: Make it possible to specify AES encrypted password in dataconfig.xml (Noble Paul)
: +
:  
:  Bug Fixes
:  ----------------------
: 
: Modified: lucene/dev/trunk/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/JdbcDataSource.java
: URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/JdbcDataSource.java?rev=1678195&r1=1678194&r2=1678195&view=diff
: ==============================================================================
: --- lucene/dev/trunk/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/JdbcDataSource.java (original)
: +++ lucene/dev/trunk/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/JdbcDataSource.java Thu May  7 13:33:23 2015
: @@ -19,12 +19,16 @@ package org.apache.solr.handler.dataimpo
:  import static org.apache.solr.handler.dataimport.DataImportHandlerException.wrapAndThrow;
:  import static org.apache.solr.handler.dataimport.DataImportHandlerException.SEVERE;
:  
: +import org.apache.solr.common.SolrException;
: +import org.apache.solr.util.CryptoKeys;
:  import org.slf4j.Logger;
:  import org.slf4j.LoggerFactory;
:  
:  import javax.naming.InitialContext;
:  import javax.naming.NamingException;
:  
: +import java.io.FileReader;
: +import java.io.IOException;
:  import java.math.BigDecimal;
:  import java.math.BigInteger;
:  import java.sql.*;
: @@ -61,6 +65,7 @@ public class JdbcDataSource extends
:  
:    @Override
:    public void init(Context context, Properties initProps) {
: +    initProps = decryptPwd(initProps);
:      Object o = initProps.get(CONVERT_TYPE);
:      if (o != null)
:        convertType = Boolean.parseBoolean(o.toString());
: @@ -101,6 +106,34 @@ public class JdbcDataSource extends
:      }
:    }
:  
: +  private Properties decryptPwd(Properties initProps) {
: +    String encryptionKey = initProps.getProperty("encryptKeyFile");
: +    if (initProps.getProperty("password") != null && encryptionKey != null) {
: +      // this means the password is encrypted and use the file to decode it
: +      try {
: +        try (FileReader fr = new FileReader(encryptionKey)) {
: +          char[] chars = new char[100];//max 100 char password
: +          int len = fr.read(chars);
: +          if (len < 6)
: +            throw new DataImportHandlerException(SEVERE, "There should be a password of length 6 atleast " + encryptionKey);
: +          Properties props = new Properties();
: +          props.putAll(initProps);
: +          String password = null;
: +          try {
: +            password = CryptoKeys.decodeAES(initProps.getProperty("password"), new String(chars, 0, len)).trim();
: +          } catch (SolrException se) {
: +            throw new DataImportHandlerException(SEVERE, "Error decoding password", se.getCause());
: +          }
: +          props.put("password", password);
: +          initProps = props;
: +        }
: +      } catch (IOException e) {
: +        throw new DataImportHandlerException(SEVERE, "Could not load encryptKeyFile  " + encryptionKey);
: +      }
: +    }
: +    return initProps;
: +  }
: +
:    protected Callable<Connection> createConnectionFactory(final Context context,
:                                         final Properties initProps) {
:  //    final VariableResolver resolver = context.getVariableResolver();
: @@ -395,7 +428,7 @@ public class JdbcDataSource extends
:      }
:    }
:  
: -  private Connection getConnection() throws Exception {
: +  Connection getConnection() throws Exception {
:      long currTime = System.nanoTime();
:      if (currTime - connLastUsed > CONN_TIME_OUT) {
:        synchronized (this) {
: 
: Modified: lucene/dev/trunk/solr/contrib/dataimporthandler/src/test/org/apache/solr/handler/dataimport/TestJdbcDataSource.java
: URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/contrib/dataimporthandler/src/test/org/apache/solr/handler/dataimport/TestJdbcDataSource.java?rev=1678195&r1=1678194&r2=1678195&view=diff
: ==============================================================================
: --- lucene/dev/trunk/solr/contrib/dataimporthandler/src/test/org/apache/solr/handler/dataimport/TestJdbcDataSource.java (original)
: +++ lucene/dev/trunk/solr/contrib/dataimporthandler/src/test/org/apache/solr/handler/dataimport/TestJdbcDataSource.java Thu May  7 13:33:23 2015
: @@ -16,6 +16,9 @@
:   */
:  package org.apache.solr.handler.dataimport;
:  
: +import java.io.File;
: +import java.nio.charset.StandardCharsets;
: +import java.nio.file.Files;
:  import java.sql.Connection;
:  import java.sql.Driver;
:  import java.sql.DriverManager;
: @@ -123,6 +126,36 @@ public class TestJdbcDataSource extends
:  
:      mockControl.verify();
:  
: +    assertSame("connection", conn, connection);
: +  }
: +
: +  @Test
: +  public void testRetrieveFromJndiWithCredentialsWithEncryptedPwd() throws Exception {
: +    MockInitialContextFactory.bind("java:comp/env/jdbc/JndiDB", dataSource);
: +    File tmpdir = File.createTempFile("test", "tmp", createTempDir().toFile());
: +    Files.delete(tmpdir.toPath());
: +    tmpdir.mkdir();
: +    byte[] content = "secret".getBytes(StandardCharsets.UTF_8);
: +    createFile(tmpdir, "enckeyfile.txt", content, false);
: +
: +    props.put(JdbcDataSource.JNDI_NAME, "java:comp/env/jdbc/JndiDB");
: +    props.put("user", "Fred");
: +    props.put("encryptKeyFile", new File(tmpdir, "enckeyfile.txt").getAbsolutePath());
: +    props.put("password", "U2FsdGVkX18QMjY0yfCqlfBMvAB4d3XkwY96L7gfO2o=");
: +    props.put("holdability", "HOLD_CURSORS_OVER_COMMIT");
: +    EasyMock.expect(dataSource.getConnection("Fred", "MyPassword")).andReturn(
: +        connection);
: +    jdbcDataSource.init(context, props);
: +
: +    connection.setAutoCommit(false);
: +    connection.setHoldability(1);
: +
: +    mockControl.replay();
: +
: +    Connection conn = jdbcDataSource.getConnection();
: +
: +    mockControl.verify();
: +
:      assertSame("connection", conn, connection);
:    }
:  
: 
: Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CryptoKeys.java
: URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CryptoKeys.java?rev=1678195&r1=1678194&r2=1678195&view=diff
: ==============================================================================
: --- lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CryptoKeys.java (original)
: +++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CryptoKeys.java Thu May  7 13:33:23 2015
: @@ -17,17 +17,27 @@ package org.apache.solr.util;
:   * limitations under the License.
:   */
:  
: +import javax.crypto.BadPaddingException;
: +import javax.crypto.Cipher;
: +import javax.crypto.IllegalBlockSizeException;
: +import javax.crypto.spec.IvParameterSpec;
: +import javax.crypto.spec.SecretKeySpec;
:  import java.nio.ByteBuffer;
: +import java.nio.charset.Charset;
: +import java.security.GeneralSecurityException;
:  import java.security.InvalidKeyException;
:  import java.security.KeyFactory;
: +import java.security.MessageDigest;
:  import java.security.NoSuchAlgorithmException;
:  import java.security.PublicKey;
:  import java.security.Signature;
:  import java.security.SignatureException;
:  import java.security.spec.X509EncodedKeySpec;
: +import java.util.Arrays;
:  import java.util.HashMap;
:  import java.util.Map;
:  
: +import org.apache.solr.common.SolrException;
:  import org.apache.solr.common.util.Base64;
:  import org.slf4j.Logger;
:  import org.slf4j.LoggerFactory;
: @@ -107,5 +117,139 @@ public final class CryptoKeys {
:      return false;
:    }
:  
: +  private static byte[][] evpBytesTokey(int key_len, int iv_len, MessageDigest md,
: +                                        byte[] salt, byte[] data, int count) {
: +    byte[][] both = new byte[2][];
: +    byte[] key = new byte[key_len];
: +    int key_ix = 0;
: +    byte[] iv = new byte[iv_len];
: +    int iv_ix = 0;
: +    both[0] = key;
: +    both[1] = iv;
: +    byte[] md_buf = null;
: +    int nkey = key_len;
: +    int niv = iv_len;
: +    int i = 0;
: +    if (data == null) {
: +      return both;
: +    }
: +    int addmd = 0;
: +    for (; ; ) {
: +      md.reset();
: +      if (addmd++ > 0) {
: +        md.update(md_buf);
: +      }
: +      md.update(data);
: +      if (null != salt) {
: +        md.update(salt, 0, 8);
: +      }
: +      md_buf = md.digest();
: +      for (i = 1; i < count; i++) {
: +        md.reset();
: +        md.update(md_buf);
: +        md_buf = md.digest();
: +      }
: +      i = 0;
: +      if (nkey > 0) {
: +        for (; ; ) {
: +          if (nkey == 0)
: +            break;
: +          if (i == md_buf.length)
: +            break;
: +          key[key_ix++] = md_buf[i];
: +          nkey--;
: +          i++;
: +        }
: +      }
: +      if (niv > 0 && i != md_buf.length) {
: +        for (; ; ) {
: +          if (niv == 0)
: +            break;
: +          if (i == md_buf.length)
: +            break;
: +          iv[iv_ix++] = md_buf[i];
: +          niv--;
: +          i++;
: +        }
: +      }
: +      if (nkey == 0 && niv == 0) {
: +        break;
: +      }
: +    }
: +    for (i = 0; i < md_buf.length; i++) {
: +      md_buf[i] = 0;
: +    }
: +    return both;
: +  }
: +
: +  public static String decodeAES(String base64CipherTxt, String pwd) {
: +    int[] strengths = new int[]{256, 192, 128};
: +    Exception e = null;
: +    for (int strength : strengths) {
: +      try {
: +        return decodeAES(base64CipherTxt, pwd, strength);
: +      } catch (Exception exp) {
: +        e = exp;
: +      }
: +    }
: +    throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Error decoding ", e);
: +  }
: +
: +
: +  public static String decodeAES(String base64CipherTxt, String pwd, final int keySizeBits) {
: +    final Charset ASCII = Charset.forName("ASCII");
: +    final int INDEX_KEY = 0;
: +    final int INDEX_IV = 1;
: +    final int ITERATIONS = 1;
: +    final int SALT_OFFSET = 8;
: +    final int SALT_SIZE = 8;
: +    final int CIPHERTEXT_OFFSET = SALT_OFFSET + SALT_SIZE;
: +
: +    try {
: +      byte[] headerSaltAndCipherText = Base64.base64ToByteArray(base64CipherTxt);
: +
: +      // --- extract salt & encrypted ---
: +      // header is "Salted__", ASCII encoded, if salt is being used (the default)
: +      byte[] salt = Arrays.copyOfRange(
: +          headerSaltAndCipherText, SALT_OFFSET, SALT_OFFSET + SALT_SIZE);
: +      byte[] encrypted = Arrays.copyOfRange(
: +          headerSaltAndCipherText, CIPHERTEXT_OFFSET, headerSaltAndCipherText.length);
: +
: +      // --- specify cipher and digest for evpBytesTokey method ---
: +
: +      Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
: +      MessageDigest md5 = MessageDigest.getInstance("MD5");
: +
: +      // --- create key and IV  ---
: +
: +      // the IV is useless, OpenSSL might as well have use zero's
: +      final byte[][] keyAndIV = evpBytesTokey(
: +          keySizeBits / Byte.SIZE,
: +          aesCBC.getBlockSize(),
: +          md5,
: +          salt,
: +          pwd.getBytes(ASCII),
: +          ITERATIONS);
: +
: +      SecretKeySpec key = new SecretKeySpec(keyAndIV[INDEX_KEY], "AES");
: +      IvParameterSpec iv = new IvParameterSpec(keyAndIV[INDEX_IV]);
: +
: +      // --- initialize cipher instance and decrypt ---
: +
: +      aesCBC.init(Cipher.DECRYPT_MODE, key, iv);
: +      byte[] decrypted = aesCBC.doFinal(encrypted);
: +      return new String(decrypted, ASCII);
: +    } catch (BadPaddingException e) {
: +      // AKA "something went wrong"
: +      throw new IllegalStateException(
: +          "Bad password, algorithm, mode or padding;" +
: +              " no salt, wrong number of iterations or corrupted ciphertext.", e);
: +    } catch (IllegalBlockSizeException e) {
: +      throw new IllegalStateException(
: +          "Bad algorithm, mode or corrupted (resized) ciphertext.", e);
: +    } catch (GeneralSecurityException e) {
: +      throw new IllegalStateException(e);
: +    }
: +  }
:  
:  }
: 
: 
: 

-Hoss
http://www.lucidworks.com/

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org