From c5be09ca483dd2cd8f23675c754ff12bb5f27704 Mon Sep 17 00:00:00 2001 From: Joel Speed <joel.speed@hotmail.co.uk> Date: Mon, 13 Apr 2020 11:34:25 +0100 Subject: [PATCH] Replace options loading with viper --- env_options.go | 54 ------------------------------ env_options_test.go | 64 ------------------------------------ go.mod | 2 -- go.sum | 7 ++-- main.go | 24 +++++++------- oauthproxy.go | 4 +-- options.go | 11 +++---- options_test.go | 2 +- pkg/apis/options/sessions.go | 6 ++-- 9 files changed, 27 insertions(+), 147 deletions(-) delete mode 100644 env_options.go delete mode 100644 env_options_test.go diff --git a/env_options.go b/env_options.go deleted file mode 100644 index 51a888f..0000000 --- a/env_options.go +++ /dev/null @@ -1,54 +0,0 @@ -package main - -import ( - "os" - "reflect" - "strings" -) - -// EnvOptions holds program options loaded from the process environment -type EnvOptions map[string]interface{} - -// LoadEnvForStruct loads environment variables for each field in an options -// struct passed into it. -// -// Fields in the options struct must have an `env` and `cfg` tag to be read -// from the environment -func (cfg EnvOptions) LoadEnvForStruct(options interface{}) { - val := reflect.ValueOf(options) - var typ reflect.Type - if val.Kind() == reflect.Ptr { - typ = val.Elem().Type() - } else { - typ = val.Type() - } - - for i := 0; i < typ.NumField(); i++ { - // pull out the struct tags: - // flag - the name of the command line flag - // deprecated - (optional) the name of the deprecated command line flag - // cfg - (optional, defaults to underscored flag) the name of the config file option - field := typ.Field(i) - fieldV := reflect.Indirect(val).Field(i) - - if field.Type.Kind() == reflect.Struct { - cfg.LoadEnvForStruct(fieldV.Interface()) - continue - } - - flagName := field.Tag.Get("flag") - envName := field.Tag.Get("env") - cfgName := field.Tag.Get("cfg") - if cfgName == "" && flagName != "" { - cfgName = strings.ReplaceAll(flagName, "-", "_") - } - if envName == "" || cfgName == "" { - // resolvable fields must have the `env` and `cfg` struct tag - continue - } - v := os.Getenv(envName) - if v != "" { - cfg[cfgName] = v - } - } -} diff --git a/env_options_test.go b/env_options_test.go deleted file mode 100644 index c8ee75c..0000000 --- a/env_options_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package main_test - -import ( - "os" - "testing" - - proxy "github.com/oauth2-proxy/oauth2-proxy" - "github.com/stretchr/testify/assert" -) - -type EnvTest struct { - TestField string `cfg:"target_field" env:"TEST_ENV_FIELD"` - EnvTestEmbed - Named EnvTestNamed -} - -type EnvTestEmbed struct { - TestFieldEmbed string `cfg:"target_field_embed" env:"TEST_ENV_FIELD_EMBED"` -} - -type EnvTestNamed struct { - TestFieldNamed string `cfg:"target_field_named" env:"TEST_ENV_FIELD_NAMED"` -} - -func TestLoadEnvForStruct(t *testing.T) { - - cfg := make(proxy.EnvOptions) - cfg.LoadEnvForStruct(&EnvTest{}) - - _, ok := cfg["target_field"] - assert.Equal(t, ok, false) - - os.Setenv("TEST_ENV_FIELD", "1234abcd") - cfg.LoadEnvForStruct(&EnvTest{}) - v := cfg["target_field"] - assert.Equal(t, v, "1234abcd") -} - -func TestLoadEnvForStructWithEmbeddedFields(t *testing.T) { - - cfg := make(proxy.EnvOptions) - cfg.LoadEnvForStruct(&EnvTest{}) - - _, ok := cfg["target_field_embed"] - assert.Equal(t, ok, false) - - os.Setenv("TEST_ENV_FIELD_EMBED", "1234abcd") - cfg.LoadEnvForStruct(&EnvTest{}) - v := cfg["target_field_embed"] - assert.Equal(t, v, "1234abcd") -} - -func TestLoadEnvForStructWithNamedStructFields(t *testing.T) { - cfg := make(proxy.EnvOptions) - cfg.LoadEnvForStruct(&EnvTest{}) - - _, ok := cfg["target_field_named"] - assert.Equal(t, ok, false) - - os.Setenv("TEST_ENV_FIELD_NAMED", "1234abcd") - cfg.LoadEnvForStruct(&EnvTest{}) - v := cfg["target_field_named"] - assert.Equal(t, v, "1234abcd") -} diff --git a/go.mod b/go.mod index 21bd59f..618c7c7 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/oauth2-proxy/oauth2-proxy go 1.14 require ( - github.com/BurntSushi/toml v0.3.1 github.com/alicebob/miniredis/v2 v2.11.2 github.com/bitly/go-simplejson v0.5.0 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect @@ -14,7 +13,6 @@ require ( github.com/kr/pretty v0.2.0 // indirect github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa github.com/mitchellh/mapstructure v1.1.2 - github.com/mreiferson/go-options v1.0.0 github.com/onsi/ginkgo v1.12.0 github.com/onsi/gomega v1.9.0 github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect diff --git a/go.sum b/go.sum index 5e85e76..45e2be1 100644 --- a/go.sum +++ b/go.sum @@ -33,6 +33,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -74,6 +75,7 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= @@ -89,6 +91,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= @@ -111,8 +114,6 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mreiferson/go-options v1.0.0 h1:RMLidydGlDWpL+lQTXo0bVIf/XT2CTq7AEJMoz5/VWs= -github.com/mreiferson/go-options v1.0.0/go.mod h1:zHtCks/HQvOt8ATyfwVe3JJq2PPuImzXINPRTC03+9w= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -142,7 +143,9 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= diff --git a/main.go b/main.go index 91111ea..698c64a 100644 --- a/main.go +++ b/main.go @@ -12,9 +12,9 @@ import ( "syscall" "time" - "github.com/BurntSushi/toml" - options "github.com/mreiferson/go-options" + "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options" "github.com/oauth2-proxy/oauth2-proxy/pkg/logger" + "github.com/spf13/pflag" ) func main() { @@ -149,7 +149,10 @@ func main() { flagSet.String("user-id-claim", "email", "which claim contains the user ID") - flagSet.Parse(os.Args[1:]) + pflagSet := pflag.NewFlagSet("oauth2-proxy", pflag.ExitOnError) + pflagSet.AddGoFlagSet(flagSet) + + pflagSet.Parse(os.Args[1:]) if *showVersion { fmt.Printf("oauth2-proxy %s (built with %s)\n", VERSION, runtime.Version()) @@ -157,18 +160,13 @@ func main() { } opts := NewOptions() - - cfg := make(EnvOptions) - if *config != "" { - _, err := toml.DecodeFile(*config, &cfg) - if err != nil { - logger.Fatalf("ERROR: failed to load config file %s - %s", *config, err) - } + err := options.Load(*config, pflagSet, opts) + if err != nil { + logger.Printf("ERROR: Failed to load config: %v", err) + os.Exit(1) } - cfg.LoadEnvForStruct(opts) - options.Resolve(opts, flagSet, cfg) - err := opts.Validate() + err = opts.Validate() if err != nil { logger.Printf("%s", err) os.Exit(1) diff --git a/oauthproxy.go b/oauthproxy.go index 516340c..587215f 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -247,7 +247,7 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy { panic(fmt.Sprintf("unknown upstream protocol %s", u.Scheme)) } } - for _, u := range opts.CompiledRegex { + for _, u := range opts.compiledRegex { logger.Printf("compiled skip-auth-regex => %q", u) } @@ -303,7 +303,7 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy { skipAuthPreflight: opts.SkipAuthPreflight, skipJwtBearerTokens: opts.SkipJwtBearerTokens, jwtBearerVerifiers: opts.jwtBearerVerifiers, - compiledRegex: opts.CompiledRegex, + compiledRegex: opts.compiledRegex, SetXAuthRequest: opts.SetXAuthRequest, PassBasicAuth: opts.PassBasicAuth, SetBasicAuth: opts.SetBasicAuth, diff --git a/options.go b/options.go index ca8c14d..b59c2b1 100644 --- a/options.go +++ b/options.go @@ -64,9 +64,8 @@ type Options struct { Banner string `flag:"banner" cfg:"banner" env:"OAUTH2_PROXY_BANNER"` Footer string `flag:"footer" cfg:"footer" env:"OAUTH2_PROXY_FOOTER"` - Cookie options.CookieOptions - - Session options.SessionOptions + Cookie options.CookieOptions `cfg:",squash"` + Session options.SessionOptions `cfg:",squash"` Upstreams []string `flag:"upstream" cfg:"upstreams" env:"OAUTH2_PROXY_UPSTREAMS"` SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex" env:"OAUTH2_PROXY_SKIP_AUTH_REGEX"` @@ -132,7 +131,7 @@ type Options struct { // internal values that are set after config validation redirectURL *url.URL proxyURLs []*url.URL - CompiledRegex []*regexp.Regexp + compiledRegex []*regexp.Regexp provider providers.Provider sessionStore sessionsapi.SessionStore signatureData *SignatureData @@ -370,12 +369,12 @@ func (o *Options) Validate() error { } for _, u := range o.SkipAuthRegex { - CompiledRegex, err := regexp.Compile(u) + compiledRegex, err := regexp.Compile(u) if err != nil { msgs = append(msgs, fmt.Sprintf("error compiling regex=%q %s", u, err)) continue } - o.CompiledRegex = append(o.CompiledRegex, CompiledRegex) + o.compiledRegex = append(o.compiledRegex, compiledRegex) } msgs = parseProviderInfo(o, msgs) diff --git a/options_test.go b/options_test.go index 42a9689..b14c9e4 100644 --- a/options_test.go +++ b/options_test.go @@ -165,7 +165,7 @@ func TestCompiledRegex(t *testing.T) { o.SkipAuthRegex = regexps assert.Equal(t, nil, o.Validate()) actual := make([]string, 0) - for _, regex := range o.CompiledRegex { + for _, regex := range o.compiledRegex { actual = append(actual, regex.String()) } assert.Equal(t, regexps, actual) diff --git a/pkg/apis/options/sessions.go b/pkg/apis/options/sessions.go index a12be7f..fd69d60 100644 --- a/pkg/apis/options/sessions.go +++ b/pkg/apis/options/sessions.go @@ -4,9 +4,9 @@ import "github.com/oauth2-proxy/oauth2-proxy/pkg/encryption" // SessionOptions contains configuration options for the SessionStore providers. type SessionOptions struct { - Type string `flag:"session-store-type" cfg:"session_store_type" env:"OAUTH2_PROXY_SESSION_STORE_TYPE"` - Cipher *encryption.Cipher - Redis RedisStoreOptions + Type string `flag:"session-store-type" cfg:"session_store_type" env:"OAUTH2_PROXY_SESSION_STORE_TYPE"` + Cipher *encryption.Cipher `cfg:",internal"` + Redis RedisStoreOptions `cfg:",squash"` } // CookieSessionStoreType is used to indicate the CookieSessionStore should be -- GitLab