org.elasticsearch.xpack.security.transport.SSLEngineUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.elasticsearch.xpack.security.transport.SSLEngineUtils.java

Source

/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License;
 * you may not use this file except in compliance with the Elastic License.
 */
package org.elasticsearch.xpack.security.transport;

import io.netty.channel.Channel;
import io.netty.handler.ssl.SslHandler;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.util.Supplier;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.http.HttpChannel;
import org.elasticsearch.http.netty4.Netty4HttpChannel;
import org.elasticsearch.http.nio.NioHttpChannel;
import org.elasticsearch.nio.SocketChannelContext;
import org.elasticsearch.transport.TcpChannel;
import org.elasticsearch.transport.netty4.Netty4TcpChannel;
import org.elasticsearch.transport.nio.NioTcpChannel;
import org.elasticsearch.xpack.security.authc.pki.PkiRealm;
import org.elasticsearch.xpack.security.transport.nio.SSLChannelContext;

import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLPeerUnverifiedException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;

public class SSLEngineUtils {

    private SSLEngineUtils() {
    }

    public static void extractClientCertificates(Logger logger, ThreadContext threadContext,
            HttpChannel httpChannel) {
        SSLEngine sslEngine = getSSLEngine(httpChannel);
        extract(logger, threadContext, sslEngine, httpChannel);
    }

    public static void extractClientCertificates(Logger logger, ThreadContext threadContext,
            TcpChannel tcpChannel) {
        SSLEngine sslEngine = getSSLEngine(tcpChannel);
        extract(logger, threadContext, sslEngine, tcpChannel);
    }

    public static SSLEngine getSSLEngine(HttpChannel httpChannel) {
        if (httpChannel instanceof Netty4HttpChannel) {
            Channel nettyChannel = ((Netty4HttpChannel) httpChannel).getNettyChannel();
            SslHandler handler = nettyChannel.pipeline().get(SslHandler.class);
            assert handler != null : "Must have SslHandler";
            return handler.engine();
        } else if (httpChannel instanceof NioHttpChannel) {
            SocketChannelContext context = ((NioHttpChannel) httpChannel).getContext();
            assert context instanceof SSLChannelContext : "Must be SSLChannelContext.class, found:  "
                    + context.getClass();
            return ((SSLChannelContext) context).getSSLEngine();
        } else {
            throw new AssertionError("Unknown channel class type: " + httpChannel.getClass());
        }
    }

    public static SSLEngine getSSLEngine(TcpChannel tcpChannel) {
        if (tcpChannel instanceof Netty4TcpChannel) {
            Channel nettyChannel = ((Netty4TcpChannel) tcpChannel).getNettyChannel();
            SslHandler handler = nettyChannel.pipeline().get(SslHandler.class);
            assert handler != null : "Must have SslHandler";
            return handler.engine();
        } else if (tcpChannel instanceof NioTcpChannel) {
            SocketChannelContext context = ((NioTcpChannel) tcpChannel).getContext();
            assert context instanceof SSLChannelContext : "Must be SSLChannelContext.class, found:  "
                    + context.getClass();
            return ((SSLChannelContext) context).getSSLEngine();
        } else {
            throw new AssertionError("Unknown channel class type: " + tcpChannel.getClass());
        }
    }

    private static void extract(Logger logger, ThreadContext threadContext, SSLEngine sslEngine, Object channel) {
        try {
            Certificate[] certs = sslEngine.getSession().getPeerCertificates();
            if (certs instanceof X509Certificate[]) {
                threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, certs);
            }
        } catch (SSLPeerUnverifiedException e) {
            // this happens when client authentication is optional and the client does not provide credentials. If client
            // authentication was required then this connection should be closed before ever getting into this class
            assert sslEngine.getNeedClientAuth() == false;
            assert sslEngine.getWantClientAuth();
            if (logger.isTraceEnabled()) {
                logger.trace((Supplier<?>) () -> new ParameterizedMessage(
                        "SSL Peer did not present a certificate on channel [{}]", channel), e);
            } else if (logger.isDebugEnabled()) {
                logger.debug("SSL Peer did not present a certificate on channel [{}]", channel);
            }
        }
    }
}