|
@@ -29,6 +29,7 @@ import java.io.IOException;
|
|
|
import java.io.InputStream;
|
|
|
import java.io.OutputStream;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
+import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
|
|
@@ -46,6 +47,7 @@ import org.apache.commons.codec.binary.Base64;
|
|
|
import org.apache.hadoop.classification.InterfaceAudience;
|
|
|
import org.apache.hadoop.conf.Configuration;
|
|
|
import org.apache.hadoop.crypto.CipherOption;
|
|
|
+import org.apache.hadoop.hdfs.client.HdfsClientConfigKeys;
|
|
|
import org.apache.hadoop.hdfs.net.Peer;
|
|
|
import org.apache.hadoop.hdfs.protocol.DatanodeID;
|
|
|
import org.apache.hadoop.hdfs.protocol.datatransfer.IOStreamPair;
|
|
@@ -178,7 +180,7 @@ public class SaslDataTransferServer {
|
|
|
dnConf.getEncryptionAlgorithm());
|
|
|
}
|
|
|
|
|
|
- CallbackHandler callbackHandler = new SaslServerCallbackHandler(
|
|
|
+ final CallbackHandler callbackHandler = new SaslServerCallbackHandler(dnConf.getConf(),
|
|
|
new PasswordFunction() {
|
|
|
@Override
|
|
|
public char[] apply(String userName) throws IOException {
|
|
@@ -195,7 +197,7 @@ public class SaslDataTransferServer {
|
|
|
* logic. It's similar to a Guava Function, but we need to let it throw
|
|
|
* exceptions.
|
|
|
*/
|
|
|
- private interface PasswordFunction {
|
|
|
+ interface PasswordFunction {
|
|
|
|
|
|
/**
|
|
|
* Returns the SASL password for the given user name.
|
|
@@ -210,18 +212,27 @@ public class SaslDataTransferServer {
|
|
|
/**
|
|
|
* Sets user name and password when asked by the server-side SASL object.
|
|
|
*/
|
|
|
- private static final class SaslServerCallbackHandler
|
|
|
+ static final class SaslServerCallbackHandler
|
|
|
implements CallbackHandler {
|
|
|
-
|
|
|
private final PasswordFunction passwordFunction;
|
|
|
+ private final CustomizedCallbackHandler customizedCallbackHandler;
|
|
|
|
|
|
/**
|
|
|
* Creates a new SaslServerCallbackHandler.
|
|
|
*
|
|
|
* @param passwordFunction for determing the user's password
|
|
|
*/
|
|
|
- public SaslServerCallbackHandler(PasswordFunction passwordFunction) {
|
|
|
+ SaslServerCallbackHandler(Configuration conf, PasswordFunction passwordFunction) {
|
|
|
this.passwordFunction = passwordFunction;
|
|
|
+
|
|
|
+ final Class<? extends CustomizedCallbackHandler> clazz = conf.getClass(
|
|
|
+ HdfsClientConfigKeys.DFS_DATA_TRANSFER_SASL_CUSTOMIZEDCALLBACKHANDLER_CLASS_KEY,
|
|
|
+ CustomizedCallbackHandler.DefaultHandler.class, CustomizedCallbackHandler.class);
|
|
|
+ try {
|
|
|
+ this.customizedCallbackHandler = clazz.newInstance();
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new IllegalStateException("Failed to create a new instance of " + clazz, e);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -230,6 +241,7 @@ public class SaslDataTransferServer {
|
|
|
NameCallback nc = null;
|
|
|
PasswordCallback pc = null;
|
|
|
AuthorizeCallback ac = null;
|
|
|
+ List<Callback> unknownCallbacks = null;
|
|
|
for (Callback callback : callbacks) {
|
|
|
if (callback instanceof AuthorizeCallback) {
|
|
|
ac = (AuthorizeCallback) callback;
|
|
@@ -240,8 +252,10 @@ public class SaslDataTransferServer {
|
|
|
} else if (callback instanceof RealmCallback) {
|
|
|
continue; // realm is ignored
|
|
|
} else {
|
|
|
- throw new UnsupportedCallbackException(callback,
|
|
|
- "Unrecognized SASL Callback: " + callback);
|
|
|
+ if (unknownCallbacks == null) {
|
|
|
+ unknownCallbacks = new ArrayList<>();
|
|
|
+ }
|
|
|
+ unknownCallbacks.add(callback);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -253,6 +267,12 @@ public class SaslDataTransferServer {
|
|
|
ac.setAuthorized(true);
|
|
|
ac.setAuthorizedID(ac.getAuthorizationID());
|
|
|
}
|
|
|
+
|
|
|
+ if (unknownCallbacks != null) {
|
|
|
+ final String name = nc != null ? nc.getDefaultName() : null;
|
|
|
+ final char[] password = name != null ? passwordFunction.apply(name) : null;
|
|
|
+ customizedCallbackHandler.handleCallback(unknownCallbacks, name, password);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -298,7 +318,7 @@ public class SaslDataTransferServer {
|
|
|
Map<String, String> saslProps = saslPropsResolver.getServerProperties(
|
|
|
getPeerAddress(peer));
|
|
|
|
|
|
- CallbackHandler callbackHandler = new SaslServerCallbackHandler(
|
|
|
+ final CallbackHandler callbackHandler = new SaslServerCallbackHandler(dnConf.getConf(),
|
|
|
new PasswordFunction() {
|
|
|
@Override
|
|
|
public char[] apply(String userName) throws IOException {
|