2019-04-24 21:52:08 +00:00
package server
import (
2022-04-04 23:57:47 +00:00
"crypto/tls"
"crypto/x509"
2022-06-14 07:20:13 +00:00
"fmt"
2020-07-16 06:36:37 +00:00
"net"
2019-04-24 21:52:08 +00:00
"os"
2022-09-10 08:02:57 +00:00
"github.com/sirupsen/logrus"
2020-04-05 12:37:21 +00:00
"github.com/valyala/fasthttp"
2023-06-23 19:19:56 +00:00
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
2020-04-05 12:37:21 +00:00
2021-08-11 01:04:35 +00:00
"github.com/authelia/authelia/v4/internal/configuration/schema"
2022-04-05 21:57:23 +00:00
"github.com/authelia/authelia/v4/internal/logging"
2021-08-11 01:04:35 +00:00
"github.com/authelia/authelia/v4/internal/middlewares"
2019-04-24 21:52:08 +00:00
)
2022-06-14 07:20:13 +00:00
// CreateDefaultServer Create Authelia's internal webserver with the given configuration and providers.
2023-02-11 10:45:26 +00:00
func CreateDefaultServer ( config * schema . Configuration , providers middlewares . Providers ) ( server * fasthttp . Server , listener net . Listener , paths [ ] string , isTLS bool , err error ) {
2023-01-03 03:49:02 +00:00
if err = providers . Templates . LoadTemplatedAssets ( assets ) ; err != nil {
2023-02-11 10:45:26 +00:00
return nil , nil , nil , false , fmt . Errorf ( "failed to load templated assets: %w" , err )
2023-01-03 03:49:02 +00:00
}
2022-06-14 07:20:13 +00:00
server = & fasthttp . Server {
2022-06-11 23:26:28 +00:00
ErrorHandler : handleError ( ) ,
Handler : handleRouter ( config , providers ) ,
2020-04-30 03:16:41 +00:00
NoDefaultServerHeader : true ,
2022-08-08 21:50:12 +00:00
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 ,
2022-10-07 02:52:01 +00:00
Logger : logging . LoggerPrintf ( logrus . DebugLevel ) ,
2020-04-11 04:59:58 +00:00
}
2022-04-07 00:58:51 +00:00
2022-04-04 23:57:47 +00:00
var (
2023-05-07 05:48:26 +00:00
connectionScheme = schemeHTTP
2022-04-04 23:57:47 +00:00
)
2019-04-24 21:52:08 +00:00
2023-05-09 11:25:56 +00:00
if listener , err = config . Server . Address . Listener ( ) ; err != nil {
2023-05-07 05:48:26 +00:00
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 )
}
2022-04-08 04:13:47 +00:00
if config . Server . TLS . Certificate != "" && config . Server . TLS . Key != "" {
2023-02-11 10:45:26 +00:00
isTLS , connectionScheme = true , schemeHTTPS
2022-04-04 23:57:47 +00:00
2023-06-23 19:19:56 +00:00
tlsConfig , err := loadTLSCertificates ( config )
if err != nil {
return nil , nil , nil , false , fmt . Errorf ( "HTTP server: %w" , err )
2021-08-05 04:02:07 +00:00
}
2023-06-23 19:19:56 +00:00
// Apply configuration
listener = tls . NewListener ( listener , tlsConfig . Clone ( ) )
2022-04-04 23:57:47 +00:00
}
2021-08-05 04:02:07 +00:00
2023-05-07 05:48:26 +00:00
if err = writeHealthCheckEnv ( config . Server . DisableHealthcheck , connectionScheme , config . Server . Address . Hostname ( ) ,
2023-05-30 08:21:19 +00:00
config . Server . Address . Path ( ) , config . Server . Address . Port ( ) ) ; err != nil {
2023-02-11 10:45:26 +00:00
return nil , nil , nil , false , fmt . Errorf ( "unable to configure healthcheck: %w" , err )
2020-03-03 07:18:25 +00:00
}
2022-04-04 23:57:47 +00:00
2023-02-11 10:45:26 +00:00
paths = [ ] string { "/" }
2022-06-14 07:20:13 +00:00
2023-05-30 08:21:19 +00:00
if config . Server . Address . Path ( ) != "/" {
paths = append ( paths , config . Server . Address . Path ( ) )
2022-04-04 23:57:47 +00:00
}
2023-02-11 10:45:26 +00:00
return server , listener , paths , isTLS , nil
2022-06-14 07:20:13 +00:00
}
// CreateMetricsServer creates a metrics server.
2023-02-11 10:45:26 +00:00
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
2022-06-14 07:20:13 +00:00
}
server = & fasthttp . Server {
ErrorHandler : handleError ( ) ,
NoDefaultServerHeader : true ,
2023-05-30 08:21:19 +00:00
Handler : handleMetrics ( config . Telemetry . Metrics . Address . Path ( ) ) ,
2023-02-11 10:45:26 +00:00
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 ,
2022-09-10 08:02:57 +00:00
Logger : logging . LoggerPrintf ( logrus . DebugLevel ) ,
2022-06-14 07:20:13 +00:00
}
2023-05-09 11:25:56 +00:00
if listener , err = config . Telemetry . Metrics . Address . Listener ( ) ; err != nil {
2023-05-07 05:48:26 +00:00
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 )
2023-02-11 10:45:26 +00:00
}
2022-08-08 21:50:12 +00:00
2023-05-30 08:21:19 +00:00
return server , listener , [ ] string { config . Telemetry . Metrics . Address . Path ( ) } , false , nil
2019-04-24 21:52:08 +00:00
}
2023-06-23 19:19:56 +00:00
// 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
}