[jboss-cvs] Picketbox SVN: r438 - in branches/embargo/4.0.17.SP2: security-jboss-sx/jbosssx/src/main/java/org/picketbox/util and 5 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Tue Jul 30 11:49:31 EDT 2013
Author: pskopek at redhat.com
Date: 2013-07-30 11:49:30 -0400 (Tue, 30 Jul 2013)
New Revision: 438
Added:
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/SecurityVaultData.java
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/resources/keystore/vault.jks
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/resources/keystore/vault_data/
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/resources/long_alias_keystore/vault_data/
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/resources/replacement_keystore/
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/resources/vault-v0/
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/resources/vault-v1-more/
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/resources/vault-v1/
Removed:
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/resources/keystore/vault.keystore
Modified:
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/PicketBoxSecurityVault.java
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/EncryptionUtil.java
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/KeyStoreUtil.java
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/java/org/jboss/test/security/vault/EncryptionUtilUnitTestCase.java
branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/java/org/jboss/test/security/vault/SecurityVaultUnitTestCase.java
branches/embargo/4.0.17.SP2/security-spi/common/src/main/java/org/jboss/security/PicketBoxLogger.java
branches/embargo/4.0.17.SP2/security-spi/common/src/main/java/org/jboss/security/PicketBoxMessages.java
Log:
Merging changes r408 - r436.
Modified: branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/PicketBoxSecurityVault.java
===================================================================
--- branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/PicketBoxSecurityVault.java 2013-07-30 15:43:11 UTC (rev 437)
+++ branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/PicketBoxSecurityVault.java 2013-07-30 15:49:30 UTC (rev 438)
@@ -26,7 +26,7 @@
import org.jboss.security.plugins.PBEUtils;
import org.jboss.security.vault.SecurityVault;
import org.jboss.security.vault.SecurityVaultException;
-import org.picketbox.commons.cipher.Base64;
+import org.picketbox.plugins.vault.SecurityVaultData;
import org.picketbox.util.EncryptionUtil;
import org.picketbox.util.KeyStoreUtil;
import org.picketbox.util.StringUtil;
@@ -36,14 +36,22 @@
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.spec.SecretKeySpec;
-import java.io.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.nio.channels.FileChannel;
import java.security.*;
-import java.security.cert.Certificate;
-import java.util.Arrays;
+import java.security.KeyStore.Entry;
+import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.StringTokenizer;
/**
* An instance of {@link SecurityVault} that uses
@@ -59,8 +67,11 @@
* SALT: salt of the masked password. Ensured it is 8 characters in length
* ITERATION_COUNT: Iteration Count of the masked password.
* KEY_SIZE: Key size of encryption. Default is 128 bytes.
+ * CREATE_KEYSTORE: Whether PicketBox Security Vault has to create missing key store in time of initialization. Default is "FALSE". Implies KEYSTORE_TYPE "JCEKS".
+ * KEYSTORE_TYPE: Key store type. Default is JCEKS.
*
* @author Anil.Saldhana at redhat.com
+ * @author Peter Skopek (pskopek_at_redhat_dot_com)
* @since Aug 12, 2011
*/
public class PicketBoxSecurityVault implements SecurityVault
@@ -69,18 +80,25 @@
protected KeyStore keystore = null;
- private KeyPair keypair = null;
-
protected String encryptionAlgorithm = "AES";
protected int keySize = 128;
private char[] keyStorePWD = null;
- protected Map<String,byte[]> theContent= new ConcurrentHashMap<String,byte[]>();
+ private String alias = null;
- protected Map<String,byte[]> sharedKeyMap = new ConcurrentHashMap<String,byte[]>();
+ private SecurityVaultData vaultContent = null;
+ private SecretKey adminKey;
+
+ private String decodedEncFileDir;
+
+ private boolean createKeyStore = false;
+
+ private String keyStoreType = defaultKeyStoreType;
+
+ // options
public static final String ENC_FILE_DIR = "ENC_FILE_DIR";
public static final String KEYSTORE_URL = "KEYSTORE_URL";
@@ -99,18 +117,22 @@
public static final String KEY_SIZE = "KEY_SIZE";
- protected static final String ENCODED_FILE = "ENC.dat";
- protected static final String SHARED_KEY_FILE = "Shared.dat";
- protected static final String ADMIN_KEY = "ADMIN_KEY";
+ public static final String CREATE_KEYSTORE = "CREATE_KEYSTORE";
- protected String decodedEncFileDir;
+ public static final String KEYSTORE_TYPE = "KEYSTORE_TYPE";
+
+ // backward compatibility constants
+ private static final String ENCODED_FILE = "ENC.dat";
+ private static final String SHARED_KEY_FILE = "Shared.dat";
+ private static final String ADMIN_KEY = "ADMIN_KEY";
- protected String LINE_BREAK = "LINE_BREAK";
+ protected static final String VAULT_CONTENT_FILE = "VAULT.dat"; // versioned vault data file
+ protected static final String defaultKeyStoreType = "JCEKS";
+
/*
* @see org.jboss.security.vault.SecurityVault#init(java.util.Map)
*/
- @SuppressWarnings("unchecked")
public void init(Map<String, Object> options) throws SecurityVaultException
{
if(options == null || options.isEmpty())
@@ -140,7 +162,7 @@
throw new SecurityVaultException(PicketBoxMessages.MESSAGES.invalidNullOrEmptyOptionMessage(ITERATION_COUNT));
int iterationCount = Integer.parseInt(iterationCountStr);
- String alias = (String) options.get(KEYSTORE_ALIAS);
+ this.alias = (String) options.get(KEYSTORE_ALIAS);
if(alias == null)
throw new SecurityVaultException(PicketBoxMessages.MESSAGES.invalidNullOrEmptyOptionMessage(KEYSTORE_ALIAS));
@@ -154,62 +176,29 @@
if(encFileDir == null)
throw new SecurityVaultException(PicketBoxMessages.MESSAGES.invalidNullOrEmptyOptionMessage(ENC_FILE_DIR));
- FileInputStream fis = null, mapFile = null;
- ObjectInputStream ois = null;
- ObjectInputStream mapIS = null;
- try
- {
- if (encFileDir.contains("${)")){
- encFileDir = encFileDir.replaceAll(":",StringUtil.PROPERTY_DEFAULT_SEPARATOR);
- }
- decodedEncFileDir = StringUtil.getSystemPropertyAsString(encFileDir); // replace single ":" with PL default
+
+ createKeyStore = (options.get(CREATE_KEYSTORE) != null ? Boolean.parseBoolean((String) options.get(CREATE_KEYSTORE))
+ : createKeyStore);
+ keyStoreType = (options.get(KEYSTORE_TYPE) != null ? (String) options.get(KEYSTORE_TYPE) : defaultKeyStoreType);
- if(directoryExists(decodedEncFileDir) == false)
- throw new SecurityVaultException(PicketBoxMessages.MESSAGES.fileOrDirectoryDoesNotExistMessage(decodedEncFileDir));
+ try {
+ String keystorePass = decode(maskedPassword, salt, iterationCount);
+ keyStorePWD = keystorePass.toCharArray();
+ keystore = getKeyStore(keystoreURL);
- if(!(decodedEncFileDir.endsWith("/") || decodedEncFileDir.endsWith("\\")))
- {
- throw new SecurityVaultException(PicketBoxMessages.MESSAGES.invalidDirectoryFormatMessage(decodedEncFileDir));
- }
- if(encodedFileExists(decodedEncFileDir) ==false)
- {
- setUpVault(decodedEncFileDir);
- }
+ checkAndConvertKeyStoreToJCEKS(keystoreURL);
- fis = new FileInputStream(decodedEncFileDir + ENCODED_FILE);
- ois = new ObjectInputStream(fis);
- theContent = (Map<String, byte[]>) ois.readObject();
-
- mapFile = new FileInputStream(decodedEncFileDir + SHARED_KEY_FILE );
- mapIS = new ObjectInputStream(mapFile);
-
- sharedKeyMap = (Map<String, byte[]>) mapIS.readObject();
+ } catch (Exception e) {
+ throw new SecurityVaultException(e);
}
- catch (Exception e)
- {
- throw new SecurityVaultException(e);
- }
- finally
- {
- safeClose(fis);
- safeClose(mapFile);
- safeClose(ois);
- safeClose(mapIS);
- }
- try
- {
- String keystorePass = decode(maskedPassword, salt, iterationCount);
- keyStorePWD = keystorePass.toCharArray();
- keystore = KeyStoreUtil.getKeyStore(keystoreURL, keystorePass.toCharArray());
- keypair = KeyStoreUtil.getPrivateKey(keystore, alias, keystorePass.toCharArray());
- }
- catch (Exception e)
- {
- throw new SecurityVaultException(e);
- }
+ // read and possibly convert vault content
+ readVaultContent(keystoreURL, encFileDir);
+
PicketBoxLogger.LOGGER.infoVaultInitialized();
- finishedInit = true;
+ finishedInit = true;
+
+
}
/*
@@ -223,44 +212,16 @@
/*
* @see org.jboss.security.vault.SecurityVault#handshake(java.util.Map)
*/
- public byte[] handshake(Map<String, Object> handshakeOptions) throws SecurityVaultException
- {
- if(handshakeOptions == null || handshakeOptions.isEmpty())
- throw PicketBoxMessages.MESSAGES.invalidNullOrEmptyOptionMap("handshakeOptions");
-
- String publicCert = (String) handshakeOptions.get(PUBLIC_CERT);
- if(publicCert == null)
- throw new SecurityVaultException(PicketBoxMessages.MESSAGES.invalidNullOrEmptyOptionMessage(PUBLIC_CERT));
-
- try
- {
- PublicKey publicKey = KeyStoreUtil.getPublicKey(keystore, publicCert, keyStorePWD);
- if(publicKey == null)
- throw new SecurityVaultException(PicketBoxMessages.MESSAGES.failedToRetrievePublicKeyMessage(publicCert));
-
- }
- catch (Exception e)
- {
- throw new SecurityVaultException(e);
- }
-
-
- StringBuilder uuid = new StringBuilder(UUID.randomUUID().toString());
- uuid.append("LINE_BREAK");
- uuid.append(publicCert);
-
- return Base64.encodeBytes(uuid.toString().getBytes(), Base64.DONT_BREAK_LINES).getBytes();
+ public byte[] handshake(Map<String, Object> handshakeOptions) throws SecurityVaultException {
+ return new byte[keySize];
}
/*
* @see org.jboss.security.vault.SecurityVault#keyList()
*/
- public Set<String> keyList() throws SecurityVaultException
- {
- Set<String> keys = theContent.keySet();
- keys.remove(ADMIN_KEY);
- return keys;
- }
+ public Set<String> keyList() throws SecurityVaultException {
+ return vaultContent.getVaultDataKeys();
+ }
/*
* @see org.jboss.security.vault.SecurityVault#store(java.lang.String, java.lang.String, char[], byte[])
@@ -273,60 +234,26 @@
if(StringUtil.isNullOrEmpty(attributeName))
throw PicketBoxMessages.MESSAGES.invalidNullArgument("attributeName");
- String mapKey = vaultBlock + "_" + attributeName;
-
- sharedKeyMap.put(mapKey, sharedKey);
-
String av = new String(attributeValue);
- //Get Public Key from shared key
- String decodedSharedKey = new String(Base64.decode(new String(sharedKey)));
- int index = decodedSharedKey.indexOf(LINE_BREAK);
-
- if(index < 0)
- throw new SecurityVaultException(PicketBoxMessages.MESSAGES.invalidSharedKeyMessage());
-
- String alias = decodedSharedKey.substring(index + LINE_BREAK.length());
-
- Certificate cert;
+ EncryptionUtil util = new EncryptionUtil(encryptionAlgorithm, keySize);
try
{
- cert = keystore.getCertificate(alias);
+ SecretKeySpec sKeySpec = new SecretKeySpec(adminKey.getEncoded(), encryptionAlgorithm);
+ byte[] encryptedData = util.encrypt(av.getBytes(), sKeySpec);
+ vaultContent.addVaultData(alias, vaultBlock, attributeName, encryptedData);
}
- catch (KeyStoreException e1)
- {
- throw new SecurityVaultException(PicketBoxMessages.MESSAGES.failedToRetrieveCertificateMessage(alias), e1);
- }
-
- EncryptionUtil util = new EncryptionUtil(encryptionAlgorithm,keySize);
- try
- {
- byte[] secretKey = theContent.get(ADMIN_KEY);
-
- SecretKeySpec sKeySpec = new SecretKeySpec(secretKey,encryptionAlgorithm);
- byte[] encryptedData = util.encrypt(av.getBytes(), cert.getPublicKey(), sKeySpec);
- theContent.put(mapKey, encryptedData);
- }
catch (Exception e1)
{
throw new SecurityVaultException(PicketBoxMessages.MESSAGES.unableToEncryptDataMessage(),e1);
}
- try
- {
- writeSharedKeyFile(this.decodedEncFileDir);
+
+ try {
+ writeVaultData();
}
- catch (IOException e)
- {
- throw new SecurityVaultException(PicketBoxMessages.MESSAGES.unableToWriteShareKeyFileMessage(), e);
+ catch (IOException e) {
+ throw new SecurityVaultException(PicketBoxMessages.MESSAGES.unableToWriteVaultDataFileMessage(VAULT_CONTENT_FILE), e);
}
- try
- {
- writeEncodedFile(this.decodedEncFileDir);
- }
- catch (IOException e)
- {
- throw new SecurityVaultException(PicketBoxMessages.MESSAGES.unableToWriteEncodedFileMessage(), e);
- }
}
/*
@@ -339,36 +266,25 @@
if(StringUtil.isNullOrEmpty(attributeName))
throw PicketBoxMessages.MESSAGES.invalidNullArgument("attributeName");
- String mapKey = vaultBlock + "_" + attributeName;
- byte[] encryptedValue = theContent.get(mapKey);
+ byte[] encryptedValue = vaultContent.getVaultData(alias, vaultBlock, attributeName);
-
- byte[] fromMap = sharedKeyMap.get(mapKey);
-
- boolean matches = Arrays.equals(sharedKey, fromMap);
- if(matches == false)
- throw new SecurityVaultException(PicketBoxMessages.MESSAGES.sharedKeyMismatchMessage(vaultBlock, attributeName));
-
- byte[] secretKey = theContent.get(ADMIN_KEY);
-
- SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, encryptionAlgorithm);
+ SecretKeySpec secretKeySpec = new SecretKeySpec(adminKey.getEncoded(), encryptionAlgorithm);
EncryptionUtil encUtil = new EncryptionUtil(encryptionAlgorithm, keySize);
try
{
- return (new String(encUtil.decrypt(encryptedValue, keypair, secretKeySpec))).toCharArray();
+ return (new String(encUtil.decrypt(encryptedValue, secretKeySpec))).toCharArray();
}
catch (Exception e)
{
throw new SecurityVaultException(e);
}
}
+
/**
* @see org.jboss.security.vault.SecurityVault#exists(String, String)
*/
- public boolean exists(String vaultBlock, String attributeName) throws SecurityVaultException
- {
- String mapKey = vaultBlock + "_" + attributeName;
- return theContent.get(mapKey) != null;
+ public boolean exists(String vaultBlock, String attributeName) throws SecurityVaultException {
+ return vaultContent.getVaultData(alias, vaultBlock, attributeName) != null;
}
/*
@@ -377,13 +293,10 @@
public boolean remove(String vaultBlock, String attributeName, byte[] sharedKey)
throws SecurityVaultException
{
- String mapKey = vaultBlock + "_" + attributeName;
- try
- {
- theContent.remove(mapKey);
+ try {
+ vaultContent.deleteVaultData(alias, vaultBlock, attributeName);
}
- catch(Exception e)
- {
+ catch(Exception e) {
return false;
}
return true;
@@ -410,26 +323,43 @@
return maskedString;
}
- private void setUpVault(String decodedEncFileDir) throws NoSuchAlgorithmException,IOException
+ private void setUpVault(String keystoreURL, String decodedEncFileDir) throws NoSuchAlgorithmException, IOException
{
- theContent = new ConcurrentHashMap<String, byte[]>();
- EncryptionUtil util = new EncryptionUtil(encryptionAlgorithm,keySize);
- SecretKey secretKey = util.generateKey();
- theContent.put(ADMIN_KEY, secretKey.getEncoded());
+ vaultContent = new SecurityVaultData();
+ writeVaultData();
- writeEncodedFile(decodedEncFileDir);
- writeSharedKeyFile(decodedEncFileDir);
+ SecretKey sk = getAdminKey();
+ if (sk != null) {
+ adminKey = sk;
+ }
+ else {
+ // try to generate new admin key and store it under specified alias
+ EncryptionUtil util = new EncryptionUtil(encryptionAlgorithm, keySize);
+ sk = util.generateKey();
+ KeyStore.SecretKeyEntry skEntry = new KeyStore.SecretKeyEntry(sk);
+ try {
+ keystore.setEntry(alias, skEntry, new KeyStore.PasswordProtection(keyStorePWD));
+ adminKey = sk;
+ saveKeyStoreToFile(keystoreURL);
+ }
+ catch (KeyStoreException e) {
+ throw PicketBoxMessages.MESSAGES.noSecretKeyandAliasAlreadyUsed(alias);
+ }
+ catch (Exception e) {
+ throw PicketBoxMessages.MESSAGES.unableToStoreKeyStoreToFile(e, keystoreURL);
+ }
+ }
}
- private void writeEncodedFile(String decodedEncFileDir) throws IOException
+ private void writeVaultData() throws IOException
{
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try
{
- fos = new FileOutputStream(decodedEncFileDir + ENCODED_FILE);
+ fos = new FileOutputStream(decodedEncFileDir + VAULT_CONTENT_FILE);
oos = new ObjectOutputStream(fos);
- oos.writeObject(theContent);
+ oos.writeObject(vaultContent);
}
finally
{
@@ -438,26 +368,9 @@
}
}
- private void writeSharedKeyFile(String decodedEncFileDir) throws IOException
+ private boolean vaultFileExists(String fileName)
{
- FileOutputStream fos = null;
- ObjectOutputStream oos = null;
- try
- {
- fos = new FileOutputStream(decodedEncFileDir + SHARED_KEY_FILE);
- oos = new ObjectOutputStream(fos);
- oos.writeObject(sharedKeyMap);
- }
- finally
- {
- safeClose(oos);
- safeClose(fos);
- }
- }
-
- private boolean encodedFileExists(String decodedEncFileDir)
- {
- File file = new File(decodedEncFileDir + ENCODED_FILE);
+ File file = new File(this.decodedEncFileDir + fileName);
return file != null && file.exists();
}
@@ -492,4 +405,251 @@
catch(Exception e)
{}
}
+
+ private void readVaultContent(String keystoreURL, String encFileDir) throws SecurityVaultException {
+
+ try {
+ if (encFileDir.contains("${)")) {
+ encFileDir = encFileDir.replaceAll(":", StringUtil.PROPERTY_DEFAULT_SEPARATOR);
+ }
+ decodedEncFileDir = StringUtil.getSystemPropertyAsString(encFileDir); // replace single ":" with PL default
+
+ if (directoryExists(decodedEncFileDir) == false)
+ throw new SecurityVaultException(
+ PicketBoxMessages.MESSAGES.fileOrDirectoryDoesNotExistMessage(decodedEncFileDir));
+
+ if (!(decodedEncFileDir.endsWith("/") || decodedEncFileDir.endsWith("\\"))) {
+ decodedEncFileDir = decodedEncFileDir + File.separator;
+ }
+
+ if (vaultFileExists(ENCODED_FILE)) {
+ if (vaultFileExists(VAULT_CONTENT_FILE)) {
+ PicketBoxLogger.LOGGER.mixedVaultDataFound(VAULT_CONTENT_FILE, ENCODED_FILE, decodedEncFileDir
+ + ENCODED_FILE);
+ throw PicketBoxMessages.MESSAGES.mixedVaultDataFound(VAULT_CONTENT_FILE, ENCODED_FILE);
+ } else {
+ convertVaultContent(keystoreURL, alias);
+ }
+ } else {
+ if (vaultFileExists(VAULT_CONTENT_FILE)) {
+ readVersionedVaultContent();
+ } else {
+ setUpVault(keystoreURL, decodedEncFileDir);
+ }
+ }
+
+ } catch (Exception e) {
+ throw new SecurityVaultException(e);
+ }
+
+ }
+
+ @SuppressWarnings("unchecked")
+ private void convertVaultContent(String keystoreURL, String alias) throws Exception {
+ FileInputStream fis = null;
+ ObjectInputStream ois = null;
+ Map<String, byte[]> theContent;
+
+ try {
+ fis = new FileInputStream(decodedEncFileDir + ENCODED_FILE);
+ ois = new ObjectInputStream(fis);
+ theContent = (Map<String, byte[]>) ois.readObject();
+ } finally {
+ safeClose(fis);
+ safeClose(ois);
+ }
+
+ // create new SecurityVaultData object for transformed vault data
+ vaultContent = new SecurityVaultData();
+
+ adminKey = null;
+ for (String key: theContent.keySet()) {
+ if (key.equals(ADMIN_KEY)) {
+ byte[] admin_key = theContent.get(key);
+ adminKey = new SecretKeySpec(admin_key, encryptionAlgorithm);
+ }
+ else {
+ if (key.contains("_")) {
+ StringTokenizer tokenizer = new StringTokenizer(key, "_");
+ String vaultBlock = tokenizer.nextToken();
+ String attributeName = tokenizer.nextToken();
+ if (tokenizer.hasMoreTokens()) {
+ attributeName = key.substring(vaultBlock.length() + 1);
+ PicketBoxLogger.LOGGER.ambiguosKeyForSecurityVaultTransformation("_", vaultBlock, attributeName);
+ }
+ byte[] encodedAttributeValue = theContent.get(key);
+ vaultContent.addVaultData(alias, vaultBlock, attributeName, encodedAttributeValue);
+ }
+ }
+ }
+ if (adminKey == null) {
+ throw PicketBoxMessages.MESSAGES.missingAdminKeyInOriginalVaultData();
+ }
+
+ // add secret key (admin_key) to keystore
+ KeyStore.SecretKeyEntry skEntry = new KeyStore.SecretKeyEntry(adminKey);
+ KeyStore.PasswordProtection p = new KeyStore.PasswordProtection(keyStorePWD);
+ Entry e = keystore.getEntry(alias, p);
+ if (e != null) {
+ // rename the old entry
+ String originalAlias = alias + "-original";
+ keystore.setEntry(originalAlias, e, p);
+ keystore.deleteEntry(alias);
+ }
+ keystore.setEntry(alias, skEntry, new KeyStore.PasswordProtection(keyStorePWD));
+
+ // save the current keystore
+ saveKeyStoreToFile(keystoreURL);
+
+ // backup original vault file (shared key file cannot be saved for obvious reasons
+ copyFile(new File(decodedEncFileDir + ENCODED_FILE), new File(decodedEncFileDir + ENCODED_FILE + ".original"));
+
+ // save vault data file
+ writeVaultData();
+
+ // delete original vault files
+ File f = new File(decodedEncFileDir + ENCODED_FILE);
+ if (!f.delete()) {
+ PicketBoxLogger.LOGGER.cannotDeleteOriginalVaultFile(f.getCanonicalPath());
+ }
+ f = new File(decodedEncFileDir + SHARED_KEY_FILE);
+ if (!f.delete()) {
+ PicketBoxLogger.LOGGER.cannotDeleteOriginalVaultFile(f.getCanonicalPath());
+ }
+
+ }
+
+ private void saveKeyStoreToFile(String keystoreURL) throws Exception {
+ keystore.store(new FileOutputStream(new File(keystoreURL)), keyStorePWD);
+ }
+
+ private void checkAndConvertKeyStoreToJCEKS(String keystoreURL) throws Exception {
+ if (keystore.getType().equalsIgnoreCase("JKS")) {
+
+ // backup original keystore file
+ copyFile(new File(keystoreURL), new File(keystoreURL + ".original"));
+
+ KeyStore jceks = KeyStoreUtil.createKeyStore("JCEKS", keyStorePWD);
+
+ Enumeration<String> aliases = keystore.aliases();
+ while (aliases.hasMoreElements()) {
+ String entryAlias = aliases.nextElement();
+ KeyStore.PasswordProtection p = new KeyStore.PasswordProtection(keyStorePWD);
+ KeyStore.Entry e = keystore.getEntry(entryAlias, p);
+ jceks.setEntry(entryAlias, e, p);
+ }
+ keystore = jceks;
+ keyStoreType = "JCEKS"; // after conversion we have to change keyStoreType to the one we really have
+ saveKeyStoreToFile(keystoreURL);
+ PicketBoxLogger.LOGGER.keyStoreConvertedToJCEKS(KEYSTORE_URL);
+ }
+ }
+
+
+
+ private void readVersionedVaultContent() throws Exception {
+ FileInputStream fis = null;
+ ObjectInputStream ois = null;
+ try {
+ fis = new FileInputStream(decodedEncFileDir + VAULT_CONTENT_FILE);
+ ois = new ObjectInputStream(fis);
+ vaultContent = (SecurityVaultData) ois.readObject();
+ } finally {
+ safeClose(fis);
+ safeClose(ois);
+ }
+
+ adminKey = getAdminKey();
+ if (adminKey == null) {
+ throw PicketBoxMessages.MESSAGES.vaultDoesnotContainSecretKey(alias);
+ }
+ }
+
+ /**
+ * Returns SecretKey stored in defined keystore under defined alias.
+ * If no such SecretKey exists returns null.
+ * @return
+ */
+ private SecretKey getAdminKey() {
+ try {
+ Entry e = keystore.getEntry(alias, new KeyStore.PasswordProtection(keyStorePWD));
+ if (e instanceof KeyStore.SecretKeyEntry) {
+ return ((KeyStore.SecretKeyEntry)e).getSecretKey();
+ }
+ }
+ catch (Exception e) {
+ PicketBoxLogger.LOGGER.vaultDoesnotContainSecretKey(alias);
+ return null;
+ }
+ return null;
+ }
+
+ /**
+ * Copy file method.
+ *
+ * @param sourceFile
+ * @param destFile
+ * @throws IOException
+ */
+ public static void copyFile(File sourceFile, File destFile) throws IOException {
+ if (!destFile.exists()) {
+ destFile.createNewFile();
+ }
+ FileInputStream fIn = null;
+ FileOutputStream fOut = null;
+ FileChannel source = null;
+ FileChannel destination = null;
+ try {
+ fIn = new FileInputStream(sourceFile);
+ source = fIn.getChannel();
+ fOut = new FileOutputStream(destFile);
+ destination = fOut.getChannel();
+ long transfered = 0;
+ long bytes = source.size();
+ while (transfered < bytes) {
+ transfered += destination.transferFrom(source, 0, source.size());
+ destination.position(transfered);
+ }
+ } finally {
+ if (source != null) {
+ source.close();
+ } else if (fIn != null) {
+ fIn.close();
+ }
+ if (destination != null) {
+ destination.close();
+ } else if (fOut != null) {
+ fOut.close();
+ }
+ }
+ }
+
+ /**
+ * Get key store based on options passed to PicketBoxSecurityVault.
+ * @return
+ */
+ private KeyStore getKeyStore(String keystoreURL) {
+
+ try {
+ return KeyStoreUtil.getKeyStore(keyStoreType, keystoreURL, keyStorePWD);
+ }
+ catch (IOException e) {
+ // deliberately empty
+ }
+ catch (GeneralSecurityException e) {
+ throw PicketBoxMessages.MESSAGES.unableToGetKeyStore(e, keystoreURL);
+ }
+
+ try {
+ if (createKeyStore) {
+ return KeyStoreUtil.createKeyStore(keyStoreType, keyStorePWD);
+ }
+ }
+ catch (Throwable e) {
+ throw PicketBoxMessages.MESSAGES.unableToGetKeyStore(e, keystoreURL);
+ }
+
+ return null;
+ }
+
}
\ No newline at end of file
Copied: branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/SecurityVaultData.java (from rev 436, branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/SecurityVaultData.java)
===================================================================
--- branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/SecurityVaultData.java (rev 0)
+++ branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/SecurityVaultData.java 2013-07-30 15:49:30 UTC (rev 438)
@@ -0,0 +1,153 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.picketbox.plugins.vault;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.jboss.security.PicketBoxLogger;
+import org.jboss.security.PicketBoxMessages;
+import org.picketbox.util.StringUtil;
+
+/**
+ * Security vault data store with version serialized data storage.
+ *
+ * @author Peter Skopek (pskopek_at_redhat_dot_com)
+ *
+ */
+public class SecurityVaultData implements Serializable {
+
+ /**
+ * Do not change this suid, it is used for handling different versions of serialized data.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Version to denote actual version of SecurityVaultData object.
+ */
+ private static final int VERSION = 1;
+
+ private transient Map<String, byte[]> vaultData = new ConcurrentHashMap<String,byte[]>();
+
+
+ /**
+ * Default constructor.
+ */
+ public SecurityVaultData() {
+ }
+
+ /**
+ * Writes object to the ObjectOutputSteream.
+ *
+ * @param oos
+ * @throws IOException
+ */
+ private void writeObject(ObjectOutputStream oos) throws IOException {
+ oos.writeObject(new Integer(VERSION));
+ oos.writeObject(vaultData);
+ }
+
+ /**
+ * Reads object from the ObjectInputStream. This method needs to be changed when implementing
+ * changes in data and {@link VERSION} is changed.
+ *
+ * @param ois
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ @SuppressWarnings("unchecked")
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ int version = (Integer) ois.readObject();
+
+ if (PicketBoxLogger.LOGGER.isDebugEnabled()) {
+ PicketBoxLogger.LOGGER.securityVaultContentVersion(String.valueOf(version), String.valueOf(VERSION));
+ }
+
+ if (version == 1) {
+ this.vaultData = (Map<String, byte[]>)ois.readObject();
+ }
+ else {
+ throw PicketBoxMessages.MESSAGES.unrecognizedVaultContentVersion(String.valueOf(version), "1", String.valueOf(VERSION));
+ }
+ }
+
+ /**
+ * Retrieves the data stored in vault storage.
+ *
+ * @param keyAlias - currently not used (for possible future extension)
+ * @param vaultBlock
+ * @param attributeName
+ * @return
+ */
+ byte[] getVaultData(String keyAlias, String vaultBlock, String attributeName) {
+ return vaultData.get(dataKey(keyAlias, vaultBlock, attributeName));
+ }
+
+ /**
+ *
+ * @param keyAlias
+ * @param vaultBlock
+ * @param attributeName
+ * @param encryptedData
+ */
+ void addVaultData(String keyAlias, String vaultBlock, String attributeName, byte[] encryptedData) {
+ vaultData.put(dataKey(keyAlias, vaultBlock, attributeName), encryptedData);
+ }
+
+ /**
+ *
+ * @param keyAlias
+ * @param vaultBlock
+ * @param attributeName
+ */
+ void deleteVaultData(String keyAlias, String vaultBlock, String attributeName) {
+ vaultData.remove(dataKey(keyAlias, vaultBlock, attributeName));
+ }
+
+ /**
+ * Returns mapping keys for all stored data.
+ * @return
+ */
+ Set<String> getVaultDataKeys() {
+ return vaultData.keySet();
+ }
+
+ /**
+ * Creates new format for data key in vault. All parameters has to be non-null.
+ *
+ * @param keyAlias - currently not used (for possible future extension)
+ * @param vaultBlock
+ * @param attributeName
+ * @param alias
+ * @return
+ */
+ private static String dataKey(String keyAlias, String vaultBlock, String attributeName) {
+ return vaultBlock + StringUtil.PROPERTY_DEFAULT_SEPARATOR + attributeName;
+ }
+
+}
Modified: branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/EncryptionUtil.java
===================================================================
--- branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/EncryptionUtil.java 2013-07-30 15:43:11 UTC (rev 437)
+++ branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/EncryptionUtil.java 2013-07-30 15:49:30 UTC (rev 438)
@@ -109,4 +109,30 @@
byte[] original = cipher.doFinal(encryptedData);
return original;
}
+
+ public byte[] encrypt(byte[] data, SecretKey key) throws Exception
+ {
+ SecretKeySpec skeySpec = new SecretKeySpec(key.getEncoded(), encryptionAlgorithm);
+
+ // Instantiate the cipher
+ Cipher cipher = Cipher.getInstance(encryptionAlgorithm);
+
+ cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
+
+ byte[] encrypted =
+ cipher.doFinal( data);
+ return encrypted;
+ }
+
+ public byte[] decrypt(byte[] encryptedData, SecretKeySpec keySpec ) throws Exception
+ {
+
+ // Instantiate the cipher
+ Cipher cipher = Cipher.getInstance(encryptionAlgorithm);
+
+ cipher.init(Cipher.DECRYPT_MODE, keySpec);
+ byte[] original = cipher.doFinal(encryptedData);
+ return original;
+ }
+
}
\ No newline at end of file
Modified: branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/KeyStoreUtil.java
===================================================================
--- branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/KeyStoreUtil.java 2013-07-30 15:43:11 UTC (rev 437)
+++ branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/KeyStoreUtil.java 2013-07-30 15:49:30 UTC (rev 438)
@@ -44,7 +44,9 @@
/**
* Utility to handle Java Keystore
+ *
* @author Anil.Saldhana at redhat.com
+ * @author Peter Skopek (pskopek_at_redhat_dot_com)
* @since Jan 12, 2009
*/
public class KeyStoreUtil
@@ -59,11 +61,67 @@
*/
public static KeyStore getKeyStore(File keyStoreFile, char[] storePass) throws GeneralSecurityException, IOException
{
+ return getKeyStore(KeyStore.getDefaultType(), keyStoreFile, storePass);
+ }
+
+ /**
+ * Get the Keystore given the url to the keystore file as a string
+ * @param fileURL
+ * @param storePass
+ * @return
+ * @throws GeneralSecurityException
+ * @throws IOException
+ */
+ public static KeyStore getKeyStore(String fileURL, char[] storePass) throws GeneralSecurityException, IOException
+ {
+ return getKeyStore(KeyStore.getDefaultType(), fileURL, storePass);
+ }
+
+ /**
+ * Get the Keystore given the URL to the keystore
+ * @param url
+ * @param storePass
+ * @return
+ * @throws GeneralSecurityException
+ * @throws IOException
+ */
+ public static KeyStore getKeyStore(URL url, char[] storePass) throws GeneralSecurityException, IOException
+ {
+ return getKeyStore(KeyStore.getDefaultType(), url, storePass);
+ }
+
+ /**
+ * Get the Key Store
+ * <b>Note:</b> This method wants the InputStream to be not null.
+ * @param ksStream
+ * @param storePass
+ * @return
+ * @throws GeneralSecurityException
+ * @throws IOException
+ * @throws IllegalArgumentException if ksStream is null
+ */
+ public static KeyStore getKeyStore(InputStream ksStream, char[] storePass) throws GeneralSecurityException,
+ IOException
+ {
+ return getKeyStore(KeyStore.getDefaultType(), ksStream, storePass);
+ }
+
+ /**
+ * Get the KeyStore
+ * @param keyStoreType or null for default
+ * @param keyStoreFile
+ * @param storePass
+ * @return
+ * @throws GeneralSecurityException
+ * @throws IOException
+ */
+ public static KeyStore getKeyStore(String keyStoreType, File keyStoreFile, char[] storePass) throws GeneralSecurityException, IOException
+ {
FileInputStream fis = null;
try
{
fis = new FileInputStream(keyStoreFile);
- return getKeyStore(fis, storePass);
+ return getKeyStore(keyStoreType, fis, storePass);
}
finally
{
@@ -73,13 +131,14 @@
/**
* Get the Keystore given the url to the keystore file as a string
+ * @param keyStoreType or null for default
* @param fileURL
* @param storePass
* @return
* @throws GeneralSecurityException
* @throws IOException
*/
- public static KeyStore getKeyStore(String fileURL, char[] storePass) throws GeneralSecurityException, IOException
+ public static KeyStore getKeyStore(String keyStoreType, String fileURL, char[] storePass) throws GeneralSecurityException, IOException
{
if (fileURL == null)
throw PicketBoxMessages.MESSAGES.invalidNullArgument("fileURL");
@@ -89,7 +148,7 @@
try
{
fis = new FileInputStream(file);
- return getKeyStore(fis, storePass);
+ return getKeyStore(keyStoreType, fis, storePass);
}
finally
{
@@ -99,13 +158,14 @@
/**
* Get the Keystore given the URL to the keystore
+ * @param keyStoreType or null for default
* @param url
* @param storePass
* @return
* @throws GeneralSecurityException
* @throws IOException
*/
- public static KeyStore getKeyStore(URL url, char[] storePass) throws GeneralSecurityException, IOException
+ public static KeyStore getKeyStore(String keyStoreType, URL url, char[] storePass) throws GeneralSecurityException, IOException
{
if (url == null)
throw PicketBoxMessages.MESSAGES.invalidNullArgument("url");
@@ -114,7 +174,7 @@
try
{
is = url.openStream();
- return getKeyStore(is, storePass);
+ return getKeyStore(keyStoreType, is, storePass);
}
finally
{
@@ -125,6 +185,7 @@
/**
* Get the Key Store
* <b>Note:</b> This method wants the InputStream to be not null.
+ * @param keyStoreType or null for default
* @param ksStream
* @param storePass
* @return
@@ -132,12 +193,11 @@
* @throws IOException
* @throws IllegalArgumentException if ksStream is null
*/
- public static KeyStore getKeyStore(InputStream ksStream, char[] storePass) throws GeneralSecurityException,
- IOException
+ public static KeyStore getKeyStore(String keyStoreType, InputStream ksStream, char[] storePass) throws GeneralSecurityException, IOException
{
if (ksStream == null)
throw PicketBoxMessages.MESSAGES.invalidNullArgument("ksStream");
- KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ KeyStore ks = KeyStore.getInstance((keyStoreType == null ? KeyStore.getDefaultType() : keyStoreType));
ks.load(ksStream, storePass);
return ks;
}
@@ -199,8 +259,23 @@
public static void addCertificate(File keystoreFile, char[] storePass, String alias, Certificate cert)
throws GeneralSecurityException, IOException
{
- KeyStore keystore = getKeyStore(keystoreFile, storePass);
+ addCertificate(KeyStore.getDefaultType(), keystoreFile, storePass, alias, cert);
+ }
+ /**
+ * Add a certificate to the KeyStore
+ * @param keystoreFile
+ * @param storePass
+ * @param alias
+ * @param cert
+ * @throws GeneralSecurityException
+ * @throws IOException
+ */
+ public static void addCertificate(String keyStoreType, File keystoreFile, char[] storePass, String alias, Certificate cert)
+ throws GeneralSecurityException, IOException
+ {
+ KeyStore keystore = getKeyStore(keyStoreType, keystoreFile, storePass);
+
// Add the certificate
keystore.setCertificateEntry(alias, cert);
@@ -243,6 +318,20 @@
}
return null;
}
+
+ /**
+ * Create new empty keystore with specified keyStoreType and keyStorePWD
+ * @param keyStoreType - key store type
+ * @param keyStorePWD - key store password
+ * @return
+ * @throws Exception
+ */
+ public static KeyStore createKeyStore(String keyStoreType, char[] keyStorePWD) throws Exception {
+ KeyStore ks = KeyStore.getInstance(keyStoreType);
+ ks.load(null, keyStorePWD);
+ return ks;
+ }
+
private static void safeClose(InputStream fis)
{
@@ -256,6 +345,7 @@
catch(Exception e)
{}
}
+
private static void safeClose(OutputStream os)
{
try
@@ -268,4 +358,5 @@
catch(Exception e)
{}
}
+
}
\ No newline at end of file
Modified: branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/java/org/jboss/test/security/vault/EncryptionUtilUnitTestCase.java
===================================================================
--- branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/java/org/jboss/test/security/vault/EncryptionUtilUnitTestCase.java 2013-07-30 15:43:11 UTC (rev 437)
+++ branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/java/org/jboss/test/security/vault/EncryptionUtilUnitTestCase.java 2013-07-30 15:49:30 UTC (rev 438)
@@ -41,13 +41,18 @@
*/
public class EncryptionUtilUnitTestCase
{
- String keyStoreURL = "src/test/resources/keystore/vault.keystore";
+ String keyStoreURL = "target/vaults/vault-enc/vault.jks";
String keyStorePass = "vault22";
String alias = "vault";
@Test
public void testEncryptDecrypt() throws Exception
{
+ SecurityVaultUnitTestCase.setInitialVaulConditions(
+ "src/test/resources/keystore/vault.jks", "target/vaults/vault-enc/vault.jks",
+ "src/test/resources/keystore/vault_data", "target/vaults/vault-enc/vault_data");
+
+
KeyStore ks = KeyStoreUtil.getKeyStore(keyStoreURL, keyStorePass.toCharArray());
assertNotNull(ks);
EncryptionUtil encUtil = new EncryptionUtil("AES", 128);
Modified: branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/java/org/jboss/test/security/vault/SecurityVaultUnitTestCase.java
===================================================================
--- branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/java/org/jboss/test/security/vault/SecurityVaultUnitTestCase.java 2013-07-30 15:43:11 UTC (rev 437)
+++ branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/java/org/jboss/test/security/vault/SecurityVaultUnitTestCase.java 2013-07-30 15:49:30 UTC (rev 438)
@@ -23,61 +23,44 @@
import org.jboss.security.plugins.PBEUtils;
import org.jboss.security.vault.SecurityVault;
+import org.jboss.security.vault.SecurityVaultException;
import org.jboss.security.vault.SecurityVaultFactory;
import org.jboss.security.vault.SecurityVaultUtil;
-import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.picketbox.plugins.vault.PicketBoxSecurityVault;
-import org.picketbox.util.StringUtil;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
+import junit.framework.Assert;
+
import static org.junit.Assert.*;
/**
* Unit Test the {@link SecurityVault} Implementation
+ *
+ * Note: replacement-vault.keystore has been created using:
+ * keytool -genkey -alias mykey -keystore replacement-vault.keystore -keyalg RSA -keysize 1024 -storepass supersecret11 -keypass supersecret11 -dname "CN=Picketbox vault,OU=picketbox,O=JBoss"
+ *
* @author Anil.Saldhana at redhat.com
* @since Aug 12, 2011
*/
public class SecurityVaultUnitTestCase
{
- String salt = "12438567";
- int iterationCount = 50;
+ //String dataDir = "${java.io.tmpdir}/enc/";
- String keyStorePass = "vault22";
-
- String maskedPWD;
-
- String dataDir = "${java.io.tmpdir}/enc/";
-
- @Before
- public void setup() throws Exception
- {
- setupEncryptionFilesDir(dataDir);
- }
-
- private void setupEncryptionFilesDir(String directoryName) {
-
- String dir = StringUtil.getSystemPropertyAsString(directoryName);
- File encDir = new File(dir);
-
- if(encDir.exists() == false)
- encDir.mkdirs();
-
- File encFile = new File(dir + "/enc.dat");
- if(encFile.exists())
- encFile.delete();
- }
-
@Test
- @Ignore
public void testDefaultVault() throws Exception
{
SecurityVault vault = SecurityVaultFactory.get();
@@ -87,43 +70,21 @@
}
@Test
- @Ignore
- public void testInitialization() throws Exception
+ public void testHandshake() throws Exception
{
- SecurityVault vault = SecurityVaultFactory.get();
- assertNotNull(vault);
- assertTrue(vault instanceof PicketBoxSecurityVault);
- assertFalse(vault.isInitialized());
- Map<String,Object> options = new HashMap<String,Object>();
- try
- {
- vault.init(options);
- fail("Should have thrown error");
- }
- catch(IllegalArgumentException iae)
- {
- }
- maskedPWD = getMaskedPassword(keyStorePass, salt,iterationCount);
+ setInitialVaulConditions("src/test/resources/keystore/vault.jks", "target/vaults/vault1/vault.jks",
+ "src/test/resources/keystore/vault_data", "target/vaults/vault1/vault_data");
- options.putAll(getMap());
+ SecurityVault vault = getNewSecurityVaultInstance();
+ Map<String,Object> options = getVaultOptionsMap(
+ "target/vaults/vault1/vault.jks",
+ "target/vaults/vault1/vault_data",
+ "vault", "12438567", 50, "vault22");
+
vault.init(options);
-
assertTrue(vault.isInitialized());
- }
-
- @Test
- public void testHandshake() throws Exception
- {
- SecurityVault vault = SecurityVaultFactory.get();
- Map<String,Object> options = new HashMap<String,Object>();
- maskedPWD = getMaskedPassword(keyStorePass, salt,iterationCount);
-
- options.putAll(getMap());
- vault.init(options);
- assertTrue(vault.isInitialized());
-
Map<String,Object> handshakeOptions = new HashMap<String,Object>();
handshakeOptions.put(PicketBoxSecurityVault.PUBLIC_CERT,"vault");
@@ -132,31 +93,25 @@
}
@Test
- public void testHandshakeForLongAlias() throws Exception
+ public void testHandshakeAnConversionForLongAlias() throws Exception
{
-
- SecurityVault vault = SecurityVaultFactory.get();
- String maskedPassword = getMaskedPassword("password1234", "87654321", 23);
- String encDir = "${java.io.tmpdir}/long_alias_keystore/";
- setupEncryptionFilesDir(encDir);
+ setInitialVaulConditions("src/test/resources/long_alias_keystore/vault.jks", "target/vaults/long_alias_keystore/vault.jks",
+ "src/test/resources/long_alias_keystore/vault_data", "target/vaults/long_alias_keystore/vault_data");
- Map<String,Object> options = new HashMap<String,Object>();
- options.put(PicketBoxSecurityVault.KEYSTORE_URL, "src/test/resources/long_alias_keystore/vault.jks");
- options.put(PicketBoxSecurityVault.KEYSTORE_PASSWORD, maskedPassword);
- options.put(PicketBoxSecurityVault.KEYSTORE_ALIAS, "superverylongvaultname");
- options.put(PicketBoxSecurityVault.SALT, "87654321");
- options.put(PicketBoxSecurityVault.ITERATION_COUNT, String.valueOf(23));
- options.put(PicketBoxSecurityVault.ENC_FILE_DIR, encDir);
+ SecurityVault vault = getNewSecurityVaultInstance();
+ Map<String,Object> options = getVaultOptionsMap(
+ "target/vaults/long_alias_keystore/vault.jks",
+ "target/vaults/long_alias_keystore/vault_data",
+ "superverylongvaultname", "87654321", 23, "password1234");
vault.init(options);
assertTrue("Vault is supposed to be inicialized", vault.isInitialized());
Map<String,Object> handshakeOptions = new HashMap<String,Object>();
- handshakeOptions.put(PicketBoxSecurityVault.PUBLIC_CERT, "superverylongvaultname");
-
byte[] sharedKey = vault.handshake(handshakeOptions);
assertNotNull(sharedKey);
-
+
+ // not relevant anymore, but leaving it as is
boolean containsLineBreaks = false;
for (byte b: sharedKey) {
if (b == '\n') {
@@ -170,22 +125,26 @@
@Test
public void testStoreAndRetrieve() throws Exception
{
+
+ setInitialVaulConditions("src/test/resources/keystore/vault.jks", "target/vaults/vault2/vault.jks",
+ "src/test/resources/keystore/vault_data", "target/vaults/vault2/vault_data");
+
+ Map<String,Object> options = getVaultOptionsMap(
+ "target/vaults/vault2/vault.jks",
+ "target/vaults/vault2/vault_data",
+ "vault", "12438567", 50, "vault22");
+
String vaultBlock = "SecBean";
String attributeName = "theAttribute";
char[] attributeValue = "someValue".toCharArray();
- SecurityVault vault = SecurityVaultFactory.get();
- Map<String,Object> options = new HashMap<String,Object>();
- maskedPWD = getMaskedPassword(keyStorePass, salt,iterationCount);
+ SecurityVault vault = getNewSecurityVaultInstance();
- options.putAll(getMap());
-
vault.init(options);
assertTrue(vault.isInitialized());
Map<String,Object> handshakeOptions = new HashMap<String,Object>();
- handshakeOptions.put(PicketBoxSecurityVault.PUBLIC_CERT,"vault");
byte[] sharedKey = vault.handshake(handshakeOptions);
assertNotNull(sharedKey);
@@ -205,7 +164,179 @@
assertFalse(vault.exists(vaultBlock+"1", attributeName+"2"));
}
+
+ /**
+ * See src/test/resources/vault-v0/readme.txt for initial vault setup (including secured attributes).
+ * @throws Exception
+ */
@Test
+ public void testConversion() throws Exception {
+
+ setInitialVaulConditions("src/test/resources/vault-v0/vault-jks.keystore", "target/vaults/vault-v0/vault-jks.keystore",
+ "src/test/resources/vault-v0/vault_data", "target/vaults/vault-v0/vault_data");
+
+ final Map<String, Object> options = getVaultOptionsMap(
+ "target/vaults/vault-v0/vault-jks.keystore",
+ "target/vaults/vault-v0/vault_data",
+ "thealias", "24681359", 88, "secretsecret");
+
+ SecurityVault vault = getNewSecurityVaultInstance();
+
+ // init should do the automatic conversion
+ vault.init(options);
+ assertTrue(vault.isInitialized());
+
+ byte[] sharedKey = vault.handshake(null);
+ assertNotNull(sharedKey);
+
+ // let's try to check if the converted vault contains all secret attributes from initial vault
+ assertSecretValue(vault, "vb", "attr1", "pwd1");
+ assertSecretValue(vault, "vb", "attr2", "pwd2");
+ assertSecretValue(vault, "vb1", "attr1", "pwd3");
+ assertSecretValue(vault, "vb2", "attr2", "pwd4");
+ assertSecretValue(vault, "vb2", "attr3", "pwd5");
+ assertSecretValue(vault, "vb", "attr3", "pwd6");
+
+
+ // get new instance of vault to simulate restart of application server
+ SecurityVault convertedVault = getNewSecurityVaultInstance();
+ assertFalse(convertedVault.isInitialized());
+ convertedVault.init(options);
+ assertTrue(convertedVault.isInitialized());
+
+ convertedVault.handshake(null);
+
+ // now try the same attributes on converted vault after restart
+ assertSecretValue(convertedVault, "vb", "attr1", "pwd1");
+ assertSecretValue(convertedVault, "vb", "attr2", "pwd2");
+ assertSecretValue(convertedVault, "vb1", "attr1", "pwd3");
+ assertSecretValue(convertedVault, "vb2", "attr2", "pwd4");
+ assertSecretValue(convertedVault, "vb2", "attr3", "pwd5");
+ assertSecretValue(convertedVault, "vb", "attr3", "pwd6");
+
+ }
+
+ @Test
+ public void testVault_V1_open_retrieve() throws Exception {
+
+ setInitialVaulConditions("src/test/resources/vault-v1/vault-jceks.keystore", "target/vaults/vault-v1/vault-jceks.keystore",
+ "src/test/resources/vault-v1/vault_data", "target/vaults/vault-v1/vault_data");
+
+ final Map<String, Object> options = getVaultOptionsMap(
+ "target/vaults/vault-v1/vault-jceks.keystore",
+ "target/vaults/vault-v1/vault_data",
+ "test", "12345678", 34, "secretsecret");
+
+ SecurityVault vault = getNewSecurityVaultInstance();
+ assertFalse(vault.isInitialized());
+
+ vault.init(options);
+ assertTrue(vault.isInitialized());
+
+ vault.handshake(null);
+
+ // let's try to check if proper values are stored in the vault
+ assertSecretValue(vault, "vb1", "attr11", "secret11");
+ assertSecretValue(vault, "vb1", "attr12", "secret12");
+
+ }
+
+ @Test(expected = SecurityVaultException.class)
+ public void testVault_V1_open_wrong_alias() throws Exception {
+
+ setInitialVaulConditions("src/test/resources/vault-v1/vault-jceks.keystore", "target/vaults/vault-v1-wrong/vault-jceks.keystore",
+ "src/test/resources/vault-v1/vault_data", "target/vaults/vault-v1-wrong/vault_data");
+
+ final Map<String, Object> options = getVaultOptionsMap(
+ "target/vaults/vault-v1-wrong/vault-jceks.keystore",
+ "target/vaults/vault-v1-wrong/vault_data",
+ "thewrongalias", "12345678", 34, "secretsecret");
+
+ SecurityVault vault = getNewSecurityVaultInstance();
+ assertFalse(vault.isInitialized());
+
+ vault.init(options);
+
+ }
+
+ @Test(expected = SecurityVaultException.class)
+ public void testVaultWithReplacedKeystore() throws Exception {
+
+ setInitialVaulConditions("src/test/resources/vault-v1/vault-replacement-jceks.keystore", "target/vaults/vault-v1/vault-jceks.keystore",
+ "src/test/resources/vault-v1/vault_data", "target/vaults/vault-v1/vault_data");
+
+ final Map<String, Object> options = getVaultOptionsMap(
+ "target/vaults/vault-v1/vault-jceks.keystore",
+ "target/vaults/vault-v1/vault_data",
+ "test", "12345678", 34, "secretsecret");
+
+ SecurityVault vault = getNewSecurityVaultInstance();
+ assertFalse(vault.isInitialized());
+
+ vault.init(options);
+ assertTrue(vault.isInitialized());
+
+ vault.handshake(null);
+
+ // let's try to check if the converted vault contains all secret attributes from initial vault
+ assertSecretValue(vault, "vb1", "attr11", "secret11");
+ assertSecretValue(vault, "vb1", "attr12", "secret12");
+
+ }
+
+ @Test
+ public void testMoreSecretKeys() throws Exception {
+ setInitialVaulConditions("src/test/resources/vault-v1-more/vault-jceks.keystore", "target/vaults/vault-v1-more/vault-jceks.keystore",
+ "src/test/resources/vault-v1-more/vault_data", "target/vaults/vault-v1-more/vault_data");
+
+ final Map<String, Object> options = getVaultOptionsMap(
+ "target/vaults/vault-v1-more/vault-jceks.keystore",
+ "target/vaults/vault-v1-more/vault_data",
+ "test", "12345678", 34, "secretsecret");
+
+ SecurityVault vault = getNewSecurityVaultInstance();
+ assertFalse(vault.isInitialized());
+
+ vault.init(options);
+ assertTrue(vault.isInitialized());
+
+ vault.handshake(null);
+
+ // let's try to check if proper values are stored in the vault
+ assertSecretValue(vault, "vb1", "attr11", "secret11");
+ assertSecretValue(vault, "vb1", "attr12", "secret12");
+
+ final Map<String, Object> options2 = getVaultOptionsMap(
+ "target/vaults/vault-v1-more/vault-jceks.keystore",
+ "target/vaults/vault-v1-more/vault_data",
+ "test2", "12345678", 34, "secretsecret");
+
+ SecurityVault vault2 = getNewSecurityVaultInstance();
+ assertFalse(vault2.isInitialized());
+
+ vault2.init(options2);
+ assertTrue(vault2.isInitialized());
+
+ vault2.handshake(null);
+
+ // let's try to check different alias can retrieve proper attribute
+ assertSecretValue(vault2, "vb1", "attr13", "secret13");
+
+ try {
+ assertSecretValue(vault2, "vb1", "attr11", "secret11");
+ fail("retrieving security attribute with different secret key alias has to fail.");
+ }
+ catch (SecurityVaultException e) {
+ // deliberately empty
+ }
+ catch (Throwable e) {
+ fail("unexpected exception " + e.getStackTrace().toString());
+ }
+
+
+ }
+
+ @Test
public void testUtil() throws Exception
{
assertFalse(SecurityVaultUtil.isVaultFormat((String)null));
@@ -229,17 +360,119 @@
return new String(PicketBoxSecurityVault.PASS_MASK_PREFIX) + maskedPass;
}
- private Map<String,Object> getMap()
- {
- Map<String,Object> options = new HashMap<String,Object>();
- options.put(PicketBoxSecurityVault.KEYSTORE_URL, "src/test/resources/keystore/vault.keystore");
- options.put(PicketBoxSecurityVault.KEYSTORE_PASSWORD, maskedPWD);
- options.put(PicketBoxSecurityVault.KEYSTORE_ALIAS, "vault");
- options.put(PicketBoxSecurityVault.SALT, salt);
- options.put(PicketBoxSecurityVault.ITERATION_COUNT, "" + iterationCount);
- options.put(PicketBoxSecurityVault.ENC_FILE_DIR,dataDir);
-
+ private Map<String, Object> getVaultOptionsMap(String keystore, String encDataDir, String alias, String salz, int iter,
+ String password) throws Exception {
+ Map<String, Object> options = new HashMap<String, Object>();
+ options.put(PicketBoxSecurityVault.KEYSTORE_URL, keystore);
+ options.put(PicketBoxSecurityVault.KEYSTORE_PASSWORD, getMaskedPassword(password, salz, iter));
+ options.put(PicketBoxSecurityVault.KEYSTORE_ALIAS, alias);
+ options.put(PicketBoxSecurityVault.SALT, salz);
+ options.put(PicketBoxSecurityVault.ITERATION_COUNT, String.valueOf(iter));
+ options.put(PicketBoxSecurityVault.ENC_FILE_DIR, encDataDir);
return options;
}
+
+ public static void setInitialVaulConditions(String originalKeyStoreFile, String targetKeyStoreFile,
+ String originalVaultContentDir, String targetVaultContentDir) throws Exception {
+
+ File tKS = new File(targetKeyStoreFile);
+ File parent = tKS.getParentFile();
+ if (!parent.exists()) {
+ parent.mkdirs();
+ }
+ SecurityVaultUnitTestCase.copyFile(new File(originalKeyStoreFile), tKS);
+
+ File targetVaultContent = new File(targetVaultContentDir);
+ cleanDirectory(targetVaultContent);
+ File originVault = new File(originalVaultContentDir);
+ for (File f : originVault.listFiles()) {
+ SecurityVaultUnitTestCase.copyFile(f, new File(targetVaultContent.getAbsolutePath() + File.separator + f.getName()));
+ }
+ }
+
+ /**
+ * Make clean new directory.
+ *
+ * @param directory
+ */
+ public static void cleanDirectory(File directory) {
+ if (directory.exists()) {
+ for (File f: directory.listFiles()) { f.delete(); }
+ directory.delete();
+ }
+ directory.mkdirs();
+ }
+
+ /**
+ * Copy file method.
+ *
+ * @param sourceFile
+ * @param destFile
+ * @throws IOException
+ */
+ public static void copyFile(File sourceFile, File destFile) throws IOException {
+ if (!destFile.exists()) {
+ destFile.createNewFile();
+ }
+ FileInputStream fIn = null;
+ FileOutputStream fOut = null;
+ FileChannel source = null;
+ FileChannel destination = null;
+ try {
+ fIn = new FileInputStream(sourceFile);
+ source = fIn.getChannel();
+ fOut = new FileOutputStream(destFile);
+ destination = fOut.getChannel();
+ long transfered = 0;
+ long bytes = source.size();
+ while (transfered < bytes) {
+ transfered += destination.transferFrom(source, 0, source.size());
+ destination.position(transfered);
+ }
+ } finally {
+ if (source != null) {
+ source.close();
+ } else if (fIn != null) {
+ fIn.close();
+ }
+ if (destination != null) {
+ destination.close();
+ } else if (fOut != null) {
+ fOut.close();
+ }
+ }
+ }
+
+ static Class<?> loadClass(final Class<?> clazz, final String fqn) {
+ return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
+ public Class<?> run() {
+ ClassLoader cl = clazz.getClassLoader();
+ Class<?> loadedClass = null;
+ try {
+ loadedClass = cl.loadClass(fqn);
+ } catch (ClassNotFoundException e) {
+ }
+ return loadedClass;
+ }
+ });
+
+ }
+
+ private void assertSecretValue(SecurityVault vault, String vaultBlock, String attributeName, String expectedSecuredAttributeValue) throws SecurityVaultException {
+ assertEquals("Expected value has to match the one in vault. " + vaultBlock + ":" + attributeName + "=" + expectedSecuredAttributeValue,
+ new String(expectedSecuredAttributeValue),
+ new String(vault.retrieve(vaultBlock, attributeName, null)));
+ }
+
+ /**
+ * get new instance of vault to simulate restart of application server
+ * @return
+ * @throws Exception
+ */
+ private SecurityVault getNewSecurityVaultInstance() throws Exception {
+ Class<?> vaultClass = loadClass(SecurityVaultFactory.class, "org.picketbox.plugins.vault.PicketBoxSecurityVault");
+ return (SecurityVault)vaultClass.newInstance();
+ }
+
}
\ No newline at end of file
Copied: branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/resources/keystore/vault.jks (from rev 436, branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/test/resources/keystore/vault.jks)
===================================================================
(Binary files differ)
Deleted: branches/embargo/4.0.17.SP2/security-jboss-sx/jbosssx/src/test/resources/keystore/vault.keystore
===================================================================
(Binary files differ)
Modified: branches/embargo/4.0.17.SP2/security-spi/common/src/main/java/org/jboss/security/PicketBoxLogger.java
===================================================================
--- branches/embargo/4.0.17.SP2/security-spi/common/src/main/java/org/jboss/security/PicketBoxLogger.java 2013-07-30 15:43:11 UTC (rev 437)
+++ branches/embargo/4.0.17.SP2/security-spi/common/src/main/java/org/jboss/security/PicketBoxLogger.java 2013-07-30 15:49:30 UTC (rev 438)
@@ -688,4 +688,28 @@
@Message(id = 366, value = "Error parsing time out number.")
void errorParsingTimeoutNumber();
+ @LogMessage(level = Logger.Level.DEBUG)
+ @Message(id = 367, value = "Reading security vault data version %s target version is %s")
+ void securityVaultContentVersion(String dataVersion, String targetVersion);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 368, value = "Security Vault contains both covnerted (%s) and pre-conversion data (%s). Try to delete %s file and start over again.")
+ void mixedVaultDataFound(String vaultDatFile, String encDatFile, String encDatFile2);
+
+ @LogMessage(level = Logger.Level.INFO)
+ @Message(id = 369, value = "Ambiguos vault block and attribute name stored in original security vault. Delimiter (%s) is part of vault block or attribute name. Took the first delimiter. Result vault block (%s) attribute name (%s). Modify security vault manually.")
+ void ambiguosKeyForSecurityVaultTransformation(String delimiter, String vaultBlock, String attributeName);
+
+ @LogMessage(level = Logger.Level.WARN)
+ @Message(id = 370, value = "Cannot delete original security vault file (%s). Delete the file manually before next start, please.")
+ void cannotDeleteOriginalVaultFile(String file);
+
+ @LogMessage(level = Logger.Level.INFO)
+ @Message(id = 371, value = "Security Vault does not contain SecretKey entry under alias (%s)")
+ void vaultDoesnotContainSecretKey(String alias);
+
+ @LogMessage(level = Logger.Level.INFO)
+ @Message(id = 372, value = "Security Vault key store successfuly converted to JCEKS type (%s). From now on use JCEKS as KEYSTORE_TYPE in Security Vault configuration.")
+ void keyStoreConvertedToJCEKS(String keyStoreFile);
+
}
\ No newline at end of file
Modified: branches/embargo/4.0.17.SP2/security-spi/common/src/main/java/org/jboss/security/PicketBoxMessages.java
===================================================================
--- branches/embargo/4.0.17.SP2/security-spi/common/src/main/java/org/jboss/security/PicketBoxMessages.java 2013-07-30 15:43:11 UTC (rev 437)
+++ branches/embargo/4.0.17.SP2/security-spi/common/src/main/java/org/jboss/security/PicketBoxMessages.java 2013-07-30 15:49:30 UTC (rev 438)
@@ -424,8 +424,8 @@
@Message(id = 129, value = "Unable to write shared key file")
String unableToWriteShareKeyFileMessage();
- @Message(id = 130, value = "Unable to write encoded file")
- String unableToWriteEncodedFileMessage();
+ @Message(id = 130, value = "Unable to write vault data file (%s)")
+ String unableToWriteVaultDataFileMessage(String fileName);
@Message(id = 131, value = "Vault mismatch: shared key does not match for vault block %s and attribute name %s")
String sharedKeyMismatchMessage(String vaultBlock, String attributeName);
@@ -435,4 +435,25 @@
@Message(id = 133, value = "Failed to match %s and %s")
RuntimeException failedToMatchStrings(String one, String two);
+
+ @Message(id = 134, value = "Unrecognized security vault content version (%s), expecting (from %s to %s)")
+ RuntimeException unrecognizedVaultContentVersion(String readVersion, String fromVersion, String toVersion);
+
+ @Message(id = 135, value = "Security Vault contains both covnerted (%s) and pre-conversion data (%s), failed to load vault")
+ RuntimeException mixedVaultDataFound(String vaultDatFile, String encDatFile);
+
+ @Message(id = 136, value = "Security Vault conversion unsuccessful missing admin key in original vault data")
+ RuntimeException missingAdminKeyInOriginalVaultData();
+
+ @Message(id = 137, value = "Security Vault does not contain SecretKey entry under alias (%s)")
+ RuntimeException vaultDoesnotContainSecretKey(String alias);
+
+ @Message(id = 138, value = "There is no SecretKey under the alias (%s) and the alias is already used to denote diffrent crypto object in the keystore.")
+ RuntimeException noSecretKeyandAliasAlreadyUsed(String alias);
+
+ @Message(id = 139, value = "Unable to store keystore to file (%s)")
+ RuntimeException unableToStoreKeyStoreToFile(@Cause Throwable throwable, String file);
+
+ @Message(id = 140, value = "Unable to get keystore (%s)")
+ RuntimeException unableToGetKeyStore(@Cause Throwable throwable, String file);
}
\ No newline at end of file
More information about the jboss-cvs-commits
mailing list