You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2014/03/30 15:19:10 UTC
svn commit: r1583130 - in /cayenne/main/trunk/cayenne-crypto/src:
main/java/org/apache/cayenne/crypto/ main/java/org/apache/cayenne/crypto/key/
test/java/org/apache/cayenne/crypto/key/ test/resources/org/
test/resources/org/apache/ test/resources/org/a...
Author: aadamchik
Date: Sun Mar 30 13:19:09 2014
New Revision: 1583130
URL: http://svn.apache.org/r1583130
Log:
CAY-1916 cayenne-crypto module that enables data encryption for certain model attributes
keystore infrastructure
Added:
cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/key/
cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/key/KeyStoreKeySourceTest.java
cayenne/main/trunk/cayenne-crypto/src/test/resources/org/
cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/
cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/cayenne/
cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/cayenne/crypto/
cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/cayenne/crypto/key/
cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/cayenne/crypto/key/README-keystore.txt
cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/cayenne/crypto/key/ks1.jceks
Modified:
cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoConstants.java
cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java
cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/key/KeyStoreKeySource.java
Modified: cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoConstants.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoConstants.java?rev=1583130&r1=1583129&r2=1583130&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoConstants.java (original)
+++ cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoConstants.java Sun Mar 30 13:19:09 2014
@@ -24,10 +24,15 @@ package org.apache.cayenne.crypto;
public interface CryptoConstants {
/**
- * An injection key for the map of the crypto properties.
+ * An injection key for the Map<String, String> of the crypto properties.
*/
public static final String PROPERTIES_MAP = "cayenne.crypto.properties";
+ /**
+ * An injection key for the map Map<String, char[]> of credentials.
+ */
+ public static final String CREDENTIALS_MAP = "cayenne.crypto.properties";
+
public static final String CIPHER_ALGORITHM = "cayenne.crypto.cipher.algorithm";
public static final String CIPHER_MODE = "cayenne.crypto.cipher.mode";
@@ -36,11 +41,8 @@ public interface CryptoConstants {
public static final String KEYSTORE_URL = "cayenne.crypto.keystore.url";
- public static final String KEYSTORE_PASSWORD = "cayenne.crypto.keystore.password";
-
/**
- * A password to access a secret key within the keystore. (As opposed to
- * keystore password specified with KEYSTORE_PASSWORD property).
+ * A password to access a secret key within the keystore.
*/
public static final String KEY_PASSWORD = "cayenne.crypto.key.password";
Modified: cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java?rev=1583130&r1=1583129&r2=1583130&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java (original)
+++ cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java Sun Mar 30 13:19:09 2014
@@ -34,6 +34,7 @@ import org.apache.cayenne.crypto.transfo
import org.apache.cayenne.crypto.transformer.TransformerFactory;
import org.apache.cayenne.crypto.transformer.value.ValueTransformerFactory;
import org.apache.cayenne.di.Binder;
+import org.apache.cayenne.di.MapBuilder;
import org.apache.cayenne.di.Module;
/**
@@ -62,6 +63,9 @@ public class CryptoModuleBuilder {
private String keyStoreUrl;
private File keyStoreFile;
+ private Class<? extends KeySource> keySourceType;
+
+ private char[] keyPassword;
public CryptoModuleBuilder() {
@@ -72,6 +76,7 @@ public class CryptoModuleBuilder {
this.cipherPadding = DEFAULT_CIPHER_PADDING;
this.cipherFactoryType = DefaultCipherFactory.class;
+ this.keySourceType = KeyStoreKeySource.class;
}
public CryptoModuleBuilder cipherAlgorithm(String algorithm) {
@@ -106,6 +111,14 @@ public class CryptoModuleBuilder {
return this;
}
+ /**
+ * Sets a password used that unlocks a secret key.
+ */
+ public CryptoModuleBuilder keyPassword(char[] password) {
+ this.keyPassword = password;
+ return this;
+ }
+
public CryptoModuleBuilder keyStore(File file) {
this.keyStoreUrl = null;
this.keyStoreFile = file;
@@ -120,6 +133,11 @@ public class CryptoModuleBuilder {
return this;
}
+ public CryptoModuleBuilder keySource(Class<? extends KeySource> type) {
+ this.keySourceType = type;
+ return this;
+ }
+
/**
* Produces a module that can be used to start Cayenne runtime.
*/
@@ -137,37 +155,44 @@ public class CryptoModuleBuilder {
throw new IllegalStateException("'CipherFactory' is not initialized");
}
- if (keyStoreUrl == null && keyStoreFile == null) {
- throw new IllegalStateException("'keyStore' is not initialized");
- }
-
- final String keyStoreUrl;
- if (this.keyStoreUrl != null) {
- keyStoreUrl = this.keyStoreUrl;
- } else {
- try {
- keyStoreUrl = keyStoreFile.toURI().toURL().toExternalForm();
- } catch (MalformedURLException e) {
- throw new IllegalStateException("Invalid keyStore file", e);
- }
- }
-
return new Module() {
@Override
public void configure(Binder binder) {
- // init default cipher settings
- binder.<String> bindMap(CryptoConstants.PROPERTIES_MAP)
+ String keyStoreUrl = null;
+ if (CryptoModuleBuilder.this.keyStoreUrl != null) {
+ keyStoreUrl = CryptoModuleBuilder.this.keyStoreUrl;
+ } else if (keyStoreFile != null) {
+ try {
+ keyStoreUrl = keyStoreFile.toURI().toURL().toExternalForm();
+ } catch (MalformedURLException e) {
+ throw new IllegalStateException("Invalid keyStore file", e);
+ }
+ }
+
+ // String properties
+ MapBuilder<String> props = binder.<String> bindMap(CryptoConstants.PROPERTIES_MAP)
.put(CryptoConstants.CIPHER_ALGORITHM, cipherAlgoritm)
.put(CryptoConstants.CIPHER_MODE, cipherMode)
- .put(CryptoConstants.CIPHER_PADDING, cipherPadding)
- .put(CryptoConstants.KEYSTORE_URL, keyStoreUrl);
+ .put(CryptoConstants.CIPHER_PADDING, cipherPadding);
+
+ if (keyStoreUrl != null) {
+ props.put(CryptoConstants.KEYSTORE_URL, keyStoreUrl);
+ }
+
+ // char[] credentials... stored as char[] to potentially allow
+ // wiping them clean in memory...
+ MapBuilder<char[]> creds = binder.<char[]> bindMap(CryptoConstants.CREDENTIALS_MAP);
+
+ if (keyPassword != null) {
+ creds.put(CryptoConstants.KEY_PASSWORD, keyPassword);
+ }
binder.bind(CipherFactory.class).to(cipherFactoryType);
binder.bind(TransformerFactory.class).to(DefaultTransformerFactory.class);
binder.bind(ValueTransformerFactory.class).to(valueTransformerFactoryType);
- binder.bind(KeySource.class).to(KeyStoreKeySource.class);
+ binder.bind(KeySource.class).to(keySourceType);
if (columnMapperType != null) {
binder.bind(ColumnMapper.class).to(columnMapperType);
Modified: cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/key/KeyStoreKeySource.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/key/KeyStoreKeySource.java?rev=1583130&r1=1583129&r2=1583130&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/key/KeyStoreKeySource.java (original)
+++ cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/key/KeyStoreKeySource.java Sun Mar 30 13:19:09 2014
@@ -40,42 +40,40 @@ import org.apache.cayenne.di.Inject;
*/
public class KeyStoreKeySource implements KeySource {
+ // this is the only standard keystore type that supports storing secret keys
+ private static final String JCEKS_KEYSTORE_TYPE = "jceks";
+
private KeyStore keyStore;
- private char[] keyPasswordChars;
+ private char[] keyPassword;
- public KeyStoreKeySource(@Inject(CryptoConstants.PROPERTIES_MAP) Map<String, String> properties)
- throws KeyStoreException {
+ public KeyStoreKeySource(@Inject(CryptoConstants.PROPERTIES_MAP) Map<String, String> properties,
+ @Inject(CryptoConstants.CREDENTIALS_MAP) Map<String, char[]> credentials) {
String keyStoreUrl = properties.get(CryptoConstants.KEYSTORE_URL);
if (keyStoreUrl == null) {
throw new CayenneCryptoException("KeyStore URL is not set. Property name: " + CryptoConstants.KEYSTORE_URL);
}
- String keyStorePassword = properties.get(CryptoConstants.KEYSTORE_PASSWORD);
- // NULL password is valid, though not secure .. so no NULL validation
-
- String keyPassword = properties.get(CryptoConstants.KEY_PASSWORD);
- this.keyPasswordChars = keyPassword != null ? keyPassword.toCharArray() : null;
+ this.keyPassword = credentials.get(CryptoConstants.KEY_PASSWORD);
// NULL password is valid, though not secure .. so no NULL validation
try {
- this.keyStore = createKeyStore(keyStoreUrl, keyStorePassword);
+ this.keyStore = createKeyStore(keyStoreUrl);
} catch (Exception e) {
throw new CayenneCryptoException("Error loading keystore at " + keyStoreUrl, e);
}
}
- private KeyStore createKeyStore(String keyStoreUrl, String keyStorePassword) throws KeyStoreException, IOException,
+ private KeyStore createKeyStore(String keyStoreUrl) throws KeyStoreException, IOException,
NoSuchAlgorithmException, CertificateException {
- char[] keyStorePasswordChars = keyStorePassword != null ? keyStorePassword.toCharArray() : null;
- KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ KeyStore keyStore = KeyStore.getInstance(JCEKS_KEYSTORE_TYPE);
URL url = new URL(keyStoreUrl);
InputStream in = url.openStream();
try {
- keyStore.load(in, keyStorePasswordChars);
+ keyStore.load(in, null);
} finally {
in.close();
}
@@ -86,7 +84,7 @@ public class KeyStoreKeySource implement
@Override
public Key getKey(String alias) {
try {
- return keyStore.getKey(alias, keyPasswordChars);
+ return keyStore.getKey(alias, keyPassword);
} catch (Exception e) {
throw new CayenneCryptoException("Error accessing key for alias: " + alias, e);
}
Added: cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/key/KeyStoreKeySourceTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/key/KeyStoreKeySourceTest.java?rev=1583130&view=auto
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/key/KeyStoreKeySourceTest.java (added)
+++ cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/key/KeyStoreKeySourceTest.java Sun Mar 30 13:19:09 2014
@@ -0,0 +1,74 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.crypto.key;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.net.URL;
+import java.security.Key;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cayenne.crypto.CayenneCryptoException;
+import org.apache.cayenne.crypto.CryptoConstants;
+import org.junit.Test;
+
+public class KeyStoreKeySourceTest {
+
+ private static final char[] TEST_KEY_PASS = "testkeypass".toCharArray();
+
+ @Test(expected = CayenneCryptoException.class)
+ public void testConstructor_NoUrl() {
+ Map<String, String> props = new HashMap<String, String>();
+ Map<String, char[]> creds = new HashMap<String, char[]>();
+ new KeyStoreKeySource(props, creds);
+ }
+
+ @Test
+ public void testGetKey_JCEKS_DES() {
+
+ URL url = getClass().getResource("ks1.jceks");
+ assertNotNull(url);
+
+ Map<String, String> props = new HashMap<String, String>();
+ props.put(CryptoConstants.KEYSTORE_URL, url.toExternalForm());
+
+ Map<String, char[]> creds = new HashMap<String, char[]>();
+ creds.put(CryptoConstants.KEY_PASSWORD, TEST_KEY_PASS);
+
+ KeyStoreKeySource ks = new KeyStoreKeySource(props, creds);
+
+ assertNull(ks.getKey("no-such-key"));
+
+ Key k1 = ks.getKey("k1");
+ assertNotNull(k1);
+ assertEquals("DES", k1.getAlgorithm());
+
+ Key k2 = ks.getKey("k2");
+ assertNotNull(k2);
+ assertEquals("DES", k2.getAlgorithm());
+
+ Key k3 = ks.getKey("k3");
+ assertNotNull(k3);
+ assertEquals("AES", k3.getAlgorithm());
+ }
+
+}
Added: cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/cayenne/crypto/key/README-keystore.txt
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/cayenne/crypto/key/README-keystore.txt?rev=1583130&view=auto
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/cayenne/crypto/key/README-keystore.txt (added)
+++ cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/cayenne/crypto/key/README-keystore.txt Sun Mar 30 13:19:09 2014
@@ -0,0 +1,15 @@
+Contains unit test keystore passwords. Storing in plaintext here, as none of these
+keystores store any real keys.
+
+ks1.jceks
+---------
+
+Created with:
+keytool -genseckey -keystore ./ks1.jceks -storetype JCEKS -alias k1
+keytool -genseckey -keystore ./ks1.jceks -storetype JCEKS -alias k2
+keytool -genseckey -keystore ./ks1.jceks -storetype JCEKS -keyalg AES -keysize 128 -alias k3
+
+ Keystore - testkspass
+ k1 - testkeypass
+ k2 - testkeypass
+ k3 - testkeypass
Added: cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/cayenne/crypto/key/ks1.jceks
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/cayenne/crypto/key/ks1.jceks?rev=1583130&view=auto
==============================================================================
Files cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/cayenne/crypto/key/ks1.jceks (added) and cayenne/main/trunk/cayenne-crypto/src/test/resources/org/apache/cayenne/crypto/key/ks1.jceks Sun Mar 30 13:19:09 2014 differ