introduce mapstructure decoder for yaml parsing
remove color output in tests for better readability in github actions bugfix: remove google as default provider for alpha options fix conversion flow for toml to yaml revert ginkgo color deactivation revert claim- and secret source back to pointers regenerate alpha config
This commit is contained in:
		
							parent
							
								
									8afb047e01
								
							
						
					
					
						commit
						31a4c34726
					
				|  | @ -37,7 +37,7 @@ linters: | ||||||
|       - linters: |       - linters: | ||||||
|           - revive |           - revive | ||||||
|         path: _test\.go |         path: _test\.go | ||||||
|         text: 'dot-imports:' |         text: "dot-imports:" | ||||||
|       # # If we have tests in shared test folders, these can be less strictly linted |       # # If we have tests in shared test folders, these can be less strictly linted | ||||||
|       - linters: |       - linters: | ||||||
|           - bodyclose |           - bodyclose | ||||||
|  |  | ||||||
|  | @ -204,16 +204,6 @@ ClaimSource allows loading a header value from a claim within the session | ||||||
| | `prefix` | _string_ | Prefix is an optional prefix that will be prepended to the value of the<br/>claim if it is non-empty. | | | `prefix` | _string_ | Prefix is an optional prefix that will be prepended to the value of the<br/>claim if it is non-empty. | | ||||||
| | `basicAuthPassword` | _[SecretSource](#secretsource)_ | BasicAuthPassword converts this claim into a basic auth header.<br/>Note the value of claim will become the basic auth username and the<br/>basicAuthPassword will be used as the password value. | | | `basicAuthPassword` | _[SecretSource](#secretsource)_ | BasicAuthPassword converts this claim into a basic auth header.<br/>Note the value of claim will become the basic auth username and the<br/>basicAuthPassword will be used as the password value. | | ||||||
| 
 | 
 | ||||||
| ### Duration |  | ||||||
| #### (`string` alias) |  | ||||||
| 
 |  | ||||||
| (**Appears on:** [Upstream](#upstream)) |  | ||||||
| 
 |  | ||||||
| Duration is as string representation of a period of time. |  | ||||||
| A duration string is a is a possibly signed sequence of decimal numbers, |  | ||||||
| each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". |  | ||||||
| Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". |  | ||||||
| 
 |  | ||||||
| ### GitHubOptions | ### GitHubOptions | ||||||
| 
 | 
 | ||||||
| (**Appears on:** [Provider](#provider)) | (**Appears on:** [Provider](#provider)) | ||||||
|  | @ -275,7 +265,7 @@ make up the header value | ||||||
| 
 | 
 | ||||||
| | Field | Type | Description | | | Field | Type | Description | | ||||||
| | ----- | ---- | ----------- | | | ----- | ---- | ----------- | | ||||||
| | `value` | _[]byte_ | Value expects a base64 encoded string value. | | | `value` | _string_ | Value expects a base64 encoded string value. | | ||||||
| | `fromEnv` | _string_ | FromEnv expects the name of an environment variable. | | | `fromEnv` | _string_ | FromEnv expects the name of an environment variable. | | ||||||
| | `fromFile` | _string_ | FromFile expects a path to a file containing the secret value. | | | `fromFile` | _string_ | FromFile expects a path to a file containing the secret value. | | ||||||
| | `claim` | _string_ | Claim is the name of the claim in the session that the value should be<br/>loaded from. Available claims: `access_token` `id_token` `created_at`<br/>`expires_on` `refresh_token` `email` `user` `groups` `preferred_username`. | | | `claim` | _string_ | Claim is the name of the claim in the session that the value should be<br/>loaded from. Available claims: `access_token` `id_token` `created_at`<br/>`expires_on` `refresh_token` `email` `user` `groups` `preferred_username`. | | ||||||
|  | @ -487,7 +477,7 @@ Only one source within the struct should be defined at any time. | ||||||
| 
 | 
 | ||||||
| | Field | Type | Description | | | Field | Type | Description | | ||||||
| | ----- | ---- | ----------- | | | ----- | ---- | ----------- | | ||||||
| | `value` | _[]byte_ | Value expects a base64 encoded string value. | | | `value` | _string_ | Value expects a base64 encoded string value. | | ||||||
| | `fromEnv` | _string_ | FromEnv expects the name of an environment variable. | | | `fromEnv` | _string_ | FromEnv expects the name of an environment variable. | | ||||||
| | `fromFile` | _string_ | FromFile expects a path to a file containing the secret value. | | | `fromFile` | _string_ | FromFile expects a path to a file containing the secret value. | | ||||||
| 
 | 
 | ||||||
|  | @ -547,10 +537,10 @@ Requests will be proxied to this upstream if the path matches the request path. | ||||||
| | `insecureSkipTLSVerify` | _bool_ | InsecureSkipTLSVerify will skip TLS verification of upstream HTTPS hosts.<br/>This option is insecure and will allow potential Man-In-The-Middle attacks<br/>between OAuth2 Proxy and the upstream server.<br/>Defaults to false. | | | `insecureSkipTLSVerify` | _bool_ | InsecureSkipTLSVerify will skip TLS verification of upstream HTTPS hosts.<br/>This option is insecure and will allow potential Man-In-The-Middle attacks<br/>between OAuth2 Proxy and the upstream server.<br/>Defaults to false. | | ||||||
| | `static` | _bool_ | Static will make all requests to this upstream have a static response.<br/>The response will have a body of "Authenticated" and a response code<br/>matching StaticCode.<br/>If StaticCode is not set, the response will return a 200 response. | | | `static` | _bool_ | Static will make all requests to this upstream have a static response.<br/>The response will have a body of "Authenticated" and a response code<br/>matching StaticCode.<br/>If StaticCode is not set, the response will return a 200 response. | | ||||||
| | `staticCode` | _int_ | StaticCode determines the response code for the Static response.<br/>This option can only be used with Static enabled. | | | `staticCode` | _int_ | StaticCode determines the response code for the Static response.<br/>This option can only be used with Static enabled. | | ||||||
| | `flushInterval` | _[Duration](#duration)_ | FlushInterval is the period between flushing the response buffer when<br/>streaming response from the upstream.<br/>Defaults to 1 second. | | | `flushInterval` | _duration_ | FlushInterval is the period between flushing the response buffer when<br/>streaming response from the upstream.<br/>Defaults to 1 second. | | ||||||
| | `passHostHeader` | _bool_ | PassHostHeader determines whether the request host header should be proxied<br/>to the upstream server.<br/>Defaults to true. | | | `passHostHeader` | _bool_ | PassHostHeader determines whether the request host header should be proxied<br/>to the upstream server.<br/>Defaults to true. | | ||||||
| | `proxyWebSockets` | _bool_ | ProxyWebSockets enables proxying of websockets to upstream servers<br/>Defaults to true. | | | `proxyWebSockets` | _bool_ | ProxyWebSockets enables proxying of websockets to upstream servers<br/>Defaults to true. | | ||||||
| | `timeout` | _[Duration](#duration)_ | Timeout is the maximum duration the server will wait for a response from the upstream server.<br/>Defaults to 30 seconds. | | | `timeout` | _duration_ | Timeout is the maximum duration the server will wait for a response from the upstream server.<br/>Defaults to 30 seconds. | | ||||||
| | `disableKeepAlives` | _bool_ | DisableKeepAlives disables HTTP keep-alive connections to the upstream server.<br/>Defaults to false. | | | `disableKeepAlives` | _bool_ | DisableKeepAlives disables HTTP keep-alive connections to the upstream server.<br/>Defaults to false. | | ||||||
| 
 | 
 | ||||||
| ### UpstreamConfig | ### UpstreamConfig | ||||||
|  |  | ||||||
							
								
								
									
										35
									
								
								main.go
								
								
								
								
							
							
						
						
									
										35
									
								
								main.go
								
								
								
								
							|  | @ -67,12 +67,17 @@ func main() { | ||||||
| // loadConfiguration will load in the user's configuration.
 | // loadConfiguration will load in the user's configuration.
 | ||||||
| // It will either load the alpha configuration (if alphaConfig is given)
 | // It will either load the alpha configuration (if alphaConfig is given)
 | ||||||
| // or the legacy configuration.
 | // or the legacy configuration.
 | ||||||
| func loadConfiguration(config, alphaConfig string, extraFlags *pflag.FlagSet, args []string) (*options.Options, error) { | func loadConfiguration(config, yamlConfig string, extraFlags *pflag.FlagSet, args []string) (*options.Options, error) { | ||||||
| 	if alphaConfig != "" { | 	opts, err := loadLegacyOptions(config, extraFlags, args) | ||||||
| 		logger.Printf("WARNING: You are using alpha configuration. The structure in this configuration file may change without notice. You MUST remove conflicting options from your existing configuration.") | 	if err != nil { | ||||||
| 		return loadAlphaOptions(config, alphaConfig, extraFlags, args) | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	return loadLegacyOptions(config, extraFlags, args) | 
 | ||||||
|  | 	if yamlConfig != "" { | ||||||
|  | 		logger.Printf("WARNING: You are using alpha configuration. The structure in this configuration file may change without notice. You MUST remove conflicting options from your existing configuration.") | ||||||
|  | 		return loadYamlOptions(yamlConfig, config, extraFlags, args) | ||||||
|  | 	} | ||||||
|  | 	return opts, err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // loadLegacyOptions loads the old toml options using the legacy flagset
 | // loadLegacyOptions loads the old toml options using the legacy flagset
 | ||||||
|  | @ -97,17 +102,17 @@ func loadLegacyOptions(config string, extraFlags *pflag.FlagSet, args []string) | ||||||
| 	return opts, nil | 	return opts, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // loadAlphaOptions loads the old style config excluding options converted to
 | // loadYamlOptions loads the old style config excluding options converted to
 | ||||||
| // the new alpha format, then merges the alpha options, loaded from YAML,
 | // the new alpha format, then merges the alpha options, loaded from YAML,
 | ||||||
| // into the core configuration.
 | // into the core configuration.
 | ||||||
| func loadAlphaOptions(config, alphaConfig string, extraFlags *pflag.FlagSet, args []string) (*options.Options, error) { | func loadYamlOptions(yamlConfig, config string, extraFlags *pflag.FlagSet, args []string) (*options.Options, error) { | ||||||
| 	opts, err := loadOptions(config, extraFlags, args) | 	opts, err := loadOptions(config, extraFlags, args) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to load core options: %v", err) | 		return nil, fmt.Errorf("failed to load core options: %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	alphaOpts := &options.AlphaOptions{} | 	alphaOpts := options.NewAlphaOptions(opts) | ||||||
| 	if err := options.LoadYAML(alphaConfig, alphaOpts); err != nil { | 	if err := options.LoadYAML(yamlConfig, alphaOpts); err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to load alpha options: %v", err) | 		return nil, fmt.Errorf("failed to load alpha options: %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -137,10 +142,16 @@ func loadOptions(config string, extraFlags *pflag.FlagSet, args []string) (*opti | ||||||
| // printConvertedConfig extracts alpha options from the loaded configuration
 | // printConvertedConfig extracts alpha options from the loaded configuration
 | ||||||
| // and renders these to stdout in YAML format.
 | // and renders these to stdout in YAML format.
 | ||||||
| func printConvertedConfig(opts *options.Options) error { | func printConvertedConfig(opts *options.Options) error { | ||||||
| 	alphaConfig := &options.AlphaOptions{} | 	alphaConfig := options.NewAlphaOptions(opts) | ||||||
| 	alphaConfig.ExtractFrom(opts) |  | ||||||
| 
 | 
 | ||||||
| 	data, err := yaml.Marshal(alphaConfig) | 	// Generic interface for loading arbitrary yaml structure
 | ||||||
|  | 	var buffer map[string]interface{} | ||||||
|  | 
 | ||||||
|  | 	if err := options.Decode(alphaConfig, &buffer); err != nil { | ||||||
|  | 		return fmt.Errorf("unable to decode alpha config into interface: %w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	data, err := yaml.Marshal(buffer) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("unable to marshal config: %v", err) | 		return fmt.Errorf("unable to marshal config: %v", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
							
								
								
									
										39
									
								
								main_test.go
								
								
								
								
							
							
						
						
									
										39
									
								
								main_test.go
								
								
								
								
							|  | @ -43,29 +43,35 @@ upstreamConfig: | ||||||
| injectRequestHeaders: | injectRequestHeaders: | ||||||
| - name: Authorization | - name: Authorization | ||||||
|   values: |   values: | ||||||
|   - claim: user |   - claimSource: | ||||||
|     prefix: "Basic " |       claim: user | ||||||
|     basicAuthPassword: |       prefix: "Basic " | ||||||
|       value: c3VwZXItc2VjcmV0LXBhc3N3b3Jk |       basicAuthPassword: | ||||||
|  |         value: super-secret-password | ||||||
| - name: X-Forwarded-Groups | - name: X-Forwarded-Groups | ||||||
|   values: |   values: | ||||||
|   - claim: groups |   - claimSource: | ||||||
|  |       claim: groups | ||||||
| - name: X-Forwarded-User | - name: X-Forwarded-User | ||||||
|   values: |   values: | ||||||
|   - claim: user |   - claimSource: | ||||||
|  |       claim: user | ||||||
| - name: X-Forwarded-Email | - name: X-Forwarded-Email | ||||||
|   values: |   values: | ||||||
|   - claim: email |   - claimSource: | ||||||
|  |       claim: email | ||||||
| - name: X-Forwarded-Preferred-Username | - name: X-Forwarded-Preferred-Username | ||||||
|   values: |   values: | ||||||
|   - claim: preferred_username |   - claimSource: | ||||||
|  |       claim: preferred_username | ||||||
| injectResponseHeaders: | injectResponseHeaders: | ||||||
| - name: Authorization | - name: Authorization | ||||||
|   values: |   values: | ||||||
|   - claim: user |   - claimSource: | ||||||
|     prefix: "Basic " |       claim: user | ||||||
|     basicAuthPassword: |       prefix: "Basic " | ||||||
|       value: c3VwZXItc2VjcmV0LXBhc3N3b3Jk |       basicAuthPassword: | ||||||
|  |         value: super-secret-password | ||||||
| server: | server: | ||||||
|   bindAddress: "127.0.0.1:4180" |   bindAddress: "127.0.0.1:4180" | ||||||
| providers: | providers: | ||||||
|  | @ -100,9 +106,8 @@ redirect_url="http://localhost:4180/oauth2/callback" | ||||||
| 		return &b | 		return &b | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	durationPtr := func(d time.Duration) *options.Duration { | 	durationPtr := func(d time.Duration) *time.Duration { | ||||||
| 		du := options.Duration(d) | 		return &d | ||||||
| 		return &du |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	testExpectedOptions := func() *options.Options { | 	testExpectedOptions := func() *options.Options { | ||||||
|  | @ -136,7 +141,7 @@ redirect_url="http://localhost:4180/oauth2/callback" | ||||||
| 						Claim:  "user", | 						Claim:  "user", | ||||||
| 						Prefix: "Basic ", | 						Prefix: "Basic ", | ||||||
| 						BasicAuthPassword: &options.SecretSource{ | 						BasicAuthPassword: &options.SecretSource{ | ||||||
| 							Value: []byte("super-secret-password"), | 							Value: "super-secret-password", | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
|  | @ -226,7 +231,7 @@ redirect_url="http://localhost:4180/oauth2/callback" | ||||||
| 
 | 
 | ||||||
| 			opts, err := loadConfiguration(configFileName, alphaConfigFileName, extraFlags, in.args) | 			opts, err := loadConfiguration(configFileName, alphaConfigFileName, extraFlags, in.args) | ||||||
| 			if in.expectedErr != nil { | 			if in.expectedErr != nil { | ||||||
| 				Expect(err).To(MatchError(in.expectedErr.Error())) | 				Expect(err).To(MatchError(ContainSubstring(in.expectedErr.Error()))) | ||||||
| 			} else { | 			} else { | ||||||
| 				Expect(err).ToNot(HaveOccurred()) | 				Expect(err).ToNot(HaveOccurred()) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | @ -215,7 +215,7 @@ func TestBasicAuthPassword(t *testing.T) { | ||||||
| 					ClaimSource: &options.ClaimSource{ | 					ClaimSource: &options.ClaimSource{ | ||||||
| 						Claim: "email", | 						Claim: "email", | ||||||
| 						BasicAuthPassword: &options.SecretSource{ | 						BasicAuthPassword: &options.SecretSource{ | ||||||
| 							Value: []byte(basicAuthPassword), | 							Value: basicAuthPassword, | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
|  | @ -1282,7 +1282,7 @@ func TestAuthOnlyEndpointSetBasicAuthTrueRequestHeaders(t *testing.T) { | ||||||
| 					ClaimSource: &options.ClaimSource{ | 					ClaimSource: &options.ClaimSource{ | ||||||
| 						Claim: "user", | 						Claim: "user", | ||||||
| 						BasicAuthPassword: &options.SecretSource{ | 						BasicAuthPassword: &options.SecretSource{ | ||||||
| 							Value: []byte("This is a secure password"), | 							Value: "This is a secure password", | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
|  | @ -2044,7 +2044,7 @@ func baseTestOptions() *options.Options { | ||||||
| 					ClaimSource: &options.ClaimSource{ | 					ClaimSource: &options.ClaimSource{ | ||||||
| 						Claim: "user", | 						Claim: "user", | ||||||
| 						BasicAuthPassword: &options.SecretSource{ | 						BasicAuthPassword: &options.SecretSource{ | ||||||
| 							Value: []byte(base64.StdEncoding.EncodeToString([]byte("This is a secure password"))), | 							Value: base64.StdEncoding.EncodeToString([]byte("This is a secure password")), | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
|  |  | ||||||
|  | @ -47,15 +47,11 @@ type AlphaOptions struct { | ||||||
| 	Providers Providers `json:"providers,omitempty"` | 	Providers Providers `json:"providers,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // MergeInto replaces alpha options in the Options struct with the values
 | // Initialize alpha options with default values and settings of the core options
 | ||||||
| // from the AlphaOptions
 | func NewAlphaOptions(opts *Options) *AlphaOptions { | ||||||
| func (a *AlphaOptions) MergeInto(opts *Options) { | 	aOpts := &AlphaOptions{} | ||||||
| 	opts.UpstreamServers = a.UpstreamConfig | 	aOpts.ExtractFrom(opts) | ||||||
| 	opts.InjectRequestHeaders = a.InjectRequestHeaders | 	return aOpts | ||||||
| 	opts.InjectResponseHeaders = a.InjectResponseHeaders |  | ||||||
| 	opts.Server = a.Server |  | ||||||
| 	opts.MetricsServer = a.MetricsServer |  | ||||||
| 	opts.Providers = a.Providers |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ExtractFrom populates the fields in the AlphaOptions with the values from
 | // ExtractFrom populates the fields in the AlphaOptions with the values from
 | ||||||
|  | @ -68,3 +64,14 @@ func (a *AlphaOptions) ExtractFrom(opts *Options) { | ||||||
| 	a.MetricsServer = opts.MetricsServer | 	a.MetricsServer = opts.MetricsServer | ||||||
| 	a.Providers = opts.Providers | 	a.Providers = opts.Providers | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // MergeInto replaces alpha options in the Options struct with the values
 | ||||||
|  | // from the AlphaOptions
 | ||||||
|  | func (a *AlphaOptions) MergeInto(opts *Options) { | ||||||
|  | 	opts.UpstreamServers = a.UpstreamConfig | ||||||
|  | 	opts.InjectRequestHeaders = a.InjectRequestHeaders | ||||||
|  | 	opts.InjectResponseHeaders = a.InjectResponseHeaders | ||||||
|  | 	opts.Server = a.Server | ||||||
|  | 	opts.MetricsServer = a.MetricsServer | ||||||
|  | 	opts.Providers = a.Providers | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1,63 +0,0 @@ | ||||||
| package options |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"strconv" |  | ||||||
| 	"time" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // SecretSource references an individual secret value.
 |  | ||||||
| // Only one source within the struct should be defined at any time.
 |  | ||||||
| type SecretSource struct { |  | ||||||
| 	// Value expects a base64 encoded string value.
 |  | ||||||
| 	Value []byte `json:"value,omitempty"` |  | ||||||
| 
 |  | ||||||
| 	// FromEnv expects the name of an environment variable.
 |  | ||||||
| 	FromEnv string `json:"fromEnv,omitempty"` |  | ||||||
| 
 |  | ||||||
| 	// FromFile expects a path to a file containing the secret value.
 |  | ||||||
| 	FromFile string `json:"fromFile,omitempty"` |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Duration is an alias for time.Duration so that we can ensure the marshalling
 |  | ||||||
| // and unmarshalling of string durations is done as users expect.
 |  | ||||||
| // Intentional blank line below to keep this first part of the comment out of
 |  | ||||||
| // any generated references.
 |  | ||||||
| 
 |  | ||||||
| // Duration is as string representation of a period of time.
 |  | ||||||
| // A duration string is a is a possibly signed sequence of decimal numbers,
 |  | ||||||
| // each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
 |  | ||||||
| // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
 |  | ||||||
| // +reference-gen:alias-name=string
 |  | ||||||
| type Duration time.Duration |  | ||||||
| 
 |  | ||||||
| // UnmarshalJSON parses the duration string and sets the value of duration
 |  | ||||||
| // to the value of the duration string.
 |  | ||||||
| func (d *Duration) UnmarshalJSON(data []byte) error { |  | ||||||
| 	input := string(data) |  | ||||||
| 	if unquoted, err := strconv.Unquote(input); err == nil { |  | ||||||
| 		input = unquoted |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	du, err := time.ParseDuration(input) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	*d = Duration(du) |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // MarshalJSON ensures that when the string is marshalled to JSON as a human
 |  | ||||||
| // readable string.
 |  | ||||||
| func (d *Duration) MarshalJSON() ([]byte, error) { |  | ||||||
| 	dStr := fmt.Sprintf("%q", d.Duration().String()) |  | ||||||
| 	return []byte(dStr), nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Duration returns the time.Duration version of this Duration
 |  | ||||||
| func (d *Duration) Duration() time.Duration { |  | ||||||
| 	if d == nil { |  | ||||||
| 		return time.Duration(0) |  | ||||||
| 	} |  | ||||||
| 	return time.Duration(*d) |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,43 @@ | ||||||
|  | package options | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"reflect" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/mitchellh/mapstructure" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Duration is an alias for time.Duration so that we can ensure the marshalling
 | ||||||
|  | // and unmarshalling of string durations is done as users expect.
 | ||||||
|  | // Intentional blank line below to keep this first part of the comment out of
 | ||||||
|  | // any generated references.
 | ||||||
|  | 
 | ||||||
|  | // Duration is as string representation of a period of time.
 | ||||||
|  | // A duration string is a is a possibly signed sequence of decimal numbers,
 | ||||||
|  | // each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
 | ||||||
|  | // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
 | ||||||
|  | 
 | ||||||
|  | // Conversion from string or floating point to golang duration type
 | ||||||
|  | // This way floating points will be converted to seconds and strings
 | ||||||
|  | // of type 3s or 5m will be parsed with time.ParseDuration
 | ||||||
|  | func toDurationHookFunc() mapstructure.DecodeHookFunc { | ||||||
|  | 	return func( | ||||||
|  | 		f reflect.Type, | ||||||
|  | 		t reflect.Type, | ||||||
|  | 		data interface{}) (interface{}, error) { | ||||||
|  | 		if t != reflect.TypeOf(time.Duration(0)) { | ||||||
|  | 			return data, nil | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		switch f.Kind() { | ||||||
|  | 		case reflect.String: | ||||||
|  | 			return time.ParseDuration(data.(string)) | ||||||
|  | 		case reflect.Float64: | ||||||
|  | 			return time.Duration(data.(float64) * float64(time.Second)), nil | ||||||
|  | 		case reflect.Int64: | ||||||
|  | 			return time.Duration(data.(int64)), nil | ||||||
|  | 		default: | ||||||
|  | 			return data, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -21,10 +21,10 @@ type Header struct { | ||||||
| // make up the header value
 | // make up the header value
 | ||||||
| type HeaderValue struct { | type HeaderValue struct { | ||||||
| 	// Allow users to load the value from a secret source
 | 	// Allow users to load the value from a secret source
 | ||||||
| 	*SecretSource `json:",omitempty"` | 	*SecretSource `json:"secretSource,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// Allow users to load the value from a session claim
 | 	// Allow users to load the value from a session claim
 | ||||||
| 	*ClaimSource `json:",omitempty"` | 	*ClaimSource `json:"claimSource,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ClaimSource allows loading a header value from a claim within the session
 | // ClaimSource allows loading a header value from a claim within the session
 | ||||||
|  |  | ||||||
|  | @ -136,8 +136,8 @@ func (l *LegacyUpstreams) convert() (UpstreamConfig, error) { | ||||||
| 			u.Path = "/" | 			u.Path = "/" | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		flushInterval := Duration(l.FlushInterval) | 		flushInterval := l.FlushInterval | ||||||
| 		timeout := Duration(l.Timeout) | 		timeout := l.Timeout | ||||||
| 		upstream := Upstream{ | 		upstream := Upstream{ | ||||||
| 			ID:                    u.Path, | 			ID:                    u.Path, | ||||||
| 			Path:                  u.Path, | 			Path:                  u.Path, | ||||||
|  | @ -294,7 +294,7 @@ func getBasicAuthHeader(preferEmailToUser bool, basicAuthPassword string) Header | ||||||
| 					Claim:  claim, | 					Claim:  claim, | ||||||
| 					Prefix: "Basic ", | 					Prefix: "Basic ", | ||||||
| 					BasicAuthPassword: &SecretSource{ | 					BasicAuthPassword: &SecretSource{ | ||||||
| 						Value: []byte(basicAuthPassword), | 						Value: basicAuthPassword, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
|  |  | ||||||
|  | @ -15,8 +15,8 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 			legacyOpts := NewLegacyOptions() | 			legacyOpts := NewLegacyOptions() | ||||||
| 
 | 
 | ||||||
| 			// Set upstreams and related options to test their conversion
 | 			// Set upstreams and related options to test their conversion
 | ||||||
| 			flushInterval := Duration(5 * time.Second) | 			flushInterval := 5 * time.Second | ||||||
| 			timeout := Duration(5 * time.Second) | 			timeout := 5 * time.Second | ||||||
| 			legacyOpts.LegacyUpstreams.FlushInterval = time.Duration(flushInterval) | 			legacyOpts.LegacyUpstreams.FlushInterval = time.Duration(flushInterval) | ||||||
| 			legacyOpts.LegacyUpstreams.Timeout = time.Duration(timeout) | 			legacyOpts.LegacyUpstreams.Timeout = time.Duration(timeout) | ||||||
| 			legacyOpts.LegacyUpstreams.PassHostHeader = true | 			legacyOpts.LegacyUpstreams.PassHostHeader = true | ||||||
|  | @ -147,8 +147,8 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 		skipVerify := true | 		skipVerify := true | ||||||
| 		passHostHeader := false | 		passHostHeader := false | ||||||
| 		proxyWebSockets := true | 		proxyWebSockets := true | ||||||
| 		flushInterval := Duration(5 * time.Second) | 		flushInterval := 5 * time.Second | ||||||
| 		timeout := Duration(5 * time.Second) | 		timeout := 5 * time.Second | ||||||
| 		disableKeepAlives := true | 		disableKeepAlives := true | ||||||
| 
 | 
 | ||||||
| 		// Test cases and expected outcomes
 | 		// Test cases and expected outcomes
 | ||||||
|  | @ -369,7 +369,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 						Claim:  "user", | 						Claim:  "user", | ||||||
| 						Prefix: "Basic ", | 						Prefix: "Basic ", | ||||||
| 						BasicAuthPassword: &SecretSource{ | 						BasicAuthPassword: &SecretSource{ | ||||||
| 							Value: []byte(basicAuthSecret), | 							Value: basicAuthSecret, | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
|  | @ -409,7 +409,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 						Claim:  "email", | 						Claim:  "email", | ||||||
| 						Prefix: "Basic ", | 						Prefix: "Basic ", | ||||||
| 						BasicAuthPassword: &SecretSource{ | 						BasicAuthPassword: &SecretSource{ | ||||||
| 							Value: []byte(basicAuthSecret), | 							Value: basicAuthSecret, | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
|  |  | ||||||
|  | @ -55,6 +55,76 @@ func Load(configFileName string, flagSet *pflag.FlagSet, into interface{}) error | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // LoadYAML will load a YAML based configuration file into the options interface provided.
 | ||||||
|  | func LoadYAML(configFileName string, opts interface{}) error { | ||||||
|  | 	buffer, err := loadAndSubstituteEnvs(configFileName) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Generic interface for loading arbitrary yaml structure
 | ||||||
|  | 	var intermediate map[string]interface{} | ||||||
|  | 
 | ||||||
|  | 	if err := yaml.Unmarshal(buffer, &intermediate); err != nil { | ||||||
|  | 		return fmt.Errorf("error unmarshalling config: %w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return Decode(intermediate, opts) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func Decode(input interface{}, result interface{}) error { | ||||||
|  | 	// Using mapstructure to decode arbitrary yaml structure into options and
 | ||||||
|  | 	// merge with existing values instead of overwriting everything. This is especially
 | ||||||
|  | 	// important as we have a lot of default values for boolean which are supposed to be
 | ||||||
|  | 	// true by default. Normally by just parsing through yaml all booleans that aren't
 | ||||||
|  | 	// referenced in the config file would be parsed as false and we cannot identify after
 | ||||||
|  | 	// the fact if they have been explicitly set to false or have not been referenced.
 | ||||||
|  | 	decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ | ||||||
|  | 		DecodeHook:           mapstructure.ComposeDecodeHookFunc(toDurationHookFunc()), | ||||||
|  | 		Metadata:             nil,    // Don't track any metadata
 | ||||||
|  | 		Result:               result, // Decode the result into the prefilled options
 | ||||||
|  | 		TagName:              "json", // Parse all fields that use the yaml tag
 | ||||||
|  | 		ZeroFields:           false,  // Don't clean the default values from the result map (options)
 | ||||||
|  | 		ErrorUnused:          true,   // Throw an error if keys have been used that aren't mapped to any struct fields
 | ||||||
|  | 		IgnoreUntaggedFields: true,   // Ignore fields in structures that aren't tagged with yaml
 | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("error creating decoder for config: %w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := decoder.Decode(input); err != nil { | ||||||
|  | 		return fmt.Errorf("error decoding config: %w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // loadAndSubstituteEnvs reads the yaml config into a generic byte buffer and
 | ||||||
|  | // substitute env references
 | ||||||
|  | func loadAndSubstituteEnvs(configFileName string) ([]byte, error) { | ||||||
|  | 	if configFileName == "" { | ||||||
|  | 		return nil, errors.New("no configuration file provided") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	unparsedBuffer, err := os.ReadFile(configFileName) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("unable to load config file: %w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	modifiedBuffer, err := normalizeSubstitution(unparsedBuffer) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("error normalizing substitution string : %w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	buffer, err := envsubst.Bytes(modifiedBuffer) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("error in substituting env variables : %w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return buffer, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // registerFlags uses `cfg` and `flag` tags to associate flags in the flagSet
 | // registerFlags uses `cfg` and `flag` tags to associate flags in the flagSet
 | ||||||
| // to the fields in the options interface provided.
 | // to the fields in the options interface provided.
 | ||||||
| // Each exported field in the options must have a `cfg` tag otherwise an error will occur.
 | // Each exported field in the options must have a `cfg` tag otherwise an error will occur.
 | ||||||
|  | @ -140,47 +210,6 @@ func isUnexported(name string) bool { | ||||||
| 	return first == strings.ToLower(first) | 	return first == strings.ToLower(first) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // LoadYAML will load a YAML based configuration file into the options interface provided.
 |  | ||||||
| func LoadYAML(configFileName string, into interface{}) error { |  | ||||||
| 	buffer, err := loadAndParseYaml(configFileName) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// UnmarshalStrict will return an error if the config includes options that are
 |  | ||||||
| 	// not mapped to fields of the into struct
 |  | ||||||
| 	if err := yaml.UnmarshalStrict(buffer, into, yaml.DisallowUnknownFields); err != nil { |  | ||||||
| 		return fmt.Errorf("error unmarshalling config: %w", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // loadAndParseYaml reads the config from the filesystem and
 |  | ||||||
| // execute the environment variable substitution
 |  | ||||||
| func loadAndParseYaml(configFileName string) ([]byte, error) { |  | ||||||
| 	if configFileName == "" { |  | ||||||
| 		return nil, errors.New("no configuration file provided") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	unparsedBuffer, err := os.ReadFile(configFileName) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("unable to load config file: %w", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	modifiedBuffer, err := normalizeSubstitution(unparsedBuffer) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("error normalizing substitution string : %w", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	buffer, err := envsubst.Bytes(modifiedBuffer) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("error in substituting env variables : %w", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return buffer, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // normalizeSubstitution normalizes dollar signs ($) with numerals like
 | // normalizeSubstitution normalizes dollar signs ($) with numerals like
 | ||||||
| // $1 or $2 properly by correctly escaping them
 | // $1 or $2 properly by correctly escaping them
 | ||||||
| func normalizeSubstitution(unparsedBuffer []byte) ([]byte, error) { | func normalizeSubstitution(unparsedBuffer []byte) ([]byte, error) { | ||||||
|  |  | ||||||
|  | @ -355,15 +355,15 @@ var _ = Describe("Load", func() { | ||||||
| var _ = Describe("LoadYAML", func() { | var _ = Describe("LoadYAML", func() { | ||||||
| 	Context("with a testOptions structure", func() { | 	Context("with a testOptions structure", func() { | ||||||
| 		type TestOptionSubStruct struct { | 		type TestOptionSubStruct struct { | ||||||
| 			StringSliceOption []string `yaml:"stringSliceOption,omitempty"` | 			StringSliceOption []string `json:"stringSliceOption,omitempty"` | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		type TestOptions struct { | 		type TestOptions struct { | ||||||
| 			StringOption string              `yaml:"stringOption,omitempty"` | 			StringOption string              `json:"stringOption,omitempty"` | ||||||
| 			Sub          TestOptionSubStruct `yaml:"sub,omitempty"` | 			Sub          TestOptionSubStruct `json:"sub,omitempty"` | ||||||
| 
 | 
 | ||||||
| 			// Check that embedded fields can be unmarshalled
 | 			// Check that embedded fields can be unmarshalled
 | ||||||
| 			TestOptionSubStruct `yaml:",inline,squash"` | 			TestOptionSubStruct `json:",inline,squash"` | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		var testOptionsConfigBytesFull = []byte(` | 		var testOptionsConfigBytesFull = []byte(` | ||||||
|  | @ -416,7 +416,7 @@ sub: | ||||||
| 
 | 
 | ||||||
| 				err := LoadYAML(configFileName, input) | 				err := LoadYAML(configFileName, input) | ||||||
| 				if in.expectedErr != nil { | 				if in.expectedErr != nil { | ||||||
| 					Expect(err).To(MatchError(in.expectedErr.Error())) | 					Expect(err).To(MatchError(ContainSubstring(in.expectedErr.Error()))) | ||||||
| 				} else { | 				} else { | ||||||
| 					Expect(err).ToNot(HaveOccurred()) | 					Expect(err).ToNot(HaveOccurred()) | ||||||
| 				} | 				} | ||||||
|  | @ -459,13 +459,13 @@ sub: | ||||||
| 						StringSliceOption: []string{"a", "b", "c"}, | 						StringSliceOption: []string{"a", "b", "c"}, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 				expectedErr: errors.New("error unmarshalling config: error unmarshaling JSON: while decoding JSON: json: unknown field \"foo\""), | 				expectedErr: errors.New("has invalid keys: foo"), | ||||||
| 			}), | 			}), | ||||||
| 			Entry("with an incorrect type for a string field", loadYAMLTableInput{ | 			Entry("with an incorrect type for a string field", loadYAMLTableInput{ | ||||||
| 				configFile:     []byte(`stringOption: ["a", "b"]`), | 				configFile:     []byte(`stringOption: ["a", "b"]`), | ||||||
| 				input:          &TestOptions{}, | 				input:          &TestOptions{}, | ||||||
| 				expectedOutput: &TestOptions{}, | 				expectedOutput: &TestOptions{}, | ||||||
| 				expectedErr:    errors.New("error unmarshalling config: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal array into Go struct field TestOptions.StringOption of type string"), | 				expectedErr:    errors.New("'stringOption' expected type 'string', got unconvertible type"), | ||||||
| 			}), | 			}), | ||||||
| 			Entry("with an incorrect type for an array field", loadYAMLTableInput{ | 			Entry("with an incorrect type for an array field", loadYAMLTableInput{ | ||||||
| 				configFile:     []byte(`stringSliceOption: "a"`), | 				configFile:     []byte(`stringSliceOption: "a"`), | ||||||
|  | @ -526,11 +526,13 @@ upstreamConfig: | ||||||
| injectRequestHeaders: | injectRequestHeaders: | ||||||
| - name: X-Forwarded-User | - name: X-Forwarded-User | ||||||
|   values: |   values: | ||||||
|   - claim: user |   - claimSource: | ||||||
|  |       claim: user | ||||||
| injectResponseHeaders: | injectResponseHeaders: | ||||||
| - name: X-Secret | - name: X-Secret | ||||||
|   values: |   values: | ||||||
|   - value: c2VjcmV0 |   - secretSource: | ||||||
|  |       value: secret | ||||||
| `) | `) | ||||||
| 
 | 
 | ||||||
| 		By("Creating a config file") | 		By("Creating a config file") | ||||||
|  | @ -548,7 +550,7 @@ injectResponseHeaders: | ||||||
| 		into := &AlphaOptions{} | 		into := &AlphaOptions{} | ||||||
| 		Expect(LoadYAML(configFileName, into)).To(Succeed()) | 		Expect(LoadYAML(configFileName, into)).To(Succeed()) | ||||||
| 
 | 
 | ||||||
| 		flushInterval := Duration(500 * time.Millisecond) | 		flushInterval := 500 * time.Millisecond | ||||||
| 
 | 
 | ||||||
| 		Expect(into).To(Equal(&AlphaOptions{ | 		Expect(into).To(Equal(&AlphaOptions{ | ||||||
| 			UpstreamConfig: UpstreamConfig{ | 			UpstreamConfig: UpstreamConfig{ | ||||||
|  | @ -579,7 +581,7 @@ injectResponseHeaders: | ||||||
| 					Values: []HeaderValue{ | 					Values: []HeaderValue{ | ||||||
| 						{ | 						{ | ||||||
| 							SecretSource: &SecretSource{ | 							SecretSource: &SecretSource{ | ||||||
| 								Value: []byte("secret"), | 								Value: "secret", | ||||||
| 							}, | 							}, | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
|  |  | ||||||
|  | @ -238,16 +238,16 @@ type OIDCOptions struct { | ||||||
| 	IssuerURL string `json:"issuerURL,omitempty"` | 	IssuerURL string `json:"issuerURL,omitempty"` | ||||||
| 	// InsecureAllowUnverifiedEmail prevents failures if an email address in an id_token is not verified
 | 	// InsecureAllowUnverifiedEmail prevents failures if an email address in an id_token is not verified
 | ||||||
| 	// default set to 'false'
 | 	// default set to 'false'
 | ||||||
| 	InsecureAllowUnverifiedEmail bool `json:"insecureAllowUnverifiedEmail,omitempty"` | 	InsecureAllowUnverifiedEmail bool `json:"insecureAllowUnverifiedEmail"` | ||||||
| 	// InsecureSkipIssuerVerification skips verification of ID token issuers. When false, ID Token Issuers must match the OIDC discovery URL
 | 	// InsecureSkipIssuerVerification skips verification of ID token issuers. When false, ID Token Issuers must match the OIDC discovery URL
 | ||||||
| 	// default set to 'false'
 | 	// default set to 'false'
 | ||||||
| 	InsecureSkipIssuerVerification bool `json:"insecureSkipIssuerVerification,omitempty"` | 	InsecureSkipIssuerVerification bool `json:"insecureSkipIssuerVerification"` | ||||||
| 	// InsecureSkipNonce skips verifying the ID Token's nonce claim that must match
 | 	// InsecureSkipNonce skips verifying the ID Token's nonce claim that must match
 | ||||||
| 	// the random nonce sent in the initial OAuth flow. Otherwise, the nonce is checked
 | 	// the random nonce sent in the initial OAuth flow. Otherwise, the nonce is checked
 | ||||||
| 	// after the initial OAuth redeem & subsequent token refreshes.
 | 	// after the initial OAuth redeem & subsequent token refreshes.
 | ||||||
| 	// default set to 'true'
 | 	// default set to 'true'
 | ||||||
| 	// Warning: In a future release, this will change to 'false' by default for enhanced security.
 | 	// Warning: In a future release, this will change to 'false' by default for enhanced security.
 | ||||||
| 	InsecureSkipNonce bool `json:"insecureSkipNonce,omitempty"` | 	InsecureSkipNonce bool `json:"insecureSkipNonce"` | ||||||
| 	// SkipDiscovery allows to skip OIDC discovery and use manually supplied Endpoints
 | 	// SkipDiscovery allows to skip OIDC discovery and use manually supplied Endpoints
 | ||||||
| 	// default set to 'false'
 | 	// default set to 'false'
 | ||||||
| 	SkipDiscovery bool `json:"skipDiscovery,omitempty"` | 	SkipDiscovery bool `json:"skipDiscovery,omitempty"` | ||||||
|  |  | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | package options | ||||||
|  | 
 | ||||||
|  | // SecretSource references an individual secret value.
 | ||||||
|  | // Only one source within the struct should be defined at any time.
 | ||||||
|  | type SecretSource struct { | ||||||
|  | 	// Value expects a base64 encoded string value.
 | ||||||
|  | 	Value string `json:"value,omitempty"` | ||||||
|  | 
 | ||||||
|  | 	// FromEnv expects the name of an environment variable.
 | ||||||
|  | 	FromEnv string `json:"fromEnv,omitempty"` | ||||||
|  | 
 | ||||||
|  | 	// FromFile expects a path to a file containing the secret value.
 | ||||||
|  | 	FromFile string `json:"fromFile,omitempty"` | ||||||
|  | } | ||||||
|  | @ -79,7 +79,7 @@ type Upstream struct { | ||||||
| 	// FlushInterval is the period between flushing the response buffer when
 | 	// FlushInterval is the period between flushing the response buffer when
 | ||||||
| 	// streaming response from the upstream.
 | 	// streaming response from the upstream.
 | ||||||
| 	// Defaults to 1 second.
 | 	// Defaults to 1 second.
 | ||||||
| 	FlushInterval *Duration `json:"flushInterval,omitempty"` | 	FlushInterval *time.Duration `json:"flushInterval,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// PassHostHeader determines whether the request host header should be proxied
 | 	// PassHostHeader determines whether the request host header should be proxied
 | ||||||
| 	// to the upstream server.
 | 	// to the upstream server.
 | ||||||
|  | @ -92,7 +92,7 @@ type Upstream struct { | ||||||
| 
 | 
 | ||||||
| 	// Timeout is the maximum duration the server will wait for a response from the upstream server.
 | 	// Timeout is the maximum duration the server will wait for a response from the upstream server.
 | ||||||
| 	// Defaults to 30 seconds.
 | 	// Defaults to 30 seconds.
 | ||||||
| 	Timeout *Duration `json:"timeout,omitempty"` | 	Timeout *time.Duration `json:"timeout,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// DisableKeepAlives disables HTTP keep-alive connections to the upstream server.
 | 	// DisableKeepAlives disables HTTP keep-alive connections to the upstream server.
 | ||||||
| 	// Defaults to false.
 | 	// Defaults to false.
 | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ import ( | ||||||
| func GetSecretValue(source *options.SecretSource) ([]byte, error) { | func GetSecretValue(source *options.SecretSource) ([]byte, error) { | ||||||
| 	switch { | 	switch { | ||||||
| 	case len(source.Value) > 0 && source.FromEnv == "" && source.FromFile == "": | 	case len(source.Value) > 0 && source.FromEnv == "" && source.FromFile == "": | ||||||
| 		return source.Value, nil | 		return []byte(source.Value), nil | ||||||
| 	case len(source.Value) == 0 && source.FromEnv != "" && source.FromFile == "": | 	case len(source.Value) == 0 && source.FromEnv != "" && source.FromFile == "": | ||||||
| 		return []byte(os.Getenv(source.FromEnv)), nil | 		return []byte(os.Getenv(source.FromEnv)), nil | ||||||
| 	case len(source.Value) == 0 && source.FromEnv == "" && source.FromFile != "": | 	case len(source.Value) == 0 && source.FromEnv == "" && source.FromFile != "": | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ var _ = Describe("GetSecretValue", func() { | ||||||
| 
 | 
 | ||||||
| 	It("returns the correct value from the string value", func() { | 	It("returns the correct value from the string value", func() { | ||||||
| 		value, err := GetSecretValue(&options.SecretSource{ | 		value, err := GetSecretValue(&options.SecretSource{ | ||||||
| 			Value: []byte("secret-value-1"), | 			Value: "secret-value-1", | ||||||
| 		}) | 		}) | ||||||
| 		Expect(err).ToNot(HaveOccurred()) | 		Expect(err).ToNot(HaveOccurred()) | ||||||
| 		Expect(string(value)).To(Equal("secret-value-1")) | 		Expect(string(value)).To(Equal("secret-value-1")) | ||||||
|  |  | ||||||
|  | @ -55,7 +55,7 @@ var _ = Describe("Injector Suite", func() { | ||||||
| 						Values: []options.HeaderValue{ | 						Values: []options.HeaderValue{ | ||||||
| 							{ | 							{ | ||||||
| 								SecretSource: &options.SecretSource{ | 								SecretSource: &options.SecretSource{ | ||||||
| 									Value: []byte("super-secret"), | 									Value: "super-secret", | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
| 						}, | 						}, | ||||||
|  | @ -199,7 +199,7 @@ var _ = Describe("Injector Suite", func() { | ||||||
| 								ClaimSource: &options.ClaimSource{ | 								ClaimSource: &options.ClaimSource{ | ||||||
| 									Claim: "user", | 									Claim: "user", | ||||||
| 									BasicAuthPassword: &options.SecretSource{ | 									BasicAuthPassword: &options.SecretSource{ | ||||||
| 										Value: []byte("basic-password"), | 										Value: "basic-password", | ||||||
| 									}, | 									}, | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
|  | @ -227,7 +227,7 @@ var _ = Describe("Injector Suite", func() { | ||||||
| 								ClaimSource: &options.ClaimSource{ | 								ClaimSource: &options.ClaimSource{ | ||||||
| 									Claim: "user", | 									Claim: "user", | ||||||
| 									BasicAuthPassword: &options.SecretSource{ | 									BasicAuthPassword: &options.SecretSource{ | ||||||
| 										Value: []byte(base64.StdEncoding.EncodeToString([]byte("basic-password"))), | 										Value: base64.StdEncoding.EncodeToString([]byte("basic-password")), | ||||||
| 									}, | 									}, | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
|  | @ -322,7 +322,7 @@ var _ = Describe("Injector Suite", func() { | ||||||
| 								ClaimSource: &options.ClaimSource{ | 								ClaimSource: &options.ClaimSource{ | ||||||
| 									Claim: "user", | 									Claim: "user", | ||||||
| 									BasicAuthPassword: &options.SecretSource{ | 									BasicAuthPassword: &options.SecretSource{ | ||||||
| 										Value:   []byte(base64.StdEncoding.EncodeToString([]byte("basic-password"))), | 										Value:   base64.StdEncoding.EncodeToString([]byte("basic-password")), | ||||||
| 										FromEnv: "SECRET_ENV", | 										FromEnv: "SECRET_ENV", | ||||||
| 									}, | 									}, | ||||||
| 								}, | 								}, | ||||||
|  | @ -348,7 +348,7 @@ var _ = Describe("Injector Suite", func() { | ||||||
| 								ClaimSource: &options.ClaimSource{ | 								ClaimSource: &options.ClaimSource{ | ||||||
| 									Claim: "user", | 									Claim: "user", | ||||||
| 									BasicAuthPassword: &options.SecretSource{ | 									BasicAuthPassword: &options.SecretSource{ | ||||||
| 										Value: []byte("basic-password"), | 										Value: "basic-password", | ||||||
| 									}, | 									}, | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
|  | @ -379,17 +379,17 @@ var _ = Describe("Injector Suite", func() { | ||||||
| 						Values: []options.HeaderValue{ | 						Values: []options.HeaderValue{ | ||||||
| 							{ | 							{ | ||||||
| 								SecretSource: &options.SecretSource{ | 								SecretSource: &options.SecretSource{ | ||||||
| 									Value: []byte("major=1"), | 									Value: "major=1", | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
| 							{ | 							{ | ||||||
| 								SecretSource: &options.SecretSource{ | 								SecretSource: &options.SecretSource{ | ||||||
| 									Value: []byte("minor=2"), | 									Value: "minor=2", | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
| 							{ | 							{ | ||||||
| 								SecretSource: &options.SecretSource{ | 								SecretSource: &options.SecretSource{ | ||||||
| 									Value: []byte("patch=3"), | 									Value: "patch=3", | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
| 						}, | 						}, | ||||||
|  |  | ||||||
|  | @ -48,10 +48,10 @@ var _ = BeforeSuite(func() { | ||||||
| 
 | 
 | ||||||
| 		certOut := new(bytes.Buffer) | 		certOut := new(bytes.Buffer) | ||||||
| 		Expect(pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})).To(Succeed()) | 		Expect(pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})).To(Succeed()) | ||||||
| 		ipv4CertDataSource.Value = certOut.Bytes() | 		ipv4CertDataSource.Value = certOut.String() | ||||||
| 		keyOut := new(bytes.Buffer) | 		keyOut := new(bytes.Buffer) | ||||||
| 		Expect(pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes})).To(Succeed()) | 		Expect(pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes})).To(Succeed()) | ||||||
| 		ipv4KeyDataSource.Value = keyOut.Bytes() | 		ipv4KeyDataSource.Value = keyOut.String() | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| 	By("Generating a ipv6 self-signed cert for TLS tests", func() { | 	By("Generating a ipv6 self-signed cert for TLS tests", func() { | ||||||
|  | @ -61,16 +61,16 @@ var _ = BeforeSuite(func() { | ||||||
| 
 | 
 | ||||||
| 		certOut := new(bytes.Buffer) | 		certOut := new(bytes.Buffer) | ||||||
| 		Expect(pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})).To(Succeed()) | 		Expect(pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})).To(Succeed()) | ||||||
| 		ipv6CertDataSource.Value = certOut.Bytes() | 		ipv6CertDataSource.Value = certOut.String() | ||||||
| 		keyOut := new(bytes.Buffer) | 		keyOut := new(bytes.Buffer) | ||||||
| 		Expect(pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes})).To(Succeed()) | 		Expect(pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes})).To(Succeed()) | ||||||
| 		ipv6KeyDataSource.Value = keyOut.Bytes() | 		ipv6KeyDataSource.Value = keyOut.String() | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| 	By("Setting up a http client", func() { | 	By("Setting up a http client", func() { | ||||||
| 		ipv4cert, err := tls.X509KeyPair(ipv4CertDataSource.Value, ipv4KeyDataSource.Value) | 		ipv4cert, err := tls.X509KeyPair([]byte(ipv4CertDataSource.Value), []byte(ipv4KeyDataSource.Value)) | ||||||
| 		Expect(err).ToNot(HaveOccurred()) | 		Expect(err).ToNot(HaveOccurred()) | ||||||
| 		ipv6cert, err := tls.X509KeyPair(ipv6CertDataSource.Value, ipv6KeyDataSource.Value) | 		ipv6cert, err := tls.X509KeyPair([]byte(ipv6CertDataSource.Value), []byte(ipv6KeyDataSource.Value)) | ||||||
| 		Expect(err).ToNot(HaveOccurred()) | 		Expect(err).ToNot(HaveOccurred()) | ||||||
| 
 | 
 | ||||||
| 		ipv4certificate, err := x509.ParseCertificate(ipv4cert.Certificate[0]) | 		ipv4certificate, err := x509.ParseCertificate(ipv4cert.Certificate[0]) | ||||||
|  |  | ||||||
|  | @ -234,7 +234,7 @@ var _ = Describe("Server", func() { | ||||||
| 					SecureBindAddress: "127.0.0.1:0", | 					SecureBindAddress: "127.0.0.1:0", | ||||||
| 					TLS: &options.TLS{ | 					TLS: &options.TLS{ | ||||||
| 						Key: &options.SecretSource{ | 						Key: &options.SecretSource{ | ||||||
| 							Value: []byte("invalid"), | 							Value: "invalid", | ||||||
| 						}, | 						}, | ||||||
| 						Cert: &ipv4CertDataSource, | 						Cert: &ipv4CertDataSource, | ||||||
| 					}, | 					}, | ||||||
|  | @ -250,7 +250,7 @@ var _ = Describe("Server", func() { | ||||||
| 					TLS: &options.TLS{ | 					TLS: &options.TLS{ | ||||||
| 						Key: &ipv4KeyDataSource, | 						Key: &ipv4KeyDataSource, | ||||||
| 						Cert: &options.SecretSource{ | 						Cert: &options.SecretSource{ | ||||||
| 							Value: []byte("invalid"), | 							Value: "invalid", | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
|  | @ -506,7 +506,7 @@ var _ = Describe("Server", func() { | ||||||
| 					SecureBindAddress: "[::1]:0", | 					SecureBindAddress: "[::1]:0", | ||||||
| 					TLS: &options.TLS{ | 					TLS: &options.TLS{ | ||||||
| 						Key: &options.SecretSource{ | 						Key: &options.SecretSource{ | ||||||
| 							Value: []byte("invalid"), | 							Value: "invalid", | ||||||
| 						}, | 						}, | ||||||
| 						Cert: &ipv6CertDataSource, | 						Cert: &ipv6CertDataSource, | ||||||
| 					}, | 					}, | ||||||
|  | @ -523,7 +523,7 @@ var _ = Describe("Server", func() { | ||||||
| 					TLS: &options.TLS{ | 					TLS: &options.TLS{ | ||||||
| 						Key: &ipv6KeyDataSource, | 						Key: &ipv6KeyDataSource, | ||||||
| 						Cert: &options.SecretSource{ | 						Cert: &options.SecretSource{ | ||||||
| 							Value: []byte("invalid"), | 							Value: "invalid", | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
|  |  | ||||||
|  | @ -188,7 +188,7 @@ var _ = Describe("Headers Suite", func() { | ||||||
| 							ClaimSource: &options.ClaimSource{ | 							ClaimSource: &options.ClaimSource{ | ||||||
| 								Claim: "user", | 								Claim: "user", | ||||||
| 								BasicAuthPassword: &options.SecretSource{ | 								BasicAuthPassword: &options.SecretSource{ | ||||||
| 									Value:   []byte(base64.StdEncoding.EncodeToString([]byte("basic-password"))), | 									Value:   base64.StdEncoding.EncodeToString([]byte("basic-password")), | ||||||
| 									FromEnv: "SECRET_ENV", | 									FromEnv: "SECRET_ENV", | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
|  | @ -260,7 +260,7 @@ var _ = Describe("Headers Suite", func() { | ||||||
| 					Values: []options.HeaderValue{ | 					Values: []options.HeaderValue{ | ||||||
| 						{ | 						{ | ||||||
| 							SecretSource: &options.SecretSource{ | 							SecretSource: &options.SecretSource{ | ||||||
| 								Value: []byte("_oauth2_proxy=ey123123123"), | 								Value: "_oauth2_proxy=ey123123123", | ||||||
| 							}, | 							}, | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
|  | @ -270,7 +270,7 @@ var _ = Describe("Headers Suite", func() { | ||||||
| 					Values: []options.HeaderValue{ | 					Values: []options.HeaderValue{ | ||||||
| 						{ | 						{ | ||||||
| 							SecretSource: &options.SecretSource{ | 							SecretSource: &options.SecretSource{ | ||||||
| 								Value: []byte("oauth_user"), | 								Value: "oauth_user", | ||||||
| 							}, | 							}, | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
|  | @ -416,7 +416,7 @@ var _ = Describe("Headers Suite", func() { | ||||||
| 							ClaimSource: &options.ClaimSource{ | 							ClaimSource: &options.ClaimSource{ | ||||||
| 								Claim: "user", | 								Claim: "user", | ||||||
| 								BasicAuthPassword: &options.SecretSource{ | 								BasicAuthPassword: &options.SecretSource{ | ||||||
| 									Value:   []byte(base64.StdEncoding.EncodeToString([]byte("basic-password"))), | 									Value:   base64.StdEncoding.EncodeToString([]byte("basic-password")), | ||||||
| 									FromEnv: "SECRET_ENV", | 									FromEnv: "SECRET_ENV", | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
|  |  | ||||||
|  | @ -137,12 +137,12 @@ func newReverseProxy(target *url.URL, upstream options.Upstream, errorHandler Pr | ||||||
| 
 | 
 | ||||||
| 	// Change default duration for waiting for an upstream response
 | 	// Change default duration for waiting for an upstream response
 | ||||||
| 	if upstream.Timeout != nil { | 	if upstream.Timeout != nil { | ||||||
| 		transport.ResponseHeaderTimeout = upstream.Timeout.Duration() | 		transport.ResponseHeaderTimeout = *upstream.Timeout | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Configure options on the SingleHostReverseProxy
 | 	// Configure options on the SingleHostReverseProxy
 | ||||||
| 	if upstream.FlushInterval != nil { | 	if upstream.FlushInterval != nil { | ||||||
| 		proxy.FlushInterval = upstream.FlushInterval.Duration() | 		proxy.FlushInterval = *upstream.FlushInterval | ||||||
| 	} else { | 	} else { | ||||||
| 		proxy.FlushInterval = options.DefaultUpstreamFlushInterval | 		proxy.FlushInterval = options.DefaultUpstreamFlushInterval | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -21,8 +21,8 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var _ = Describe("HTTP Upstream Suite", func() { | var _ = Describe("HTTP Upstream Suite", func() { | ||||||
| 	defaultFlushInterval := options.Duration(options.DefaultUpstreamFlushInterval) | 	defaultFlushInterval := options.DefaultUpstreamFlushInterval | ||||||
| 	defaultTimeout := options.Duration(options.DefaultUpstreamTimeout) | 	defaultTimeout := options.DefaultUpstreamTimeout | ||||||
| 	truth := true | 	truth := true | ||||||
| 	falsum := false | 	falsum := false | ||||||
| 
 | 
 | ||||||
|  | @ -57,9 +57,9 @@ var _ = Describe("HTTP Upstream Suite", func() { | ||||||
| 			req = middlewareapi.AddRequestScope(req, &middlewareapi.RequestScope{}) | 			req = middlewareapi.AddRequestScope(req, &middlewareapi.RequestScope{}) | ||||||
| 			rw := httptest.NewRecorder() | 			rw := httptest.NewRecorder() | ||||||
| 
 | 
 | ||||||
| 			flush := options.Duration(1 * time.Second) | 			flush := 1 * time.Second | ||||||
| 
 | 
 | ||||||
| 			timeout := options.Duration(options.DefaultUpstreamTimeout) | 			timeout := options.DefaultUpstreamTimeout | ||||||
| 
 | 
 | ||||||
| 			upstream := options.Upstream{ | 			upstream := options.Upstream{ | ||||||
| 				ID:                    in.id, | 				ID:                    in.id, | ||||||
|  | @ -373,11 +373,11 @@ var _ = Describe("HTTP Upstream Suite", func() { | ||||||
| 
 | 
 | ||||||
| 	type newUpstreamTableInput struct { | 	type newUpstreamTableInput struct { | ||||||
| 		proxyWebSockets   bool | 		proxyWebSockets   bool | ||||||
| 		flushInterval     options.Duration | 		flushInterval     time.Duration | ||||||
| 		skipVerify        bool | 		skipVerify        bool | ||||||
| 		sigData           *options.SignatureData | 		sigData           *options.SignatureData | ||||||
| 		errorHandler      func(http.ResponseWriter, *http.Request, error) | 		errorHandler      func(http.ResponseWriter, *http.Request, error) | ||||||
| 		timeout           options.Duration | 		timeout           time.Duration | ||||||
| 		disableKeepAlives bool | 		disableKeepAlives bool | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -406,10 +406,10 @@ var _ = Describe("HTTP Upstream Suite", func() { | ||||||
| 
 | 
 | ||||||
| 			proxy, ok := upstreamProxy.handler.(*httputil.ReverseProxy) | 			proxy, ok := upstreamProxy.handler.(*httputil.ReverseProxy) | ||||||
| 			Expect(ok).To(BeTrue()) | 			Expect(ok).To(BeTrue()) | ||||||
| 			Expect(proxy.FlushInterval).To(Equal(in.flushInterval.Duration())) | 			Expect(proxy.FlushInterval).To(Equal(in.flushInterval)) | ||||||
| 			transport, ok := proxy.Transport.(*http.Transport) | 			transport, ok := proxy.Transport.(*http.Transport) | ||||||
| 			Expect(ok).To(BeTrue()) | 			Expect(ok).To(BeTrue()) | ||||||
| 			Expect(transport.ResponseHeaderTimeout).To(Equal(in.timeout.Duration())) | 			Expect(transport.ResponseHeaderTimeout).To(Equal(in.timeout)) | ||||||
| 			Expect(proxy.ErrorHandler != nil).To(Equal(in.errorHandler != nil)) | 			Expect(proxy.ErrorHandler != nil).To(Equal(in.errorHandler != nil)) | ||||||
| 			if in.skipVerify { | 			if in.skipVerify { | ||||||
| 				Expect(transport.TLSClientConfig.InsecureSkipVerify).To(Equal(true)) | 				Expect(transport.TLSClientConfig.InsecureSkipVerify).To(Equal(true)) | ||||||
|  | @ -428,7 +428,7 @@ var _ = Describe("HTTP Upstream Suite", func() { | ||||||
| 		}), | 		}), | ||||||
| 		Entry("with a non standard flush interval", &newUpstreamTableInput{ | 		Entry("with a non standard flush interval", &newUpstreamTableInput{ | ||||||
| 			proxyWebSockets: false, | 			proxyWebSockets: false, | ||||||
| 			flushInterval:   options.Duration(5 * time.Second), | 			flushInterval:   5 * time.Second, | ||||||
| 			skipVerify:      false, | 			skipVerify:      false, | ||||||
| 			sigData:         nil, | 			sigData:         nil, | ||||||
| 			errorHandler:    nil, | 			errorHandler:    nil, | ||||||
|  | @ -466,7 +466,7 @@ var _ = Describe("HTTP Upstream Suite", func() { | ||||||
| 			skipVerify:      false, | 			skipVerify:      false, | ||||||
| 			sigData:         nil, | 			sigData:         nil, | ||||||
| 			errorHandler:    nil, | 			errorHandler:    nil, | ||||||
| 			timeout:         options.Duration(5 * time.Second), | 			timeout:         5 * time.Second, | ||||||
| 		}), | 		}), | ||||||
| 		Entry("with a DisableKeepAlives", &newUpstreamTableInput{ | 		Entry("with a DisableKeepAlives", &newUpstreamTableInput{ | ||||||
| 			proxyWebSockets:   false, | 			proxyWebSockets:   false, | ||||||
|  | @ -483,8 +483,8 @@ var _ = Describe("HTTP Upstream Suite", func() { | ||||||
| 		var proxyServer *httptest.Server | 		var proxyServer *httptest.Server | ||||||
| 
 | 
 | ||||||
| 		BeforeEach(func() { | 		BeforeEach(func() { | ||||||
| 			flush := options.Duration(1 * time.Second) | 			flush := 1 * time.Second | ||||||
| 			timeout := options.Duration(options.DefaultUpstreamTimeout) | 			timeout := options.DefaultUpstreamTimeout | ||||||
| 			upstream := options.Upstream{ | 			upstream := options.Upstream{ | ||||||
| 				ID:                    "websocketProxy", | 				ID:                    "websocketProxy", | ||||||
| 				PassHostHeader:        &truth, | 				PassHostHeader:        &truth, | ||||||
|  |  | ||||||
|  | @ -9,12 +9,12 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var _ = Describe("Common", func() { | var _ = Describe("Common", func() { | ||||||
| 	var validSecretSourceValue []byte | 	var validSecretSourceValue string | ||||||
| 	const validSecretSourceEnv = "OAUTH2_PROXY_TEST_SECRET_SOURCE_ENV" | 	const validSecretSourceEnv = "OAUTH2_PROXY_TEST_SECRET_SOURCE_ENV" | ||||||
| 	var validSecretSourceFile string | 	var validSecretSourceFile string | ||||||
| 
 | 
 | ||||||
| 	BeforeEach(func() { | 	BeforeEach(func() { | ||||||
| 		validSecretSourceValue = []byte("This is a secret source value") | 		validSecretSourceValue = "This is a secret source value" | ||||||
| 		Expect(os.Setenv(validSecretSourceEnv, "This is a secret source env")).To(Succeed()) | 		Expect(os.Setenv(validSecretSourceEnv, "This is a secret source env")).To(Succeed()) | ||||||
| 		tmp, err := os.CreateTemp("", "oauth2-proxy-secret-source-test") | 		tmp, err := os.CreateTemp("", "oauth2-proxy-secret-source-test") | ||||||
| 		Expect(err).ToNot(HaveOccurred()) | 		Expect(err).ToNot(HaveOccurred()) | ||||||
|  |  | ||||||
|  | @ -51,11 +51,9 @@ func validateHeaderValue(_ string, value options.HeaderValue) []string { | ||||||
| 
 | 
 | ||||||
| func validateHeaderValueClaimSource(claim options.ClaimSource) []string { | func validateHeaderValueClaimSource(claim options.ClaimSource) []string { | ||||||
| 	msgs := []string{} | 	msgs := []string{} | ||||||
| 
 |  | ||||||
| 	if claim.Claim == "" { | 	if claim.Claim == "" { | ||||||
| 		msgs = append(msgs, "claim should not be empty") | 		msgs = append(msgs, "claim should not be empty") | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	if claim.BasicAuthPassword != nil { | 	if claim.BasicAuthPassword != nil { | ||||||
| 		msgs = append(msgs, prefixValues("invalid basicAuthPassword: ", validateSecretSource(*claim.BasicAuthPassword))...) | 		msgs = append(msgs, prefixValues("invalid basicAuthPassword: ", validateSecretSource(*claim.BasicAuthPassword))...) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -30,7 +30,7 @@ var _ = Describe("Headers", func() { | ||||||
| 		Values: []options.HeaderValue{ | 		Values: []options.HeaderValue{ | ||||||
| 			{ | 			{ | ||||||
| 				SecretSource: &options.SecretSource{ | 				SecretSource: &options.SecretSource{ | ||||||
| 					Value: []byte(base64.StdEncoding.EncodeToString([]byte("secret"))), | 					Value: base64.StdEncoding.EncodeToString([]byte("secret")), | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
|  | @ -43,7 +43,7 @@ var _ = Describe("Headers", func() { | ||||||
| 				ClaimSource: &options.ClaimSource{ | 				ClaimSource: &options.ClaimSource{ | ||||||
| 					Claim: "email", | 					Claim: "email", | ||||||
| 					BasicAuthPassword: &options.SecretSource{ | 					BasicAuthPassword: &options.SecretSource{ | ||||||
| 						Value: []byte(base64.StdEncoding.EncodeToString([]byte("secret"))), | 						Value: base64.StdEncoding.EncodeToString([]byte("secret")), | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
|  |  | ||||||
|  | @ -69,7 +69,7 @@ func validateStaticUpstream(upstream options.Upstream) []string { | ||||||
| 	if upstream.InsecureSkipTLSVerify { | 	if upstream.InsecureSkipTLSVerify { | ||||||
| 		msgs = append(msgs, fmt.Sprintf("upstream %q has insecureSkipTLSVerify, but is a static upstream, this will have no effect.", upstream.ID)) | 		msgs = append(msgs, fmt.Sprintf("upstream %q has insecureSkipTLSVerify, but is a static upstream, this will have no effect.", upstream.ID)) | ||||||
| 	} | 	} | ||||||
| 	if upstream.FlushInterval != nil && upstream.FlushInterval.Duration() != options.DefaultUpstreamFlushInterval { | 	if upstream.FlushInterval != nil && *upstream.FlushInterval != options.DefaultUpstreamFlushInterval { | ||||||
| 		msgs = append(msgs, fmt.Sprintf("upstream %q has flushInterval, but is a static upstream, this will have no effect.", upstream.ID)) | 		msgs = append(msgs, fmt.Sprintf("upstream %q has flushInterval, but is a static upstream, this will have no effect.", upstream.ID)) | ||||||
| 	} | 	} | ||||||
| 	if upstream.PassHostHeader != nil { | 	if upstream.PassHostHeader != nil { | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ var _ = Describe("Upstreams", func() { | ||||||
| 		errStrings []string | 		errStrings []string | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	flushInterval := options.Duration(5 * time.Second) | 	flushInterval := 5 * time.Second | ||||||
| 	staticCode200 := 200 | 	staticCode200 := 200 | ||||||
| 	truth := true | 	truth := true | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue