fix merge problems and test cases
Signed-off-by: Jan Larwig <jan@larwig.com>
This commit is contained in:
		
							parent
							
								
									1d73f140bf
								
							
						
					
					
						commit
						fa2587ac09
					
				
							
								
								
									
										2
									
								
								main.go
								
								
								
								
							
							
						
						
									
										2
									
								
								main.go
								
								
								
								
							|  | @ -70,7 +70,7 @@ func main() { | |||
| func loadConfiguration(config, yamlConfig string, extraFlags *pflag.FlagSet, args []string) (*options.Options, error) { | ||||
| 	opts, err := loadLegacyOptions(config, extraFlags, args) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("couldn't load legacy options: %w", err) | ||||
| 		return nil, fmt.Errorf("failed to load legacy options: %w", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if yamlConfig != "" { | ||||
|  |  | |||
							
								
								
									
										16
									
								
								main_test.go
								
								
								
								
							
							
						
						
									
										16
									
								
								main_test.go
								
								
								
								
							|  | @ -22,7 +22,7 @@ var _ = Describe("Configuration Loading Suite", func() { | |||
| http_address="127.0.0.1:4180" | ||||
| upstreams="http://httpbin" | ||||
| set_basic_auth="true" | ||||
| basic_auth_password="super-secret-password" | ||||
| basic_auth_password="c3VwZXItc2VjcmV0LXBhc3N3b3Jk" | ||||
| client_id="oauth2-proxy" | ||||
| client_secret="b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK" | ||||
| ` | ||||
|  | @ -45,7 +45,7 @@ injectRequestHeaders: | |||
|       claim: user | ||||
|       prefix: "Basic " | ||||
|       basicAuthPassword: | ||||
|         value: super-secret-password | ||||
|         value: c3VwZXItc2VjcmV0LXBhc3N3b3Jk | ||||
| - name: X-Forwarded-Groups | ||||
|   values: | ||||
|   - claimSource: | ||||
|  | @ -69,12 +69,12 @@ injectResponseHeaders: | |||
|       claim: user | ||||
|       prefix: "Basic " | ||||
|       basicAuthPassword: | ||||
|         value: super-secret-password | ||||
|         value: c3VwZXItc2VjcmV0LXBhc3N3b3Jk | ||||
| server: | ||||
|   bindAddress: "127.0.0.1:4180" | ||||
| providers: | ||||
| - provider: google | ||||
|   ID: google=oauth2-proxy | ||||
| - id: google=oauth2-proxy | ||||
|   provider: google | ||||
|   clientSecret: b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK | ||||
|   clientID: oauth2-proxy | ||||
|   azureConfig: | ||||
|  | @ -139,7 +139,7 @@ redirect_url="http://localhost:4180/oauth2/callback" | |||
| 						Claim:  "user", | ||||
| 						Prefix: "Basic ", | ||||
| 						BasicAuthPassword: &options.SecretSource{ | ||||
| 							Value: []byte("super-secret-password"), | ||||
| 							Value: []byte("c3VwZXItc2VjcmV0LXBhc3N3b3Jk"), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
|  | @ -248,7 +248,7 @@ redirect_url="http://localhost:4180/oauth2/callback" | |||
| 		Entry("with bad legacy configuration", loadConfigurationTableInput{ | ||||
| 			configContent:   testCoreConfig + "unknown_field=\"something\"", | ||||
| 			expectedOptions: func() *options.Options { return nil }, | ||||
| 			expectedErr:     errors.New("failed to load config: error unmarshalling config: decoding failed due to the following error(s):\n\n'' has invalid keys: unknown_field"), | ||||
| 			expectedErr:     errors.New("failed to load legacy options: failed to load config: error unmarshalling config: decoding failed due to the following error(s):\n\n'' has invalid keys: unknown_field"), | ||||
| 		}), | ||||
| 		Entry("with bad alpha configuration", loadConfigurationTableInput{ | ||||
| 			configContent:      testCoreConfig, | ||||
|  | @ -260,7 +260,7 @@ redirect_url="http://localhost:4180/oauth2/callback" | |||
| 			configContent:      testCoreConfig + "unknown_field=\"something\"", | ||||
| 			alphaConfigContent: testAlphaConfig, | ||||
| 			expectedOptions:    func() *options.Options { return nil }, | ||||
| 			expectedErr:        errors.New("failed to load core options: failed to load config: error unmarshalling config: decoding failed due to the following error(s):\n\n'' has invalid keys: unknown_field"), | ||||
| 			expectedErr:        errors.New("failed to load legacy options: failed to load config: error unmarshalling config: decoding failed due to the following error(s):\n\n'' has invalid keys: unknown_field"), | ||||
| 		}), | ||||
| 	) | ||||
| }) | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ type Header struct { | |||
| 	// should be preserved for the request to the upstream server.
 | ||||
| 	// This option only applies to injected request headers.
 | ||||
| 	// Defaults to false (headers that match this header will be stripped).
 | ||||
| 	PreserveRequestValue bool `yaml:"preserveRequestValue,omitempty"` | ||||
| 	PreserveRequestValue bool `yaml:"preserveRequestValue"` | ||||
| 
 | ||||
| 	// Values contains the desired values for this header
 | ||||
| 	Values []HeaderValue `yaml:"values,omitempty"` | ||||
|  |  | |||
|  | @ -41,3 +41,17 @@ func toDurationHookFunc() mapstructure.DecodeHookFunc { | |||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // StringToBytesHookFunc returns a DecodeHookFunc that converts string to []byte.
 | ||||
| func stringToBytesHookFunc() mapstructure.DecodeHookFunc { | ||||
| 	return func( | ||||
| 		f reflect.Type, | ||||
| 		t reflect.Type, | ||||
| 		data interface{}, | ||||
| 	) (interface{}, error) { | ||||
| 		if f.Kind() == reflect.String && t == reflect.TypeOf([]byte{}) { | ||||
| 			return []byte(data.(string)), nil | ||||
| 		} | ||||
| 		return data, nil | ||||
| 	} | ||||
| } | ||||
|  | @ -5,7 +5,7 @@ import ( | |||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| func TestDecode(t *testing.T) { | ||||
| func TestToDurationHook(t *testing.T) { | ||||
| 	type result struct { | ||||
| 		Duration time.Duration `yaml:"duration"` | ||||
| 	} | ||||
|  | @ -80,3 +80,17 @@ func TestDecode(t *testing.T) { | |||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestStringToBytesHook(t *testing.T) { | ||||
| 	var result struct { | ||||
| 		Value []byte `yaml:"value"` | ||||
| 	} | ||||
| 
 | ||||
| 	if err := Decode(map[string]interface{}{"value": "hello-world"}, &result); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	if string(result.Value) != "hello-world" { | ||||
| 		t.Errorf("expected %q, got %q", "hello-world", string(result.Value)) | ||||
| 	} | ||||
| } | ||||
|  | @ -89,7 +89,10 @@ func LoadYAML(configFileName string, opts interface{}) error { | |||
| // - An error if decoding fails or if there are unmapped keys.
 | ||||
| func Decode(input interface{}, result interface{}) error { | ||||
| 	decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ | ||||
| 		DecodeHook:           mapstructure.ComposeDecodeHookFunc(toDurationHookFunc()), | ||||
| 		DecodeHook: mapstructure.ComposeDecodeHookFunc( | ||||
| 			toDurationHookFunc(), | ||||
| 			stringToBytesHookFunc(), | ||||
| 		), | ||||
| 		Metadata:             nil,    // Don't track any metadata
 | ||||
| 		Result:               result, // Decode the result into the prefilled options
 | ||||
| 		TagName:              "yaml", // Parse all fields that use the json tag
 | ||||
|  |  | |||
|  | @ -155,7 +155,7 @@ var _ = Describe("Load", func() { | |||
| 				} | ||||
| 				err := Load(configFileName, flagSet, input) | ||||
| 				if o.expectedErr != nil { | ||||
| 					Expect(err).To(MatchError(o.expectedErr.Error())) | ||||
| 					Expect(err).To(MatchError(ContainSubstring(o.expectedErr.Error()))) | ||||
| 				} else { | ||||
| 					Expect(err).ToNot(HaveOccurred()) | ||||
| 				} | ||||
|  | @ -471,7 +471,7 @@ sub: | |||
| 				configFile:     []byte(`stringSliceOption: "a"`), | ||||
| 				input:          &TestOptions{}, | ||||
| 				expectedOutput: &TestOptions{}, | ||||
| 				expectedErr:    errors.New("error unmarshalling config: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go struct field TestOptions.TestOptionSubStruct.StringSliceOption of type []string"), | ||||
| 				expectedErr:    errors.New("error decoding config: decoding failed due to the following error(s):\n\n'stringSliceOption' source data must be an array or slice, got string"), | ||||
| 			}), | ||||
| 			Entry("with a config file containing environment variable references", loadYAMLTableInput{ | ||||
| 				configFile: []byte("stringOption: ${TESTUSER}"), | ||||
|  |  | |||
|  | @ -67,7 +67,7 @@ type Provider struct { | |||
| 	CAFiles []string `yaml:"caFiles,omitempty"` | ||||
| 	// UseSystemTrustStore determines if your custom CA files and the system trust store are used
 | ||||
| 	// If set to true, your custom CA files and the system trust store are used otherwise only your custom CA files.
 | ||||
| 	UseSystemTrustStore bool `yaml:"useSystemTrustStore,omitempty"` | ||||
| 	UseSystemTrustStore bool `yaml:"useSystemTrustStore"` | ||||
| 	// LoginURL is the authentication endpoint
 | ||||
| 	LoginURL string `yaml:"loginURL,omitempty"` | ||||
| 	// LoginURLParameters defines the parameters that can be passed from the start URL to the IdP login URL
 | ||||
|  | @ -80,7 +80,7 @@ type Provider struct { | |||
| 	ProfileURL string `yaml:"profileURL,omitempty"` | ||||
| 	// SkipClaimsFromProfileURL allows to skip request to Profile URL for resolving claims not present in id_token
 | ||||
| 	// default set to 'false'
 | ||||
| 	SkipClaimsFromProfileURL bool `yaml:"skipClaimsFromProfileURL,omitempty"` | ||||
| 	SkipClaimsFromProfileURL bool `yaml:"skipClaimsFromProfileURL"` | ||||
| 	// ProtectedResource is the resource that is protected (Azure AD and ADFS only)
 | ||||
| 	ProtectedResource string `yaml:"resource,omitempty"` | ||||
| 	// ValidateURL is the access token validation endpoint
 | ||||
|  | @ -181,13 +181,13 @@ type MicrosoftEntraIDOptions struct { | |||
| 
 | ||||
| 	// FederatedTokenAuth enable oAuth2 client authentication with federated token projected
 | ||||
| 	// by Entra Workload Identity plugin, instead of client secret.
 | ||||
| 	FederatedTokenAuth bool `yaml:"federatedTokenAuth,omitempty"` | ||||
| 	FederatedTokenAuth bool `yaml:"federatedTokenAuth"` | ||||
| } | ||||
| 
 | ||||
| type ADFSOptions struct { | ||||
| 	// Skip adding the scope parameter in login request
 | ||||
| 	// Default value is 'false'
 | ||||
| 	SkipScope bool `yaml:"skipScope,omitempty"` | ||||
| 	SkipScope bool `yaml:"skipScope"` | ||||
| } | ||||
| 
 | ||||
| type BitbucketOptions struct { | ||||
|  | @ -227,7 +227,7 @@ type GoogleOptions struct { | |||
| 	// ServiceAccountJSON is the path to the service account json credentials
 | ||||
| 	ServiceAccountJSON string `yaml:"serviceAccountJson,omitempty"` | ||||
| 	// UseApplicationDefaultCredentials is a boolean whether to use Application Default Credentials instead of a ServiceAccountJSON
 | ||||
| 	UseApplicationDefaultCredentials bool `yaml:"useApplicationDefaultCredentials,omitempty"` | ||||
| 	UseApplicationDefaultCredentials bool `yaml:"useApplicationDefaultCredentials"` | ||||
| 	// TargetPrincipal is the Google Service Account used for Application Default Credentials
 | ||||
| 	TargetPrincipal string `yaml:"targetPrincipal,omitempty"` | ||||
| } | ||||
|  | @ -250,7 +250,7 @@ type OIDCOptions struct { | |||
| 	InsecureSkipNonce bool `yaml:"insecureSkipNonce"` | ||||
| 	// SkipDiscovery allows to skip OIDC discovery and use manually supplied Endpoints
 | ||||
| 	// default set to 'false'
 | ||||
| 	SkipDiscovery bool `yaml:"skipDiscovery,omitempty"` | ||||
| 	SkipDiscovery bool `yaml:"skipDiscovery"` | ||||
| 	// JwksURL is the OpenID Connect JWKS URL
 | ||||
| 	// eg: https://www.googleapis.com/oauth2/v3/certs
 | ||||
| 	JwksURL string `yaml:"jwksURL,omitempty"` | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ const ( | |||
| type UpstreamConfig struct { | ||||
| 	// ProxyRawPath will pass the raw url path to upstream allowing for urls
 | ||||
| 	// like: "/%2F/" which would otherwise be redirected to "/"
 | ||||
| 	ProxyRawPath bool `yaml:"proxyRawPath,omitempty"` | ||||
| 	ProxyRawPath bool `yaml:"proxyRawPath"` | ||||
| 
 | ||||
| 	// Upstreams represents the configuration for the upstream servers.
 | ||||
| 	// Requests will be proxied to this upstream if the path matches the request path.
 | ||||
|  | @ -64,13 +64,13 @@ type Upstream struct { | |||
| 	// This option is insecure and will allow potential Man-In-The-Middle attacks
 | ||||
| 	// between OAuth2 Proxy and the upstream server.
 | ||||
| 	// Defaults to false.
 | ||||
| 	InsecureSkipTLSVerify bool `yaml:"insecureSkipTLSVerify,omitempty"` | ||||
| 	InsecureSkipTLSVerify bool `yaml:"insecureSkipTLSVerify"` | ||||
| 
 | ||||
| 	// Static will make all requests to this upstream have a static response.
 | ||||
| 	// The response will have a body of "Authenticated" and a response code
 | ||||
| 	// matching StaticCode.
 | ||||
| 	// If StaticCode is not set, the response will return a 200 response.
 | ||||
| 	Static bool `yaml:"static,omitempty"` | ||||
| 	Static bool `yaml:"static"` | ||||
| 
 | ||||
| 	// StaticCode determines the response code for the Static response.
 | ||||
| 	// This option can only be used with Static enabled.
 | ||||
|  | @ -84,11 +84,11 @@ type Upstream struct { | |||
| 	// PassHostHeader determines whether the request host header should be proxied
 | ||||
| 	// to the upstream server.
 | ||||
| 	// Defaults to true.
 | ||||
| 	PassHostHeader *bool `yaml:"passHostHeader,omitempty"` | ||||
| 	PassHostHeader *bool `yaml:"passHostHeader"` | ||||
| 
 | ||||
| 	// ProxyWebSockets enables proxying of websockets to upstream servers
 | ||||
| 	// Defaults to true.
 | ||||
| 	ProxyWebSockets *bool `yaml:"proxyWebSockets,omitempty"` | ||||
| 	ProxyWebSockets *bool `yaml:"proxyWebSockets"` | ||||
| 
 | ||||
| 	// Timeout is the maximum duration the server will wait for a response from the upstream server.
 | ||||
| 	// Defaults to 30 seconds.
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue