You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@logging.apache.org by Gary Gregory <ga...@gmail.com> on 2017/09/25 16:08:06 UTC

Re: logging-log4j2 git commit: 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

On Mon, Sep 25, 2017 at 10:00 AM, <rp...@apache.org> wrote:

> 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 <rp...@apache.org>
> Authored: Tue Sep 26 01:00:15 2017 +0900
> Committer: rpopma <rp...@apache.org>
> 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();
>

Needs a null check IMO with throws IllegalArgumentException message.

Gary


> +    }
> +}


> 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>
>
>

Re: logging-log4j2 git commit: 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

Posted by Remko Popma <re...@gmail.com>.
Thanks for reviewing. 
Good catch, a null check is needed to prevent NPEs. 
But null passwords are possible so perhaps make it like this:

return password == null ? null : password.toCharArray();


> On Sep 26, 2017, at 1:08, Gary Gregory <ga...@gmail.com> wrote:
> 
>> On Mon, Sep 25, 2017 at 10:00 AM, <rp...@apache.org> wrote:
>> 
>> 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 <rp...@apache.org>
>> Authored: Tue Sep 26 01:00:15 2017 +0900
>> Committer: rpopma <rp...@apache.org>
>> 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();
>> 
> 
> Needs a null check IMO with throws IllegalArgumentException message.
> 
> Gary
> 
> 
>> +    }
>> +}
> 
> 
>> 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>
>> 
>>