From 609a55c57ce23eaedd6b53dc9bccc25aa73bc690 Mon Sep 17 00:00:00 2001 From: Gerd Behrmann Date: Wed, 12 Oct 2016 10:04:58 +0200 Subject: [PATCH 1/2] xrootd4j: Move HAProxy processing to xrootd4j library To enable HAProxy aware code in xrootd4j, this patch moves the HAProxy support code from dCache to xrootd4j. Target: master,3.2 Acked-by: Anupam Ashish Reviewed at https://rb.dcache.org/r/9831/ --- pom.xml | 7 +- xrootd4j/pom.xml | 4 ++ .../xrootd/core/XrootdRequestHandler.java | 72 +++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e4e32822..b4572fd1 100644 --- a/pom.xml +++ b/pom.xml @@ -131,7 +131,12 @@ io.netty netty-handler - 4.1.4.Final + 4.1.5.Final + + + io.netty + netty-codec-haproxy + 4.1.5.Final org.slf4j diff --git a/xrootd4j/pom.xml b/xrootd4j/pom.xml index 8c08bddb..b79c6e71 100644 --- a/xrootd4j/pom.xml +++ b/xrootd4j/pom.xml @@ -52,6 +52,10 @@ io.netty netty-handler + + io.netty + netty-codec-haproxy + org.slf4j slf4j-api diff --git a/xrootd4j/src/main/java/org/dcache/xrootd/core/XrootdRequestHandler.java b/xrootd4j/src/main/java/org/dcache/xrootd/core/XrootdRequestHandler.java index 36269957..806b1897 100644 --- a/xrootd4j/src/main/java/org/dcache/xrootd/core/XrootdRequestHandler.java +++ b/xrootd4j/src/main/java/org/dcache/xrootd/core/XrootdRequestHandler.java @@ -19,14 +19,20 @@ package org.dcache.xrootd.core; import com.google.common.base.Strings; +import com.google.common.net.InetAddresses; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.codec.haproxy.HAProxyMessage; +import io.netty.handler.codec.haproxy.HAProxyProxiedProtocol; import io.netty.util.ReferenceCountUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.InetSocketAddress; +import java.util.Objects; + import org.dcache.xrootd.protocol.messages.AuthenticationRequest; import org.dcache.xrootd.protocol.messages.CloseRequest; import org.dcache.xrootd.protocol.messages.DirListRequest; @@ -72,11 +78,49 @@ public class XrootdRequestHandler extends ChannelInboundHandlerAdapter private static final Logger _log = LoggerFactory.getLogger(XrootdRequestHandler.class); + private boolean _isHealthCheck; + + private InetSocketAddress _destinationAddress; + + private InetSocketAddress _sourceAddress; + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception + { + _destinationAddress = (InetSocketAddress) ctx.channel().localAddress(); + _sourceAddress = (InetSocketAddress) ctx.channel().remoteAddress(); + } + @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof XrootdRequest) { requestReceived(ctx, (XrootdRequest) msg); + } else if (msg instanceof HAProxyMessage) { + HAProxyMessage proxyMessage = (HAProxyMessage) msg; + switch (proxyMessage.command()) { + case LOCAL: + _isHealthCheck = true; + break; + case PROXY: + String sourceAddress = proxyMessage.sourceAddress(); + String destinationAddress = proxyMessage.destinationAddress(); + InetSocketAddress localAddress = (InetSocketAddress) ctx.channel().localAddress(); + if (proxyMessage.proxiedProtocol() == HAProxyProxiedProtocol.TCP4 || + proxyMessage.proxiedProtocol() == HAProxyProxiedProtocol.TCP6) { + if (Objects.equals(destinationAddress, localAddress.getAddress().getHostAddress())) { + /* Workaround for what looks like a bug in HAProxy - health checks should + * generate a LOCAL command, but it appears they do actually use PROXY. + */ + _isHealthCheck = true; + } else { + _destinationAddress = new InetSocketAddress(InetAddresses.forString(destinationAddress), proxyMessage.destinationPort()); + _sourceAddress = new InetSocketAddress(InetAddresses.forString(sourceAddress), proxyMessage.sourcePort()); + } + } + break; + } + ctx.fireChannelRead(msg); } else { ctx.fireChannelRead(msg); } @@ -362,4 +406,32 @@ protected Object doOnEndSession(ChannelHandlerContext ctx, { return unsupported(ctx, request); } + + /** + * The socket address the client connected to. May be the local address + * of the channel, but could also be an address on a proxy server + * between the client and the server. + */ + protected InetSocketAddress getDestinationAddress() + { + return _destinationAddress; + } + + /** + * The socket address the client connected from. May be the remote address + * of the channel, but in case a proxy is in between the client and the + * server, the source address will be a different from the remote address. + */ + protected InetSocketAddress getSourceAddress() + { + return _sourceAddress; + } + + /** + * True if this looks like a health check connection from a proxy server. + */ + protected boolean isHealthCheck() + { + return _isHealthCheck; + } } From e870e4eb47d21e926af67976d5fddabfdc12a68a Mon Sep 17 00:00:00 2001 From: Gerd Behrmann Date: Wed, 12 Oct 2016 10:10:24 +0200 Subject: [PATCH 2/2] xrootd4j: Enable HAProxy aware authorization Authorization plugins can authorize by local and remote socket address. E.g. the alice authorization token plugin verifies that the token is for a TURL for the destination address. In the pressence of an HAProxy in front of the server, the destination address is different from the local address of the channel and thus the alice token plugin fails. This patch injects the actual source and destination address into the authorization plugin. Target: master,3.2 Acked-by: Anupam Ashish Reviewed at https://rb.dcache.org/r/9832/ --- .../xrootd/core/XrootdAuthorizationHandler.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/xrootd4j/src/main/java/org/dcache/xrootd/core/XrootdAuthorizationHandler.java b/xrootd4j/src/main/java/org/dcache/xrootd/core/XrootdAuthorizationHandler.java index 9e78c00c..f1814470 100644 --- a/xrootd4j/src/main/java/org/dcache/xrootd/core/XrootdAuthorizationHandler.java +++ b/xrootd4j/src/main/java/org/dcache/xrootd/core/XrootdAuthorizationHandler.java @@ -315,17 +315,14 @@ private String authorize(ChannelHandlerContext ctx, throws XrootdException { try { - Channel channel = ctx.channel(); - InetSocketAddress localAddress = - (InetSocketAddress) channel.localAddress(); - InetSocketAddress remoteAddress = - (InetSocketAddress) channel.remoteAddress(); + InetSocketAddress destinationAddress = getDestinationAddress(); + InetSocketAddress sourceAddress = getSourceAddress(); AuthorizationHandler handler = _authorizationFactory.createHandler(); return handler.authorize(request.getSubject(), - localAddress, - remoteAddress, + destinationAddress, + sourceAddress, path, OpaqueStringParser.getOpaqueMap(opaque), request.getRequestId(),