type: string
@@ -96,7 +118,9 @@ required: no
The SQL connection timeout.
-### sslmode
+### ssl
+
+#### mode
type: string
{: .label .label-config .label-purple }
@@ -111,3 +135,33 @@ Valid options are 'disable', 'require', 'verify-ca', or 'verify-full'.
See the [PostgreSQL Documentation](https://www.postgresql.org/docs/12/libpq-ssl.html)
or [pgx - PostgreSQL Driver and Toolkit Documentation](https://pkg.go.dev/github.com/jackc/pgx?tab=doc)
for more information.
+
+#### root_certificate
+
+type: string
+{: .label .label-config .label-purple }
+required: no
+{: .label .label-config .label-green }
+
+
+The optional location of the root certificate file encoded in the PEM format for validation purposes.
+
+#### certificate
+
+type: string
+{: .label .label-config .label-purple }
+required: no
+{: .label .label-config .label-green }
+
+
+The optional location of the certificate file encoded in the PEM format for validation purposes.
+
+#### key
+
+type: string
+{: .label .label-config .label-purple }
+required: no
+{: .label .label-config .label-green }
+
+
+The optional location of the key file encoded in the PEM format for authentication purposes.
diff --git a/internal/commands/storage.go b/internal/commands/storage.go
index df1250077..1ac7c1317 100644
--- a/internal/commands/storage.go
+++ b/internal/commands/storage.go
@@ -28,8 +28,13 @@ func NewStorageCmd() (cmd *cobra.Command) {
cmd.PersistentFlags().String("postgres.host", "", "the PostgreSQL hostname")
cmd.PersistentFlags().Int("postgres.port", 5432, "the PostgreSQL port")
cmd.PersistentFlags().String("postgres.database", "authelia", "the PostgreSQL database name")
+ cmd.PersistentFlags().String("postgres.schema", "public", "the PostgreSQL schema name")
cmd.PersistentFlags().String("postgres.username", "authelia", "the PostgreSQL username")
cmd.PersistentFlags().String("postgres.password", "", "the PostgreSQL password")
+ cmd.PersistentFlags().String("postgres.ssl.mode", "disable", "the PostgreSQL ssl mode")
+ cmd.PersistentFlags().String("postgres.ssl.root_certificate", "", "the PostgreSQL ssl root certificate file location")
+ cmd.PersistentFlags().String("postgres.ssl.certificate", "", "the PostgreSQL ssl certificate file location")
+ cmd.PersistentFlags().String("postgres.ssl.key", "", "the PostgreSQL ssl key file location")
cmd.AddCommand(
newStorageMigrateCmd(),
diff --git a/internal/commands/storage_run.go b/internal/commands/storage_run.go
index c24a7f679..87a382051 100644
--- a/internal/commands/storage_run.go
+++ b/internal/commands/storage_run.go
@@ -40,23 +40,30 @@ func storagePersistentPreRunE(cmd *cobra.Command, _ []string) (err error) {
}
mapping := map[string]string{
- "encryption-key": "storage.encryption_key",
- "sqlite.path": "storage.local.path",
- "mysql.host": "storage.mysql.host",
- "mysql.port": "storage.mysql.port",
- "mysql.database": "storage.mysql.database",
- "mysql.username": "storage.mysql.username",
- "mysql.password": "storage.mysql.password",
- "postgres.host": "storage.postgres.host",
- "postgres.port": "storage.postgres.port",
- "postgres.database": "storage.postgres.database",
- "postgres.username": "storage.postgres.username",
- "postgres.password": "storage.postgres.password",
- "postgres.schema": "storage.postgres.schema",
- "period": "totp.period",
- "digits": "totp.digits",
- "algorithm": "totp.algorithm",
- "issuer": "totp.issuer",
+ "encryption-key": "storage.encryption_key",
+ "sqlite.path": "storage.local.path",
+
+ "mysql.host": "storage.mysql.host",
+ "mysql.port": "storage.mysql.port",
+ "mysql.database": "storage.mysql.database",
+ "mysql.username": "storage.mysql.username",
+ "mysql.password": "storage.mysql.password",
+
+ "postgres.host": "storage.postgres.host",
+ "postgres.port": "storage.postgres.port",
+ "postgres.database": "storage.postgres.database",
+ "postgres.schema": "storage.postgres.schema",
+ "postgres.username": "storage.postgres.username",
+ "postgres.password": "storage.postgres.password",
+ "postgres.ssl.mode": "storage.postgres.ssl.mode",
+ "postgres.ssl.root_certificate": "storage.postgres.ssl.root_certificate",
+ "postgres.ssl.certificate": "storage.postgres.ssl.certificate",
+ "postgres.ssl.key": "storage.postgres.ssl.key",
+
+ "period": "totp.period",
+ "digits": "totp.digits",
+ "algorithm": "totp.algorithm",
+ "issuer": "totp.issuer",
}
sources = append(sources, configuration.NewEnvironmentSource(configuration.DefaultEnvPrefix, configuration.DefaultEnvDelimiter))
diff --git a/internal/configuration/config.template.yml b/internal/configuration/config.template.yml
index 471cd1478..e94f8ae16 100644
--- a/internal/configuration/config.template.yml
+++ b/internal/configuration/config.template.yml
@@ -556,11 +556,16 @@ storage:
# host: 127.0.0.1
# port: 5432
# database: authelia
+ # schema: public
# username: authelia
# ## Password can also be set using a secret: https://www.authelia.com/docs/configuration/secrets.html
# password: mypassword
# timeout: 5s
- # sslmode: disable
+ # ssl:
+ # mode: disable
+ # root_certificate: disable
+ # certificate: disable
+ # key: disable
##
## Notification Provider
diff --git a/internal/configuration/schema/storage.go b/internal/configuration/schema/storage.go
index 831872eb6..f806fd3ef 100644
--- a/internal/configuration/schema/storage.go
+++ b/internal/configuration/schema/storage.go
@@ -22,10 +22,23 @@ type MySQLStorageConfiguration struct {
SQLStorageConfiguration `koanf:",squash"`
}
-// PostgreSQLStorageConfiguration represents the configuration of a Postgres database.
+// PostgreSQLStorageConfiguration represents the configuration of a PostgreSQL database.
type PostgreSQLStorageConfiguration struct {
SQLStorageConfiguration `koanf:",squash"`
- SSLMode string `koanf:"sslmode"`
+ Schema string `koanf:"schema"`
+
+ SSL PostgreSQLSSLStorageConfiguration `koanf:"ssl"`
+
+ // Deprecated. TODO: Remove in v4.36.0.
+ SSLMode string `koanf:"sslmode"`
+}
+
+// PostgreSQLSSLStorageConfiguration represents the SSL configuration of a PostgreSQL database.
+type PostgreSQLSSLStorageConfiguration struct {
+ Mode string `koanf:"mode"`
+ RootCertificate string `koanf:"root_certificate"`
+ Certificate string `koanf:"certificate"`
+ Key string `koanf:"key"`
}
// StorageConfiguration represents the configuration of the storage backend.
@@ -37,16 +50,7 @@ type StorageConfiguration struct {
EncryptionKey string `koanf:"encryption_key"`
}
-// DefaultPostgreSQLStorageConfiguration represents the default PostgreSQL configuration.
-var DefaultPostgreSQLStorageConfiguration = PostgreSQLStorageConfiguration{
- SQLStorageConfiguration: SQLStorageConfiguration{
- Timeout: 5 * time.Second,
- },
-}
-
-// DefaultMySQLStorageConfiguration represents the default MySQL configuration.
-var DefaultMySQLStorageConfiguration = MySQLStorageConfiguration{
- SQLStorageConfiguration: SQLStorageConfiguration{
- Timeout: 5 * time.Second,
- },
+// DefaultSQLStorageConfiguration represents the default SQL configuration.
+var DefaultSQLStorageConfiguration = SQLStorageConfiguration{
+ Timeout: 5 * time.Second,
}
diff --git a/internal/configuration/validator/const.go b/internal/configuration/validator/const.go
index 8c9900ab0..ab0a04f98 100644
--- a/internal/configuration/validator/const.go
+++ b/internal/configuration/validator/const.go
@@ -61,6 +61,18 @@ const (
errFmtTOTPInvalidDigits = "totp: digits '%d' is invalid: must be 6 or 8"
)
+// Storage Error constants.
+const (
+ errStrStorage = "storage: configuration for a 'local', 'mysql' or 'postgres' database must be provided"
+ errStrStorageEncryptionKeyMustBeProvided = "storage: 'encryption_key' configuration option must be provided"
+ errStrStorageEncryptionKeyTooShort = "storage: 'encryption_key' configuration option must be 20 characters or longer"
+ errFmtStorageUserPassMustBeProvided = "storage: %s: 'username' and 'password' configuration options must be provided" //nolint: gosec
+ errFmtStorageOptionMustBeProvided = "storage: %s: '%s' configuration option must be provided"
+ errFmtStoragePostgreSQLInvalidSSLMode = "storage: postgres: ssl: 'mode' configuration option '%s' is invalid: must be one of '%s'"
+)
+
+var storagePostgreSQLValidSSLModes = []string{testModeDisabled, "require", "verify-ca", "verify-full"}
+
// OpenID Error constants.
const (
errFmtOIDCClientsDuplicateID = "openid connect provider: one or more clients have the same ID"
@@ -235,7 +247,13 @@ var ValidKeys = []string{
"storage.postgres.username",
"storage.postgres.password",
"storage.postgres.timeout",
- "storage.postgres.sslmode",
+ "storage.postgres.schema",
+ "storage.postgres.ssl.mode",
+ "storage.postgres.ssl.root_certificate",
+ "storage.postgres.ssl.certificate",
+ "storage.postgres.ssl.key",
+
+ "storage.postgres.sslmode", // Deprecated. TODO: Remove in v4.36.0.
// FileSystem Notifier Keys.
"notifier.filesystem.filename",
diff --git a/internal/configuration/validator/storage.go b/internal/configuration/validator/storage.go
index b4ab54a2c..0a2c69f8b 100644
--- a/internal/configuration/validator/storage.go
+++ b/internal/configuration/validator/storage.go
@@ -2,19 +2,22 @@ package validator
import (
"errors"
+ "fmt"
+ "strings"
"github.com/authelia/authelia/v4/internal/configuration/schema"
+ "github.com/authelia/authelia/v4/internal/utils"
)
// ValidateStorage validates storage configuration.
func ValidateStorage(configuration schema.StorageConfiguration, validator *schema.StructValidator) {
if configuration.Local == nil && configuration.MySQL == nil && configuration.PostgreSQL == nil {
- validator.Push(errors.New("A storage configuration must be provided. It could be 'local', 'mysql' or 'postgres'"))
+ validator.Push(errors.New(errStrStorage))
}
switch {
case configuration.MySQL != nil:
- validateMySQLConfiguration(&configuration.MySQL.SQLStorageConfiguration, validator)
+ validateSQLConfiguration(&configuration.MySQL.SQLStorageConfiguration, validator, "mysql")
case configuration.PostgreSQL != nil:
validatePostgreSQLConfiguration(configuration.PostgreSQL, validator)
case configuration.Local != nil:
@@ -22,45 +25,47 @@ func ValidateStorage(configuration schema.StorageConfiguration, validator *schem
}
if configuration.EncryptionKey == "" {
- validator.Push(errors.New("the configuration option storage.encryption_key must be provided"))
+ validator.Push(errors.New(errStrStorageEncryptionKeyMustBeProvided))
} else if len(configuration.EncryptionKey) < 20 {
- validator.Push(errors.New("the configuration option storage.encryption_key must be 20 characters or longer"))
+ validator.Push(errors.New(errStrStorageEncryptionKeyTooShort))
}
}
-func validateMySQLConfiguration(configuration *schema.SQLStorageConfiguration, validator *schema.StructValidator) {
+func validateSQLConfiguration(configuration *schema.SQLStorageConfiguration, validator *schema.StructValidator, provider string) {
if configuration.Timeout == 0 {
- configuration.Timeout = schema.DefaultMySQLStorageConfiguration.Timeout
+ configuration.Timeout = schema.DefaultSQLStorageConfiguration.Timeout
}
- if configuration.Password == "" || configuration.Username == "" {
- validator.Push(errors.New("the SQL username and password must be provided"))
+ if configuration.Host == "" {
+ validator.Push(fmt.Errorf(errFmtStorageOptionMustBeProvided, provider, "host"))
+ }
+
+ if configuration.Username == "" || configuration.Password == "" {
+ validator.Push(fmt.Errorf(errFmtStorageUserPassMustBeProvided, provider))
}
if configuration.Database == "" {
- validator.Push(errors.New("the SQL database must be provided"))
+ validator.Push(fmt.Errorf(errFmtStorageOptionMustBeProvided, provider, "database"))
}
}
func validatePostgreSQLConfiguration(configuration *schema.PostgreSQLStorageConfiguration, validator *schema.StructValidator) {
- validateMySQLConfiguration(&configuration.SQLStorageConfiguration, validator)
+ validateSQLConfiguration(&configuration.SQLStorageConfiguration, validator, "postgres")
- if configuration.Timeout == 0 {
- configuration.Timeout = schema.DefaultPostgreSQLStorageConfiguration.Timeout
+ // Deprecated. TODO: Remove in v4.36.0.
+ if configuration.SSLMode != "" && configuration.SSL.Mode == "" {
+ configuration.SSL.Mode = configuration.SSLMode
}
- if configuration.SSLMode == "" {
- configuration.SSLMode = testModeDisabled
- }
-
- if !(configuration.SSLMode == testModeDisabled || configuration.SSLMode == "require" ||
- configuration.SSLMode == "verify-ca" || configuration.SSLMode == "verify-full") {
- validator.Push(errors.New("SSL mode must be 'disable', 'require', 'verify-ca', or 'verify-full'"))
+ if configuration.SSL.Mode == "" {
+ configuration.SSL.Mode = testModeDisabled
+ } else if !utils.IsStringInSlice(configuration.SSL.Mode, storagePostgreSQLValidSSLModes) {
+ validator.Push(fmt.Errorf(errFmtStoragePostgreSQLInvalidSSLMode, configuration.SSL.Mode, strings.Join(storagePostgreSQLValidSSLModes, "', '")))
}
}
func validateLocalStorageConfiguration(configuration *schema.LocalStorageConfiguration, validator *schema.StructValidator) {
if configuration.Path == "" {
- validator.Push(errors.New("A file path must be provided with key 'path'"))
+ validator.Push(fmt.Errorf(errFmtStorageOptionMustBeProvided, "local", "path"))
}
}
diff --git a/internal/configuration/validator/storage_test.go b/internal/configuration/validator/storage_test.go
index 927d93699..b1aa888c3 100644
--- a/internal/configuration/validator/storage_test.go
+++ b/internal/configuration/validator/storage_test.go
@@ -17,51 +17,57 @@ type StorageSuite struct {
func (suite *StorageSuite) SetupTest() {
suite.validator = schema.NewStructValidator()
suite.configuration.EncryptionKey = testEncryptionKey
- suite.configuration.Local = &schema.LocalStorageConfiguration{
- Path: "/this/is/a/path",
- }
+ suite.configuration.Local = nil
+ suite.configuration.PostgreSQL = nil
+ suite.configuration.MySQL = nil
}
func (suite *StorageSuite) TestShouldValidateOneStorageIsConfigured() {
suite.configuration.Local = nil
+ suite.configuration.PostgreSQL = nil
+ suite.configuration.MySQL = nil
ValidateStorage(suite.configuration, suite.validator)
- suite.Assert().False(suite.validator.HasWarnings())
+ suite.Require().Len(suite.validator.Warnings(), 0)
suite.Require().Len(suite.validator.Errors(), 1)
- suite.Assert().EqualError(suite.validator.Errors()[0], "A storage configuration must be provided. It could be 'local', 'mysql' or 'postgres'")
+ suite.Assert().EqualError(suite.validator.Errors()[0], "storage: configuration for a 'local', 'mysql' or 'postgres' database must be provided")
}
func (suite *StorageSuite) TestShouldValidateLocalPathIsProvided() {
- suite.configuration.Local.Path = ""
+ suite.configuration.Local = &schema.LocalStorageConfiguration{
+ Path: "",
+ }
ValidateStorage(suite.configuration, suite.validator)
- suite.Assert().False(suite.validator.HasWarnings())
+ suite.Require().Len(suite.validator.Warnings(), 0)
suite.Require().Len(suite.validator.Errors(), 1)
- suite.Assert().EqualError(suite.validator.Errors()[0], "A file path must be provided with key 'path'")
+ suite.Assert().EqualError(suite.validator.Errors()[0], "storage: local: 'path' configuration option must be provided")
suite.validator.Clear()
suite.configuration.Local.Path = "/myapth"
ValidateStorage(suite.configuration, suite.validator)
- suite.Assert().False(suite.validator.HasWarnings())
- suite.Assert().False(suite.validator.HasErrors())
+ suite.Require().Len(suite.validator.Warnings(), 0)
+ suite.Require().Len(suite.validator.Errors(), 0)
}
-func (suite *StorageSuite) TestShouldValidateSQLUsernamePasswordAndDatabaseAreProvided() {
+func (suite *StorageSuite) TestShouldValidateMySQLHostUsernamePasswordAndDatabaseAreProvided() {
suite.configuration.MySQL = &schema.MySQLStorageConfiguration{}
ValidateStorage(suite.configuration, suite.validator)
- suite.Require().Len(suite.validator.Errors(), 2)
- suite.Assert().EqualError(suite.validator.Errors()[0], "the SQL username and password must be provided")
- suite.Assert().EqualError(suite.validator.Errors()[1], "the SQL database must be provided")
+ suite.Require().Len(suite.validator.Errors(), 3)
+ suite.Assert().EqualError(suite.validator.Errors()[0], "storage: mysql: 'host' configuration option must be provided")
+ suite.Assert().EqualError(suite.validator.Errors()[1], "storage: mysql: 'username' and 'password' configuration options must be provided")
+ suite.Assert().EqualError(suite.validator.Errors()[2], "storage: mysql: 'database' configuration option must be provided")
suite.validator.Clear()
suite.configuration.MySQL = &schema.MySQLStorageConfiguration{
SQLStorageConfiguration: schema.SQLStorageConfiguration{
+ Host: "localhost",
Username: "myuser",
Password: "pass",
Database: "database",
@@ -69,13 +75,39 @@ func (suite *StorageSuite) TestShouldValidateSQLUsernamePasswordAndDatabaseArePr
}
ValidateStorage(suite.configuration, suite.validator)
- suite.Assert().False(suite.validator.HasWarnings())
- suite.Assert().False(suite.validator.HasErrors())
+ suite.Require().Len(suite.validator.Warnings(), 0)
+ suite.Require().Len(suite.validator.Errors(), 0)
+}
+
+func (suite *StorageSuite) TestShouldValidatePostgreSQLHostUsernamePasswordAndDatabaseAreProvided() {
+ suite.configuration.PostgreSQL = &schema.PostgreSQLStorageConfiguration{}
+ suite.configuration.MySQL = nil
+ ValidateStorage(suite.configuration, suite.validator)
+
+ suite.Require().Len(suite.validator.Errors(), 3)
+ suite.Assert().EqualError(suite.validator.Errors()[0], "storage: postgres: 'host' configuration option must be provided")
+ suite.Assert().EqualError(suite.validator.Errors()[1], "storage: postgres: 'username' and 'password' configuration options must be provided")
+ suite.Assert().EqualError(suite.validator.Errors()[2], "storage: postgres: 'database' configuration option must be provided")
+
+ suite.validator.Clear()
+ suite.configuration.PostgreSQL = &schema.PostgreSQLStorageConfiguration{
+ SQLStorageConfiguration: schema.SQLStorageConfiguration{
+ Host: "postgre",
+ Username: "myuser",
+ Password: "pass",
+ Database: "database",
+ },
+ }
+ ValidateStorage(suite.configuration, suite.validator)
+
+ suite.Assert().Len(suite.validator.Warnings(), 0)
+ suite.Assert().Len(suite.validator.Errors(), 0)
}
func (suite *StorageSuite) TestShouldValidatePostgresSSLModeIsDisableByDefault() {
suite.configuration.PostgreSQL = &schema.PostgreSQLStorageConfiguration{
SQLStorageConfiguration: schema.SQLStorageConfiguration{
+ Host: "db1",
Username: "myuser",
Password: "pass",
Database: "database",
@@ -84,47 +116,76 @@ func (suite *StorageSuite) TestShouldValidatePostgresSSLModeIsDisableByDefault()
ValidateStorage(suite.configuration, suite.validator)
- suite.Assert().False(suite.validator.HasWarnings())
- suite.Assert().False(suite.validator.HasErrors())
+ suite.Assert().Len(suite.validator.Warnings(), 0)
+ suite.Assert().Len(suite.validator.Errors(), 0)
- suite.Assert().Equal("disable", suite.configuration.PostgreSQL.SSLMode)
+ suite.Assert().Equal("disable", suite.configuration.PostgreSQL.SSL.Mode)
}
func (suite *StorageSuite) TestShouldValidatePostgresSSLModeMustBeValid() {
suite.configuration.PostgreSQL = &schema.PostgreSQLStorageConfiguration{
SQLStorageConfiguration: schema.SQLStorageConfiguration{
+ Host: "db2",
Username: "myuser",
Password: "pass",
Database: "database",
},
- SSLMode: "unknown",
+ SSL: schema.PostgreSQLSSLStorageConfiguration{
+ Mode: "unknown",
+ },
}
ValidateStorage(suite.configuration, suite.validator)
- suite.Assert().False(suite.validator.HasWarnings())
+ suite.Assert().Len(suite.validator.Warnings(), 0)
suite.Require().Len(suite.validator.Errors(), 1)
- suite.Assert().EqualError(suite.validator.Errors()[0], "SSL mode must be 'disable', 'require', 'verify-ca', or 'verify-full'")
+ suite.Assert().EqualError(suite.validator.Errors()[0], "storage: postgres: ssl: 'mode' configuration option 'unknown' is invalid: must be one of 'disable', 'require', 'verify-ca', 'verify-full'")
+}
+
+// Deprecated. TODO: Remove in v4.36.0.
+func (suite *StorageSuite) TestShouldValidatePostgresSSLModeMustBeMappedForDeprecations() {
+ suite.configuration.PostgreSQL = &schema.PostgreSQLStorageConfiguration{
+ SQLStorageConfiguration: schema.SQLStorageConfiguration{
+ Host: "pg",
+ Username: "myuser",
+ Password: "pass",
+ Database: "database",
+ },
+ SSLMode: "require",
+ }
+
+ ValidateStorage(suite.configuration, suite.validator)
+
+ suite.Assert().Len(suite.validator.Warnings(), 0)
+ suite.Assert().Len(suite.validator.Errors(), 0)
+
+ suite.Assert().Equal(suite.configuration.PostgreSQL.SSL.Mode, "require")
}
func (suite *StorageSuite) TestShouldRaiseErrorOnNoEncryptionKey() {
suite.configuration.EncryptionKey = ""
+ suite.configuration.Local = &schema.LocalStorageConfiguration{
+ Path: "/this/is/a/path",
+ }
ValidateStorage(suite.configuration, suite.validator)
- suite.Assert().False(suite.validator.HasWarnings())
+ suite.Require().Len(suite.validator.Warnings(), 0)
suite.Require().Len(suite.validator.Errors(), 1)
- suite.Assert().EqualError(suite.validator.Errors()[0], "the configuration option storage.encryption_key must be provided")
+ suite.Assert().EqualError(suite.validator.Errors()[0], "storage: 'encryption_key' configuration option must be provided")
}
func (suite *StorageSuite) TestShouldRaiseErrorOnShortEncryptionKey() {
suite.configuration.EncryptionKey = "abc"
+ suite.configuration.Local = &schema.LocalStorageConfiguration{
+ Path: "/this/is/a/path",
+ }
ValidateStorage(suite.configuration, suite.validator)
- suite.Assert().False(suite.validator.HasWarnings())
+ suite.Require().Len(suite.validator.Warnings(), 0)
suite.Require().Len(suite.validator.Errors(), 1)
- suite.Assert().EqualError(suite.validator.Errors()[0], "the configuration option storage.encryption_key must be 20 characters or longer")
+ suite.Assert().EqualError(suite.validator.Errors()[0], "storage: 'encryption_key' configuration option must be 20 characters or longer")
}
func TestShouldRunStorageSuite(t *testing.T) {
diff --git a/internal/storage/sql_provider_backend_mysql.go b/internal/storage/sql_provider_backend_mysql.go
index dfdff770d..6c313ee57 100644
--- a/internal/storage/sql_provider_backend_mysql.go
+++ b/internal/storage/sql_provider_backend_mysql.go
@@ -41,10 +41,7 @@ func dataSourceNameMySQL(config schema.MySQLStorageConfiguration) (dataSourceNam
address += fmt.Sprintf(":%d", config.Port)
}
- dataSourceName += fmt.Sprintf("tcp(%s)", address)
- if config.Database != "" {
- dataSourceName += fmt.Sprintf("/%s", config.Database)
- }
+ dataSourceName += fmt.Sprintf("tcp(%s)/%s", address, config.Database)
dataSourceName += "?"
dataSourceName += fmt.Sprintf("timeout=%ds&multiStatements=true&parseTime=true", int32(config.Timeout/time.Second))
diff --git a/internal/storage/sql_provider_backend_postgres.go b/internal/storage/sql_provider_backend_postgres.go
index 5eadf8539..300f3f50d 100644
--- a/internal/storage/sql_provider_backend_postgres.go
+++ b/internal/storage/sql_provider_backend_postgres.go
@@ -56,20 +56,34 @@ func NewPostgreSQLProvider(config *schema.Configuration) (provider *PostgreSQLPr
func dataSourceNamePostgreSQL(config schema.PostgreSQLStorageConfiguration) (dataSourceName string) {
args := []string{
+ fmt.Sprintf("host=%s", config.Host),
fmt.Sprintf("user='%s'", config.Username),
fmt.Sprintf("password='%s'", config.Password),
- }
-
- if config.Host != "" {
- args = append(args, fmt.Sprintf("host=%s", config.Host))
+ fmt.Sprintf("dbname=%s", config.Database),
}
if config.Port > 0 {
args = append(args, fmt.Sprintf("port=%d", config.Port))
}
- if config.Database != "" {
- args = append(args, fmt.Sprintf("dbname=%s", config.Database))
+ if config.Schema != "" {
+ args = append(args, fmt.Sprintf("search_path=%s", config.Schema))
+ }
+
+ if config.SSL.Mode != "" {
+ args = append(args, fmt.Sprintf("sslmode=%s", config.SSL.Mode))
+ }
+
+ if config.SSL.RootCertificate != "" {
+ args = append(args, fmt.Sprintf("sslrootcert=%s", config.SSL.RootCertificate))
+ }
+
+ if config.SSL.Certificate != "" {
+ args = append(args, fmt.Sprintf("sslcert=%s", config.SSL.Certificate))
+ }
+
+ if config.SSL.Key != "" {
+ args = append(args, fmt.Sprintf("sslkey=%s", config.SSL.Key))
}
args = append(args, fmt.Sprintf("connect_timeout=%d", int32(config.Timeout/time.Second)))
diff --git a/internal/suites/suite_cli_test.go b/internal/suites/suite_cli_test.go
index f287646eb..c64a56e01 100644
--- a/internal/suites/suite_cli_test.go
+++ b/internal/suites/suite_cli_test.go
@@ -168,12 +168,12 @@ func (s *CLISuite) TestStorageShouldShowErrWithoutConfig() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "storage", "schema-info"})
s.Assert().EqualError(err, "exit status 1")
- s.Assert().Contains(output, "Error: A storage configuration must be provided. It could be 'local', 'mysql' or 'postgres', the configuration option storage.encryption_key must be provided\n")
+ s.Assert().Contains(output, "Error: storage: configuration for a 'local', 'mysql' or 'postgres' database must be provided, storage: 'encryption_key' configuration option must be provided\n")
output, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "storage", "migrate", "history"})
s.Assert().EqualError(err, "exit status 1")
- s.Assert().Contains(output, "Error: A storage configuration must be provided. It could be 'local', 'mysql' or 'postgres', the configuration option storage.encryption_key must be provided\n")
+ s.Assert().Contains(output, "Error: storage: configuration for a 'local', 'mysql' or 'postgres' database must be provided, storage: 'encryption_key' configuration option must be provided\n")
}
func (s *CLISuite) TestStorage00ShouldShowCorrectPreInitInformation() {