diff --git a/hadoop-project/pom.xml b/hadoop-project/pom.xml
index 184cb3d1ac8..a13283a0ac6 100644
--- a/hadoop-project/pom.xml
+++ b/hadoop-project/pom.xml
@@ -1349,6 +1349,13 @@
7.0.0
+
+
+ org.wildfly.openssl
+ wildfly-openssl
+ 1.0.4.Final
+
+
org.threadly
threadly
diff --git a/hadoop-tools/hadoop-azure/pom.xml b/hadoop-tools/hadoop-azure/pom.xml
index 7d0406c6cf8..7152f6383a3 100644
--- a/hadoop-tools/hadoop-azure/pom.xml
+++ b/hadoop-tools/hadoop-azure/pom.xml
@@ -197,13 +197,18 @@
jackson-mapper-asl
compile
+
org.codehaus.jackson
jackson-core-asl
compile
-
+
+ org.wildfly.openssl
+ wildfly-openssl
+ compile
+
diff --git a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/AbfsConfiguration.java b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/AbfsConfiguration.java
index 1fb5df9aa39..e647ae8f250 100644
--- a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/AbfsConfiguration.java
+++ b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/AbfsConfiguration.java
@@ -44,6 +44,10 @@ import org.apache.hadoop.fs.azurebfs.diagnostics.LongConfigurationBasicValidator
import org.apache.hadoop.fs.azurebfs.diagnostics.StringConfigurationBasicValidator;
import org.apache.hadoop.fs.azurebfs.services.KeyProvider;
import org.apache.hadoop.fs.azurebfs.services.SimpleKeyProvider;
+import org.apache.hadoop.fs.azurebfs.utils.SSLSocketFactoryEx;
+
+import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_SSL_CHANNEL_MODE_KEY;
+import static org.apache.hadoop.fs.azurebfs.constants.FileSystemConfigurations.DEFAULT_FS_AZURE_SSL_CHANNEL_MODE;
/**
* Configuration for Azure Blob FileSystem.
@@ -270,6 +274,10 @@ public class AbfsConfiguration{
return this.userAgentId;
}
+ public SSLSocketFactoryEx.SSLChannelMode getPreferredSSLFactoryOption() {
+ return configuration.getEnum(FS_AZURE_SSL_CHANNEL_MODE_KEY, DEFAULT_FS_AZURE_SSL_CHANNEL_MODE);
+ }
+
void validateStorageAccountKeys() throws InvalidConfigurationValueException {
Base64StringConfigurationBasicValidator validator = new Base64StringConfigurationBasicValidator(
ConfigurationKeys.FS_AZURE_ACCOUNT_KEY_PROPERTY_NAME, "", true);
diff --git a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/constants/ConfigurationKeys.java b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/constants/ConfigurationKeys.java
index 9c805a2a7c2..16ddd900edd 100644
--- a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/constants/ConfigurationKeys.java
+++ b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/constants/ConfigurationKeys.java
@@ -55,6 +55,7 @@ public final class ConfigurationKeys {
public static final String FS_AZURE_READ_AHEAD_QUEUE_DEPTH = "fs.azure.readaheadqueue.depth";
public static final String FS_AZURE_ENABLE_FLUSH = "fs.azure.enable.flush";
public static final String FS_AZURE_USER_AGENT_PREFIX_KEY = "fs.azure.user.agent.prefix";
+ public static final String FS_AZURE_SSL_CHANNEL_MODE_KEY = "fs.azure.ssl.channel.mode";
public static final String AZURE_KEY_ACCOUNT_KEYPROVIDER_PREFIX = "fs.azure.account.keyprovider.";
public static final String AZURE_KEY_ACCOUNT_SHELLKEYPROVIDER_SCRIPT = "fs.azure.shellkeyprovider.script";
diff --git a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/constants/FileSystemConfigurations.java b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/constants/FileSystemConfigurations.java
index 1655d040493..5b92dddf732 100644
--- a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/constants/FileSystemConfigurations.java
+++ b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/constants/FileSystemConfigurations.java
@@ -20,6 +20,7 @@ package org.apache.hadoop.fs.azurebfs.constants;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.fs.azurebfs.utils.SSLSocketFactoryEx;
/**
* Responsible to keep all the Azure Blob File System related configurations.
@@ -57,5 +58,8 @@ public final class FileSystemConfigurations {
public static final int DEFAULT_READ_AHEAD_QUEUE_DEPTH = -1;
public static final boolean DEFAULT_ENABLE_FLUSH = true;
+ public static final SSLSocketFactoryEx.SSLChannelMode DEFAULT_FS_AZURE_SSL_CHANNEL_MODE
+ = SSLSocketFactoryEx.SSLChannelMode.Default;
+
private FileSystemConfigurations() {}
}
\ No newline at end of file
diff --git a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsClient.java b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsClient.java
index 60369be9bc7..e003ffd31d9 100644
--- a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsClient.java
+++ b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsClient.java
@@ -18,6 +18,7 @@
package org.apache.hadoop.fs.azurebfs.services;
+import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
@@ -27,6 +28,7 @@ import java.util.List;
import java.util.Locale;
import com.google.common.annotations.VisibleForTesting;
+import org.apache.hadoop.fs.azurebfs.utils.SSLSocketFactoryEx;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,6 +37,7 @@ import org.apache.hadoop.fs.azurebfs.contracts.exceptions.InvalidUriException;
import org.apache.hadoop.fs.azurebfs.AbfsConfiguration;
import static org.apache.hadoop.fs.azurebfs.constants.AbfsHttpConstants.*;
+import static org.apache.hadoop.fs.azurebfs.constants.FileSystemUriSchemes.HTTPS_SCHEME;
import static org.apache.hadoop.fs.azurebfs.constants.HttpHeaderConfigurations.*;
import static org.apache.hadoop.fs.azurebfs.constants.HttpQueryParams.*;
@@ -60,7 +63,19 @@ public class AbfsClient {
this.filesystem = baseUrlString.substring(baseUrlString.lastIndexOf(FORWARD_SLASH) + 1);
this.abfsConfiguration = abfsConfiguration;
this.retryPolicy = exponentialRetryPolicy;
- this.userAgent = initializeUserAgent(abfsConfiguration);
+
+ String sslProviderName = null;
+
+ if (this.baseUrl.toString().startsWith(HTTPS_SCHEME)) {
+ try {
+ SSLSocketFactoryEx.initializeDefaultFactory(this.abfsConfiguration.getPreferredSSLFactoryOption());
+ sslProviderName = SSLSocketFactoryEx.getDefaultFactory().getProviderName();
+ } catch (IOException e) {
+ // Suppress exception. Failure to init SSLSocketFactoryEx would have only performance impact.
+ }
+ }
+
+ this.userAgent = initializeUserAgent(abfsConfiguration, sslProviderName);
}
public String getFileSystem() {
@@ -395,16 +410,26 @@ public class AbfsClient {
}
@VisibleForTesting
- String initializeUserAgent(final AbfsConfiguration abfsConfiguration) {
- final String userAgentComment = String.format(Locale.ROOT,
- "(JavaJRE %s; %s %s)",
- System.getProperty(JAVA_VERSION),
- System.getProperty(OS_NAME)
- .replaceAll(SINGLE_WHITE_SPACE, EMPTY_STRING),
- System.getProperty(OS_VERSION));
+ String initializeUserAgent(final AbfsConfiguration abfsConfiguration,
+ final String sslProviderName) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("(JavaJRE ");
+ sb.append(System.getProperty(JAVA_VERSION));
+ sb.append("; ");
+ sb.append(
+ System.getProperty(OS_NAME).replaceAll(SINGLE_WHITE_SPACE, EMPTY_STRING));
+ sb.append(" ");
+ sb.append(System.getProperty(OS_VERSION));
+ if (sslProviderName != null && !sslProviderName.isEmpty()) {
+ sb.append("; ");
+ sb.append(sslProviderName);
+ }
+ sb.append(")");
+ final String userAgentComment = sb.toString();
String customUserAgentId = abfsConfiguration.getCustomUserAgentPrefix();
if (customUserAgentId != null && !customUserAgentId.isEmpty()) {
- return String.format(Locale.ROOT, CLIENT_VERSION + " %s %s", userAgentComment, customUserAgentId);
+ return String.format(Locale.ROOT, CLIENT_VERSION + " %s %s",
+ userAgentComment, customUserAgentId);
}
return String.format(CLIENT_VERSION + " %s", userAgentComment);
}
diff --git a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsHttpOperation.java b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsHttpOperation.java
index 2bfcff25003..f493298f2c1 100644
--- a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsHttpOperation.java
+++ b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsHttpOperation.java
@@ -26,6 +26,10 @@ import java.net.URL;
import java.util.List;
import java.util.UUID;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.apache.hadoop.fs.azurebfs.utils.SSLSocketFactoryEx;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
@@ -174,6 +178,13 @@ public class AbfsHttpOperation {
this.clientRequestId = UUID.randomUUID().toString();
this.connection = openConnection();
+ if (this.connection instanceof HttpsURLConnection) {
+ HttpsURLConnection secureConn = (HttpsURLConnection) this.connection;
+ SSLSocketFactory sslSocketFactory = SSLSocketFactoryEx.getDefaultFactory();
+ if (sslSocketFactory != null) {
+ secureConn.setSSLSocketFactory(sslSocketFactory);
+ }
+ }
this.connection.setConnectTimeout(CONNECT_TIMEOUT);
this.connection.setReadTimeout(READ_TIMEOUT);
diff --git a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/utils/SSLSocketFactoryEx.java b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/utils/SSLSocketFactoryEx.java
new file mode 100644
index 00000000000..202e1850603
--- /dev/null
+++ b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/utils/SSLSocketFactoryEx.java
@@ -0,0 +1,240 @@
+/**
+ * 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.azurebfs.utils;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.wildfly.openssl.OpenSSLProvider;
+
+
+/**
+ * Extension to use native OpenSSL library instead of JSSE for better
+ * performance.
+ *
+ */
+public class SSLSocketFactoryEx extends SSLSocketFactory {
+
+ /**
+ * Default indicates Ordered, preferred OpenSSL, if failed to load then fall
+ * back to Default_JSSE
+ */
+ public enum SSLChannelMode {
+ OpenSSL,
+ Default,
+ Default_JSSE
+ }
+
+ private static SSLSocketFactoryEx instance = null;
+ private static final Logger LOG = LoggerFactory.getLogger(
+ SSLSocketFactoryEx.class);
+ private String providerName;
+ private SSLContext ctx;
+ private String[] ciphers;
+ private SSLChannelMode channelMode;
+
+ /**
+ * Initialize a singleton SSL socket factory.
+ *
+ * @param preferredMode applicable only if the instance is not initialized.
+ * @throws IOException
+ */
+ public synchronized static void initializeDefaultFactory(
+ SSLChannelMode preferredMode) throws IOException {
+ if (instance == null) {
+ instance = new SSLSocketFactoryEx(preferredMode);
+ }
+ }
+
+ /**
+ * Singletone instance of the SSLSocketFactory.
+ *
+ * SSLSocketFactory must be initialized with appropriate SSLChannelMode
+ * using initializeDefaultFactory method.
+ *
+ * @return instance of the SSLSocketFactory, instance must be initialized by
+ * initializeDefaultFactory.
+ */
+ public static SSLSocketFactoryEx getDefaultFactory() {
+ return instance;
+ }
+
+ static {
+ OpenSSLProvider.register();
+ }
+
+ private SSLSocketFactoryEx(SSLChannelMode preferredChannelMode)
+ throws IOException {
+ try {
+ initializeSSLContext(preferredChannelMode);
+ } catch (NoSuchAlgorithmException e) {
+ throw new IOException(e);
+ } catch (KeyManagementException e) {
+ throw new IOException(e);
+ }
+
+ // Get list of supported cipher suits from the SSL factory.
+ SSLSocketFactory factory = ctx.getSocketFactory();
+ String[] defaultCiphers = factory.getSupportedCipherSuites();
+ String version = System.getProperty("java.version");
+
+ ciphers = (channelMode == SSLChannelMode.Default_JSSE
+ && version.startsWith("1.8"))
+ ? alterCipherList(defaultCiphers) : defaultCiphers;
+
+ providerName = ctx.getProvider().getName() + "-"
+ + ctx.getProvider().getVersion();
+ }
+
+ private void initializeSSLContext(SSLChannelMode preferredChannelMode)
+ throws NoSuchAlgorithmException, KeyManagementException {
+ switch (preferredChannelMode) {
+ case Default:
+ try {
+ ctx = SSLContext.getInstance("openssl.TLS");
+ ctx.init(null, null, null);
+ channelMode = SSLChannelMode.OpenSSL;
+ } catch (NoSuchAlgorithmException e) {
+ LOG.warn("Failed to load OpenSSL. Falling back to the JSSE default.");
+ ctx = SSLContext.getDefault();
+ channelMode = SSLChannelMode.Default_JSSE;
+ }
+ break;
+ case OpenSSL:
+ ctx = SSLContext.getInstance("openssl.TLS");
+ ctx.init(null, null, null);
+ channelMode = SSLChannelMode.OpenSSL;
+ break;
+ case Default_JSSE:
+ ctx = SSLContext.getDefault();
+ channelMode = SSLChannelMode.Default_JSSE;
+ break;
+ default:
+ throw new AssertionError("Unknown channel mode: "
+ + preferredChannelMode);
+ }
+ }
+
+ public String getProviderName() {
+ return providerName;
+ }
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return ciphers.clone();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return ciphers.clone();
+ }
+
+ public Socket createSocket() throws IOException {
+ SSLSocketFactory factory = ctx.getSocketFactory();
+ SSLSocket ss = (SSLSocket) factory.createSocket();
+ configureSocket(ss);
+ return ss;
+ }
+
+ @Override
+ public Socket createSocket(Socket s, String host, int port,
+ boolean autoClose) throws IOException {
+ SSLSocketFactory factory = ctx.getSocketFactory();
+ SSLSocket ss = (SSLSocket) factory.createSocket(s, host, port, autoClose);
+
+ configureSocket(ss);
+ return ss;
+ }
+
+ @Override
+ public Socket createSocket(InetAddress address, int port,
+ InetAddress localAddress, int localPort)
+ throws IOException {
+ SSLSocketFactory factory = ctx.getSocketFactory();
+ SSLSocket ss = (SSLSocket) factory
+ .createSocket(address, port, localAddress, localPort);
+
+ configureSocket(ss);
+ return ss;
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localHost,
+ int localPort) throws IOException {
+ SSLSocketFactory factory = ctx.getSocketFactory();
+ SSLSocket ss = (SSLSocket) factory
+ .createSocket(host, port, localHost, localPort);
+
+ configureSocket(ss);
+
+ return ss;
+ }
+
+ @Override
+ public Socket createSocket(InetAddress host, int port) throws IOException {
+ SSLSocketFactory factory = ctx.getSocketFactory();
+ SSLSocket ss = (SSLSocket) factory.createSocket(host, port);
+
+ configureSocket(ss);
+
+ return ss;
+ }
+
+ @Override
+ public Socket createSocket(String host, int port) throws IOException {
+ SSLSocketFactory factory = ctx.getSocketFactory();
+ SSLSocket ss = (SSLSocket) factory.createSocket(host, port);
+
+ configureSocket(ss);
+
+ return ss;
+ }
+
+ private void configureSocket(SSLSocket ss) throws SocketException {
+ ss.setEnabledCipherSuites(ciphers);
+ }
+
+ private String[] alterCipherList(String[] defaultCiphers) {
+
+ ArrayList preferredSuits = new ArrayList<>();
+
+ // Remove GCM mode based ciphers from the supported list.
+ for (int i = 0; i < defaultCiphers.length; i++) {
+ if (defaultCiphers[i].contains("_GCM_")) {
+ LOG.debug("Removed Cipher - " + defaultCiphers[i]);
+ } else {
+ preferredSuits.add(defaultCiphers[i]);
+ }
+ }
+
+ ciphers = preferredSuits.toArray(new String[0]);
+ return ciphers;
+ }
+}
\ No newline at end of file
diff --git a/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/TestAbfsConfigurationFieldsValidation.java b/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/TestAbfsConfigurationFieldsValidation.java
index fb667ddc8a8..556dcdb0422 100644
--- a/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/TestAbfsConfigurationFieldsValidation.java
+++ b/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/TestAbfsConfigurationFieldsValidation.java
@@ -30,6 +30,7 @@ import org.apache.hadoop.fs.azurebfs.contracts.annotations.ConfigurationValidati
import org.apache.hadoop.fs.azurebfs.contracts.annotations.ConfigurationValidationAnnotations.Base64StringConfigurationValidatorAnnotation;
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.ConfigurationPropertyNotFoundException;
+import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_SSL_CHANNEL_MODE_KEY;
import static org.apache.hadoop.fs.azurebfs.constants.FileSystemConfigurations.DEFAULT_READ_BUFFER_SIZE;
import static org.apache.hadoop.fs.azurebfs.constants.FileSystemConfigurations.DEFAULT_WRITE_BUFFER_SIZE;
import static org.apache.hadoop.fs.azurebfs.constants.FileSystemConfigurations.DEFAULT_MAX_RETRY_ATTEMPTS;
@@ -41,7 +42,10 @@ import static org.apache.hadoop.fs.azurebfs.constants.FileSystemConfigurations.A
import org.apache.commons.codec.binary.Base64;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import org.apache.hadoop.fs.azurebfs.contracts.exceptions.InvalidConfigurationValueException;
+import org.apache.hadoop.fs.azurebfs.utils.SSLSocketFactoryEx;
import org.junit.Test;
/**
@@ -50,11 +54,11 @@ import org.junit.Test;
public class TestAbfsConfigurationFieldsValidation {
private AbfsConfiguration abfsConfiguration;
- private static final String INT_KEY= "intKey";
- private static final String LONG_KEY= "longKey";
- private static final String STRING_KEY= "stringKey";
- private static final String BASE64_KEY= "base64Key";
- private static final String BOOLEAN_KEY= "booleanKey";
+ private static final String INT_KEY = "intKey";
+ private static final String LONG_KEY = "longKey";
+ private static final String STRING_KEY = "stringKey";
+ private static final String BASE64_KEY = "base64Key";
+ private static final String BOOLEAN_KEY = "booleanKey";
private static final int DEFAULT_INT = 4194304;
private static final int DEFAULT_LONG = 4194304;
@@ -77,15 +81,15 @@ public class TestAbfsConfigurationFieldsValidation {
private int longField;
@StringConfigurationValidatorAnnotation(ConfigurationKey = STRING_KEY,
- DefaultValue = "default")
+ DefaultValue = "default")
private String stringField;
@Base64StringConfigurationValidatorAnnotation(ConfigurationKey = BASE64_KEY,
- DefaultValue = "base64")
+ DefaultValue = "base64")
private String base64Field;
@BooleanConfigurationValidatorAnnotation(ConfigurationKey = BOOLEAN_KEY,
- DefaultValue = false)
+ DefaultValue = false)
private boolean boolField;
public TestAbfsConfigurationFieldsValidation() throws Exception {
@@ -142,8 +146,26 @@ public class TestAbfsConfigurationFieldsValidation {
assertEquals(this.encodedAccountKey, accountKey);
}
- @Test (expected = ConfigurationPropertyNotFoundException.class)
+ @Test(expected = ConfigurationPropertyNotFoundException.class)
public void testGetAccountKeyWithNonExistingAccountName() throws Exception {
abfsConfiguration.getStorageAccountKey("bogusAccountName");
}
-}
+
+ @Test
+ public void testSSLSocketFactoryConfiguration() throws InvalidConfigurationValueException, IllegalAccessException {
+ assertEquals(SSLSocketFactoryEx.SSLChannelMode.Default, abfsConfiguration.getPreferredSSLFactoryOption());
+ assertNotEquals(SSLSocketFactoryEx.SSLChannelMode.Default_JSSE, abfsConfiguration.getPreferredSSLFactoryOption());
+ assertNotEquals(SSLSocketFactoryEx.SSLChannelMode.OpenSSL, abfsConfiguration.getPreferredSSLFactoryOption());
+
+ Configuration configuration = new Configuration();
+ configuration.setEnum(FS_AZURE_SSL_CHANNEL_MODE_KEY, SSLSocketFactoryEx.SSLChannelMode.Default_JSSE);
+ AbfsConfiguration localAbfsConfiguration = new AbfsConfiguration(configuration);
+ assertEquals(SSLSocketFactoryEx.SSLChannelMode.Default_JSSE, localAbfsConfiguration.getPreferredSSLFactoryOption());
+
+ configuration = new Configuration();
+ configuration.setEnum(FS_AZURE_SSL_CHANNEL_MODE_KEY, SSLSocketFactoryEx.SSLChannelMode.OpenSSL);
+ localAbfsConfiguration = new AbfsConfiguration(configuration);
+ assertEquals(SSLSocketFactoryEx.SSLChannelMode.OpenSSL, localAbfsConfiguration.getPreferredSSLFactoryOption());
+ }
+
+}
\ No newline at end of file
diff --git a/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/services/TestAbfsClient.java b/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/services/TestAbfsClient.java
index 0b335a53e06..7bb27fc4514 100644
--- a/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/services/TestAbfsClient.java
+++ b/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/services/TestAbfsClient.java
@@ -22,6 +22,7 @@ import java.net.URL;
import java.util.regex.Pattern;
import org.apache.hadoop.fs.azurebfs.AbfsConfiguration;
+import org.apache.hadoop.fs.azurebfs.utils.SSLSocketFactoryEx;
import org.junit.Assert;
import org.junit.Test;
@@ -34,16 +35,29 @@ import org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys;
*/
public final class TestAbfsClient {
+ private void validateUserAgent(String expectedPattern,
+ URL baseUrl,
+ AbfsConfiguration config,
+ boolean includeSSLProvider) {
+ AbfsClient client = new AbfsClient(baseUrl, null,
+ config, null);
+ String sslProviderName = null;
+ if (includeSSLProvider) {
+ sslProviderName = SSLSocketFactoryEx.getDefaultFactory().getProviderName();
+ }
+ String userAgent = client.initializeUserAgent(config, sslProviderName);
+ Pattern pattern = Pattern.compile(expectedPattern);
+ Assert.assertTrue(pattern.matcher(userAgent).matches());
+ }
+
@Test
public void verifyUnknownUserAgent() throws Exception {
String expectedUserAgentPattern = "Azure Blob FS\\/1.0 \\(JavaJRE ([^\\)]+)\\)";
final Configuration configuration = new Configuration();
configuration.unset(ConfigurationKeys.FS_AZURE_USER_AGENT_PREFIX_KEY);
AbfsConfiguration abfsConfiguration = new AbfsConfiguration(configuration);
- AbfsClient abfsClient = new AbfsClient(new URL("http://azure.com"), null, abfsConfiguration, null);
- String userAgent = abfsClient.initializeUserAgent(abfsConfiguration);
- Pattern pattern = Pattern.compile(expectedUserAgentPattern);
- Assert.assertTrue(pattern.matcher(userAgent).matches());
+ validateUserAgent(expectedUserAgentPattern, new URL("http://azure.com"),
+ abfsConfiguration, false);
}
@Test
@@ -52,9 +66,19 @@ public final class TestAbfsClient {
final Configuration configuration = new Configuration();
configuration.set(ConfigurationKeys.FS_AZURE_USER_AGENT_PREFIX_KEY, "Partner Service");
AbfsConfiguration abfsConfiguration = new AbfsConfiguration(configuration);
- AbfsClient abfsClient = new AbfsClient(new URL("http://azure.com"), null, abfsConfiguration, null);
- String userAgent = abfsClient.initializeUserAgent(abfsConfiguration);
- Pattern pattern = Pattern.compile(expectedUserAgentPattern);
- Assert.assertTrue(pattern.matcher(userAgent).matches());
+ validateUserAgent(expectedUserAgentPattern, new URL("http://azure.com"),
+ abfsConfiguration, false);
+ }
+
+ @Test
+ public void verifyUserAgentWithSSLProvider() throws Exception {
+ String expectedUserAgentPattern = "Azure Blob FS\\/1.0 \\(JavaJRE ([^\\)]+) SunJSSE-1.8\\) Partner Service";
+ final Configuration configuration = new Configuration();
+ configuration.set(ConfigurationKeys.FS_AZURE_USER_AGENT_PREFIX_KEY, "Partner Service");
+ configuration.set(ConfigurationKeys.FS_AZURE_SSL_CHANNEL_MODE_KEY,
+ SSLSocketFactoryEx.SSLChannelMode.Default_JSSE.name());
+ AbfsConfiguration abfsConfiguration = new AbfsConfiguration(configuration);
+ validateUserAgent(expectedUserAgentPattern, new URL("https://azure.com"),
+ abfsConfiguration, true);
}
}
\ No newline at end of file