[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