Example #1
0
        public async Task OnConnectionAsync(ConnectionContext context, Func <Task> next)
        {
            if (_server.ServerStore.Initialized == false)
            {
                await _server.ServerStore.InitializationCompleted.WaitAsync();
            }

            var tlsConnectionFeature     = context.Features.Get <ITlsConnectionFeature>();
            X509Certificate2 certificate = null;

            if (tlsConnectionFeature != null)
            {
                certificate = await tlsConnectionFeature.GetClientCertificateAsync(context.ConnectionClosed);
            }

            var httpConnectionFeature = context.Features.Get <IHttpConnectionFeature>();
            var authenticationStatus  = _server.AuthenticateConnectionCertificate(certificate, httpConnectionFeature);

            // build the token
            context.Features.Set <IHttpAuthenticationFeature>(authenticationStatus);

            await next();
        }
Example #2
0
        public async Task <IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
        {
            if (context.ConnectionStream is RawStream rs)
            {
                // here we do protocol sniffing to see if user is trying to access us via
                // http while we are expecting HTTPS.

                var input = GetInput(rs); // uses a delegate to get the private RawStream._input out
                // here we take advantage of the fact that Kestrel allow to get the data from the buffer
                // without actually consuming it
                var result = await input.ReadAsync();

                try
                {
                    if (result.Buffer.First.IsEmpty == false)
                    {
                        var b = result.Buffer.First.Span[0];
                        if (b >= 'A' && b <= 'Z')
                        {
                            // this is a good indication that we have been connected using HTTP, instead of HTTPS
                            // because the first character is a valid ASCII value. However, in SSL2, the first bit
                            // is always on, and in SSL 3 / TLS 1.0 - 1.2 the first byte is 22.
                            // https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
                            context.Features.Set <IHttpAuthenticationFeature>(new RavenServer.AuthenticateConnection
                            {
                                WrongProtocolMessage = "Attempted to access an HTTPS server using HTTP, did you forget to change 'http://' to 'https://' ?"
                            });
                            return(new SameConnectionStream(rs));
                        }
                    }
                }
                finally
                {
                    input.AdvanceTo(result.Buffer.Start, result.Buffer.Start);
                }
            }

            var connection = await _httpsConnectionAdapter.OnConnectionAsync(context);

            if (connection is HttpsConnectionAdapter.HttpsAdaptedConnection c)
            {
                if (c.SslProtocol != SslProtocols.Tls12)
                {
                    context.Features.Set <IHttpAuthenticationFeature>(new RavenServer.AuthenticateConnection
                    {
                        WrongProtocolMessage = "RavenDB requires clients to connect using TLS 1.2, but the client used: '" + c.SslProtocol + "'."
                    });

                    return(c);
                }
            }

            if (_server.ServerStore.Initialized == false)
            {
                await _server.ServerStore.InitializationCompleted.WaitAsync();
            }

            var tls                  = context.Features.Get <ITlsConnectionFeature>();
            var certificate          = tls?.ClientCertificate;
            var conn                 = context.Features.Get <IHttpConnectionFeature>();
            var authenticationStatus = _server.AuthenticateConnectionCertificate(certificate, conn);

            // build the token
            context.Features.Set <IHttpAuthenticationFeature>(authenticationStatus);

            return(connection);
        }
        public async Task <IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
        {
            if (context.ConnectionStream is RawStream rs)
            {
                // here we do protocol sniffing to see if user is trying to access us via
                // http while we are expecting HTTPS.

                var input = GetInput(rs); // uses a delegate to get the private RawStream._input out
                // here we take advantage of the fact that Kestrel allow to get the data from the buffer
                // without actually consuming it
                var result = await input.ReadAsync();

                try
                {
                    if (result.Buffer.First.TryGetArray(out var bytes) && bytes.Count > 0)
                    {
                        var b = bytes.Array[bytes.Offset];
                        if (b >= 'A' && b <= 'Z')
                        {
                            // this is a good indication that we have been connected using HTTP, instead of HTTPS
                            // because the first characeter is a valid ASCII value. However, in SSL2, the first bit
                            // is always on, and in SSL 3 / TLS 1.0 - 1.2 the first byte is 22.
                            // https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
                            context.Features.Set <IHttpAuthenticationFeature>(new RavenServer.AuthenticateConnection
                            {
                                WrongProtocolMessage = "Attempted to access an HTTPS server using HTTP, did you forget to change 'http://' to 'https://' ?"
                            });
                            return(new SameConnectionStream(rs));
                        }
                    }
                }
                finally
                {
                    input.Advance(result.Buffer.Start, result.Buffer.Start);
                }
            }

            var connection = await _httpsConnectionAdapter.OnConnectionAsync(context);

            if (connection is HttpsConnectionAdapter.HttpsAdaptedConnection c)
            {
                if (c.SslProtocol != SslProtocols.Tls12)
                {
                    context.Features.Set <IHttpAuthenticationFeature>(new RavenServer.AuthenticateConnection
                    {
                        WrongProtocolMessage = "RavenDB requires clients to connect using TLS 1.2, but the client used: '" + c.SslProtocol + "'."
                    });

                    return(c);
                }
            }

            var tls                  = context.Features.Get <ITlsConnectionFeature>();
            var certificate          = tls?.ClientCertificate;
            var authenticationStatus = _server.AuthenticateConnectionCertificate(certificate);
            var info                 = context.Features.Get <IHttpConnectionFeature>();

            if (Logger.IsInfoEnabled &&
                authenticationStatus.Status != RavenServer.AuthenticationStatus.Allowed &&
                authenticationStatus.Status != RavenServer.AuthenticationStatus.Operator &&
                authenticationStatus.Status != RavenServer.AuthenticationStatus.ClusterAdmin)
            {
                Logger.Info($"Received TLS connection request from {info?.RemoteIpAddress}:{info?.RemotePort} with client certificate: {certificate?.SubjectName?.Name}. " +
                            $"Authentication status: {authenticationStatus.Status}.");
            }

            // build the token
            context.Features.Set <IHttpAuthenticationFeature>(authenticationStatus);

            return(connection);
        }