Skip to content

Commit

Permalink
Merge pull request #148 from buzzfeed/default-allowed-groups
Browse files Browse the repository at this point in the history
proxy: default allowed groups
  • Loading branch information
jphines authored Jan 25, 2019
2 parents 4bff12f + 20ee9b9 commit 4fed3dc
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 63 deletions.
13 changes: 4 additions & 9 deletions internal/proxy/oauthproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,18 +245,13 @@ func NewReverseProxyHandler(reverseProxy *httputil.ReverseProxy, opts *Options,
if config.FlushInterval != 0 {
return NewStreamingHandler(upstreamProxy, opts, config), []string{"handler:streaming"}
}
return NewTimeoutHandler(upstreamProxy, opts, config), []string{"handler:timeout"}
return NewTimeoutHandler(upstreamProxy, config), []string{"handler:timeout"}
}

// NewTimeoutHandler creates a new handler with a configure timeout.
func NewTimeoutHandler(handler http.Handler, opts *Options, config *UpstreamConfig) http.Handler {
timeout := opts.DefaultUpstreamTimeout
if config.Timeout != 0 {
timeout = config.Timeout
}
timeoutMsg := fmt.Sprintf(
"%s failed to respond within the %s timeout period", config.Service, timeout)
return http.TimeoutHandler(handler, timeout, timeoutMsg)
func NewTimeoutHandler(handler http.Handler, config *UpstreamConfig) http.Handler {
timeoutMsg := fmt.Sprintf("%s failed to respond within the %s timeout period", config.Service, config.Timeout)
return http.TimeoutHandler(handler, config.Timeout, timeoutMsg)
}

// NewStreamingHandler creates a new handler capable of proxying a stream
Expand Down
43 changes: 17 additions & 26 deletions internal/proxy/oauthproxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,12 +511,13 @@ func generateTestUpstreamConfigs(to string) []*UpstreamConfig {
"root_domain": "dev",
"cluster": "sso",
}
defaultUpstreamOpts := &OptionsConfig{Timeout: time.Duration(1) * time.Second}
upstreamConfigs, err := loadServiceConfigs([]byte(fmt.Sprintf(`
- service: foo
default:
from: foo.sso.dev
to: %s
`, parsed)), "sso", "http", templateVars)
`, parsed)), "sso", "http", templateVars, defaultUpstreamOpts)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -692,6 +693,7 @@ func generateTestAuthSkipConfigs(to string) []*UpstreamConfig {
"root_domain": "dev",
"cluster": "sso",
}
defaultUpstreamOpts := &OptionsConfig{Timeout: time.Duration(1) * time.Second}
upstreamConfigs, err := loadServiceConfigs([]byte(fmt.Sprintf(`
- service: foo
default:
Expand All @@ -700,7 +702,7 @@ func generateTestAuthSkipConfigs(to string) []*UpstreamConfig {
options:
skip_auth_regex:
- ^\/allow$
`, parsed)), "sso", "http", templateVars)
`, parsed)), "sso", "http", templateVars, defaultUpstreamOpts)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -787,6 +789,7 @@ func generateTestSkipRequestSigningConfig(to string) []*UpstreamConfig {
"root_domain": "dev",
"cluster": "sso",
}
defaultUpstreamOpts := &OptionsConfig{Timeout: time.Duration(1) * time.Second}
upstreamConfigs, err := loadServiceConfigs([]byte(fmt.Sprintf(`
- service: foo
default:
Expand All @@ -796,7 +799,7 @@ func generateTestSkipRequestSigningConfig(to string) []*UpstreamConfig {
skip_request_signing: true
skip_auth_regex:
- ^.*$
`, parsed)), "sso", "http", templateVars)
`, parsed)), "sso", "http", templateVars, defaultUpstreamOpts)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -861,6 +864,7 @@ func generateMultiTestAuthSkipConfigs(toFoo, toBar string) []*UpstreamConfig {
"root_domain": "dev",
"cluster": "sso",
}
defaultUpstreamOpts := &OptionsConfig{Timeout: time.Duration(1) * time.Second}
upstreamConfigs, err := loadServiceConfigs([]byte(fmt.Sprintf(`
- service: foo
default:
Expand All @@ -873,7 +877,7 @@ func generateMultiTestAuthSkipConfigs(toFoo, toBar string) []*UpstreamConfig {
default:
from: bar.sso.dev
to: %s
`, parsedFoo, parsedBar)), "sso", "http", templateVars)
`, parsedFoo, parsedBar)), "sso", "http", templateVars, defaultUpstreamOpts)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -968,12 +972,13 @@ func generateSignatureTestUpstreamConfigs(key, to string) []*UpstreamConfig {
"cluster": "sso",
"foo_signing_key": key,
}
defaultUpstreamOpts := &OptionsConfig{Timeout: time.Duration(1) * time.Second}
upstreamConfigs, err := loadServiceConfigs([]byte(fmt.Sprintf(`
- service: foo
default:
from: foo.{{cluster}}.{{root_domain}}
to: %s
`, parsed)), "sso", "http", templateVars)
`, parsed)), "sso", "http", templateVars, defaultUpstreamOpts)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -1747,6 +1752,7 @@ func makeUpstreamConfigWithHeaderOverrides(overrides map[string]string) []*Upstr
"root_domain": "dev",
"cluster": "sso",
}
defaultUpstreamOpts := &OptionsConfig{Timeout: time.Duration(1) * time.Second}
upstreamConfigs, err := loadServiceConfigs([]byte(fmt.Sprintf(`
- service: foo
default:
Expand All @@ -1757,7 +1763,7 @@ func makeUpstreamConfigWithHeaderOverrides(overrides map[string]string) []*Upstr
default:
from: bar.sso.dev
to: bar-internal.sso.dev
`)), "sso", "http", templateVars)
`)), "sso", "http", templateVars, defaultUpstreamOpts)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -2035,7 +2041,6 @@ func TestTimeoutHandler(t *testing.T) {
testCases := []struct {
name string
config *UpstreamConfig
defaultTimeout time.Duration
globalTimeout time.Duration
ExpectedStatusCode int
ExpectedBody string
Expand All @@ -2046,7 +2051,6 @@ func TestTimeoutHandler(t *testing.T) {
config: &UpstreamConfig{
Timeout: time.Duration(100) * time.Millisecond,
},
defaultTimeout: time.Duration(100) * time.Millisecond,
globalTimeout: time.Duration(100) * time.Millisecond,
ExpectedStatusCode: 200,
ExpectedBody: "OK",
Expand All @@ -2057,17 +2061,6 @@ func TestTimeoutHandler(t *testing.T) {
Service: "service-test",
Timeout: time.Duration(10) * time.Millisecond,
},
defaultTimeout: time.Duration(100) * time.Millisecond,
globalTimeout: time.Duration(100) * time.Millisecond,
ExpectedStatusCode: 503,
ExpectedBody: fmt.Sprintf("service-test failed to respond within the 10ms timeout period"),
},
{
name: "times out using default upstream config timeout",
config: &UpstreamConfig{
Service: "service-test",
},
defaultTimeout: time.Duration(10) * time.Millisecond,
globalTimeout: time.Duration(100) * time.Millisecond,
ExpectedStatusCode: 503,
ExpectedBody: fmt.Sprintf("service-test failed to respond within the 10ms timeout period"),
Expand All @@ -2076,25 +2069,22 @@ func TestTimeoutHandler(t *testing.T) {
name: "times out using global write timeout",
config: &UpstreamConfig{
Service: "service-test",
Timeout: time.Duration(100) * time.Millisecond,
},
defaultTimeout: time.Duration(100) * time.Millisecond,
globalTimeout: time.Duration(10) * time.Millisecond,
globalTimeout: time.Duration(10) * time.Millisecond,
ExpectedErr: &url.Error{
Err: io.EOF,
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
opts := NewOptions()
opts.DefaultUpstreamTimeout = tc.defaultTimeout

baseHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
timer := time.NewTimer(time.Duration(50) * time.Millisecond)
<-timer.C
w.Write([]byte("OK"))
})
timeoutHandler := NewTimeoutHandler(baseHandler, opts, tc.config)
timeoutHandler := NewTimeoutHandler(baseHandler, tc.config)

srv := httptest.NewUnstartedServer(timeoutHandler)
srv.Config.WriteTimeout = tc.globalTimeout
Expand Down Expand Up @@ -2142,13 +2132,14 @@ func generateTestRewriteUpstreamConfigs(fromRegex, toTemplate string) []*Upstrea
"root_domain": "dev",
"cluster": "sso",
}
defaultUpstreamOpts := &OptionsConfig{Timeout: time.Duration(1) * time.Second}
upstreamConfigs, err := loadServiceConfigs([]byte(fmt.Sprintf(`
- service: foo
default:
from: %s
to: %s
type: rewrite
`, fromRegex, toTemplate)), "sso", "http", templateVars)
`, fromRegex, toTemplate)), "sso", "http", templateVars, defaultUpstreamOpts)
if err != nil {
panic(err)
}
Expand Down
17 changes: 13 additions & 4 deletions internal/proxy/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
// Scheme - the default scheme, used for upstream configs
// SkipAuthPreflight - will skip authentication for OPTIONS requests, default false
// EmailDomains - csv list of emails with the specified domain to authenticate. Use * to authenticate any email
// DefaultAllowedGroups - csv list of default allowed groups that are applied to authorize access to upstreams. Will be overriden by groups specified in upstream configs.
// ClientID - the OAuth Client ID: ie: "123456.apps.googleusercontent.com"
// ClientSecret - The OAuth Client Secret
// DefaultUpstreamTimeout - the default time period to wait for a response from an upstream
Expand Down Expand Up @@ -57,9 +58,11 @@ type Options struct {

SkipAuthPreflight bool `envconfig:"SKIP_AUTH_PREFLIGHT"`

EmailDomains []string `envconfig:"EMAIL_DOMAIN"`
ClientID string `envconfig:"CLIENT_ID"`
ClientSecret string `envconfig:"CLIENT_SECRET"`
EmailDomains []string `envconfig:"EMAIL_DOMAIN"`
DefaultAllowedGroups []string `envconfig:"DEFAULT_ALLOWED_GROUPS"`

ClientID string `envconfig:"CLIENT_ID"`
ClientSecret string `envconfig:"CLIENT_SECRET"`

DefaultUpstreamTimeout time.Duration `envconfig:"DEFAULT_UPSTREAM_TIMEOUT" default:"10s"`

Expand Down Expand Up @@ -112,6 +115,7 @@ func NewOptions() *Options {
SkipAuthPreflight: false,
RequestLogging: true,
DefaultUpstreamTimeout: time.Duration(1) * time.Second,
DefaultAllowedGroups: []string{},
PassAccessToken: false,
}
}
Expand Down Expand Up @@ -176,7 +180,12 @@ func (o *Options) Validate() error {
templateVars = o.testTemplateVars
}

o.upstreamConfigs, err = loadServiceConfigs(rawBytes, o.Cluster, o.Scheme, templateVars)
defaultUpstreamOptionsConfig := &OptionsConfig{
AllowedGroups: o.DefaultAllowedGroups,
Timeout: o.DefaultUpstreamTimeout,
}

o.upstreamConfigs, err = loadServiceConfigs(rawBytes, o.Cluster, o.Scheme, templateVars, defaultUpstreamOptionsConfig)
if err != nil {
msgs = append(msgs, fmt.Sprintf("error parsing upstream configs file %s", err))
}
Expand Down
42 changes: 29 additions & 13 deletions internal/proxy/proxy_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func (e *ErrParsingConfig) Error() string {
return e.Message
}

func loadServiceConfigs(raw []byte, cluster, scheme string, configVars map[string]string) ([]*UpstreamConfig, error) {
func loadServiceConfigs(raw []byte, cluster, scheme string, configVars map[string]string, defaultOpts *OptionsConfig) ([]*UpstreamConfig, error) {
// We fill in all templated values and resolve overrides
rawTemplated := resolveTemplates(raw, configVars)

Expand Down Expand Up @@ -181,7 +181,7 @@ func loadServiceConfigs(raw []byte, cluster, scheme string, configVars map[strin

// We validate OptionsConfig
for _, proxy := range configs {
err := parseOptionsConfig(proxy)
err := parseOptionsConfig(proxy, defaultOpts)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -347,13 +347,29 @@ func resolveTemplates(raw []byte, templateVars map[string]string) []byte {
return []byte(rawString)
}

func parseOptionsConfig(proxy *UpstreamConfig) error {
if proxy.RouteConfig.Options == nil {
return nil
func parseOptionsConfig(proxy *UpstreamConfig, defaultOpts *OptionsConfig) error {
dst := &OptionsConfig{}

if defaultOpts == nil {
defaultOpts = &OptionsConfig{}
}

// Override empty with defaults
err := mergo.Merge(dst, *defaultOpts, mergo.WithOverride)
if err != nil {
return err
}

// Override defaults with specified
if proxy.RouteConfig.Options != nil {
err := mergo.Merge(dst, proxy.RouteConfig.Options, mergo.WithOverride)
if err != nil {
return err
}
}

// We compile all the regexes in SkipAuth Regex
for _, uncompiled := range proxy.RouteConfig.Options.SkipAuthRegex {
for _, uncompiled := range dst.SkipAuthRegex {
compiled, err := regexp.Compile(uncompiled)
if err != nil {
return &ErrParsingConfig{
Expand All @@ -364,13 +380,13 @@ func parseOptionsConfig(proxy *UpstreamConfig) error {
proxy.SkipAuthCompiledRegex = append(proxy.SkipAuthCompiledRegex, compiled)
}

proxy.AllowedGroups = proxy.RouteConfig.Options.AllowedGroups
proxy.Timeout = proxy.RouteConfig.Options.Timeout
proxy.FlushInterval = proxy.RouteConfig.Options.FlushInterval
proxy.HeaderOverrides = proxy.RouteConfig.Options.HeaderOverrides
proxy.TLSSkipVerify = proxy.RouteConfig.Options.TLSSkipVerify
proxy.PreserveHost = proxy.RouteConfig.Options.PreserveHost
proxy.SkipRequestSigning = proxy.RouteConfig.Options.SkipRequestSigning
proxy.AllowedGroups = dst.AllowedGroups
proxy.Timeout = dst.Timeout
proxy.FlushInterval = dst.FlushInterval
proxy.HeaderOverrides = dst.HeaderOverrides
proxy.TLSSkipVerify = dst.TLSSkipVerify
proxy.PreserveHost = dst.PreserveHost
proxy.SkipRequestSigning = dst.SkipRequestSigning

proxy.RouteConfig.Options = nil

Expand Down
Loading

0 comments on commit 4fed3dc

Please sign in to comment.