Merge pull request #1439 from sks/feature/fail_on_invalid_config

Return config validation errors in one go
This commit is contained in:
Joel Speed 2019-07-30 11:00:17 +02:00 committed by GitHub
commit e2ddefff31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 22 deletions

View file

@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"os"
"strings"
"golang.org/x/crypto/bcrypt"
@ -48,6 +49,38 @@ type Config struct {
StaticPasswords []password `json:"staticPasswords"`
}
//Validate the configuration
func (c Config) Validate() error {
// Fast checks. Perform these first for a more responsive CLI.
checks := []struct {
bad bool
errMsg string
}{
{c.Issuer == "", "no issuer specified in config file"},
{!c.EnablePasswordDB && len(c.StaticPasswords) != 0, "cannot specify static passwords without enabling password db"},
{c.Storage.Config == nil, "no storage supplied in config file"},
{c.Web.HTTP == "" && c.Web.HTTPS == "", "must supply a HTTP/HTTPS address to listen on"},
{c.Web.HTTPS != "" && c.Web.TLSCert == "", "no cert specified for HTTPS"},
{c.Web.HTTPS != "" && c.Web.TLSKey == "", "no private key specified for HTTPS"},
{c.GRPC.TLSCert != "" && c.GRPC.Addr == "", "no address specified for gRPC"},
{c.GRPC.TLSKey != "" && c.GRPC.Addr == "", "no address specified for gRPC"},
{(c.GRPC.TLSCert == "") != (c.GRPC.TLSKey == ""), "must specific both a gRPC TLS cert and key"},
{c.GRPC.TLSCert == "" && c.GRPC.TLSClientCA != "", "cannot specify gRPC TLS client CA without a gRPC TLS cert"},
}
var checkErrors []string
for _, check := range checks {
if check.bad {
checkErrors = append(checkErrors, check.errMsg)
}
}
if len(checkErrors) != 0 {
return fmt.Errorf("invalid Config:\n\t-\t%s", strings.Join(checkErrors, "\n\t-\t"))
}
return nil
}
type password storage.Password
func (p *password) UnmarshalJSON(b []byte) error {

View file

@ -14,6 +14,47 @@ import (
var _ = yaml.YAMLToJSON
func TestValidConfiguration(t *testing.T) {
configuration := Config{
Issuer: "http://127.0.0.1:5556/dex",
Storage: Storage{
Type: "sqlite3",
Config: &sql.SQLite3{
File: "examples/dex.db",
},
},
Web: Web{
HTTP: "127.0.0.1:5556",
},
StaticConnectors: []Connector{
{
Type: "mockCallback",
ID: "mock",
Name: "Example",
Config: &mock.CallbackConfig{},
},
},
}
if err := configuration.Validate(); err != nil {
t.Fatalf("this configuration should have been valid: %v", err)
}
}
func TestInvalidConfiguration(t *testing.T) {
configuration := Config{}
err := configuration.Validate()
if err == nil {
t.Fatal("this configuration should be invalid")
}
got := err.Error()
wanted := `invalid Config:
- no issuer specified in config file
- no storage supplied in config file
- must supply a HTTP/HTTPS address to listen on`
if got != wanted {
t.Fatalf("Expected error message to be %q, got %q", wanted, got)
}
}
func TestUnmarshalConfig(t *testing.T) {
rawConfig := []byte(`
issuer: http://127.0.0.1:5556/dex

View file

@ -71,28 +71,8 @@ func serve(cmd *cobra.Command, args []string) error {
if c.Logger.Level != "" {
logger.Infof("config using log level: %s", c.Logger.Level)
}
// Fast checks. Perform these first for a more responsive CLI.
checks := []struct {
bad bool
errMsg string
}{
{c.Issuer == "", "no issuer specified in config file"},
{!c.EnablePasswordDB && len(c.StaticPasswords) != 0, "cannot specify static passwords without enabling password db"},
{c.Storage.Config == nil, "no storage supplied in config file"},
{c.Web.HTTP == "" && c.Web.HTTPS == "", "must supply a HTTP/HTTPS address to listen on"},
{c.Web.HTTPS != "" && c.Web.TLSCert == "", "no cert specified for HTTPS"},
{c.Web.HTTPS != "" && c.Web.TLSKey == "", "no private key specified for HTTPS"},
{c.GRPC.TLSCert != "" && c.GRPC.Addr == "", "no address specified for gRPC"},
{c.GRPC.TLSKey != "" && c.GRPC.Addr == "", "no address specified for gRPC"},
{(c.GRPC.TLSCert == "") != (c.GRPC.TLSKey == ""), "must specific both a gRPC TLS cert and key"},
{c.GRPC.TLSCert == "" && c.GRPC.TLSClientCA != "", "cannot specify gRPC TLS client CA without a gRPC TLS cert"},
}
for _, check := range checks {
if check.bad {
return fmt.Errorf("invalid config: %s", check.errMsg)
}
if err := c.Validate(); err != nil {
return err
}
logger.Infof("config issuer: %s", c.Issuer)