This violates "ant precommit" because of forbidden API (default charset) problems.
: Date: Thu, 07 May 2015 13:33:23 -0000 : From: [email protected] : Reply-To: [email protected] : To: [email protected] : 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: [email protected] For additional commands, e-mail: [email protected]
