Search in sources :

Example 1 with SslHandshakeInfo

use of com.netflix.netty.common.ssl.SslHandshakeInfo in project zuul by Netflix.

the class ClientRequestReceiver method buildZuulHttpRequest.

// Build a ZuulMessage from the netty request.
private HttpRequestMessage buildZuulHttpRequest(final HttpRequest nativeRequest, final ChannelHandlerContext clientCtx) {
    PerfMark.attachTag("path", nativeRequest, HttpRequest::uri);
    // Setup the context for this request.
    final SessionContext context;
    if (decorator != null) {
        // Optionally decorate the context.
        SessionContext tempContext = new SessionContext();
        // Store the netty channel in SessionContext.
        tempContext.set(CommonContextKeys.NETTY_SERVER_CHANNEL_HANDLER_CONTEXT, clientCtx);
        context = decorator.decorate(tempContext);
        // We expect the UUID is present after decoration
        PerfMark.attachTag("uuid", context, SessionContext::getUUID);
    } else {
        context = new SessionContext();
    }
    // Get the client IP (ignore XFF headers at this point, as that can be app specific).
    final Channel channel = clientCtx.channel();
    final String clientIp = channel.attr(SourceAddressChannelHandler.ATTR_SOURCE_ADDRESS).get();
    // This is the only way I found to get the port of the request with netty...
    final int port = channel.attr(SourceAddressChannelHandler.ATTR_SERVER_LOCAL_PORT).get();
    final String serverName = channel.attr(SourceAddressChannelHandler.ATTR_SERVER_LOCAL_ADDRESS).get();
    final SocketAddress clientDestinationAddress = channel.attr(SourceAddressChannelHandler.ATTR_LOCAL_ADDR).get();
    final InetSocketAddress proxyProtocolDestinationAddress = channel.attr(SourceAddressChannelHandler.ATTR_PROXY_PROTOCOL_DESTINATION_ADDRESS).get();
    if (proxyProtocolDestinationAddress != null) {
        context.set(CommonContextKeys.PROXY_PROTOCOL_DESTINATION_ADDRESS, proxyProtocolDestinationAddress);
    }
    // Store info about the SSL handshake if applicable, and choose the http scheme.
    String scheme = SCHEME_HTTP;
    final SslHandshakeInfo sslHandshakeInfo = channel.attr(SslHandshakeInfoHandler.ATTR_SSL_INFO).get();
    if (sslHandshakeInfo != null) {
        context.set(CommonContextKeys.SSL_HANDSHAKE_INFO, sslHandshakeInfo);
        scheme = SCHEME_HTTPS;
    }
    // Decide if this is HTTP/1 or HTTP/2.
    String protocol = channel.attr(PROTOCOL_NAME).get();
    if (protocol == null) {
        protocol = nativeRequest.protocolVersion().text();
    }
    // Strip off the query from the path.
    String path = parsePath(nativeRequest.uri());
    // Setup the req/resp message objects.
    final HttpRequestMessage request = new HttpRequestMessageImpl(context, protocol, nativeRequest.method().asciiName().toString().toLowerCase(), path, copyQueryParams(nativeRequest), copyHeaders(nativeRequest), clientIp, scheme, port, serverName, clientDestinationAddress, false);
    // a LastHttpContent without any prior HttpContent's.
    if (HttpUtils.hasChunkedTransferEncodingHeader(request) || HttpUtils.hasNonZeroContentLengthHeader(request)) {
        request.setHasBody(true);
    }
    // Store this original request info for future reference (ie. for metrics and access logging purposes).
    request.storeInboundRequest();
    // Store the netty request for use later.
    context.set(CommonContextKeys.NETTY_HTTP_REQUEST, nativeRequest);
    // Store zuul request on netty channel for later use.
    channel.attr(ATTR_ZUUL_REQ).set(request);
    if (nativeRequest instanceof DefaultFullHttpRequest) {
        final ByteBuf chunk = ((DefaultFullHttpRequest) nativeRequest).content();
        request.bufferBodyContents(new DefaultLastHttpContent(chunk));
    }
    return request;
}
Also used : DefaultFullHttpRequest(io.netty.handler.codec.http.DefaultFullHttpRequest) HttpRequest(io.netty.handler.codec.http.HttpRequest) DefaultFullHttpRequest(io.netty.handler.codec.http.DefaultFullHttpRequest) InetSocketAddress(java.net.InetSocketAddress) HttpRequestMessage(com.netflix.zuul.message.http.HttpRequestMessage) Channel(io.netty.channel.Channel) HttpRequestMessageImpl(com.netflix.zuul.message.http.HttpRequestMessageImpl) ByteBuf(io.netty.buffer.ByteBuf) SslHandshakeInfo(com.netflix.netty.common.ssl.SslHandshakeInfo) DefaultLastHttpContent(io.netty.handler.codec.http.DefaultLastHttpContent) SessionContext(com.netflix.zuul.context.SessionContext) SocketAddress(java.net.SocketAddress) InetSocketAddress(java.net.InetSocketAddress)

Example 2 with SslHandshakeInfo

use of com.netflix.netty.common.ssl.SslHandshakeInfo in project zuul by Netflix.

the class SslHandshakeInfoHandler method userEventTriggered.

@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    if (evt instanceof SslHandshakeCompletionEvent) {
        try {
            SslHandshakeCompletionEvent sslEvent = (SslHandshakeCompletionEvent) evt;
            if (sslEvent.isSuccess()) {
                CurrentPassport.fromChannel(ctx.channel()).add(PassportState.SERVER_CH_SSL_HANDSHAKE_COMPLETE);
                SslHandler sslhandler = ctx.channel().pipeline().get(SslHandler.class);
                SSLSession session = sslhandler.engine().getSession();
                ClientAuth clientAuth = whichClientAuthEnum(sslhandler);
                Certificate serverCert = null;
                X509Certificate peerCert = null;
                if ((clientAuth == ClientAuth.REQUIRE || clientAuth == ClientAuth.OPTIONAL) && session.getPeerCertificates() != null && session.getPeerCertificates().length > 0) {
                    peerCert = (X509Certificate) session.getPeerCertificates()[0];
                }
                if (session.getLocalCertificates() != null && session.getLocalCertificates().length > 0) {
                    serverCert = session.getLocalCertificates()[0];
                }
                SslHandshakeInfo info = new SslHandshakeInfo(isSSlFromIntermediary, session.getProtocol(), session.getCipherSuite(), clientAuth, serverCert, peerCert);
                ctx.channel().attr(ATTR_SSL_INFO).set(info);
                // Metrics.
                incrementCounters(sslEvent, info);
                logger.debug("Successful SSL Handshake: {}", info);
            } else {
                String clientIP = ctx.channel().attr(SourceAddressChannelHandler.ATTR_SOURCE_ADDRESS).get();
                Throwable cause = sslEvent.cause();
                PassportState passportState = CurrentPassport.fromChannel(ctx.channel()).getState();
                if (cause instanceof ClosedChannelException && (PassportState.SERVER_CH_INACTIVE.equals(passportState) || PassportState.SERVER_CH_IDLE_TIMEOUT.equals(passportState))) {
                    // Either client closed the connection without/before having completed a handshake, or
                    // the connection idle timed-out before handshake.
                    // NOTE: we were seeing a lot of these in prod and can repro by just telnetting to port and then closing terminal
                    // without sending anything.
                    // So don't treat these as SSL handshake failures.
                    logger.debug("Client closed connection or it idle timed-out without doing an ssl handshake. " + ", client_ip = " + clientIP + ", channel_info = " + ChannelUtils.channelInfoForLogging(ctx.channel()));
                } else if (cause instanceof SSLException && cause.getMessage().contains("handshake timed out")) {
                    logger.debug("Client timed-out doing the ssl handshake. " + ", client_ip = " + clientIP + ", channel_info = " + ChannelUtils.channelInfoForLogging(ctx.channel()));
                } else if (cause instanceof SSLException && cause.getMessage().contains("failure when writing TLS control frames")) {
                    // This can happen if the ClientHello is sent followed  by a RST packet, before we can respond.
                    logger.debug("Client terminated handshake early." + ", client_ip = " + clientIP + ", channel_info = " + ChannelUtils.channelInfoForLogging(ctx.channel()));
                } else {
                    String msg = "Unsuccessful SSL Handshake: " + sslEvent + ", client_ip = " + clientIP + ", channel_info = " + ChannelUtils.channelInfoForLogging(ctx.channel()) + ", error = " + cause;
                    if (cause instanceof ClosedChannelException) {
                        logger.debug(msg);
                    } else {
                        logger.debug(msg, cause);
                    }
                    incrementCounters(sslEvent, null);
                }
            }
        } catch (Throwable e) {
            logger.warn("Error getting the SSL handshake info.", e);
        } finally {
            // Now remove this handler from the pipeline as no longer needed once the ssl handshake has completed.
            ctx.pipeline().remove(this);
        }
    } else if (evt instanceof SslCloseCompletionEvent) {
    // TODO - increment a separate metric for this event?
    } else if (evt instanceof SniCompletionEvent) {
        logger.debug("SNI Parsing Complete: {}", evt);
        SniCompletionEvent sniCompletionEvent = (SniCompletionEvent) evt;
        if (sniCompletionEvent.isSuccess()) {
            spectatorRegistry.counter("zuul.sni.parse.success").increment();
        } else {
            Throwable cause = sniCompletionEvent.cause();
            spectatorRegistry.counter("zuul.sni.parse.failure", "cause", cause != null ? cause.getMessage() : "UNKNOWN").increment();
        }
    }
    super.userEventTriggered(ctx, evt);
}
Also used : ClosedChannelException(java.nio.channels.ClosedChannelException) SslHandshakeCompletionEvent(io.netty.handler.ssl.SslHandshakeCompletionEvent) SniCompletionEvent(io.netty.handler.ssl.SniCompletionEvent) SSLSession(javax.net.ssl.SSLSession) ClientAuth(io.netty.handler.ssl.ClientAuth) SSLException(javax.net.ssl.SSLException) SslHandler(io.netty.handler.ssl.SslHandler) X509Certificate(java.security.cert.X509Certificate) PassportState(com.netflix.zuul.passport.PassportState) SslHandshakeInfo(com.netflix.netty.common.ssl.SslHandshakeInfo) SslCloseCompletionEvent(io.netty.handler.ssl.SslCloseCompletionEvent) X509Certificate(java.security.cert.X509Certificate) Certificate(java.security.cert.Certificate)

Example 3 with SslHandshakeInfo

use of com.netflix.netty.common.ssl.SslHandshakeInfo in project zuul by Netflix.

the class StripUntrustedProxyHeadersHandler method connectionIsUsingMutualSSLWithAuthEnforced.

@VisibleForTesting
boolean connectionIsUsingMutualSSLWithAuthEnforced(Channel ch) {
    boolean is = false;
    SslHandshakeInfo sslHandshakeInfo = ch.attr(SslHandshakeInfoHandler.ATTR_SSL_INFO).get();
    if (sslHandshakeInfo != null) {
        if (sslHandshakeInfo.getClientAuthRequirement() == ClientAuth.REQUIRE) {
            is = true;
        }
    }
    return is;
}
Also used : SslHandshakeInfo(com.netflix.netty.common.ssl.SslHandshakeInfo) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Aggregations

SslHandshakeInfo (com.netflix.netty.common.ssl.SslHandshakeInfo)3 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 SessionContext (com.netflix.zuul.context.SessionContext)1 HttpRequestMessage (com.netflix.zuul.message.http.HttpRequestMessage)1 HttpRequestMessageImpl (com.netflix.zuul.message.http.HttpRequestMessageImpl)1 PassportState (com.netflix.zuul.passport.PassportState)1 ByteBuf (io.netty.buffer.ByteBuf)1 Channel (io.netty.channel.Channel)1 DefaultFullHttpRequest (io.netty.handler.codec.http.DefaultFullHttpRequest)1 DefaultLastHttpContent (io.netty.handler.codec.http.DefaultLastHttpContent)1 HttpRequest (io.netty.handler.codec.http.HttpRequest)1 ClientAuth (io.netty.handler.ssl.ClientAuth)1 SniCompletionEvent (io.netty.handler.ssl.SniCompletionEvent)1 SslCloseCompletionEvent (io.netty.handler.ssl.SslCloseCompletionEvent)1 SslHandler (io.netty.handler.ssl.SslHandler)1 SslHandshakeCompletionEvent (io.netty.handler.ssl.SslHandshakeCompletionEvent)1 InetSocketAddress (java.net.InetSocketAddress)1 SocketAddress (java.net.SocketAddress)1 ClosedChannelException (java.nio.channels.ClosedChannelException)1 Certificate (java.security.cert.Certificate)1