summaryrefslogtreecommitdiff
path: root/internal/storage
diff options
context:
space:
mode:
authorJames Elliott <james-d-elliott@users.noreply.github.com>2024-12-30 17:59:36 +1100
committerGitHub <noreply@github.com>2024-12-30 06:59:36 +0000
commit31565e447ba1e357828c99db5410de879bfd7669 (patch)
tree7683ef81e1372f5cc686677670dfe5d8814951e0 /internal/storage
parent29b582e1735aff6baabf503c0a2dee533fc41ebe (diff)
fix(configuration): allow unix socket ports (#8520)
This allows unix sockets to include ports in the address URL. In addition allows for a absolute path for the PostgreSQL socket type. Both options are only used by PostgreSQL but other unix sockets will not expressly error if this is included. Fixes #8509
Diffstat (limited to 'internal/storage')
-rw-r--r--internal/storage/const.go3
-rw-r--r--internal/storage/sql_provider_backend_postgres.go55
-rw-r--r--internal/storage/sql_provider_backend_postgres_test.go305
3 files changed, 349 insertions, 14 deletions
diff --git a/internal/storage/const.go b/internal/storage/const.go
index 907842b89..84066fa23 100644
--- a/internal/storage/const.go
+++ b/internal/storage/const.go
@@ -70,7 +70,8 @@ const (
)
var (
- reMigration = regexp.MustCompile(`^V(?P<Version>\d{4})\.(?P<Name>[^.]+)\.(?P<Direction>(up|down))\.sql$`)
+ reMigration = regexp.MustCompile(`^V(?P<Version>\d{4})\.(?P<Name>[^.]+)\.(?P<Direction>(up|down))\.sql$`)
+ rePostgreSQLUnixDomainSocket = regexp.MustCompile(`^\.s\.PGSQL\.(\d+)$`)
)
const (
diff --git a/internal/storage/sql_provider_backend_postgres.go b/internal/storage/sql_provider_backend_postgres.go
index 41dd83db0..2886d387e 100644
--- a/internal/storage/sql_provider_backend_postgres.go
+++ b/internal/storage/sql_provider_backend_postgres.go
@@ -3,9 +3,12 @@ package storage
import (
"crypto/tls"
"crypto/x509"
+ "encoding/pem"
"errors"
"fmt"
"os"
+ "path/filepath"
+ "strconv"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/stdlib"
@@ -153,8 +156,7 @@ func NewPostgreSQLProvider(config *schema.Configuration, caCertPool *x509.CertPo
func dsnPostgreSQL(config *schema.StoragePostgreSQL, globalCACertPool *x509.CertPool) (dsn string) {
dsnConfig, _ := pgx.ParseConfig("")
- dsnConfig.Host = config.Address.SocketHostname()
- dsnConfig.Port = config.Address.Port()
+ dsnConfig.Host, dsnConfig.Port = dsnPostgreSQLHostPort(config.Address)
dsnConfig.Database = config.Database
dsnConfig.User = config.Username
dsnConfig.Password = config.Password
@@ -164,11 +166,34 @@ func dsnPostgreSQL(config *schema.StoragePostgreSQL, globalCACertPool *x509.Cert
"search_path": config.Schema,
}
- if dsnConfig.Port == 0 && config.Address.IsUnixDomainSocket() {
- dsnConfig.Port = 5432
+ return stdlib.RegisterConnConfig(dsnConfig)
+}
+
+func dsnPostgreSQLHostPort(address *schema.AddressTCP) (host string, port uint16) {
+ if !address.IsUnixDomainSocket() {
+ return address.SocketHostname(), address.Port()
}
- return stdlib.RegisterConnConfig(dsnConfig)
+ host, port = address.SocketHostname(), address.Port()
+
+ if port == 0 {
+ port = 5432
+ }
+
+ dir, base := filepath.Dir(host), filepath.Base(host)
+
+ matches := rePostgreSQLUnixDomainSocket.FindStringSubmatch(base)
+
+ if len(matches) != 2 {
+ return host, port
+ }
+
+ if raw, err := strconv.ParseUint(matches[1], 10, 16); err == nil {
+ host = dir
+ port = uint16(raw)
+ }
+
+ return host, port
}
func loadPostgreSQLTLSConfig(config *schema.StoragePostgreSQL, globalCACertPool *x509.CertPool) (tlsConfig *tls.Config) {
@@ -231,34 +256,38 @@ func loadPostgreSQLLegacyTLSConfigFiles(config *schema.StoragePostgreSQL) (ca *x
)
if config.SSL.RootCertificate != "" {
- var caPEMBlock []byte
+ var (
+ data []byte
+ block *pem.Block
+ )
- if caPEMBlock, err = os.ReadFile(config.SSL.RootCertificate); err != nil {
+ if data, err = os.ReadFile(config.SSL.RootCertificate); err != nil {
return nil, nil
}
- if ca, err = x509.ParseCertificate(caPEMBlock); err != nil {
+ block, _ = pem.Decode(data)
+
+ if ca, err = x509.ParseCertificate(block.Bytes); err != nil {
return nil, nil
}
}
if config.SSL.Certificate != "" && config.SSL.Key != "" {
var (
- keyPEMBlock []byte
- certPEMBlock []byte
+ dataKey, dataCert []byte
)
- if keyPEMBlock, err = os.ReadFile(config.SSL.Key); err != nil {
+ if dataKey, err = os.ReadFile(config.SSL.Key); err != nil {
return nil, nil
}
- if certPEMBlock, err = os.ReadFile(config.SSL.Certificate); err != nil {
+ if dataCert, err = os.ReadFile(config.SSL.Certificate); err != nil {
return nil, nil
}
var cert tls.Certificate
- if cert, err = tls.X509KeyPair(certPEMBlock, keyPEMBlock); err != nil {
+ if cert, err = tls.X509KeyPair(dataCert, dataKey); err != nil {
return nil, nil
}
diff --git a/internal/storage/sql_provider_backend_postgres_test.go b/internal/storage/sql_provider_backend_postgres_test.go
new file mode 100644
index 000000000..4a56c25a1
--- /dev/null
+++ b/internal/storage/sql_provider_backend_postgres_test.go
@@ -0,0 +1,305 @@
+package storage
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/authelia/authelia/v4/internal/configuration/schema"
+)
+
+func TestNewPostgreSQLProvider(t *testing.T) {
+ address, err := schema.NewAddress("tcp://localhost:5432")
+ require.NoError(t, err)
+
+ testCases := []struct {
+ name string
+ have *schema.Configuration
+ }{
+ {
+ "ShouldHandleSimple",
+ &schema.Configuration{
+ Storage: schema.Storage{
+ PostgreSQL: &schema.StoragePostgreSQL{
+ StorageSQL: schema.StorageSQL{
+ Address: &schema.AddressTCP{Address: *address},
+ },
+ },
+ },
+ },
+ },
+ {
+ "ShouldHandleTLS",
+ &schema.Configuration{
+ Storage: schema.Storage{
+ PostgreSQL: &schema.StoragePostgreSQL{
+ StorageSQL: schema.StorageSQL{
+ Address: &schema.AddressTCP{Address: *address},
+ },
+ TLS: &schema.TLS{
+ MinimumVersion: schema.TLSVersion{Value: tls.VersionTLS12},
+ MaximumVersion: schema.TLSVersion{Value: tls.VersionTLS13},
+ },
+ },
+ },
+ },
+ },
+ {
+ "ShouldHandleLegacyTLSVerifyFull",
+ &schema.Configuration{
+ Storage: schema.Storage{
+ PostgreSQL: &schema.StoragePostgreSQL{
+ StorageSQL: schema.StorageSQL{
+ Address: &schema.AddressTCP{Address: *address},
+ },
+ SSL: &schema.StoragePostgreSQLSSL{
+ Mode: "verify-full",
+ },
+ },
+ },
+ },
+ },
+ {
+ "ShouldHandleLegacyTLSVerifyCA",
+ &schema.Configuration{
+ Storage: schema.Storage{
+ PostgreSQL: &schema.StoragePostgreSQL{
+ StorageSQL: schema.StorageSQL{
+ Address: &schema.AddressTCP{Address: *address},
+ },
+ SSL: &schema.StoragePostgreSQLSSL{
+ Mode: "verify-ca",
+ },
+ },
+ },
+ },
+ },
+ {
+ "ShouldHandleLegacyTLSRequire",
+ &schema.Configuration{
+ Storage: schema.Storage{
+ PostgreSQL: &schema.StoragePostgreSQL{
+ StorageSQL: schema.StorageSQL{
+ Address: &schema.AddressTCP{Address: *address},
+ },
+ SSL: &schema.StoragePostgreSQLSSL{
+ Mode: "require",
+ },
+ },
+ },
+ },
+ },
+ {
+ "ShouldHandleLegacyTLSDisabled",
+ &schema.Configuration{
+ Storage: schema.Storage{
+ PostgreSQL: &schema.StoragePostgreSQL{
+ StorageSQL: schema.StorageSQL{
+ Address: &schema.AddressTCP{Address: *address},
+ },
+ SSL: &schema.StoragePostgreSQLSSL{
+ Mode: "disable",
+ },
+ },
+ },
+ },
+ },
+ {
+ "ShouldHandleLegacyTLSVerifyCARootCA",
+ &schema.Configuration{
+ Storage: schema.Storage{
+ PostgreSQL: &schema.StoragePostgreSQL{
+ StorageSQL: schema.StorageSQL{
+ Address: &schema.AddressTCP{Address: *address},
+ },
+ SSL: &schema.StoragePostgreSQLSSL{
+ Mode: "verify-ca",
+ RootCertificate: "../configuration/test_resources/crypto/ca.rsa.2048.crt",
+ },
+ },
+ },
+ },
+ },
+ {
+ "ShouldHandleLegacyTLSVerifyCAAllCertificates",
+ &schema.Configuration{
+ Storage: schema.Storage{
+ PostgreSQL: &schema.StoragePostgreSQL{
+ StorageSQL: schema.StorageSQL{
+ Address: &schema.AddressTCP{Address: *address},
+ },
+ SSL: &schema.StoragePostgreSQLSSL{
+ Mode: "verify-ca",
+ RootCertificate: "../configuration/test_resources/crypto/ca.rsa.2048.crt",
+ Certificate: "../configuration/test_resources/crypto/rsa.2048.crt",
+ Key: "../configuration/test_resources/crypto/rsa.2048.pem",
+ },
+ },
+ },
+ },
+ },
+ {
+ "ShouldHandleLegacyTLSVerifyCAAllCertificatesFailReadFileCA",
+ &schema.Configuration{
+ Storage: schema.Storage{
+ PostgreSQL: &schema.StoragePostgreSQL{
+ StorageSQL: schema.StorageSQL{
+ Address: &schema.AddressTCP{Address: *address},
+ },
+ SSL: &schema.StoragePostgreSQLSSL{
+ Mode: "verify-ca",
+ RootCertificate: "../configuration/test_resources/crypto/ca.rsa.2048.cert",
+ Certificate: "../configuration/test_resources/crypto/rsa.2048.crt",
+ Key: "../configuration/test_resources/crypto/rsa.2048.pem",
+ },
+ },
+ },
+ },
+ },
+ {
+ "ShouldHandleLegacyTLSVerifyCAAllCertificatesFailReadFileKey",
+ &schema.Configuration{
+ Storage: schema.Storage{
+ PostgreSQL: &schema.StoragePostgreSQL{
+ StorageSQL: schema.StorageSQL{
+ Address: &schema.AddressTCP{Address: *address},
+ },
+ SSL: &schema.StoragePostgreSQLSSL{
+ Mode: "verify-ca",
+ RootCertificate: "../configuration/test_resources/crypto/ca.rsa.2048.crt",
+ Certificate: "../configuration/test_resources/crypto/rsa.2048.crt",
+ Key: "../configuration/test_resources/crypto/rsa.2048.key",
+ },
+ },
+ },
+ },
+ },
+ {
+ "ShouldHandleLegacyTLSVerifyCAAllCertificatesFailReadFileCertificate",
+ &schema.Configuration{
+ Storage: schema.Storage{
+ PostgreSQL: &schema.StoragePostgreSQL{
+ StorageSQL: schema.StorageSQL{
+ Address: &schema.AddressTCP{Address: *address},
+ },
+ SSL: &schema.StoragePostgreSQLSSL{
+ Mode: "verify-ca",
+ RootCertificate: "../configuration/test_resources/crypto/ca.rsa.2048.crt",
+ Certificate: "../configuration/test_resources/crypto/rsa.2048.cert",
+ Key: "../configuration/test_resources/crypto/rsa.2048.pem",
+ },
+ },
+ },
+ },
+ },
+ {
+ "ShouldHandleLegacyTLSVerifyCAAllCertificatesFailPair",
+ &schema.Configuration{
+ Storage: schema.Storage{
+ PostgreSQL: &schema.StoragePostgreSQL{
+ StorageSQL: schema.StorageSQL{
+ Address: &schema.AddressTCP{Address: *address},
+ },
+ SSL: &schema.StoragePostgreSQLSSL{
+ Mode: "verify-ca",
+ RootCertificate: "../configuration/test_resources/crypto/ca.rsa.2048.crt",
+ Certificate: "../configuration/test_resources/crypto/rsa.2048.crt",
+ Key: "../configuration/test_resources/crypto/rsa.4096.pem",
+ },
+ },
+ },
+ },
+ },
+ {
+ "ShouldHandleLegacyTLSVerifyCAAllCertificatesFailReadCACertificateFromPrivateKey",
+ &schema.Configuration{
+ Storage: schema.Storage{
+ PostgreSQL: &schema.StoragePostgreSQL{
+ StorageSQL: schema.StorageSQL{
+ Address: &schema.AddressTCP{Address: *address},
+ },
+ SSL: &schema.StoragePostgreSQLSSL{
+ Mode: "verify-ca",
+ RootCertificate: "../configuration/test_resources/crypto/ca.rsa.2048.pem",
+ Certificate: "../configuration/test_resources/crypto/rsa.2048.crt",
+ Key: "../configuration/test_resources/crypto/rsa.2048.pem",
+ },
+ },
+ },
+ },
+ },
+ }
+
+ t.Parallel()
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ provider := NewPostgreSQLProvider(tc.have, x509.NewCertPool())
+
+ assert.NotNil(t, provider)
+ })
+ }
+}
+
+func TestDSNConfigPostgreSQLHostPort(t *testing.T) {
+ testCases := []struct {
+ name string
+ have string
+ hexpected string
+ pexpected uint16
+ }{
+ {
+ "ShouldParseDirectoryDefaultPort",
+ "unix:///tmp",
+ "/tmp",
+ 5432,
+ },
+ {
+ "ShouldParseURLPort",
+ "unix://:255/tmp",
+ "/tmp",
+ 255,
+ },
+ {
+ "ShouldParseAbsolutePort",
+ "unix:///tmp/.s.PGSQL.25432",
+ "/tmp",
+ 25432,
+ },
+ {
+ "ShouldParseAbsolutePortWithURLPort",
+ "unix://:2455/tmp/.s.PGSQL.25432",
+ "/tmp",
+ 25432,
+ },
+ {
+ "ShouldParseAbsolutePortInvalidWithURLPort",
+ "unix://:2455/tmp/.s.PGSQL.233335432",
+ "/tmp/.s.PGSQL.233335432",
+ 2455,
+ },
+ {
+ "ShouldParseAbsolutePortInvalid",
+ "unix:///tmp/.s.PGSQL.233335432",
+ "/tmp/.s.PGSQL.233335432",
+ 5432,
+ },
+ }
+
+ t.Parallel()
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ address, err := schema.NewAddress(tc.have)
+ require.NotNil(t, address)
+ require.NoError(t, err)
+
+ host, port := dsnPostgreSQLHostPort(&schema.AddressTCP{Address: *address})
+ assert.Equal(t, tc.hexpected, host)
+ assert.Equal(t, tc.pexpected, port)
+ })
+ }
+}