|
@@ -34,6 +34,7 @@ import java.util.Arrays;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.Set;
|
|
|
+import java.util.function.Function;
|
|
|
import javax.security.sasl.Sasl;
|
|
|
|
|
|
import org.apache.commons.codec.binary.Base64;
|
|
@@ -52,6 +53,7 @@ import org.apache.hadoop.hdfs.protocol.proto.DataTransferProtos.DataTransferEncr
|
|
|
import org.apache.hadoop.hdfs.protocol.proto.DataTransferProtos.HandshakeSecretProto;
|
|
|
import org.apache.hadoop.hdfs.protocol.proto.HdfsProtos.CipherOptionProto;
|
|
|
import org.apache.hadoop.hdfs.protocolPB.PBHelperClient;
|
|
|
+import org.apache.hadoop.hdfs.security.token.block.InvalidBlockTokenException;
|
|
|
import org.apache.hadoop.security.SaslPropertiesResolver;
|
|
|
import org.apache.hadoop.security.SaslRpcServer.QualityOfProtection;
|
|
|
import org.slf4j.Logger;
|
|
@@ -204,6 +206,26 @@ public final class DataTransferSaslUtil {
|
|
|
return resolver;
|
|
|
}
|
|
|
|
|
|
+ private static <T> T readSaslMessage(InputStream in,
|
|
|
+ Function<DataTransferEncryptorMessageProto, ? extends T> handler) throws IOException {
|
|
|
+ DataTransferEncryptorMessageProto proto =
|
|
|
+ DataTransferEncryptorMessageProto.parseFrom(vintPrefixed(in));
|
|
|
+ switch (proto.getStatus()) {
|
|
|
+ case ERROR_UNKNOWN_KEY:
|
|
|
+ throw new InvalidEncryptionKeyException(proto.getMessage());
|
|
|
+ case ERROR:
|
|
|
+ if (proto.hasAccessTokenError() && proto.getAccessTokenError()) {
|
|
|
+ throw new InvalidBlockTokenException(proto.getMessage());
|
|
|
+ }
|
|
|
+ throw new IOException(proto.getMessage());
|
|
|
+ case SUCCESS:
|
|
|
+ return handler.apply(proto);
|
|
|
+ default:
|
|
|
+ throw new IOException(
|
|
|
+ "Unknown status: " + proto.getStatus() + ", message: " + proto.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Reads a SASL negotiation message.
|
|
|
*
|
|
@@ -212,15 +234,7 @@ public final class DataTransferSaslUtil {
|
|
|
* @throws IOException for any error
|
|
|
*/
|
|
|
public static byte[] readSaslMessage(InputStream in) throws IOException {
|
|
|
- DataTransferEncryptorMessageProto proto =
|
|
|
- DataTransferEncryptorMessageProto.parseFrom(vintPrefixed(in));
|
|
|
- if (proto.getStatus() == DataTransferEncryptorStatus.ERROR_UNKNOWN_KEY) {
|
|
|
- throw new InvalidEncryptionKeyException(proto.getMessage());
|
|
|
- } else if (proto.getStatus() == DataTransferEncryptorStatus.ERROR) {
|
|
|
- throw new IOException(proto.getMessage());
|
|
|
- } else {
|
|
|
- return proto.getPayload().toByteArray();
|
|
|
- }
|
|
|
+ return readSaslMessage(in, proto -> proto.getPayload().toByteArray());
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -233,13 +247,7 @@ public final class DataTransferSaslUtil {
|
|
|
*/
|
|
|
public static byte[] readSaslMessageAndNegotiationCipherOptions(
|
|
|
InputStream in, List<CipherOption> cipherOptions) throws IOException {
|
|
|
- DataTransferEncryptorMessageProto proto =
|
|
|
- DataTransferEncryptorMessageProto.parseFrom(vintPrefixed(in));
|
|
|
- if (proto.getStatus() == DataTransferEncryptorStatus.ERROR_UNKNOWN_KEY) {
|
|
|
- throw new InvalidEncryptionKeyException(proto.getMessage());
|
|
|
- } else if (proto.getStatus() == DataTransferEncryptorStatus.ERROR) {
|
|
|
- throw new IOException(proto.getMessage());
|
|
|
- } else {
|
|
|
+ return readSaslMessage(in, proto -> {
|
|
|
List<CipherOptionProto> optionProtos = proto.getCipherOptionList();
|
|
|
if (optionProtos != null) {
|
|
|
for (CipherOptionProto optionProto : optionProtos) {
|
|
@@ -247,7 +255,7 @@ public final class DataTransferSaslUtil {
|
|
|
}
|
|
|
}
|
|
|
return proto.getPayload().toByteArray();
|
|
|
- }
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
static class SaslMessageWithHandshake {
|
|
@@ -276,13 +284,7 @@ public final class DataTransferSaslUtil {
|
|
|
|
|
|
public static SaslMessageWithHandshake readSaslMessageWithHandshakeSecret(
|
|
|
InputStream in) throws IOException {
|
|
|
- DataTransferEncryptorMessageProto proto =
|
|
|
- DataTransferEncryptorMessageProto.parseFrom(vintPrefixed(in));
|
|
|
- if (proto.getStatus() == DataTransferEncryptorStatus.ERROR_UNKNOWN_KEY) {
|
|
|
- throw new InvalidEncryptionKeyException(proto.getMessage());
|
|
|
- } else if (proto.getStatus() == DataTransferEncryptorStatus.ERROR) {
|
|
|
- throw new IOException(proto.getMessage());
|
|
|
- } else {
|
|
|
+ return readSaslMessage(in, proto -> {
|
|
|
byte[] payload = proto.getPayload().toByteArray();
|
|
|
byte[] secret = null;
|
|
|
String bpid = null;
|
|
@@ -292,7 +294,7 @@ public final class DataTransferSaslUtil {
|
|
|
bpid = handshakeSecret.getBpid();
|
|
|
}
|
|
|
return new SaslMessageWithHandshake(payload, secret, bpid);
|
|
|
- }
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -467,13 +469,7 @@ public final class DataTransferSaslUtil {
|
|
|
public static SaslResponseWithNegotiatedCipherOption
|
|
|
readSaslMessageAndNegotiatedCipherOption(InputStream in)
|
|
|
throws IOException {
|
|
|
- DataTransferEncryptorMessageProto proto =
|
|
|
- DataTransferEncryptorMessageProto.parseFrom(vintPrefixed(in));
|
|
|
- if (proto.getStatus() == DataTransferEncryptorStatus.ERROR_UNKNOWN_KEY) {
|
|
|
- throw new InvalidEncryptionKeyException(proto.getMessage());
|
|
|
- } else if (proto.getStatus() == DataTransferEncryptorStatus.ERROR) {
|
|
|
- throw new IOException(proto.getMessage());
|
|
|
- } else {
|
|
|
+ return readSaslMessage(in, proto -> {
|
|
|
byte[] response = proto.getPayload().toByteArray();
|
|
|
List<CipherOption> options = PBHelperClient.convertCipherOptionProtos(
|
|
|
proto.getCipherOptionList());
|
|
@@ -482,7 +478,7 @@ public final class DataTransferSaslUtil {
|
|
|
option = options.get(0);
|
|
|
}
|
|
|
return new SaslResponseWithNegotiatedCipherOption(response, option);
|
|
|
- }
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -558,6 +554,13 @@ public final class DataTransferSaslUtil {
|
|
|
DataTransferEncryptorStatus status, byte[] payload, String message,
|
|
|
HandshakeSecretProto handshakeSecret)
|
|
|
throws IOException {
|
|
|
+ sendSaslMessage(out, status, payload, message, handshakeSecret, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void sendSaslMessage(OutputStream out,
|
|
|
+ DataTransferEncryptorStatus status, byte[] payload, String message,
|
|
|
+ HandshakeSecretProto handshakeSecret, boolean accessTokenError)
|
|
|
+ throws IOException {
|
|
|
DataTransferEncryptorMessageProto.Builder builder =
|
|
|
DataTransferEncryptorMessageProto.newBuilder();
|
|
|
|
|
@@ -571,6 +574,9 @@ public final class DataTransferSaslUtil {
|
|
|
if (handshakeSecret != null) {
|
|
|
builder.setHandshakeSecret(handshakeSecret);
|
|
|
}
|
|
|
+ if (accessTokenError) {
|
|
|
+ builder.setAccessTokenError(true);
|
|
|
+ }
|
|
|
|
|
|
DataTransferEncryptorMessageProto proto = builder.build();
|
|
|
proto.writeDelimitedTo(out);
|