blob: 51506a834f7273e97b06079676519817b312be75 [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;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.UUID;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.FileUtils;
import org.apache.knox.gateway.services.DefaultGatewayServices;
import org.apache.knox.gateway.services.ServiceType;
import org.apache.knox.gateway.services.GatewayServices;
import org.apache.knox.gateway.services.ServiceLifecycleException;
import org.apache.knox.gateway.services.topology.TopologyService;
import org.apache.knox.test.TestUtils;
import org.apache.knox.test.category.ReleaseTest;
import org.apache.knox.test.mock.MockServer;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.knox.test.TestUtils.LOG_ENTER;
import static org.apache.knox.test.TestUtils.LOG_EXIT;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;
import static org.xmlmatchers.transform.XmlConverters.the;
import static org.xmlmatchers.xpath.HasXPath.hasXPath;
@Category( ReleaseTest.class )
public class GatewaySslFuncTest {
private static final Logger LOG = LoggerFactory.getLogger( GatewaySslFuncTest.class );
private static final Class<?> DAT = GatewaySslFuncTest.class;
private static GatewayTestConfig config;
private static DefaultGatewayServices services;
private static GatewayServer gateway;
private static String gatewayScheme;
private static int gatewayPort;
private static String gatewayUrl;
private static Properties params;
private static TopologyService topos;
private static MockServer mockWebHdfs;
private static GatewayTestDriver driver = new GatewayTestDriver();
@BeforeClass
public static void setUpBeforeClass() throws Exception {
LOG_ENTER();
driver.setupLdap(0);
setupGateway();
LOG_EXIT();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
LOG_ENTER();
gateway.stop();
driver.cleanup();
FileUtils.deleteQuietly( new File( config.getGatewayHomeDir() ) );
LOG_EXIT();
}
@After
public void cleanupTest() throws Exception {
FileUtils.cleanDirectory( new File( config.getGatewayTopologyDir() ) );
// Test run should not fail if deleting deployment files is not successful.
// Deletion has been already done by TopologyService.
FileUtils.deleteQuietly( new File( config.getGatewayDeploymentDir() ) );
}
public static void setupGateway() throws Exception {
File targetDir = new File( System.getProperty( "user.dir" ), "target" );
File gatewayDir = new File( targetDir, "gateway-home-" + UUID.randomUUID() );
gatewayDir.mkdirs();
config = new GatewayTestConfig();
config.setGatewayHomeDir( gatewayDir.getAbsolutePath() );
File topoDir = new File( config.getGatewayTopologyDir() );
topoDir.mkdirs();
File deployDir = new File( config.getGatewayDeploymentDir() );
deployDir.mkdirs();
File securityDir = new File( config.getGatewaySecurityDir() );
securityDir.mkdirs();
config.setSSLEnabled( true );
setupMockServers();
startGatewayServer();
}
public static void setupMockServers() throws Exception {
mockWebHdfs = new MockServer( "WEBHDFS", true );
}
private static GatewayServices instantiateGatewayServices() {
ServiceLoader<GatewayServices> loader = ServiceLoader.load( GatewayServices.class );
Iterator<GatewayServices> services = loader.iterator();
if (services.hasNext()) {
return services.next();
}
return null;
}
public static void startGatewayServer() throws Exception {
instantiateGatewayServices();
services = new DefaultGatewayServices();
Map<String,String> options = new HashMap<>();
options.put( "persist-master", "false" );
options.put( "master", "password" );
try {
services.init( config, options );
} catch ( ServiceLifecycleException e ) {
e.printStackTrace(); // I18N not required.
}
topos = services.getService(ServiceType.TOPOLOGY_SERVICE);
gateway = GatewayServer.startGateway( config, services );
assertThat( "Failed to start gateway.", gateway, notNullValue() );
gatewayScheme = config.isSSLEnabled() ? "https" : "http";
gatewayPort = gateway.getAddresses()[0].getPort();
gatewayUrl = gatewayScheme + "://localhost:" + gatewayPort + "/" + config.getGatewayPath();
LOG.info( "Gateway port = " + gateway.getAddresses()[ 0 ].getPort() );
params = new Properties();
params.put( "LDAP_URL", driver.getLdapUrl() );
params.put( "WEBHDFS_URL", "http://localhost:" + mockWebHdfs.getPort() );
}
@Test( timeout = TestUtils.MEDIUM_TIMEOUT )
public void testKnox674SslCipherSuiteConfig() throws Exception {
LOG_ENTER();
String topoStr = TestUtils.merge( DAT, "test-admin-topology.xml", params );
File topoFile = new File( config.getGatewayTopologyDir(), "test-topology.xml" );
FileUtils.writeStringToFile( topoFile, topoStr, StandardCharsets.UTF_8);
topos.reloadTopologies();
String username = "guest";
String password = "guest-password";
String serviceUrl = gatewayUrl + "/test-topology/api/v1/version";
HttpHost targetHost = new HttpHost( "localhost", gatewayPort, gatewayScheme );
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope( targetHost.getHostName(), targetHost.getPort() ),
new UsernamePasswordCredentials( username, password ) );
AuthCache authCache = new BasicAuthCache();
BasicScheme basicAuth = new BasicScheme();
authCache.put( targetHost, basicAuth );
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider( credsProvider );
context.setAuthCache( authCache );
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(
new SSLConnectionSocketFactory(
createInsecureSslContext(),
new String[]{"TLSv1.2"},
new String[]{"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"},
new TrustAllHosts() ) )
.build();
HttpGet request = new HttpGet( serviceUrl );
CloseableHttpResponse response = client.execute( request, context );
assertThat( the( new StreamSource( response.getEntity().getContent() ) ), hasXPath( "/ServerVersion/version" ) );
response.close();
client.close();
gateway.stop();
config.setExcludedSSLCiphers( Arrays.asList( new String[]{ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" } ) );
config.setIncludedSSLCiphers( Arrays.asList( new String[]{ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA" } ) );
startGatewayServer();
serviceUrl = gatewayUrl + "/test-topology/api/v1/version";
try {
client = HttpClients.custom()
.setSSLSocketFactory(
new SSLConnectionSocketFactory(
createInsecureSslContext(),
new String[]{ "TLSv1.2" },
new String[]{ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" },
new TrustAllHosts() ) ).build();
request = new HttpGet( serviceUrl );
client.execute( request, context );
fail( "Expected SSLHandshakeException" );
} catch ( SSLHandshakeException e ) {
// Expected.
client.close();
}
client = HttpClients.custom()
.setSSLSocketFactory(
new SSLConnectionSocketFactory(
createInsecureSslContext(),
new String[]{ "TLSv1.2" },
new String[]{ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA" },
new TrustAllHosts() ) ).build();
request = new HttpGet( serviceUrl );
response = client.execute( request, context );
assertThat( the( new StreamSource( response.getEntity().getContent() ) ), hasXPath( "/ServerVersion/version" ) );
response.close();
client.close();
LOG_EXIT();
}
public static class TrustAllHosts implements HostnameVerifier {
@Override
public boolean verify( String host, SSLSession sslSession ) {
// Trust all hostnames.
return true;
}
}
public static class TrustAllCerts implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s ) throws CertificateException {
// Trust all certificates.
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s ) throws CertificateException {
// Trust all certificates.
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
public static SSLContext createInsecureSslContext() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sslContext = SSLContext.getInstance( "SSL" );
sslContext.init( null, new TrustManager[]{ new TrustAllCerts() }, new SecureRandom() );
return sslContext;
}
}