From 71dc70222b705acf687bec97c1469cc363d3329f Mon Sep 17 00:00:00 2001 From: Joel Speed Date: Sun, 12 Jul 2020 16:47:25 +0100 Subject: [PATCH] Break legacy upstream options into LegacyUpstreams struct --- pkg/apis/options/legacy_options.go | 49 +++++++++++++++++-------- pkg/apis/options/legacy_options_test.go | 20 +++++++--- pkg/apis/options/options.go | 7 +--- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/pkg/apis/options/legacy_options.go b/pkg/apis/options/legacy_options.go index b0198c9c..6d7c7185 100644 --- a/pkg/apis/options/legacy_options.go +++ b/pkg/apis/options/legacy_options.go @@ -7,31 +7,30 @@ import ( "time" "github.com/oauth2-proxy/oauth2-proxy/pkg/logger" + "github.com/spf13/pflag" ) type LegacyOptions struct { // Legacy options related to upstream servers - LegacyFlushInterval time.Duration `flag:"flush-interval" cfg:"flush_interval"` - LegacyPassHostHeader bool `flag:"pass-host-header" cfg:"pass_host_header"` - LegacyProxyWebSockets bool `flag:"proxy-websockets" cfg:"proxy_websockets"` - LegacySSLUpstreamInsecureSkipVerify bool `flag:"ssl-upstream-insecure-skip-verify" cfg:"ssl_upstream_insecure_skip_verify"` - LegacyUpstreams []string `flag:"upstream" cfg:"upstreams"` + LegacyUpstreams LegacyUpstreams `cfg:",squash"` Options Options `cfg:",squash"` } func NewLegacyOptions() *LegacyOptions { return &LegacyOptions{ - LegacyPassHostHeader: true, - LegacyProxyWebSockets: true, - LegacyFlushInterval: time.Duration(1) * time.Second, + LegacyUpstreams: LegacyUpstreams{ + PassHostHeader: true, + ProxyWebSockets: true, + FlushInterval: time.Duration(1) * time.Second, + }, Options: *NewOptions(), } } func (l *LegacyOptions) ToOptions() (*Options, error) { - upstreams, err := convertLegacyUpstreams(l.LegacyUpstreams, l.LegacySSLUpstreamInsecureSkipVerify, l.LegacyPassHostHeader, l.LegacyProxyWebSockets, l.LegacyFlushInterval) + upstreams, err := l.LegacyUpstreams.convert() if err != nil { return nil, fmt.Errorf("error converting upstreams: %v", err) } @@ -40,10 +39,30 @@ func (l *LegacyOptions) ToOptions() (*Options, error) { return &l.Options, nil } -func convertLegacyUpstreams(upstreamStrings []string, skipVerify, passHostHeader, proxyWebSockets bool, flushInterval time.Duration) (Upstreams, error) { +type LegacyUpstreams struct { + FlushInterval time.Duration `flag:"flush-interval" cfg:"flush_interval"` + PassHostHeader bool `flag:"pass-host-header" cfg:"pass_host_header"` + ProxyWebSockets bool `flag:"proxy-websockets" cfg:"proxy_websockets"` + SSLUpstreamInsecureSkipVerify bool `flag:"ssl-upstream-insecure-skip-verify" cfg:"ssl_upstream_insecure_skip_verify"` + Upstreams []string `flag:"upstream" cfg:"upstreams"` +} + +func legacyUpstreamsFlagSet() *pflag.FlagSet { + flagSet := pflag.NewFlagSet("upstreams", pflag.ExitOnError) + + flagSet.Duration("flush-interval", time.Duration(1)*time.Second, "period between response flushing when streaming responses") + flagSet.Bool("pass-host-header", true, "pass the request Host Header to upstream") + flagSet.Bool("proxy-websockets", true, "enables WebSocket proxying") + flagSet.Bool("ssl-upstream-insecure-skip-verify", false, "skip validation of certificates presented when using HTTPS upstreams") + flagSet.StringSlice("upstream", []string{}, "the http url(s) of the upstream endpoint, file:// paths for static files or static:// for static response. Routing is based on the path") + + return flagSet +} + +func (l *LegacyUpstreams) convert() (Upstreams, error) { upstreams := Upstreams{} - for _, upstreamString := range upstreamStrings { + for _, upstreamString := range l.Upstreams { u, err := url.Parse(upstreamString) if err != nil { return nil, fmt.Errorf("could not parse upstream %q: %v", upstreamString, err) @@ -57,10 +76,10 @@ func convertLegacyUpstreams(upstreamStrings []string, skipVerify, passHostHeader ID: u.Path, Path: u.Path, URI: upstreamString, - InsecureSkipTLSVerify: skipVerify, - PassHostHeader: passHostHeader, - ProxyWebSockets: proxyWebSockets, - FlushInterval: &flushInterval, + InsecureSkipTLSVerify: l.SSLUpstreamInsecureSkipVerify, + PassHostHeader: l.PassHostHeader, + ProxyWebSockets: l.ProxyWebSockets, + FlushInterval: &l.FlushInterval, } switch u.Scheme { diff --git a/pkg/apis/options/legacy_options_test.go b/pkg/apis/options/legacy_options_test.go index 0e221749..3046e4a1 100644 --- a/pkg/apis/options/legacy_options_test.go +++ b/pkg/apis/options/legacy_options_test.go @@ -17,11 +17,11 @@ var _ = Describe("Legacy Options", func() { // Set upstreams and related options to test their conversion flushInterval := 5 * time.Second - legacyOpts.LegacyFlushInterval = flushInterval - legacyOpts.LegacyPassHostHeader = true - legacyOpts.LegacyProxyWebSockets = true - legacyOpts.LegacySSLUpstreamInsecureSkipVerify = true - legacyOpts.LegacyUpstreams = []string{"http://foo.bar/baz", "file://var/lib/website#/bar"} + legacyOpts.LegacyUpstreams.FlushInterval = flushInterval + legacyOpts.LegacyUpstreams.PassHostHeader = true + legacyOpts.LegacyUpstreams.ProxyWebSockets = true + legacyOpts.LegacyUpstreams.SSLUpstreamInsecureSkipVerify = true + legacyOpts.LegacyUpstreams.Upstreams = []string{"http://foo.bar/baz", "file://var/lib/website#/bar"} opts.UpstreamServers = Upstreams{ { @@ -133,7 +133,15 @@ var _ = Describe("Legacy Options", func() { DescribeTable("convertLegacyUpstreams", func(o *convertUpstreamsTableInput) { - upstreams, err := convertLegacyUpstreams(o.upstreamStrings, skipVerify, passHostHeader, proxyWebSockets, flushInterval) + legacyUpstreams := LegacyUpstreams{ + Upstreams: o.upstreamStrings, + SSLUpstreamInsecureSkipVerify: skipVerify, + PassHostHeader: passHostHeader, + ProxyWebSockets: proxyWebSockets, + FlushInterval: flushInterval, + } + + upstreams, err := legacyUpstreams.convert() if o.errMsg != "" { Expect(err).To(HaveOccurred()) diff --git a/pkg/apis/options/options.go b/pkg/apis/options/options.go index 325c263c..e37dc63b 100644 --- a/pkg/apis/options/options.go +++ b/pkg/apis/options/options.go @@ -4,7 +4,6 @@ import ( "crypto" "net/url" "regexp" - "time" oidc "github.com/coreos/go-oidc" ipapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/ip" @@ -185,14 +184,12 @@ func NewFlagSet() *pflag.FlagSet { flagSet.String("tls-key-file", "", "path to private key file") flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"") flagSet.Bool("set-xauthrequest", false, "set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode)") - flagSet.StringSlice("upstream", []string{}, "the http url(s) of the upstream endpoint, file:// paths for static files or static:// for static response. Routing is based on the path") flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream") flagSet.Bool("set-basic-auth", false, "set HTTP Basic Auth information in response (useful in Nginx auth_request mode)") flagSet.Bool("prefer-email-to-user", false, "Prefer to use the Email address as the Username when passing information to upstream. Will only use Username if Email is unavailable, eg. htaccess authentication. Used in conjunction with -pass-basic-auth and -pass-user-headers") flagSet.Bool("pass-user-headers", true, "pass X-Forwarded-User and X-Forwarded-Email information to upstream") flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header") flagSet.Bool("pass-access-token", false, "pass OAuth access_token to upstream via X-Forwarded-Access-Token header") - flagSet.Bool("pass-host-header", true, "pass the request Host Header to upstream") flagSet.Bool("pass-authorization-header", false, "pass the Authorization Header to upstream") flagSet.Bool("set-authorization-header", false, "set Authorization response headers (useful in Nginx auth_request mode)") flagSet.StringSlice("skip-auth-regex", []string{}, "bypass authentication for requests path's that match (may be given multiple times)") @@ -200,8 +197,6 @@ func NewFlagSet() *pflag.FlagSet { flagSet.Bool("skip-provider-button", false, "will skip sign-in-page to directly reach the next step: oauth/start") flagSet.Bool("skip-auth-preflight", false, "will skip authentication for OPTIONS requests") flagSet.Bool("ssl-insecure-skip-verify", false, "skip validation of certificates presented when using HTTPS providers") - flagSet.Bool("ssl-upstream-insecure-skip-verify", false, "skip validation of certificates presented when using HTTPS upstreams") - flagSet.Duration("flush-interval", time.Duration(1)*time.Second, "period between response flushing when streaming responses") flagSet.Bool("skip-jwt-bearer-tokens", false, "will skip requests that have verified JWT bearer tokens (default false)") flagSet.StringSlice("extra-jwt-issuers", []string{}, "if skip-jwt-bearer-tokens is set, a list of extra JWT issuer=audience pairs (where the issuer URL has a .well-known/openid-configuration or a .well-known/jwks.json)") @@ -232,7 +227,6 @@ func NewFlagSet() *pflag.FlagSet { flagSet.String("proxy-prefix", "/oauth2", "the url root path that this proxy should be nested under (e.g. //sign_in)") flagSet.String("ping-path", "/ping", "the ping endpoint that can be used for basic health checks") flagSet.String("ping-user-agent", "", "special User-Agent that will be used for basic health checks") - flagSet.Bool("proxy-websockets", true, "enables WebSocket proxying") flagSet.String("session-store-type", "cookie", "the session storage provider to use") flagSet.Bool("session-cookie-minimal", false, "strip OAuth tokens from cookie session stores if they aren't needed (cookie session store only)") flagSet.String("redis-connection-url", "", "URL of redis server for redis session storage (eg: redis://HOST[:PORT])") @@ -272,6 +266,7 @@ func NewFlagSet() *pflag.FlagSet { flagSet.AddFlagSet(cookieFlagSet()) flagSet.AddFlagSet(loggingFlagSet()) + flagSet.AddFlagSet(legacyUpstreamsFlagSet()) return flagSet }