Repository: logging-log4j2
Updated Branches:
  refs/heads/master a73fce2e7 -> 08077cba3


LOG4J2-2054 Provide ways to configure SSL that avoid plain-text passwords in 
the log4j configuration. The configuration may now specify a system environment 
variable that holds the password, or the path to a file that holds the password.


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/08077cba
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/08077cba
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/08077cba

Branch: refs/heads/master
Commit: 08077cba385ee376aa44ae33c66833421e9d19bc
Parents: a73fce2
Author: rpopma <[email protected]>
Authored: Tue Sep 26 01:00:15 2017 +0900
Committer: rpopma <[email protected]>
Committed: Tue Sep 26 01:00:15 2017 +0900

----------------------------------------------------------------------
 .../net/ssl/EnvironmentPasswordProvider.java    |  54 ++++++
 .../core/net/ssl/FilePasswordProvider.java      |  83 +++++++++
 .../core/net/ssl/KeyStoreConfiguration.java     |  58 +++++--
 .../core/net/ssl/MemoryPasswordProvider.java    |  20 ++-
 .../core/net/ssl/TrustStoreConfiguration.java   |  57 ++++--
 .../log4j/core/appender/HttpAppenderTest.java   |   6 +-
 .../SecureSocketAppenderSocketOptionsTest.java  |   8 +-
 .../core/appender/TlsSyslogAppenderTest.java    |   4 +-
 .../ssl/EnvironmentPasswordProviderTest.java    |  38 ++++
 .../core/net/ssl/FilePasswordProviderTest.java  |  50 ++++++
 .../core/net/ssl/KeyStoreConfigurationTest.java |   8 +-
 .../net/ssl/MemoryPasswordProviderTest.java     |  49 ++++++
 .../core/net/ssl/SslConfigurationTest.java      |  16 +-
 .../log4j/core/net/ssl/TestConstants.java       |  10 +-
 .../net/ssl/TrustStoreConfigurationTest.java    |   8 +-
 src/changes/changes.xml                         |   3 +
 src/site/site.xml                               |   1 +
 src/site/xdoc/manual/appenders.xml              | 172 +++++++++++++++++--
 18 files changed, 580 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProvider.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProvider.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProvider.java
new file mode 100644
index 0000000..e501c15
--- /dev/null
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProvider.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.net.ssl;
+
+import java.util.Objects;
+
+/**
+ * PasswordProvider implementation that obtains the password value from a 
system environment variable.
+ * <p>
+ * This implementation is not very secure because the Java interface to obtain 
system environment variable values
+ * requires us to use String objects. String objects are immutable and Java 
does not provide a way to erase this
+ * sensitive data from the application memory. The password data will stay 
resident in memory until the String object
+ * and its associated char[] array object are garbage collected and the memory 
is overwritten by another object.
+ * </p><p>
+ * This is slightly more secure than {@link MemoryPasswordProvider} because 
the actual password string is not pulled
+ * into memory until it is needed (so the password string does not need to be 
passed in from the command line or in a
+ * configuration file).
+ * This gives an attacker a smaller window  of opportunity to obtain the 
password from a memory dump.
+ * </p><p>
+ * A more secure implementation is {@link FilePasswordProvider}.
+ * </p>
+ */
+class EnvironmentPasswordProvider implements PasswordProvider {
+    private final String passwordEnvironmentVariable;
+
+    /**
+     * Constructs a new EnvironmentPasswordProvider with the specified 
environment variable name
+     * @param passwordEnvironmentVariable name of the system environment 
variable that holds the password
+     */
+    public EnvironmentPasswordProvider(final String 
passwordEnvironmentVariable) {
+        this.passwordEnvironmentVariable = Objects.requireNonNull(
+                passwordEnvironmentVariable, "passwordEnvironmentVariable");
+    }
+
+    @Override
+    public char[] getPassword() {
+        String password = System.getenv(passwordEnvironmentVariable);
+        return password.toCharArray();
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProvider.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProvider.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProvider.java
new file mode 100644
index 0000000..ff59b00
--- /dev/null
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProvider.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.net.ssl;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+/**
+ * PasswordProvider that reads password from a file.
+ * <p>
+ * This is a relatively secure way to handle passwords:
+ * <ul>
+ *     <li>Managing file access privileges can be delegated to the operating 
system.</li>
+ *     <li>The password file can be in a separate location from the logging 
configuration.
+ *       This gives flexibility to have different passwords in different 
environments while
+ *       using the same logging configuration. It also allows for separation 
of responsibilities:
+ *       developers don't need to know the password that is used in the 
production environment.</li>
+ *     <li>There is only a small window of opportunity for attackers to obtain 
the password from a memory
+ *       dump: the password data is only resident in memory from the moment 
the caller calls the
+ *       {@link #getPassword()} method and the password file is read until the 
moment that the caller
+ *       completes authentication and overwrites the password char[] 
array.</li>
+ * </ul>
+ * </p><p>
+ * Less secure implementations are {@link MemoryPasswordProvider} and {@link 
EnvironmentPasswordProvider}.
+ * </p>
+ */
+class FilePasswordProvider implements PasswordProvider {
+    private final Path passwordPath;
+
+    /**
+     * Constructs a new FilePasswordProvider with the specified path.
+     * @param passwordFile the path to the password file
+     * @throws NoSuchFileException if the password file does not exist when 
this FilePasswordProvider is constructed
+     */
+    public FilePasswordProvider(final String passwordFile) throws 
NoSuchFileException {
+        this.passwordPath = Paths.get(passwordFile);
+        if (!Files.exists(passwordPath)) {
+            throw new NoSuchFileException("PasswordFile '" + passwordFile + "' 
does not exist");
+        }
+    }
+
+    @Override
+    public char[] getPassword() {
+        byte[] bytes = null;
+        try {
+            bytes = Files.readAllBytes(passwordPath);
+            ByteBuffer bb = ByteBuffer.wrap(bytes);
+            CharBuffer decoded = Charset.defaultCharset().decode(bb);
+            char[] result = new char[decoded.limit()];
+            decoded.get(result, 0, result.length);
+            decoded.rewind();
+            decoded.put(new char[result.length]); // erase decoded CharBuffer
+            return result;
+        } catch (IOException e) {
+            throw new IllegalStateException("Could not read password from " + 
passwordPath + ": " + e, e);
+        } finally {
+            if (bytes != null) {
+                Arrays.fill(bytes, (byte) 0x0);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java
index 3fc37bd..d0c7bb0 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java
@@ -59,6 +59,9 @@ public class KeyStoreConfiguration extends 
AbstractKeyStoreConfiguration {
                                  final String keyStoreType,
                                  final String keyManagerFactoryAlgorithm) 
throws StoreConfigurationException {
         this(location, new MemoryPasswordProvider(password), keyStoreType, 
keyManagerFactoryAlgorithm);
+        if (password != null) {
+            Arrays.fill(password, '\0');
+        }
     }
 
     /**
@@ -92,24 +95,54 @@ public class KeyStoreConfiguration extends 
AbstractKeyStoreConfiguration {
             // @formatter:off
             @PluginAttribute("location") final String location,
             @PluginAttribute(value = "password", sensitive = true) final 
char[] password,
+            @PluginAttribute("passwordEnvironmentVariable") final String 
passwordEnvironmentVariable,
+            @PluginAttribute("passwordFile") final String passwordFile,
             @PluginAttribute("type") final String keyStoreType,
             @PluginAttribute("keyManagerFactoryAlgorithm") final String 
keyManagerFactoryAlgorithm) throws StoreConfigurationException {
             // @formatter:on
-        return new KeyStoreConfiguration(location, new 
MemoryPasswordProvider(password), keyStoreType,
-                keyManagerFactoryAlgorithm);
+
+        if (password != null && passwordEnvironmentVariable != null && 
passwordFile != null) {
+            throw new StoreConfigurationException("You MUST set only one of 
'password', 'passwordEnvironmentVariable' or 'passwordFile'.");
+        }
+        try {
+            // @formatter:off
+            PasswordProvider provider = passwordFile != null
+                    ? new FilePasswordProvider(passwordFile)
+                    : passwordEnvironmentVariable != null
+                            ? new 
EnvironmentPasswordProvider(passwordEnvironmentVariable)
+                            // the default is memory char[] array, which may 
be null
+                            : new MemoryPasswordProvider(password);
+            // @formatter:on
+            if (password != null) {
+                Arrays.fill(password, '\0');
+            }
+            return new KeyStoreConfiguration(location, provider, keyStoreType, 
keyManagerFactoryAlgorithm);
+        } catch (Exception ex) {
+            throw new StoreConfigurationException("Could not configure 
KeyStore", ex);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #createKeyStoreConfiguration(String, char[], 
String, String, String, String)}
+     */
+    public static KeyStoreConfiguration createKeyStoreConfiguration(
+            // @formatter:off
+            final String location,
+            final char[] password,
+            final String keyStoreType,
+            final String keyManagerFactoryAlgorithm) throws 
StoreConfigurationException {
+            // @formatter:on
+        return createKeyStoreConfiguration(location, password, null, null, 
keyStoreType, keyManagerFactoryAlgorithm);
     }
 
     /**
      * Creates a KeyStoreConfiguration.
      *
-     * @param location
-     *        The location of the KeyStore, a file path, URL or resource.
-     * @param password
-     *        The password to access the KeyStore.
-     * @param keyStoreType
-     *        The KeyStore type, null defaults to {@code "JKS"}.
-     * @param keyManagerFactoryAlgorithm
-     *         The standard name of the requested algorithm. See the Java 
Secure Socket Extension Reference Guide for information about these names.
+     * @param location The location of the KeyStore, a file path, URL or 
resource.
+     * @param password The password to access the KeyStore.
+     * @param keyStoreType The KeyStore type, null defaults to {@code "JKS"}.
+     * @param keyManagerFactoryAlgorithm The standard name of the requested 
algorithm. See the Java Secure Socket
+     * Extension Reference Guide for information about these names.
      * @return a new KeyStoreConfiguration
      * @throws StoreConfigurationException Thrown if this call cannot load the 
KeyStore.
      * @deprecated Use createKeyStoreConfiguration(String, char[], String, 
String)
@@ -122,8 +155,9 @@ public class KeyStoreConfiguration extends 
AbstractKeyStoreConfiguration {
             final String keyStoreType,
             final String keyManagerFactoryAlgorithm) throws 
StoreConfigurationException {
             // @formatter:on
-        return new KeyStoreConfiguration(location,
-                new MemoryPasswordProvider(password == null ? null : 
password.toCharArray()), keyStoreType,
+        return createKeyStoreConfiguration(location,
+                (password == null ? null : password.toCharArray()),
+                keyStoreType,
                 keyManagerFactoryAlgorithm);
     }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProvider.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProvider.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProvider.java
index 328728d..6fd7ab4 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProvider.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProvider.java
@@ -16,14 +16,26 @@
  */
 package org.apache.logging.log4j.core.net.ssl;
 
+import java.util.Arrays;
+
 /**
- * Simple (and not very secure) PasswordProvider implementation that keeps the 
password char[] array in memory.
+ * Simple PasswordProvider implementation that keeps the password char[] array 
in memory.
+ * <p>
+ * This implementation is not very secure because the password data is 
resident in memory during the life of this
+ * provider object, giving attackers a large window of opportunity to obtain 
the password from a memory dump.
+ * A slightly more secure implementation is {@link 
EnvironmentPasswordProvider},
+ * and an even more secure implementation is {@link FilePasswordProvider}.
+ * </p>
  */
 class MemoryPasswordProvider implements PasswordProvider {
     private final char[] password;
 
     public MemoryPasswordProvider(final char[] chars) {
-        password = chars;
+        if (chars != null) {
+            password = chars.clone();
+        } else {
+            password = null;
+        }
     }
 
     @Override
@@ -33,4 +45,8 @@ class MemoryPasswordProvider implements PasswordProvider {
         }
         return password.clone();
     }
+
+    public void clearSecrets() {
+        Arrays.fill(password, '\0');
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java
index c472186..d884aed 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.net.ssl;
 
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
 
 import javax.net.ssl.TrustManagerFactory;
 
@@ -50,6 +51,9 @@ public class TrustStoreConfiguration extends 
AbstractKeyStoreConfiguration {
     public TrustStoreConfiguration(final String location, final char[] 
password, final String keyStoreType,
             final String trustManagerFactoryAlgorithm) throws 
StoreConfigurationException {
         this(location, new MemoryPasswordProvider(password), keyStoreType, 
trustManagerFactoryAlgorithm);
+        if (password != null) {
+            Arrays.fill(password, '\0');
+        }
     }
 
     /**
@@ -81,24 +85,54 @@ public class TrustStoreConfiguration extends 
AbstractKeyStoreConfiguration {
             // @formatter:off
             @PluginAttribute("location") final String location,
             @PluginAttribute(value = "password", sensitive = true) final 
char[] password,
+            @PluginAttribute("passwordEnvironmentVariable") final String 
passwordEnvironmentVariable,
+            @PluginAttribute("passwordFile") final String passwordFile,
             @PluginAttribute("type") final String keyStoreType,
             @PluginAttribute("trustManagerFactoryAlgorithm") final String 
trustManagerFactoryAlgorithm) throws StoreConfigurationException {
             // @formatter:on
-        return new TrustStoreConfiguration(location, new 
MemoryPasswordProvider(password), keyStoreType,
-                trustManagerFactoryAlgorithm);
+
+        if (password != null && passwordEnvironmentVariable != null && 
passwordFile != null) {
+            throw new IllegalStateException("You MUST set only one of 
'password', 'passwordEnvironmentVariable' or 'passwordFile'.");
+        }
+        try {
+            // @formatter:off
+            PasswordProvider provider = passwordFile != null
+                    ? new FilePasswordProvider(passwordFile)
+                    : passwordEnvironmentVariable != null
+                            ? new 
EnvironmentPasswordProvider(passwordEnvironmentVariable)
+                            // the default is memory char[] array, which may 
be null
+                            : new MemoryPasswordProvider(password);
+            // @formatter:on
+            if (password != null) {
+                Arrays.fill(password, '\0');
+            }
+            return new TrustStoreConfiguration(location, provider, 
keyStoreType, trustManagerFactoryAlgorithm);
+        } catch (Exception ex) {
+            throw new StoreConfigurationException("Could not configure 
TrustStore", ex);
+        }
+    }
+
+    /**
+     * @deprecated Use {@link #createKeyStoreConfiguration(String, char[], 
String, String, String, String)}
+     */
+    public static TrustStoreConfiguration createKeyStoreConfiguration(
+            // @formatter:off
+            final String location,
+            final char[] password,
+            final String keyStoreType,
+            final String trustManagerFactoryAlgorithm) throws 
StoreConfigurationException {
+        // @formatter:on
+        return createKeyStoreConfiguration(location, password, null, null, 
keyStoreType, trustManagerFactoryAlgorithm);
     }
 
     /**
      * Creates a KeyStoreConfiguration.
      *
-     * @param location
-     *        The location of the KeyStore, a file path, URL or resource.
-     * @param password
-     *        The password to access the KeyStore.
-     * @param keyStoreType
-     *        The KeyStore type, null defaults to {@code "JKS"}.
-     * @param trustManagerFactoryAlgorithm
-     *        The standard name of the requested trust management algorithm. 
See the Java Secure Socket Extension Reference Guide for information these 
names.
+     * @param location The location of the KeyStore, a file path, URL or 
resource.
+     * @param password The password to access the KeyStore.
+     * @param keyStoreType The KeyStore type, null defaults to {@code "JKS"}.
+     * @param trustManagerFactoryAlgorithm The standard name of the requested 
trust management algorithm. See the Java
+     * Secure Socket Extension Reference Guide for information these names.
      * @return a new TrustStoreConfiguration
      * @throws StoreConfigurationException Thrown if this instance cannot load 
the KeyStore.
      * @deprecated Use createKeyStoreConfiguration(String, char[], String, 
String)
@@ -111,7 +145,8 @@ public class TrustStoreConfiguration extends 
AbstractKeyStoreConfiguration {
             final String keyStoreType,
             final String trustManagerFactoryAlgorithm) throws 
StoreConfigurationException {
             // @formatter:on
-        return new TrustStoreConfiguration(location, password, keyStoreType, 
trustManagerFactoryAlgorithm);
+        return createKeyStoreConfiguration(location, (password == null ? null 
: password.toCharArray()),
+                null, null, keyStoreType, trustManagerFactoryAlgorithm);
     }
 
     public TrustManagerFactory initTrustManagerFactory() throws 
NoSuchAlgorithmException, KeyStoreException {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java
index 337a0c0..c50c8ce 100644
--- 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java
@@ -82,7 +82,7 @@ public class HttpAppenderTest {
     @Rule
     public WireMockRule wireMockRule = new 
WireMockRule(wireMockConfig().dynamicPort().dynamicHttpsPort()
         .keystorePath(TestConstants.KEYSTORE_FILE)
-        .keystorePassword(String.valueOf(TestConstants.KEYSTORE_PWD))
+        .keystorePassword(String.valueOf(TestConstants.KEYSTORE_PWD()))
         .keystoreType(TestConstants.KEYSTORE_TYPE));
 
     @Test
@@ -115,8 +115,8 @@ public class HttpAppenderTest {
             .setConfiguration(ctx.getConfiguration())
             .setUrl(new URL("https://localhost:"; + wireMockRule.httpsPort() + 
"/test/log4j/"))
             .setSslConfiguration(SslConfiguration.createSSLConfiguration(null,
-                
KeyStoreConfiguration.createKeyStoreConfiguration(TestConstants.KEYSTORE_FILE, 
TestConstants.KEYSTORE_PWD, TestConstants.KEYSTORE_TYPE, null),
-                
TrustStoreConfiguration.createKeyStoreConfiguration(TestConstants.TRUSTSTORE_FILE,
 TestConstants.TRUSTSTORE_PWD, TestConstants.TRUSTSTORE_TYPE, null)))
+                
KeyStoreConfiguration.createKeyStoreConfiguration(TestConstants.KEYSTORE_FILE, 
TestConstants.KEYSTORE_PWD(), TestConstants.KEYSTORE_TYPE, null),
+                
TrustStoreConfiguration.createKeyStoreConfiguration(TestConstants.TRUSTSTORE_FILE,
 TestConstants.TRUSTSTORE_PWD(), TestConstants.TRUSTSTORE_TYPE, null)))
             .setVerifyHostname(false)
             .build();
         appender.append(createLogEvent());

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
index b92e393..abee218 100644
--- 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
@@ -75,13 +75,17 @@ public class SecureSocketAppenderSocketOptionsTest {
     public static void initServerSocketFactory() throws 
StoreConfigurationException {
         final KeyStoreConfiguration ksc = 
KeyStoreConfiguration.createKeyStoreConfiguration(
                 TestConstants.KEYSTORE_FILE, // file
-                TestConstants.KEYSTORE_PWD,  // password
+                TestConstants.KEYSTORE_PWD(),  // password
+                null, // passwordEnvironmentVariable
+                null, // passwordFile
                 null, // key store type
                 null); // algorithm
 
         final TrustStoreConfiguration tsc = 
TrustStoreConfiguration.createKeyStoreConfiguration(
                 TestConstants.TRUSTSTORE_FILE, // file
-                TestConstants.TRUSTSTORE_PWD, // password
+                TestConstants.TRUSTSTORE_PWD(), // password
+                null, // passwordEnvironmentVariable
+                null, // passwordFile
                 null, // key store type
                 null); // algorithm
         sslConfiguration = SslConfiguration.createSSLConfiguration(null, ksc, 
tsc);

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java
index e025fd8..ae567a0 100644
--- 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java
@@ -78,8 +78,8 @@ public class TlsSyslogAppenderTest extends SyslogAppenderTest 
{
     }
 
     private void initServerSocketFactory() throws StoreConfigurationException {
-        final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD, 
null, null);
-        final TrustStoreConfiguration tsc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, 
TestConstants.TRUSTSTORE_PWD, null, null);
+        final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, 
TestConstants.KEYSTORE_PWD(), null, null);
+        final TrustStoreConfiguration tsc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, 
TestConstants.TRUSTSTORE_PWD(), null, null);
         sslConfiguration = SslConfiguration.createSSLConfiguration(null, ksc, 
tsc);
         serverSocketFactory = sslConfiguration.getSslServerSocketFactory();
     }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProviderTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProviderTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProviderTest.java
new file mode 100644
index 0000000..a9b266f
--- /dev/null
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProviderTest.java
@@ -0,0 +1,38 @@
+package org.apache.logging.log4j.core.net.ssl;/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class EnvironmentPasswordProviderTest {
+
+    @Test(expected = NullPointerException.class)
+    public void testConstructorDisallowsNull() {
+        new EnvironmentPasswordProvider(null);
+    }
+
+    @Test
+    public void testGetPasswordReturnsEnvironmentVariableValue() {
+        final String value = System.getenv("PATH");
+        if (value == null) {
+            return; // we cannot test in this environment
+        }
+        final char[] actual = new 
EnvironmentPasswordProvider("PATH").getPassword();
+        assertArrayEquals(value.toCharArray(), actual);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProviderTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProviderTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProviderTest.java
new file mode 100644
index 0000000..eaa2d82
--- /dev/null
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProviderTest.java
@@ -0,0 +1,50 @@
+package org.apache.logging.log4j.core.net.ssl;/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class FilePasswordProviderTest {
+
+    @Test
+    public void testGetPassword() throws Exception {
+        final String PASSWORD = "myPass123";
+        final Path path = Files.createTempFile("testPass", ".txt");
+        Files.write(path, PASSWORD.getBytes(Charset.defaultCharset()));
+
+        char[] actual = new 
FilePasswordProvider(path.toString()).getPassword();
+        Files.delete(path);
+        assertArrayEquals(PASSWORD.toCharArray(), actual);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testConstructorDisallowsNull() throws Exception {
+        new FilePasswordProvider(null);
+    }
+
+    @Test(expected = NoSuchFileException.class)
+    public void testConstructorFailsIfFileDoesNotExist() throws Exception {
+        new FilePasswordProvider("nosuchfile");
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java
index ef38483..d5761ac 100644
--- 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java
@@ -37,7 +37,7 @@ public class KeyStoreConfigurationTest {
 
     @Test
     public void loadNotEmptyConfigurationDeprecated() throws 
StoreConfigurationException {
-        final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD,
+        final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD(),
                 TestConstants.KEYSTORE_TYPE, null);
         final KeyStore ks = ksc.getKeyStore();
         Assert.assertTrue(ks != null);
@@ -45,7 +45,7 @@ public class KeyStoreConfigurationTest {
 
     @Test
     public void loadNotEmptyConfiguration() throws StoreConfigurationException 
{
-        final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, new 
MemoryPasswordProvider(TestConstants.KEYSTORE_PWD),
+        final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, new 
MemoryPasswordProvider(TestConstants.KEYSTORE_PWD()),
                 TestConstants.KEYSTORE_TYPE, null);
         final KeyStore ks = ksc.getKeyStore();
         Assert.assertTrue(ks != null);
@@ -53,7 +53,7 @@ public class KeyStoreConfigurationTest {
 
     @Test
     public void returnTheSameKeyStoreAfterMultipleLoadsDeprecated() throws 
StoreConfigurationException {
-        final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD,
+        final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD(),
                 TestConstants.KEYSTORE_TYPE, null);
         final KeyStore ks = ksc.getKeyStore();
         final KeyStore ks2 = ksc.getKeyStore();
@@ -62,7 +62,7 @@ public class KeyStoreConfigurationTest {
 
     @Test
     public void returnTheSameKeyStoreAfterMultipleLoads() throws 
StoreConfigurationException {
-        final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, new 
MemoryPasswordProvider(TestConstants.KEYSTORE_PWD),
+        final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, new 
MemoryPasswordProvider(TestConstants.KEYSTORE_PWD()),
                 TestConstants.KEYSTORE_TYPE, null);
         final KeyStore ks = ksc.getKeyStore();
         final KeyStore ks2 = ksc.getKeyStore();

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProviderTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProviderTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProviderTest.java
new file mode 100644
index 0000000..df4b5f2
--- /dev/null
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProviderTest.java
@@ -0,0 +1,49 @@
+package org.apache.logging.log4j.core.net.ssl;/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class MemoryPasswordProviderTest {
+    @Test
+    public void testConstructorAllowsNull() {
+        assertEquals(null, new MemoryPasswordProvider(null).getPassword());
+    }
+
+    @Test
+    public void testConstructorDoesNotModifyOriginalParameterArray() {
+        char[] initial = "123".toCharArray();
+        new MemoryPasswordProvider(initial);
+        assertArrayEquals("123".toCharArray(), initial);
+    }
+
+    @Test
+    public void testGetPasswordReturnsCopyOfConstructorArray() {
+        char[] initial = "123".toCharArray();
+        MemoryPasswordProvider provider = new MemoryPasswordProvider(initial);
+        char[] actual = provider.getPassword();
+        assertArrayEquals("123".toCharArray(), actual);
+        assertNotSame(initial, actual);
+
+        Arrays.fill(initial, 'a');
+        assertArrayEquals("123".toCharArray(), provider.getPassword());
+        assertNotSame(provider.getPassword(), provider.getPassword());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java
index 936cc66..41349a0 100644
--- 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java
@@ -33,33 +33,33 @@ public class SslConfigurationTest {
 
     public static SslConfiguration 
createTestSslConfigurationResourcesDeprecated() throws 
StoreConfigurationException {
         final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE_RESOURCE,
-                TestConstants.KEYSTORE_PWD, TestConstants.KEYSTORE_TYPE, null);
+                TestConstants.KEYSTORE_PWD(), TestConstants.KEYSTORE_TYPE, 
null);
         final TrustStoreConfiguration tsc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE_RESOURCE,
-                TestConstants.TRUSTSTORE_PWD, null, null);
+                TestConstants.TRUSTSTORE_PWD(), null, null);
         return SslConfiguration.createSSLConfiguration(null, ksc, tsc);
     }
 
     public static SslConfiguration createTestSslConfigurationResources() 
throws StoreConfigurationException {
         final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE_RESOURCE,
-                new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD), 
TestConstants.KEYSTORE_TYPE, null);
+                new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD()), 
TestConstants.KEYSTORE_TYPE, null);
         final TrustStoreConfiguration tsc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE_RESOURCE,
-                new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD), 
null, null);
+                new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD()), 
null, null);
         return SslConfiguration.createSSLConfiguration(null, ksc, tsc);
     }
 
     public static SslConfiguration createTestSslConfigurationFilesDeprecated() 
throws StoreConfigurationException {
         final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE,
-                TestConstants.KEYSTORE_PWD, TestConstants.KEYSTORE_TYPE, null);
+                TestConstants.KEYSTORE_PWD(), TestConstants.KEYSTORE_TYPE, 
null);
         final TrustStoreConfiguration tsc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE,
-                TestConstants.TRUSTSTORE_PWD, null, null);
+                TestConstants.TRUSTSTORE_PWD(), null, null);
         return SslConfiguration.createSSLConfiguration(null, ksc, tsc);
     }
 
     public static SslConfiguration createTestSslConfigurationFiles() throws 
StoreConfigurationException {
         final KeyStoreConfiguration ksc = new 
KeyStoreConfiguration(TestConstants.KEYSTORE_FILE,
-                new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD), 
TestConstants.KEYSTORE_TYPE, null);
+                new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD()), 
TestConstants.KEYSTORE_TYPE, null);
         final TrustStoreConfiguration tsc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE,
-                new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD), 
null, null);
+                new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD()), 
null, null);
         return SslConfiguration.createSSLConfiguration(null, ksc, tsc);
     }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TestConstants.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TestConstants.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TestConstants.java
index 1fa8572..90b3bed 100644
--- 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TestConstants.java
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TestConstants.java
@@ -17,24 +17,24 @@
 package org.apache.logging.log4j.core.net.ssl;
 
 public class TestConstants {
-    
+
     public static final String SOURCE_FOLDER =  "src/test/resources/";
     public static final String RESOURCE_ROOT =  
"org/apache/logging/log4j/core/net/ssl/";
-    
+
     public static final String PATH =  SOURCE_FOLDER + RESOURCE_ROOT;
     public static final String TRUSTSTORE_PATH = PATH;
     public static final String TRUSTSTORE_RESOURCE = RESOURCE_ROOT;
     public static final String TRUSTSTORE_FILE = TRUSTSTORE_PATH + 
"truststore.jks";
     public static final String TRUSTSTORE_FILE_RESOURCE = TRUSTSTORE_RESOURCE 
+ "truststore.jks";
-    public static final char[] TRUSTSTORE_PWD = "changeit".toCharArray();
+    public static final char[] TRUSTSTORE_PWD() { return 
"changeit".toCharArray(); }
     public static final String TRUSTSTORE_TYPE = "JKS";
 
     public static final String KEYSTORE_PATH = PATH;
     public static final String KEYSTORE_RESOURCE = RESOURCE_ROOT;
     public static final String KEYSTORE_FILE = KEYSTORE_PATH + 
"client.log4j2-keystore.jks";
     public static final String KEYSTORE_FILE_RESOURCE = KEYSTORE_RESOURCE + 
"client.log4j2-keystore.jks";
-    public static final char[] KEYSTORE_PWD = "changeit".toCharArray();
+    public static final char[] KEYSTORE_PWD() { return 
"changeit".toCharArray(); }
     public static final String KEYSTORE_TYPE = "JKS";
-    
+
     public static final char[] NULL_PWD = null;
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java
index 14c58bb..d27a1fd 100644
--- 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java
@@ -37,21 +37,21 @@ public class TrustStoreConfigurationTest {
 
     @Test
     public void loadConfigurationDeprecated() throws 
StoreConfigurationException {
-        final TrustStoreConfiguration ksc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, 
TestConstants.TRUSTSTORE_PWD, null, null);
+        final TrustStoreConfiguration ksc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, 
TestConstants.TRUSTSTORE_PWD(), null, null);
         final KeyStore ks = ksc.getKeyStore();
         Assert.assertNotNull(ks);
     }
 
     @Test
     public void loadConfiguration() throws StoreConfigurationException {
-        final TrustStoreConfiguration ksc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, new 
MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD), null, null);
+        final TrustStoreConfiguration ksc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, new 
MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD()), null, null);
         final KeyStore ks = ksc.getKeyStore();
         Assert.assertNotNull(ks);
     }
 
     @Test
     public void returnTheSameKeyStoreAfterMultipleLoadsDeprecated() throws 
StoreConfigurationException {
-        final TrustStoreConfiguration ksc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, 
TestConstants.TRUSTSTORE_PWD, null, null);
+        final TrustStoreConfiguration ksc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, 
TestConstants.TRUSTSTORE_PWD(), null, null);
         final KeyStore ks = ksc.getKeyStore();
         final KeyStore ks2 = ksc.getKeyStore();
         Assert.assertTrue(ks == ks2);
@@ -59,7 +59,7 @@ public class TrustStoreConfigurationTest {
 
     @Test
     public void returnTheSameKeyStoreAfterMultipleLoads() throws 
StoreConfigurationException {
-        final TrustStoreConfiguration ksc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, new 
MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD), null, null);
+        final TrustStoreConfiguration ksc = new 
TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, new 
MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD()), null, null);
         final KeyStore ks = ksc.getKeyStore();
         final KeyStore ks2 = ksc.getKeyStore();
         Assert.assertTrue(ks == ks2);

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 55b18f9..94b1033 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -31,6 +31,9 @@
          - "remove" - Removed
     -->
     <release version="2.9.2" date="2017-XX-XX" description="GA Release 2.9.2">
+      <action issue="LOG4J2-2054" dev="rpopma" type="add">
+        Provide ways to configure SSL that avoid plain-text passwords in the 
log4j configuration. The configuration may now specify a system environment 
variable that holds the password, or the path to a file that holds the password.
+      </action>
       <action issue="LOG4J2-2057" dev="rgoers" type="update">
         Support new SLF4J binding mechanism introduced in SLF4J 1.8.
       </action>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/src/site/site.xml
----------------------------------------------------------------------
diff --git a/src/site/site.xml b/src/site/site.xml
index dca832a..6de65be 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -147,6 +147,7 @@
         <item name="SMTP" href="/manual/appenders.html#SMTPAppender"/>
         <item name="ScriptAppenderSelector" 
href="/manual/appenders.html#ScriptAppenderSelector"/>
         <item name="Socket" href="/manual/appenders.html#SocketAppender"/>
+        <item name="SSL" href="/manual/appenders.html#SSL"/>
         <item name="Syslog" href="/manual/appenders.html#SyslogAppender"/>
         <item name="ZeroMQ/JeroMQ" 
href="/manual/appenders.html#JeroMQAppender"/>
       </item>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/src/site/xdoc/manual/appenders.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/appenders.xml 
b/src/site/xdoc/manual/appenders.xml
index c4982c0..b9ef28a 100644
--- a/src/site/xdoc/manual/appenders.xml
+++ b/src/site/xdoc/manual/appenders.xml
@@ -1658,7 +1658,7 @@ public class JpaLogEntity extends 
AbstractLogEventWrapperEntity {
               <td>Ssl</td>
               <td>SslConfiguration</td>
               <td>Contains the configuration for the KeyStore and TrustStore 
for https.
-                  Optional, uses Java runtime defaults if not specified.</td>
+                  Optional, uses Java runtime defaults if not specified. See 
<a href="#SSL">SSL</a></td>
             </tr>
             <tr>
               <td>verifyHostname</td>
@@ -1710,8 +1710,8 @@ public class JpaLogEntity extends 
AbstractLogEventWrapperEntity {
       <Property name="X-Java-Runtime" value="$${java:runtime}" />
       <JsonLayout properties="true"/>
       <SSL>
-        <KeyStore location="log4j2-keystore.jks" password="changeme"/>
-        <TrustStore location="truststore.jks" password="changeme"/>
+        <KeyStore   location="log4j2-keystore.jks" 
passwordEnvironmentVariable="KEYSTORE_PASSWORD"/>
+        <TrustStore location="truststore.jks"      
passwordFile="${sys:user.home}/truststore.pwd"/>
       </SSL>
     </Http>
   </Appenders>]]></pre>
@@ -4355,7 +4355,7 @@ public class JpaLogEntity extends 
AbstractLogEventWrapperEntity {
           <p>
             The <code>SocketAppender</code> is an OutputStreamAppender that 
writes its output to a remote destination
             specified by a host and port. The data can be sent over either TCP 
or UDP and can be sent in any format.
-            You can optionally secure communication with SSL.
+            You can optionally secure communication with <a 
href="#SSL">SSL</a>.
           </p>
           <table>
             <caption align="top"><code>SocketAppender</code> 
Parameters</caption>
@@ -4387,7 +4387,7 @@ public class JpaLogEntity extends 
AbstractLogEventWrapperEntity {
             <tr>
               <td>SSL</td>
               <td>SslConfiguration</td>
-              <td>Contains the configuration for the KeyStore and 
TrustStore.</td>
+              <td>Contains the configuration for the KeyStore and TrustStore. 
See <a href="#SSL">SSL</a>.</td>
             </tr>
             <tr>
               <td>filter</td>
@@ -4467,7 +4467,7 @@ public class JpaLogEntity extends 
AbstractLogEventWrapperEntity {
 </Configuration>]]></pre>
 
           <p>
-            This is a secured SSL configuration:
+            This is a secured <a href="#SSL">SSL</a> configuration:
           </p>
           <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" 
encoding="UTF-8"?>
 <Configuration status="warn" name="MyApp" packages="">
@@ -4475,8 +4475,8 @@ public class JpaLogEntity extends 
AbstractLogEventWrapperEntity {
     <Socket name="socket" host="localhost" port="9500">
       <JsonLayout properties="true"/>
       <SSL>
-        <KeyStore location="log4j2-keystore.jks" password="changeme"/>
-        <TrustStore location="truststore.jks" password="changeme"/>
+        <KeyStore   location="log4j2-keystore.jks" 
passwordEnvironmentVariable="KEYSTORE_PASSWORD"/>
+        <TrustStore location="truststore.jks"      
passwordFile="${sys:user.home}/truststore.pwd"/>
       </SSL>
     </Socket>
   </Appenders>
@@ -4488,6 +4488,154 @@ public class JpaLogEntity extends 
AbstractLogEventWrapperEntity {
 </Configuration>]]></pre>
 
         </subsection>
+        <a name="SSL" />
+        <subsection name="SSL Configuration">
+          <p>
+            Several appenders can be configured to use either a plain network 
connection or a Secure Socket Layer (SSL)
+            connection. This section documents the parameters available for 
SSL configuration.
+          </p>
+          <table>
+          <caption align="top">SSL Configuration Parameters</caption>
+          <tr>
+            <th>Parameter Name</th>
+            <th>Type</th>
+            <th>Description</th>
+          </tr>
+          <tr>
+            <td>protocol</td>
+            <td>String</td>
+            <td><code>SSL</code> if omitted.
+            See also <a 
href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext";>Standard
 names</a>.</td>
+          </tr>
+          <tr>
+            <td>KeyStore</td>
+            <td>KeyStore</td>
+            <td>Contains your private keys and certificates,
+              and determines which authentication credentials to send to the 
remote host.</td>
+          </tr>
+          <tr>
+            <td>TrustStore</td>
+            <td>TrustStore</td>
+            <td>Contains the CA certificates of the remote counterparty.
+              Determines whether the remote authentication credentials
+              (and thus the connection) should be trusted.</td>
+          </tr>
+          </table>
+
+          <h4>KeyStore</h4>
+          The keystore is meant to contain your private keys and certificates,
+          and determines which authentication credentials to send to the 
remote host.
+
+          <table>
+            <caption align="top">KeyStore Configuration Parameters</caption>
+            <tr>
+              <th>Parameter Name</th>
+              <th>Type</th>
+              <th>Description</th>
+            </tr>
+            <tr>
+              <td>location</td>
+              <td>String</td>
+              <td>Path to the keystore file.</td>
+            </tr>
+            <tr>
+              <td>password</td>
+              <td>char[]</td>
+              <td>Plain text password to access the keystore. Cannot be 
combined with either
+                <code>passwordEnvironmentVariable</code> or 
<code>passwordFile</code>.</td>
+            </tr>
+            <tr>
+              <td>passwordEnvironmentVariable</td>
+              <td>String</td>
+              <td>Name of an environment variable that holds the password. 
Cannot be combined with either
+                <code>password</code> or <code>passwordFile</code>.</td>
+            </tr>
+            <tr>
+              <td>passwordFile</td>
+              <td>String</td>
+              <td>Path to a file that holds the password. Cannot be combined 
with either
+                <code>password</code> or 
<code>passwordEnvironmentVariable</code>.</td>
+            </tr>
+            <tr>
+              <td>type</td>
+              <td>String</td>
+              <td>Optional KeyStore type, e.g. <code>JKS</code>, 
<code>PKCS12</code>, <code>PKCS11</code>,
+                <code>BKS</code>, <code>Windows-MY/Windows-ROOT</code>, 
<code>KeychainStore</code>, etc.
+                The default is JKS. See also <a 
href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyStore";>Standard
 types</a>.</td>
+            </tr>
+            <tr>
+              <td>keyManagerFactoryAlgorithm</td>
+              <td>String</td>
+              <td>Optional KeyManagerFactory algorithm. The default is 
<code>SunX509</code>.
+              See also <a 
href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyManagerFactory";>Standard
 algorithms</a>.</td>
+            </tr>
+          </table>
+
+          <h4>TrustStore</h4>
+          <p>
+            The trust store is meant to contain the CA certificates you are 
willing to trust
+            when a remote party presents its certificate. Determines whether 
the remote authentication credentials
+            (and thus the connection) should be trusted.
+          </p><p>
+          In some cases, they can be one and the same store,
+          although it is often better practice to use distinct stores 
(especially when they are file-based).
+          </p>
+
+          <table>
+            <caption align="top">TrustStore Configuration Parameters</caption>
+            <tr>
+              <th>Parameter Name</th>
+              <th>Type</th>
+              <th>Description</th>
+            </tr>
+            <tr>
+              <td>location</td>
+              <td>String</td>
+              <td>Path to the keystore file.</td>
+            </tr>
+            <tr>
+              <td>password</td>
+              <td>char[]</td>
+              <td>Plain text password to access the keystore. Cannot be 
combined with either
+                <code>passwordEnvironmentVariable</code> or 
<code>passwordFile</code>.</td>
+            </tr>
+            <tr>
+              <td>passwordEnvironmentVariable</td>
+              <td>String</td>
+              <td>Name of an environment variable that holds the password. 
Cannot be combined with either
+                <code>password</code> or <code>passwordFile</code>.</td>
+            </tr>
+            <tr>
+              <td>passwordFile</td>
+              <td>String</td>
+              <td>Path to a file that holds the password. Cannot be combined 
with either
+                <code>password</code> or 
<code>passwordEnvironmentVariable</code>.</td>
+            </tr>
+            <tr>
+              <td>type</td>
+              <td>String</td>
+              <td>Optional KeyStore type, e.g. <code>JKS</code>, 
<code>PKCS12</code>, <code>PKCS11</code>,
+                <code>BKS</code>, <code>Windows-MY/Windows-ROOT</code>, 
<code>KeychainStore</code>, etc.
+                The default is JKS. See also <a 
href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyStore";>Standard
 types</a>.</td>
+            </tr>
+            <tr>
+              <td>trustManagerFactoryAlgorithm</td>
+              <td>String</td>
+              <td>Optional TrustManagerFactory algorithm. The default is 
<code>SunX509</code>.
+                See also <a 
href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#TrustManagerFactory";>Standard
 algorithms</a>.</td>
+            </tr>
+          </table>
+
+          <h4>Example</h4>
+          <pre class="prettyprint linenums"><![CDATA[
+  ...
+      <SSL>
+        <KeyStore   location="log4j2-keystore.jks" 
passwordEnvironmentVariable="KEYSTORE_PASSWORD"/>
+        <TrustStore location="truststore.jks"      
passwordFile="${sys:user.home}/truststore.pwd"/>
+      </SSL>
+  ...]]></pre>
+
+        </subsection>
         <a name="SyslogAppender"/>
         <subsection name="SyslogAppender">
           <p>
@@ -4659,7 +4807,7 @@ public class JpaLogEntity extends 
AbstractLogEventWrapperEntity {
             <tr>
               <td>SSL</td>
               <td>SslConfiguration</td>
-              <td>Contains the configuration for the KeyStore and 
TrustStore.</td>
+              <td>Contains the configuration for the KeyStore and TrustStore. 
See <a href="#SSL">SSL</a>.</td>
             </tr>
             <tr>
               <td>reconnectionDelayMillis</td>
@@ -4695,7 +4843,7 @@ public class JpaLogEntity extends 
AbstractLogEventWrapperEntity {
 </Configuration>]]></pre>
 
           <p>
-            For SSL this appender writes its output to a remote destination 
specified by a host and port over SSL in
+            For <a href="#SSL">SSL</a> this appender writes its output to a 
remote destination specified by a host and port over SSL in
             a format that conforms with either the BSD Syslog format or the 
RFC 5424 format.
           </p>
 
@@ -4704,8 +4852,8 @@ public class JpaLogEntity extends 
AbstractLogEventWrapperEntity {
   <Appenders>
     <TLSSyslog name="bsd" host="localhost" port="6514">
       <SSL>
-        <KeyStore location="log4j2-keystore.jks" password="changeme"/>
-        <TrustStore location="truststore.jks" password="changeme"/>
+        <KeyStore   location="log4j2-keystore.jks" 
passwordEnvironmentVariable="KEYSTORE_PASSWORD"/>
+        <TrustStore location="truststore.jks"      
passwordFile="${sys:user.home}/truststore.pwd"/>
       </SSL>
     </TLSSyslog>
   </Appenders>

Reply via email to