Merge branch 'main' into fix/1027-improve-passkey-naming

This commit is contained in:
Stefan Jacobi
2024-01-31 14:00:58 +01:00
committed by GitHub
16 changed files with 126 additions and 39 deletions

View File

@ -11,6 +11,7 @@ import (
"github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/providers/file"
"github.com/teamhanko/hanko/backend/ee/saml/config" "github.com/teamhanko/hanko/backend/ee/saml/config"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
zeroLogger "github.com/rs/zerolog/log"
"log" "log"
"strings" "strings"
"time" "time"
@ -20,6 +21,7 @@ import (
type Config struct { type Config struct {
Server Server `yaml:"server" json:"server,omitempty" koanf:"server"` Server Server `yaml:"server" json:"server,omitempty" koanf:"server"`
Webauthn WebauthnSettings `yaml:"webauthn" json:"webauthn,omitempty" koanf:"webauthn"` Webauthn WebauthnSettings `yaml:"webauthn" json:"webauthn,omitempty" koanf:"webauthn"`
Smtp SMTP `yaml:"smtp" json:"smtp,omitempty" koanf:"smtp"`
Passcode Passcode `yaml:"passcode" json:"passcode" koanf:"passcode"` Passcode Passcode `yaml:"passcode" json:"passcode" koanf:"passcode"`
Password Password `yaml:"password" json:"password,omitempty" koanf:"password"` Password Password `yaml:"password" json:"password,omitempty" koanf:"password"`
Database Database `yaml:"database" json:"database" koanf:"database"` Database Database `yaml:"database" json:"database" koanf:"database"`
@ -83,6 +85,8 @@ func Load(cfgFile *string) (*Config, error) {
return nil, fmt.Errorf("failed to post process config: %w", err) return nil, fmt.Errorf("failed to post process config: %w", err)
} }
c.arrangeSmtpSettings()
if err = c.Validate(); err != nil { if err = c.Validate(); err != nil {
return nil, fmt.Errorf("failed to validate config: %s", err) return nil, fmt.Errorf("failed to validate config: %s", err)
} }
@ -109,15 +113,18 @@ func DefaultConfig() *Config {
UserVerification: "preferred", UserVerification: "preferred",
Timeout: 60000, Timeout: 60000,
}, },
Passcode: Passcode{
Smtp: SMTP{ Smtp: SMTP{
Port: "465", Port: "465",
}, },
Passcode: Passcode{
TTL: 300, TTL: 300,
Email: Email{ Email: Email{
FromAddress: "passcode@hanko.io", FromAddress: "passcode@hanko.io",
FromName: "Hanko", FromName: "Hanko",
}, },
Smtp: SMTP{
Port: "465",
},
}, },
Password: Password{ Password: Password{
MinPasswordLength: 8, MinPasswordLength: 8,
@ -175,6 +182,10 @@ func (c *Config) Validate() error {
if err != nil { if err != nil {
return fmt.Errorf("failed to validate webauthn settings: %w", err) return fmt.Errorf("failed to validate webauthn settings: %w", err)
} }
err = c.Smtp.Validate()
if err != nil {
return fmt.Errorf("failed to validate smtp settings: %w", err)
}
err = c.Passcode.Validate() err = c.Passcode.Validate()
if err != nil { if err != nil {
return fmt.Errorf("failed to validate passcode settings: %w", err) return fmt.Errorf("failed to validate passcode settings: %w", err)
@ -360,8 +371,9 @@ func (e *Email) Validate() error {
type Passcode struct { type Passcode struct {
Email Email `yaml:"email" json:"email,omitempty" koanf:"email"` Email Email `yaml:"email" json:"email,omitempty" koanf:"email"`
Smtp SMTP `yaml:"smtp" json:"smtp" koanf:"smtp"`
TTL int `yaml:"ttl" json:"ttl,omitempty" koanf:"ttl" jsonschema:"default=300"` TTL int `yaml:"ttl" json:"ttl,omitempty" koanf:"ttl" jsonschema:"default=300"`
//Deprecated: Use root level Smtp instead
Smtp SMTP `yaml:"smtp" json:"smtp,omitempty" koanf:"smtp,omitempty" required:"false" envconfig:"smtp,omitempty"`
} }
func (p *Passcode) Validate() error { func (p *Passcode) Validate() error {
@ -369,10 +381,6 @@ func (p *Passcode) Validate() error {
if err != nil { if err != nil {
return fmt.Errorf("failed to validate email settings: %w", err) return fmt.Errorf("failed to validate email settings: %w", err)
} }
err = p.Smtp.Validate()
if err != nil {
return fmt.Errorf("failed to validate smtp settings: %w", err)
}
return nil return nil
} }
@ -651,6 +659,17 @@ func (c *Config) PostProcess() error {
} }
func (c *Config) arrangeSmtpSettings() {
if c.Passcode.Smtp.Validate() == nil {
if c.Smtp.Validate() == nil {
zeroLogger.Warn().Msg("Both root smtp and passcode.smtp are set. Using smtp settings from root configuration")
return
}
c.Smtp = c.Passcode.Smtp
}
}
type LoggerConfig struct { type LoggerConfig struct {
LogHealthAndMetrics bool `yaml:"log_health_and_metrics,omitempty" json:"log_health_and_metrics" koanf:"log_health_and_metrics" jsonschema:"default=true"` LogHealthAndMetrics bool `yaml:"log_health_and_metrics,omitempty" json:"log_health_and_metrics" koanf:"log_health_and_metrics" jsonschema:"default=true"`
} }

View File

@ -4,13 +4,13 @@ database:
host: localhost host: localhost
port: 5432 port: 5432
dialect: postgres dialect: postgres
passcode: smtp:
email:
from_address: no-reply@hanko.io
smtp:
host: smtp.example.com host: smtp.example.com
user: example user: example
password: example password: example
passcode:
email:
from_address: no-reply@hanko.io
secrets: secrets:
keys: keys:
- abcedfghijklmnopqrstuvwxyz - abcedfghijklmnopqrstuvwxyz

View File

@ -21,6 +21,11 @@ func TestDefaultConfigAccountParameters(t *testing.T) {
assert.Equal(t, cfg.Account.AllowSignup, true) assert.Equal(t, cfg.Account.AllowSignup, true)
} }
func TestDefaultConfigSmtpParameters(t *testing.T) {
cfg := DefaultConfig()
assert.Equal(t, cfg.Smtp.Port, "465")
}
func TestParseValidConfig(t *testing.T) { func TestParseValidConfig(t *testing.T) {
configPath := "./config.yaml" configPath := "./config.yaml"
cfg, err := Load(&configPath) cfg, err := Load(&configPath)
@ -32,6 +37,28 @@ func TestParseValidConfig(t *testing.T) {
} }
} }
func TestPasscodeSmtpSettingsCopiedToRootLevelSmtp(t *testing.T) {
configPath := "./passcode-smtp-config.yaml"
cfg, err := Load(&configPath)
if err != nil {
t.Error(err)
}
if err := cfg.Validate(); err != nil {
t.Error(err)
}
assert.Equal(t, cfg.Smtp.Port, cfg.Passcode.Smtp.Port)
assert.Equal(t, cfg.Smtp.Host, cfg.Passcode.Smtp.Host)
assert.Equal(t, cfg.Smtp.Password, cfg.Passcode.Smtp.Password)
assert.Equal(t, cfg.Smtp.User, cfg.Passcode.Smtp.User)
}
func TestRootSmtpPasscodeSmtpConflict(t *testing.T) {
configPath := "./root-passcode-smtp-config.yaml"
_, err := Load(&configPath)
assert.NoError(t, err)
}
func TestMinimalConfigValidates(t *testing.T) { func TestMinimalConfigValidates(t *testing.T) {
configPath := "./minimal-config.yaml" configPath := "./minimal-config.yaml"
cfg, err := Load(&configPath) cfg, err := Load(&configPath)
@ -76,7 +103,7 @@ func TestRateLimiterConfig(t *testing.T) {
} }
func TestEnvironmentVariables(t *testing.T) { func TestEnvironmentVariables(t *testing.T) {
err := os.Setenv("PASSCODE_SMTP_HOST", "valueFromEnvVars") err := os.Setenv("SMTP_HOST", "valueFromEnvVars")
require.NoError(t, err) require.NoError(t, err)
err = os.Setenv("WEBAUTHN_RELYING_PARTY_ORIGINS", "https://hanko.io,https://auth.hanko.io") err = os.Setenv("WEBAUTHN_RELYING_PARTY_ORIGINS", "https://hanko.io,https://auth.hanko.io")
@ -86,6 +113,6 @@ func TestEnvironmentVariables(t *testing.T) {
cfg, err := Load(&configPath) cfg, err := Load(&configPath)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "valueFromEnvVars", cfg.Passcode.Smtp.Host) assert.Equal(t, "valueFromEnvVars", cfg.Smtp.Host)
assert.True(t, reflect.DeepEqual([]string{"https://hanko.io", "https://auth.hanko.io"}, cfg.Webauthn.RelyingParty.Origins)) assert.True(t, reflect.DeepEqual([]string{"https://hanko.io", "https://auth.hanko.io"}, cfg.Webauthn.RelyingParty.Origins))
} }

View File

@ -1,5 +1,4 @@
passcode: smtp:
smtp:
host: smtp.example.com host: smtp.example.com
user: example user: example
password: example password: example

View File

@ -0,0 +1,18 @@
database:
user: hanko
password: hanko
host: localhost
port: 5432
dialect: postgres
passcode:
email:
from_address: no-reply@hanko.io
smtp:
host: smtp.example.com
user: example
password: example
secrets:
keys:
- abcedfghijklmnopqrstuvwxyz
service:
name: Hanko Authentication Service

View File

@ -0,0 +1,22 @@
database:
user: hanko
password: hanko
host: localhost
port: 5432
dialect: postgres
smtp:
host: smtp1.example.com
user: example1
password: example1
passcode:
email:
from_address: no-reply@hanko.io
smtp:
host: smtp2.example.com
user: example2
password: example2
secrets:
keys:
- abcedfghijklmnopqrstuvwxyz
service:
name: Hanko Authentication Service

View File

@ -38,8 +38,8 @@ func (s *passcodeSuite) TestPasscodeHandler_Init() {
cfg := func() *config.Config { cfg := func() *config.Config {
cfg := &test.DefaultConfig cfg := &test.DefaultConfig
cfg.Passcode.Smtp.Host = "localhost" cfg.Smtp.Host = s.EmailServer.SmtpHost
cfg.Passcode.Smtp.Port = s.EmailServer.SmtpPort cfg.Smtp.Port = s.EmailServer.SmtpPort
return cfg return cfg
} }

View File

@ -70,7 +70,7 @@ func NewPublicRouter(cfg *config.Config, persister persistence.Persister, promet
sessionMiddleware := hankoMiddleware.Session(cfg, sessionManager) sessionMiddleware := hankoMiddleware.Session(cfg, sessionManager)
mailer, err := mail.NewMailer(cfg.Passcode.Smtp) mailer, err := mail.NewMailer(cfg.Smtp)
if err != nil { if err != nil {
panic(fmt.Errorf("failed to create mailer: %w", err)) panic(fmt.Errorf("failed to create mailer: %w", err))
} }

View File

@ -343,10 +343,10 @@ var defaultConfig = config.Config{
Secrets: config.Secrets{ Secrets: config.Secrets{
Keys: []string{"abcdefghijklmnop"}, Keys: []string{"abcdefghijklmnop"},
}, },
Passcode: config.Passcode{Smtp: config.SMTP{ Smtp: config.SMTP{
Host: "localhost", Host: "localhost",
Port: "2500", Port: "2500",
}}, },
} }
type sessionManager struct { type sessionManager struct {

View File

@ -16,11 +16,11 @@ var DefaultConfig = config.Config{
Secrets: config.Secrets{ Secrets: config.Secrets{
Keys: []string{"abcdefghijklmnop"}, Keys: []string{"abcdefghijklmnop"},
}, },
Passcode: config.Passcode{
Smtp: config.SMTP{ Smtp: config.SMTP{
Host: "localhost", Host: "localhost",
Port: "2500", Port: "2500",
}, },
Passcode: config.Passcode{
Email: config.Email{ Email: config.Email{
FromAddress: "test@hanko.io", FromAddress: "test@hanko.io",
FromName: "Hanko Test", FromName: "Hanko Test",

View File

@ -18,6 +18,7 @@ type TestMailslurper struct {
pool *dockertest.Pool pool *dockertest.Pool
resource *dockertest.Resource resource *dockertest.Resource
httpUrl string httpUrl string
SmtpHost string
SmtpPort string SmtpPort string
} }
@ -74,6 +75,7 @@ func StartMailslurper() (*TestMailslurper, error) {
pool: pool, pool: pool,
resource: resource, resource: resource,
httpUrl: dsn, httpUrl: dsn,
SmtpHost: "localhost",
SmtpPort: smtpPort, SmtpPort: smtpPort,
}, nil }, nil
} }

View File

@ -4,12 +4,12 @@ database:
host: postgresd host: postgresd
port: 5432 port: 5432
dialect: postgres dialect: postgres
smtp:
host: "mailslurper"
port: "2500"
passcode: passcode:
email: email:
from_address: no-reply@hanko.io from_address: no-reply@hanko.io
smtp:
host: "mailslurper"
port: "2500"
secrets: secrets:
keys: keys:
- abcedfghijklmnopqrstuvwxyz - abcedfghijklmnopqrstuvwxyz

View File

@ -4,12 +4,12 @@ database:
host: postgresd host: postgresd
port: 5432 port: 5432
dialect: postgres dialect: postgres
smtp:
host: "mailslurper"
port: "2500"
passcode: passcode:
email: email:
from_address: no-reply@hanko.io from_address: no-reply@hanko.io
smtp:
host: "mailslurper"
port: "2500"
secrets: secrets:
keys: keys:
- abcedfghijklmnopqrstuvwxyz - abcedfghijklmnopqrstuvwxyz

View File

@ -4,12 +4,12 @@ database:
host: postgresd host: postgresd
port: 5432 port: 5432
dialect: postgres dialect: postgres
smtp:
host: "mailslurper"
port: "2500"
passcode: passcode:
email: email:
from_address: no-reply@hanko.io from_address: no-reply@hanko.io
smtp:
host: "mailslurper"
port: "2500"
secrets: secrets:
keys: keys:
- abcedfghijklmnopqrstuvwxyz - abcedfghijklmnopqrstuvwxyz

View File

@ -4,12 +4,12 @@ database:
host: postgres host: postgres
port: 5432 port: 5432
dialect: postgres dialect: postgres
smtp:
host: "mailhog"
port: "2500"
passcode: passcode:
email: email:
from_address: no-reply@hanko.io from_address: no-reply@hanko.io
smtp:
host: "mailhog"
port: "2500"
secrets: secrets:
keys: keys:
- abcedfghijklmnopqrstuvwxyz - abcedfghijklmnopqrstuvwxyz

View File

@ -1 +1 @@
v16.15.1 v18.6.0