HDFS-13061. SaslDataTransferClient#checkTrustAndSend should not trust a partially trusted channel. Contributed by Ajay Kumar.

This commit is contained in:
Xiaoyu Yao 2018-01-31 10:09:43 -08:00
parent 12eaae383a
commit 37b7536568
2 changed files with 161 additions and 5 deletions

View File

@ -203,11 +203,15 @@ private IOStreamPair checkTrustAndSend(InetAddress addr,
DataEncryptionKeyFactory encryptionKeyFactory, DataEncryptionKeyFactory encryptionKeyFactory,
Token<BlockTokenIdentifier> accessToken, DatanodeID datanodeId) Token<BlockTokenIdentifier> accessToken, DatanodeID datanodeId)
throws IOException { throws IOException {
if (!trustedChannelResolver.isTrusted() && boolean localTrusted = trustedChannelResolver.isTrusted();
!trustedChannelResolver.isTrusted(addr)) { boolean remoteTrusted = trustedChannelResolver.isTrusted(addr);
LOG.debug("SASL encryption trust check: localHostTrusted = {}, "
+ "remoteHostTrusted = {}", localTrusted, remoteTrusted);
if (!localTrusted || !remoteTrusted) {
// The encryption key factory only returns a key if encryption is enabled. // The encryption key factory only returns a key if encryption is enabled.
DataEncryptionKey encryptionKey = DataEncryptionKey encryptionKey = encryptionKeyFactory
encryptionKeyFactory.newDataEncryptionKey(); .newDataEncryptionKey();
return send(addr, underlyingOut, underlyingIn, encryptionKey, accessToken, return send(addr, underlyingOut, underlyingIn, encryptionKey, accessToken,
datanodeId); datanodeId);
} else { } else {

View File

@ -23,8 +23,12 @@
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
@ -56,6 +60,7 @@
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.junit.rules.Timeout; import org.junit.rules.Timeout;
import org.mockito.Mockito;
public class TestSaslDataTransfer extends SaslDataTransferTestCase { public class TestSaslDataTransfer extends SaslDataTransferTestCase {
@ -74,7 +79,7 @@ public class TestSaslDataTransfer extends SaslDataTransferTestCase {
@After @After
public void shutdown() { public void shutdown() {
IOUtils.cleanup(null, fs); IOUtils.cleanupWithLogger(null, fs);
if (cluster != null) { if (cluster != null) {
cluster.shutdown(); cluster.shutdown();
cluster = null; cluster = null;
@ -245,4 +250,151 @@ public DataEncryptionKey newDataEncryptionKey() {
IOUtils.cleanup(null, socket, serverSocket); IOUtils.cleanup(null, socket, serverSocket);
} }
} }
/**
* Verifies that SaslDataTransferClient#checkTrustAndSend should not trust a
* partially trusted channel.
*/
@Test
public void testSaslDataTransferWithTrustedServerUntrustedClient() throws
Exception {
HdfsConfiguration conf = createSecureConfig(
"authentication,integrity,privacy");
AtomicBoolean fallbackToSimpleAuth = new AtomicBoolean(false);
TrustedChannelResolver trustedChannelResolver = new
TrustedChannelResolver() {
@Override
public boolean isTrusted() {
return true;
}
@Override
public boolean isTrusted(InetAddress peerAddress) {
return false;
}
};
SaslDataTransferClient saslClient = new SaslDataTransferClient(
conf, DataTransferSaslUtil.getSaslPropertiesResolver(conf),
trustedChannelResolver, fallbackToSimpleAuth);
ServerSocket serverSocket = null;
Socket socket = null;
DataEncryptionKeyFactory dataEncryptionKeyFactory = null;
try {
serverSocket = new ServerSocket(10002, 10);
socket = new Socket(serverSocket.getInetAddress(),
serverSocket.getLocalPort());
dataEncryptionKeyFactory = mock(DataEncryptionKeyFactory.class);
Mockito.when(dataEncryptionKeyFactory.newDataEncryptionKey())
.thenThrow(new IOException("Encryption enabled"));
saslClient.socketSend(socket, null, null, dataEncryptionKeyFactory,
null, null);
Assert.fail("Expected IOException from "
+ "SaslDataTransferClient#checkTrustAndSend");
} catch (IOException e) {
GenericTestUtils.assertExceptionContains("Encryption enabled", e);
verify(dataEncryptionKeyFactory, times(1)).newDataEncryptionKey();
} finally {
IOUtils.cleanupWithLogger(null, socket, serverSocket);
}
}
@Test
public void testSaslDataTransferWithUntrustedServerUntrustedClient() throws
Exception {
HdfsConfiguration conf = createSecureConfig(
"authentication,integrity,privacy");
AtomicBoolean fallbackToSimpleAuth = new AtomicBoolean(false);
TrustedChannelResolver trustedChannelResolver = new
TrustedChannelResolver() {
@Override
public boolean isTrusted() {
return false;
}
@Override
public boolean isTrusted(InetAddress peerAddress) {
return false;
}
};
SaslDataTransferClient saslClient = new SaslDataTransferClient(
conf, DataTransferSaslUtil.getSaslPropertiesResolver(conf),
trustedChannelResolver, fallbackToSimpleAuth);
ServerSocket serverSocket = null;
Socket socket = null;
DataEncryptionKeyFactory dataEncryptionKeyFactory = null;
try {
serverSocket = new ServerSocket(10002, 10);
socket = new Socket(serverSocket.getInetAddress(),
serverSocket.getLocalPort());
dataEncryptionKeyFactory = mock(DataEncryptionKeyFactory.class);
Mockito.when(dataEncryptionKeyFactory.newDataEncryptionKey())
.thenThrow(new IOException("Encryption enabled"));
saslClient.socketSend(socket, null, null, dataEncryptionKeyFactory,
null, null);
Assert.fail("Expected IOException from "
+ "SaslDataTransferClient#checkTrustAndSend");
} catch (IOException e) {
GenericTestUtils.assertExceptionContains("Encryption enabled", e);
verify(dataEncryptionKeyFactory, times(1)).newDataEncryptionKey();
} finally {
IOUtils.cleanupWithLogger(null, socket, serverSocket);
}
}
@Test
public void testSaslDataTransferWithTrustedServerTrustedClient() throws
Exception {
HdfsConfiguration conf = createSecureConfig(
"authentication,integrity,privacy");
AtomicBoolean fallbackToSimpleAuth = new AtomicBoolean(false);
TrustedChannelResolver trustedChannelResolver = new
TrustedChannelResolver() {
@Override
public boolean isTrusted() {
return true;
}
@Override
public boolean isTrusted(InetAddress peerAddress) {
return true;
}
};
SaslDataTransferClient saslClient = new SaslDataTransferClient(
conf, DataTransferSaslUtil.getSaslPropertiesResolver(conf),
trustedChannelResolver, fallbackToSimpleAuth);
ServerSocket serverSocket = null;
Socket socket = null;
DataEncryptionKeyFactory dataEncryptionKeyFactory = null;
try {
serverSocket = new ServerSocket(10002, 10);
socket = new Socket(serverSocket.getInetAddress(),
serverSocket.getLocalPort());
dataEncryptionKeyFactory = mock(DataEncryptionKeyFactory.class);
Mockito.when(dataEncryptionKeyFactory.newDataEncryptionKey())
.thenThrow(new IOException("Encryption enabled"));
saslClient.socketSend(socket, null, null, dataEncryptionKeyFactory,
null, null);
verify(dataEncryptionKeyFactory, times(0)).newDataEncryptionKey();
} finally {
IOUtils.cleanupWithLogger(null, socket, serverSocket);
}
}
} }