blob: a2b013f468a79da83e16534b6bb0c3ad1054ef1b [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.hadoop.fs.s3a;
import java.io.IOException;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.Protocol;
import org.junit.Before;
import org.junit.Test;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.ssl.DelegatingSSLSocketFactory;
import org.apache.hadoop.test.AbstractHadoopTestBase;
import static org.apache.hadoop.fs.s3a.Constants.SSL_CHANNEL_MODE;
import static org.apache.hadoop.fs.s3a.impl.NetworkBinding.bindSSLChannelMode;
import static org.apache.hadoop.security.ssl.DelegatingSSLSocketFactory.SSLChannelMode.Default;
import static org.apache.hadoop.security.ssl.DelegatingSSLSocketFactory.SSLChannelMode.Default_JSSE;
import static org.apache.hadoop.security.ssl.DelegatingSSLSocketFactory.SSLChannelMode.Default_JSSE_with_GCM;
import static org.apache.hadoop.security.ssl.DelegatingSSLSocketFactory.SSLChannelMode.OpenSSL;
import static org.apache.hadoop.test.LambdaTestUtils.intercept;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;
/**
* Make sure that wildfly is not on this classpath and that we can still
* create connections in the default option, but that openssl fails.
* This test suite is designed to work whether or not wildfly JAR is on
* the classpath, and when openssl native libraries are/are not
* on the path.
* Some of the tests are skipped in a maven build because wildfly
* is always on the classpath -but they are retained as in-IDE
* runs may be different, and if wildfly is removed from
* the compile or test CP then different test cases will execute.
*/
public class TestWildflyAndOpenSSLBinding extends AbstractHadoopTestBase {
/** Was wildfly found. */
private boolean hasWildfly;
@Before
public void setup() throws Exception {
// determine whether or not wildfly is on the classpath
ClassLoader loader = this.getClass().getClassLoader();
try {
loader.loadClass("org.wildfly.openssl.OpenSSLProvider");
hasWildfly = true;
} catch (ClassNotFoundException e) {
hasWildfly = false;
}
}
@Test
public void testUnknownMode() throws Throwable {
DelegatingSSLSocketFactory.resetDefaultFactory();
Configuration conf = new Configuration(false);
conf.set(SSL_CHANNEL_MODE, "no-such-mode ");
intercept(IllegalArgumentException.class, () ->
bindSSLChannelMode(conf, new ClientConfiguration()));
}
@Test
public void testOpenSSLNoWildfly() throws Throwable {
assumeThat(hasWildfly).isFalse();
intercept(NoClassDefFoundError.class, "wildfly", () ->
bindSocketFactory(OpenSSL));
}
/**
* If there is no WF on the CP, then we always downgrade
* to default.
*/
@Test
public void testDefaultDowngradesNoWildfly() throws Throwable {
assumeThat(hasWildfly).isFalse();
expectBound(Default, Default_JSSE);
}
/**
* Wildfly is on the CP; if openssl native is on the
* path then openssl will load, otherwise JSSE.
*/
@Test
public void testWildflyOpenSSL() throws Throwable {
assumeThat(hasWildfly).isTrue();
assertThat(bindSocketFactory(Default))
.describedAs("Sockets from mode " + Default)
.isIn(OpenSSL, Default_JSSE);
}
@Test
public void testJSSE() throws Throwable {
expectBound(Default_JSSE, Default_JSSE);
}
@Test
public void testGCM() throws Throwable {
expectBound(Default_JSSE_with_GCM, Default_JSSE_with_GCM);
}
/**
* Bind to a socket mode and verify that the result matches
* that expected -which does not have to be the one requested.
* @param channelMode mode to use
* @param finalMode mode to test for
*/
private void expectBound(
DelegatingSSLSocketFactory.SSLChannelMode channelMode,
DelegatingSSLSocketFactory.SSLChannelMode finalMode)
throws Throwable {
assertThat(bindSocketFactory(channelMode))
.describedAs("Channel mode of socket factory created with mode %s",
channelMode)
.isEqualTo(finalMode);
}
/**
* Bind the socket factory to a given channel mode.
* @param channelMode mode to use
* @return the actual channel mode.
*/
private DelegatingSSLSocketFactory.SSLChannelMode bindSocketFactory(
final DelegatingSSLSocketFactory.SSLChannelMode channelMode)
throws IOException {
DelegatingSSLSocketFactory.resetDefaultFactory();
Configuration conf = new Configuration(false);
conf.set(SSL_CHANNEL_MODE, channelMode.name());
ClientConfiguration awsConf = new ClientConfiguration();
awsConf.setProtocol(Protocol.HTTPS);
bindSSLChannelMode(conf, awsConf);
return DelegatingSSLSocketFactory.getDefaultFactory().getChannelMode();
}
}