refactor(configuration): umask from query (#5416)

Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com>
pull/5419/head
James Elliott 2023-05-09 21:25:56 +10:00 committed by GitHub
parent 3a752f5ac9
commit 6c472d8627
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 340 additions and 197 deletions

View File

@ -22,7 +22,6 @@ aliases:
```yaml
server:
address: 'tcp://:9091'
umask: 0022
path: ''
disable_healthcheck: false
tls:
@ -80,20 +79,6 @@ server:
address: unix:///var/run/authelia.sock
```
### umask
{{< confkey type="int" required="no" >}}
If set temporarily changes the umask during the creation of the unix domain socket if configured as such in the
[address](#address). Typically this should be set before the process is actually running and users should not use this
option, however it's recognized in various specific scenarios this may not be completely adequate.
One such example is when you want the proxy to have permission to the socket but not the files, in which case running a
umask of `0077` by default is good, and running a umask of `0027` so that the group Authelia is running as has
permission to the socket.
This value should typically be prefixed with a `0` to ensure the relevant parsers handle it correctly.
### path
{{< confkey type="string " required="no" >}}

View File

@ -108,10 +108,22 @@ The following format represents the unix domain socket format. It's valid for bo
instances. Refer to the individual documentation for an option for clarity. In this format as per the notation there
are no optional portions.
The Unix Domain Socket format also accepts a query string. The following query parameters control certain behaviour of
this address type.
| Parameter | Listeners | Connectors | Purpose |
|:---------:|:---------:|:----------:|:------------------------------------------------------------------------------------------------------------------------------------:|
| `umask` | Yes | No | Sets the umask prior to creating the socket and restores it after creating it. The value must be an octal number with 3 or 4 digits. |
```text
unix://<path>
```
```text
unix://<path>?umask=0022
```
##### Examples
Various examples for these formats.

View File

@ -23,7 +23,6 @@ telemetry:
metrics:
enabled: false
address: 'tcp://:9959'
umask: 0022
buffers:
read: 4096
write: 4096
@ -53,20 +52,6 @@ see the [documentation](../prologue/common.md#address) on this format for more i
Configures the listener address for the [Prometheus] Metrics Exporter HTTP Server. The address itself is a listener and
the scheme must either be the `unix` scheme or one of the `tcp` schemes.
### umask
{{< confkey type="int" required="no" >}}
If set temporarily changes the umask during the creation of the unix domain socket if configured as such in the
[address](#address). Typically this should be set before the process is actually running and users should not use this
option, however it's recognized in various specific scenarios this may not be completely adequate.
One such example is when you want the proxy to have permission to the socket but not the files, in which case running a
umask of `0077` by default is good, and running a umask of `0027` so that the group Authelia is running as has
permission to the socket.
This value should typically be prefixed with a `0` to ensure the relevant parsers handle it correctly.
### buffers
*__Reference Note:__ This configuration option uses the

File diff suppressed because one or more lines are too long

View File

@ -103,9 +103,17 @@ const (
TOTPSecretSizeMinimum = 20
)
var (
// regexpHasScheme checks if a string has a scheme. Valid characters for schemes include alphanumeric, hyphen,
// period, and plus characters.
var regexpHasScheme = regexp.MustCompile(`^[-+.a-zA-Z\d]*(://|:$)`)
regexpHasScheme = regexp.MustCompile(`^[-+.a-zA-Z\d]*(://|:$)`)
regexpIsUmask = regexp.MustCompile(`^[0-7]{3,4}$`)
)
const (
addressQueryParamUmask = "umask"
)
const (
blockCERTIFICATE = "CERTIFICATE"

View File

@ -239,7 +239,6 @@ var Keys = []string{
"notifier.smtp.port",
"notifier.template_path",
"server.address",
"server.umask",
"server.path",
"server.asset_path",
"server.disable_healthcheck",
@ -262,7 +261,6 @@ var Keys = []string{
"server.port",
"telemetry.metrics.enabled",
"telemetry.metrics.address",
"telemetry.metrics.umask",
"telemetry.metrics.buffers.read",
"telemetry.metrics.buffers.write",
"telemetry.metrics.timeouts.read",

View File

@ -44,7 +44,7 @@ type NotifierConfiguration struct {
// DefaultSMTPNotifierConfiguration represents default configuration parameters for the SMTP notifier.
var DefaultSMTPNotifierConfiguration = SMTPNotifierConfiguration{
Address: &AddressSMTP{Address{true, false, 25, &url.URL{Scheme: AddressSchemeSMTP, Host: "localhost:25"}}},
Address: &AddressSMTP{Address{true, false, -1, 25, &url.URL{Scheme: AddressSchemeSMTP, Host: "localhost:25"}}},
Timeout: time.Second * 5,
Subject: "[Authelia] {title}",
Identifier: "localhost",

View File

@ -8,8 +8,6 @@ import (
// ServerConfiguration represents the configuration of the http server.
type ServerConfiguration struct {
Address *AddressTCP `koanf:"address"`
UMask *int `koanf:"umask"`
Path string `koanf:"path"`
AssetPath string `koanf:"asset_path"`
DisableHealthcheck bool `koanf:"disable_healthcheck"`
@ -62,7 +60,7 @@ type ServerHeaders struct {
// DefaultServerConfiguration represents the default values of the ServerConfiguration.
var DefaultServerConfiguration = ServerConfiguration{
Address: &AddressTCP{Address{true, false, 9091, &url.URL{Scheme: AddressSchemeTCP, Host: ":9091"}}},
Address: &AddressTCP{Address{true, false, -1, 9091, &url.URL{Scheme: AddressSchemeTCP, Host: ":9091"}}},
Buffers: ServerBuffers{
Read: 4096,
Write: 4096,

View File

@ -75,7 +75,7 @@ var DefaultMySQLStorageConfiguration = MySQLStorageConfiguration{
// DefaultPostgreSQLStorageConfiguration represents the default PostgreSQL configuration.
var DefaultPostgreSQLStorageConfiguration = PostgreSQLStorageConfiguration{
SQLStorageConfiguration: SQLStorageConfiguration{
Address: &AddressTCP{Address{true, false, 5432, &url.URL{Scheme: AddressSchemeTCP, Host: "localhost:5432"}}},
Address: &AddressTCP{Address{true, false, -1, 5432, &url.URL{Scheme: AddressSchemeTCP, Host: "localhost:5432"}}},
},
Schema: "public",
TLS: &TLSConfig{

View File

@ -14,8 +14,6 @@ type TelemetryConfig struct {
type TelemetryMetricsConfig struct {
Enabled bool `koanf:"enabled"`
Address *AddressTCP `koanf:"address"`
UMask *int `koanf:"umask"`
Buffers ServerBuffers `koanf:"buffers"`
Timeouts ServerTimeouts `koanf:"timeouts"`
}
@ -23,7 +21,7 @@ type TelemetryMetricsConfig struct {
// DefaultTelemetryConfig is the default telemetry configuration.
var DefaultTelemetryConfig = TelemetryConfig{
Metrics: TelemetryMetricsConfig{
Address: &AddressTCP{Address{true, false, 9959, &url.URL{Scheme: AddressSchemeTCP, Host: ":9959"}}},
Address: &AddressTCP{Address{true, false, -1, 9959, &url.URL{Scheme: AddressSchemeTCP, Host: ":9959"}}},
Buffers: ServerBuffers{
Read: 4096,
Write: 4096,

View File

@ -21,7 +21,7 @@ func NewAddress(value string) (address *Address, err error) {
// else without a scheme is the schemeDefault scheme.
func NewAddressDefault(value, schemeDefault, schemeDefaultPath string) (address *Address, err error) {
if len(value) == 0 {
return &Address{true, false, 0, &url.URL{Scheme: AddressSchemeTCP, Host: ":0"}}, nil
return &Address{true, false, -1, 0, &url.URL{Scheme: AddressSchemeTCP, Host: ":0"}}, nil
}
var u *url.URL
@ -71,12 +71,17 @@ func NewAddressFromNetworkValuesDefault(value string, port int, schemeDefault, s
// NewAddressUnix returns an *Address from a path value.
func NewAddressUnix(path string) Address {
return Address{true, true, 0, &url.URL{Scheme: AddressSchemeUnix, Path: path}}
return Address{true, true, -1, 0, &url.URL{Scheme: AddressSchemeUnix, Path: path}}
}
// NewAddressFromNetworkValues returns an *Address from network values.
func NewAddressFromNetworkValues(network, host string, port int) Address {
return Address{true, false, port, &url.URL{Scheme: network, Host: fmt.Sprintf("%s:%d", host, port)}}
return NewAddressFromNetworkPathValues(network, host, port, "")
}
// NewAddressFromNetworkPathValues returns an *Address from network values and a path.
func NewAddressFromNetworkPathValues(network, host string, port int, path string) Address {
return Address{true, false, -1, port, &url.URL{Scheme: network, Host: fmt.Sprintf("%s:%d", host, port), Path: path}}
}
// NewSMTPAddress returns an *AddressSMTP from SMTP values.
@ -103,13 +108,14 @@ func NewSMTPAddress(scheme, host string, port int) *AddressSMTP {
}
}
return &AddressSMTP{Address: Address{true, false, port, &url.URL{Scheme: scheme, Host: fmt.Sprintf("%s:%d", host, port)}}}
return &AddressSMTP{Address: Address{true, false, -1, port, &url.URL{Scheme: scheme, Host: fmt.Sprintf("%s:%d", host, port)}}}
}
// NewAddressFromURL returns an *Address and error depending on the ability to parse the *url.URL as an Address.
func NewAddressFromURL(u *url.URL) (addr *Address, err error) {
addr = &Address{
url: u,
umask: -1,
}
if err = addr.validate(); err != nil {
@ -143,6 +149,7 @@ type AddressSMTP struct {
type Address struct {
valid bool
socket bool
umask int
port int
url *url.URL
@ -153,6 +160,15 @@ func (a *Address) Valid() bool {
return a.valid
}
// Umask returns the formatted umask or an empty string.
func (a *Address) Umask() string {
if a.umask == -1 {
return ""
}
return fmt.Sprintf("%04s", strconv.FormatInt(int64(a.umask), 8))
}
// IsUnixDomainSocket returns true if the address has been determined to be a Unix Domain Socket.
func (a *Address) IsUnixDomainSocket() bool {
return a.socket
@ -257,16 +273,6 @@ func (a *Address) String() string {
return a.url.String()
}
// Network returns the Scheme() if it's appropriate for the net packages network arguments otherwise it returns tcp.
func (a *Address) Network() string {
switch scheme := a.Scheme(); scheme {
case AddressSchemeTCP, AddressSchemeTCP4, AddressSchemeTCP6, AddressSchemeUDP, AddressSchemeUDP4, AddressSchemeUDP6, AddressSchemeUnix:
return scheme
default:
return AddressSchemeTCP
}
}
// Scheme returns the *url.URL Scheme field.
func (a *Address) Scheme() string {
if !a.valid || a.url == nil {
@ -276,6 +282,15 @@ func (a *Address) Scheme() string {
return a.url.Scheme
}
// Host returns the *url.URL Host field.
func (a *Address) Host() string {
if !a.valid || a.url == nil {
return ""
}
return a.url.Host
}
// Hostname returns the output of the *url.URL Hostname func.
func (a *Address) Hostname() string {
if !a.valid || a.url == nil {
@ -285,19 +300,6 @@ func (a *Address) Hostname() string {
return a.url.Hostname()
}
// SocketHostname returns the correct hostname for a socket connection.
func (a *Address) SocketHostname() string {
if !a.valid || a.url == nil {
return ""
}
if a.socket {
return a.url.Path
}
return a.url.Hostname()
}
// SetHostname sets the hostname preserving the port.
func (a *Address) SetHostname(hostname string) {
if !a.valid || a.url == nil {
@ -325,13 +327,36 @@ func (a *Address) SetPort(port int) {
a.setport(port)
}
// Host returns the *url.URL Host field.
func (a *Address) Host() string {
// Path returns the path.
func (a *Address) Path() string {
if !a.valid || a.url == nil {
return ""
}
return a.url.Host
return a.url.Path
}
// SocketHostname returns the correct hostname for a socket connection.
func (a *Address) SocketHostname() string {
if !a.valid || a.url == nil {
return ""
}
if a.socket {
return a.url.Path
}
return a.url.Hostname()
}
// Network returns the Scheme() if it's appropriate for the net packages network arguments otherwise it returns tcp.
func (a *Address) Network() string {
switch scheme := a.Scheme(); scheme {
case AddressSchemeTCP, AddressSchemeTCP4, AddressSchemeTCP6, AddressSchemeUDP, AddressSchemeUDP4, AddressSchemeUDP6, AddressSchemeUnix:
return scheme
default:
return AddressSchemeTCP
}
}
// NetworkAddress returns a string representation of the Address with just the host and port.
@ -348,30 +373,13 @@ func (a *Address) NetworkAddress() string {
}
// Listener creates and returns a net.Listener.
func (a *Address) Listener() (net.Listener, error) {
return a.listener()
}
// Dial creates and returns a dialed net.Conn.
func (a *Address) Dial() (net.Conn, error) {
func (a *Address) Listener() (ln net.Listener, err error) {
if a.url == nil {
return nil, fmt.Errorf("address url is nil")
}
return net.Dial(a.Network(), a.NetworkAddress())
}
// ListenerWithUMask creates and returns a net.Listener with a temporary UMask if the scheme is `unix`.
func (a *Address) ListenerWithUMask(umask int) (ln net.Listener, err error) {
if !a.socket {
return a.listener()
}
if a.url == nil {
return nil, fmt.Errorf("address url is nil")
}
umask = syscall.Umask(umask)
if a.socket && a.umask != -1 {
umask := syscall.Umask(a.umask)
ln, err = net.Listen(a.Network(), a.NetworkAddress())
@ -380,12 +388,16 @@ func (a *Address) ListenerWithUMask(umask int) (ln net.Listener, err error) {
return ln, err
}
func (a *Address) listener() (net.Listener, error) {
if a.url == nil {
return net.Listen(a.Network(), a.NetworkAddress())
}
// Dial creates and returns a dialed net.Conn.
func (a *Address) Dial() (net.Conn, error) {
if !a.valid || a.url == nil {
return nil, fmt.Errorf("address url is nil")
}
return net.Listen(a.Network(), a.NetworkAddress())
return net.Dial(a.Network(), a.NetworkAddress())
}
func (a *Address) setport(port int) {
@ -399,8 +411,8 @@ func (a *Address) validate() (err error) {
}
switch {
case a.url.RawQuery != "":
return fmt.Errorf("error validating the address: the url '%s' appears to have a query but this is not valid for addresses", a.url.String())
case a.url.RawQuery != "" && a.url.Scheme != AddressSchemeUnix:
return fmt.Errorf("error validating the address: the url '%s' appears to have a query but this is not valid for addresses with the '%s' scheme", a.url.String(), a.url.Scheme)
case a.url.RawFragment != "", a.url.Fragment != "":
return fmt.Errorf("error validating the address: the url '%s' appears to have a fragment but this is not valid for addresses", a.url.String())
case a.url.User != nil:
@ -469,6 +481,8 @@ func (a *Address) validateTCPUDP() (err error) {
}
func (a *Address) validateUnixSocket() (err error) {
umask := -1
switch {
case a.url.Path == "" && a.url.Scheme != AddressSchemeLDAPI:
return fmt.Errorf("error validating the unix socket address: could not determine path from '%s'", a.url.String())
@ -476,7 +490,22 @@ func (a *Address) validateUnixSocket() (err error) {
return fmt.Errorf("error validating the unix socket address: the url '%s' appears to have a host but this is not valid for unix sockets: this may occur if you omit the leading forward slash from the socket path", a.url.String())
}
if a.url.Query().Has(addressQueryParamUmask) {
v := a.url.Query().Get(addressQueryParamUmask)
if !regexpIsUmask.MatchString(v) {
return fmt.Errorf("error validating the unix socket address: could not parse address '%s': the address has a umask value of '%s' which does not appear to be a valid octal string", a.url.String(), v)
}
var p int64
p, _ = strconv.ParseInt(v, 8, 0)
umask = int(p)
}
a.socket = true
a.umask = umask
return nil
}

View File

@ -1,6 +1,7 @@
package schema
import (
"fmt"
"net"
"net/url"
"path/filepath"
@ -20,7 +21,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldParseBasicAddress",
"tcp://0.0.0.0:9091",
&Address{true, false, 9091, &url.URL{Scheme: AddressSchemeTCP, Host: "0.0.0.0:9091"}},
&Address{true, false, -1, 9091, &url.URL{Scheme: AddressSchemeTCP, Host: "0.0.0.0:9091"}},
"0.0.0.0:9091",
"tcp://0.0.0.0:9091",
"",
@ -28,7 +29,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldParseEmptyAddress",
"",
&Address{true, false, 0, &url.URL{Scheme: AddressSchemeTCP, Host: ":0"}},
&Address{true, false, -1, 0, &url.URL{Scheme: AddressSchemeTCP, Host: ":0"}},
":0",
"tcp://:0",
"",
@ -36,7 +37,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldParseAddressMissingScheme",
"0.0.0.0:9091",
&Address{true, false, 9091, &url.URL{Scheme: AddressSchemeTCP, Host: "0.0.0.0:9091"}},
&Address{true, false, -1, 9091, &url.URL{Scheme: AddressSchemeTCP, Host: "0.0.0.0:9091"}},
"0.0.0.0:9091",
"tcp://0.0.0.0:9091",
"",
@ -44,7 +45,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldParseUnixAddressMissingScheme",
"/var/run/example.sock",
&Address{true, true, 0, &url.URL{Scheme: AddressSchemeUnix, Path: "/var/run/example.sock"}},
&Address{true, true, -1, 0, &url.URL{Scheme: AddressSchemeUnix, Path: "/var/run/example.sock"}},
"/var/run/example.sock",
"unix:///var/run/example.sock",
"",
@ -52,15 +53,23 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldParseAddressMissingPort",
"tcp://0.0.0.0",
&Address{true, false, 0, &url.URL{Scheme: AddressSchemeTCP, Host: "0.0.0.0:0"}},
&Address{true, false, -1, 0, &url.URL{Scheme: AddressSchemeTCP, Host: "0.0.0.0:0"}},
"0.0.0.0:0",
"tcp://0.0.0.0:0",
"",
},
{
"ShouldNotParseAddressWithQuery",
"tcp://0.0.0.0?umask=0022",
nil,
"0.0.0.0:0",
"tcp://0.0.0.0:0",
"error validating the address: the url 'tcp://0.0.0.0?umask=0022' appears to have a query but this is not valid for addresses with the 'tcp' scheme",
},
{
"ShouldParseUnixSocket",
"unix:///path/to/a/socket.sock",
&Address{true, true, 0, &url.URL{Scheme: AddressSchemeUnix, Path: "/path/to/a/socket.sock"}},
&Address{true, true, -1, 0, &url.URL{Scheme: AddressSchemeUnix, Path: "/path/to/a/socket.sock"}},
"/path/to/a/socket.sock",
"unix:///path/to/a/socket.sock",
"",
@ -82,12 +91,12 @@ func TestNewAddressFromString(t *testing.T) {
"error validating the unix socket address: could not determine path from 'unix://nopath.com'",
},
{
"ShouldNotParseUnixSocketWithQuery",
"unix:///path/to/a/socket.sock?q=yes",
nil,
"ShouldParseUnixSocketWithQuery",
"unix:///path/to/a/socket.sock?umask=0022",
&Address{true, true, 18, 0, &url.URL{Scheme: AddressSchemeUnix, Path: "/path/to/a/socket.sock", RawQuery: "umask=0022"}},
"/path/to/a/socket.sock",
"unix:///path/to/a/socket.sock?umask=0022",
"",
"",
"error validating the address: the url 'unix:///path/to/a/socket.sock?q=yes' appears to have a query but this is not valid for addresses",
},
{
"ShouldNotParseUnixSocketWithFragment",
@ -108,7 +117,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldParseUnknownScheme",
"a://0.0.0.0",
&Address{true, false, 0, &url.URL{Scheme: "a", Host: "0.0.0.0"}},
&Address{true, false, -1, 0, &url.URL{Scheme: "a", Host: "0.0.0.0"}},
"0.0.0.0",
"a://0.0.0.0",
"",
@ -140,7 +149,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldSetDefaultPortLDAP",
"ldap://127.0.0.1",
&Address{true, false, 389, &url.URL{Scheme: AddressSchemeLDAP, Host: "127.0.0.1:389"}},
&Address{true, false, -1, 389, &url.URL{Scheme: AddressSchemeLDAP, Host: "127.0.0.1:389"}},
"127.0.0.1:389",
"ldap://127.0.0.1:389",
"",
@ -148,7 +157,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldSetDefaultPortLDAPS",
"ldaps://127.0.0.1",
&Address{true, false, 636, &url.URL{Scheme: AddressSchemeLDAPS, Host: "127.0.0.1:636"}},
&Address{true, false, -1, 636, &url.URL{Scheme: AddressSchemeLDAPS, Host: "127.0.0.1:636"}},
"127.0.0.1:636",
"ldaps://127.0.0.1:636",
"",
@ -156,7 +165,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldAllowLDAPI",
"ldapi:///abc",
&Address{true, true, 0, &url.URL{Scheme: AddressSchemeLDAPI, Path: "/abc"}},
&Address{true, true, -1, 0, &url.URL{Scheme: AddressSchemeLDAPI, Path: "/abc"}},
"/abc",
"ldapi:///abc",
"",
@ -164,7 +173,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldAllowImplicitLDAPI",
"ldapi://",
&Address{true, true, 0, &url.URL{Scheme: AddressSchemeLDAPI, Path: ""}},
&Address{true, true, -1, 0, &url.URL{Scheme: AddressSchemeLDAPI, Path: ""}},
"",
"ldapi:",
"",
@ -172,7 +181,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldAllowImplicitLDAPINoSlash",
"ldapi:",
&Address{true, true, 0, &url.URL{Scheme: AddressSchemeLDAPI, Path: ""}},
&Address{true, true, -1, 0, &url.URL{Scheme: AddressSchemeLDAPI, Path: ""}},
"",
"ldapi:",
"",
@ -180,7 +189,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldSetDefaultPortSMTP",
"smtp://127.0.0.1",
&Address{true, false, 25, &url.URL{Scheme: AddressSchemeSMTP, Host: "127.0.0.1:25"}},
&Address{true, false, -1, 25, &url.URL{Scheme: AddressSchemeSMTP, Host: "127.0.0.1:25"}},
"127.0.0.1:25",
"smtp://127.0.0.1:25",
"",
@ -188,7 +197,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldSetDefaultPortSUBMISSION",
"submission://127.0.0.1",
&Address{true, false, 587, &url.URL{Scheme: AddressSchemeSUBMISSION, Host: "127.0.0.1:587"}},
&Address{true, false, -1, 587, &url.URL{Scheme: AddressSchemeSUBMISSION, Host: "127.0.0.1:587"}},
"127.0.0.1:587",
"submission://127.0.0.1:587",
"",
@ -196,7 +205,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldSetDefaultPortSUBMISSIONS",
"submissions://127.0.0.1",
&Address{true, false, 465, &url.URL{Scheme: AddressSchemeSUBMISSIONS, Host: "127.0.0.1:465"}},
&Address{true, false, -1, 465, &url.URL{Scheme: AddressSchemeSUBMISSIONS, Host: "127.0.0.1:465"}},
"127.0.0.1:465",
"submissions://127.0.0.1:465",
"",
@ -204,7 +213,7 @@ func TestNewAddressFromString(t *testing.T) {
{
"ShouldNotOverridePort",
"ldap://127.0.0.1:123",
&Address{true, false, 123, &url.URL{Scheme: AddressSchemeLDAP, Host: "127.0.0.1:123"}},
&Address{true, false, -1, 123, &url.URL{Scheme: AddressSchemeLDAP, Host: "127.0.0.1:123"}},
"127.0.0.1:123",
"ldap://127.0.0.1:123",
"",
@ -239,7 +248,7 @@ func TestAddress_ValidateErrors(t *testing.T) {
}{
{
"ShouldValidateLDAPAddress",
&Address{true, false, 0, &url.URL{Scheme: AddressSchemeLDAP, Host: "127.0.0.1"}},
&Address{true, false, -1, 0, &url.URL{Scheme: AddressSchemeLDAP, Host: "127.0.0.1"}},
"",
"scheme must be one of 'smtp', 'submission', or 'submissions' but is configured as 'ldap'",
"scheme must be one of 'tcp', 'tcp4', 'tcp6', or 'unix' but is configured as 'ldap'",
@ -248,7 +257,7 @@ func TestAddress_ValidateErrors(t *testing.T) {
},
{
"ShouldValidateSMTPAddress",
&Address{true, false, 0, &url.URL{Scheme: AddressSchemeSMTP, Host: "127.0.0.1"}},
&Address{true, false, -1, 0, &url.URL{Scheme: AddressSchemeSMTP, Host: "127.0.0.1"}},
"scheme must be one of 'ldap', 'ldaps', or 'ldapi' but is configured as 'smtp'",
"",
"scheme must be one of 'tcp', 'tcp4', 'tcp6', or 'unix' but is configured as 'smtp'",
@ -257,7 +266,7 @@ func TestAddress_ValidateErrors(t *testing.T) {
},
{
"ShouldValidateTCPAddress",
&Address{true, false, 0, &url.URL{Scheme: AddressSchemeTCP, Host: "127.0.0.1"}},
&Address{true, false, -1, 0, &url.URL{Scheme: AddressSchemeTCP, Host: "127.0.0.1"}},
"scheme must be one of 'ldap', 'ldaps', or 'ldapi' but is configured as 'tcp'",
"scheme must be one of 'smtp', 'submission', or 'submissions' but is configured as 'tcp'",
"",
@ -266,7 +275,7 @@ func TestAddress_ValidateErrors(t *testing.T) {
},
{
"ShouldValidateUnixSocket",
&Address{true, true, 0, &url.URL{Scheme: AddressSchemeUnix, Path: "/path/to/socket"}},
&Address{true, true, -1, 0, &url.URL{Scheme: AddressSchemeUnix, Path: "/path/to/socket"}},
"scheme must be one of 'ldap', 'ldaps', or 'ldapi' but is configured as 'unix'",
"scheme must be one of 'smtp', 'submission', or 'submissions' but is configured as 'unix'",
"",
@ -311,7 +320,7 @@ func TestAddress_ValidateErrors(t *testing.T) {
}
func TestAddress_SetHostname(t *testing.T) {
address := &Address{true, false, 0, &url.URL{Scheme: AddressSchemeTCP, Host: "0.0.0.0"}}
address := &Address{true, false, -1, 0, &url.URL{Scheme: AddressSchemeTCP, Host: "0.0.0.0"}}
assert.Equal(t, "tcp://0.0.0.0", address.String())
@ -320,32 +329,6 @@ func TestAddress_SetHostname(t *testing.T) {
assert.Equal(t, "tcp://127.0.0.1", address.String())
}
func TestAddress_ListenerWithUMask(t *testing.T) {
dir := t.TempDir()
address := &Address{true, true, 0, &url.URL{Scheme: AddressSchemeUnix, Path: filepath.Join(dir, "example.sock")}}
ln, err := address.ListenerWithUMask(600)
assert.NotNil(t, ln)
assert.NoError(t, err)
assert.NoError(t, ln.Close())
address = &Address{true, true, 0, nil}
ln, err = address.ListenerWithUMask(600)
assert.Nil(t, ln)
assert.EqualError(t, err, "address url is nil")
address = &Address{true, false, 0, nil}
ln, err = address.ListenerWithUMask(600)
assert.Nil(t, ln)
assert.EqualError(t, err, "address url is nil")
}
func TestAddressOutputValues(t *testing.T) {
var (
address *Address
@ -356,7 +339,7 @@ func TestAddressOutputValues(t *testing.T) {
address = &Address{}
assert.EqualError(t, address.validate(), "error validating the address: address url was nil")
address = &Address{false, false, 0, nil}
address = &Address{false, false, -1, 0, nil}
assert.Equal(t, "", address.String())
assert.Equal(t, "", address.Scheme())
@ -370,7 +353,7 @@ func TestAddressOutputValues(t *testing.T) {
assert.Nil(t, listener)
assert.EqualError(t, err, "address url is nil")
address = &Address{true, false, 8080, &url.URL{Scheme: AddressSchemeTCP, Host: "0.0.0.0:8080"}}
address = &Address{true, false, -1, 8080, &url.URL{Scheme: AddressSchemeTCP, Host: "0.0.0.0:8080"}}
assert.Equal(t, "tcp://0.0.0.0:8080", address.String())
assert.Equal(t, "tcp", address.Scheme())
@ -384,7 +367,7 @@ func TestAddressOutputValues(t *testing.T) {
assert.NotNil(t, listener)
assert.NoError(t, err)
address = &Address{true, false, 0, nil}
address = &Address{true, false, -1, 0, nil}
assert.Equal(t, "", address.String())
assert.Equal(t, "", address.Scheme())
@ -413,7 +396,7 @@ func TestAddressOutputValues(t *testing.T) {
assert.Nil(t, listener)
assert.EqualError(t, err, "address url is nil")
address = &Address{true, false, 9091, &url.URL{Scheme: AddressSchemeTCP, Host: "0.0.0.0:9091"}}
address = &Address{true, false, -1, 9091, &url.URL{Scheme: AddressSchemeTCP, Host: "0.0.0.0:9091"}}
assert.Equal(t, "tcp://0.0.0.0:9091", address.String())
assert.Equal(t, "tcp", address.Scheme())
@ -570,6 +553,132 @@ func TestNewSMTPAddress(t *testing.T) {
}
}
func TestAddress_Dial(t *testing.T) {
testCases := []struct {
name string
have Address
success bool
err string
}{
{
"ShouldNotDialNil",
Address{true, false, -1, 0, nil},
false,
"address url is nil",
},
{
"ShouldNotDialInvalid",
Address{false, false, -1, 0, &url.URL{}},
false,
"address url is nil",
},
{
"ShouldNotDialInvalidAddress",
Address{true, false, -1, 0, &url.URL{Scheme: "abc", Host: "127.0.0.1:0"}},
false,
"dial tcp 127.0.0.1:0: connect: connection refused",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
conn, err := tc.have.Dial()
defer func(c net.Conn) {
if c == nil {
return
}
conn.Close()
}(conn)
if tc.success {
} else {
assert.Nil(t, conn)
if tc.err != "" {
assert.EqualError(t, err, tc.err)
} else {
assert.NotNil(t, err)
}
}
})
}
}
func TestAddress_UnixDomainSocket(t *testing.T) {
dir := t.TempDir()
testCases := []struct {
name string
have string
socket bool
path string
strUmask string
umask int
err string
}{
{
"ShouldNotBeSocket",
"tcp://:9091",
false,
"",
"",
-1,
"",
},
{
"ShouldParseSocket",
fmt.Sprintf("unix://%s", filepath.Join(dir, "example.sock")),
true,
filepath.Join(dir, "example.sock"),
"",
-1,
"",
},
{
"ShouldParseSocketWithUmask",
fmt.Sprintf("unix://%s?umask=0022", filepath.Join(dir, "example.sock")),
true,
filepath.Join(dir, "example.sock"),
"0022",
18,
"",
},
{
"ShouldParseSocketWithBadUmask",
fmt.Sprintf("unix://%s?umask=abc", filepath.Join(dir, "example.sock")),
true,
"",
"",
-1,
fmt.Sprintf("error validating the unix socket address: could not parse address 'unix://%s?umask=abc': the address has a umask value of 'abc' which does not appear to be a valid octal string", filepath.Join(dir, "example.sock")),
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actual, err := NewAddress(tc.have)
if tc.err == "" {
assert.Equal(t, tc.socket, actual.IsUnixDomainSocket())
assert.Equal(t, tc.path, actual.Path())
assert.Equal(t, tc.strUmask, actual.Umask())
assert.Equal(t, tc.umask, actual.umask)
ln, err := actual.Listener()
assert.NoError(t, err)
assert.NotNil(t, ln)
assert.NoError(t, ln.Close())
} else {
assert.EqualError(t, err, tc.err)
}
})
}
}
func TestAddress_SocketHostname(t *testing.T) {
testCases := []struct {
name string
@ -578,22 +687,22 @@ func TestAddress_SocketHostname(t *testing.T) {
}{
{
"ShouldReturnHostname",
Address{true, false, 80, &url.URL{Scheme: AddressSchemeTCP, Host: "examplea:80"}},
Address{true, false, -1, 80, &url.URL{Scheme: AddressSchemeTCP, Host: "examplea:80"}},
"examplea",
},
{
"ShouldReturnPath",
Address{true, true, 80, &url.URL{Scheme: AddressSchemeUnix, Path: "/abc/123"}},
Address{true, true, -1, 80, &url.URL{Scheme: AddressSchemeUnix, Path: "/abc/123"}},
"/abc/123",
},
{
"ShouldReturnNothing",
Address{false, true, 80, &url.URL{Scheme: AddressSchemeUnix, Path: "/abc/123"}},
Address{false, true, -1, 80, &url.URL{Scheme: AddressSchemeUnix, Path: "/abc/123"}},
"",
},
{
"ShouldReturnNothingNil",
Address{true, true, 80, nil},
Address{true, true, -1, 80, nil},
"",
},
}
@ -605,6 +714,41 @@ func TestAddress_SocketHostname(t *testing.T) {
}
}
func TestAddress_Path(t *testing.T) {
testCases := []struct {
name string
have Address
expected string
}{
{
"ShouldReturnEmptyPath",
Address{true, false, -1, 80, &url.URL{Scheme: AddressSchemeTCP, Host: "tcphosta"}},
"",
},
{
"ShouldReturnPath",
Address{true, false, -1, 80, &url.URL{Scheme: AddressSchemeTCP, Host: "tcphosta", Path: "/apath"}},
"/apath",
},
{
"ShouldNotReturnPathInvalid",
Address{false, false, -1, 80, &url.URL{Scheme: AddressSchemeTCP, Host: "tcphosta", Path: "/apath"}},
"",
},
{
"ShouldNotReturnPathNil",
Address{true, false, -1, 80, nil},
"",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
assert.Equal(t, tc.expected, tc.have.Path())
})
}
}
func TestAddress_IsTCP_IsUDP(t *testing.T) {
testCases := []struct {
name string
@ -614,49 +758,49 @@ func TestAddress_IsTCP_IsUDP(t *testing.T) {
}{
{
"ShouldReturnTrueTCP",
Address{true, false, 80, &url.URL{Scheme: AddressSchemeTCP, Host: "tcphosta"}},
Address{true, false, -1, 80, &url.URL{Scheme: AddressSchemeTCP, Host: "tcphosta"}},
true,
false,
},
{
"ShouldReturnTrueTCP4",
Address{true, false, 80, &url.URL{Scheme: AddressSchemeTCP4, Host: "tcphostb"}},
Address{true, false, -1, 80, &url.URL{Scheme: AddressSchemeTCP4, Host: "tcphostb"}},
true,
false,
},
{
"ShouldReturnTrueTCP6",
Address{true, false, 80, &url.URL{Scheme: AddressSchemeTCP6, Host: "tcphostc"}},
Address{true, false, -1, 80, &url.URL{Scheme: AddressSchemeTCP6, Host: "tcphostc"}},
true,
false,
},
{
"ShouldReturnFalseUDP",
Address{true, false, 80, &url.URL{Scheme: AddressSchemeUDP, Host: "tcphostd"}},
Address{true, false, -1, 80, &url.URL{Scheme: AddressSchemeUDP, Host: "tcphostd"}},
false,
true,
},
{
"ShouldReturnFalseUDP4",
Address{true, false, 80, &url.URL{Scheme: AddressSchemeUDP4, Host: "tcphoste"}},
Address{true, false, -1, 80, &url.URL{Scheme: AddressSchemeUDP4, Host: "tcphoste"}},
false,
true,
},
{
"ShouldReturnFalseUDP6",
Address{true, false, 80, &url.URL{Scheme: AddressSchemeUDP6, Host: "tcphostf"}},
Address{true, false, -1, 80, &url.URL{Scheme: AddressSchemeUDP6, Host: "tcphostf"}},
false,
true,
},
{
"ShouldReturnFalseSMTP",
Address{true, false, 80, &url.URL{Scheme: AddressSchemeSMTP, Host: "tcphostg"}},
Address{true, false, -1, 80, &url.URL{Scheme: AddressSchemeSMTP, Host: "tcphostg"}},
false,
false,
},
{
"ShouldReturnFalseUnix",
Address{true, true, 80, &url.URL{Scheme: AddressSchemeUnix, Host: "tcphosth"}},
Address{true, true, -1, 80, &url.URL{Scheme: AddressSchemeUnix, Host: "tcphosth"}},
false,
false,
},

View File

@ -37,14 +37,7 @@ func CreateDefaultServer(config *schema.Configuration, providers middlewares.Pro
connectionScheme = schemeHTTP
)
switch config.Server.UMask {
case nil:
listener, err = config.Server.Address.Listener()
default:
listener, err = config.Server.Address.ListenerWithUMask(*config.Server.UMask)
}
if err != nil {
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)
}
@ -109,14 +102,7 @@ func CreateMetricsServer(config *schema.Configuration, providers middlewares.Pro
Logger: logging.LoggerPrintf(logrus.DebugLevel),
}
switch config.Telemetry.Metrics.UMask {
case nil:
listener, err = config.Telemetry.Metrics.Address.Listener()
default:
listener, err = config.Telemetry.Metrics.Address.ListenerWithUMask(*config.Telemetry.Metrics.UMask)
}
if err != nil {
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)
}