All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hotels.styx.server.netty.SslContexts Maven / Gradle / Ivy

/**
 * Copyright (C) 2013-2018 Expedia Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hotels.styx.server.netty;

import com.codahale.metrics.Gauge;
import com.hotels.styx.api.metrics.MetricRegistry;
import com.hotels.styx.server.HttpsConnectorConfig;
import io.netty.handler.ssl.OpenSslSessionContext;
import io.netty.handler.ssl.OpenSslSessionStats;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.util.SelfSignedCertificate;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSessionContext;
import java.io.File;
import java.security.cert.CertificateException;
import java.util.List;

import static com.google.common.base.Throwables.propagate;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

/**
 * Methods for producing {@link SslContext} classes.
 */
public final class SslContexts {
    private SslContexts() {
    }

    /**
     * Produce an SslContext based on the provided configuration.
     *
     * @param httpsConnectorConfig configuration
     * @return SslContext
     */
    public static SslContext newSSLContext(HttpsConnectorConfig httpsConnectorConfig) {
        SslContextBuilder builder = httpsConnectorConfig.isConfigured()
                ? sslContextFromConfiguration(httpsConnectorConfig)
                : sslContextFromSelfSignedCertificate(httpsConnectorConfig);

        try {
            return builder.build();
        } catch (SSLException e) {
            throw propagate(e);
        }
    }

    /**
     * Produce an SslContext that will record metrics, based on the provided configuration.
     *
     * @param httpsConnectorConfig configuration
     * @param metricRegistry       metric registry
     * @return SslContext
     */
    public static SslContext newSSLContext(HttpsConnectorConfig httpsConnectorConfig, MetricRegistry metricRegistry) {
        SslContext sslContext = newSSLContext(httpsConnectorConfig);
        registerOpenSslStats(sslContext, metricRegistry);
        return sslContext;
    }

    private static void registerOpenSslStats(SslContext sslContext, MetricRegistry metricRegistry) {
        SSLSessionContext sslSessionContext = sslContext.sessionContext();
        if (sslSessionContext instanceof OpenSslSessionContext) {
            OpenSslSessionStats stats = ((OpenSslSessionContext) sslSessionContext).stats();
            MetricRegistry sessionStatsRegistry = metricRegistry.scope("connections.openssl.session");
            sessionStatsRegistry.register("number", (Gauge) stats::number);
            sessionStatsRegistry.register("accept", (Gauge) stats::accept);
            sessionStatsRegistry.register("acceptGood", (Gauge) stats::acceptGood);
            sessionStatsRegistry.register("acceptRenegotiate", (Gauge) stats::acceptRenegotiate);
            sessionStatsRegistry.register("hits", (Gauge) stats::hits);
            sessionStatsRegistry.register("misses", (Gauge) stats::misses);
            sessionStatsRegistry.register("cbHits", (Gauge) stats::cbHits);
            sessionStatsRegistry.register("cacheFull", (Gauge) stats::cacheFull);
            sessionStatsRegistry.register("timeouts", (Gauge) stats::timeouts);
        }
    }

    private static SelfSignedCertificate newSelfSignedCertificate() {
        try {
            return new SelfSignedCertificate();
        } catch (CertificateException e) {
            throw propagate(e);
        }
    }

    private static SslContextBuilder sslContextFromSelfSignedCertificate(HttpsConnectorConfig httpsConnectorConfig) {
        SelfSignedCertificate certificate = newSelfSignedCertificate();
        return SslContextBuilder.forServer(certificate.certificate(), certificate.privateKey())
                .protocols(toProtocolsOrDefault(httpsConnectorConfig.protocols()))
                .ciphers(toCiphersOrDefault(httpsConnectorConfig.ciphers()))
                .sslProvider(SslProvider.valueOf(httpsConnectorConfig.sslProvider()));
    }

    private static SslContextBuilder sslContextFromConfiguration(HttpsConnectorConfig httpsConnectorConfig) {
        return SslContextBuilder.forServer(new File(httpsConnectorConfig.certificateFile()), new File(httpsConnectorConfig.certificateKeyFile()))
                .sslProvider(SslProvider.valueOf(httpsConnectorConfig.sslProvider()))
                .ciphers(toCiphersOrDefault(httpsConnectorConfig.ciphers()))
                .sessionTimeout(MILLISECONDS.toSeconds(httpsConnectorConfig.sessionTimeoutMillis()))
                .sessionCacheSize(httpsConnectorConfig.sessionCacheSize())
                .protocols(toProtocolsOrDefault(httpsConnectorConfig.protocols()));
    }

    private static Iterable toCiphersOrDefault(List ciphers) {
        return ciphers.isEmpty() ? null : ciphers;
    }

    private static String[] toProtocolsOrDefault(List elems) {
        return (elems != null && elems.size() > 0)
                ? elems.toArray(new String[elems.size()])
                : null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy