165 lines
5.9 KiB
Go
165 lines
5.9 KiB
Go
package server
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/valyala/fasthttp"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials"
|
|
|
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
"github.com/authelia/authelia/v4/internal/logging"
|
|
"github.com/authelia/authelia/v4/internal/middlewares"
|
|
)
|
|
|
|
// CreateDefaultServer Create Authelia's internal webserver with the given configuration and providers.
|
|
func CreateDefaultServer(config *schema.Configuration, providers middlewares.Providers) (server *fasthttp.Server, listener net.Listener, paths []string, isTLS bool, err error) {
|
|
if err = providers.Templates.LoadTemplatedAssets(assets); err != nil {
|
|
return nil, nil, nil, false, fmt.Errorf("failed to load templated assets: %w", err)
|
|
}
|
|
|
|
server = &fasthttp.Server{
|
|
ErrorHandler: handleError(),
|
|
Handler: handleRouter(config, providers),
|
|
NoDefaultServerHeader: true,
|
|
ReadBufferSize: config.Server.Buffers.Read,
|
|
WriteBufferSize: config.Server.Buffers.Write,
|
|
ReadTimeout: config.Server.Timeouts.Read,
|
|
WriteTimeout: config.Server.Timeouts.Write,
|
|
IdleTimeout: config.Server.Timeouts.Idle,
|
|
Logger: logging.LoggerPrintf(logrus.DebugLevel),
|
|
}
|
|
|
|
var (
|
|
connectionScheme = schemeHTTP
|
|
)
|
|
|
|
if listener, err = config.Server.Address.Listener(); err != nil {
|
|
return nil, nil, nil, false, fmt.Errorf("error occurred while attempting to initialize main server listener for address '%s': %w", config.Server.Address.String(), err)
|
|
}
|
|
|
|
if config.Server.TLS.Certificate != "" && config.Server.TLS.Key != "" {
|
|
isTLS, connectionScheme = true, schemeHTTPS
|
|
|
|
tlsConfig, err := loadTLSCertificates(config)
|
|
if err != nil {
|
|
return nil, nil, nil, false, fmt.Errorf("HTTP server: %w", err)
|
|
}
|
|
|
|
// Apply configuration
|
|
listener = tls.NewListener(listener, tlsConfig.Clone())
|
|
}
|
|
|
|
if err = writeHealthCheckEnv(config.Server.DisableHealthcheck, connectionScheme, config.Server.Address.Hostname(),
|
|
config.Server.Address.Path(), config.Server.Address.Port()); err != nil {
|
|
return nil, nil, nil, false, fmt.Errorf("unable to configure healthcheck: %w", err)
|
|
}
|
|
|
|
paths = []string{"/"}
|
|
|
|
if config.Server.Address.Path() != "/" {
|
|
paths = append(paths, config.Server.Address.Path())
|
|
}
|
|
|
|
return server, listener, paths, isTLS, nil
|
|
}
|
|
|
|
// CreateMetricsServer creates a metrics server.
|
|
func CreateMetricsServer(config *schema.Configuration, providers middlewares.Providers) (server *fasthttp.Server, listener net.Listener, paths []string, tls bool, err error) {
|
|
if providers.Metrics == nil {
|
|
return
|
|
}
|
|
|
|
server = &fasthttp.Server{
|
|
ErrorHandler: handleError(),
|
|
NoDefaultServerHeader: true,
|
|
Handler: handleMetrics(config.Telemetry.Metrics.Address.Path()),
|
|
ReadBufferSize: config.Telemetry.Metrics.Buffers.Read,
|
|
WriteBufferSize: config.Telemetry.Metrics.Buffers.Write,
|
|
ReadTimeout: config.Telemetry.Metrics.Timeouts.Read,
|
|
WriteTimeout: config.Telemetry.Metrics.Timeouts.Write,
|
|
IdleTimeout: config.Telemetry.Metrics.Timeouts.Idle,
|
|
Logger: logging.LoggerPrintf(logrus.DebugLevel),
|
|
}
|
|
|
|
if listener, err = config.Telemetry.Metrics.Address.Listener(); err != nil {
|
|
return nil, nil, nil, false, fmt.Errorf("error occurred while attempting to initialize metrics telemetry server listener for address '%s': %w", config.Telemetry.Metrics.Address.String(), err)
|
|
}
|
|
|
|
return server, listener, []string{config.Telemetry.Metrics.Address.Path()}, false, nil
|
|
}
|
|
|
|
// CreateGRPCServer creates a server for handling gRPC authentication requests from an envoy proxy.
|
|
func CreateGRPCServer(config *schema.Configuration, providers middlewares.Providers) (server *grpc.Server, listener net.Listener, tls bool, err error) {
|
|
if config.Server.GRPC.Address == nil {
|
|
return nil, nil, false, nil
|
|
}
|
|
|
|
// Initialize gPRC server
|
|
lis, err := config.Server.GRPC.Address.Listener()
|
|
if err != nil {
|
|
return nil, nil, false, fmt.Errorf("error occurred while attempting to initialize grcp server listener for address '%s': %w", config.Server.GRPC.Address, err)
|
|
}
|
|
|
|
opts := []grpc.ServerOption{grpc.MaxConcurrentStreams(10)}
|
|
|
|
if config.Server.TLS.Certificate != "" && config.Server.TLS.Key != "" && !config.Server.GRPC.DisableTLS {
|
|
tlsConfig, err := loadTLSCertificates(config)
|
|
if err != nil {
|
|
return nil, nil, false, fmt.Errorf("gRPC server: %w", err)
|
|
}
|
|
|
|
opts = append(opts, grpc.Creds(credentials.NewTLS(tlsConfig)))
|
|
tls = true
|
|
}
|
|
|
|
s := grpc.NewServer(opts...)
|
|
handleGRCP(s, config, providers)
|
|
|
|
return s, lis, tls, nil
|
|
}
|
|
|
|
// loadTLSCertificates loads the server and client certificates from the files and returns a
|
|
// tls.Config object for the server
|
|
func loadTLSCertificates(config *schema.Configuration) (*tls.Config, error) {
|
|
|
|
// Load the server certificates
|
|
serverCert, err := tls.LoadX509KeyPair(config.Server.TLS.Certificate, config.Server.TLS.Key)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("unable to load server certificate '%s' or key '%s': %w", config.Server.TLS.Certificate, config.Server.TLS.Key, err)
|
|
}
|
|
|
|
// Create the tls configuration
|
|
tlsConfig := &tls.Config{
|
|
Certificates: []tls.Certificate{serverCert},
|
|
ClientAuth: tls.NoClientCert,
|
|
}
|
|
|
|
// Load client certificates
|
|
if len(config.Server.TLS.ClientCertificates) > 0 {
|
|
caCertPool := x509.NewCertPool()
|
|
|
|
var cert []byte
|
|
|
|
for _, path := range config.Server.TLS.ClientCertificates {
|
|
if cert, err = os.ReadFile(path); err != nil {
|
|
return nil, fmt.Errorf("unable to load tls client certificate '%s': %w", path, err)
|
|
}
|
|
|
|
caCertPool.AppendCertsFromPEM(cert)
|
|
}
|
|
|
|
// ClientCAs should never be nil, otherwise the system cert pool is used for client authentication,
|
|
// but we don't want everybody on the Internet to be able to authenticate.
|
|
tlsConfig.ClientCAs = caCertPool
|
|
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
|
}
|
|
|
|
return tlsConfig, nil
|
|
}
|