Repository: logging-log4j2 Updated Branches: refs/heads/master a73fce2e7 -> 08077cba3
LOG4J2-2054 Provide ways to configure SSL that avoid plain-text passwords in the log4j configuration. The configuration may now specify a system environment variable that holds the password, or the path to a file that holds the password. Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/08077cba Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/08077cba Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/08077cba Branch: refs/heads/master Commit: 08077cba385ee376aa44ae33c66833421e9d19bc Parents: a73fce2 Author: rpopma <[email protected]> Authored: Tue Sep 26 01:00:15 2017 +0900 Committer: rpopma <[email protected]> Committed: Tue Sep 26 01:00:15 2017 +0900 ---------------------------------------------------------------------- .../net/ssl/EnvironmentPasswordProvider.java | 54 ++++++ .../core/net/ssl/FilePasswordProvider.java | 83 +++++++++ .../core/net/ssl/KeyStoreConfiguration.java | 58 +++++-- .../core/net/ssl/MemoryPasswordProvider.java | 20 ++- .../core/net/ssl/TrustStoreConfiguration.java | 57 ++++-- .../log4j/core/appender/HttpAppenderTest.java | 6 +- .../SecureSocketAppenderSocketOptionsTest.java | 8 +- .../core/appender/TlsSyslogAppenderTest.java | 4 +- .../ssl/EnvironmentPasswordProviderTest.java | 38 ++++ .../core/net/ssl/FilePasswordProviderTest.java | 50 ++++++ .../core/net/ssl/KeyStoreConfigurationTest.java | 8 +- .../net/ssl/MemoryPasswordProviderTest.java | 49 ++++++ .../core/net/ssl/SslConfigurationTest.java | 16 +- .../log4j/core/net/ssl/TestConstants.java | 10 +- .../net/ssl/TrustStoreConfigurationTest.java | 8 +- src/changes/changes.xml | 3 + src/site/site.xml | 1 + src/site/xdoc/manual/appenders.xml | 172 +++++++++++++++++-- 18 files changed, 580 insertions(+), 65 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProvider.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProvider.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProvider.java new file mode 100644 index 0000000..e501c15 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProvider.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.net.ssl; + +import java.util.Objects; + +/** + * PasswordProvider implementation that obtains the password value from a system environment variable. + * <p> + * This implementation is not very secure because the Java interface to obtain system environment variable values + * requires us to use String objects. String objects are immutable and Java does not provide a way to erase this + * sensitive data from the application memory. The password data will stay resident in memory until the String object + * and its associated char[] array object are garbage collected and the memory is overwritten by another object. + * </p><p> + * This is slightly more secure than {@link MemoryPasswordProvider} because the actual password string is not pulled + * into memory until it is needed (so the password string does not need to be passed in from the command line or in a + * configuration file). + * This gives an attacker a smaller window of opportunity to obtain the password from a memory dump. + * </p><p> + * A more secure implementation is {@link FilePasswordProvider}. + * </p> + */ +class EnvironmentPasswordProvider implements PasswordProvider { + private final String passwordEnvironmentVariable; + + /** + * Constructs a new EnvironmentPasswordProvider with the specified environment variable name + * @param passwordEnvironmentVariable name of the system environment variable that holds the password + */ + public EnvironmentPasswordProvider(final String passwordEnvironmentVariable) { + this.passwordEnvironmentVariable = Objects.requireNonNull( + passwordEnvironmentVariable, "passwordEnvironmentVariable"); + } + + @Override + public char[] getPassword() { + String password = System.getenv(passwordEnvironmentVariable); + return password.toCharArray(); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProvider.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProvider.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProvider.java new file mode 100644 index 0000000..ff59b00 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProvider.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.net.ssl; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; + +/** + * PasswordProvider that reads password from a file. + * <p> + * This is a relatively secure way to handle passwords: + * <ul> + * <li>Managing file access privileges can be delegated to the operating system.</li> + * <li>The password file can be in a separate location from the logging configuration. + * This gives flexibility to have different passwords in different environments while + * using the same logging configuration. It also allows for separation of responsibilities: + * developers don't need to know the password that is used in the production environment.</li> + * <li>There is only a small window of opportunity for attackers to obtain the password from a memory + * dump: the password data is only resident in memory from the moment the caller calls the + * {@link #getPassword()} method and the password file is read until the moment that the caller + * completes authentication and overwrites the password char[] array.</li> + * </ul> + * </p><p> + * Less secure implementations are {@link MemoryPasswordProvider} and {@link EnvironmentPasswordProvider}. + * </p> + */ +class FilePasswordProvider implements PasswordProvider { + private final Path passwordPath; + + /** + * Constructs a new FilePasswordProvider with the specified path. + * @param passwordFile the path to the password file + * @throws NoSuchFileException if the password file does not exist when this FilePasswordProvider is constructed + */ + public FilePasswordProvider(final String passwordFile) throws NoSuchFileException { + this.passwordPath = Paths.get(passwordFile); + if (!Files.exists(passwordPath)) { + throw new NoSuchFileException("PasswordFile '" + passwordFile + "' does not exist"); + } + } + + @Override + public char[] getPassword() { + byte[] bytes = null; + try { + bytes = Files.readAllBytes(passwordPath); + ByteBuffer bb = ByteBuffer.wrap(bytes); + CharBuffer decoded = Charset.defaultCharset().decode(bb); + char[] result = new char[decoded.limit()]; + decoded.get(result, 0, result.length); + decoded.rewind(); + decoded.put(new char[result.length]); // erase decoded CharBuffer + return result; + } catch (IOException e) { + throw new IllegalStateException("Could not read password from " + passwordPath + ": " + e, e); + } finally { + if (bytes != null) { + Arrays.fill(bytes, (byte) 0x0); + } + } + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java index 3fc37bd..d0c7bb0 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java @@ -59,6 +59,9 @@ public class KeyStoreConfiguration extends AbstractKeyStoreConfiguration { final String keyStoreType, final String keyManagerFactoryAlgorithm) throws StoreConfigurationException { this(location, new MemoryPasswordProvider(password), keyStoreType, keyManagerFactoryAlgorithm); + if (password != null) { + Arrays.fill(password, '\0'); + } } /** @@ -92,24 +95,54 @@ public class KeyStoreConfiguration extends AbstractKeyStoreConfiguration { // @formatter:off @PluginAttribute("location") final String location, @PluginAttribute(value = "password", sensitive = true) final char[] password, + @PluginAttribute("passwordEnvironmentVariable") final String passwordEnvironmentVariable, + @PluginAttribute("passwordFile") final String passwordFile, @PluginAttribute("type") final String keyStoreType, @PluginAttribute("keyManagerFactoryAlgorithm") final String keyManagerFactoryAlgorithm) throws StoreConfigurationException { // @formatter:on - return new KeyStoreConfiguration(location, new MemoryPasswordProvider(password), keyStoreType, - keyManagerFactoryAlgorithm); + + if (password != null && passwordEnvironmentVariable != null && passwordFile != null) { + throw new StoreConfigurationException("You MUST set only one of 'password', 'passwordEnvironmentVariable' or 'passwordFile'."); + } + try { + // @formatter:off + PasswordProvider provider = passwordFile != null + ? new FilePasswordProvider(passwordFile) + : passwordEnvironmentVariable != null + ? new EnvironmentPasswordProvider(passwordEnvironmentVariable) + // the default is memory char[] array, which may be null + : new MemoryPasswordProvider(password); + // @formatter:on + if (password != null) { + Arrays.fill(password, '\0'); + } + return new KeyStoreConfiguration(location, provider, keyStoreType, keyManagerFactoryAlgorithm); + } catch (Exception ex) { + throw new StoreConfigurationException("Could not configure KeyStore", ex); + } + } + + /** + * @deprecated use {@link #createKeyStoreConfiguration(String, char[], String, String, String, String)} + */ + public static KeyStoreConfiguration createKeyStoreConfiguration( + // @formatter:off + final String location, + final char[] password, + final String keyStoreType, + final String keyManagerFactoryAlgorithm) throws StoreConfigurationException { + // @formatter:on + return createKeyStoreConfiguration(location, password, null, null, keyStoreType, keyManagerFactoryAlgorithm); } /** * Creates a KeyStoreConfiguration. * - * @param location - * The location of the KeyStore, a file path, URL or resource. - * @param password - * The password to access the KeyStore. - * @param keyStoreType - * The KeyStore type, null defaults to {@code "JKS"}. - * @param keyManagerFactoryAlgorithm - * The standard name of the requested algorithm. See the Java Secure Socket Extension Reference Guide for information about these names. + * @param location The location of the KeyStore, a file path, URL or resource. + * @param password The password to access the KeyStore. + * @param keyStoreType The KeyStore type, null defaults to {@code "JKS"}. + * @param keyManagerFactoryAlgorithm The standard name of the requested algorithm. See the Java Secure Socket + * Extension Reference Guide for information about these names. * @return a new KeyStoreConfiguration * @throws StoreConfigurationException Thrown if this call cannot load the KeyStore. * @deprecated Use createKeyStoreConfiguration(String, char[], String, String) @@ -122,8 +155,9 @@ public class KeyStoreConfiguration extends AbstractKeyStoreConfiguration { final String keyStoreType, final String keyManagerFactoryAlgorithm) throws StoreConfigurationException { // @formatter:on - return new KeyStoreConfiguration(location, - new MemoryPasswordProvider(password == null ? null : password.toCharArray()), keyStoreType, + return createKeyStoreConfiguration(location, + (password == null ? null : password.toCharArray()), + keyStoreType, keyManagerFactoryAlgorithm); } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProvider.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProvider.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProvider.java index 328728d..6fd7ab4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProvider.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProvider.java @@ -16,14 +16,26 @@ */ package org.apache.logging.log4j.core.net.ssl; +import java.util.Arrays; + /** - * Simple (and not very secure) PasswordProvider implementation that keeps the password char[] array in memory. + * Simple PasswordProvider implementation that keeps the password char[] array in memory. + * <p> + * This implementation is not very secure because the password data is resident in memory during the life of this + * provider object, giving attackers a large window of opportunity to obtain the password from a memory dump. + * A slightly more secure implementation is {@link EnvironmentPasswordProvider}, + * and an even more secure implementation is {@link FilePasswordProvider}. + * </p> */ class MemoryPasswordProvider implements PasswordProvider { private final char[] password; public MemoryPasswordProvider(final char[] chars) { - password = chars; + if (chars != null) { + password = chars.clone(); + } else { + password = null; + } } @Override @@ -33,4 +45,8 @@ class MemoryPasswordProvider implements PasswordProvider { } return password.clone(); } + + public void clearSecrets() { + Arrays.fill(password, '\0'); + } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java index c472186..d884aed 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java @@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.net.ssl; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.util.Arrays; import javax.net.ssl.TrustManagerFactory; @@ -50,6 +51,9 @@ public class TrustStoreConfiguration extends AbstractKeyStoreConfiguration { public TrustStoreConfiguration(final String location, final char[] password, final String keyStoreType, final String trustManagerFactoryAlgorithm) throws StoreConfigurationException { this(location, new MemoryPasswordProvider(password), keyStoreType, trustManagerFactoryAlgorithm); + if (password != null) { + Arrays.fill(password, '\0'); + } } /** @@ -81,24 +85,54 @@ public class TrustStoreConfiguration extends AbstractKeyStoreConfiguration { // @formatter:off @PluginAttribute("location") final String location, @PluginAttribute(value = "password", sensitive = true) final char[] password, + @PluginAttribute("passwordEnvironmentVariable") final String passwordEnvironmentVariable, + @PluginAttribute("passwordFile") final String passwordFile, @PluginAttribute("type") final String keyStoreType, @PluginAttribute("trustManagerFactoryAlgorithm") final String trustManagerFactoryAlgorithm) throws StoreConfigurationException { // @formatter:on - return new TrustStoreConfiguration(location, new MemoryPasswordProvider(password), keyStoreType, - trustManagerFactoryAlgorithm); + + if (password != null && passwordEnvironmentVariable != null && passwordFile != null) { + throw new IllegalStateException("You MUST set only one of 'password', 'passwordEnvironmentVariable' or 'passwordFile'."); + } + try { + // @formatter:off + PasswordProvider provider = passwordFile != null + ? new FilePasswordProvider(passwordFile) + : passwordEnvironmentVariable != null + ? new EnvironmentPasswordProvider(passwordEnvironmentVariable) + // the default is memory char[] array, which may be null + : new MemoryPasswordProvider(password); + // @formatter:on + if (password != null) { + Arrays.fill(password, '\0'); + } + return new TrustStoreConfiguration(location, provider, keyStoreType, trustManagerFactoryAlgorithm); + } catch (Exception ex) { + throw new StoreConfigurationException("Could not configure TrustStore", ex); + } + } + + /** + * @deprecated Use {@link #createKeyStoreConfiguration(String, char[], String, String, String, String)} + */ + public static TrustStoreConfiguration createKeyStoreConfiguration( + // @formatter:off + final String location, + final char[] password, + final String keyStoreType, + final String trustManagerFactoryAlgorithm) throws StoreConfigurationException { + // @formatter:on + return createKeyStoreConfiguration(location, password, null, null, keyStoreType, trustManagerFactoryAlgorithm); } /** * Creates a KeyStoreConfiguration. * - * @param location - * The location of the KeyStore, a file path, URL or resource. - * @param password - * The password to access the KeyStore. - * @param keyStoreType - * The KeyStore type, null defaults to {@code "JKS"}. - * @param trustManagerFactoryAlgorithm - * The standard name of the requested trust management algorithm. See the Java Secure Socket Extension Reference Guide for information these names. + * @param location The location of the KeyStore, a file path, URL or resource. + * @param password The password to access the KeyStore. + * @param keyStoreType The KeyStore type, null defaults to {@code "JKS"}. + * @param trustManagerFactoryAlgorithm The standard name of the requested trust management algorithm. See the Java + * Secure Socket Extension Reference Guide for information these names. * @return a new TrustStoreConfiguration * @throws StoreConfigurationException Thrown if this instance cannot load the KeyStore. * @deprecated Use createKeyStoreConfiguration(String, char[], String, String) @@ -111,7 +145,8 @@ public class TrustStoreConfiguration extends AbstractKeyStoreConfiguration { final String keyStoreType, final String trustManagerFactoryAlgorithm) throws StoreConfigurationException { // @formatter:on - return new TrustStoreConfiguration(location, password, keyStoreType, trustManagerFactoryAlgorithm); + return createKeyStoreConfiguration(location, (password == null ? null : password.toCharArray()), + null, null, keyStoreType, trustManagerFactoryAlgorithm); } public TrustManagerFactory initTrustManagerFactory() throws NoSuchAlgorithmException, KeyStoreException { http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java index 337a0c0..c50c8ce 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java @@ -82,7 +82,7 @@ public class HttpAppenderTest { @Rule public WireMockRule wireMockRule = new WireMockRule(wireMockConfig().dynamicPort().dynamicHttpsPort() .keystorePath(TestConstants.KEYSTORE_FILE) - .keystorePassword(String.valueOf(TestConstants.KEYSTORE_PWD)) + .keystorePassword(String.valueOf(TestConstants.KEYSTORE_PWD())) .keystoreType(TestConstants.KEYSTORE_TYPE)); @Test @@ -115,8 +115,8 @@ public class HttpAppenderTest { .setConfiguration(ctx.getConfiguration()) .setUrl(new URL("https://localhost:" + wireMockRule.httpsPort() + "/test/log4j/")) .setSslConfiguration(SslConfiguration.createSSLConfiguration(null, - KeyStoreConfiguration.createKeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD, TestConstants.KEYSTORE_TYPE, null), - TrustStoreConfiguration.createKeyStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD, TestConstants.TRUSTSTORE_TYPE, null))) + KeyStoreConfiguration.createKeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD(), TestConstants.KEYSTORE_TYPE, null), + TrustStoreConfiguration.createKeyStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD(), TestConstants.TRUSTSTORE_TYPE, null))) .setVerifyHostname(false) .build(); appender.append(createLogEvent()); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java index b92e393..abee218 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java @@ -75,13 +75,17 @@ public class SecureSocketAppenderSocketOptionsTest { public static void initServerSocketFactory() throws StoreConfigurationException { final KeyStoreConfiguration ksc = KeyStoreConfiguration.createKeyStoreConfiguration( TestConstants.KEYSTORE_FILE, // file - TestConstants.KEYSTORE_PWD, // password + TestConstants.KEYSTORE_PWD(), // password + null, // passwordEnvironmentVariable + null, // passwordFile null, // key store type null); // algorithm final TrustStoreConfiguration tsc = TrustStoreConfiguration.createKeyStoreConfiguration( TestConstants.TRUSTSTORE_FILE, // file - TestConstants.TRUSTSTORE_PWD, // password + TestConstants.TRUSTSTORE_PWD(), // password + null, // passwordEnvironmentVariable + null, // passwordFile null, // key store type null); // algorithm sslConfiguration = SslConfiguration.createSSLConfiguration(null, ksc, tsc); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java index e025fd8..ae567a0 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java @@ -78,8 +78,8 @@ public class TlsSyslogAppenderTest extends SyslogAppenderTest { } private void initServerSocketFactory() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD, null, null); - final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD, null, null); + final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD(), null, null); + final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD(), null, null); sslConfiguration = SslConfiguration.createSSLConfiguration(null, ksc, tsc); serverSocketFactory = sslConfiguration.getSslServerSocketFactory(); } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProviderTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProviderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProviderTest.java new file mode 100644 index 0000000..a9b266f --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/EnvironmentPasswordProviderTest.java @@ -0,0 +1,38 @@ +package org.apache.logging.log4j.core.net.ssl;/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class EnvironmentPasswordProviderTest { + + @Test(expected = NullPointerException.class) + public void testConstructorDisallowsNull() { + new EnvironmentPasswordProvider(null); + } + + @Test + public void testGetPasswordReturnsEnvironmentVariableValue() { + final String value = System.getenv("PATH"); + if (value == null) { + return; // we cannot test in this environment + } + final char[] actual = new EnvironmentPasswordProvider("PATH").getPassword(); + assertArrayEquals(value.toCharArray(), actual); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProviderTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProviderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProviderTest.java new file mode 100644 index 0000000..eaa2d82 --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/FilePasswordProviderTest.java @@ -0,0 +1,50 @@ +package org.apache.logging.log4j.core.net.ssl;/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ + +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.Arrays; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class FilePasswordProviderTest { + + @Test + public void testGetPassword() throws Exception { + final String PASSWORD = "myPass123"; + final Path path = Files.createTempFile("testPass", ".txt"); + Files.write(path, PASSWORD.getBytes(Charset.defaultCharset())); + + char[] actual = new FilePasswordProvider(path.toString()).getPassword(); + Files.delete(path); + assertArrayEquals(PASSWORD.toCharArray(), actual); + } + + @Test(expected = NullPointerException.class) + public void testConstructorDisallowsNull() throws Exception { + new FilePasswordProvider(null); + } + + @Test(expected = NoSuchFileException.class) + public void testConstructorFailsIfFileDoesNotExist() throws Exception { + new FilePasswordProvider("nosuchfile"); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java index ef38483..d5761ac 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfigurationTest.java @@ -37,7 +37,7 @@ public class KeyStoreConfigurationTest { @Test public void loadNotEmptyConfigurationDeprecated() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD, + final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD(), TestConstants.KEYSTORE_TYPE, null); final KeyStore ks = ksc.getKeyStore(); Assert.assertTrue(ks != null); @@ -45,7 +45,7 @@ public class KeyStoreConfigurationTest { @Test public void loadNotEmptyConfiguration() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD), + final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD()), TestConstants.KEYSTORE_TYPE, null); final KeyStore ks = ksc.getKeyStore(); Assert.assertTrue(ks != null); @@ -53,7 +53,7 @@ public class KeyStoreConfigurationTest { @Test public void returnTheSameKeyStoreAfterMultipleLoadsDeprecated() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD, + final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD(), TestConstants.KEYSTORE_TYPE, null); final KeyStore ks = ksc.getKeyStore(); final KeyStore ks2 = ksc.getKeyStore(); @@ -62,7 +62,7 @@ public class KeyStoreConfigurationTest { @Test public void returnTheSameKeyStoreAfterMultipleLoads() throws StoreConfigurationException { - final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD), + final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD()), TestConstants.KEYSTORE_TYPE, null); final KeyStore ks = ksc.getKeyStore(); final KeyStore ks2 = ksc.getKeyStore(); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProviderTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProviderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProviderTest.java new file mode 100644 index 0000000..df4b5f2 --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/MemoryPasswordProviderTest.java @@ -0,0 +1,49 @@ +package org.apache.logging.log4j.core.net.ssl;/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ + +import java.util.Arrays; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class MemoryPasswordProviderTest { + @Test + public void testConstructorAllowsNull() { + assertEquals(null, new MemoryPasswordProvider(null).getPassword()); + } + + @Test + public void testConstructorDoesNotModifyOriginalParameterArray() { + char[] initial = "123".toCharArray(); + new MemoryPasswordProvider(initial); + assertArrayEquals("123".toCharArray(), initial); + } + + @Test + public void testGetPasswordReturnsCopyOfConstructorArray() { + char[] initial = "123".toCharArray(); + MemoryPasswordProvider provider = new MemoryPasswordProvider(initial); + char[] actual = provider.getPassword(); + assertArrayEquals("123".toCharArray(), actual); + assertNotSame(initial, actual); + + Arrays.fill(initial, 'a'); + assertArrayEquals("123".toCharArray(), provider.getPassword()); + assertNotSame(provider.getPassword(), provider.getPassword()); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java index 936cc66..41349a0 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationTest.java @@ -33,33 +33,33 @@ public class SslConfigurationTest { public static SslConfiguration createTestSslConfigurationResourcesDeprecated() throws StoreConfigurationException { final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE_RESOURCE, - TestConstants.KEYSTORE_PWD, TestConstants.KEYSTORE_TYPE, null); + TestConstants.KEYSTORE_PWD(), TestConstants.KEYSTORE_TYPE, null); final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE_RESOURCE, - TestConstants.TRUSTSTORE_PWD, null, null); + TestConstants.TRUSTSTORE_PWD(), null, null); return SslConfiguration.createSSLConfiguration(null, ksc, tsc); } public static SslConfiguration createTestSslConfigurationResources() throws StoreConfigurationException { final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE_RESOURCE, - new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD), TestConstants.KEYSTORE_TYPE, null); + new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD()), TestConstants.KEYSTORE_TYPE, null); final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE_RESOURCE, - new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD), null, null); + new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD()), null, null); return SslConfiguration.createSSLConfiguration(null, ksc, tsc); } public static SslConfiguration createTestSslConfigurationFilesDeprecated() throws StoreConfigurationException { final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, - TestConstants.KEYSTORE_PWD, TestConstants.KEYSTORE_TYPE, null); + TestConstants.KEYSTORE_PWD(), TestConstants.KEYSTORE_TYPE, null); final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, - TestConstants.TRUSTSTORE_PWD, null, null); + TestConstants.TRUSTSTORE_PWD(), null, null); return SslConfiguration.createSSLConfiguration(null, ksc, tsc); } public static SslConfiguration createTestSslConfigurationFiles() throws StoreConfigurationException { final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, - new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD), TestConstants.KEYSTORE_TYPE, null); + new MemoryPasswordProvider(TestConstants.KEYSTORE_PWD()), TestConstants.KEYSTORE_TYPE, null); final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, - new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD), null, null); + new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD()), null, null); return SslConfiguration.createSSLConfiguration(null, ksc, tsc); } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TestConstants.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TestConstants.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TestConstants.java index 1fa8572..90b3bed 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TestConstants.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TestConstants.java @@ -17,24 +17,24 @@ package org.apache.logging.log4j.core.net.ssl; public class TestConstants { - + public static final String SOURCE_FOLDER = "src/test/resources/"; public static final String RESOURCE_ROOT = "org/apache/logging/log4j/core/net/ssl/"; - + public static final String PATH = SOURCE_FOLDER + RESOURCE_ROOT; public static final String TRUSTSTORE_PATH = PATH; public static final String TRUSTSTORE_RESOURCE = RESOURCE_ROOT; public static final String TRUSTSTORE_FILE = TRUSTSTORE_PATH + "truststore.jks"; public static final String TRUSTSTORE_FILE_RESOURCE = TRUSTSTORE_RESOURCE + "truststore.jks"; - public static final char[] TRUSTSTORE_PWD = "changeit".toCharArray(); + public static final char[] TRUSTSTORE_PWD() { return "changeit".toCharArray(); } public static final String TRUSTSTORE_TYPE = "JKS"; public static final String KEYSTORE_PATH = PATH; public static final String KEYSTORE_RESOURCE = RESOURCE_ROOT; public static final String KEYSTORE_FILE = KEYSTORE_PATH + "client.log4j2-keystore.jks"; public static final String KEYSTORE_FILE_RESOURCE = KEYSTORE_RESOURCE + "client.log4j2-keystore.jks"; - public static final char[] KEYSTORE_PWD = "changeit".toCharArray(); + public static final char[] KEYSTORE_PWD() { return "changeit".toCharArray(); } public static final String KEYSTORE_TYPE = "JKS"; - + public static final char[] NULL_PWD = null; } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java index 14c58bb..d27a1fd 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfigurationTest.java @@ -37,21 +37,21 @@ public class TrustStoreConfigurationTest { @Test public void loadConfigurationDeprecated() throws StoreConfigurationException { - final TrustStoreConfiguration ksc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD, null, null); + final TrustStoreConfiguration ksc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD(), null, null); final KeyStore ks = ksc.getKeyStore(); Assert.assertNotNull(ks); } @Test public void loadConfiguration() throws StoreConfigurationException { - final TrustStoreConfiguration ksc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD), null, null); + final TrustStoreConfiguration ksc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD()), null, null); final KeyStore ks = ksc.getKeyStore(); Assert.assertNotNull(ks); } @Test public void returnTheSameKeyStoreAfterMultipleLoadsDeprecated() throws StoreConfigurationException { - final TrustStoreConfiguration ksc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD, null, null); + final TrustStoreConfiguration ksc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD(), null, null); final KeyStore ks = ksc.getKeyStore(); final KeyStore ks2 = ksc.getKeyStore(); Assert.assertTrue(ks == ks2); @@ -59,7 +59,7 @@ public class TrustStoreConfigurationTest { @Test public void returnTheSameKeyStoreAfterMultipleLoads() throws StoreConfigurationException { - final TrustStoreConfiguration ksc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD), null, null); + final TrustStoreConfiguration ksc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, new MemoryPasswordProvider(TestConstants.TRUSTSTORE_PWD()), null, null); final KeyStore ks = ksc.getKeyStore(); final KeyStore ks2 = ksc.getKeyStore(); Assert.assertTrue(ks == ks2); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 55b18f9..94b1033 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -31,6 +31,9 @@ - "remove" - Removed --> <release version="2.9.2" date="2017-XX-XX" description="GA Release 2.9.2"> + <action issue="LOG4J2-2054" dev="rpopma" type="add"> + Provide ways to configure SSL that avoid plain-text passwords in the log4j configuration. The configuration may now specify a system environment variable that holds the password, or the path to a file that holds the password. + </action> <action issue="LOG4J2-2057" dev="rgoers" type="update"> Support new SLF4J binding mechanism introduced in SLF4J 1.8. </action> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/src/site/site.xml ---------------------------------------------------------------------- diff --git a/src/site/site.xml b/src/site/site.xml index dca832a..6de65be 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -147,6 +147,7 @@ <item name="SMTP" href="/manual/appenders.html#SMTPAppender"/> <item name="ScriptAppenderSelector" href="/manual/appenders.html#ScriptAppenderSelector"/> <item name="Socket" href="/manual/appenders.html#SocketAppender"/> + <item name="SSL" href="/manual/appenders.html#SSL"/> <item name="Syslog" href="/manual/appenders.html#SyslogAppender"/> <item name="ZeroMQ/JeroMQ" href="/manual/appenders.html#JeroMQAppender"/> </item> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08077cba/src/site/xdoc/manual/appenders.xml ---------------------------------------------------------------------- diff --git a/src/site/xdoc/manual/appenders.xml b/src/site/xdoc/manual/appenders.xml index c4982c0..b9ef28a 100644 --- a/src/site/xdoc/manual/appenders.xml +++ b/src/site/xdoc/manual/appenders.xml @@ -1658,7 +1658,7 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { <td>Ssl</td> <td>SslConfiguration</td> <td>Contains the configuration for the KeyStore and TrustStore for https. - Optional, uses Java runtime defaults if not specified.</td> + Optional, uses Java runtime defaults if not specified. See <a href="#SSL">SSL</a></td> </tr> <tr> <td>verifyHostname</td> @@ -1710,8 +1710,8 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { <Property name="X-Java-Runtime" value="$${java:runtime}" /> <JsonLayout properties="true"/> <SSL> - <KeyStore location="log4j2-keystore.jks" password="changeme"/> - <TrustStore location="truststore.jks" password="changeme"/> + <KeyStore location="log4j2-keystore.jks" passwordEnvironmentVariable="KEYSTORE_PASSWORD"/> + <TrustStore location="truststore.jks" passwordFile="${sys:user.home}/truststore.pwd"/> </SSL> </Http> </Appenders>]]></pre> @@ -4355,7 +4355,7 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { <p> The <code>SocketAppender</code> is an OutputStreamAppender that writes its output to a remote destination specified by a host and port. The data can be sent over either TCP or UDP and can be sent in any format. - You can optionally secure communication with SSL. + You can optionally secure communication with <a href="#SSL">SSL</a>. </p> <table> <caption align="top"><code>SocketAppender</code> Parameters</caption> @@ -4387,7 +4387,7 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { <tr> <td>SSL</td> <td>SslConfiguration</td> - <td>Contains the configuration for the KeyStore and TrustStore.</td> + <td>Contains the configuration for the KeyStore and TrustStore. See <a href="#SSL">SSL</a>.</td> </tr> <tr> <td>filter</td> @@ -4467,7 +4467,7 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { </Configuration>]]></pre> <p> - This is a secured SSL configuration: + This is a secured <a href="#SSL">SSL</a> configuration: </p> <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?> <Configuration status="warn" name="MyApp" packages=""> @@ -4475,8 +4475,8 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { <Socket name="socket" host="localhost" port="9500"> <JsonLayout properties="true"/> <SSL> - <KeyStore location="log4j2-keystore.jks" password="changeme"/> - <TrustStore location="truststore.jks" password="changeme"/> + <KeyStore location="log4j2-keystore.jks" passwordEnvironmentVariable="KEYSTORE_PASSWORD"/> + <TrustStore location="truststore.jks" passwordFile="${sys:user.home}/truststore.pwd"/> </SSL> </Socket> </Appenders> @@ -4488,6 +4488,154 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { </Configuration>]]></pre> </subsection> + <a name="SSL" /> + <subsection name="SSL Configuration"> + <p> + Several appenders can be configured to use either a plain network connection or a Secure Socket Layer (SSL) + connection. This section documents the parameters available for SSL configuration. + </p> + <table> + <caption align="top">SSL Configuration Parameters</caption> + <tr> + <th>Parameter Name</th> + <th>Type</th> + <th>Description</th> + </tr> + <tr> + <td>protocol</td> + <td>String</td> + <td><code>SSL</code> if omitted. + See also <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext">Standard names</a>.</td> + </tr> + <tr> + <td>KeyStore</td> + <td>KeyStore</td> + <td>Contains your private keys and certificates, + and determines which authentication credentials to send to the remote host.</td> + </tr> + <tr> + <td>TrustStore</td> + <td>TrustStore</td> + <td>Contains the CA certificates of the remote counterparty. + Determines whether the remote authentication credentials + (and thus the connection) should be trusted.</td> + </tr> + </table> + + <h4>KeyStore</h4> + The keystore is meant to contain your private keys and certificates, + and determines which authentication credentials to send to the remote host. + + <table> + <caption align="top">KeyStore Configuration Parameters</caption> + <tr> + <th>Parameter Name</th> + <th>Type</th> + <th>Description</th> + </tr> + <tr> + <td>location</td> + <td>String</td> + <td>Path to the keystore file.</td> + </tr> + <tr> + <td>password</td> + <td>char[]</td> + <td>Plain text password to access the keystore. Cannot be combined with either + <code>passwordEnvironmentVariable</code> or <code>passwordFile</code>.</td> + </tr> + <tr> + <td>passwordEnvironmentVariable</td> + <td>String</td> + <td>Name of an environment variable that holds the password. Cannot be combined with either + <code>password</code> or <code>passwordFile</code>.</td> + </tr> + <tr> + <td>passwordFile</td> + <td>String</td> + <td>Path to a file that holds the password. Cannot be combined with either + <code>password</code> or <code>passwordEnvironmentVariable</code>.</td> + </tr> + <tr> + <td>type</td> + <td>String</td> + <td>Optional KeyStore type, e.g. <code>JKS</code>, <code>PKCS12</code>, <code>PKCS11</code>, + <code>BKS</code>, <code>Windows-MY/Windows-ROOT</code>, <code>KeychainStore</code>, etc. + The default is JKS. See also <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyStore">Standard types</a>.</td> + </tr> + <tr> + <td>keyManagerFactoryAlgorithm</td> + <td>String</td> + <td>Optional KeyManagerFactory algorithm. The default is <code>SunX509</code>. + See also <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyManagerFactory">Standard algorithms</a>.</td> + </tr> + </table> + + <h4>TrustStore</h4> + <p> + The trust store is meant to contain the CA certificates you are willing to trust + when a remote party presents its certificate. Determines whether the remote authentication credentials + (and thus the connection) should be trusted. + </p><p> + In some cases, they can be one and the same store, + although it is often better practice to use distinct stores (especially when they are file-based). + </p> + + <table> + <caption align="top">TrustStore Configuration Parameters</caption> + <tr> + <th>Parameter Name</th> + <th>Type</th> + <th>Description</th> + </tr> + <tr> + <td>location</td> + <td>String</td> + <td>Path to the keystore file.</td> + </tr> + <tr> + <td>password</td> + <td>char[]</td> + <td>Plain text password to access the keystore. Cannot be combined with either + <code>passwordEnvironmentVariable</code> or <code>passwordFile</code>.</td> + </tr> + <tr> + <td>passwordEnvironmentVariable</td> + <td>String</td> + <td>Name of an environment variable that holds the password. Cannot be combined with either + <code>password</code> or <code>passwordFile</code>.</td> + </tr> + <tr> + <td>passwordFile</td> + <td>String</td> + <td>Path to a file that holds the password. Cannot be combined with either + <code>password</code> or <code>passwordEnvironmentVariable</code>.</td> + </tr> + <tr> + <td>type</td> + <td>String</td> + <td>Optional KeyStore type, e.g. <code>JKS</code>, <code>PKCS12</code>, <code>PKCS11</code>, + <code>BKS</code>, <code>Windows-MY/Windows-ROOT</code>, <code>KeychainStore</code>, etc. + The default is JKS. See also <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyStore">Standard types</a>.</td> + </tr> + <tr> + <td>trustManagerFactoryAlgorithm</td> + <td>String</td> + <td>Optional TrustManagerFactory algorithm. The default is <code>SunX509</code>. + See also <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#TrustManagerFactory">Standard algorithms</a>.</td> + </tr> + </table> + + <h4>Example</h4> + <pre class="prettyprint linenums"><![CDATA[ + ... + <SSL> + <KeyStore location="log4j2-keystore.jks" passwordEnvironmentVariable="KEYSTORE_PASSWORD"/> + <TrustStore location="truststore.jks" passwordFile="${sys:user.home}/truststore.pwd"/> + </SSL> + ...]]></pre> + + </subsection> <a name="SyslogAppender"/> <subsection name="SyslogAppender"> <p> @@ -4659,7 +4807,7 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { <tr> <td>SSL</td> <td>SslConfiguration</td> - <td>Contains the configuration for the KeyStore and TrustStore.</td> + <td>Contains the configuration for the KeyStore and TrustStore. See <a href="#SSL">SSL</a>.</td> </tr> <tr> <td>reconnectionDelayMillis</td> @@ -4695,7 +4843,7 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { </Configuration>]]></pre> <p> - For SSL this appender writes its output to a remote destination specified by a host and port over SSL in + For <a href="#SSL">SSL</a> this appender writes its output to a remote destination specified by a host and port over SSL in a format that conforms with either the BSD Syslog format or the RFC 5424 format. </p> @@ -4704,8 +4852,8 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { <Appenders> <TLSSyslog name="bsd" host="localhost" port="6514"> <SSL> - <KeyStore location="log4j2-keystore.jks" password="changeme"/> - <TrustStore location="truststore.jks" password="changeme"/> + <KeyStore location="log4j2-keystore.jks" passwordEnvironmentVariable="KEYSTORE_PASSWORD"/> + <TrustStore location="truststore.jks" passwordFile="${sys:user.home}/truststore.pwd"/> </SSL> </TLSSyslog> </Appenders>
