blob: 51cdf0508c381e029d86e993670c461e0896e4fa [file] [log] [blame]
/*
* 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.knox.gateway.services.security.impl;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.services.security.AliasService;
import org.apache.knox.gateway.services.security.AliasServiceException;
import org.apache.knox.gateway.services.security.KeystoreService;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.Test;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.UnrecoverableKeyException;
public class JettySSLServiceTest {
@Test
public void TestBuildSslContextFactoryOnlyIdentityKeystore() throws Exception {
String basedir = System.getProperty("basedir");
if (basedir == null) {
basedir = new File(".").getCanonicalPath();
}
Path identityKeystorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-keystore.jks");
String identityKeystoreType = "jks";
char[] identityKeystorePassword = "horton".toCharArray();
char[] identityKeyPassphrase = "horton".toCharArray();
String identityKeyAlias = "server";
Path truststorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-truststore.jks");
String truststoreType = "jks";
String truststorePasswordAlias = "trust_store_password";
GatewayConfig config = createGatewayConfig(false, false, identityKeystorePath, identityKeystoreType, identityKeyAlias, truststorePath, truststoreType, truststorePasswordAlias);
AliasService aliasService = createMock(AliasService.class);
expect(aliasService.getGatewayIdentityKeystorePassword()).andReturn(identityKeystorePassword).atLeastOnce();
expect(aliasService.getGatewayIdentityPassphrase()).andReturn(identityKeyPassphrase).atLeastOnce();
KeystoreService keystoreService = createMock(KeystoreService.class);
replay(config, aliasService, keystoreService);
JettySSLService sslService = new JettySSLService();
sslService.setAliasService(aliasService);
sslService.setKeystoreService(keystoreService);
Object result = sslService.buildSslContextFactory(config);
assertNotNull(result);
assertTrue(result instanceof SslContextFactory);
SslContextFactory sslContextFactory = (SslContextFactory) result;
sslContextFactory.start();
assertEquals(identityKeystorePath.toUri().toString(), sslContextFactory.getKeyStorePath());
assertEquals(identityKeystoreType, sslContextFactory.getKeyStoreType());
assertNotNull(sslContextFactory.getKeyStore());
assertNull(sslContextFactory.getTrustStorePath());
assertNull(sslContextFactory.getTrustStoreType());
// If the truststore is not set, by default the identity keystore is used by Jetty.
assertEquals(sslContextFactory.getKeyStore().size(), sslContextFactory.getTrustStore().size());
assertTrue(sslContextFactory.getTrustStore().containsAlias(identityKeyAlias));
verify(config, aliasService, keystoreService);
}
@Test(expected = AliasServiceException.class)
public void TestBuildSslContextFactoryOnlyIdentityKeystoreErrorGettingPassword() throws Exception {
String basedir = System.getProperty("basedir");
if (basedir == null) {
basedir = new File(".").getCanonicalPath();
}
Path identityKeystorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-keystore.jks");
String identityKeystoreType = "jks";
char[] identityKeyPassphrase = "horton".toCharArray();
String identityKeyAlias = "server";
Path truststorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-truststore.jks");
String truststoreType = "jks";
String truststorePasswordAlias = "trust_store_password";
GatewayConfig config = createGatewayConfig(false, false, identityKeystorePath, identityKeystoreType, identityKeyAlias, truststorePath, truststoreType, truststorePasswordAlias);
AliasService aliasService = createMock(AliasService.class);
expect(aliasService.getGatewayIdentityKeystorePassword()).andThrow(new AliasServiceException(null)).atLeastOnce();
expect(aliasService.getGatewayIdentityPassphrase()).andReturn(identityKeyPassphrase).atLeastOnce();
KeystoreService keystoreService = createMock(KeystoreService.class);
replay(config, aliasService, keystoreService);
JettySSLService sslService = new JettySSLService();
sslService.setAliasService(aliasService);
sslService.setKeystoreService(keystoreService);
sslService.buildSslContextFactory(config);
fail("AliasServiceException should have been thrown");
}
@Test
public void TestBuildSslContextFactoryOnlyIdentityKeystoreNullKeystorePassword() throws Exception {
String basedir = System.getProperty("basedir");
if (basedir == null) {
basedir = new File(".").getCanonicalPath();
}
Path identityKeystorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-keystore.jks");
String identityKeystoreType = "jks";
char[] identityKeyPassphrase = "horton".toCharArray();
String identityKeyAlias = "server";
Path truststorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-truststore.jks");
String truststoreType = "jks";
String truststorePasswordAlias = "trust_store_password";
GatewayConfig config = createGatewayConfig(false, false, identityKeystorePath, identityKeystoreType, identityKeyAlias, truststorePath, truststoreType, truststorePasswordAlias);
AliasService aliasService = createMock(AliasService.class);
expect(aliasService.getGatewayIdentityKeystorePassword()).andReturn(null).atLeastOnce();
expect(aliasService.getGatewayIdentityPassphrase()).andReturn(identityKeyPassphrase).atLeastOnce();
KeystoreService keystoreService = createMock(KeystoreService.class);
replay(config, aliasService, keystoreService);
JettySSLService sslService = new JettySSLService();
sslService.setAliasService(aliasService);
sslService.setKeystoreService(keystoreService);
Object result = sslService.buildSslContextFactory(config);
assertNotNull(result);
assertTrue(result instanceof SslContextFactory);
SslContextFactory sslContextFactory = (SslContextFactory) result;
sslContextFactory.start();
assertEquals(identityKeystorePath.toUri().toString(), sslContextFactory.getKeyStorePath());
assertEquals(identityKeystoreType, sslContextFactory.getKeyStoreType());
assertNotNull(sslContextFactory.getKeyStore());
assertNull(sslContextFactory.getTrustStorePath());
assertNull(sslContextFactory.getTrustStoreType());
// If the truststore is not set, by default the identity keystore is used by Jetty.
assertEquals(sslContextFactory.getKeyStore().size(), sslContextFactory.getTrustStore().size());
assertTrue(sslContextFactory.getTrustStore().containsAlias(identityKeyAlias));
verify(config, aliasService, keystoreService);
// Note: The key password is used if the keystore password is not set; and vice versa
}
@Test(expected = UnrecoverableKeyException.class)
public void TestBuildSslContextFactoryOnlyIdentityKeystoreNullKeyPassword() throws Exception {
String basedir = System.getProperty("basedir");
if (basedir == null) {
basedir = new File(".").getCanonicalPath();
}
Path identityKeystorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-keystore.jks");
String identityKeystoreType = "jks";
String identityKeyAlias = "server";
Path truststorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-truststore.jks");
String truststoreType = "jks";
String truststorePasswordAlias = "trust_store_password";
GatewayConfig config = createGatewayConfig(false, false, identityKeystorePath, identityKeystoreType, identityKeyAlias, truststorePath, truststoreType, truststorePasswordAlias);
AliasService aliasService = createMock(AliasService.class);
expect(aliasService.getGatewayIdentityKeystorePassword()).andReturn(null).atLeastOnce();
expect(aliasService.getGatewayIdentityPassphrase()).andReturn(null).atLeastOnce();
KeystoreService keystoreService = createMock(KeystoreService.class);
replay(config, aliasService, keystoreService);
JettySSLService sslService = new JettySSLService();
sslService.setAliasService(aliasService);
sslService.setKeystoreService(keystoreService);
Object result = sslService.buildSslContextFactory(config);
assertNotNull(result);
assertTrue(result instanceof SslContextFactory);
SslContextFactory sslContextFactory = (SslContextFactory) result;
sslContextFactory.start();
fail("UnrecoverableKeyException should have been thrown");
}
@Test
public void TestBuildSslContextFactoryImplicitTrustStore() throws Exception {
String basedir = System.getProperty("basedir");
if (basedir == null) {
basedir = new File(".").getCanonicalPath();
}
Path identityKeystorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-keystore.jks");
String identityKeystoreType = "jks";
char[] identityKeystorePassword = "horton".toCharArray();
char[] identityKeyPassphrase = "horton".toCharArray();
String identityKeyAlias = "server";
Path truststorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-truststore.jks");
String truststoreType = "jks";
String truststorePasswordAlias = "trust_store_password";
GatewayConfig config = createGatewayConfig(true, false, identityKeystorePath, identityKeystoreType, identityKeyAlias, truststorePath, truststoreType, truststorePasswordAlias);
AliasService aliasService = createMock(AliasService.class);
expect(aliasService.getGatewayIdentityKeystorePassword()).andReturn(identityKeystorePassword).atLeastOnce();
expect(aliasService.getGatewayIdentityPassphrase()).andReturn(identityKeyPassphrase).atLeastOnce();
KeystoreService keystoreService = createMock(KeystoreService.class);
replay(config, aliasService, keystoreService);
JettySSLService sslService = new JettySSLService();
sslService.setAliasService(aliasService);
sslService.setKeystoreService(keystoreService);
Object result = sslService.buildSslContextFactory(config);
assertNotNull(result);
assertTrue(result instanceof SslContextFactory);
SslContextFactory sslContextFactory = (SslContextFactory) result;
sslContextFactory.start();
assertEquals(identityKeystorePath.toUri().toString(), sslContextFactory.getKeyStorePath());
assertEquals(identityKeystoreType, sslContextFactory.getKeyStoreType());
assertNotNull(sslContextFactory.getKeyStore());
assertEquals(identityKeystorePath.toUri().toString(), sslContextFactory.getTrustStorePath());
assertEquals(identityKeystoreType, sslContextFactory.getTrustStoreType());
// The truststore is expected to be the same as the identity keystore
assertEquals(sslContextFactory.getKeyStore().size(), sslContextFactory.getTrustStore().size());
assertTrue(sslContextFactory.getTrustStore().containsAlias(identityKeyAlias));
verify(config, aliasService, keystoreService);
}
@Test
public void TestBuildSslContextFactoryExplicitTrustStore() throws Exception {
String basedir = System.getProperty("basedir");
if (basedir == null) {
basedir = new File(".").getCanonicalPath();
}
Path identityKeystorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-keystore.jks");
String identityKeystoreType = "jks";
char[] identityKeystorePassword = "horton".toCharArray();
char[] identityKeyPassphrase = "horton".toCharArray();
String identityKeyAlias = "server";
Path truststorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-truststore.jks");
String truststoreType = "jks";
char[] truststorePassword = "horton".toCharArray();
String truststorePasswordAlias = "trust_store_password";
GatewayConfig config = createGatewayConfig(true, true, identityKeystorePath, identityKeystoreType, identityKeyAlias, truststorePath, truststoreType, truststorePasswordAlias);
AliasService aliasService = createMock(AliasService.class);
expect(aliasService.getGatewayIdentityKeystorePassword()).andReturn(identityKeystorePassword).atLeastOnce();
expect(aliasService.getGatewayIdentityPassphrase()).andReturn(identityKeyPassphrase).atLeastOnce();
expect(aliasService.getPasswordFromAliasForGateway(eq(truststorePasswordAlias))).andReturn(truststorePassword).atLeastOnce();
KeystoreService keystoreService = createMock(KeystoreService.class);
replay(config, aliasService, keystoreService);
JettySSLService sslService = new JettySSLService();
sslService.setAliasService(aliasService);
sslService.setKeystoreService(keystoreService);
Object result = sslService.buildSslContextFactory(config);
assertNotNull(result);
assertTrue(result instanceof SslContextFactory);
SslContextFactory sslContextFactory = (SslContextFactory) result;
sslContextFactory.start();
assertEquals(identityKeystorePath.toUri().toString(), sslContextFactory.getKeyStorePath());
assertEquals(identityKeystoreType, sslContextFactory.getKeyStoreType());
assertNotNull(sslContextFactory.getKeyStore());
assertEquals(truststorePath.toUri().toString(), sslContextFactory.getTrustStorePath());
assertEquals(truststoreType, sslContextFactory.getTrustStoreType());
assertNotNull(sslContextFactory.getTrustStore());
// The truststore is expected to be different than the identity keystore
assertTrue(sslContextFactory.getKeyStore().containsAlias(identityKeyAlias));
assertFalse(sslContextFactory.getTrustStore().containsAlias(identityKeyAlias));
verify(config, aliasService, keystoreService);
}
@Test(expected = AliasServiceException.class)
public void TestBuildSslContextFactoryExplicitTrustStoreErrorGettingPassword() throws Exception {
String basedir = System.getProperty("basedir");
if (basedir == null) {
basedir = new File(".").getCanonicalPath();
}
Path identityKeystorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-keystore.jks");
String identityKeystoreType = "jks";
char[] identityKeystorePassword = "horton".toCharArray();
char[] identityKeyPassphrase = "horton".toCharArray();
String identityKeyAlias = "server";
Path truststorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-truststore.jks");
String truststoreType = "jks";
String truststorePasswordAlias = "trust_store_password";
GatewayConfig config = createGatewayConfig(true, true, identityKeystorePath, identityKeystoreType, identityKeyAlias, truststorePath, truststoreType, truststorePasswordAlias);
AliasService aliasService = createMock(AliasService.class);
expect(aliasService.getGatewayIdentityKeystorePassword()).andReturn(identityKeystorePassword).atLeastOnce();
expect(aliasService.getGatewayIdentityPassphrase()).andReturn(identityKeyPassphrase).atLeastOnce();
expect(aliasService.getPasswordFromAliasForGateway(eq(truststorePasswordAlias))).andThrow(new AliasServiceException(null)).atLeastOnce();
KeystoreService keystoreService = createMock(KeystoreService.class);
replay(config, aliasService, keystoreService);
JettySSLService sslService = new JettySSLService();
sslService.setAliasService(aliasService);
sslService.setKeystoreService(keystoreService);
sslService.buildSslContextFactory(config);
fail("AliasServiceException should have been thrown");
}
@Test
public void TestBuildSslContextFactoryExplicitTrustStoreNullPassword() throws Exception {
String basedir = System.getProperty("basedir");
if (basedir == null) {
basedir = new File(".").getCanonicalPath();
}
Path identityKeystorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-keystore.jks");
String identityKeystoreType = "jks";
char[] identityKeystorePassword = "horton".toCharArray();
char[] identityKeyPassphrase = "horton".toCharArray();
String identityKeyAlias = "server";
Path truststorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-truststore.jks");
String truststoreType = "jks";
String truststorePasswordAlias = "trust_store_password";
GatewayConfig config = createGatewayConfig(true, true, identityKeystorePath, identityKeystoreType, identityKeyAlias, truststorePath, truststoreType, truststorePasswordAlias);
AliasService aliasService = createMock(AliasService.class);
expect(aliasService.getGatewayIdentityKeystorePassword()).andReturn(identityKeystorePassword).atLeastOnce();
expect(aliasService.getGatewayIdentityPassphrase()).andReturn(identityKeyPassphrase).atLeastOnce();
expect(aliasService.getPasswordFromAliasForGateway(eq(truststorePasswordAlias))).andReturn(null).atLeastOnce();
KeystoreService keystoreService = createMock(KeystoreService.class);
replay(config, aliasService, keystoreService);
JettySSLService sslService = new JettySSLService();
sslService.setAliasService(aliasService);
sslService.setKeystoreService(keystoreService);
Object result = sslService.buildSslContextFactory(config);
assertNotNull(result);
assertTrue(result instanceof SslContextFactory);
SslContextFactory sslContextFactory = (SslContextFactory) result;
sslContextFactory.start();
assertEquals(identityKeystorePath.toUri().toString(), sslContextFactory.getKeyStorePath());
assertEquals(identityKeystoreType, sslContextFactory.getKeyStoreType());
assertNotNull(sslContextFactory.getKeyStore());
assertEquals(truststorePath.toUri().toString(), sslContextFactory.getTrustStorePath());
assertEquals(truststoreType, sslContextFactory.getTrustStoreType());
assertNotNull(sslContextFactory.getTrustStore());
// The truststore is expected to be different than the identity keystore
assertTrue(sslContextFactory.getKeyStore().containsAlias(identityKeyAlias));
assertFalse(sslContextFactory.getTrustStore().containsAlias(identityKeyAlias));
verify(config, aliasService, keystoreService);
// Note: The keystore password is used if the truststore password is not set
}
@Test(expected = UnrecoverableKeyException.class)
public void TestBuildSslContextFactoryExplicitTrustStoreNullPasswords() throws Exception {
String basedir = System.getProperty("basedir");
if (basedir == null) {
basedir = new File(".").getCanonicalPath();
}
Path identityKeystorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-keystore.jks");
String identityKeystoreType = "jks";
String identityKeyAlias = "server";
Path truststorePath = Paths.get(basedir, "target", "test-classes", "keystores", "server-truststore.jks");
String truststoreType = "jks";
String truststorePasswordAlias = "trust_store_password";
GatewayConfig config = createGatewayConfig(true, true, identityKeystorePath, identityKeystoreType, identityKeyAlias, truststorePath, truststoreType, truststorePasswordAlias);
AliasService aliasService = createMock(AliasService.class);
expect(aliasService.getGatewayIdentityKeystorePassword()).andReturn(null).atLeastOnce();
expect(aliasService.getGatewayIdentityPassphrase()).andReturn(null).atLeastOnce();
expect(aliasService.getPasswordFromAliasForGateway(eq(truststorePasswordAlias))).andReturn(null).atLeastOnce();
KeystoreService keystoreService = createMock(KeystoreService.class);
replay(config, aliasService, keystoreService);
JettySSLService sslService = new JettySSLService();
sslService.setAliasService(aliasService);
sslService.setKeystoreService(keystoreService);
Object result = sslService.buildSslContextFactory(config);
assertNotNull(result);
assertTrue(result instanceof SslContextFactory);
SslContextFactory sslContextFactory = (SslContextFactory) result;
sslContextFactory.start();
fail("UnrecoverableKeyException should have been thrown");
}
private GatewayConfig createGatewayConfig(boolean isClientAuthNeeded, boolean isExplicitTruststore,
Path identityKeystorePath, String identityKeystoreType,
String identityKeyAlias, Path truststorePath,
String truststoreType, String trustStorePasswordAlias) {
GatewayConfig config = createMock(GatewayConfig.class);
expect(config.getIdentityKeystorePath()).andReturn(identityKeystorePath.toString()).atLeastOnce();
expect(config.getIdentityKeystoreType()).andReturn(identityKeystoreType).atLeastOnce();
expect(config.getIdentityKeyAlias()).andReturn(identityKeyAlias).atLeastOnce();
if (isClientAuthNeeded) {
expect(config.isClientAuthNeeded()).andReturn(true).atLeastOnce();
if (isExplicitTruststore) {
expect(config.getTruststorePath()).andReturn(truststorePath.toString()).atLeastOnce();
expect(config.getTruststoreType()).andReturn(truststoreType).atLeastOnce();
expect(config.getTruststorePasswordAlias()).andReturn(trustStorePasswordAlias).atLeastOnce();
} else {
expect(config.getTruststorePath()).andReturn(null).atLeastOnce();
}
} else {
expect(config.isClientAuthNeeded()).andReturn(false).atLeastOnce();
}
expect(config.isClientAuthWanted()).andReturn(false).atLeastOnce();
expect(config.getTrustAllCerts()).andReturn(false).atLeastOnce();
expect(config.getIncludedSSLCiphers()).andReturn(null).atLeastOnce();
expect(config.getExcludedSSLCiphers()).andReturn(null).atLeastOnce();
expect(config.getExcludedSSLProtocols()).andReturn(null).atLeastOnce();
expect(config.isSSLRenegotiationAllowed()).andReturn(true).atLeastOnce();
return config;
}
}