refactor(server): use errgroup to supervise services (#3755)
Uses the errgroup package and pattern for supervising services like servers etc.pull/3808/head
parent
a59a3c62f9
commit
342497a869
|
@ -51,13 +51,6 @@ server:
|
||||||
## Useful to allow overriding of specific static assets.
|
## Useful to allow overriding of specific static assets.
|
||||||
# asset_path: /config/assets/
|
# asset_path: /config/assets/
|
||||||
|
|
||||||
## Buffers usually should be configured to be the same value.
|
|
||||||
## Explanation at https://www.authelia.com/c/server#buffer-sizes
|
|
||||||
## Read buffer size adjusts the server's max incoming request size in bytes.
|
|
||||||
## Write buffer size does the same for outgoing responses.
|
|
||||||
read_buffer_size: 4096
|
|
||||||
write_buffer_size: 4096
|
|
||||||
|
|
||||||
## Enables the pprof endpoint.
|
## Enables the pprof endpoint.
|
||||||
enable_pprof: false
|
enable_pprof: false
|
||||||
|
|
||||||
|
@ -85,6 +78,32 @@ server:
|
||||||
## The CSP Template. Read the docs.
|
## The CSP Template. Read the docs.
|
||||||
csp_template: ""
|
csp_template: ""
|
||||||
|
|
||||||
|
## Server Buffers configuration.
|
||||||
|
# buffers:
|
||||||
|
|
||||||
|
## Buffers usually should be configured to be the same value.
|
||||||
|
## Explanation at https://www.authelia.com/c/server#buffer-sizes
|
||||||
|
## Read buffer size adjusts the server's max incoming request size in bytes.
|
||||||
|
## Write buffer size does the same for outgoing responses.
|
||||||
|
|
||||||
|
## Read buffer.
|
||||||
|
# read: 4096
|
||||||
|
|
||||||
|
## Write buffer.
|
||||||
|
# write: 4096
|
||||||
|
|
||||||
|
## Server Timeouts configuration.
|
||||||
|
# timeouts:
|
||||||
|
|
||||||
|
## Read timeout.
|
||||||
|
# read: 2s
|
||||||
|
|
||||||
|
## Write timeout.
|
||||||
|
# write: 2s
|
||||||
|
|
||||||
|
## Idle timeout.
|
||||||
|
# idle: 30s
|
||||||
|
|
||||||
##
|
##
|
||||||
## Log Configuration
|
## Log Configuration
|
||||||
##
|
##
|
||||||
|
@ -116,6 +135,27 @@ telemetry:
|
||||||
## The address to listen on for metrics. This should be on a different port to the main server.port value.
|
## The address to listen on for metrics. This should be on a different port to the main server.port value.
|
||||||
address: tcp://0.0.0.0:9959
|
address: tcp://0.0.0.0:9959
|
||||||
|
|
||||||
|
## Metrics Server Buffers configuration.
|
||||||
|
# buffers:
|
||||||
|
|
||||||
|
## Read buffer.
|
||||||
|
# read: 4096
|
||||||
|
|
||||||
|
## Write buffer.
|
||||||
|
# write: 4096
|
||||||
|
|
||||||
|
## Metrics Server Timeouts configuration.
|
||||||
|
# timeouts:
|
||||||
|
|
||||||
|
## Read timeout.
|
||||||
|
# read: 2s
|
||||||
|
|
||||||
|
## Write timeout.
|
||||||
|
# write: 2s
|
||||||
|
|
||||||
|
## Idle timeout.
|
||||||
|
# idle: 30s
|
||||||
|
|
||||||
##
|
##
|
||||||
## TOTP Configuration
|
## TOTP Configuration
|
||||||
##
|
##
|
||||||
|
|
|
@ -40,12 +40,13 @@ For example this YAML configuration:
|
||||||
log:
|
log:
|
||||||
level: info
|
level: info
|
||||||
server:
|
server:
|
||||||
read_buffer_size: 4096
|
buffers:
|
||||||
|
read: 4096
|
||||||
```
|
```
|
||||||
|
|
||||||
Can be replaced by this environment variable configuration:
|
Can be replaced by this environment variable configuration:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
AUTHELIA_LOG_LEVEL=info
|
AUTHELIA_LOG_LEVEL=info
|
||||||
AUTHELIA_SERVER_READ_BUFFER_SIZE=4096
|
AUTHELIA_SERVER_BUFFERS_READ=4096
|
||||||
```
|
```
|
||||||
|
|
|
@ -22,8 +22,6 @@ server:
|
||||||
host: 0.0.0.0
|
host: 0.0.0.0
|
||||||
port: 9091
|
port: 9091
|
||||||
path: ""
|
path: ""
|
||||||
read_buffer_size: 4096
|
|
||||||
write_buffer_size: 4096
|
|
||||||
enable_pprof: false
|
enable_pprof: false
|
||||||
enable_expvars: false
|
enable_expvars: false
|
||||||
disable_healthcheck: false
|
disable_healthcheck: false
|
||||||
|
@ -33,6 +31,13 @@ server:
|
||||||
client_certificates: []
|
client_certificates: []
|
||||||
headers:
|
headers:
|
||||||
csp_template: ""
|
csp_template: ""
|
||||||
|
buffers:
|
||||||
|
read: 4096
|
||||||
|
write: 4096
|
||||||
|
timeouts:
|
||||||
|
read: 10s
|
||||||
|
write: 10s
|
||||||
|
idle: 10s
|
||||||
```
|
```
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
@ -95,18 +100,6 @@ assets that can be overridden must be placed in the `asset_path`. The structure
|
||||||
can be overriden is documented in the
|
can be overriden is documented in the
|
||||||
[Sever Asset Overrides Reference Guide](../../reference/guides/server-asset-overrides.md).
|
[Sever Asset Overrides Reference Guide](../../reference/guides/server-asset-overrides.md).
|
||||||
|
|
||||||
### read_buffer_size
|
|
||||||
|
|
||||||
{{< confkey type="integer " default="4096" required="no" >}}
|
|
||||||
|
|
||||||
Configures the maximum request size. The default of 4096 is generally sufficient for most use cases.
|
|
||||||
|
|
||||||
### write_buffer_size
|
|
||||||
|
|
||||||
{{< confkey type="integer " default="4096" required="no" >}}
|
|
||||||
|
|
||||||
Configures the maximum response size. The default of 4096 is generally sufficient for most use cases.
|
|
||||||
|
|
||||||
### enable_pprof
|
### enable_pprof
|
||||||
|
|
||||||
{{< confkey type="boolean" default="false" required="no" >}}
|
{{< confkey type="boolean" default="false" required="no" >}}
|
||||||
|
@ -174,6 +167,16 @@ about how browsers utilize and understand this header before attempting to custo
|
||||||
|
|
||||||
For example, the default CSP template is `default-src 'self'; object-src 'none'; style-src 'self' 'nonce-${NONCE}'`.
|
For example, the default CSP template is `default-src 'self'; object-src 'none'; style-src 'self' 'nonce-${NONCE}'`.
|
||||||
|
|
||||||
|
### buffers
|
||||||
|
|
||||||
|
Configures the server buffers. See the [Server Buffers](../prologue/common.md#server-buffers) documentation for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
### timeouts
|
||||||
|
|
||||||
|
Configures the server timeouts. See the [Server Timeouts](../prologue/common.md#server-timeouts) documentation for more
|
||||||
|
information.
|
||||||
|
|
||||||
## Additional Notes
|
## Additional Notes
|
||||||
|
|
||||||
### Buffer Sizes
|
### Buffer Sizes
|
||||||
|
|
|
@ -133,3 +133,46 @@ The key `minimum_version` controls the minimum TLS version Authelia will use whe
|
||||||
The possible values are `TLS1.3`, `TLS1.2`, `TLS1.1`, `TLS1.0`. Anything other than `TLS1.3` or `TLS1.2`
|
The possible values are `TLS1.3`, `TLS1.2`, `TLS1.1`, `TLS1.0`. Anything other than `TLS1.3` or `TLS1.2`
|
||||||
are very old and deprecated. You should avoid using these and upgrade your backend service instead of decreasing
|
are very old and deprecated. You should avoid using these and upgrade your backend service instead of decreasing
|
||||||
this value.
|
this value.
|
||||||
|
|
||||||
|
## Server Buffers
|
||||||
|
|
||||||
|
### read
|
||||||
|
|
||||||
|
{{< confkey type="integer" default="4096" required="no" >}}
|
||||||
|
|
||||||
|
Configures the maximum request size. The default of 4096 is generally sufficient for most use cases.
|
||||||
|
|
||||||
|
### write
|
||||||
|
|
||||||
|
{{< confkey type="integer" default="4096" required="no" >}}
|
||||||
|
|
||||||
|
Configures the maximum response size. The default of 4096 is generally sufficient for most use cases.
|
||||||
|
|
||||||
|
## Server Timeouts
|
||||||
|
|
||||||
|
### read
|
||||||
|
|
||||||
|
{{< confkey type="duration" default="2s" required="no" >}}
|
||||||
|
|
||||||
|
*__Note:__ This setting uses the [duration notation format](#duration-notation-format). Please see the
|
||||||
|
[common options](#duration-notation-format) documentation for information on this format.*
|
||||||
|
|
||||||
|
Configures the server read timeout.
|
||||||
|
|
||||||
|
### write
|
||||||
|
|
||||||
|
{{< confkey type="duration" default="2s" required="no" >}}
|
||||||
|
|
||||||
|
*__Note:__ This setting uses the [duration notation format](#duration-notation-format). Please see the
|
||||||
|
[common options](#duration-notation-format) documentation for information on this format.*
|
||||||
|
|
||||||
|
Configures the server write timeout.
|
||||||
|
|
||||||
|
### idle
|
||||||
|
|
||||||
|
{{< confkey type="duration" default="30s" required="no" >}}
|
||||||
|
|
||||||
|
*__Note:__ This setting uses the [duration notation format](#duration-notation-format). Please see the
|
||||||
|
[common options](#duration-notation-format) documentation for information on this format.*
|
||||||
|
|
||||||
|
Configures the server write timeout.
|
||||||
|
|
|
@ -21,6 +21,13 @@ telemetry:
|
||||||
metrics:
|
metrics:
|
||||||
enabled: false
|
enabled: false
|
||||||
address: "tcp://0.0.0.0:9959"
|
address: "tcp://0.0.0.0:9959"
|
||||||
|
buffers:
|
||||||
|
read: 4096
|
||||||
|
write: 4096
|
||||||
|
timeouts:
|
||||||
|
read: 10s
|
||||||
|
write: 10s
|
||||||
|
idle: 10s
|
||||||
```
|
```
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
@ -38,6 +45,16 @@ Determines if the [Prometheus] HTTP Metrics Exporter is enabled.
|
||||||
Configures the listener address for the [Prometheus] HTTP Metrics Exporter. This configuration key uses the
|
Configures the listener address for the [Prometheus] HTTP Metrics Exporter. This configuration key uses the
|
||||||
[Address](../prologue/common.md#address) format. The scheme must be `tcp://` or empty.
|
[Address](../prologue/common.md#address) format. The scheme must be `tcp://` or empty.
|
||||||
|
|
||||||
|
### buffers
|
||||||
|
|
||||||
|
Configures the server buffers. See the [Server Buffers](../prologue/common.md#server-buffers) documentation for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
### timeouts
|
||||||
|
|
||||||
|
Configures the server timeouts. See the [Server Timeouts](../prologue/common.md#server-timeouts) documentation for more
|
||||||
|
information.
|
||||||
|
|
||||||
## See More
|
## See More
|
||||||
|
|
||||||
- [Telemetry Reference Documentation](../../reference/guides/metrics.md)
|
- [Telemetry Reference Documentation](../../reference/guides/metrics.md)
|
||||||
|
|
|
@ -15,15 +15,15 @@ toc: true
|
||||||
## Request Header Too Large
|
## Request Header Too Large
|
||||||
|
|
||||||
The `request header too large` error with a status code of `431` indicates the HTTP request made to *Authelia* had
|
The `request header too large` error with a status code of `431` indicates the HTTP request made to *Authelia* had
|
||||||
headers exceeding the server [read_buffer_size](../../configuration/miscellaneous/server.md#read_buffer_size) parameter.
|
headers exceeding the server [read buffer](../../configuration/miscellaneous/server.md#buffers) parameter.
|
||||||
|
|
||||||
Usually the defaults are sufficient however some applications cause fairly large headers to be added to requests.
|
Usually the defaults are sufficient however some applications cause fairly large headers to be added to requests.
|
||||||
|
|
||||||
It's suggested you increase the [read_buffer_size](../../configuration/miscellaneous/server.md#read_buffer_size)
|
It's suggested you increase the [read buffer](../../configuration/miscellaneous/server.md#buffers)
|
||||||
configuration option (by either doubling or quadrupling it) in order to alleviate this issue or use the reverse proxy to
|
configuration option (by either doubling or quadrupling it) in order to alleviate this issue or use the reverse proxy to
|
||||||
remove the excessive headers which are causing this issue.
|
remove the excessive headers which are causing this issue.
|
||||||
|
|
||||||
It's generally recommended the [write_buffer_size](../../configuration/miscellaneous/server.md#write_buffer_size) is
|
It's generally recommended the [write buffer](../../configuration/miscellaneous/server.md#buffers) is
|
||||||
also increased.
|
also increased.
|
||||||
|
|
||||||
## User Has Been Inactive Too Long
|
## User Has Been Inactive Too Long
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -36,6 +36,7 @@ require (
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stretchr/testify v1.8.0
|
||||||
github.com/trustelem/zxcvbn v1.0.1
|
github.com/trustelem/zxcvbn v1.0.1
|
||||||
github.com/valyala/fasthttp v1.38.0
|
github.com/valyala/fasthttp v1.38.0
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
|
||||||
golang.org/x/text v0.3.7
|
golang.org/x/text v0.3.7
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0
|
gopkg.in/square/go-jose.v2 v2.6.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
|
3
go.sum
3
go.sum
|
@ -1587,7 +1587,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"syscall"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
"github.com/authelia/authelia/v4/internal/logging"
|
"github.com/authelia/authelia/v4/internal/logging"
|
||||||
|
@ -74,99 +79,127 @@ func cmdRootRun(_ *cobra.Command, _ []string) {
|
||||||
logger.Fatalf("Errors occurred provisioning providers.")
|
logger.Fatalf("Errors occurred provisioning providers.")
|
||||||
}
|
}
|
||||||
|
|
||||||
doStartupChecks(config, &providers)
|
doStartupChecks(config, &providers, logger)
|
||||||
|
|
||||||
runServers(config, providers, logger)
|
runServers(config, providers, logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runServers(config *schema.Configuration, providers middlewares.Providers, logger *logrus.Logger) {
|
func runServers(config *schema.Configuration, providers middlewares.Providers, log *logrus.Logger) {
|
||||||
wg := new(sync.WaitGroup)
|
ctx := context.Background()
|
||||||
|
|
||||||
wg.Add(2)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
go func() {
|
defer cancel()
|
||||||
err := startDefaultServer(config, providers)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Done()
|
quit := make(chan os.Signal, 1)
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||||
err := startMetricsServer(config, providers)
|
|
||||||
if err != nil {
|
defer signal.Stop(quit)
|
||||||
logger.Fatal(err)
|
|
||||||
|
g, ctx := errgroup.WithContext(ctx)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mainServer, metricsServer *fasthttp.Server
|
||||||
|
mainListener, metricsListener net.Listener
|
||||||
|
)
|
||||||
|
|
||||||
|
g.Go(func() (err error) {
|
||||||
|
defer func() {
|
||||||
|
if rec := recover(); rec != nil {
|
||||||
|
log.WithError(recoverErr(rec)).Errorf("Critical error in server caught (recovered)")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
wg.Wait()
|
if mainServer, mainListener, err = server.CreateDefaultServer(*config, providers); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func startDefaultServer(config *schema.Configuration, providers middlewares.Providers) (err error) {
|
if err = mainServer.Serve(mainListener); err != nil {
|
||||||
svr, listener, err := server.CreateDefaultServer(*config, providers)
|
return err
|
||||||
|
|
||||||
switch err {
|
|
||||||
case nil:
|
|
||||||
if err = svr.Serve(listener); err != nil {
|
|
||||||
return fmt.Errorf("error occurred during default server operation: %w", err)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("error occurred during default server startup: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
})
|
||||||
|
|
||||||
func startMetricsServer(config *schema.Configuration, providers middlewares.Providers) (err error) {
|
g.Go(func() (err error) {
|
||||||
if providers.Metrics == nil {
|
if providers.Metrics == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
svr, listener, err := server.CreateMetricsServer(config.Telemetry.Metrics)
|
defer func() {
|
||||||
|
if rec := recover(); rec != nil {
|
||||||
switch err {
|
log.WithError(recoverErr(rec)).Errorf("Critical error in metrics server caught (recovered)")
|
||||||
case nil:
|
|
||||||
if err = svr.Serve(listener); err != nil {
|
|
||||||
return fmt.Errorf("error occurred during metrics server operation: %w", err)
|
|
||||||
}
|
}
|
||||||
default:
|
}()
|
||||||
return fmt.Errorf("error occurred during metrics server startup: %w", err)
|
|
||||||
|
if metricsServer, metricsListener, err = server.CreateMetricsServer(config.Telemetry.Metrics); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = metricsServer.Serve(metricsListener); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-quit:
|
||||||
|
break
|
||||||
|
case <-ctx.Done():
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
func doStartupChecks(config *schema.Configuration, providers *middlewares.Providers) {
|
cancel()
|
||||||
logger := logging.Logger()
|
|
||||||
|
|
||||||
|
log.Infof("Shutting down")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if err = mainServer.Shutdown(); err != nil {
|
||||||
|
log.WithError(err).Errorf("Error occurred shutting down the server")
|
||||||
|
}
|
||||||
|
|
||||||
|
if metricsServer != nil {
|
||||||
|
if err = metricsServer.Shutdown(); err != nil {
|
||||||
|
log.WithError(err).Errorf("Error occurred shutting down the metrics server")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = g.Wait(); err != nil {
|
||||||
|
log.WithError(err).Errorf("Error occurred waiting for shutdown")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doStartupChecks(config *schema.Configuration, providers *middlewares.Providers, log *logrus.Logger) {
|
||||||
var (
|
var (
|
||||||
failures []string
|
failures []string
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
if err = doStartupCheck(logger, "storage", providers.StorageProvider, false); err != nil {
|
if err = doStartupCheck(log, "storage", providers.StorageProvider, false); err != nil {
|
||||||
logger.Errorf("Failure running the storage provider startup check: %+v", err)
|
log.Errorf("Failure running the storage provider startup check: %+v", err)
|
||||||
|
|
||||||
failures = append(failures, "storage")
|
failures = append(failures, "storage")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = doStartupCheck(logger, "user", providers.UserProvider, false); err != nil {
|
if err = doStartupCheck(log, "user", providers.UserProvider, false); err != nil {
|
||||||
logger.Errorf("Failure running the user provider startup check: %+v", err)
|
log.Errorf("Failure running the user provider startup check: %+v", err)
|
||||||
|
|
||||||
failures = append(failures, "user")
|
failures = append(failures, "user")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = doStartupCheck(logger, "notification", providers.Notifier, config.Notifier.DisableStartupCheck); err != nil {
|
if err = doStartupCheck(log, "notification", providers.Notifier, config.Notifier.DisableStartupCheck); err != nil {
|
||||||
logger.Errorf("Failure running the notification provider startup check: %+v", err)
|
log.Errorf("Failure running the notification provider startup check: %+v", err)
|
||||||
|
|
||||||
failures = append(failures, "notification")
|
failures = append(failures, "notification")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !config.NTP.DisableStartupCheck && !providers.Authorizer.IsSecondFactorEnabled() {
|
if !config.NTP.DisableStartupCheck && !providers.Authorizer.IsSecondFactorEnabled() {
|
||||||
logger.Debug("The NTP startup check was skipped due to there being no configured 2FA access control rules")
|
log.Debug("The NTP startup check was skipped due to there being no configured 2FA access control rules")
|
||||||
} else if err = doStartupCheck(logger, "ntp", providers.NTP, config.NTP.DisableStartupCheck); err != nil {
|
} else if err = doStartupCheck(log, "ntp", providers.NTP, config.NTP.DisableStartupCheck); err != nil {
|
||||||
logger.Errorf("Failure running the ntp provider startup check: %+v", err)
|
log.Errorf("Failure running the ntp provider startup check: %+v", err)
|
||||||
|
|
||||||
if !config.NTP.DisableFailure {
|
if !config.NTP.DisableFailure {
|
||||||
failures = append(failures, "ntp")
|
failures = append(failures, "ntp")
|
||||||
|
@ -174,7 +207,7 @@ func doStartupChecks(config *schema.Configuration, providers *middlewares.Provid
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(failures) != 0 {
|
if len(failures) != 0 {
|
||||||
logger.Fatalf("The following providers had fatal failures during startup: %s", strings.Join(failures, ", "))
|
log.Fatalf("The following providers had fatal failures during startup: %s", strings.Join(failures, ", "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func recoverErr(i interface{}) error {
|
||||||
|
switch v := i.(type) {
|
||||||
|
case nil:
|
||||||
|
return nil
|
||||||
|
case string:
|
||||||
|
return fmt.Errorf("recovered panic: %s", v)
|
||||||
|
case error:
|
||||||
|
return fmt.Errorf("recovered panic: %w", v)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("recovered panic with unknown type: %v", v)
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,13 +51,6 @@ server:
|
||||||
## Useful to allow overriding of specific static assets.
|
## Useful to allow overriding of specific static assets.
|
||||||
# asset_path: /config/assets/
|
# asset_path: /config/assets/
|
||||||
|
|
||||||
## Buffers usually should be configured to be the same value.
|
|
||||||
## Explanation at https://www.authelia.com/c/server#buffer-sizes
|
|
||||||
## Read buffer size adjusts the server's max incoming request size in bytes.
|
|
||||||
## Write buffer size does the same for outgoing responses.
|
|
||||||
read_buffer_size: 4096
|
|
||||||
write_buffer_size: 4096
|
|
||||||
|
|
||||||
## Enables the pprof endpoint.
|
## Enables the pprof endpoint.
|
||||||
enable_pprof: false
|
enable_pprof: false
|
||||||
|
|
||||||
|
@ -85,6 +78,32 @@ server:
|
||||||
## The CSP Template. Read the docs.
|
## The CSP Template. Read the docs.
|
||||||
csp_template: ""
|
csp_template: ""
|
||||||
|
|
||||||
|
## Server Buffers configuration.
|
||||||
|
# buffers:
|
||||||
|
|
||||||
|
## Buffers usually should be configured to be the same value.
|
||||||
|
## Explanation at https://www.authelia.com/c/server#buffer-sizes
|
||||||
|
## Read buffer size adjusts the server's max incoming request size in bytes.
|
||||||
|
## Write buffer size does the same for outgoing responses.
|
||||||
|
|
||||||
|
## Read buffer.
|
||||||
|
# read: 4096
|
||||||
|
|
||||||
|
## Write buffer.
|
||||||
|
# write: 4096
|
||||||
|
|
||||||
|
## Server Timeouts configuration.
|
||||||
|
# timeouts:
|
||||||
|
|
||||||
|
## Read timeout.
|
||||||
|
# read: 2s
|
||||||
|
|
||||||
|
## Write timeout.
|
||||||
|
# write: 2s
|
||||||
|
|
||||||
|
## Idle timeout.
|
||||||
|
# idle: 30s
|
||||||
|
|
||||||
##
|
##
|
||||||
## Log Configuration
|
## Log Configuration
|
||||||
##
|
##
|
||||||
|
@ -116,6 +135,27 @@ telemetry:
|
||||||
## The address to listen on for metrics. This should be on a different port to the main server.port value.
|
## The address to listen on for metrics. This should be on a different port to the main server.port value.
|
||||||
address: tcp://0.0.0.0:9959
|
address: tcp://0.0.0.0:9959
|
||||||
|
|
||||||
|
## Metrics Server Buffers configuration.
|
||||||
|
# buffers:
|
||||||
|
|
||||||
|
## Read buffer.
|
||||||
|
# read: 4096
|
||||||
|
|
||||||
|
## Write buffer.
|
||||||
|
# write: 4096
|
||||||
|
|
||||||
|
## Metrics Server Timeouts configuration.
|
||||||
|
# timeouts:
|
||||||
|
|
||||||
|
## Read timeout.
|
||||||
|
# read: 2s
|
||||||
|
|
||||||
|
## Write timeout.
|
||||||
|
# write: 2s
|
||||||
|
|
||||||
|
## Idle timeout.
|
||||||
|
# idle: 30s
|
||||||
|
|
||||||
##
|
##
|
||||||
## TOTP Configuration
|
## TOTP Configuration
|
||||||
##
|
##
|
||||||
|
|
|
@ -106,6 +106,13 @@ var deprecations = map[string]Deprecation{
|
||||||
AutoMap: true,
|
AutoMap: true,
|
||||||
MapFunc: nil,
|
MapFunc: nil,
|
||||||
},
|
},
|
||||||
|
"storage.postgres.sslmode": {
|
||||||
|
Version: model.SemanticVersion{Major: 4, Minor: 36},
|
||||||
|
Key: "storage.postgres.sslmode",
|
||||||
|
NewKey: "storage.postgres.ssl.mode",
|
||||||
|
AutoMap: true,
|
||||||
|
MapFunc: nil,
|
||||||
|
},
|
||||||
"authentication_backend.disable_reset_password": {
|
"authentication_backend.disable_reset_password": {
|
||||||
Version: model.SemanticVersion{Major: 4, Minor: 36},
|
Version: model.SemanticVersion{Major: 4, Minor: 36},
|
||||||
Key: "authentication_backend.disable_reset_password",
|
Key: "authentication_backend.disable_reset_password",
|
||||||
|
@ -113,4 +120,18 @@ var deprecations = map[string]Deprecation{
|
||||||
AutoMap: true,
|
AutoMap: true,
|
||||||
MapFunc: nil,
|
MapFunc: nil,
|
||||||
},
|
},
|
||||||
|
"server.read_buffer_size": {
|
||||||
|
Version: model.SemanticVersion{Major: 4, Minor: 37},
|
||||||
|
Key: "server.read_buffer_size",
|
||||||
|
NewKey: "server.buffers.read",
|
||||||
|
AutoMap: true,
|
||||||
|
MapFunc: nil,
|
||||||
|
},
|
||||||
|
"server.write_buffer_size": {
|
||||||
|
Version: model.SemanticVersion{Major: 4, Minor: 37},
|
||||||
|
Key: "server.write_buffer_size",
|
||||||
|
NewKey: "server.buffers.write",
|
||||||
|
AutoMap: true,
|
||||||
|
MapFunc: nil,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,6 @@ var Keys = []string{
|
||||||
"storage.postgres.ssl.root_certificate",
|
"storage.postgres.ssl.root_certificate",
|
||||||
"storage.postgres.ssl.certificate",
|
"storage.postgres.ssl.certificate",
|
||||||
"storage.postgres.ssl.key",
|
"storage.postgres.ssl.key",
|
||||||
"storage.postgres.sslmode",
|
|
||||||
"storage.encryption_key",
|
"storage.encryption_key",
|
||||||
"notifier.disable_startup_check",
|
"notifier.disable_startup_check",
|
||||||
"notifier.filesystem.filename",
|
"notifier.filesystem.filename",
|
||||||
|
@ -173,8 +172,6 @@ var Keys = []string{
|
||||||
"server.port",
|
"server.port",
|
||||||
"server.path",
|
"server.path",
|
||||||
"server.asset_path",
|
"server.asset_path",
|
||||||
"server.read_buffer_size",
|
|
||||||
"server.write_buffer_size",
|
|
||||||
"server.enable_pprof",
|
"server.enable_pprof",
|
||||||
"server.enable_expvars",
|
"server.enable_expvars",
|
||||||
"server.disable_healthcheck",
|
"server.disable_healthcheck",
|
||||||
|
@ -182,8 +179,18 @@ var Keys = []string{
|
||||||
"server.tls.key",
|
"server.tls.key",
|
||||||
"server.tls.client_certificates",
|
"server.tls.client_certificates",
|
||||||
"server.headers.csp_template",
|
"server.headers.csp_template",
|
||||||
|
"server.buffers.read",
|
||||||
|
"server.buffers.write",
|
||||||
|
"server.timeouts.read",
|
||||||
|
"server.timeouts.write",
|
||||||
|
"server.timeouts.idle",
|
||||||
"telemetry.metrics.enabled",
|
"telemetry.metrics.enabled",
|
||||||
"telemetry.metrics.address",
|
"telemetry.metrics.address",
|
||||||
|
"telemetry.metrics.buffers.read",
|
||||||
|
"telemetry.metrics.buffers.write",
|
||||||
|
"telemetry.metrics.timeouts.read",
|
||||||
|
"telemetry.metrics.timeouts.write",
|
||||||
|
"telemetry.metrics.timeouts.idle",
|
||||||
"webauthn.disable",
|
"webauthn.disable",
|
||||||
"webauthn.display_name",
|
"webauthn.display_name",
|
||||||
"webauthn.attestation_conveyance_preference",
|
"webauthn.attestation_conveyance_preference",
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
package schema
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// ServerConfiguration represents the configuration of the http server.
|
// ServerConfiguration represents the configuration of the http server.
|
||||||
type ServerConfiguration struct {
|
type ServerConfiguration struct {
|
||||||
Host string `koanf:"host"`
|
Host string `koanf:"host"`
|
||||||
Port int `koanf:"port"`
|
Port int `koanf:"port"`
|
||||||
Path string `koanf:"path"`
|
Path string `koanf:"path"`
|
||||||
AssetPath string `koanf:"asset_path"`
|
AssetPath string `koanf:"asset_path"`
|
||||||
ReadBufferSize int `koanf:"read_buffer_size"`
|
|
||||||
WriteBufferSize int `koanf:"write_buffer_size"`
|
|
||||||
EnablePprof bool `koanf:"enable_pprof"`
|
EnablePprof bool `koanf:"enable_pprof"`
|
||||||
EnableExpvars bool `koanf:"enable_expvars"`
|
EnableExpvars bool `koanf:"enable_expvars"`
|
||||||
DisableHealthcheck bool `koanf:"disable_healthcheck"`
|
DisableHealthcheck bool `koanf:"disable_healthcheck"`
|
||||||
|
|
||||||
TLS ServerTLSConfiguration `koanf:"tls"`
|
TLS ServerTLSConfiguration `koanf:"tls"`
|
||||||
Headers ServerHeadersConfiguration `koanf:"headers"`
|
Headers ServerHeadersConfiguration `koanf:"headers"`
|
||||||
|
|
||||||
|
Buffers ServerBuffers `koanf:"buffers"`
|
||||||
|
Timeouts ServerTimeouts `koanf:"timeouts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerTLSConfiguration represents the configuration of the http servers TLS options.
|
// ServerTLSConfiguration represents the configuration of the http servers TLS options.
|
||||||
|
@ -32,6 +37,13 @@ type ServerHeadersConfiguration struct {
|
||||||
var DefaultServerConfiguration = ServerConfiguration{
|
var DefaultServerConfiguration = ServerConfiguration{
|
||||||
Host: "0.0.0.0",
|
Host: "0.0.0.0",
|
||||||
Port: 9091,
|
Port: 9091,
|
||||||
ReadBufferSize: 4096,
|
Buffers: ServerBuffers{
|
||||||
WriteBufferSize: 4096,
|
Read: 4096,
|
||||||
|
Write: 4096,
|
||||||
|
},
|
||||||
|
Timeouts: ServerTimeouts{
|
||||||
|
Read: time.Second * 2,
|
||||||
|
Write: time.Second * 2,
|
||||||
|
Idle: time.Second * 30,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,25 @@
|
||||||
package schema
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// TLSConfig is a representation of the TLS configuration.
|
// TLSConfig is a representation of the TLS configuration.
|
||||||
type TLSConfig struct {
|
type TLSConfig struct {
|
||||||
MinimumVersion string `koanf:"minimum_version"`
|
MinimumVersion string `koanf:"minimum_version"`
|
||||||
SkipVerify bool `koanf:"skip_verify"`
|
SkipVerify bool `koanf:"skip_verify"`
|
||||||
ServerName string `koanf:"server_name"`
|
ServerName string `koanf:"server_name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServerTimeouts represents server timeout configurations.
|
||||||
|
type ServerTimeouts struct {
|
||||||
|
Read time.Duration `koanf:"read"`
|
||||||
|
Write time.Duration `koanf:"write"`
|
||||||
|
Idle time.Duration `koanf:"idle"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerBuffers represents server buffer configurations.
|
||||||
|
type ServerBuffers struct {
|
||||||
|
Read int `koanf:"read"`
|
||||||
|
Write int `koanf:"write"`
|
||||||
|
}
|
||||||
|
|
|
@ -28,9 +28,6 @@ type PostgreSQLStorageConfiguration struct {
|
||||||
Schema string `koanf:"schema"`
|
Schema string `koanf:"schema"`
|
||||||
|
|
||||||
SSL PostgreSQLSSLStorageConfiguration `koanf:"ssl"`
|
SSL PostgreSQLSSLStorageConfiguration `koanf:"ssl"`
|
||||||
|
|
||||||
// Deprecated. TODO: Remove in v4.36.0.
|
|
||||||
SSLMode string `koanf:"sslmode"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostgreSQLSSLStorageConfiguration represents the SSL configuration of a PostgreSQL database.
|
// PostgreSQLSSLStorageConfiguration represents the SSL configuration of a PostgreSQL database.
|
||||||
|
|
|
@ -2,6 +2,7 @@ package schema
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TelemetryConfig represents the telemetry config.
|
// TelemetryConfig represents the telemetry config.
|
||||||
|
@ -13,11 +14,23 @@ type TelemetryConfig struct {
|
||||||
type TelemetryMetricsConfig struct {
|
type TelemetryMetricsConfig struct {
|
||||||
Enabled bool `koanf:"enabled"`
|
Enabled bool `koanf:"enabled"`
|
||||||
Address *Address `koanf:"address"`
|
Address *Address `koanf:"address"`
|
||||||
|
|
||||||
|
Buffers ServerBuffers `koanf:"buffers"`
|
||||||
|
Timeouts ServerTimeouts `koanf:"timeouts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultTelemetryConfig is the default telemetry configuration.
|
// DefaultTelemetryConfig is the default telemetry configuration.
|
||||||
var DefaultTelemetryConfig = TelemetryConfig{
|
var DefaultTelemetryConfig = TelemetryConfig{
|
||||||
Metrics: TelemetryMetricsConfig{
|
Metrics: TelemetryMetricsConfig{
|
||||||
Address: &Address{true, "tcp", net.ParseIP("0.0.0.0"), 9959},
|
Address: &Address{true, "tcp", net.ParseIP("0.0.0.0"), 9959},
|
||||||
|
Buffers: ServerBuffers{
|
||||||
|
Read: 4096,
|
||||||
|
Write: 4096,
|
||||||
|
},
|
||||||
|
Timeouts: ServerTimeouts{
|
||||||
|
Read: time.Second * 2,
|
||||||
|
Write: time.Second * 2,
|
||||||
|
Idle: time.Second * 30,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,7 +247,6 @@ const (
|
||||||
|
|
||||||
errFmtServerPathNoForwardSlashes = "server: option 'path' must not contain any forward slashes"
|
errFmtServerPathNoForwardSlashes = "server: option 'path' must not contain any forward slashes"
|
||||||
errFmtServerPathAlphaNum = "server: option 'path' must only contain alpha numeric characters"
|
errFmtServerPathAlphaNum = "server: option 'path' must only contain alpha numeric characters"
|
||||||
errFmtServerBufferSize = "server: option '%s_buffer_size' must be above 0 but it is configured as '%d'"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -70,15 +70,23 @@ func ValidateServer(config *schema.Configuration, validator *schema.StructValida
|
||||||
config.Server.Path = path.Clean("/" + config.Server.Path)
|
config.Server.Path = path.Clean("/" + config.Server.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Server.ReadBufferSize == 0 {
|
if config.Server.Buffers.Read <= 0 {
|
||||||
config.Server.ReadBufferSize = schema.DefaultServerConfiguration.ReadBufferSize
|
config.Server.Buffers.Read = schema.DefaultServerConfiguration.Buffers.Read
|
||||||
} else if config.Server.ReadBufferSize < 0 {
|
|
||||||
validator.Push(fmt.Errorf(errFmtServerBufferSize, "read", config.Server.ReadBufferSize))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Server.WriteBufferSize == 0 {
|
if config.Server.Buffers.Write <= 0 {
|
||||||
config.Server.WriteBufferSize = schema.DefaultServerConfiguration.WriteBufferSize
|
config.Server.Buffers.Write = schema.DefaultServerConfiguration.Buffers.Write
|
||||||
} else if config.Server.WriteBufferSize < 0 {
|
}
|
||||||
validator.Push(fmt.Errorf(errFmtServerBufferSize, "write", config.Server.WriteBufferSize))
|
|
||||||
|
if config.Server.Timeouts.Read <= 0 {
|
||||||
|
config.Server.Timeouts.Read = schema.DefaultServerConfiguration.Timeouts.Read
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Server.Timeouts.Write <= 0 {
|
||||||
|
config.Server.Timeouts.Write = schema.DefaultServerConfiguration.Timeouts.Write
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Server.Timeouts.Idle <= 0 {
|
||||||
|
config.Server.Timeouts.Idle = schema.DefaultServerConfiguration.Timeouts.Idle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package validator
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -23,8 +24,8 @@ func TestShouldSetDefaultServerValues(t *testing.T) {
|
||||||
|
|
||||||
assert.Equal(t, schema.DefaultServerConfiguration.Host, config.Server.Host)
|
assert.Equal(t, schema.DefaultServerConfiguration.Host, config.Server.Host)
|
||||||
assert.Equal(t, schema.DefaultServerConfiguration.Port, config.Server.Port)
|
assert.Equal(t, schema.DefaultServerConfiguration.Port, config.Server.Port)
|
||||||
assert.Equal(t, schema.DefaultServerConfiguration.ReadBufferSize, config.Server.ReadBufferSize)
|
assert.Equal(t, schema.DefaultServerConfiguration.Buffers.Read, config.Server.Buffers.Read)
|
||||||
assert.Equal(t, schema.DefaultServerConfiguration.WriteBufferSize, config.Server.WriteBufferSize)
|
assert.Equal(t, schema.DefaultServerConfiguration.Buffers.Write, config.Server.Buffers.Write)
|
||||||
assert.Equal(t, schema.DefaultServerConfiguration.TLS.Key, config.Server.TLS.Key)
|
assert.Equal(t, schema.DefaultServerConfiguration.TLS.Key, config.Server.TLS.Key)
|
||||||
assert.Equal(t, schema.DefaultServerConfiguration.TLS.Certificate, config.Server.TLS.Certificate)
|
assert.Equal(t, schema.DefaultServerConfiguration.TLS.Certificate, config.Server.TLS.Certificate)
|
||||||
assert.Equal(t, schema.DefaultServerConfiguration.Path, config.Server.Path)
|
assert.Equal(t, schema.DefaultServerConfiguration.Path, config.Server.Path)
|
||||||
|
@ -41,8 +42,8 @@ func TestShouldSetDefaultConfig(t *testing.T) {
|
||||||
assert.Len(t, validator.Errors(), 0)
|
assert.Len(t, validator.Errors(), 0)
|
||||||
assert.Len(t, validator.Warnings(), 0)
|
assert.Len(t, validator.Warnings(), 0)
|
||||||
|
|
||||||
assert.Equal(t, schema.DefaultServerConfiguration.ReadBufferSize, config.Server.ReadBufferSize)
|
assert.Equal(t, schema.DefaultServerConfiguration.Buffers.Read, config.Server.Buffers.Read)
|
||||||
assert.Equal(t, schema.DefaultServerConfiguration.WriteBufferSize, config.Server.WriteBufferSize)
|
assert.Equal(t, schema.DefaultServerConfiguration.Buffers.Write, config.Server.Buffers.Write)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldParsePathCorrectly(t *testing.T) {
|
func TestShouldParsePathCorrectly(t *testing.T) {
|
||||||
|
@ -61,21 +62,32 @@ func TestShouldParsePathCorrectly(t *testing.T) {
|
||||||
assert.Equal(t, "/apple", config.Server.Path)
|
assert.Equal(t, "/apple", config.Server.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldRaiseOnNegativeValues(t *testing.T) {
|
func TestShouldDefaultOnNegativeValues(t *testing.T) {
|
||||||
validator := schema.NewStructValidator()
|
validator := schema.NewStructValidator()
|
||||||
config := &schema.Configuration{
|
config := &schema.Configuration{
|
||||||
Server: schema.ServerConfiguration{
|
Server: schema.ServerConfiguration{
|
||||||
ReadBufferSize: -1,
|
Buffers: schema.ServerBuffers{
|
||||||
WriteBufferSize: -1,
|
Read: -1,
|
||||||
|
Write: -1,
|
||||||
|
},
|
||||||
|
Timeouts: schema.ServerTimeouts{
|
||||||
|
Read: time.Second * -1,
|
||||||
|
Write: time.Second * -1,
|
||||||
|
Idle: time.Second * -1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidateServer(config, validator)
|
ValidateServer(config, validator)
|
||||||
|
|
||||||
require.Len(t, validator.Errors(), 2)
|
require.Len(t, validator.Errors(), 0)
|
||||||
|
|
||||||
assert.EqualError(t, validator.Errors()[0], "server: option 'read_buffer_size' must be above 0 but it is configured as '-1'")
|
assert.Equal(t, schema.DefaultServerConfiguration.Buffers.Read, config.Server.Buffers.Read)
|
||||||
assert.EqualError(t, validator.Errors()[1], "server: option 'write_buffer_size' must be above 0 but it is configured as '-1'")
|
assert.Equal(t, schema.DefaultServerConfiguration.Buffers.Write, config.Server.Buffers.Write)
|
||||||
|
|
||||||
|
assert.Equal(t, schema.DefaultServerConfiguration.Timeouts.Read, config.Server.Timeouts.Read)
|
||||||
|
assert.Equal(t, schema.DefaultServerConfiguration.Timeouts.Write, config.Server.Timeouts.Write)
|
||||||
|
assert.Equal(t, schema.DefaultServerConfiguration.Timeouts.Idle, config.Server.Timeouts.Idle)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldRaiseOnNonAlphanumericCharsInPath(t *testing.T) {
|
func TestShouldRaiseOnNonAlphanumericCharsInPath(t *testing.T) {
|
||||||
|
|
|
@ -56,11 +56,6 @@ func validatePostgreSQLConfiguration(config *schema.PostgreSQLStorageConfigurati
|
||||||
config.Schema = schema.DefaultPostgreSQLStorageConfiguration.Schema
|
config.Schema = schema.DefaultPostgreSQLStorageConfiguration.Schema
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated. TODO: Remove in v4.36.0.
|
|
||||||
if config.SSLMode != "" && config.SSL.Mode == "" {
|
|
||||||
config.SSL.Mode = config.SSLMode
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.SSL.Mode == "" {
|
if config.SSL.Mode == "" {
|
||||||
config.SSL.Mode = schema.DefaultPostgreSQLStorageConfiguration.SSL.Mode
|
config.SSL.Mode = schema.DefaultPostgreSQLStorageConfiguration.SSL.Mode
|
||||||
} else if !utils.IsStringInSlice(config.SSL.Mode, validStoragePostgreSQLSSLModes) {
|
} else if !utils.IsStringInSlice(config.SSL.Mode, validStoragePostgreSQLSSLModes) {
|
||||||
|
|
|
@ -166,26 +166,6 @@ func (suite *StorageSuite) TestShouldValidatePostgresSSLModeMustBeValid() {
|
||||||
suite.Assert().EqualError(suite.validator.Errors()[0], "storage: postgres: ssl: option 'mode' must be one of 'disable', 'require', 'verify-ca', 'verify-full' but it is configured as 'unknown'")
|
suite.Assert().EqualError(suite.validator.Errors()[0], "storage: postgres: ssl: option 'mode' must be one of 'disable', 'require', 'verify-ca', 'verify-full' but it is configured as 'unknown'")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated. TODO: Remove in v4.36.0.
|
|
||||||
func (suite *StorageSuite) TestShouldValidatePostgresSSLModeMustBeMappedForDeprecations() {
|
|
||||||
suite.config.PostgreSQL = &schema.PostgreSQLStorageConfiguration{
|
|
||||||
SQLStorageConfiguration: schema.SQLStorageConfiguration{
|
|
||||||
Host: "pg",
|
|
||||||
Username: "myuser",
|
|
||||||
Password: "pass",
|
|
||||||
Database: "database",
|
|
||||||
},
|
|
||||||
SSLMode: "require",
|
|
||||||
}
|
|
||||||
|
|
||||||
ValidateStorage(suite.config, suite.validator)
|
|
||||||
|
|
||||||
suite.Assert().Len(suite.validator.Warnings(), 0)
|
|
||||||
suite.Assert().Len(suite.validator.Errors(), 0)
|
|
||||||
|
|
||||||
suite.Assert().Equal(suite.config.PostgreSQL.SSL.Mode, "require")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *StorageSuite) TestShouldRaiseErrorOnNoEncryptionKey() {
|
func (suite *StorageSuite) TestShouldRaiseErrorOnNoEncryptionKey() {
|
||||||
suite.config.EncryptionKey = ""
|
suite.config.EncryptionKey = ""
|
||||||
suite.config.Local = &schema.LocalStorageConfiguration{
|
suite.config.Local = &schema.LocalStorageConfiguration{
|
||||||
|
|
|
@ -22,4 +22,24 @@ func ValidateTelemetry(config *schema.Configuration, validator *schema.StructVal
|
||||||
if config.Telemetry.Metrics.Address.Port == 0 {
|
if config.Telemetry.Metrics.Address.Port == 0 {
|
||||||
config.Telemetry.Metrics.Address.Port = schema.DefaultTelemetryConfig.Metrics.Address.Port
|
config.Telemetry.Metrics.Address.Port = schema.DefaultTelemetryConfig.Metrics.Address.Port
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.Telemetry.Metrics.Buffers.Read <= 0 {
|
||||||
|
config.Telemetry.Metrics.Buffers.Read = schema.DefaultTelemetryConfig.Metrics.Buffers.Read
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Telemetry.Metrics.Buffers.Write <= 0 {
|
||||||
|
config.Telemetry.Metrics.Buffers.Write = schema.DefaultTelemetryConfig.Metrics.Buffers.Write
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Telemetry.Metrics.Timeouts.Read <= 0 {
|
||||||
|
config.Telemetry.Metrics.Timeouts.Read = schema.DefaultTelemetryConfig.Metrics.Timeouts.Read
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Telemetry.Metrics.Timeouts.Write <= 0 {
|
||||||
|
config.Telemetry.Metrics.Timeouts.Write = schema.DefaultTelemetryConfig.Metrics.Timeouts.Write
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Telemetry.Metrics.Timeouts.Idle <= 0 {
|
||||||
|
config.Telemetry.Metrics.Timeouts.Idle = schema.DefaultTelemetryConfig.Metrics.Timeouts.Idle
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,3 +74,12 @@ const (
|
||||||
cspDefaultTemplate = "default-src 'self'%s; frame-src 'none'; object-src 'none'; style-src 'self' 'nonce-%s'; frame-ancestors 'none'; base-uri 'self'"
|
cspDefaultTemplate = "default-src 'self'%s; frame-src 'none'; object-src 'none'; style-src 'self' 'nonce-%s'; frame-ancestors 'none'; base-uri 'self'"
|
||||||
cspNoncePlaceholder = "${NONCE}"
|
cspNoncePlaceholder = "${NONCE}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
connNonTLS = "non-TLS"
|
||||||
|
connTLS = "TLS"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
fmtLogServerInit = "Initializing %s for %s connections on '%s' path '%s'"
|
||||||
|
)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
|
|
||||||
|
@ -21,8 +22,11 @@ func CreateDefaultServer(config schema.Configuration, providers middlewares.Prov
|
||||||
ErrorHandler: handleError(),
|
ErrorHandler: handleError(),
|
||||||
Handler: handleRouter(config, providers),
|
Handler: handleRouter(config, providers),
|
||||||
NoDefaultServerHeader: true,
|
NoDefaultServerHeader: true,
|
||||||
ReadBufferSize: config.Server.ReadBufferSize,
|
ReadBufferSize: config.Server.Buffers.Read,
|
||||||
WriteBufferSize: config.Server.WriteBufferSize,
|
WriteBufferSize: config.Server.Buffers.Write,
|
||||||
|
ReadTimeout: config.Server.Timeouts.Read,
|
||||||
|
WriteTimeout: config.Server.Timeouts.Write,
|
||||||
|
IdleTimeout: config.Server.Timeouts.Idle,
|
||||||
}
|
}
|
||||||
|
|
||||||
address := net.JoinHostPort(config.Server.Host, strconv.Itoa(config.Server.Port))
|
address := net.JoinHostPort(config.Server.Host, strconv.Itoa(config.Server.Port))
|
||||||
|
@ -33,7 +37,7 @@ func CreateDefaultServer(config schema.Configuration, providers middlewares.Prov
|
||||||
)
|
)
|
||||||
|
|
||||||
if config.Server.TLS.Certificate != "" && config.Server.TLS.Key != "" {
|
if config.Server.TLS.Certificate != "" && config.Server.TLS.Key != "" {
|
||||||
connectionType, connectionScheme = "TLS", schemeHTTPS
|
connectionType, connectionScheme = connTLS, schemeHTTPS
|
||||||
|
|
||||||
if err = server.AppendCert(config.Server.TLS.Certificate, config.Server.TLS.Key); err != nil {
|
if err = server.AppendCert(config.Server.TLS.Certificate, config.Server.TLS.Key); err != nil {
|
||||||
return nil, nil, fmt.Errorf("unable to load tls server certificate '%s' or private key '%s': %w", config.Server.TLS.Certificate, config.Server.TLS.Key, err)
|
return nil, nil, fmt.Errorf("unable to load tls server certificate '%s' or private key '%s': %w", config.Server.TLS.Certificate, config.Server.TLS.Key, err)
|
||||||
|
@ -62,7 +66,7 @@ func CreateDefaultServer(config schema.Configuration, providers middlewares.Prov
|
||||||
return nil, nil, fmt.Errorf("unable to initialize tcp listener: %w", err)
|
return nil, nil, fmt.Errorf("unable to initialize tcp listener: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
connectionType, connectionScheme = "non-TLS", schemeHTTP
|
connectionType, connectionScheme = connNonTLS, schemeHTTP
|
||||||
|
|
||||||
if listener, err = net.Listen("tcp", address); err != nil {
|
if listener, err = net.Listen("tcp", address); err != nil {
|
||||||
return nil, nil, fmt.Errorf("unable to initialize tcp listener: %w", err)
|
return nil, nil, fmt.Errorf("unable to initialize tcp listener: %w", err)
|
||||||
|
@ -74,14 +78,14 @@ func CreateDefaultServer(config schema.Configuration, providers middlewares.Prov
|
||||||
return nil, nil, fmt.Errorf("unable to configure healthcheck: %w", err)
|
return nil, nil, fmt.Errorf("unable to configure healthcheck: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger := logging.Logger()
|
paths := []string{"/"}
|
||||||
|
|
||||||
if config.Server.Path == "" {
|
if config.Server.Path != "" {
|
||||||
logger.Infof("Initializing server for %s connections on '%s' path '/'", connectionType, listener.Addr().String())
|
paths = append(paths, config.Server.Path)
|
||||||
} else {
|
|
||||||
logger.Infof("Initializing server for %s connections on '%s' paths '/' and '%s'", connectionType, listener.Addr().String(), config.Server.Path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logging.Logger().Infof(fmtLogServerInit, "server", connectionType, listener.Addr().String(), strings.Join(paths, "' and '"))
|
||||||
|
|
||||||
return server, listener, nil
|
return server, listener, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +99,14 @@ func CreateMetricsServer(config schema.TelemetryMetricsConfig) (server *fasthttp
|
||||||
ErrorHandler: handleError(),
|
ErrorHandler: handleError(),
|
||||||
NoDefaultServerHeader: true,
|
NoDefaultServerHeader: true,
|
||||||
Handler: handleMetrics(),
|
Handler: handleMetrics(),
|
||||||
|
ReadBufferSize: config.Buffers.Read,
|
||||||
|
WriteBufferSize: config.Buffers.Write,
|
||||||
|
ReadTimeout: config.Timeouts.Read,
|
||||||
|
WriteTimeout: config.Timeouts.Write,
|
||||||
|
IdleTimeout: config.Timeouts.Idle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logging.Logger().Infof(fmtLogServerInit, "server (metrics)", connNonTLS, listener.Addr().String(), "/metrics")
|
||||||
|
|
||||||
return server, listener, nil
|
return server, listener, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,6 @@ func TestShouldRaiseErrorWhenClientDoesNotSkipVerify(t *testing.T) {
|
||||||
|
|
||||||
defer tlsServerContext.Close()
|
defer tlsServerContext.Close()
|
||||||
|
|
||||||
fmt.Println(tlsServerContext.Port())
|
|
||||||
req, err := http.NewRequest("GET", fmt.Sprintf("https://local.example.com:%d", tlsServerContext.Port()), nil)
|
req, err := http.NewRequest("GET", fmt.Sprintf("https://local.example.com:%d", tlsServerContext.Port()), nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue