HADOOP-7215. RPC clients must use network interface corresponding to the host in the client's kerberos principal key. Contributed by Suresh Srinivas.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1087844 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f2625d494f
commit
67c79a2520
|
@ -124,6 +124,10 @@ Trunk (unreleased changes)
|
|||
HADOOP-7210. Chown command is not working from FSShell
|
||||
(Uma Maheswara Rao G via todd)
|
||||
|
||||
HADOOP-7215. RPC clients must use network interface corresponding to
|
||||
the host in the client's kerberos principal key. (suresh)
|
||||
|
||||
>>>>>>> .r1087843
|
||||
Release 0.22.0 - Unreleased
|
||||
|
||||
INCOMPATIBLE CHANGES
|
||||
|
|
|
@ -18,8 +18,11 @@
|
|||
|
||||
package org.apache.hadoop.ipc;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.Socket;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.net.ConnectException;
|
||||
|
@ -412,6 +415,27 @@ public class Client {
|
|||
try {
|
||||
this.socket = socketFactory.createSocket();
|
||||
this.socket.setTcpNoDelay(tcpNoDelay);
|
||||
|
||||
/*
|
||||
* Bind the socket to the host specified in the principal name of the
|
||||
* client, to ensure Server matching address of the client connection
|
||||
* to host name in principal passed.
|
||||
*/
|
||||
if (UserGroupInformation.isSecurityEnabled()) {
|
||||
KerberosInfo krbInfo =
|
||||
remoteId.getProtocol().getAnnotation(KerberosInfo.class);
|
||||
if (krbInfo != null && krbInfo.clientPrincipal() != null) {
|
||||
String host =
|
||||
SecurityUtil.getHostFromPrincipal(remoteId.getTicket().getUserName());
|
||||
|
||||
// If host name is a valid local address then bind socket to it
|
||||
InetAddress localAddr = NetUtils.getLocalInetAddress(host);
|
||||
if (localAddr != null) {
|
||||
this.socket.bind(new InetSocketAddress(localAddr, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// connection time out is 20s
|
||||
NetUtils.connect(this.socket, remoteId.getAddress(), 20000);
|
||||
if (rpcTimeout > 0) {
|
||||
|
|
|
@ -22,8 +22,10 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.URI;
|
||||
import java.net.UnknownHostException;
|
||||
import java.net.ConnectException;
|
||||
|
@ -250,7 +252,7 @@ public class NetUtils {
|
|||
* case, the timeout argument is ignored and the timeout set with
|
||||
* {@link Socket#setSoTimeout(int)} applies for reads.<br><br>
|
||||
*
|
||||
* Any socket created using socket factories returned by {@link #NetUtils},
|
||||
* Any socket created using socket factories returned by {@link NetUtils},
|
||||
* must use this interface instead of {@link Socket#getInputStream()}.
|
||||
*
|
||||
* @see #getInputStream(Socket, long)
|
||||
|
@ -272,7 +274,7 @@ public class NetUtils {
|
|||
* case, the timeout argument is ignored and the timeout set with
|
||||
* {@link Socket#setSoTimeout(int)} applies for reads.<br><br>
|
||||
*
|
||||
* Any socket created using socket factories returned by {@link #NetUtils},
|
||||
* Any socket created using socket factories returned by {@link NetUtils},
|
||||
* must use this interface instead of {@link Socket#getInputStream()}.
|
||||
*
|
||||
* @see Socket#getChannel()
|
||||
|
@ -301,7 +303,7 @@ public class NetUtils {
|
|||
* case, the timeout argument is ignored and the write will wait until
|
||||
* data is available.<br><br>
|
||||
*
|
||||
* Any socket created using socket factories returned by {@link #NetUtils},
|
||||
* Any socket created using socket factories returned by {@link NetUtils},
|
||||
* must use this interface instead of {@link Socket#getOutputStream()}.
|
||||
*
|
||||
* @see #getOutputStream(Socket, long)
|
||||
|
@ -323,7 +325,7 @@ public class NetUtils {
|
|||
* case, the timeout argument is ignored and the write will wait until
|
||||
* data is available.<br><br>
|
||||
*
|
||||
* Any socket created using socket factories returned by {@link #NetUtils},
|
||||
* Any socket created using socket factories returned by {@link NetUtils},
|
||||
* must use this interface instead of {@link Socket#getOutputStream()}.
|
||||
*
|
||||
* @see Socket#getChannel()
|
||||
|
@ -426,6 +428,9 @@ public class NetUtils {
|
|||
return hostNames;
|
||||
}
|
||||
|
||||
private static final Pattern ipPattern = // Pattern for matching hostname to ip:port
|
||||
Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:?\\d*");
|
||||
|
||||
/**
|
||||
* Attempt to obtain the host name of a name specified by ip address.
|
||||
* Check that the node name is an ip addr and if so, attempt to determine
|
||||
|
@ -434,8 +439,6 @@ public class NetUtils {
|
|||
*
|
||||
* @return Host name or null
|
||||
*/
|
||||
private static final Pattern ipPattern = // Pattern for matching hostname to ip:port
|
||||
Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:?\\d*");
|
||||
public static String getHostNameOfIP(String ip) {
|
||||
// If name is not an ip addr, don't bother looking it up
|
||||
if(!ipPattern.matcher(ip).matches())
|
||||
|
@ -460,4 +463,27 @@ public class NetUtils {
|
|||
try {return "" + InetAddress.getLocalHost();}
|
||||
catch(UnknownHostException uhe) {return "" + uhe;}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if {@code host} is a local host name and return {@link InetAddress}
|
||||
* corresponding to that address.
|
||||
*
|
||||
* @param host the specified host
|
||||
* @return a valid local {@link InetAddress} or null
|
||||
* @throws SocketException if an I/O error occurs
|
||||
*/
|
||||
public static InetAddress getLocalInetAddress(String host)
|
||||
throws SocketException {
|
||||
if (host == null) {
|
||||
return null;
|
||||
}
|
||||
InetAddress addr = null;
|
||||
try {
|
||||
addr = InetAddress.getByName(host);
|
||||
if (NetworkInterface.getByInetAddress(addr) == null) {
|
||||
addr = null; // Not a local address
|
||||
}
|
||||
} catch (UnknownHostException ignore) { }
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -282,4 +282,13 @@ public class SecurityUtil {
|
|||
sb.append(host).append(":").append(port);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the host name from the principal name of format <service>/host@realm.
|
||||
* @param principalName principal name of format as described above
|
||||
* @return host name if the the string conforms to the above format, else null
|
||||
*/
|
||||
public static String getHostFromPrincipal(String principalName) {
|
||||
return new KerberosName(principalName).getHostName();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ import java.net.Socket;
|
|||
import java.net.ConnectException;
|
||||
import java.net.SocketException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
|
||||
public class TestNetUtils {
|
||||
|
@ -58,4 +60,16 @@ public class TestNetUtils {
|
|||
assertTrue(se.getMessage().contains("Invalid argument"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {
|
||||
* @throws UnknownHostException @link NetUtils#getLocalInetAddress(String)
|
||||
* @throws SocketException
|
||||
*/
|
||||
@Test
|
||||
public void testGetLocalInetAddress() throws Exception {
|
||||
assertNotNull(NetUtils.getLocalInetAddress("127.0.0.1"));
|
||||
assertNull(NetUtils.getLocalInetAddress("invalid-address-for-test"));
|
||||
assertNull(NetUtils.getLocalInetAddress(null));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,4 +113,12 @@ public class TestSecurityUtil {
|
|||
}
|
||||
assertTrue("Exception for empty keytabfile name was expected", gotException);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetHostFromPrincipal() {
|
||||
assertEquals("host",
|
||||
SecurityUtil.getHostFromPrincipal("service/host@realm"));
|
||||
assertEquals(null,
|
||||
SecurityUtil.getHostFromPrincipal("service@realm"));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue