HADOOP-8784. Improve IPC.Client's token use (daryn)
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1397634 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
89b66da42c
commit
22ef03bc76
@ -312,6 +312,8 @@ Release 2.0.3-alpha - Unreleased
|
|||||||
HADOOP-8912. Add .gitattributes file to prevent CRLF and LF mismatches
|
HADOOP-8912. Add .gitattributes file to prevent CRLF and LF mismatches
|
||||||
for source and text files. (Raja Aluri via suresh)
|
for source and text files. (Raja Aluri via suresh)
|
||||||
|
|
||||||
|
HADOOP-8784. Improve IPC.Client's token use (daryn)
|
||||||
|
|
||||||
OPTIMIZATIONS
|
OPTIMIZATIONS
|
||||||
|
|
||||||
HADOOP-8866. SampleQuantiles#query is O(N^2) instead of O(N). (Andrew Wang
|
HADOOP-8866. SampleQuantiles#query is O(N^2) instead of O(N). (Andrew Wang
|
||||||
|
@ -225,7 +225,6 @@ private class Connection extends Thread {
|
|||||||
private IpcConnectionContextProto connectionContext; // connection context
|
private IpcConnectionContextProto connectionContext; // connection context
|
||||||
private final ConnectionId remoteId; // connection id
|
private final ConnectionId remoteId; // connection id
|
||||||
private AuthMethod authMethod; // authentication method
|
private AuthMethod authMethod; // authentication method
|
||||||
private boolean useSasl;
|
|
||||||
private Token<? extends TokenIdentifier> token;
|
private Token<? extends TokenIdentifier> token;
|
||||||
private SaslRpcClient saslRpcClient;
|
private SaslRpcClient saslRpcClient;
|
||||||
|
|
||||||
@ -270,8 +269,7 @@ public Connection(ConnectionId remoteId) throws IOException {
|
|||||||
|
|
||||||
UserGroupInformation ticket = remoteId.getTicket();
|
UserGroupInformation ticket = remoteId.getTicket();
|
||||||
Class<?> protocol = remoteId.getProtocol();
|
Class<?> protocol = remoteId.getProtocol();
|
||||||
this.useSasl = UserGroupInformation.isSecurityEnabled();
|
if (protocol != null) {
|
||||||
if (useSasl && protocol != null) {
|
|
||||||
TokenInfo tokenInfo = SecurityUtil.getTokenInfo(protocol, conf);
|
TokenInfo tokenInfo = SecurityUtil.getTokenInfo(protocol, conf);
|
||||||
if (tokenInfo != null) {
|
if (tokenInfo != null) {
|
||||||
TokenSelector<? extends TokenIdentifier> tokenSelector = null;
|
TokenSelector<? extends TokenIdentifier> tokenSelector = null;
|
||||||
@ -296,12 +294,12 @@ public Connection(ConnectionId remoteId) throws IOException {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!useSasl) {
|
if (token != null) {
|
||||||
authMethod = AuthMethod.SIMPLE;
|
|
||||||
} else if (token != null) {
|
|
||||||
authMethod = AuthMethod.DIGEST;
|
authMethod = AuthMethod.DIGEST;
|
||||||
} else {
|
} else if (UserGroupInformation.isSecurityEnabled()) {
|
||||||
authMethod = AuthMethod.KERBEROS;
|
authMethod = AuthMethod.KERBEROS;
|
||||||
|
} else {
|
||||||
|
authMethod = AuthMethod.SIMPLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionContext = ProtoUtil.makeIpcConnectionContext(
|
connectionContext = ProtoUtil.makeIpcConnectionContext(
|
||||||
@ -576,15 +574,13 @@ private synchronized void setupIOstreams() throws InterruptedException {
|
|||||||
InputStream inStream = NetUtils.getInputStream(socket);
|
InputStream inStream = NetUtils.getInputStream(socket);
|
||||||
OutputStream outStream = NetUtils.getOutputStream(socket);
|
OutputStream outStream = NetUtils.getOutputStream(socket);
|
||||||
writeConnectionHeader(outStream);
|
writeConnectionHeader(outStream);
|
||||||
if (useSasl) {
|
if (authMethod != AuthMethod.SIMPLE) {
|
||||||
final InputStream in2 = inStream;
|
final InputStream in2 = inStream;
|
||||||
final OutputStream out2 = outStream;
|
final OutputStream out2 = outStream;
|
||||||
UserGroupInformation ticket = remoteId.getTicket();
|
UserGroupInformation ticket = remoteId.getTicket();
|
||||||
if (authMethod == AuthMethod.KERBEROS) {
|
|
||||||
if (ticket.getRealUser() != null) {
|
if (ticket.getRealUser() != null) {
|
||||||
ticket = ticket.getRealUser();
|
ticket = ticket.getRealUser();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
boolean continueSasl = false;
|
boolean continueSasl = false;
|
||||||
try {
|
try {
|
||||||
continueSasl = ticket
|
continueSasl = ticket
|
||||||
@ -614,7 +610,6 @@ public Boolean run() throws IOException {
|
|||||||
connectionContext.getProtocol(),
|
connectionContext.getProtocol(),
|
||||||
ProtoUtil.getUgi(connectionContext.getUserInfo()),
|
ProtoUtil.getUgi(connectionContext.getUserInfo()),
|
||||||
authMethod);
|
authMethod);
|
||||||
useSasl = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1174,7 +1169,7 @@ public Writable call(RPC.RpcKind rpcKind, Writable rpcRequest,
|
|||||||
call.error);
|
call.error);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return call.rpcResponse;
|
return call.getRpcResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,7 @@
|
|||||||
package org.apache.hadoop.ipc;
|
package org.apache.hadoop.ipc;
|
||||||
|
|
||||||
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION;
|
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -44,6 +41,7 @@
|
|||||||
import org.apache.hadoop.io.Text;
|
import org.apache.hadoop.io.Text;
|
||||||
import org.apache.hadoop.ipc.Client.ConnectionId;
|
import org.apache.hadoop.ipc.Client.ConnectionId;
|
||||||
import org.apache.hadoop.net.NetUtils;
|
import org.apache.hadoop.net.NetUtils;
|
||||||
|
import org.apache.hadoop.security.AccessControlException;
|
||||||
import org.apache.hadoop.security.KerberosInfo;
|
import org.apache.hadoop.security.KerberosInfo;
|
||||||
import org.apache.hadoop.security.SaslInputStream;
|
import org.apache.hadoop.security.SaslInputStream;
|
||||||
import org.apache.hadoop.security.SaslRpcClient;
|
import org.apache.hadoop.security.SaslRpcClient;
|
||||||
@ -450,22 +448,99 @@ static void testKerberosRpc(String principal, String keytab) throws Exception {
|
|||||||
System.out.println("Test is successful.");
|
System.out.println("Test is successful.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// insecure -> insecure
|
||||||
@Test
|
@Test
|
||||||
public void testDigestAuthMethodSecureServer() throws Exception {
|
public void testInsecureClientInsecureServer() throws Exception {
|
||||||
checkDigestAuthMethod(true);
|
assertEquals(AuthenticationMethod.SIMPLE,
|
||||||
|
getAuthMethod(false, false, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDigestAuthMethodInsecureServer() throws Exception {
|
public void testInsecureClientInsecureServerWithToken() throws Exception {
|
||||||
checkDigestAuthMethod(false);
|
assertEquals(AuthenticationMethod.TOKEN,
|
||||||
|
getAuthMethod(false, false, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkDigestAuthMethod(boolean secureServer) throws Exception {
|
// insecure -> secure
|
||||||
|
@Test
|
||||||
|
public void testInsecureClientSecureServer() throws Exception {
|
||||||
|
RemoteException e = null;
|
||||||
|
try {
|
||||||
|
getAuthMethod(false, true, false);
|
||||||
|
} catch (RemoteException re) {
|
||||||
|
e = re;
|
||||||
|
}
|
||||||
|
assertNotNull(e);
|
||||||
|
assertEquals(AccessControlException.class.getName(), e.getClassName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInsecureClientSecureServerWithToken() throws Exception {
|
||||||
|
assertEquals(AuthenticationMethod.TOKEN,
|
||||||
|
getAuthMethod(false, true, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// secure -> secure
|
||||||
|
@Test
|
||||||
|
public void testSecureClientSecureServer() throws Exception {
|
||||||
|
/* Should be this when multiple secure auths are supported and we can
|
||||||
|
* dummy one out:
|
||||||
|
* assertEquals(AuthenticationMethod.SECURE_AUTH_METHOD,
|
||||||
|
* getAuthMethod(true, true, false));
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
getAuthMethod(true, true, false);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// can't actually test kerberos w/o kerberos...
|
||||||
|
String expectedError = "Failed to specify server's Kerberos principal";
|
||||||
|
String actualError = ioe.getMessage();
|
||||||
|
assertTrue("["+actualError+"] doesn't start with ["+expectedError+"]",
|
||||||
|
actualError.contains(expectedError));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSecureClientSecureServerWithToken() throws Exception {
|
||||||
|
assertEquals(AuthenticationMethod.TOKEN,
|
||||||
|
getAuthMethod(true, true, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// secure -> insecure
|
||||||
|
@Test
|
||||||
|
public void testSecureClientInsecureServerWithToken() throws Exception {
|
||||||
|
assertEquals(AuthenticationMethod.TOKEN,
|
||||||
|
getAuthMethod(true, false, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSecureClientInsecureServer() throws Exception {
|
||||||
|
/* Should be this when multiple secure auths are supported and we can
|
||||||
|
* dummy one out:
|
||||||
|
* assertEquals(AuthenticationMethod.SIMPLE
|
||||||
|
* getAuthMethod(true, false, false));
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
getAuthMethod(true, false, false);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// can't actually test kerberos w/o kerberos...
|
||||||
|
String expectedError = "Failed to specify server's Kerberos principal";
|
||||||
|
String actualError = ioe.getMessage();
|
||||||
|
assertTrue("["+actualError+"] doesn't start with ["+expectedError+"]",
|
||||||
|
actualError.contains(expectedError));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private AuthenticationMethod getAuthMethod(final boolean isSecureClient,
|
||||||
|
final boolean isSecureServer,
|
||||||
|
final boolean useToken
|
||||||
|
|
||||||
|
) throws Exception {
|
||||||
TestTokenSecretManager sm = new TestTokenSecretManager();
|
TestTokenSecretManager sm = new TestTokenSecretManager();
|
||||||
Server server = new RPC.Builder(conf).setProtocol(TestSaslProtocol.class)
|
Server server = new RPC.Builder(conf).setProtocol(TestSaslProtocol.class)
|
||||||
.setInstance(new TestSaslImpl()).setBindAddress(ADDRESS).setPort(0)
|
.setInstance(new TestSaslImpl()).setBindAddress(ADDRESS).setPort(0)
|
||||||
.setNumHandlers(5).setVerbose(true).setSecretManager(sm).build();
|
.setNumHandlers(5).setVerbose(true).setSecretManager(sm).build();
|
||||||
if (secureServer) {
|
if (isSecureServer) {
|
||||||
server.enableSecurity();
|
server.enableSecurity();
|
||||||
} else {
|
} else {
|
||||||
server.disableSecurity();
|
server.disableSecurity();
|
||||||
@ -474,31 +549,37 @@ private void checkDigestAuthMethod(boolean secureServer) throws Exception {
|
|||||||
|
|
||||||
final UserGroupInformation current = UserGroupInformation.getCurrentUser();
|
final UserGroupInformation current = UserGroupInformation.getCurrentUser();
|
||||||
final InetSocketAddress addr = NetUtils.getConnectAddress(server);
|
final InetSocketAddress addr = NetUtils.getConnectAddress(server);
|
||||||
TestTokenIdentifier tokenId = new TestTokenIdentifier(new Text(current
|
if (useToken) {
|
||||||
.getUserName()));
|
TestTokenIdentifier tokenId = new TestTokenIdentifier(
|
||||||
Token<TestTokenIdentifier> token = new Token<TestTokenIdentifier>(tokenId,
|
new Text(current.getUserName()));
|
||||||
sm);
|
Token<TestTokenIdentifier> token =
|
||||||
|
new Token<TestTokenIdentifier>(tokenId, sm);
|
||||||
SecurityUtil.setTokenService(token, addr);
|
SecurityUtil.setTokenService(token, addr);
|
||||||
current.addToken(token);
|
current.addToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
current.doAs(new PrivilegedExceptionAction<Object>() {
|
conf.set(HADOOP_SECURITY_AUTHENTICATION, isSecureClient ? "kerberos" : "simple");
|
||||||
|
UserGroupInformation.setConfiguration(conf);
|
||||||
|
try {
|
||||||
|
return current.doAs(new PrivilegedExceptionAction<AuthenticationMethod>() {
|
||||||
@Override
|
@Override
|
||||||
public Object run() throws IOException {
|
public AuthenticationMethod run() throws IOException {
|
||||||
TestSaslProtocol proxy = null;
|
TestSaslProtocol proxy = null;
|
||||||
try {
|
try {
|
||||||
proxy = (TestSaslProtocol) RPC.getProxy(TestSaslProtocol.class,
|
proxy = (TestSaslProtocol) RPC.getProxy(TestSaslProtocol.class,
|
||||||
TestSaslProtocol.versionID, addr, conf);
|
TestSaslProtocol.versionID, addr, conf);
|
||||||
Assert.assertEquals(AuthenticationMethod.TOKEN, proxy.getAuthMethod());
|
return proxy.getAuthMethod();
|
||||||
} finally {
|
} finally {
|
||||||
if (proxy != null) {
|
if (proxy != null) {
|
||||||
RPC.stopProxy(proxy);
|
RPC.stopProxy(proxy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} finally {
|
||||||
server.stop();
|
server.stop();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
System.out.println("Testing Kerberos authentication over RPC");
|
System.out.println("Testing Kerberos authentication over RPC");
|
||||||
|
Loading…
Reference in New Issue
Block a user