Author: shv Date: Tue Jun 5 05:28:58 2012 New Revision: 1346241 URL: http://svn.apache.org/viewvc?rev=1346241&view=rev Log: HADOOP-7215. RPC clients must use network interface corresponding to the host in the client's kerberos principal key. Contributed by Suresh Srinivas and Benoy Antony.
Modified: hadoop/common/branches/branch-0.22/common/CHANGES.txt hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/ipc/Client.java hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/net/NetUtils.java hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/security/SecurityUtil.java hadoop/common/branches/branch-0.22/common/src/test/core/org/apache/hadoop/security/TestSecurityUtil.java Modified: hadoop/common/branches/branch-0.22/common/CHANGES.txt URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.22/common/CHANGES.txt?rev=1346241&r1=1346240&r2=1346241&view=diff ============================================================================== --- hadoop/common/branches/branch-0.22/common/CHANGES.txt (original) +++ hadoop/common/branches/branch-0.22/common/CHANGES.txt Tue Jun 5 05:28:58 2012 @@ -40,6 +40,10 @@ Release 0.22.1 - Unreleased HADOOP-7272. Remove unnecessary security related info logs. (Suresh Srinivas and Benoy Antony via shv) + HADOOP-7215. RPC clients must use network interface corresponding to + the host in the client's kerberos principal key. + (Suresh Srinivas and Benoy Antony via shv) + Release 0.22.0 - 2011-11-29 INCOMPATIBLE CHANGES Modified: hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/ipc/Client.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/ipc/Client.java?rev=1346241&r1=1346240&r2=1346241&view=diff ============================================================================== --- hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/ipc/Client.java (original) +++ hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/ipc/Client.java Tue Jun 5 05:28:58 2012 @@ -32,7 +32,7 @@ import java.io.BufferedOutputStream; import java.io.FilterInputStream; import java.io.InputStream; import java.io.OutputStream; - +import java.net.InetAddress; import java.security.PrivilegedExceptionAction; import java.util.Hashtable; import java.util.Iterator; @@ -412,6 +412,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) { Modified: hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/net/NetUtils.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/net/NetUtils.java?rev=1346241&r1=1346240&r2=1346241&view=diff ============================================================================== --- hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/net/NetUtils.java (original) +++ hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/net/NetUtils.java Tue Jun 5 05:28:58 2012 @@ -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() @@ -460,4 +462,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; + } } Modified: hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/security/SecurityUtil.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/security/SecurityUtil.java?rev=1346241&r1=1346240&r2=1346241&view=diff ============================================================================== --- hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/security/SecurityUtil.java (original) +++ hadoop/common/branches/branch-0.22/common/src/java/org/apache/hadoop/security/SecurityUtil.java Tue Jun 5 05:28:58 2012 @@ -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(); + } } Modified: hadoop/common/branches/branch-0.22/common/src/test/core/org/apache/hadoop/security/TestSecurityUtil.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.22/common/src/test/core/org/apache/hadoop/security/TestSecurityUtil.java?rev=1346241&r1=1346240&r2=1346241&view=diff ============================================================================== --- hadoop/common/branches/branch-0.22/common/src/test/core/org/apache/hadoop/security/TestSecurityUtil.java (original) +++ hadoop/common/branches/branch-0.22/common/src/test/core/org/apache/hadoop/security/TestSecurityUtil.java Tue Jun 5 05:28:58 2012 @@ -115,4 +115,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")); + } }