Exemple #1
0
    /// <summary>
    /// Configure Kestrel to use HTTPS. This does not use default certificates or other defaults specified via config or
    /// <see cref="KestrelServerOptions.ConfigureHttpsDefaults(Action{HttpsConnectionAdapterOptions})"/>.
    /// </summary>
    /// <param name="listenOptions">The <see cref="ListenOptions"/> to configure.</param>
    /// <param name="callbackOptions">Options for a per connection callback.</param>
    /// <returns>The <see cref="ListenOptions"/>.</returns>
    public static ListenOptions UseHttps(this ListenOptions listenOptions, TlsHandshakeCallbackOptions callbackOptions)
    {
        if (callbackOptions is null)
        {
            throw new ArgumentNullException(nameof(callbackOptions));
        }

        if (callbackOptions.OnConnection is null)
        {
            throw new ArgumentException($"{nameof(TlsHandshakeCallbackOptions.OnConnection)} must not be null.");
        }

        var loggerFactory = listenOptions.KestrelServerOptions?.ApplicationServices.GetRequiredService <ILoggerFactory>() ?? NullLoggerFactory.Instance;

        listenOptions.IsTls = true;
        listenOptions.HttpsCallbackOptions = callbackOptions;

        listenOptions.Use(next =>
        {
            // Set the list of protocols from listen options.
            // Set it inside Use delegate so Protocols and UseHttps can be called out of order.
            callbackOptions.HttpProtocols = listenOptions.Protocols;

            var middleware = new HttpsConnectionMiddleware(next, callbackOptions, loggerFactory);
            return(middleware.OnConnectionAsync);
        });

        return(listenOptions);
    }
Exemple #2
0
        /// <summary>
        /// Configure Kestrel to use HTTPS. This does not use default certificates or other defaults specified via config or
        /// <see cref="KestrelServerOptions.ConfigureHttpsDefaults(Action{HttpsConnectionAdapterOptions})"/>.
        /// </summary>
        /// <param name="listenOptions">The <see cref="ListenOptions"/> to configure.</param>
        /// <param name="callbackOptions">Options for a per connection callback.</param>
        /// <returns>The <see cref="ListenOptions"/>.</returns>
        public static ListenOptions UseHttps(this ListenOptions listenOptions, TlsHandshakeCallbackOptions callbackOptions)
        {
            if (callbackOptions is null)
            {
                throw new ArgumentNullException(nameof(callbackOptions));
            }

            if (callbackOptions.OnConnection is null)
            {
                throw new ArgumentException($"{nameof(TlsHandshakeCallbackOptions.OnConnection)} must not be null.");
            }

            if (listenOptions.Protocols.HasFlag(HttpProtocols.Http3))
            {
                throw new NotSupportedException($"{nameof(UseHttps)} with {nameof(TlsHandshakeCallbackOptions)} is not supported with HTTP/3.");
            }

            var loggerFactory = listenOptions.KestrelServerOptions?.ApplicationServices.GetRequiredService <ILoggerFactory>() ?? NullLoggerFactory.Instance;

            listenOptions.IsTls = true;
            listenOptions.Use(next =>
            {
                // Set the list of protocols from listen options
                callbackOptions.HttpProtocols = listenOptions.Protocols;
                var middleware = new HttpsConnectionMiddleware(next, callbackOptions, loggerFactory);
                return(middleware.OnConnectionAsync);
            });

            return(listenOptions);
        }
Exemple #3
0
    // Adds endpoints from config to KestrelServerOptions.ConfigurationBackedListenOptions and configures some other options.
    // Any endpoints that were removed from the last time endpoints were loaded are returned.
    internal (List <ListenOptions>, List <ListenOptions>) Reload()
    {
        var endpointsToStop  = Options.ConfigurationBackedListenOptions.ToList();
        var endpointsToStart = new List <ListenOptions>();

        Options.ConfigurationBackedListenOptions.Clear();
        DefaultCertificateConfig = null;

        ConfigurationReader = new ConfigurationReader(Configuration);

        LoadDefaultCert();

        foreach (var endpoint in ConfigurationReader.Endpoints)
        {
            var listenOptions = AddressBinder.ParseAddress(endpoint.Url, out var https);

            if (!https)
            {
                ConfigurationReader.ThrowIfContainsHttpsOnlyConfiguration(endpoint);
            }

            Options.ApplyEndpointDefaults(listenOptions);

            if (endpoint.Protocols.HasValue)
            {
                listenOptions.Protocols = endpoint.Protocols.Value;
            }
            else
            {
                // Ensure endpoint is reloaded if it used the default protocol and the protocol changed.
                // listenOptions.Protocols should already be set to this by ApplyEndpointDefaults.
                endpoint.Protocols = ConfigurationReader.EndpointDefaults.Protocols;
            }

            // Compare to UseHttps(httpsOptions => { })
            var httpsOptions = new HttpsConnectionAdapterOptions();

            if (https)
            {
                // Defaults
                Options.ApplyHttpsDefaults(httpsOptions);

                if (endpoint.SslProtocols.HasValue)
                {
                    httpsOptions.SslProtocols = endpoint.SslProtocols.Value;
                }
                else
                {
                    // Ensure endpoint is reloaded if it used the default protocol and the SslProtocols changed.
                    endpoint.SslProtocols = ConfigurationReader.EndpointDefaults.SslProtocols;
                }

                if (endpoint.ClientCertificateMode.HasValue)
                {
                    httpsOptions.ClientCertificateMode = endpoint.ClientCertificateMode.Value;
                }
                else
                {
                    // Ensure endpoint is reloaded if it used the default mode and the ClientCertificateMode changed.
                    endpoint.ClientCertificateMode = ConfigurationReader.EndpointDefaults.ClientCertificateMode;
                }

                // A cert specified directly on the endpoint overrides any defaults.
                httpsOptions.ServerCertificate = CertificateConfigLoader.LoadCertificate(endpoint.Certificate, endpoint.Name)
                                                 ?? httpsOptions.ServerCertificate;

                if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null)
                {
                    // Fallback
                    Options.ApplyDefaultCert(httpsOptions);

                    // Ensure endpoint is reloaded if it used the default certificate and the certificate changed.
                    endpoint.Certificate = DefaultCertificateConfig;
                }
            }

            // Now that defaults have been loaded, we can compare to the currently bound endpoints to see if the config changed.
            // There's no reason to rerun an EndpointConfigurations callback if nothing changed.
            var matchingBoundEndpoints = endpointsToStop.Where(o => o.EndpointConfig == endpoint).ToList();

            if (matchingBoundEndpoints.Count > 0)
            {
                endpointsToStop.RemoveAll(o => o.EndpointConfig == endpoint);
                Options.ConfigurationBackedListenOptions.AddRange(matchingBoundEndpoints);
                continue;
            }

            if (EndpointConfigurations.TryGetValue(endpoint.Name, out var configureEndpoint))
            {
                var endpointConfig = new EndpointConfiguration(https, listenOptions, httpsOptions, endpoint.ConfigSection);
                configureEndpoint(endpointConfig);
            }

            // EndpointDefaults or configureEndpoint may have added an https adapter.
            if (https && !listenOptions.IsTls)
            {
                if (endpoint.Sni.Count == 0)
                {
                    if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null)
                    {
                        throw new InvalidOperationException(CoreStrings.NoCertSpecifiedNoDevelopmentCertificateFound);
                    }

                    listenOptions.UseHttps(httpsOptions);
                }
                else
                {
                    var sniOptionsSelector = new SniOptionsSelector(endpoint.Name, endpoint.Sni, CertificateConfigLoader,
                                                                    httpsOptions, listenOptions.Protocols, HttpsLogger);
                    var tlsCallbackOptions = new TlsHandshakeCallbackOptions()
                    {
                        OnConnection      = SniOptionsSelector.OptionsCallback,
                        HandshakeTimeout  = httpsOptions.HandshakeTimeout,
                        OnConnectionState = sniOptionsSelector,
                    };

                    listenOptions.UseHttps(tlsCallbackOptions);
                }
            }

            listenOptions.EndpointConfig = endpoint;

            endpointsToStart.Add(listenOptions);
            Options.ConfigurationBackedListenOptions.Add(listenOptions);
        }

        return(endpointsToStop, endpointsToStart);
    }