[jboss-cvs] Picketbox SVN: r409 - in branches/embargo/4.0.16.Final-vault: security-jboss-sx/jbosssx/src/main/java/org/picketbox/util and 1 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Thu Apr 18 08:10:12 EDT 2013
Author: pskopek
Date: 2013-04-18 08:10:11 -0400 (Thu, 18 Apr 2013)
New Revision: 409
Added:
branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/SecurityVaultData.java
Modified:
branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/PicketBoxSecurityVault.java
branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/EncryptionUtil.java
branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/KeyStoreUtil.java
branches/embargo/4.0.16.Final-vault/security-spi/common/src/main/java/org/jboss/security/PicketBoxLogger.java
branches/embargo/4.0.16.Final-vault/security-spi/common/src/main/java/org/jboss/security/PicketBoxMessages.java
Log:
Security Vault implementation change to use JCEKS as SecretKey storage.
Modified: branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/PicketBoxSecurityVault.java
===================================================================
--- branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/PicketBoxSecurityVault.java 2013-04-17 15:57:40 UTC (rev 408)
+++ branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/PicketBoxSecurityVault.java 2013-04-18 12:10:11 UTC (rev 409)
@@ -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,13 +36,21 @@
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.Map;
import java.util.Set;
-import java.util.UUID;
+import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -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,26 @@
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));
-
- if(!(decodedEncFileDir.endsWith("/") || decodedEncFileDir.endsWith("\\")))
- {
- throw new SecurityVaultException(PicketBoxMessages.MESSAGES.invalidDirectoryFormatMessage(decodedEncFileDir));
- }
- if(encodedFileExists(decodedEncFileDir) ==false)
- {
- setUpVault(decodedEncFileDir);
- }
-
- 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);
- }
- finally
- {
- safeClose(fis);
- safeClose(mapFile);
- safeClose(ois);
- safeClose(mapIS);
- }
-
- try
- {
+ 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)
- {
+ keystore = getKeyStore(keystoreURL);
+ } 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 +209,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.getVaultData().keySet();
+ }
/*
* @see org.jboss.security.vault.SecurityVault#store(java.lang.String, java.lang.String, char[], byte[])
@@ -273,60 +231,28 @@
if(StringUtil.isNullOrEmpty(attributeName))
throw PicketBoxMessages.MESSAGES.invalidNullArgument("attributeName");
- String mapKey = vaultBlock + "_" + attributeName;
+ vaultContent.getVaultData().put(dataKey(vaultBlock, attributeName), sharedKey);
- 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.getVaultData().put(dataKey(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 +265,25 @@
if(StringUtil.isNullOrEmpty(attributeName))
throw PicketBoxMessages.MESSAGES.invalidNullArgument("attributeName");
- String mapKey = vaultBlock + "_" + attributeName;
- byte[] encryptedValue = theContent.get(mapKey);
+ byte[] encryptedValue = vaultContent.getVaultData().get(dataKey(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().get(dataKey(vaultBlock, attributeName)) != null;
}
/*
@@ -377,13 +292,10 @@
public boolean remove(String vaultBlock, String attributeName, byte[] sharedKey)
throws SecurityVaultException
{
- String mapKey = vaultBlock + "_" + attributeName;
- try
- {
- theContent.remove(mapKey);
+ try {
+ vaultContent.getVaultData().remove(dataKey(vaultBlock, attributeName));
}
- catch(Exception e)
- {
+ catch(Exception e) {
return false;
}
return true;
@@ -410,26 +322,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(new ConcurrentHashMap<String, byte[]>());
+ 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 +367,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 +404,248 @@
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);
+ }
+
+ Map<String, byte[]> newVault = new ConcurrentHashMap<String, byte[]>();
+
+ 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);
+ newVault.put(dataKey(vaultBlock, attributeName), encodedAttributeValue);
+ }
+ }
+ }
+ if (adminKey == null) {
+ throw PicketBoxMessages.MESSAGES.missingAdminKeyInOriginalVaultData();
+ }
+
+ // create new transformed vault data
+ vaultContent = new SecurityVaultData(newVault);
+
+ // convert keystore to JCEKS format
+ convertKeyStoreToJCEKS();
+
+ // add secret key (admin_key) to keystore
+ KeyStore.SecretKeyEntry skEntry = new KeyStore.SecretKeyEntry(adminKey);
+ keystore.setEntry(alias, skEntry, new KeyStore.PasswordProtection(keyStorePWD));
+
+ // backup original keystore file
+ copyFile(new File(keystoreURL), new File(keystoreURL + ".original"));
+ // save the current keystore
+ saveKeyStoreToFile(keystoreURL);
+
+ // backup original vault files
+ copyFile(new File(decodedEncFileDir + ENCODED_FILE), new File(decodedEncFileDir + ENCODED_FILE + ".original"));
+ copyFile(new File(decodedEncFileDir + SHARED_KEY_FILE), new File(decodedEncFileDir + SHARED_KEY_FILE + ".original"));
+
+ // 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 convertKeyStoreToJCEKS() throws Exception {
+ if (keystore.getType().equalsIgnoreCase("JKS")) {
+ createKeyStore("JCEKS");
+ }
+ }
+
+ private KeyStore createKeyStore(String keyStoreType) throws Exception {
+ KeyStore ks = KeyStore.getInstance(keyStoreType);
+ ks.load(null, keyStorePWD);
+ return ks;
+ }
+
+ /**
+ * Creates new format for data key in vault. All parameters has to be non-null.
+ *
+ * @param vaultBlock
+ * @param attributeName
+ * @param alias
+ * @return
+ */
+ public static String dataKey(String vaultBlock, String attributeName) {
+ return vaultBlock + StringUtil.PROPERTY_DEFAULT_SEPARATOR + attributeName;
+ }
+
+ 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 createKeyStore(keyStoreType);
+ }
+ }
+ catch (Throwable e) {
+ throw PicketBoxMessages.MESSAGES.unableToGetKeyStore(e, keystoreURL);
+ }
+
+ return null;
+ }
+
}
\ No newline at end of file
Added: branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/SecurityVaultData.java
===================================================================
--- branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/SecurityVaultData.java (rev 0)
+++ branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/plugins/vault/SecurityVaultData.java 2013-04-18 12:10:11 UTC (rev 409)
@@ -0,0 +1,100 @@
+/*
+ * 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.concurrent.ConcurrentHashMap;
+
+import org.jboss.security.PicketBoxLogger;
+import org.jboss.security.PicketBoxMessages;
+
+/**
+ * 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[]>();
+
+ /**
+ * Constructor which fills the vault data.
+ * @param vaultData
+ */
+ public SecurityVaultData(Map<String, byte[]> vaultData) {
+ this.vaultData = vaultData;
+ }
+
+ /**
+ * Default constructor for serialization purpose.
+ * @param vaultData
+ */
+ public SecurityVaultData() {
+ }
+
+ private void writeObject(ObjectOutputStream oos) throws IOException {
+ oos.writeObject(new Integer(VERSION));
+ oos.writeObject(vaultData);
+ }
+
+ @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));
+ }
+ }
+
+ /**
+ * Returns vault data internal store.
+ *
+ * @return
+ */
+ public Map<String, byte[]> getVaultData() {
+ return vaultData;
+ }
+
+}
Modified: branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/EncryptionUtil.java
===================================================================
--- branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/EncryptionUtil.java 2013-04-17 15:57:40 UTC (rev 408)
+++ branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/EncryptionUtil.java 2013-04-18 12:10:11 UTC (rev 409)
@@ -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.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/KeyStoreUtil.java
===================================================================
--- branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/KeyStoreUtil.java 2013-04-17 15:57:40 UTC (rev 408)
+++ branches/embargo/4.0.16.Final-vault/security-jboss-sx/jbosssx/src/main/java/org/picketbox/util/KeyStoreUtil.java 2013-04-18 12:10:11 UTC (rev 409)
@@ -59,11 +59,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 +129,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 +146,7 @@
try
{
fis = new FileInputStream(file);
- return getKeyStore(fis, storePass);
+ return getKeyStore(keyStoreType, fis, storePass);
}
finally
{
@@ -99,13 +156,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 +172,7 @@
try
{
is = url.openStream();
- return getKeyStore(is, storePass);
+ return getKeyStore(keyStoreType, is, storePass);
}
finally
{
@@ -125,6 +183,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 +191,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 +257,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 +316,7 @@
}
return null;
}
+
private static void safeClose(InputStream fis)
{
Modified: branches/embargo/4.0.16.Final-vault/security-spi/common/src/main/java/org/jboss/security/PicketBoxLogger.java
===================================================================
--- branches/embargo/4.0.16.Final-vault/security-spi/common/src/main/java/org/jboss/security/PicketBoxLogger.java 2013-04-17 15:57:40 UTC (rev 408)
+++ branches/embargo/4.0.16.Final-vault/security-spi/common/src/main/java/org/jboss/security/PicketBoxLogger.java 2013-04-18 12:10:11 UTC (rev 409)
@@ -688,4 +688,25 @@
@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);
+
+
}
\ No newline at end of file
Modified: branches/embargo/4.0.16.Final-vault/security-spi/common/src/main/java/org/jboss/security/PicketBoxMessages.java
===================================================================
--- branches/embargo/4.0.16.Final-vault/security-spi/common/src/main/java/org/jboss/security/PicketBoxMessages.java 2013-04-17 15:57:40 UTC (rev 408)
+++ branches/embargo/4.0.16.Final-vault/security-spi/common/src/main/java/org/jboss/security/PicketBoxMessages.java 2013-04-18 12:10:11 UTC (rev 409)
@@ -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