mirror of https://github.com/apache/nifi.git
NIFI-6830 Added regression test. Added failing unit test. Added Test Resources.
Implemented KeyPassword detection in the SSLContextFactory. Resolved Java 8/11 unit test issue. Fixed unit test wildcard imports and added Javadoc to test helper methods. This closes #3873. Signed-off-by: Andy LoPresto <alopresto@apache.org>
This commit is contained in:
parent
49b7a7cd6b
commit
36bdb474c3
|
@ -26,6 +26,7 @@ import java.security.NoSuchAlgorithmException;
|
|||
import java.security.SecureRandom;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
|
@ -42,6 +43,7 @@ public class SSLContextFactory {
|
|||
private final String keystore;
|
||||
private final char[] keystorePass;
|
||||
private final String keystoreType;
|
||||
private final char[] keyPassword;
|
||||
private final String truststore;
|
||||
private final char[] truststorePass;
|
||||
private final String truststoreType;
|
||||
|
@ -53,6 +55,7 @@ public class SSLContextFactory {
|
|||
keystore = properties.getProperty(NiFiProperties.SECURITY_KEYSTORE);
|
||||
keystorePass = getPass(properties.getProperty(NiFiProperties.SECURITY_KEYSTORE_PASSWD));
|
||||
keystoreType = properties.getProperty(NiFiProperties.SECURITY_KEYSTORE_TYPE);
|
||||
keyPassword = getPass(properties.getProperty(NiFiProperties.SECURITY_KEY_PASSWD));
|
||||
|
||||
truststore = properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE);
|
||||
truststorePass = getPass(properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD));
|
||||
|
@ -67,7 +70,11 @@ public class SSLContextFactory {
|
|||
FileUtils.closeQuietly(keyStoreStream);
|
||||
}
|
||||
final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
keyManagerFactory.init(keyStore, keystorePass);
|
||||
if (keyPassword != null && !Arrays.equals(keyPassword, keystorePass)) {
|
||||
keyManagerFactory.init(keyStore, keyPassword);
|
||||
} else {
|
||||
keyManagerFactory.init(keyStore, keystorePass);
|
||||
}
|
||||
|
||||
// prepare the truststore
|
||||
final KeyStore trustStore = KeyStoreUtils.getTrustStore(truststoreType);
|
||||
|
@ -91,14 +98,13 @@ public class SSLContextFactory {
|
|||
/**
|
||||
* Creates a SSLContext instance using the given information.
|
||||
*
|
||||
*
|
||||
* @return a SSLContext instance
|
||||
* @throws java.security.KeyStoreException if problem with keystore
|
||||
* @throws java.io.IOException if unable to create context
|
||||
* @throws java.security.NoSuchAlgorithmException if algorithm isn't known
|
||||
* @throws java.security.KeyStoreException if problem with keystore
|
||||
* @throws java.io.IOException if unable to create context
|
||||
* @throws java.security.NoSuchAlgorithmException if algorithm isn't known
|
||||
* @throws java.security.cert.CertificateException if certificate is invalid
|
||||
* @throws java.security.UnrecoverableKeyException if the key cannot be recovered
|
||||
* @throws java.security.KeyManagementException if the key is improper
|
||||
* @throws java.security.KeyManagementException if the key is improper
|
||||
*/
|
||||
public SSLContext createSslContext() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException,
|
||||
UnrecoverableKeyException, KeyManagementException {
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* 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.nifi.io.socket
|
||||
|
||||
import org.apache.nifi.util.NiFiProperties
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.junit.After
|
||||
import org.junit.AfterClass
|
||||
import org.junit.Before
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import javax.net.ssl.SSLContext
|
||||
import java.security.Security
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
class SSLContextFactoryTest extends GroovyTestCase {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SSLContextFactoryTest.class)
|
||||
|
||||
private static String NF_PROPS_FILE = null
|
||||
|
||||
@BeforeClass
|
||||
static void setUpOnce() throws Exception {
|
||||
Security.addProvider(new BouncyCastleProvider())
|
||||
|
||||
if (System.getProperty(NiFiProperties.PROPERTIES_FILE_PATH)) {
|
||||
NF_PROPS_FILE = System.getProperty(NiFiProperties.PROPERTIES_FILE_PATH)
|
||||
System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, null)
|
||||
}
|
||||
|
||||
logger.metaClass.methodMissing = { String name, args ->
|
||||
logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
void setUp() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
static void tearDownOnce() throws Exception {
|
||||
if (NF_PROPS_FILE) {
|
||||
System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, NF_PROPS_FILE)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link NiFiProperties} object configured with default values for accessing
|
||||
* keystores and truststores. The values can be overridden by providing a map parameter.
|
||||
*
|
||||
* @param overrides an optional Map of overriding configuration values
|
||||
* @return the configured NiFiProperties object
|
||||
*/
|
||||
private static NiFiProperties buildNiFiProperties(Map<String, String> overrides = [:]) {
|
||||
final Map DEFAULTS = [
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD) : "keystorepassword",
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : "src/test/resources/samepassword.jks",
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE) : "JKS",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD): "changeit",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE) : buildCacertsPath(),
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_TYPE) : "JKS",
|
||||
]
|
||||
DEFAULTS.putAll(overrides)
|
||||
NiFiProperties.createBasicNiFiProperties(null, DEFAULTS)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file path to the {@code cacerts} default JRE truststore. Handles Java 8
|
||||
* and earlier as well as Java 9 and later directory structures.
|
||||
*
|
||||
* @return the path to cacerts
|
||||
*/
|
||||
private static String buildCacertsPath() {
|
||||
String javaHome = System.getenv("JAVA_HOME")
|
||||
if (System.getProperty("java.version").startsWith("1.")) {
|
||||
javaHome + "/jre/lib/security/cacerts"
|
||||
} else {
|
||||
javaHome + "/lib/security/cacerts"
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldVerifyKeystoreWithSameKeyPassword() throws Exception {
|
||||
// Arrange
|
||||
|
||||
// Set up the keystore configuration as NiFiProperties object
|
||||
NiFiProperties np = buildNiFiProperties()
|
||||
|
||||
// Create the SSLContextFactory with the config
|
||||
SSLContextFactory sslcf = new SSLContextFactory(np)
|
||||
|
||||
// Act
|
||||
|
||||
// Access the SSLContextFactory to create an SSLContext
|
||||
SSLContext sslContext = sslcf.createSslContext()
|
||||
|
||||
// Assert
|
||||
|
||||
// The SSLContext was accessible and correct
|
||||
assert sslContext
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldVerifyKeystoreWithDifferentKeyPassword() throws Exception {
|
||||
// Arrange
|
||||
|
||||
// Set up the keystore configuration as NiFiProperties object
|
||||
// (prior to NIFI-6830, an UnrecoverableKeyException was thrown due to the wrong password being provided)
|
||||
NiFiProperties np = buildNiFiProperties([
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : "src/test/resources/differentpassword.jks",
|
||||
(NiFiProperties.SECURITY_KEY_PASSWD): "keypassword",
|
||||
])
|
||||
|
||||
// Create the SSLContextFactory with the config
|
||||
SSLContextFactory sslcf = new SSLContextFactory(np)
|
||||
|
||||
// Act
|
||||
|
||||
// Access the SSLContextFactory to create an SSLContext
|
||||
SSLContext sslContext = sslcf.createSslContext()
|
||||
|
||||
// Assert
|
||||
|
||||
// The SSLContext was accessible and correct
|
||||
assert sslContext
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue