You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by tr...@apache.org on 2014/01/23 23:45:55 UTC

svn commit: r1560840 - in /jackrabbit/commons/filevault/trunk: vault-cli/src/main/java/org/apache/jackrabbit/vault/cli/ vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/ vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/

Author: tripod
Date: Thu Jan 23 22:45:55 2014
New Revision: 1560840

URL: http://svn.apache.org/r1560840
Log:
JCRVLT-26 File vault stores passwords in clear text in ~/.vault/auth.xml

- adding new option --update-credentials
- adding prompt for password if missing in --credentials
- avoid storing credentials if not explicitely indicated (except admin:admin)

Removed:
    jackrabbit/commons/filevault/trunk/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/DefaultCredentialsProvider.java
Modified:
    jackrabbit/commons/filevault/trunk/vault-cli/src/main/java/org/apache/jackrabbit/vault/cli/VaultFsApp.java
    jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/SimpleCredentialsConfig.java
    jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/VaultAuthConfig.java
    jackrabbit/commons/filevault/trunk/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/ConfigCredentialsProvider.java

Modified: jackrabbit/commons/filevault/trunk/vault-cli/src/main/java/org/apache/jackrabbit/vault/cli/VaultFsApp.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-cli/src/main/java/org/apache/jackrabbit/vault/cli/VaultFsApp.java?rev=1560840&r1=1560839&r2=1560840&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-cli/src/main/java/org/apache/jackrabbit/vault/cli/VaultFsApp.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-cli/src/main/java/org/apache/jackrabbit/vault/cli/VaultFsApp.java Thu Jan 23 22:45:55 2014
@@ -58,7 +58,7 @@ import org.apache.jackrabbit.vault.util.
 import org.apache.jackrabbit.vault.util.console.util.Log4JConfig;
 import org.apache.jackrabbit.vault.util.console.util.PomProperties;
 import org.apache.jackrabbit.vault.vlt.ConfigCredentialsProvider;
-import org.apache.jackrabbit.vault.vlt.DefaultCredentialsProvider;
+import org.apache.jackrabbit.vault.vlt.CredentialsProvider;
 import org.apache.jackrabbit.vault.vlt.VltContext;
 import org.apache.jackrabbit.vault.vlt.VltDirectory;
 import org.apache.jackrabbit.vault.vlt.meta.MetaDirectory;
@@ -92,8 +92,7 @@ public class VaultFsApp extends Abstract
 
     private RepositoryProvider repProvider;
 
-    private DefaultCredentialsProvider defCredsProvider;
-
+    private CredentialsProvider credentialsProvider;
     private ConfigCredentialsProvider confCredsProvider;
 
     private Repository rep;
@@ -107,6 +106,7 @@ public class VaultFsApp extends Abstract
     private Option optCreds;
     //private Option optMountpoint;
     private Option optConfig;
+    private Option optUpdateCreds;
 
     private ExtendedOption[] xOpts = new ExtendedOption[]{
             new XJcrLog(),
@@ -134,10 +134,10 @@ public class VaultFsApp extends Abstract
         try {
             // hack for setting the default credentials
             if (ctxRepository != null) {
-                defCredsProvider.setDefaultCredentials(getProperty(KEY_DEFAULT_CREDS));
+                confCredsProvider.setDefaultCredentials(getProperty(KEY_DEFAULT_CREDS));
             }
             File cwd = getPlatformFile("", true).getCanonicalFile();
-            return new VltContext(cwd, localFile, repProvider, confCredsProvider);
+            return new VltContext(cwd, localFile, repProvider, credentialsProvider);
         } catch (IOException e) {
             throw new ExecutionException(e);
         } catch (ConfigurationException e) {
@@ -463,8 +463,8 @@ public class VaultFsApp extends Abstract
 
         // init providers
         repProvider = new RepositoryProvider();
-        defCredsProvider = new DefaultCredentialsProvider();
-        confCredsProvider = new ConfigCredentialsProvider(defCredsProvider);
+        confCredsProvider = new ConfigCredentialsProvider();
+        credentialsProvider = new PasswordPromptingCredentialProvider(confCredsProvider);
 
         // setup default config
         setProperty(KEY_DEFAULT_CREDS, null);
@@ -544,12 +544,17 @@ public class VaultFsApp extends Abstract
                 .withLongName("credentials")
                 .withDescription("The default credentials to use")
                 .withArgument(new ArgumentBuilder()
-                        .withDescription("Format: <user:pass>. If missing an anoymous login is used")
+                        .withDescription("Format: <user:pass>. If missing an anonymous login is used. " +
+                                "If the password is not specified it is prompted via console.")
                         .withMinimum(0)
                         .withMaximum(1)
                         .create()
                 )
                 .create();
+        optUpdateCreds = new DefaultOptionBuilder()
+                .withLongName("update-credentials")
+                .withDescription("if present the credentials-to-host list is updated in the ~/.vault/auth.xml")
+                .create();
         /*
         optMountpoint = new DefaultOptionBuilder()
                 .withLongName("mountpoint")
@@ -580,6 +585,7 @@ public class VaultFsApp extends Abstract
         //gbuilder.withOption(optURI);
         //gbuilder.withOption(optWorkspace);
         gbuilder.withOption(optCreds);
+        gbuilder.withOption(optUpdateCreds);
         //gbuilder.withOption(optMountpoint);
         gbuilder.withOption(optConfig);
         return super.addApplicationOptions(gbuilder);
@@ -620,12 +626,43 @@ public class VaultFsApp extends Abstract
         if (cl.getValue(optCreds) != null) {
             String userPass = (String) cl.getValue(optCreds);
             setProperty(KEY_DEFAULT_CREDS, userPass);
-            confCredsProvider.setDefaultCredentials(userPass);
+            confCredsProvider.setCredentials(userPass);
+            confCredsProvider.setStoreEnabled(cl.hasOption(optUpdateCreds));
         }
         if (cl.getValue(optConfig) != null) {
             setProperty(KEY_DEFAULT_CONFIG_XML, (String) cl.getValue(optConfig));
         }
     }
 
+    private static class PasswordPromptingCredentialProvider implements CredentialsProvider {
+
+        private CredentialsProvider base;
+
+        private PasswordPromptingCredentialProvider(CredentialsProvider base) {
+            this.base = base;
+        }
+
+        public Credentials getCredentials(RepositoryAddress mountpoint) {
+            Credentials creds = base.getCredentials(mountpoint);
+            if (creds instanceof SimpleCredentials) {
+                try {
+                    SimpleCredentials simpleCredentials = (SimpleCredentials) creds;
+                    if (simpleCredentials.getPassword().length == 0) {
+                        System.out.printf("Please enter password for user %s connecting to %s: ",
+                                simpleCredentials.getUserID(), mountpoint);
+                        String password = new jline.ConsoleReader().readLine('*');
+                        creds = new SimpleCredentials(simpleCredentials.getUserID(), password.toCharArray());
+                    }
+                } catch (IOException e) {
+                    log.error("Error while opening console for reading password" + e);
+                }
+            }
+            return creds;
+        }
+
+        public void storeCredentials(RepositoryAddress mountpoint, Credentials creds) {
+            base.storeCredentials(mountpoint, creds);
+        }
+    }
 
 }

Modified: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/SimpleCredentialsConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/SimpleCredentialsConfig.java?rev=1560840&r1=1560839&r2=1560840&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/SimpleCredentialsConfig.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/SimpleCredentialsConfig.java Thu Jan 23 22:45:55 2014
@@ -17,9 +17,18 @@
 
 package org.apache.jackrabbit.vault.fs.config;
 
+import java.io.ByteArrayOutputStream;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
 import javax.jcr.Credentials;
 import javax.jcr.SimpleCredentials;
 
+import org.apache.jackrabbit.vault.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -33,6 +42,21 @@ import org.xml.sax.helpers.AttributesImp
 */
 public class SimpleCredentialsConfig extends CredentialsConfig {
 
+    /**
+     * key length
+     */
+    private final static int KEY_LENGTH = 8;
+
+    /**
+     * encryption prefix
+     */
+    private final static String PREFIX = "{DES}";
+
+    /**
+     * default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(SimpleCredentialsConfig.class);
+
     private final SimpleCredentials creds;
     public static final String ELEM_USER = "user";
     public static final String ATTR_NAME = "name";
@@ -57,7 +81,7 @@ public class SimpleCredentialsConfig ext
                 if (child.getNodeName().equals(ELEM_USER)) {
                     Element e = (Element) child;
                     String name = e.getAttribute(ATTR_NAME);
-                    String pass = e.getAttribute(ATTR_PASSWORD);
+                    String pass = decrypt(e.getAttribute(ATTR_PASSWORD));
                     return new SimpleCredentialsConfig(
                             new SimpleCredentials(
                                     name,
@@ -72,9 +96,67 @@ public class SimpleCredentialsConfig ext
         if (creds != null) {
             AttributesImpl attrs = new AttributesImpl();
             attrs.addAttribute("", ATTR_NAME, "", "CDATA", creds.getUserID());
-            attrs.addAttribute("", ATTR_PASSWORD, "", "CDATA", new String(creds.getPassword()));
+            attrs.addAttribute("", ATTR_PASSWORD, "", "CDATA", encrypt(new String(creds.getPassword())));
             handler.startElement("", ELEM_USER, "", attrs);
             handler.endElement("", ELEM_USER, "");
         }
     }
+
+    /**
+     * Encrypts the given string in a fairly secure way so that it can be
+     * {@link #decrypt(String) decrypted} again.
+     *
+     * @param s string to encrypt
+     * @return the encrypted string with a "{AES}" prefix.
+     */
+    private static String encrypt(String s) {
+        try {
+            SecretKey key = KeyGenerator.getInstance("DES").generateKey();
+            Cipher cipher = Cipher.getInstance("DES");
+            byte[] keyBytes = key.getEncoded();
+            byte[] data = s.getBytes("utf-8");
+            ByteArrayOutputStream out = new ByteArrayOutputStream(keyBytes.length + data.length);
+            out.write(keyBytes);
+            cipher.init(Cipher.ENCRYPT_MODE, key);
+            out.write(cipher.update(data));
+            out.write(cipher.doFinal());
+            StringBuilder ret = new StringBuilder(PREFIX);
+            for (byte b: out.toByteArray()) {
+                ret.append(Text.hexTable[b>>4 & 0x0f]).append(Text.hexTable[b&0x0f]);
+            }
+            return ret.toString();
+        } catch (Exception e) {
+            log.warn("Unable to encrypt string: " + e);
+            return null;
+        }
+    }
+
+    /**
+     * Decrypts a string that was previously {@link #encrypt(String)} encrypted}.
+     *
+     * @param s the data to decrypt
+     * @return the string or <code>null</code> if an internal error occurred
+     */
+    private static String decrypt(String s) {
+        if (s == null || !s.startsWith(PREFIX)) {
+            return s;
+        }
+        try {
+            byte[] data = new byte[(s.length() - PREFIX.length())/2];
+            for (int i=PREFIX.length(),b=0; i<s.length(); i+=2, b++) {
+                data[b] = (byte) (Integer.parseInt(s.substring(i, i+2), 16) &0xff);
+            }
+            SecretKeySpec key = new SecretKeySpec(data, 0, KEY_LENGTH, "DES");
+            Cipher cipher = Cipher.getInstance("DES");
+            ByteArrayOutputStream out = new ByteArrayOutputStream(data.length);
+            cipher.init(Cipher.DECRYPT_MODE, key);
+            out.write(cipher.update(data, KEY_LENGTH, data.length - KEY_LENGTH));
+            out.write(cipher.doFinal());
+            return out.toString("utf-8");
+        } catch (Exception e) {
+            log.warn("Unable to decrypt data: " + e);
+            return null;
+        }
+    }
+
 }
\ No newline at end of file

Modified: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/VaultAuthConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/VaultAuthConfig.java?rev=1560840&r1=1560839&r2=1560840&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/VaultAuthConfig.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/VaultAuthConfig.java Thu Jan 23 22:45:55 2014
@@ -82,7 +82,11 @@ public class VaultAuthConfig extends Abs
     }
 
     public void save() throws IOException {
-        save(new File(getConfigDir(), Constants.AUTH_XML));
+        save(getConfigFile());
+    }
+
+    public File getConfigFile() throws IOException {
+        return new File(getConfigDir(), Constants.AUTH_XML);
     }
 
     public static class RepositoryConfig {
@@ -116,9 +120,9 @@ public class VaultAuthConfig extends Abs
                 Node child = nl.item(i);
                 if (child.getNodeType() == Node.ELEMENT_NODE) {
                     if (child.getNodeName().equals(CredentialsConfig.ELEM_CREDETIALS)) {
-                        CredentialsConfig ccfg = CredentialsConfig.load((Element) child);
-                        if (ccfg != null) {
-                            cfg.creds = ccfg;
+                        CredentialsConfig credentialsConfig = CredentialsConfig.load((Element) child);
+                        if (credentialsConfig != null) {
+                            cfg.creds = credentialsConfig;
                         }
                     } else {
                         throw new ConfigurationException("unexpected element: " + child.getLocalName());

Modified: jackrabbit/commons/filevault/trunk/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/ConfigCredentialsProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/ConfigCredentialsProvider.java?rev=1560840&r1=1560839&r2=1560840&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/ConfigCredentialsProvider.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/ConfigCredentialsProvider.java Thu Jan 23 22:45:55 2014
@@ -32,14 +32,19 @@ import org.slf4j.LoggerFactory;
  * <code>CredentialsProvider</code>...
  *
  */
-public class ConfigCredentialsProvider extends DefaultCredentialsProvider {
+public class ConfigCredentialsProvider implements CredentialsProvider {
 
     protected static Logger log = LoggerFactory.getLogger(ConfigCredentialsProvider.class);
 
     private VaultAuthConfig config;
 
-    public ConfigCredentialsProvider(CredentialsProvider base) {
-        super(base);
+    private Credentials defaultCreds;
+
+    private Credentials credentials;
+
+    private boolean storeEnabled;
+
+    public ConfigCredentialsProvider() {
         config = new VaultAuthConfig();
         try {
             config.load();
@@ -50,21 +55,38 @@ public class ConfigCredentialsProvider e
         }
     }
 
+    public void setDefaultCredentials(String userPass) {
+        this.defaultCreds = fromUserPass(userPass);
+    }
+
+    public void setCredentials(String userPass) {
+        this.credentials = fromUserPass(userPass);
+    }
+
+    private static Credentials fromUserPass(String userPass) {
+        if (userPass != null) {
+            int idx = userPass.indexOf(':');
+            if (idx > 0) {
+                return new SimpleCredentials(userPass.substring(0, idx), userPass.substring(idx + 1).toCharArray());
+            } else {
+                return new SimpleCredentials(userPass, new char[0]);
+            }
+        }
+        return null;
+    }
+
     public Credentials getCredentials(RepositoryAddress mountpoint) {
-        // check if temporary creds are set
-        if (super.getCredentials(mountpoint) != null) {
-            return super.getCredentials(mountpoint);
+        if (credentials != null) {
+            return credentials;
         }
         Credentials creds = fetchCredentials(mountpoint);
         return creds == null
-                ? super.getCredentials(mountpoint)
+                ? defaultCreds
                 : creds;
     }
 
     private Credentials fetchCredentials(RepositoryAddress mountpoint) {
-        VaultAuthConfig.RepositoryConfig cfg = config.getRepoConfig(
-                getLookupId(mountpoint)
-        );
+        VaultAuthConfig.RepositoryConfig cfg = config.getRepoConfig(getLookupId(mountpoint));
         if (cfg == null) {
             return null;
         }
@@ -82,15 +104,28 @@ public class ConfigCredentialsProvider e
             }
             return;
         }
-        VaultAuthConfig.RepositoryConfig cfg  = new VaultAuthConfig.RepositoryConfig(
-                getLookupId(mountpoint)
-        );
-        cfg.addCredsConfig(new SimpleCredentialsConfig(((SimpleCredentials) creds)));
-        config.addRepositoryConfig(cfg);
-        try {
-            config.save();
-        } catch (IOException e) {
-            log.error("Error while saving auth configuration: {} ", e.toString());
+        Credentials currentCreds = fetchCredentials(mountpoint);
+        if (creds.equals(currentCreds)) {
+            // don't update if already stored
+            return;
         }
+
+        SimpleCredentials simpleCredentials = (SimpleCredentials) creds;
+        if (storeEnabled ||
+                "admin".equals(simpleCredentials.getUserID()) && "admin".equals(new String(simpleCredentials.getPassword()))) {
+            VaultAuthConfig.RepositoryConfig cfg  = new VaultAuthConfig.RepositoryConfig(getLookupId(mountpoint));
+            cfg.addCredsConfig(new SimpleCredentialsConfig(simpleCredentials));
+            config.addRepositoryConfig(cfg);
+            try {
+                config.save();
+                log.warn("Credentials for {} updated in {}.", mountpoint, config.getConfigFile().getPath());
+            } catch (IOException e) {
+                log.error("Error while saving auth configuration: {} ", e.toString());
+            }
+        }
+    }
+
+    public void setStoreEnabled(boolean storeEnabled) {
+        this.storeEnabled = storeEnabled;
     }
 }
\ No newline at end of file