|
@@ -85,6 +85,7 @@ import org.apache.hadoop.util.StringUtils;
|
|
*/
|
|
*/
|
|
public abstract class Server {
|
|
public abstract class Server {
|
|
private final boolean authorize;
|
|
private final boolean authorize;
|
|
|
|
+ private boolean isSecurityEnabled;
|
|
|
|
|
|
/**
|
|
/**
|
|
* The first four bytes of Hadoop RPC connections
|
|
* The first four bytes of Hadoop RPC connections
|
|
@@ -746,6 +747,7 @@ public abstract class Server {
|
|
SaslServer saslServer;
|
|
SaslServer saslServer;
|
|
private AuthMethod authMethod;
|
|
private AuthMethod authMethod;
|
|
private boolean saslContextEstablished;
|
|
private boolean saslContextEstablished;
|
|
|
|
+ private boolean skipInitialSaslHandshake;
|
|
private ByteBuffer rpcHeaderBuffer;
|
|
private ByteBuffer rpcHeaderBuffer;
|
|
private ByteBuffer unwrappedData;
|
|
private ByteBuffer unwrappedData;
|
|
private ByteBuffer unwrappedDataLengthBuffer;
|
|
private ByteBuffer unwrappedDataLengthBuffer;
|
|
@@ -929,6 +931,15 @@ public abstract class Server {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private void askClientToUseSimpleAuth() throws IOException {
|
|
|
|
+ saslCall.connection = this;
|
|
|
|
+ saslResponse.reset();
|
|
|
|
+ DataOutputStream out = new DataOutputStream(saslResponse);
|
|
|
|
+ out.writeInt(SaslRpcServer.SWITCH_TO_SIMPLE_AUTH);
|
|
|
|
+ saslCall.setResponse(ByteBuffer.wrap(saslResponse.toByteArray()));
|
|
|
|
+ responder.doRespond(saslCall);
|
|
|
|
+ }
|
|
|
|
+
|
|
public int readAndProcess() throws IOException, InterruptedException {
|
|
public int readAndProcess() throws IOException, InterruptedException {
|
|
while (true) {
|
|
while (true) {
|
|
/* Read at most one RPC. If the header is not read completely yet
|
|
/* Read at most one RPC. If the header is not read completely yet
|
|
@@ -957,13 +968,16 @@ public abstract class Server {
|
|
if (authMethod == null) {
|
|
if (authMethod == null) {
|
|
throw new IOException("Unable to read authentication method");
|
|
throw new IOException("Unable to read authentication method");
|
|
}
|
|
}
|
|
- if (UserGroupInformation.isSecurityEnabled()
|
|
|
|
- && authMethod == AuthMethod.SIMPLE) {
|
|
|
|
|
|
+ if (isSecurityEnabled && authMethod == AuthMethod.SIMPLE) {
|
|
throw new IOException("Authentication is required");
|
|
throw new IOException("Authentication is required");
|
|
- }
|
|
|
|
- if (!UserGroupInformation.isSecurityEnabled()
|
|
|
|
- && authMethod != AuthMethod.SIMPLE) {
|
|
|
|
- throw new IOException("Authentication is not supported");
|
|
|
|
|
|
+ }
|
|
|
|
+ if (!isSecurityEnabled && authMethod != AuthMethod.SIMPLE) {
|
|
|
|
+ askClientToUseSimpleAuth();
|
|
|
|
+ authMethod = AuthMethod.SIMPLE;
|
|
|
|
+ // client has already sent the initial Sasl message and we
|
|
|
|
+ // should ignore it. Both client and server should fall back
|
|
|
|
+ // to simple auth from now on.
|
|
|
|
+ skipInitialSaslHandshake = true;
|
|
}
|
|
}
|
|
if (authMethod != AuthMethod.SIMPLE) {
|
|
if (authMethod != AuthMethod.SIMPLE) {
|
|
useSasl = true;
|
|
useSasl = true;
|
|
@@ -1000,6 +1014,11 @@ public abstract class Server {
|
|
if (data.remaining() == 0) {
|
|
if (data.remaining() == 0) {
|
|
dataLengthBuffer.clear();
|
|
dataLengthBuffer.clear();
|
|
data.flip();
|
|
data.flip();
|
|
|
|
+ if (skipInitialSaslHandshake) {
|
|
|
|
+ data = null;
|
|
|
|
+ skipInitialSaslHandshake = false;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
boolean isHeaderRead = headerRead;
|
|
boolean isHeaderRead = headerRead;
|
|
if (useSasl) {
|
|
if (useSasl) {
|
|
saslReadAndProcess(data.array());
|
|
saslReadAndProcess(data.array());
|
|
@@ -1278,6 +1297,7 @@ public abstract class Server {
|
|
this.authorize =
|
|
this.authorize =
|
|
conf.getBoolean(ServiceAuthorizationManager.SERVICE_AUTHORIZATION_CONFIG,
|
|
conf.getBoolean(ServiceAuthorizationManager.SERVICE_AUTHORIZATION_CONFIG,
|
|
false);
|
|
false);
|
|
|
|
+ this.isSecurityEnabled = UserGroupInformation.isSecurityEnabled();
|
|
|
|
|
|
// Start the listener here and let it bind to the port
|
|
// Start the listener here and let it bind to the port
|
|
listener = new Listener();
|
|
listener = new Listener();
|
|
@@ -1355,6 +1375,11 @@ public abstract class Server {
|
|
return conf;
|
|
return conf;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /** for unit testing only, should be called before server is started */
|
|
|
|
+ void disableSecurity() {
|
|
|
|
+ this.isSecurityEnabled = false;
|
|
|
|
+ }
|
|
|
|
+
|
|
/** Sets the socket buffer size used for responding to RPCs */
|
|
/** Sets the socket buffer size used for responding to RPCs */
|
|
public void setSocketSendBufSize(int size) { this.socketSendBufferSize = size; }
|
|
public void setSocketSendBufSize(int size) { this.socketSendBufferSize = size; }
|
|
|
|
|