feat(storage): postgresql schema and ssl options (#2659)

Adds the schema name and all ssl options for PostgreSQL. Also a significant refactor of the storage validation process.
pull/2662/head
James Elliott 2021-12-02 16:36:03 +11:00 committed by GitHub
parent 252b844b46
commit f90ca855e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 275 additions and 102 deletions

View File

@ -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

View File

@ -32,10 +32,8 @@ See the [encryption_key docs](./index.md#encryption_key).
<div markdown="1">
type: string
{: .label .label-config .label-purple }
default: localhost
{: .label .label-config .label-blue }
required: no
{: .label .label-config .label-green }
required: yes
{: .label .label-config .label-red }
</div>
The database server host.

View File

@ -19,9 +19,14 @@ storage:
host: 127.0.0.1
port: 5432
database: authelia
schema: public
username: authelia
password: mypassword
sslmode: disable
ssl:
mode: disable
root_certificate: /path/to/root_cert.pem
certificate: /path/to/cert.pem
key: /path/to/key.pem
```
## Options
@ -33,10 +38,8 @@ See the [encryption_key docs](./index.md#encryption_key).
<div markdown="1">
type: string
{: .label .label-config .label-purple }
default: localhost
{: .label .label-config .label-blue }
required: no
{: .label .label-config .label-green }
required: yes
{: .label .label-config .label-red }
</div>
The database server host.
@ -59,10 +62,29 @@ required: no
The port the database server is listening on.
### database
<div markdown="1">
type: string
{: .label .label-config .label-purple }
required: yes
{: .label .label-config .label-red }
</div>
The database name on the database server that the assigned [user](#username) has access to for the purpose of
**Authelia**.
### schema
<div markdown="1">
type: string
{: .label .label-config .label-purple }
default: public
{: .label .label-config .label-blue }
required: no
{: .label .label-config .label-green }
</div>
The database schema name to use on the database server that the assigned [user](#username) has access to for the purpose
of **Authelia**. By default this is the public schema.
### username
<div markdown="1">
type: string
@ -96,7 +118,9 @@ required: no
The SQL connection timeout.
### sslmode
### ssl
#### mode
<div markdown="1">
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
<div markdown="1">
type: string
{: .label .label-config .label-purple }
required: no
{: .label .label-config .label-green }
</div>
The optional location of the root certificate file encoded in the PEM format for validation purposes.
#### certificate
<div markdown="1">
type: string
{: .label .label-config .label-purple }
required: no
{: .label .label-config .label-green }
</div>
The optional location of the certificate file encoded in the PEM format for validation purposes.
#### key
<div markdown="1">
type: string
{: .label .label-config .label-purple }
required: no
{: .label .label-config .label-green }
</div>
The optional location of the key file encoded in the PEM format for authentication purposes.

View File

@ -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(),

View File

@ -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))

View File

@ -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

View File

@ -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,
}

View File

@ -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",

View File

@ -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"))
}
}

View File

@ -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) {

View File

@ -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))

View File

@ -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)))

View File

@ -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() {