Merge 9db77384d0 into 9168731c7a
				
					
				
			This commit is contained in:
		
						commit
						40b75a6f0b
					
				|  | @ -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 | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										4
									
								
								Makefile
								
								
								
								
							|  | @ -75,6 +75,10 @@ DOCKER_BUILDX_PUSH_X_PLATFORM_ALPINE := $(DOCKER_BUILDX_X_PLATFORM_ALPINE) --pus | ||||||
| .PHONY: build-docker | .PHONY: build-docker | ||||||
| build-docker: build-distroless build-alpine ## Build multi architecture docker images in both flavours (distroless / alpine)
 | build-docker: build-distroless build-alpine ## Build multi architecture docker images in both flavours (distroless / alpine)
 | ||||||
| 
 | 
 | ||||||
|  | .PHONY: build-docker-local | ||||||
|  | build-docker-local: ## Build distroless docker image and locally load into docker images
 | ||||||
|  | 	$(DOCKER_BUILDX) --load -t $(REGISTRY)/$(REPOSITORY):${VERSION}-local . | ||||||
|  | 
 | ||||||
| .PHONY: build-distroless | .PHONY: build-distroless | ||||||
| build-distroless: ## Build multi architecture distroless based docker image
 | build-distroless: ## Build multi architecture distroless based docker image
 | ||||||
| 	$(DOCKER_BUILDX_X_PLATFORM) -t $(REGISTRY)/$(REPOSITORY):latest -t $(REGISTRY)/$(REPOSITORY):${VERSION} . | 	$(DOCKER_BUILDX_X_PLATFORM) -t $(REGISTRY)/$(REPOSITORY):latest -t $(REGISTRY)/$(REPOSITORY):${VERSION} . | ||||||
|  |  | ||||||
|  | @ -10,11 +10,58 @@ | ||||||
| #    make alpha-config-<command> (eg make nginx-up, make nginx-down) | #    make alpha-config-<command> (eg make nginx-up, make nginx-down) | ||||||
| # | # | ||||||
| # Access http://localhost:4180 to initiate a login cycle | # Access http://localhost:4180 to initiate a login cycle | ||||||
| version: '3.0' | version: "3.0" | ||||||
| services: | services: | ||||||
|   oauth2-proxy: |   oauth2-proxy: | ||||||
|  |     container_name: oauth2-proxy | ||||||
|     image: quay.io/oauth2-proxy/oauth2-proxy:v7.12.0 |     image: quay.io/oauth2-proxy/oauth2-proxy:v7.12.0 | ||||||
|     command: --config /oauth2-proxy.cfg --alpha-config /oauth2-proxy-alpha-config.yaml |     command: --config /oauth2-proxy.cfg --alpha-config /oauth2-proxy-alpha-config.yaml | ||||||
|  |     hostname: oauth2-proxy | ||||||
|     volumes: |     volumes: | ||||||
|       - "./oauth2-proxy-alpha-config.cfg:/oauth2-proxy.cfg" |       - "./oauth2-proxy-alpha-config.cfg:/oauth2-proxy.cfg" | ||||||
|       - "./oauth2-proxy-alpha-config.yaml:/oauth2-proxy-alpha-config.yaml" |       - "./oauth2-proxy-alpha-config.yaml:/oauth2-proxy-alpha-config.yaml" | ||||||
|  |     restart: unless-stopped | ||||||
|  |     ports: | ||||||
|  |       - 4180:4180/tcp | ||||||
|  |     networks: | ||||||
|  |       dex: {} | ||||||
|  |       httpbin: {} | ||||||
|  |     depends_on: | ||||||
|  |       - dex | ||||||
|  |       - httpbin | ||||||
|  |   dex: | ||||||
|  |     container_name: dex | ||||||
|  |     image: ghcr.io/dexidp/dex:v2.43.1 | ||||||
|  |     command: dex serve /dex.yaml | ||||||
|  |     hostname: dex | ||||||
|  |     volumes: | ||||||
|  |       - "./dex.yaml:/dex.yaml" | ||||||
|  |     restart: unless-stopped | ||||||
|  |     ports: | ||||||
|  |       - 5556:5556/tcp | ||||||
|  |     networks: | ||||||
|  |       dex: | ||||||
|  |         aliases: | ||||||
|  |           - dex.localtest.me | ||||||
|  |       etcd: {} | ||||||
|  |     depends_on: | ||||||
|  |       - etcd | ||||||
|  |   httpbin: | ||||||
|  |     container_name: httpbin | ||||||
|  |     image: kennethreitz/httpbin | ||||||
|  |     ports: [] | ||||||
|  |     networks: | ||||||
|  |       httpbin: {} | ||||||
|  |   etcd: | ||||||
|  |     container_name: etcd | ||||||
|  |     image: gcr.io/etcd-development/etcd:v3.6.2 | ||||||
|  |     entrypoint: /usr/local/bin/etcd | ||||||
|  |     command: | ||||||
|  |       - --listen-client-urls=http://0.0.0.0:2379 | ||||||
|  |       - --advertise-client-urls=http://etcd:2379 | ||||||
|  |     networks: | ||||||
|  |       etcd: {} | ||||||
|  | networks: | ||||||
|  |   dex: {} | ||||||
|  |   etcd: {} | ||||||
|  |   httpbin: {} | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ | ||||||
| #    make <command> (eg. make up, make down) | #    make <command> (eg. make up, make down) | ||||||
| # | # | ||||||
| # Access http://oauth2-proxy.localtest.me:4180 to initiate a login cycle | # Access http://oauth2-proxy.localtest.me:4180 to initiate a login cycle | ||||||
| version: '3.0' | version: "3.0" | ||||||
| services: | services: | ||||||
|   oauth2-proxy: |   oauth2-proxy: | ||||||
|     container_name: oauth2-proxy |     container_name: oauth2-proxy | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| http_address="0.0.0.0:4180" |  | ||||||
| cookie_secret="OQINaROshtE9TcZkNAm-5Zs2Pv3xaWytBmc5W7sPX7w=" | cookie_secret="OQINaROshtE9TcZkNAm-5Zs2Pv3xaWytBmc5W7sPX7w=" | ||||||
| email_domains="example.com" | email_domains="example.com" | ||||||
| cookie_secure="false" | cookie_secure="false" | ||||||
| redirect_url="http://localhost:4180/oauth2/callback" | redirect_url="http://oauth2-proxy.localtest.me:4180/oauth2/callback" | ||||||
|  |  | ||||||
|  | @ -1,23 +1,23 @@ | ||||||
| upstreams: | server: | ||||||
|  |   bindAddress: "0.0.0.0:4180" | ||||||
|  | upstreamConfig: | ||||||
|  |   upstreams: | ||||||
|     - id: httpbin |     - id: httpbin | ||||||
|       path: / |       path: / | ||||||
|       uri: http://httpbin |       uri: http://httpbin | ||||||
| injectRequestHeaders: | injectRequestHeaders: | ||||||
| - name: X-Forwarded-Groups |   - name: X-Forwarded-User | ||||||
|     values: |     values: | ||||||
|   - claim: groups |       - claimSource: | ||||||
| - name: X-Forwarded-User |           claim: user | ||||||
|  |   - name: X-Forwarded-Email | ||||||
|     values: |     values: | ||||||
|   -   claim: user |       - claimSource: | ||||||
| - name: X-Forwarded-Email |           claim: email | ||||||
|   values: |  | ||||||
|   - claim: email |  | ||||||
| - name: X-Forwarded-Preferred-Username |  | ||||||
|   values: |  | ||||||
|   - claim: preferred_username |  | ||||||
| providers: | providers: | ||||||
| - provider: oidc |   - id: oidc | ||||||
|  |     provider: oidc | ||||||
|     clientSecret: b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK |     clientSecret: b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK | ||||||
|     clientID: oauth2-proxy |     clientID: oauth2-proxy | ||||||
|     oidcConfig: |     oidcConfig: | ||||||
|     issuerURL: http://dex.localhost:5556/dex |       issuerURL: http://dex.localtest.me:5556/dex | ||||||
|  |  | ||||||
|  | @ -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)) | ||||||
|  | @ -499,9 +489,9 @@ Server represents the configuration for an HTTP(S) server | ||||||
| 
 | 
 | ||||||
| | Field | Type | Description | | | Field | Type | Description | | ||||||
| | ----- | ---- | ----------- | | | ----- | ---- | ----------- | | ||||||
| | `BindAddress` | _string_ | BindAddress is the address on which to serve traffic.<br/>Leave blank or set to "-" to disable. | | | `bindAddress` | _string_ | BindAddress is the address on which to serve traffic.<br/>Leave blank or set to "-" to disable. | | ||||||
| | `SecureBindAddress` | _string_ | SecureBindAddress is the address on which to serve secure traffic.<br/>Leave blank or set to "-" to disable. | | | `secureBindAddress` | _string_ | SecureBindAddress is the address on which to serve secure traffic.<br/>Leave blank or set to "-" to disable. | | ||||||
| | `TLS` | _[TLS](#tls)_ | TLS contains the information for loading the certificate and key for the<br/>secure traffic and further configuration for the TLS server. | | | `tls` | _[TLS](#tls)_ | TLS contains the information for loading the certificate and key for the<br/>secure traffic and further configuration for the TLS server. | | ||||||
| 
 | 
 | ||||||
| ### TLS | ### TLS | ||||||
| 
 | 
 | ||||||
|  | @ -512,10 +502,10 @@ as well as an optional minimal TLS version that is acceptable. | ||||||
| 
 | 
 | ||||||
| | Field | Type | Description | | | Field | Type | Description | | ||||||
| | ----- | ---- | ----------- | | | ----- | ---- | ----------- | | ||||||
| | `Key` | _[SecretSource](#secretsource)_ | Key is the TLS key data to use.<br/>Typically this will come from a file. | | | `key` | _[SecretSource](#secretsource)_ | Key is the TLS key data to use.<br/>Typically this will come from a file. | | ||||||
| | `Cert` | _[SecretSource](#secretsource)_ | Cert is the TLS certificate data to use.<br/>Typically this will come from a file. | | | `cert` | _[SecretSource](#secretsource)_ | Cert is the TLS certificate data to use.<br/>Typically this will come from a file. | | ||||||
| | `MinVersion` | _string_ | MinVersion is the minimal TLS version that is acceptable.<br/>E.g. Set to "TLS1.3" to select TLS version 1.3 | | | `minVersion` | _string_ | MinVersion is the minimal TLS version that is acceptable.<br/>E.g. Set to "TLS1.3" to select TLS version 1.3 | | ||||||
| | `CipherSuites` | _[]string_ | CipherSuites is a list of TLS cipher suites that are allowed.<br/>E.g.:<br/>- TLS_RSA_WITH_RC4_128_SHA<br/>- TLS_RSA_WITH_AES_256_GCM_SHA384<br/>If not specified, the default Go safe cipher list is used.<br/>List of valid cipher suites can be found in the [crypto/tls documentation](https://pkg.go.dev/crypto/tls#pkg-constants). | | | `cipherSuites` | _[]string_ | CipherSuites is a list of TLS cipher suites that are allowed.<br/>E.g.:<br/>- TLS_RSA_WITH_RC4_128_SHA<br/>- TLS_RSA_WITH_AES_256_GCM_SHA384<br/>If not specified, the default Go safe cipher list is used.<br/>List of valid cipher suites can be found in the [crypto/tls documentation](https://pkg.go.dev/crypto/tls#pkg-constants). | | ||||||
| 
 | 
 | ||||||
| ### URLParameterRule | ### URLParameterRule | ||||||
| 
 | 
 | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										13
									
								
								go.mod
								
								
								
								
							|  | @ -13,7 +13,6 @@ require ( | ||||||
| 	github.com/coreos/go-oidc/v3 v3.14.1 | 	github.com/coreos/go-oidc/v3 v3.14.1 | ||||||
| 	github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf | 	github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf | ||||||
| 	github.com/fsnotify/fsnotify v1.9.0 | 	github.com/fsnotify/fsnotify v1.9.0 | ||||||
| 	github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 |  | ||||||
| 	github.com/go-jose/go-jose/v3 v3.0.4 | 	github.com/go-jose/go-jose/v3 v3.0.4 | ||||||
| 	github.com/go-viper/mapstructure/v2 v2.4.0 | 	github.com/go-viper/mapstructure/v2 v2.4.0 | ||||||
| 	github.com/golang-jwt/jwt/v5 v5.2.3 | 	github.com/golang-jwt/jwt/v5 v5.2.3 | ||||||
|  | @ -24,7 +23,7 @@ require ( | ||||||
| 	github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa | 	github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa | ||||||
| 	github.com/oauth2-proxy/mockoidc v0.0.0-20240214162133-caebfff84d25 | 	github.com/oauth2-proxy/mockoidc v0.0.0-20240214162133-caebfff84d25 | ||||||
| 	github.com/onsi/ginkgo/v2 v2.23.4 | 	github.com/onsi/ginkgo/v2 v2.23.4 | ||||||
| 	github.com/onsi/gomega v1.37.0 | 	github.com/onsi/gomega v1.38.0 | ||||||
| 	github.com/pierrec/lz4/v4 v4.1.22 | 	github.com/pierrec/lz4/v4 v4.1.22 | ||||||
| 	github.com/prometheus/client_golang v1.22.0 | 	github.com/prometheus/client_golang v1.22.0 | ||||||
| 	github.com/redis/go-redis/v9 v9.11.0 | 	github.com/redis/go-redis/v9 v9.11.0 | ||||||
|  | @ -37,13 +36,14 @@ require ( | ||||||
| 	golang.org/x/net v0.42.0 | 	golang.org/x/net v0.42.0 | ||||||
| 	golang.org/x/oauth2 v0.30.0 | 	golang.org/x/oauth2 v0.30.0 | ||||||
| 	golang.org/x/sync v0.16.0 | 	golang.org/x/sync v0.16.0 | ||||||
| 	google.golang.org/api v0.242.0 | 	google.golang.org/api v0.243.0 | ||||||
| 	gopkg.in/natefinch/lumberjack.v2 v2.2.1 | 	gopkg.in/natefinch/lumberjack.v2 v2.2.1 | ||||||
|  | 	gopkg.in/yaml.v3 v3.0.1 | ||||||
| 	k8s.io/apimachinery v0.33.3 | 	k8s.io/apimachinery v0.33.3 | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	cloud.google.com/go/auth v0.16.2 // indirect | 	cloud.google.com/go/auth v0.16.3 // indirect | ||||||
| 	cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect | 	cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect | ||||||
| 	github.com/beorn7/perks v1.0.1 // indirect | 	github.com/beorn7/perks v1.0.1 // indirect | ||||||
| 	github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect | 	github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect | ||||||
|  | @ -83,9 +83,8 @@ require ( | ||||||
| 	golang.org/x/sys v0.34.0 // indirect | 	golang.org/x/sys v0.34.0 // indirect | ||||||
| 	golang.org/x/text v0.27.0 // indirect | 	golang.org/x/text v0.27.0 // indirect | ||||||
| 	golang.org/x/tools v0.35.0 // indirect | 	golang.org/x/tools v0.35.0 // indirect | ||||||
| 	google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect | 	google.golang.org/genproto/googleapis/rpc v0.0.0-20250721164621-a45f3dfb1074 // indirect | ||||||
| 	google.golang.org/grpc v1.73.0 // indirect | 	google.golang.org/grpc v1.74.2 // indirect | ||||||
| 	google.golang.org/protobuf v1.36.6 // indirect | 	google.golang.org/protobuf v1.36.6 // indirect | ||||||
| 	gopkg.in/yaml.v2 v2.4.0 // indirect | 	gopkg.in/yaml.v2 v2.4.0 // indirect | ||||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
							
								
								
									
										89
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										89
									
								
								go.sum
								
								
								
								
							|  | @ -1,12 +1,11 @@ | ||||||
| cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4= | cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= | ||||||
| cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA= | cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= | ||||||
| cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= | cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= | ||||||
| cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= | cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= | ||||||
| cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= | cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= | ||||||
| cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= | cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= | ||||||
| github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb h1:ZVN4Iat3runWOFLaBCDVU5a9X/XikSRBosye++6gojw= | github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb h1:ZVN4Iat3runWOFLaBCDVU5a9X/XikSRBosye++6gojw= | ||||||
| github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb/go.mod h1:WsAABbY4HQBgd3mGuG4KMNTbHJCPvx9IVBHzysbknss= | github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb/go.mod h1:WsAABbY4HQBgd3mGuG4KMNTbHJCPvx9IVBHzysbknss= | ||||||
| github.com/FZambia/sentinel v1.0.0 h1:KJ0ryjKTZk5WMp0dXvSdNqp3lFaW1fNFuEYfrkLOYIc= |  | ||||||
| github.com/FZambia/sentinel v1.0.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI= | github.com/FZambia/sentinel v1.0.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI= | ||||||
| github.com/a8m/envsubst v1.4.3 h1:kDF7paGK8QACWYaQo6KtyYBozY2jhQrTuNNuUxQkhJY= | github.com/a8m/envsubst v1.4.3 h1:kDF7paGK8QACWYaQo6KtyYBozY2jhQrTuNNuUxQkhJY= | ||||||
| github.com/a8m/envsubst v1.4.3/go.mod h1:4jjHWQlZoaXPoLQUb7H2qT4iLkZDdmEQiOUogdUmqVU= | github.com/a8m/envsubst v1.4.3/go.mod h1:4jjHWQlZoaXPoLQUb7H2qT4iLkZDdmEQiOUogdUmqVU= | ||||||
|  | @ -20,12 +19,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= | ||||||
| github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= | ||||||
| github.com/bitly/go-simplejson v0.5.1 h1:xgwPbetQScXt1gh9BmoJ6j9JMr3TElvuIyjR8pgdoow= | github.com/bitly/go-simplejson v0.5.1 h1:xgwPbetQScXt1gh9BmoJ6j9JMr3TElvuIyjR8pgdoow= | ||||||
| github.com/bitly/go-simplejson v0.5.1/go.mod h1:YOPVLzCfwK14b4Sff3oP1AmGhI9T9Vsg84etUnlyp+Q= | github.com/bitly/go-simplejson v0.5.1/go.mod h1:YOPVLzCfwK14b4Sff3oP1AmGhI9T9Vsg84etUnlyp+Q= | ||||||
| github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= |  | ||||||
| github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= | github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= | ||||||
| github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= |  | ||||||
| github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= |  | ||||||
| github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= |  | ||||||
| github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= |  | ||||||
| github.com/bsm/redislock v0.9.4 h1:X/Wse1DPpiQgHbVYRE9zv6m070UcKoOGekgvpNhiSvw= | github.com/bsm/redislock v0.9.4 h1:X/Wse1DPpiQgHbVYRE9zv6m070UcKoOGekgvpNhiSvw= | ||||||
| github.com/bsm/redislock v0.9.4/go.mod h1:Epf7AJLiSFwLCiZcfi6pWFO/8eAYrYpQXFxEDPoDeAk= | github.com/bsm/redislock v0.9.4/go.mod h1:Epf7AJLiSFwLCiZcfi6pWFO/8eAYrYpQXFxEDPoDeAk= | ||||||
| github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= | github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= | ||||||
|  | @ -44,12 +38,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r | ||||||
| github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= | ||||||
| github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= | github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= | ||||||
| github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= | github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= | ||||||
| github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= |  | ||||||
| github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= |  | ||||||
| github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= | github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= | ||||||
| github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= | github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= | ||||||
| github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4= |  | ||||||
| github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= |  | ||||||
| github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= | github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= | ||||||
| github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= | github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= | ||||||
| github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI= | github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI= | ||||||
|  | @ -61,17 +51,10 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= | ||||||
| github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= | ||||||
| github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= | ||||||
| github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= | ||||||
| github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= |  | ||||||
| github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= |  | ||||||
| github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= | github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= | ||||||
| github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= | github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= | ||||||
| github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= |  | ||||||
| github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= |  | ||||||
| github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0= | github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0= | ||||||
| github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= | github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= | ||||||
| github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= |  | ||||||
| github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= |  | ||||||
| github.com/gomodule/redigo v1.7.1-0.20190322064113-39e2c31b7ca3 h1:6amM4HsNPOvMLVc2ZnyqrjeQ92YAVWn7T4WBKK87inY= |  | ||||||
| github.com/gomodule/redigo v1.7.1-0.20190322064113-39e2c31b7ca3/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= | github.com/gomodule/redigo v1.7.1-0.20190322064113-39e2c31b7ca3/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= | ||||||
| github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | ||||||
| github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= | ||||||
|  | @ -85,23 +68,14 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= | ||||||
| github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||||
| github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= | github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= | ||||||
| github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= | github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= | ||||||
| github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= |  | ||||||
| github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= |  | ||||||
| github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= | github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= | ||||||
| github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= | github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= | ||||||
| github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= | github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= | ||||||
| github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= | github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= | ||||||
| github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo= | github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo= | ||||||
| github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA= | github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA= | ||||||
| github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= |  | ||||||
| github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= |  | ||||||
| github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= |  | ||||||
| github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= |  | ||||||
| github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= |  | ||||||
| github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= |  | ||||||
| github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= | ||||||
| github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= | ||||||
| github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= |  | ||||||
| github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= | github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= | ||||||
| github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa h1:hI1uC2A3vJFjwvBn0G0a7QBRdBUp6Y048BtLAHRTKPo= | github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa h1:hI1uC2A3vJFjwvBn0G0a7QBRdBUp6Y048BtLAHRTKPo= | ||||||
| github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa/go.mod h1:8vxFeeg++MqgCHwehSuwTlYCF0ALyDJbYJ1JsKi7v6s= | github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa/go.mod h1:8vxFeeg++MqgCHwehSuwTlYCF0ALyDJbYJ1JsKi7v6s= | ||||||
|  | @ -111,8 +85,8 @@ github.com/oauth2-proxy/mockoidc v0.0.0-20240214162133-caebfff84d25 h1:9bCMuD3Tc | ||||||
| github.com/oauth2-proxy/mockoidc v0.0.0-20240214162133-caebfff84d25/go.mod h1:eDjgYHYDJbPLBLsyZ6qRaugP0mX8vePOhZ5id1fdzJw= | github.com/oauth2-proxy/mockoidc v0.0.0-20240214162133-caebfff84d25/go.mod h1:eDjgYHYDJbPLBLsyZ6qRaugP0mX8vePOhZ5id1fdzJw= | ||||||
| github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= | github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= | ||||||
| github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= | github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= | ||||||
| github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= | github.com/onsi/gomega v1.38.0 h1:c/WX+w8SLAinvuKKQFh77WEucCnPk4j2OTUr7lt7BeY= | ||||||
| github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= | github.com/onsi/gomega v1.38.0/go.mod h1:OcXcwId0b9QsE7Y49u+BTrL4IdKOBOKnD6VQNTJEB6o= | ||||||
| github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= | github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= | ||||||
| github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= | github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= | ||||||
| github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= | github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= | ||||||
|  | @ -120,8 +94,6 @@ github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFu | ||||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
| github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= | ||||||
| github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
| github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= |  | ||||||
| github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= |  | ||||||
| github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= | github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= | ||||||
| github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= | github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= | ||||||
| github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= | github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= | ||||||
|  | @ -132,7 +104,6 @@ github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7D | ||||||
| github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= | github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= | ||||||
| github.com/redis/go-redis/v9 v9.11.0 h1:E3S08Gl/nJNn5vkxd2i78wZxWAPNZgUNTp8WIJUAiIs= | github.com/redis/go-redis/v9 v9.11.0 h1:E3S08Gl/nJNn5vkxd2i78wZxWAPNZgUNTp8WIJUAiIs= | ||||||
| github.com/redis/go-redis/v9 v9.11.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= | github.com/redis/go-redis/v9 v9.11.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= | ||||||
| github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= |  | ||||||
| github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= | github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= | ||||||
| github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= | github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= | ||||||
| github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= | github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= | ||||||
|  | @ -142,8 +113,6 @@ github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= | ||||||
| github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= | github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= | ||||||
| github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= | github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= | ||||||
| github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= | github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= | ||||||
| github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= |  | ||||||
| github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= |  | ||||||
| github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= | github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= | ||||||
| github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= | github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= | ||||||
| github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= | github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= | ||||||
|  | @ -165,18 +134,12 @@ github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M | ||||||
| github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= | github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= | ||||||
| go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= | go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= | ||||||
| go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= | go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= | ||||||
| go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= |  | ||||||
| go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= |  | ||||||
| go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= | ||||||
| go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= | ||||||
| go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= | go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= | ||||||
| go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= | go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= | ||||||
| go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= | go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= | ||||||
| go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= | go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= | ||||||
| go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= |  | ||||||
| go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= |  | ||||||
| go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= |  | ||||||
| go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= |  | ||||||
| go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= | go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= | ||||||
| go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= | go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= | ||||||
| go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= | go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= | ||||||
|  | @ -186,8 +149,6 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 | ||||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||||
| golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||||||
| golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= | golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= | ||||||
| golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= |  | ||||||
| golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= |  | ||||||
| golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= | golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= | ||||||
| golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= | golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= | ||||||
| golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | ||||||
|  | @ -197,8 +158,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v | ||||||
| golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | ||||||
| golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= | ||||||
| golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= | ||||||
| golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= |  | ||||||
| golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= |  | ||||||
| golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= | golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= | ||||||
| golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= | golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= | ||||||
| golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= | golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= | ||||||
|  | @ -206,8 +165,6 @@ golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKl | ||||||
| golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= |  | ||||||
| golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= |  | ||||||
| golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= | golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= | ||||||
| golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= | golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= | ||||||
| golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
|  | @ -219,8 +176,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc | ||||||
| golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | ||||||
| golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= |  | ||||||
| golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= |  | ||||||
| golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= | golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= | ||||||
| golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= | golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= | ||||||
| golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||||||
|  | @ -234,53 +189,29 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | ||||||
| golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= | ||||||
| golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= | ||||||
| golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= | ||||||
| golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= |  | ||||||
| golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= |  | ||||||
| golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= | golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= | ||||||
| golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= | golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= | ||||||
| golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= |  | ||||||
| golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= |  | ||||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||||
| golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||||||
| golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | ||||||
| golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= | ||||||
| golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= |  | ||||||
| golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= |  | ||||||
| golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= | golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= | ||||||
| golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= | golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= | ||||||
| golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
| google.golang.org/api v0.240.0 h1:PxG3AA2UIqT1ofIzWV2COM3j3JagKTKSwy7L6RHNXNU= | google.golang.org/api v0.243.0 h1:sw+ESIJ4BVnlJcWu9S+p2Z6Qq1PjG77T8IJ1xtp4jZQ= | ||||||
| google.golang.org/api v0.240.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= | google.golang.org/api v0.243.0/go.mod h1:GE4QtYfaybx1KmeHMdBnNnyLzBZCVihGBXAmJu/uUr8= | ||||||
| google.golang.org/api v0.241.0 h1:QKwqWQlkc6O895LchPEDUSYr22Xp3NCxpQRiWTB6avE= | google.golang.org/genproto/googleapis/rpc v0.0.0-20250721164621-a45f3dfb1074 h1:qJW29YvkiJmXOYMu5Tf8lyrTp3dOS+K4z6IixtLaCf8= | ||||||
| google.golang.org/api v0.241.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= | google.golang.org/genproto/googleapis/rpc v0.0.0-20250721164621-a45f3dfb1074/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= | ||||||
| google.golang.org/api v0.242.0 h1:7Lnb1nfnpvbkCiZek6IXKdJ0MFuAZNAJKQfA1ws62xg= | google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= | ||||||
| google.golang.org/api v0.242.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= | google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= | ||||||
| google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78= |  | ||||||
| google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk= |  | ||||||
| google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= |  | ||||||
| google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 h1:vPV0tzlsK6EzEDHNNH5sa7Hs9bd7iXR7B1tSiPepkV0= |  | ||||||
| google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw= |  | ||||||
| google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= |  | ||||||
| google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= |  | ||||||
| google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= |  | ||||||
| google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= |  | ||||||
| google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= |  | ||||||
| google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= |  | ||||||
| google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= |  | ||||||
| google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= | google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= | ||||||
| google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= | google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
| gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= |  | ||||||
| gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= |  | ||||||
| gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= | gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= | ||||||
| gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= | gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= | ||||||
| gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |  | ||||||
| gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= |  | ||||||
| gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | ||||||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||||
| k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY= |  | ||||||
| k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= |  | ||||||
| k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= | k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= | ||||||
| k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= | k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= | ||||||
|  |  | ||||||
							
								
								
									
										38
									
								
								main.go
								
								
								
								
							
							
						
						
									
										38
									
								
								main.go
								
								
								
								
							|  | @ -5,12 +5,12 @@ import ( | ||||||
| 	"os" | 	"os" | ||||||
| 	"runtime" | 	"runtime" | ||||||
| 
 | 
 | ||||||
| 	"github.com/ghodss/yaml" |  | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/validation" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/validation" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/version" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/version" | ||||||
| 	"github.com/spf13/pflag" | 	"github.com/spf13/pflag" | ||||||
|  | 	"gopkg.in/yaml.v3" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
|  | @ -67,12 +67,18 @@ 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, fmt.Errorf("failed to load legacy options: %w", 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, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // loadLegacyOptions loads the old toml options using the legacy flagset
 | // loadLegacyOptions loads the old toml options using the legacy flagset
 | ||||||
|  | @ -97,17 +103,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 +143,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) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
							
								
								
									
										86
									
								
								main_test.go
								
								
								
								
							
							
						
						
									
										86
									
								
								main_test.go
								
								
								
								
							|  | @ -2,13 +2,12 @@ package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" |  | ||||||
| 	"os" | 	"os" | ||||||
| 	"strings" |  | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | ||||||
| 	. "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options/testutil" | 	. "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options/testutil" | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
| 	. "github.com/onsi/ginkgo/v2" | 	. "github.com/onsi/ginkgo/v2" | ||||||
| 	. "github.com/onsi/gomega" | 	. "github.com/onsi/gomega" | ||||||
| 	"github.com/onsi/gomega/format" | 	"github.com/onsi/gomega/format" | ||||||
|  | @ -24,14 +23,15 @@ var _ = Describe("Configuration Loading Suite", func() { | ||||||
| http_address="127.0.0.1:4180" | http_address="127.0.0.1:4180" | ||||||
| upstreams="http://httpbin" | upstreams="http://httpbin" | ||||||
| set_basic_auth="true" | set_basic_auth="true" | ||||||
| basic_auth_password="super-secret-password" | basic_auth_password="c3VwZXItc2VjcmV0LXBhc3N3b3Jk" | ||||||
| client_id="oauth2-proxy" | client_id="oauth2-proxy" | ||||||
| client_secret="b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK" | client_secret="b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK" | ||||||
|  | google_admin_email="admin@example.com" | ||||||
|  | google_target_principal="principal" | ||||||
| ` | ` | ||||||
| 
 | 
 | ||||||
| 	const testAlphaConfig = ` | 	const testAlphaConfig = ` | ||||||
| upstreamConfig: | upstreamConfig: | ||||||
|   proxyrawpath: false |  | ||||||
|   upstreams: |   upstreams: | ||||||
|   - id: / |   - id: / | ||||||
|     path: / |     path: / | ||||||
|  | @ -40,45 +40,63 @@ upstreamConfig: | ||||||
|     passHostHeader: true |     passHostHeader: true | ||||||
|     proxyWebSockets: true |     proxyWebSockets: true | ||||||
|     timeout: 30s |     timeout: 30s | ||||||
|  |     insecureSkipTLSVerify: false | ||||||
|  |     disableKeepAlives: false | ||||||
| injectRequestHeaders: | injectRequestHeaders: | ||||||
| - name: Authorization | - name: Authorization | ||||||
|  |   preserveRequestValue: false | ||||||
|   values: |   values: | ||||||
|   - claim: user |   - claimSource: | ||||||
|  |       claim: user | ||||||
|       prefix: "Basic " |       prefix: "Basic " | ||||||
|       basicAuthPassword: |       basicAuthPassword: | ||||||
|         value: c3VwZXItc2VjcmV0LXBhc3N3b3Jk |         value: c3VwZXItc2VjcmV0LXBhc3N3b3Jk | ||||||
| - name: X-Forwarded-Groups | - name: X-Forwarded-Groups | ||||||
|  |   preserveRequestValue: false | ||||||
|   values: |   values: | ||||||
|   - claim: groups |   - claimSource: | ||||||
|  |       claim: groups | ||||||
| - name: X-Forwarded-User | - name: X-Forwarded-User | ||||||
|  |   preserveRequestValue: false | ||||||
|   values: |   values: | ||||||
|   - claim: user |   - claimSource: | ||||||
|  |       claim: user | ||||||
| - name: X-Forwarded-Email | - name: X-Forwarded-Email | ||||||
|  |   preserveRequestValue: false | ||||||
|   values: |   values: | ||||||
|   - claim: email |   - claimSource: | ||||||
|  |       claim: email | ||||||
| - name: X-Forwarded-Preferred-Username | - name: X-Forwarded-Preferred-Username | ||||||
|  |   preserveRequestValue: false | ||||||
|   values: |   values: | ||||||
|   - claim: preferred_username |   - claimSource: | ||||||
|  |       claim: preferred_username | ||||||
| injectResponseHeaders: | injectResponseHeaders: | ||||||
| - name: Authorization | - name: Authorization | ||||||
|   values: |   values: | ||||||
|   - claim: user |   - claimSource: | ||||||
|  |       claim: user | ||||||
|       prefix: "Basic " |       prefix: "Basic " | ||||||
|       basicAuthPassword: |       basicAuthPassword: | ||||||
|         value: c3VwZXItc2VjcmV0LXBhc3N3b3Jk |         value: c3VwZXItc2VjcmV0LXBhc3N3b3Jk | ||||||
| server: | server: | ||||||
|   bindAddress: "127.0.0.1:4180" |   bindAddress: "127.0.0.1:4180" | ||||||
| providers: | providers: | ||||||
| - provider: google | - id: google=oauth2-proxy | ||||||
|   ID: google=oauth2-proxy |   provider: google | ||||||
|   clientSecret: b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK |   clientSecret: b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK | ||||||
|   clientID: oauth2-proxy |   clientID: oauth2-proxy | ||||||
|   azureConfig: |   useSystemTrustStore: false | ||||||
|     tenant: common |   skipClaimsFromProfileURL: false | ||||||
|  |   googleConfig: | ||||||
|  |     adminEmail: admin@example.com | ||||||
|  |     targetPrincipal: principal | ||||||
|  |     useApplicationDefaultCredentials: false | ||||||
|   oidcConfig: |   oidcConfig: | ||||||
|     groupsClaim: groups |     groupsClaim: groups | ||||||
|     emailClaim: email |     emailClaim: email | ||||||
|     userIDClaim: email |     userIDClaim: email | ||||||
|  |     insecureSkipIssuerVerification: false | ||||||
|     insecureSkipNonce: true |     insecureSkipNonce: true | ||||||
|     audienceClaims: [aud] |     audienceClaims: [aud] | ||||||
|     extraAudiences: [] |     extraAudiences: [] | ||||||
|  | @ -96,13 +114,8 @@ cookie_secure="false" | ||||||
| redirect_url="http://localhost:4180/oauth2/callback" | redirect_url="http://localhost:4180/oauth2/callback" | ||||||
| ` | ` | ||||||
| 
 | 
 | ||||||
| 	boolPtr := func(b bool) *bool { | 	durationPtr := func(d time.Duration) *time.Duration { | ||||||
| 		return &b | 		return &d | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	durationPtr := func(d time.Duration) *options.Duration { |  | ||||||
| 		du := options.Duration(d) |  | ||||||
| 		return &du |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	testExpectedOptions := func() *options.Options { | 	testExpectedOptions := func() *options.Options { | ||||||
|  | @ -121,9 +134,11 @@ redirect_url="http://localhost:4180/oauth2/callback" | ||||||
| 					Path:                  "/", | 					Path:                  "/", | ||||||
| 					URI:                   "http://httpbin", | 					URI:                   "http://httpbin", | ||||||
| 					FlushInterval:         durationPtr(options.DefaultUpstreamFlushInterval), | 					FlushInterval:         durationPtr(options.DefaultUpstreamFlushInterval), | ||||||
| 					PassHostHeader:  boolPtr(true), | 					PassHostHeader:        ptr.Ptr(true), | ||||||
| 					ProxyWebSockets: boolPtr(true), | 					ProxyWebSockets:       ptr.Ptr(true), | ||||||
| 					Timeout:               durationPtr(options.DefaultUpstreamTimeout), | 					Timeout:               durationPtr(options.DefaultUpstreamTimeout), | ||||||
|  | 					InsecureSkipTLSVerify: ptr.Ptr(false), | ||||||
|  | 					DisableKeepAlives:     ptr.Ptr(false), | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| 		} | 		} | ||||||
|  | @ -136,14 +151,17 @@ 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: []byte("c3VwZXItc2VjcmV0LXBhc3N3b3Jk"), | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		authHeader.PreserveRequestValue = ptr.Ptr(false) | ||||||
| 		opts.InjectRequestHeaders = append([]options.Header{authHeader}, opts.InjectRequestHeaders...) | 		opts.InjectRequestHeaders = append([]options.Header{authHeader}, opts.InjectRequestHeaders...) | ||||||
|  | 
 | ||||||
|  | 		authHeader.PreserveRequestValue = nil | ||||||
| 		opts.InjectResponseHeaders = append(opts.InjectResponseHeaders, authHeader) | 		opts.InjectResponseHeaders = append(opts.InjectResponseHeaders, authHeader) | ||||||
| 
 | 
 | ||||||
| 		opts.Providers = options.Providers{ | 		opts.Providers = options.Providers{ | ||||||
|  | @ -152,6 +170,13 @@ redirect_url="http://localhost:4180/oauth2/callback" | ||||||
| 				Type:                     "google", | 				Type:                     "google", | ||||||
| 				ClientSecret:             "b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK", | 				ClientSecret:             "b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK", | ||||||
| 				ClientID:                 "oauth2-proxy", | 				ClientID:                 "oauth2-proxy", | ||||||
|  | 				UseSystemTrustStore:      ptr.Ptr(false), | ||||||
|  | 				SkipClaimsFromProfileURL: ptr.Ptr(false), | ||||||
|  | 				GoogleConfig: options.GoogleOptions{ | ||||||
|  | 					AdminEmail:                       "admin@example.com", | ||||||
|  | 					UseApplicationDefaultCredentials: ptr.Ptr(false), | ||||||
|  | 					TargetPrincipal:                  "principal", | ||||||
|  | 				}, | ||||||
| 				AzureConfig: options.AzureOptions{ | 				AzureConfig: options.AzureOptions{ | ||||||
| 					Tenant: "common", | 					Tenant: "common", | ||||||
| 				}, | 				}, | ||||||
|  | @ -161,7 +186,10 @@ redirect_url="http://localhost:4180/oauth2/callback" | ||||||
| 					UserIDClaim:                    "email", | 					UserIDClaim:                    "email", | ||||||
| 					AudienceClaims:                 []string{"aud"}, | 					AudienceClaims:                 []string{"aud"}, | ||||||
| 					ExtraAudiences:                 []string{}, | 					ExtraAudiences:                 []string{}, | ||||||
| 					InsecureSkipNonce: true, | 					InsecureSkipNonce:              ptr.Ptr(true), | ||||||
|  | 					InsecureAllowUnverifiedEmail:   ptr.Ptr(false), | ||||||
|  | 					InsecureSkipIssuerVerification: ptr.Ptr(false), | ||||||
|  | 					SkipDiscovery:                  ptr.Ptr(false), | ||||||
| 				}, | 				}, | ||||||
| 				LoginURLParameters: []options.LoginURLParameter{ | 				LoginURLParameters: []options.LoginURLParameter{ | ||||||
| 					{Name: "approval_prompt", Default: []string{"force"}}, | 					{Name: "approval_prompt", Default: []string{"force"}}, | ||||||
|  | @ -226,7 +254,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()) | ||||||
| 			} | 			} | ||||||
|  | @ -245,19 +273,19 @@ redirect_url="http://localhost:4180/oauth2/callback" | ||||||
| 		Entry("with bad legacy configuration", loadConfigurationTableInput{ | 		Entry("with bad legacy configuration", loadConfigurationTableInput{ | ||||||
| 			configContent:   testCoreConfig + "unknown_field=\"something\"", | 			configContent:   testCoreConfig + "unknown_field=\"something\"", | ||||||
| 			expectedOptions: func() *options.Options { return nil }, | 			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{ | 		Entry("with bad alpha configuration", loadConfigurationTableInput{ | ||||||
| 			configContent:      testCoreConfig, | 			configContent:      testCoreConfig, | ||||||
| 			alphaConfigContent: testAlphaConfig + ":", | 			alphaConfigContent: testAlphaConfig + ":", | ||||||
| 			expectedOptions:    func() *options.Options { return nil }, | 			expectedOptions:    func() *options.Options { return nil }, | ||||||
| 			expectedErr:        fmt.Errorf("failed to load alpha options: error unmarshalling config: error converting YAML to JSON: yaml: line %d: did not find expected key", strings.Count(testAlphaConfig, "\n")), | 			expectedErr:        errors.New("failed to load alpha options: error unmarshalling config: yaml: line 1: did not find expected key"), | ||||||
| 		}), | 		}), | ||||||
| 		Entry("with alpha configuration and bad core configuration", loadConfigurationTableInput{ | 		Entry("with alpha configuration and bad core configuration", loadConfigurationTableInput{ | ||||||
| 			configContent:      testCoreConfig + "unknown_field=\"something\"", | 			configContent:      testCoreConfig + "unknown_field=\"something\"", | ||||||
| 			alphaConfigContent: testAlphaConfig, | 			alphaConfigContent: testAlphaConfig, | ||||||
| 			expectedOptions:    func() *options.Options { return nil }, | 			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"), | ||||||
| 		}), | 		}), | ||||||
| 	) | 	) | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  | @ -23,6 +23,7 @@ import ( | ||||||
| 	internaloidc "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/providers/oidc" | 	internaloidc "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/providers/oidc" | ||||||
| 	sessionscookie "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/cookie" | 	sessionscookie "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/cookie" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/upstream" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/upstream" | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/validation" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/validation" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/providers" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/providers" | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
|  | @ -506,7 +507,7 @@ func TestStaticProxyUpstream(t *testing.T) { | ||||||
| 		ProxyUpstream: options.Upstream{ | 		ProxyUpstream: options.Upstream{ | ||||||
| 			ID:     "static-proxy", | 			ID:     "static-proxy", | ||||||
| 			Path:   "/static-proxy", | 			Path:   "/static-proxy", | ||||||
| 			Static: true, | 			Static: ptr.Ptr(true), | ||||||
| 		}, | 		}, | ||||||
| 	}) | 	}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -2223,7 +2224,7 @@ func TestTrustedIPs(t *testing.T) { | ||||||
| 					{ | 					{ | ||||||
| 						ID:     "static", | 						ID:     "static", | ||||||
| 						Path:   "/", | 						Path:   "/", | ||||||
| 						Static: true, | 						Static: ptr.Ptr(true), | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | @ -12,13 +12,13 @@ type AlphaOptions struct { | ||||||
| 	// UpstreamConfig is used to configure upstream servers.
 | 	// UpstreamConfig is used to configure upstream servers.
 | ||||||
| 	// Once a user is authenticated, requests to the server will be proxied to
 | 	// Once a user is authenticated, requests to the server will be proxied to
 | ||||||
| 	// these upstream servers based on the path mappings defined in this list.
 | 	// these upstream servers based on the path mappings defined in this list.
 | ||||||
| 	UpstreamConfig UpstreamConfig `json:"upstreamConfig,omitempty"` | 	UpstreamConfig UpstreamConfig `yaml:"upstreamConfig,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// InjectRequestHeaders is used to configure headers that should be added
 | 	// InjectRequestHeaders is used to configure headers that should be added
 | ||||||
| 	// to requests to upstream servers.
 | 	// to requests to upstream servers.
 | ||||||
| 	// Headers may source values from either the authenticated user's session
 | 	// Headers may source values from either the authenticated user's session
 | ||||||
| 	// or from a static secret value.
 | 	// or from a static secret value.
 | ||||||
| 	InjectRequestHeaders []Header `json:"injectRequestHeaders,omitempty"` | 	InjectRequestHeaders []Header `yaml:"injectRequestHeaders,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// InjectResponseHeaders is used to configure headers that should be added
 | 	// InjectResponseHeaders is used to configure headers that should be added
 | ||||||
| 	// to responses from the proxy.
 | 	// to responses from the proxy.
 | ||||||
|  | @ -27,35 +27,31 @@ type AlphaOptions struct { | ||||||
| 	// auth_request module.
 | 	// auth_request module.
 | ||||||
| 	// Headers may source values from either the authenticated user's session
 | 	// Headers may source values from either the authenticated user's session
 | ||||||
| 	// or from a static secret value.
 | 	// or from a static secret value.
 | ||||||
| 	InjectResponseHeaders []Header `json:"injectResponseHeaders,omitempty"` | 	InjectResponseHeaders []Header `yaml:"injectResponseHeaders,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// Server is used to configure the HTTP(S) server for the proxy application.
 | 	// Server is used to configure the HTTP(S) server for the proxy application.
 | ||||||
| 	// You may choose to run both HTTP and HTTPS servers simultaneously.
 | 	// You may choose to run both HTTP and HTTPS servers simultaneously.
 | ||||||
| 	// This can be done by setting the BindAddress and the SecureBindAddress simultaneously.
 | 	// This can be done by setting the BindAddress and the SecureBindAddress simultaneously.
 | ||||||
| 	// To use the secure server you must configure a TLS certificate and key.
 | 	// To use the secure server you must configure a TLS certificate and key.
 | ||||||
| 	Server Server `json:"server,omitempty"` | 	Server Server `yaml:"server,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// MetricsServer is used to configure the HTTP(S) server for metrics.
 | 	// MetricsServer is used to configure the HTTP(S) server for metrics.
 | ||||||
| 	// You may choose to run both HTTP and HTTPS servers simultaneously.
 | 	// You may choose to run both HTTP and HTTPS servers simultaneously.
 | ||||||
| 	// This can be done by setting the BindAddress and the SecureBindAddress simultaneously.
 | 	// This can be done by setting the BindAddress and the SecureBindAddress simultaneously.
 | ||||||
| 	// To use the secure server you must configure a TLS certificate and key.
 | 	// To use the secure server you must configure a TLS certificate and key.
 | ||||||
| 	MetricsServer Server `json:"metricsServer,omitempty"` | 	MetricsServer Server `yaml:"metricsServer,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// Providers is used to configure your provider. **Multiple-providers is not
 | 	// Providers is used to configure your provider. **Multiple-providers is not
 | ||||||
| 	// yet working.** [This feature is tracked in
 | 	// yet working.** [This feature is tracked in
 | ||||||
| 	// #925](https://github.com/oauth2-proxy/oauth2-proxy/issues/926)
 | 	// #925](https://github.com/oauth2-proxy/oauth2-proxy/issues/926)
 | ||||||
| 	Providers Providers `json:"providers,omitempty"` | 	Providers Providers `yaml:"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) |  | ||||||
| } |  | ||||||
|  | @ -1,87 +0,0 @@ | ||||||
| package options |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"errors" |  | ||||||
| 	"time" |  | ||||||
| 
 |  | ||||||
| 	. "github.com/onsi/ginkgo/v2" |  | ||||||
| 	. "github.com/onsi/gomega" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| var _ = Describe("Common", func() { |  | ||||||
| 	Context("Duration", func() { |  | ||||||
| 		type marshalJSONTableInput struct { |  | ||||||
| 			duration     Duration |  | ||||||
| 			expectedJSON string |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		DescribeTable("MarshalJSON", |  | ||||||
| 			func(in marshalJSONTableInput) { |  | ||||||
| 				data, err := in.duration.MarshalJSON() |  | ||||||
| 				Expect(err).ToNot(HaveOccurred()) |  | ||||||
| 				Expect(string(data)).To(Equal(in.expectedJSON)) |  | ||||||
| 
 |  | ||||||
| 				var d Duration |  | ||||||
| 				Expect(json.Unmarshal(data, &d)).To(Succeed()) |  | ||||||
| 				Expect(d).To(Equal(in.duration)) |  | ||||||
| 			}, |  | ||||||
| 			Entry("30 seconds", marshalJSONTableInput{ |  | ||||||
| 				duration:     Duration(30 * time.Second), |  | ||||||
| 				expectedJSON: "\"30s\"", |  | ||||||
| 			}), |  | ||||||
| 			Entry("1 minute", marshalJSONTableInput{ |  | ||||||
| 				duration:     Duration(1 * time.Minute), |  | ||||||
| 				expectedJSON: "\"1m0s\"", |  | ||||||
| 			}), |  | ||||||
| 			Entry("1 hour 15 minutes", marshalJSONTableInput{ |  | ||||||
| 				duration:     Duration(75 * time.Minute), |  | ||||||
| 				expectedJSON: "\"1h15m0s\"", |  | ||||||
| 			}), |  | ||||||
| 			Entry("A zero Duration", marshalJSONTableInput{ |  | ||||||
| 				duration:     Duration(0), |  | ||||||
| 				expectedJSON: "\"0s\"", |  | ||||||
| 			}), |  | ||||||
| 		) |  | ||||||
| 
 |  | ||||||
| 		type unmarshalJSONTableInput struct { |  | ||||||
| 			json             string |  | ||||||
| 			expectedErr      error |  | ||||||
| 			expectedDuration Duration |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		DescribeTable("UnmarshalJSON", |  | ||||||
| 			func(in unmarshalJSONTableInput) { |  | ||||||
| 				// A duration must be initialised pointer before UnmarshalJSON will work.
 |  | ||||||
| 				zero := Duration(0) |  | ||||||
| 				d := &zero |  | ||||||
| 
 |  | ||||||
| 				err := d.UnmarshalJSON([]byte(in.json)) |  | ||||||
| 				if in.expectedErr != nil { |  | ||||||
| 					Expect(err).To(MatchError(in.expectedErr.Error())) |  | ||||||
| 				} else { |  | ||||||
| 					Expect(err).ToNot(HaveOccurred()) |  | ||||||
| 				} |  | ||||||
| 				Expect(d).ToNot(BeNil()) |  | ||||||
| 				Expect(*d).To(Equal(in.expectedDuration)) |  | ||||||
| 			}, |  | ||||||
| 			Entry("1m", unmarshalJSONTableInput{ |  | ||||||
| 				json:             "\"1m\"", |  | ||||||
| 				expectedDuration: Duration(1 * time.Minute), |  | ||||||
| 			}), |  | ||||||
| 			Entry("30s", unmarshalJSONTableInput{ |  | ||||||
| 				json:             "\"30s\"", |  | ||||||
| 				expectedDuration: Duration(30 * time.Second), |  | ||||||
| 			}), |  | ||||||
| 			Entry("1h15m", unmarshalJSONTableInput{ |  | ||||||
| 				json:             "\"1h15m\"", |  | ||||||
| 				expectedDuration: Duration(75 * time.Minute), |  | ||||||
| 			}), |  | ||||||
| 			Entry("am", unmarshalJSONTableInput{ |  | ||||||
| 				json:             "\"am\"", |  | ||||||
| 				expectedErr:      errors.New("time: invalid duration \"am\""), |  | ||||||
| 				expectedDuration: Duration(0), |  | ||||||
| 			}), |  | ||||||
| 		) |  | ||||||
| 	}) |  | ||||||
| }) |  | ||||||
|  | @ -1,3 +1,3 @@ | ||||||
| //go:generate -command reference-gen go run github.com/oauth2-proxy/tools/reference-gen/cmd/reference-gen@v0.0.0-20220223111546-d3b50d1a591a
 | //go:generate -command reference-gen go run github.com/oauth2-proxy/tools/reference-gen/cmd/reference-gen@v0.0.0-20250404153144-32055bc45bc3
 | ||||||
| //go:generate reference-gen --package github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options --types AlphaOptions --header-file ../../../docs/docs/configuration/alpha_config.md.tmpl --out-file ../../../docs/docs/configuration/alpha_config.md
 | //go:generate reference-gen --package github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options --types AlphaOptions --header-file ../../../docs/docs/configuration/alpha_config.md.tmpl --out-file ../../../docs/docs/configuration/alpha_config.md
 | ||||||
| package options | package options | ||||||
|  |  | ||||||
|  | @ -5,26 +5,26 @@ package options | ||||||
| type Header struct { | type Header struct { | ||||||
| 	// Name is the header name to be used for this set of values.
 | 	// Name is the header name to be used for this set of values.
 | ||||||
| 	// Names should be unique within a list of Headers.
 | 	// Names should be unique within a list of Headers.
 | ||||||
| 	Name string `json:"name,omitempty"` | 	Name string `yaml:"name,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// PreserveRequestValue determines whether any values for this header
 | 	// PreserveRequestValue determines whether any values for this header
 | ||||||
| 	// should be preserved for the request to the upstream server.
 | 	// should be preserved for the request to the upstream server.
 | ||||||
| 	// This option only applies to injected request headers.
 | 	// This option only applies to injected request headers.
 | ||||||
| 	// Defaults to false (headers that match this header will be stripped).
 | 	// Defaults to false (headers that match this header will be stripped).
 | ||||||
| 	PreserveRequestValue bool `json:"preserveRequestValue,omitempty"` | 	PreserveRequestValue *bool `yaml:"preserveRequestValue,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// Values contains the desired values for this header
 | 	// Values contains the desired values for this header
 | ||||||
| 	Values []HeaderValue `json:"values,omitempty"` | 	Values []HeaderValue `yaml:"values,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // HeaderValue represents a single header value and the sources that can
 | // HeaderValue represents a single header value and the sources that can
 | ||||||
| // 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 `yaml:"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 `yaml:"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
 | ||||||
|  | @ -32,14 +32,14 @@ type ClaimSource struct { | ||||||
| 	// Claim is the name of the claim in the session that the value should be
 | 	// Claim is the name of the claim in the session that the value should be
 | ||||||
| 	// loaded from. Available claims: `access_token` `id_token` `created_at`
 | 	// loaded from. Available claims: `access_token` `id_token` `created_at`
 | ||||||
| 	// `expires_on` `refresh_token` `email` `user` `groups` `preferred_username`.
 | 	// `expires_on` `refresh_token` `email` `user` `groups` `preferred_username`.
 | ||||||
| 	Claim string `json:"claim,omitempty"` | 	Claim string `yaml:"claim,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// Prefix is an optional prefix that will be prepended to the value of the
 | 	// Prefix is an optional prefix that will be prepended to the value of the
 | ||||||
| 	// claim if it is non-empty.
 | 	// claim if it is non-empty.
 | ||||||
| 	Prefix string `json:"prefix,omitempty"` | 	Prefix string `yaml:"prefix,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// BasicAuthPassword converts this claim into a basic auth header.
 | 	// BasicAuthPassword converts this claim into a basic auth header.
 | ||||||
| 	// Note the value of claim will become the basic auth username and the
 | 	// Note the value of claim will become the basic auth username and the
 | ||||||
| 	// basicAuthPassword will be used as the password value.
 | 	// basicAuthPassword will be used as the password value.
 | ||||||
| 	BasicAuthPassword *SecretSource `json:"basicAuthPassword,omitempty"` | 	BasicAuthPassword *SecretSource `yaml:"basicAuthPassword,omitempty"` | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,57 @@ | ||||||
|  | package options | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"reflect" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/go-viper/mapstructure/v2" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // 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 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 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 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,96 @@ | ||||||
|  | package options | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestToDurationHook(t *testing.T) { | ||||||
|  | 	type result struct { | ||||||
|  | 		Duration time.Duration `yaml:"duration"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	tests := []struct { | ||||||
|  | 		name        string | ||||||
|  | 		input       map[string]interface{} | ||||||
|  | 		out         result | ||||||
|  | 		expected    time.Duration | ||||||
|  | 		expectedErr bool | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			name:        "Valid String Duration with single unit", | ||||||
|  | 			input:       map[string]interface{}{"duration": "3s"}, | ||||||
|  | 			out:         result{}, | ||||||
|  | 			expected:    3 * time.Second, | ||||||
|  | 			expectedErr: false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:        "Valid String Duration with multiple units", | ||||||
|  | 			input:       map[string]interface{}{"duration": "1h20m30s"}, | ||||||
|  | 			out:         result{}, | ||||||
|  | 			expected:    1*time.Hour + 20*time.Minute + 30*time.Second, | ||||||
|  | 			expectedErr: false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:        "Valid Float Duration", | ||||||
|  | 			input:       map[string]interface{}{"duration": 2.5}, | ||||||
|  | 			out:         result{}, | ||||||
|  | 			expected:    2500 * time.Millisecond, | ||||||
|  | 			expectedErr: false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:        "Valid Int64 Duration", | ||||||
|  | 			input:       map[string]interface{}{"duration": int64(5000000000)}, | ||||||
|  | 			out:         result{}, | ||||||
|  | 			expected:    5 * time.Second, | ||||||
|  | 			expectedErr: false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:        "Invalid String", | ||||||
|  | 			input:       map[string]interface{}{"duration": "invalid"}, | ||||||
|  | 			out:         result{}, | ||||||
|  | 			expected:    0, | ||||||
|  | 			expectedErr: true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:        "Unsupported Type", | ||||||
|  | 			input:       map[string]interface{}{"duration": true}, | ||||||
|  | 			out:         result{}, | ||||||
|  | 			expected:    0, | ||||||
|  | 			expectedErr: true, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, tt := range tests { | ||||||
|  | 		t.Run(tt.name, func(t *testing.T) { | ||||||
|  | 			var result struct { | ||||||
|  | 				Duration time.Duration `yaml:"duration"` | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			err := Decode(tt.input, &result) | ||||||
|  | 			if (err != nil) != tt.expectedErr { | ||||||
|  | 				t.Errorf("expected error: %v, got: %v", tt.expectedErr, err) | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if !tt.expectedErr { | ||||||
|  | 				if result.Duration != tt.expected { | ||||||
|  | 					t.Errorf("expected: %v, got: %v", tt.expected, result.Duration) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 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)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -9,6 +9,7 @@ import ( | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger" | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
| 	"github.com/spf13/pflag" | 	"github.com/spf13/pflag" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -136,18 +137,18 @@ 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, | ||||||
| 			URI:                   upstreamString, | 			URI:                   upstreamString, | ||||||
| 			InsecureSkipTLSVerify: l.SSLUpstreamInsecureSkipVerify, | 			InsecureSkipTLSVerify: &l.SSLUpstreamInsecureSkipVerify, | ||||||
| 			PassHostHeader:        &l.PassHostHeader, | 			PassHostHeader:        &l.PassHostHeader, | ||||||
| 			ProxyWebSockets:       &l.ProxyWebSockets, | 			ProxyWebSockets:       &l.ProxyWebSockets, | ||||||
| 			FlushInterval:         &flushInterval, | 			FlushInterval:         &flushInterval, | ||||||
| 			Timeout:               &timeout, | 			Timeout:               &timeout, | ||||||
| 			DisableKeepAlives:     l.DisableKeepAlives, | 			DisableKeepAlives:     &l.DisableKeepAlives, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		switch u.Scheme { | 		switch u.Scheme { | ||||||
|  | @ -164,7 +165,7 @@ func (l *LegacyUpstreams) convert() (UpstreamConfig, error) { | ||||||
| 				logger.Errorf("unable to convert %q to int, use default \"200\"", u.Host) | 				logger.Errorf("unable to convert %q to int, use default \"200\"", u.Host) | ||||||
| 				responseCode = 200 | 				responseCode = 200 | ||||||
| 			} | 			} | ||||||
| 			upstream.Static = true | 			upstream.Static = ptr.Ptr(true) | ||||||
| 			upstream.StaticCode = &responseCode | 			upstream.StaticCode = &responseCode | ||||||
| 
 | 
 | ||||||
| 			// This is not allowed to be empty and must be unique
 | 			// This is not allowed to be empty and must be unique
 | ||||||
|  | @ -175,12 +176,12 @@ func (l *LegacyUpstreams) convert() (UpstreamConfig, error) { | ||||||
| 
 | 
 | ||||||
| 			// Force defaults compatible with static responses
 | 			// Force defaults compatible with static responses
 | ||||||
| 			upstream.URI = "" | 			upstream.URI = "" | ||||||
| 			upstream.InsecureSkipTLSVerify = false | 			upstream.InsecureSkipTLSVerify = ptr.Ptr(false) | ||||||
| 			upstream.PassHostHeader = nil | 			upstream.PassHostHeader = nil | ||||||
| 			upstream.ProxyWebSockets = nil | 			upstream.ProxyWebSockets = nil | ||||||
| 			upstream.FlushInterval = nil | 			upstream.FlushInterval = nil | ||||||
| 			upstream.Timeout = nil | 			upstream.Timeout = nil | ||||||
| 			upstream.DisableKeepAlives = false | 			upstream.DisableKeepAlives = ptr.Ptr(false) | ||||||
| 		case "unix": | 		case "unix": | ||||||
| 			upstream.Path = "/" | 			upstream.Path = "/" | ||||||
| 		} | 		} | ||||||
|  | @ -253,7 +254,7 @@ func (l *LegacyHeaders) getRequestHeaders() []Header { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for i := range requestHeaders { | 	for i := range requestHeaders { | ||||||
| 		requestHeaders[i].PreserveRequestValue = !l.SkipAuthStripHeaders | 		requestHeaders[i].PreserveRequestValue = ptr.Ptr(!l.SkipAuthStripHeaders) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return requestHeaders | 	return requestHeaders | ||||||
|  | @ -680,11 +681,11 @@ func (l *LegacyProvider) convert() (Providers, error) { | ||||||
| 		ClientSecretFile:         l.ClientSecretFile, | 		ClientSecretFile:         l.ClientSecretFile, | ||||||
| 		Type:                     ProviderType(l.ProviderType), | 		Type:                     ProviderType(l.ProviderType), | ||||||
| 		CAFiles:                  l.ProviderCAFiles, | 		CAFiles:                  l.ProviderCAFiles, | ||||||
| 		UseSystemTrustStore:      l.UseSystemTrustStore, | 		UseSystemTrustStore:      &l.UseSystemTrustStore, | ||||||
| 		LoginURL:                 l.LoginURL, | 		LoginURL:                 l.LoginURL, | ||||||
| 		RedeemURL:                l.RedeemURL, | 		RedeemURL:                l.RedeemURL, | ||||||
| 		ProfileURL:               l.ProfileURL, | 		ProfileURL:               l.ProfileURL, | ||||||
| 		SkipClaimsFromProfileURL: l.SkipClaimsFromProfileURL, | 		SkipClaimsFromProfileURL: &l.SkipClaimsFromProfileURL, | ||||||
| 		ProtectedResource:        l.ProtectedResource, | 		ProtectedResource:        l.ProtectedResource, | ||||||
| 		ValidateURL:              l.ValidateURL, | 		ValidateURL:              l.ValidateURL, | ||||||
| 		Scope:                    l.Scope, | 		Scope:                    l.Scope, | ||||||
|  | @ -697,10 +698,10 @@ func (l *LegacyProvider) convert() (Providers, error) { | ||||||
| 	// This part is out of the switch section for all providers that support OIDC
 | 	// This part is out of the switch section for all providers that support OIDC
 | ||||||
| 	provider.OIDCConfig = OIDCOptions{ | 	provider.OIDCConfig = OIDCOptions{ | ||||||
| 		IssuerURL:                      l.OIDCIssuerURL, | 		IssuerURL:                      l.OIDCIssuerURL, | ||||||
| 		InsecureAllowUnverifiedEmail:   l.InsecureOIDCAllowUnverifiedEmail, | 		InsecureAllowUnverifiedEmail:   &l.InsecureOIDCAllowUnverifiedEmail, | ||||||
| 		InsecureSkipIssuerVerification: l.InsecureOIDCSkipIssuerVerification, | 		InsecureSkipIssuerVerification: &l.InsecureOIDCSkipIssuerVerification, | ||||||
| 		InsecureSkipNonce:              l.InsecureOIDCSkipNonce, | 		InsecureSkipNonce:              &l.InsecureOIDCSkipNonce, | ||||||
| 		SkipDiscovery:                  l.SkipOIDCDiscovery, | 		SkipDiscovery:                  &l.SkipOIDCDiscovery, | ||||||
| 		JwksURL:                        l.OIDCJwksURL, | 		JwksURL:                        l.OIDCJwksURL, | ||||||
| 		UserIDClaim:                    l.UserIDClaim, | 		UserIDClaim:                    l.UserIDClaim, | ||||||
| 		EmailClaim:                     l.OIDCEmailClaim, | 		EmailClaim:                     l.OIDCEmailClaim, | ||||||
|  | @ -768,13 +769,13 @@ func (l *LegacyProvider) convert() (Providers, error) { | ||||||
| 			Groups:                           l.GoogleGroups, | 			Groups:                           l.GoogleGroups, | ||||||
| 			AdminEmail:                       l.GoogleAdminEmail, | 			AdminEmail:                       l.GoogleAdminEmail, | ||||||
| 			ServiceAccountJSON:               l.GoogleServiceAccountJSON, | 			ServiceAccountJSON:               l.GoogleServiceAccountJSON, | ||||||
| 			UseApplicationDefaultCredentials: l.GoogleUseApplicationDefaultCredentials, | 			UseApplicationDefaultCredentials: &l.GoogleUseApplicationDefaultCredentials, | ||||||
| 			TargetPrincipal:                  l.GoogleTargetPrincipal, | 			TargetPrincipal:                  l.GoogleTargetPrincipal, | ||||||
| 		} | 		} | ||||||
| 	case "entra-id": | 	case "entra-id": | ||||||
| 		provider.MicrosoftEntraIDConfig = MicrosoftEntraIDOptions{ | 		provider.MicrosoftEntraIDConfig = MicrosoftEntraIDOptions{ | ||||||
| 			AllowedTenants:     l.EntraIDAllowedTenants, | 			AllowedTenants:     l.EntraIDAllowedTenants, | ||||||
| 			FederatedTokenAuth: l.EntraIDFederatedTokenAuth, | 			FederatedTokenAuth: &l.EntraIDFederatedTokenAuth, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ package options | ||||||
| import ( | import ( | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
| 	. "github.com/onsi/ginkgo/v2" | 	. "github.com/onsi/ginkgo/v2" | ||||||
| 	. "github.com/onsi/gomega" | 	. "github.com/onsi/gomega" | ||||||
| ) | ) | ||||||
|  | @ -15,8 +16,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 | ||||||
|  | @ -26,7 +27,6 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 			legacyOpts.LegacyProvider.ClientID = "oauth-proxy" | 			legacyOpts.LegacyProvider.ClientID = "oauth-proxy" | ||||||
| 			legacyOpts.LegacyUpstreams.DisableKeepAlives = false | 			legacyOpts.LegacyUpstreams.DisableKeepAlives = false | ||||||
| 
 | 
 | ||||||
| 			truth := true |  | ||||||
| 			staticCode := 204 | 			staticCode := 204 | ||||||
| 			opts.UpstreamServers = UpstreamConfig{ | 			opts.UpstreamServers = UpstreamConfig{ | ||||||
| 				Upstreams: []Upstream{ | 				Upstreams: []Upstream{ | ||||||
|  | @ -35,35 +35,35 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 						Path:                  "/baz", | 						Path:                  "/baz", | ||||||
| 						URI:                   "http://foo.bar/baz", | 						URI:                   "http://foo.bar/baz", | ||||||
| 						FlushInterval:         &flushInterval, | 						FlushInterval:         &flushInterval, | ||||||
| 						InsecureSkipTLSVerify: true, | 						InsecureSkipTLSVerify: ptr.Ptr(true), | ||||||
| 						PassHostHeader:        &truth, | 						PassHostHeader:        ptr.Ptr(true), | ||||||
| 						ProxyWebSockets:       &truth, | 						ProxyWebSockets:       ptr.Ptr(true), | ||||||
| 						Timeout:               &timeout, | 						Timeout:               &timeout, | ||||||
| 						DisableKeepAlives:     legacyOpts.LegacyUpstreams.DisableKeepAlives, | 						DisableKeepAlives:     &legacyOpts.LegacyUpstreams.DisableKeepAlives, | ||||||
| 					}, | 					}, | ||||||
| 					{ | 					{ | ||||||
| 						ID:                    "/bar", | 						ID:                    "/bar", | ||||||
| 						Path:                  "/bar", | 						Path:                  "/bar", | ||||||
| 						URI:                   "file:///var/lib/website", | 						URI:                   "file:///var/lib/website", | ||||||
| 						FlushInterval:         &flushInterval, | 						FlushInterval:         &flushInterval, | ||||||
| 						InsecureSkipTLSVerify: true, | 						InsecureSkipTLSVerify: ptr.Ptr(true), | ||||||
| 						PassHostHeader:        &truth, | 						PassHostHeader:        ptr.Ptr(true), | ||||||
| 						ProxyWebSockets:       &truth, | 						ProxyWebSockets:       ptr.Ptr(true), | ||||||
| 						Timeout:               &timeout, | 						Timeout:               &timeout, | ||||||
| 						DisableKeepAlives:     legacyOpts.LegacyUpstreams.DisableKeepAlives, | 						DisableKeepAlives:     &legacyOpts.LegacyUpstreams.DisableKeepAlives, | ||||||
| 					}, | 					}, | ||||||
| 					{ | 					{ | ||||||
| 						ID:                    "static://204", | 						ID:                    "static://204", | ||||||
| 						Path:                  "/", | 						Path:                  "/", | ||||||
| 						URI:                   "", | 						URI:                   "", | ||||||
| 						Static:                true, | 						Static:                ptr.Ptr(true), | ||||||
| 						StaticCode:            &staticCode, | 						StaticCode:            &staticCode, | ||||||
| 						FlushInterval:         nil, | 						FlushInterval:         nil, | ||||||
| 						InsecureSkipTLSVerify: false, | 						InsecureSkipTLSVerify: ptr.Ptr(false), | ||||||
| 						PassHostHeader:        nil, | 						PassHostHeader:        nil, | ||||||
| 						ProxyWebSockets:       nil, | 						ProxyWebSockets:       nil, | ||||||
| 						Timeout:               nil, | 						Timeout:               nil, | ||||||
| 						DisableKeepAlives:     legacyOpts.LegacyUpstreams.DisableKeepAlives, | 						DisableKeepAlives:     &legacyOpts.LegacyUpstreams.DisableKeepAlives, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			} | 			} | ||||||
|  | @ -71,7 +71,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 			opts.InjectRequestHeaders = []Header{ | 			opts.InjectRequestHeaders = []Header{ | ||||||
| 				{ | 				{ | ||||||
| 					Name:                 "X-Forwarded-Groups", | 					Name:                 "X-Forwarded-Groups", | ||||||
| 					PreserveRequestValue: false, | 					PreserveRequestValue: ptr.Ptr(false), | ||||||
| 					Values: []HeaderValue{ | 					Values: []HeaderValue{ | ||||||
| 						{ | 						{ | ||||||
| 							ClaimSource: &ClaimSource{ | 							ClaimSource: &ClaimSource{ | ||||||
|  | @ -82,7 +82,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Name:                 "X-Forwarded-User", | 					Name:                 "X-Forwarded-User", | ||||||
| 					PreserveRequestValue: false, | 					PreserveRequestValue: ptr.Ptr(false), | ||||||
| 					Values: []HeaderValue{ | 					Values: []HeaderValue{ | ||||||
| 						{ | 						{ | ||||||
| 							ClaimSource: &ClaimSource{ | 							ClaimSource: &ClaimSource{ | ||||||
|  | @ -93,7 +93,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Name:                 "X-Forwarded-Email", | 					Name:                 "X-Forwarded-Email", | ||||||
| 					PreserveRequestValue: false, | 					PreserveRequestValue: ptr.Ptr(false), | ||||||
| 					Values: []HeaderValue{ | 					Values: []HeaderValue{ | ||||||
| 						{ | 						{ | ||||||
| 							ClaimSource: &ClaimSource{ | 							ClaimSource: &ClaimSource{ | ||||||
|  | @ -104,7 +104,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Name:                 "X-Forwarded-Preferred-Username", | 					Name:                 "X-Forwarded-Preferred-Username", | ||||||
| 					PreserveRequestValue: false, | 					PreserveRequestValue: ptr.Ptr(false), | ||||||
| 					Values: []HeaderValue{ | 					Values: []HeaderValue{ | ||||||
| 						{ | 						{ | ||||||
| 							ClaimSource: &ClaimSource{ | 							ClaimSource: &ClaimSource{ | ||||||
|  | @ -123,7 +123,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 			opts.Providers[0].ClientID = "oauth-proxy" | 			opts.Providers[0].ClientID = "oauth-proxy" | ||||||
| 			opts.Providers[0].ID = "google=oauth-proxy" | 			opts.Providers[0].ID = "google=oauth-proxy" | ||||||
| 			opts.Providers[0].OIDCConfig.InsecureSkipNonce = true | 			opts.Providers[0].OIDCConfig.InsecureSkipNonce = ptr.Ptr(true) | ||||||
| 			opts.Providers[0].OIDCConfig.AudienceClaims = []string{"aud"} | 			opts.Providers[0].OIDCConfig.AudienceClaims = []string{"aud"} | ||||||
| 			opts.Providers[0].OIDCConfig.ExtraAudiences = []string{} | 			opts.Providers[0].OIDCConfig.ExtraAudiences = []string{} | ||||||
| 			opts.Providers[0].LoginURLParameters = []LoginURLParameter{ | 			opts.Providers[0].LoginURLParameters = []LoginURLParameter{ | ||||||
|  | @ -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
 | ||||||
|  | @ -157,12 +157,12 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 			ID:                    "/baz", | 			ID:                    "/baz", | ||||||
| 			Path:                  "/baz", | 			Path:                  "/baz", | ||||||
| 			URI:                   validHTTP, | 			URI:                   validHTTP, | ||||||
| 			InsecureSkipTLSVerify: skipVerify, | 			InsecureSkipTLSVerify: &skipVerify, | ||||||
| 			PassHostHeader:        &passHostHeader, | 			PassHostHeader:        &passHostHeader, | ||||||
| 			ProxyWebSockets:       &proxyWebSockets, | 			ProxyWebSockets:       &proxyWebSockets, | ||||||
| 			FlushInterval:         &flushInterval, | 			FlushInterval:         &flushInterval, | ||||||
| 			Timeout:               &timeout, | 			Timeout:               &timeout, | ||||||
| 			DisableKeepAlives:     disableKeepAlives, | 			DisableKeepAlives:     &disableKeepAlives, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Test cases and expected outcomes
 | 		// Test cases and expected outcomes
 | ||||||
|  | @ -171,12 +171,12 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 			ID:                    "/", | 			ID:                    "/", | ||||||
| 			Path:                  "/", | 			Path:                  "/", | ||||||
| 			URI:                   emptyPathHTTP, | 			URI:                   emptyPathHTTP, | ||||||
| 			InsecureSkipTLSVerify: skipVerify, | 			InsecureSkipTLSVerify: &skipVerify, | ||||||
| 			PassHostHeader:        &passHostHeader, | 			PassHostHeader:        &passHostHeader, | ||||||
| 			ProxyWebSockets:       &proxyWebSockets, | 			ProxyWebSockets:       &proxyWebSockets, | ||||||
| 			FlushInterval:         &flushInterval, | 			FlushInterval:         &flushInterval, | ||||||
| 			Timeout:               &timeout, | 			Timeout:               &timeout, | ||||||
| 			DisableKeepAlives:     disableKeepAlives, | 			DisableKeepAlives:     &disableKeepAlives, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		validFileWithFragment := "file:///var/lib/website#/bar" | 		validFileWithFragment := "file:///var/lib/website#/bar" | ||||||
|  | @ -184,12 +184,12 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 			ID:                    "/bar", | 			ID:                    "/bar", | ||||||
| 			Path:                  "/bar", | 			Path:                  "/bar", | ||||||
| 			URI:                   "file:///var/lib/website", | 			URI:                   "file:///var/lib/website", | ||||||
| 			InsecureSkipTLSVerify: skipVerify, | 			InsecureSkipTLSVerify: &skipVerify, | ||||||
| 			PassHostHeader:        &passHostHeader, | 			PassHostHeader:        &passHostHeader, | ||||||
| 			ProxyWebSockets:       &proxyWebSockets, | 			ProxyWebSockets:       &proxyWebSockets, | ||||||
| 			FlushInterval:         &flushInterval, | 			FlushInterval:         &flushInterval, | ||||||
| 			Timeout:               &timeout, | 			Timeout:               &timeout, | ||||||
| 			DisableKeepAlives:     disableKeepAlives, | 			DisableKeepAlives:     &disableKeepAlives, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		validStatic := "static://204" | 		validStatic := "static://204" | ||||||
|  | @ -198,14 +198,14 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 			ID:                    validStatic, | 			ID:                    validStatic, | ||||||
| 			Path:                  "/", | 			Path:                  "/", | ||||||
| 			URI:                   "", | 			URI:                   "", | ||||||
| 			Static:                true, | 			Static:                ptr.Ptr(true), | ||||||
| 			StaticCode:            &validStaticCode, | 			StaticCode:            &validStaticCode, | ||||||
| 			InsecureSkipTLSVerify: false, | 			InsecureSkipTLSVerify: ptr.Ptr(false), | ||||||
| 			PassHostHeader:        nil, | 			PassHostHeader:        nil, | ||||||
| 			ProxyWebSockets:       nil, | 			ProxyWebSockets:       nil, | ||||||
| 			FlushInterval:         nil, | 			FlushInterval:         nil, | ||||||
| 			Timeout:               nil, | 			Timeout:               nil, | ||||||
| 			DisableKeepAlives:     false, | 			DisableKeepAlives:     ptr.Ptr(false), | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		invalidStatic := "static://abc" | 		invalidStatic := "static://abc" | ||||||
|  | @ -214,14 +214,14 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 			ID:                    invalidStatic, | 			ID:                    invalidStatic, | ||||||
| 			Path:                  "/", | 			Path:                  "/", | ||||||
| 			URI:                   "", | 			URI:                   "", | ||||||
| 			Static:                true, | 			Static:                ptr.Ptr(true), | ||||||
| 			StaticCode:            &invalidStaticCode, | 			StaticCode:            &invalidStaticCode, | ||||||
| 			InsecureSkipTLSVerify: false, | 			InsecureSkipTLSVerify: ptr.Ptr(false), | ||||||
| 			PassHostHeader:        nil, | 			PassHostHeader:        nil, | ||||||
| 			ProxyWebSockets:       nil, | 			ProxyWebSockets:       nil, | ||||||
| 			FlushInterval:         nil, | 			FlushInterval:         nil, | ||||||
| 			Timeout:               nil, | 			Timeout:               nil, | ||||||
| 			DisableKeepAlives:     false, | 			DisableKeepAlives:     ptr.Ptr(false), | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		invalidHTTP := ":foo" | 		invalidHTTP := ":foo" | ||||||
|  | @ -308,13 +308,13 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		withPreserveRequestValue := func(h Header, preserve bool) Header { | 		withPreserveRequestValue := func(h Header, preserve bool) Header { | ||||||
| 			h.PreserveRequestValue = preserve | 			h.PreserveRequestValue = &preserve | ||||||
| 			return h | 			return h | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		xForwardedUser := Header{ | 		xForwardedUser := Header{ | ||||||
| 			Name:                 "X-Forwarded-User", | 			Name:                 "X-Forwarded-User", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  | @ -326,7 +326,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 		xForwardedEmail := Header{ | 		xForwardedEmail := Header{ | ||||||
| 			Name:                 "X-Forwarded-Email", | 			Name:                 "X-Forwarded-Email", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  | @ -338,7 +338,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 		xForwardedGroups := Header{ | 		xForwardedGroups := Header{ | ||||||
| 			Name:                 "X-Forwarded-Groups", | 			Name:                 "X-Forwarded-Groups", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  | @ -350,7 +350,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 		xForwardedPreferredUsername := Header{ | 		xForwardedPreferredUsername := Header{ | ||||||
| 			Name:                 "X-Forwarded-Preferred-Username", | 			Name:                 "X-Forwarded-Preferred-Username", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  | @ -362,7 +362,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 		basicAuthHeader := Header{ | 		basicAuthHeader := Header{ | ||||||
| 			Name:                 "Authorization", | 			Name:                 "Authorization", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  | @ -378,7 +378,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 		xForwardedUserWithEmail := Header{ | 		xForwardedUserWithEmail := Header{ | ||||||
| 			Name:                 "X-Forwarded-User", | 			Name:                 "X-Forwarded-User", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  | @ -390,7 +390,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 		xForwardedAccessToken := Header{ | 		xForwardedAccessToken := Header{ | ||||||
| 			Name:                 "X-Forwarded-Access-Token", | 			Name:                 "X-Forwarded-Access-Token", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  | @ -402,7 +402,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 		basicAuthHeaderWithEmail := Header{ | 		basicAuthHeaderWithEmail := Header{ | ||||||
| 			Name:                 "Authorization", | 			Name:                 "Authorization", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  | @ -418,7 +418,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 		xAuthRequestUser := Header{ | 		xAuthRequestUser := Header{ | ||||||
| 			Name:                 "X-Auth-Request-User", | 			Name:                 "X-Auth-Request-User", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  | @ -430,7 +430,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 		xAuthRequestEmail := Header{ | 		xAuthRequestEmail := Header{ | ||||||
| 			Name:                 "X-Auth-Request-Email", | 			Name:                 "X-Auth-Request-Email", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  | @ -442,7 +442,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 		xAuthRequestGroups := Header{ | 		xAuthRequestGroups := Header{ | ||||||
| 			Name:                 "X-Auth-Request-Groups", | 			Name:                 "X-Auth-Request-Groups", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  | @ -454,7 +454,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 		xAuthRequestPreferredUsername := Header{ | 		xAuthRequestPreferredUsername := Header{ | ||||||
| 			Name:                 "X-Auth-Request-Preferred-Username", | 			Name:                 "X-Auth-Request-Preferred-Username", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  | @ -466,7 +466,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 		xAuthRequestAccessToken := Header{ | 		xAuthRequestAccessToken := Header{ | ||||||
| 			Name:                 "X-Auth-Request-Access-Token", | 			Name:                 "X-Auth-Request-Access-Token", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  | @ -478,7 +478,7 @@ var _ = Describe("Legacy Options", func() { | ||||||
| 
 | 
 | ||||||
| 		authorizationHeader := Header{ | 		authorizationHeader := Header{ | ||||||
| 			Name:                 "Authorization", | 			Name:                 "Authorization", | ||||||
| 			PreserveRequestValue: false, | 			PreserveRequestValue: ptr.Ptr(false), | ||||||
| 			Values: []HeaderValue{ | 			Values: []HeaderValue{ | ||||||
| 				{ | 				{ | ||||||
| 					ClaimSource: &ClaimSource{ | 					ClaimSource: &ClaimSource{ | ||||||
|  |  | ||||||
|  | @ -9,10 +9,10 @@ import ( | ||||||
| 	"strings" | 	"strings" | ||||||
| 
 | 
 | ||||||
| 	"github.com/a8m/envsubst" | 	"github.com/a8m/envsubst" | ||||||
| 	"github.com/ghodss/yaml" |  | ||||||
| 	"github.com/go-viper/mapstructure/v2" | 	"github.com/go-viper/mapstructure/v2" | ||||||
| 	"github.com/spf13/pflag" | 	"github.com/spf13/pflag" | ||||||
| 	"github.com/spf13/viper" | 	"github.com/spf13/viper" | ||||||
|  | 	"gopkg.in/yaml.v3" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Load reads in the config file at the path given, then merges in environment
 | // Load reads in the config file at the path given, then merges in environment
 | ||||||
|  | @ -55,6 +55,87 @@ 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) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// 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.
 | ||||||
|  | 	return Decode(intermediate, opts) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Decode processes an input map and decodes it into a given struct while preserving default values.
 | ||||||
|  | // It ensures proper conversion of duration values from strings, floats, and int64 into time.Duration.
 | ||||||
|  | //
 | ||||||
|  | // Parameters:
 | ||||||
|  | // - input: A map[string]interface{} representing the input data.
 | ||||||
|  | // - result: A pointer to a struct where the decoded values will be stored.
 | ||||||
|  | //
 | ||||||
|  | // Returns:
 | ||||||
|  | // - 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(), | ||||||
|  | 			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
 | ||||||
|  | 		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 json
 | ||||||
|  | 	}) | ||||||
|  | 	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 +221,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) { | ||||||
|  |  | ||||||
|  | @ -155,7 +155,7 @@ var _ = Describe("Load", func() { | ||||||
| 				} | 				} | ||||||
| 				err := Load(configFileName, flagSet, input) | 				err := Load(configFileName, flagSet, input) | ||||||
| 				if o.expectedErr != nil { | 				if o.expectedErr != nil { | ||||||
| 					Expect(err).To(MatchError(o.expectedErr.Error())) | 					Expect(err).To(MatchError(ContainSubstring(o.expectedErr.Error()))) | ||||||
| 				} else { | 				} else { | ||||||
| 					Expect(err).ToNot(HaveOccurred()) | 					Expect(err).ToNot(HaveOccurred()) | ||||||
| 				} | 				} | ||||||
|  | @ -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()) | ||||||
| 				} | 				} | ||||||
|  | @ -445,7 +445,7 @@ sub: | ||||||
| 				configFile:     []byte("\tfoo: bar"), | 				configFile:     []byte("\tfoo: bar"), | ||||||
| 				input:          &TestOptions{}, | 				input:          &TestOptions{}, | ||||||
| 				expectedOutput: &TestOptions{}, | 				expectedOutput: &TestOptions{}, | ||||||
| 				expectedErr:    errors.New("error unmarshalling config: error converting YAML to JSON: yaml: found character that cannot start any token"), | 				expectedErr:    errors.New("error unmarshalling config: yaml: found character that cannot start any token"), | ||||||
| 			}), | 			}), | ||||||
| 			Entry("with extra fields in the YAML", loadYAMLTableInput{ | 			Entry("with extra fields in the YAML", loadYAMLTableInput{ | ||||||
| 				configFile: append(testOptionsConfigBytesFull, []byte("foo: bar\n")...), | 				configFile: append(testOptionsConfigBytesFull, []byte("foo: bar\n")...), | ||||||
|  | @ -459,19 +459,19 @@ 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"`), | ||||||
| 				input:          &TestOptions{}, | 				input:          &TestOptions{}, | ||||||
| 				expectedOutput: &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{ | 			Entry("with a config file containing environment variable references", loadYAMLTableInput{ | ||||||
| 				configFile: []byte("stringOption: ${TESTUSER}"), | 				configFile: []byte("stringOption: ${TESTUSER}"), | ||||||
|  | @ -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{ | ||||||
|  |  | ||||||
|  | @ -71,19 +71,19 @@ package options | ||||||
| // character.
 | // character.
 | ||||||
| type LoginURLParameter struct { | type LoginURLParameter struct { | ||||||
| 	// Name specifies the name of the query parameter.
 | 	// Name specifies the name of the query parameter.
 | ||||||
| 	Name string `json:"name"` | 	Name string `yaml:"name"` | ||||||
| 
 | 
 | ||||||
| 	// Default specifies a default value or values that will be
 | 	// Default specifies a default value or values that will be
 | ||||||
| 	// passed to the IdP if not overridden.
 | 	// passed to the IdP if not overridden.
 | ||||||
| 	//+optional
 | 	//+optional
 | ||||||
| 	Default []string `json:"default,omitempty"` | 	Default []string `yaml:"default,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// Allow specifies rules about how the default (if any) may be
 | 	// Allow specifies rules about how the default (if any) may be
 | ||||||
| 	// overridden via the query string to `/oauth2/start`.  Only
 | 	// overridden via the query string to `/oauth2/start`.  Only
 | ||||||
| 	// values that match one or more of the allow rules will be
 | 	// values that match one or more of the allow rules will be
 | ||||||
| 	// forwarded to the IdP.
 | 	// forwarded to the IdP.
 | ||||||
| 	//+optional
 | 	//+optional
 | ||||||
| 	Allow []URLParameterRule `json:"allow,omitempty"` | 	Allow []URLParameterRule `yaml:"allow,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // URLParameterRule represents a rule by which query parameters
 | // URLParameterRule represents a rule by which query parameters
 | ||||||
|  | @ -92,11 +92,11 @@ type LoginURLParameter struct { | ||||||
| // login URL.  Either Value or Pattern should be supplied, not both.
 | // login URL.  Either Value or Pattern should be supplied, not both.
 | ||||||
| type URLParameterRule struct { | type URLParameterRule struct { | ||||||
| 	// A Value rule matches just this specific value
 | 	// A Value rule matches just this specific value
 | ||||||
| 	Value *string `json:"value,omitempty"` | 	Value *string `yaml:"value,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// A Pattern rule gives a regular expression that must be matched by
 | 	// A Pattern rule gives a regular expression that must be matched by
 | ||||||
| 	// some substring of the value.  The expression is _not_ automatically
 | 	// some substring of the value.  The expression is _not_ automatically
 | ||||||
| 	// anchored to the start and end of the value, if you _want_ to restrict
 | 	// anchored to the start and end of the value, if you _want_ to restrict
 | ||||||
| 	// the whole parameter value you must anchor it yourself with `^` and `$`.
 | 	// the whole parameter value you must anchor it yourself with `^` and `$`.
 | ||||||
| 	Pattern *string `json:"pattern,omitempty"` | 	Pattern *string `yaml:"pattern,omitempty"` | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,7 @@ | ||||||
| package options | package options | ||||||
| 
 | 
 | ||||||
|  | import "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
|  | 
 | ||||||
| const ( | const ( | ||||||
| 	// OIDCEmailClaim is the generic email claim used by the OIDC provider.
 | 	// OIDCEmailClaim is the generic email claim used by the OIDC provider.
 | ||||||
| 	OIDCEmailClaim = "email" | 	OIDCEmailClaim = "email" | ||||||
|  | @ -22,78 +24,78 @@ type Providers []Provider | ||||||
| type Provider struct { | type Provider struct { | ||||||
| 	// ClientID is the OAuth Client ID that is defined in the provider
 | 	// ClientID is the OAuth Client ID that is defined in the provider
 | ||||||
| 	// This value is required for all providers.
 | 	// This value is required for all providers.
 | ||||||
| 	ClientID string `json:"clientID,omitempty"` | 	ClientID string `yaml:"clientID,omitempty"` | ||||||
| 	// ClientSecret is the OAuth Client Secret that is defined in the provider
 | 	// ClientSecret is the OAuth Client Secret that is defined in the provider
 | ||||||
| 	// This value is required for all providers.
 | 	// This value is required for all providers.
 | ||||||
| 	ClientSecret string `json:"clientSecret,omitempty"` | 	ClientSecret string `yaml:"clientSecret,omitempty"` | ||||||
| 	// ClientSecretFile is the name of the file
 | 	// ClientSecretFile is the name of the file
 | ||||||
| 	// containing the OAuth Client Secret, it will be used if ClientSecret is not set.
 | 	// containing the OAuth Client Secret, it will be used if ClientSecret is not set.
 | ||||||
| 	ClientSecretFile string `json:"clientSecretFile,omitempty"` | 	ClientSecretFile string `yaml:"clientSecretFile,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// KeycloakConfig holds all configurations for Keycloak provider.
 | 	// KeycloakConfig holds all configurations for Keycloak provider.
 | ||||||
| 	KeycloakConfig KeycloakOptions `json:"keycloakConfig,omitempty"` | 	KeycloakConfig KeycloakOptions `yaml:"keycloakConfig,omitempty"` | ||||||
| 	// AzureConfig holds all configurations for Azure provider.
 | 	// AzureConfig holds all configurations for Azure provider.
 | ||||||
| 	AzureConfig AzureOptions `json:"azureConfig,omitempty"` | 	AzureConfig AzureOptions `yaml:"azureConfig,omitempty"` | ||||||
| 	// MicrosoftEntraIDConfig holds all configurations for Entra ID provider.
 | 	// MicrosoftEntraIDConfig holds all configurations for Entra ID provider.
 | ||||||
| 	MicrosoftEntraIDConfig MicrosoftEntraIDOptions `json:"microsoftEntraIDConfig,omitempty"` | 	MicrosoftEntraIDConfig MicrosoftEntraIDOptions `yaml:"microsoftEntraIDConfig,omitempty"` | ||||||
| 	// ADFSConfig holds all configurations for ADFS provider.
 | 	// ADFSConfig holds all configurations for ADFS provider.
 | ||||||
| 	ADFSConfig ADFSOptions `json:"ADFSConfig,omitempty"` | 	ADFSConfig ADFSOptions `yaml:"ADFSConfig,omitempty"` | ||||||
| 	// BitbucketConfig holds all configurations for Bitbucket provider.
 | 	// BitbucketConfig holds all configurations for Bitbucket provider.
 | ||||||
| 	BitbucketConfig BitbucketOptions `json:"bitbucketConfig,omitempty"` | 	BitbucketConfig BitbucketOptions `yaml:"bitbucketConfig,omitempty"` | ||||||
| 	// GitHubConfig holds all configurations for GitHubC provider.
 | 	// GitHubConfig holds all configurations for GitHubC provider.
 | ||||||
| 	GitHubConfig GitHubOptions `json:"githubConfig,omitempty"` | 	GitHubConfig GitHubOptions `yaml:"githubConfig,omitempty"` | ||||||
| 	// GitLabConfig holds all configurations for GitLab provider.
 | 	// GitLabConfig holds all configurations for GitLab provider.
 | ||||||
| 	GitLabConfig GitLabOptions `json:"gitlabConfig,omitempty"` | 	GitLabConfig GitLabOptions `yaml:"gitlabConfig,omitempty"` | ||||||
| 	// GoogleConfig holds all configurations for Google provider.
 | 	// GoogleConfig holds all configurations for Google provider.
 | ||||||
| 	GoogleConfig GoogleOptions `json:"googleConfig,omitempty"` | 	GoogleConfig GoogleOptions `yaml:"googleConfig,omitempty"` | ||||||
| 	// OIDCConfig holds all configurations for OIDC provider
 | 	// OIDCConfig holds all configurations for OIDC provider
 | ||||||
| 	// or providers utilize OIDC configurations.
 | 	// or providers utilize OIDC configurations.
 | ||||||
| 	OIDCConfig OIDCOptions `json:"oidcConfig,omitempty"` | 	OIDCConfig OIDCOptions `yaml:"oidcConfig,omitempty"` | ||||||
| 	// LoginGovConfig holds all configurations for LoginGov provider.
 | 	// LoginGovConfig holds all configurations for LoginGov provider.
 | ||||||
| 	LoginGovConfig LoginGovOptions `json:"loginGovConfig,omitempty"` | 	LoginGovConfig LoginGovOptions `yaml:"loginGovConfig,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// ID should be a unique identifier for the provider.
 | 	// ID should be a unique identifier for the provider.
 | ||||||
| 	// This value is required for all providers.
 | 	// This value is required for all providers.
 | ||||||
| 	ID string `json:"id,omitempty"` | 	ID string `yaml:"id,omitempty"` | ||||||
| 	// Type is the OAuth provider
 | 	// Type is the OAuth provider
 | ||||||
| 	// must be set from the supported providers group,
 | 	// must be set from the supported providers group,
 | ||||||
| 	// otherwise 'Google' is set as default
 | 	// otherwise 'Google' is set as default
 | ||||||
| 	Type ProviderType `json:"provider,omitempty"` | 	Type ProviderType `yaml:"provider,omitempty"` | ||||||
| 	// Name is the providers display name
 | 	// Name is the providers display name
 | ||||||
| 	// if set, it will be shown to the users in the login page.
 | 	// if set, it will be shown to the users in the login page.
 | ||||||
| 	Name string `json:"name,omitempty"` | 	Name string `yaml:"name,omitempty"` | ||||||
| 	// CAFiles is a list of paths to CA certificates that should be used when connecting to the provider.
 | 	// CAFiles is a list of paths to CA certificates that should be used when connecting to the provider.
 | ||||||
| 	// If not specified, the default Go trust sources are used instead
 | 	// If not specified, the default Go trust sources are used instead
 | ||||||
| 	CAFiles []string `json:"caFiles,omitempty"` | 	CAFiles []string `yaml:"caFiles,omitempty"` | ||||||
| 	// UseSystemTrustStore determines if your custom CA files and the system trust store are used
 | 	// 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.
 | 	// If set to true, your custom CA files and the system trust store are used otherwise only your custom CA files.
 | ||||||
| 	UseSystemTrustStore bool `json:"useSystemTrustStore,omitempty"` | 	UseSystemTrustStore *bool `yaml:"useSystemTrustStore,omitempty"` | ||||||
| 	// LoginURL is the authentication endpoint
 | 	// LoginURL is the authentication endpoint
 | ||||||
| 	LoginURL string `json:"loginURL,omitempty"` | 	LoginURL string `yaml:"loginURL,omitempty"` | ||||||
| 	// LoginURLParameters defines the parameters that can be passed from the start URL to the IdP login URL
 | 	// LoginURLParameters defines the parameters that can be passed from the start URL to the IdP login URL
 | ||||||
| 	LoginURLParameters []LoginURLParameter `json:"loginURLParameters,omitempty"` | 	LoginURLParameters []LoginURLParameter `yaml:"loginURLParameters,omitempty"` | ||||||
| 	// AuthRequestResponseMode defines the response mode to request during authorization request
 | 	// AuthRequestResponseMode defines the response mode to request during authorization request
 | ||||||
| 	AuthRequestResponseMode string `json:"authRequestResponseMode,omitempty"` | 	AuthRequestResponseMode string `yaml:"authRequestResponseMode,omitempty"` | ||||||
| 	// RedeemURL is the token redemption endpoint
 | 	// RedeemURL is the token redemption endpoint
 | ||||||
| 	RedeemURL string `json:"redeemURL,omitempty"` | 	RedeemURL string `yaml:"redeemURL,omitempty"` | ||||||
| 	// ProfileURL is the profile access endpoint
 | 	// ProfileURL is the profile access endpoint
 | ||||||
| 	ProfileURL string `json:"profileURL,omitempty"` | 	ProfileURL string `yaml:"profileURL,omitempty"` | ||||||
| 	// SkipClaimsFromProfileURL allows to skip request to Profile URL for resolving claims not present in id_token
 | 	// SkipClaimsFromProfileURL allows to skip request to Profile URL for resolving claims not present in id_token
 | ||||||
| 	// default set to 'false'
 | 	// default set to 'false'
 | ||||||
| 	SkipClaimsFromProfileURL bool `json:"skipClaimsFromProfileURL,omitempty"` | 	SkipClaimsFromProfileURL *bool `yaml:"skipClaimsFromProfileURL,omitempty"` | ||||||
| 	// ProtectedResource is the resource that is protected (Azure AD and ADFS only)
 | 	// ProtectedResource is the resource that is protected (Azure AD and ADFS only)
 | ||||||
| 	ProtectedResource string `json:"resource,omitempty"` | 	ProtectedResource string `yaml:"resource,omitempty"` | ||||||
| 	// ValidateURL is the access token validation endpoint
 | 	// ValidateURL is the access token validation endpoint
 | ||||||
| 	ValidateURL string `json:"validateURL,omitempty"` | 	ValidateURL string `yaml:"validateURL,omitempty"` | ||||||
| 	// Scope is the OAuth scope specification
 | 	// Scope is the OAuth scope specification
 | ||||||
| 	Scope string `json:"scope,omitempty"` | 	Scope string `yaml:"scope,omitempty"` | ||||||
| 	// AllowedGroups is a list of restrict logins to members of this group
 | 	// AllowedGroups is a list of restrict logins to members of this group
 | ||||||
| 	AllowedGroups []string `json:"allowedGroups,omitempty"` | 	AllowedGroups []string `yaml:"allowedGroups,omitempty"` | ||||||
| 	// The code challenge method
 | 	// The code challenge method
 | ||||||
| 	CodeChallengeMethod string `json:"code_challenge_method,omitempty"` | 	CodeChallengeMethod string `yaml:"code_challenge_method,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// URL to call to perform backend logout, `{id_token}` would be replaced by the actual `id_token` if available in the session
 | 	// URL to call to perform backend logout, `{id_token}` would be replaced by the actual `id_token` if available in the session
 | ||||||
| 	BackendLogoutURL string `json:"backendLogoutURL"` | 	BackendLogoutURL string `yaml:"backendLogoutURL"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ProviderType is used to enumerate the different provider type options
 | // ProviderType is used to enumerate the different provider type options
 | ||||||
|  | @ -157,19 +159,19 @@ const ( | ||||||
| 
 | 
 | ||||||
| type KeycloakOptions struct { | type KeycloakOptions struct { | ||||||
| 	// Group enables to restrict login to members of indicated group
 | 	// Group enables to restrict login to members of indicated group
 | ||||||
| 	Groups []string `json:"groups,omitempty"` | 	Groups []string `yaml:"groups,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// Role enables to restrict login to users with role (only available when using the keycloak-oidc provider)
 | 	// Role enables to restrict login to users with role (only available when using the keycloak-oidc provider)
 | ||||||
| 	Roles []string `json:"roles,omitempty"` | 	Roles []string `yaml:"roles,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type AzureOptions struct { | type AzureOptions struct { | ||||||
| 	// Tenant directs to a tenant-specific or common (tenant-independent) endpoint
 | 	// Tenant directs to a tenant-specific or common (tenant-independent) endpoint
 | ||||||
| 	// Default value is 'common'
 | 	// Default value is 'common'
 | ||||||
| 	Tenant string `json:"tenant,omitempty"` | 	Tenant string `yaml:"tenant,omitempty"` | ||||||
| 	// GraphGroupField configures the group field to be used when building the groups list from Microsoft Graph
 | 	// GraphGroupField configures the group field to be used when building the groups list from Microsoft Graph
 | ||||||
| 	// Default value is 'id'
 | 	// Default value is 'id'
 | ||||||
| 	GraphGroupField string `json:"graphGroupField,omitempty"` | 	GraphGroupField string `yaml:"graphGroupField,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type MicrosoftEntraIDOptions struct { | type MicrosoftEntraIDOptions struct { | ||||||
|  | @ -177,110 +179,110 @@ type MicrosoftEntraIDOptions struct { | ||||||
| 	// issued by different issuers and OIDC issuer verification needs to be disabled.
 | 	// issued by different issuers and OIDC issuer verification needs to be disabled.
 | ||||||
| 	// When not specified, all tenants are allowed. Redundant for single-tenant apps
 | 	// When not specified, all tenants are allowed. Redundant for single-tenant apps
 | ||||||
| 	// (regular ID token validation matches the issuer).
 | 	// (regular ID token validation matches the issuer).
 | ||||||
| 	AllowedTenants []string `json:"allowedTenants,omitempty"` | 	AllowedTenants []string `yaml:"allowedTenants,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// FederatedTokenAuth enable oAuth2 client authentication with federated token projected
 | 	// FederatedTokenAuth enable oAuth2 client authentication with federated token projected
 | ||||||
| 	// by Entra Workload Identity plugin, instead of client secret.
 | 	// by Entra Workload Identity plugin, instead of client secret.
 | ||||||
| 	FederatedTokenAuth bool `json:"federatedTokenAuth,omitempty"` | 	FederatedTokenAuth *bool `yaml:"federatedTokenAuth,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type ADFSOptions struct { | type ADFSOptions struct { | ||||||
| 	// Skip adding the scope parameter in login request
 | 	// Skip adding the scope parameter in login request
 | ||||||
| 	// Default value is 'false'
 | 	// Default value is 'false'
 | ||||||
| 	SkipScope bool `json:"skipScope,omitempty"` | 	SkipScope *bool `yaml:"skipScope,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type BitbucketOptions struct { | type BitbucketOptions struct { | ||||||
| 	// Team sets restrict logins to members of this team
 | 	// Team sets restrict logins to members of this team
 | ||||||
| 	Team string `json:"team,omitempty"` | 	Team string `yaml:"team,omitempty"` | ||||||
| 	// Repository sets restrict logins to user with access to this repository
 | 	// Repository sets restrict logins to user with access to this repository
 | ||||||
| 	Repository string `json:"repository,omitempty"` | 	Repository string `yaml:"repository,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type GitHubOptions struct { | type GitHubOptions struct { | ||||||
| 	// Org sets restrict logins to members of this organisation
 | 	// Org sets restrict logins to members of this organisation
 | ||||||
| 	Org string `json:"org,omitempty"` | 	Org string `yaml:"org,omitempty"` | ||||||
| 	// Team sets restrict logins to members of this team
 | 	// Team sets restrict logins to members of this team
 | ||||||
| 	Team string `json:"team,omitempty"` | 	Team string `yaml:"team,omitempty"` | ||||||
| 	// Repo sets restrict logins to collaborators of this repository
 | 	// Repo sets restrict logins to collaborators of this repository
 | ||||||
| 	Repo string `json:"repo,omitempty"` | 	Repo string `yaml:"repo,omitempty"` | ||||||
| 	// Token is the token to use when verifying repository collaborators
 | 	// Token is the token to use when verifying repository collaborators
 | ||||||
| 	// it must have push access to the repository
 | 	// it must have push access to the repository
 | ||||||
| 	Token string `json:"token,omitempty"` | 	Token string `yaml:"token,omitempty"` | ||||||
| 	// Users allows users with these usernames to login
 | 	// Users allows users with these usernames to login
 | ||||||
| 	// even if they do not belong to the specified org and team or collaborators
 | 	// even if they do not belong to the specified org and team or collaborators
 | ||||||
| 	Users []string `json:"users,omitempty"` | 	Users []string `yaml:"users,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type GitLabOptions struct { | type GitLabOptions struct { | ||||||
| 	// Group sets restrict logins to members of this group
 | 	// Group sets restrict logins to members of this group
 | ||||||
| 	Group []string `json:"group,omitempty"` | 	Group []string `yaml:"group,omitempty"` | ||||||
| 	// Projects restricts logins to members of these projects
 | 	// Projects restricts logins to members of these projects
 | ||||||
| 	Projects []string `json:"projects,omitempty"` | 	Projects []string `yaml:"projects,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type GoogleOptions struct { | type GoogleOptions struct { | ||||||
| 	// Groups sets restrict logins to members of this Google group
 | 	// Groups sets restrict logins to members of this Google group
 | ||||||
| 	Groups []string `json:"group,omitempty"` | 	Groups []string `yaml:"group,omitempty"` | ||||||
| 	// AdminEmail is the Google admin to impersonate for api calls
 | 	// AdminEmail is the Google admin to impersonate for api calls
 | ||||||
| 	AdminEmail string `json:"adminEmail,omitempty"` | 	AdminEmail string `yaml:"adminEmail,omitempty"` | ||||||
| 	// ServiceAccountJSON is the path to the service account json credentials
 | 	// ServiceAccountJSON is the path to the service account json credentials
 | ||||||
| 	ServiceAccountJSON string `json:"serviceAccountJson,omitempty"` | 	ServiceAccountJSON string `yaml:"serviceAccountJson,omitempty"` | ||||||
| 	// UseApplicationDefaultCredentials is a boolean whether to use Application Default Credentials instead of a ServiceAccountJSON
 | 	// UseApplicationDefaultCredentials is a boolean whether to use Application Default Credentials instead of a ServiceAccountJSON
 | ||||||
| 	UseApplicationDefaultCredentials bool `json:"useApplicationDefaultCredentials,omitempty"` | 	UseApplicationDefaultCredentials *bool `yaml:"useApplicationDefaultCredentials,omitempty"` | ||||||
| 	// TargetPrincipal is the Google Service Account used for Application Default Credentials
 | 	// TargetPrincipal is the Google Service Account used for Application Default Credentials
 | ||||||
| 	TargetPrincipal string `json:"targetPrincipal,omitempty"` | 	TargetPrincipal string `yaml:"targetPrincipal,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type OIDCOptions struct { | type OIDCOptions struct { | ||||||
| 	// IssuerURL is the OpenID Connect issuer URL
 | 	// IssuerURL is the OpenID Connect issuer URL
 | ||||||
| 	// eg: https://accounts.google.com
 | 	// eg: https://accounts.google.com
 | ||||||
| 	IssuerURL string `json:"issuerURL,omitempty"` | 	IssuerURL string `yaml:"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 `yaml:"insecureAllowUnverifiedEmail,omitempty"` | ||||||
| 	// 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 `yaml:"insecureSkipIssuerVerification,omitempty"` | ||||||
| 	// 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 `yaml:"insecureSkipNonce,omitempty"` | ||||||
| 	// 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 `yaml:"skipDiscovery,omitempty"` | ||||||
| 	// JwksURL is the OpenID Connect JWKS URL
 | 	// JwksURL is the OpenID Connect JWKS URL
 | ||||||
| 	// eg: https://www.googleapis.com/oauth2/v3/certs
 | 	// eg: https://www.googleapis.com/oauth2/v3/certs
 | ||||||
| 	JwksURL string `json:"jwksURL,omitempty"` | 	JwksURL string `yaml:"jwksURL,omitempty"` | ||||||
| 	// PublicKeyFiles is a list of paths pointing to public key files in PEM format to use
 | 	// PublicKeyFiles is a list of paths pointing to public key files in PEM format to use
 | ||||||
| 	// for verifying JWT tokens
 | 	// for verifying JWT tokens
 | ||||||
| 	PublicKeyFiles []string `json:"publicKeyFiles,omitempty"` | 	PublicKeyFiles []string `yaml:"publicKeyFiles,omitempty"` | ||||||
| 	// EmailClaim indicates which claim contains the user email,
 | 	// EmailClaim indicates which claim contains the user email,
 | ||||||
| 	// default set to 'email'
 | 	// default set to 'email'
 | ||||||
| 	EmailClaim string `json:"emailClaim,omitempty"` | 	EmailClaim string `yaml:"emailClaim,omitempty"` | ||||||
| 	// GroupsClaim indicates which claim contains the user groups
 | 	// GroupsClaim indicates which claim contains the user groups
 | ||||||
| 	// default set to 'groups'
 | 	// default set to 'groups'
 | ||||||
| 	GroupsClaim string `json:"groupsClaim,omitempty"` | 	GroupsClaim string `yaml:"groupsClaim,omitempty"` | ||||||
| 	// UserIDClaim indicates which claim contains the user ID
 | 	// UserIDClaim indicates which claim contains the user ID
 | ||||||
| 	// default set to 'email'
 | 	// default set to 'email'
 | ||||||
| 	UserIDClaim string `json:"userIDClaim,omitempty"` | 	UserIDClaim string `yaml:"userIDClaim,omitempty"` | ||||||
| 	// AudienceClaim allows to define any claim that is verified against the client id
 | 	// AudienceClaim allows to define any claim that is verified against the client id
 | ||||||
| 	// By default `aud` claim is used for verification.
 | 	// By default `aud` claim is used for verification.
 | ||||||
| 	AudienceClaims []string `json:"audienceClaims,omitempty"` | 	AudienceClaims []string `yaml:"audienceClaims,omitempty"` | ||||||
| 	// ExtraAudiences is a list of additional audiences that are allowed
 | 	// ExtraAudiences is a list of additional audiences that are allowed
 | ||||||
| 	// to pass verification in addition to the client id.
 | 	// to pass verification in addition to the client id.
 | ||||||
| 	ExtraAudiences []string `json:"extraAudiences,omitempty"` | 	ExtraAudiences []string `yaml:"extraAudiences,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type LoginGovOptions struct { | type LoginGovOptions struct { | ||||||
| 	// JWTKey is a private key in PEM format used to sign JWT,
 | 	// JWTKey is a private key in PEM format used to sign JWT,
 | ||||||
| 	JWTKey string `json:"jwtKey,omitempty"` | 	JWTKey string `yaml:"jwtKey,omitempty"` | ||||||
| 	// JWTKeyFile is a path to the private key file in PEM format used to sign the JWT
 | 	// JWTKeyFile is a path to the private key file in PEM format used to sign the JWT
 | ||||||
| 	JWTKeyFile string `json:"jwtKeyFile,omitempty"` | 	JWTKeyFile string `yaml:"jwtKeyFile,omitempty"` | ||||||
| 	// PubJWKURL is the JWK pubkey access endpoint
 | 	// PubJWKURL is the JWK pubkey access endpoint
 | ||||||
| 	PubJWKURL string `json:"pubjwkURL,omitempty"` | 	PubJWKURL string `yaml:"pubjwkURL,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func providerDefaults() Providers { | func providerDefaults() Providers { | ||||||
|  | @ -291,9 +293,9 @@ func providerDefaults() Providers { | ||||||
| 				Tenant: "common", | 				Tenant: "common", | ||||||
| 			}, | 			}, | ||||||
| 			OIDCConfig: OIDCOptions{ | 			OIDCConfig: OIDCOptions{ | ||||||
| 				InsecureAllowUnverifiedEmail: false, | 				InsecureAllowUnverifiedEmail: ptr.Ptr(false), | ||||||
| 				InsecureSkipNonce:            true, | 				InsecureSkipNonce:            ptr.Ptr(true), | ||||||
| 				SkipDiscovery:                false, | 				SkipDiscovery:                ptr.Ptr(false), | ||||||
| 				UserIDClaim:                  OIDCEmailClaim, // Deprecated: Use OIDCEmailClaim
 | 				UserIDClaim:                  OIDCEmailClaim, // Deprecated: Use OIDCEmailClaim
 | ||||||
| 				EmailClaim:                   OIDCEmailClaim, | 				EmailClaim:                   OIDCEmailClaim, | ||||||
| 				GroupsClaim:                  OIDCGroupsClaim, | 				GroupsClaim:                  OIDCGroupsClaim, | ||||||
|  |  | ||||||
|  | @ -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 []byte `yaml:"value,omitempty"` | ||||||
|  | 
 | ||||||
|  | 	// FromEnv expects the name of an environment variable.
 | ||||||
|  | 	FromEnv string `yaml:"fromEnv,omitempty"` | ||||||
|  | 
 | ||||||
|  | 	// FromFile expects a path to a file containing the secret value.
 | ||||||
|  | 	FromFile string `yaml:"fromFile,omitempty"` | ||||||
|  | } | ||||||
|  | @ -4,15 +4,15 @@ package options | ||||||
| type Server struct { | type Server struct { | ||||||
| 	// BindAddress is the address on which to serve traffic.
 | 	// BindAddress is the address on which to serve traffic.
 | ||||||
| 	// Leave blank or set to "-" to disable.
 | 	// Leave blank or set to "-" to disable.
 | ||||||
| 	BindAddress string | 	BindAddress string `yaml:"bindAddress,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// SecureBindAddress is the address on which to serve secure traffic.
 | 	// SecureBindAddress is the address on which to serve secure traffic.
 | ||||||
| 	// Leave blank or set to "-" to disable.
 | 	// Leave blank or set to "-" to disable.
 | ||||||
| 	SecureBindAddress string | 	SecureBindAddress string `yaml:"secureBindAddress,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// TLS contains the information for loading the certificate and key for the
 | 	// TLS contains the information for loading the certificate and key for the
 | ||||||
| 	// secure traffic and further configuration for the TLS server.
 | 	// secure traffic and further configuration for the TLS server.
 | ||||||
| 	TLS *TLS | 	TLS *TLS `yaml:"tls,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TLS contains the information for loading a TLS certificate and key
 | // TLS contains the information for loading a TLS certificate and key
 | ||||||
|  | @ -20,15 +20,15 @@ type Server struct { | ||||||
| type TLS struct { | type TLS struct { | ||||||
| 	// Key is the TLS key data to use.
 | 	// Key is the TLS key data to use.
 | ||||||
| 	// Typically this will come from a file.
 | 	// Typically this will come from a file.
 | ||||||
| 	Key *SecretSource | 	Key *SecretSource `yaml:"key,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// Cert is the TLS certificate data to use.
 | 	// Cert is the TLS certificate data to use.
 | ||||||
| 	// Typically this will come from a file.
 | 	// Typically this will come from a file.
 | ||||||
| 	Cert *SecretSource | 	Cert *SecretSource `yaml:"cert,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// MinVersion is the minimal TLS version that is acceptable.
 | 	// MinVersion is the minimal TLS version that is acceptable.
 | ||||||
| 	// E.g. Set to "TLS1.3" to select TLS version 1.3
 | 	// E.g. Set to "TLS1.3" to select TLS version 1.3
 | ||||||
| 	MinVersion string | 	MinVersion string `yaml:"minVersion,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// CipherSuites is a list of TLS cipher suites that are allowed.
 | 	// CipherSuites is a list of TLS cipher suites that are allowed.
 | ||||||
| 	// E.g.:
 | 	// E.g.:
 | ||||||
|  | @ -36,5 +36,5 @@ type TLS struct { | ||||||
| 	// - TLS_RSA_WITH_AES_256_GCM_SHA384
 | 	// - TLS_RSA_WITH_AES_256_GCM_SHA384
 | ||||||
| 	// If not specified, the default Go safe cipher list is used.
 | 	// If not specified, the default Go safe cipher list is used.
 | ||||||
| 	// List of valid cipher suites can be found in the [crypto/tls documentation](https://pkg.go.dev/crypto/tls#pkg-constants).
 | 	// List of valid cipher suites can be found in the [crypto/tls documentation](https://pkg.go.dev/crypto/tls#pkg-constants).
 | ||||||
| 	CipherSuites []string | 	CipherSuites []string `yaml:"cipherSuites,omitempty"` | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -14,11 +14,11 @@ const ( | ||||||
| type UpstreamConfig struct { | type UpstreamConfig struct { | ||||||
| 	// ProxyRawPath will pass the raw url path to upstream allowing for urls
 | 	// ProxyRawPath will pass the raw url path to upstream allowing for urls
 | ||||||
| 	// like: "/%2F/" which would otherwise be redirected to "/"
 | 	// like: "/%2F/" which would otherwise be redirected to "/"
 | ||||||
| 	ProxyRawPath bool `json:"proxyRawPath,omitempty"` | 	ProxyRawPath *bool `yaml:"proxyRawPath,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// Upstreams represents the configuration for the upstream servers.
 | 	// Upstreams represents the configuration for the upstream servers.
 | ||||||
| 	// Requests will be proxied to this upstream if the path matches the request path.
 | 	// Requests will be proxied to this upstream if the path matches the request path.
 | ||||||
| 	Upstreams []Upstream `json:"upstreams,omitempty"` | 	Upstreams []Upstream `yaml:"upstreams,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Upstream represents the configuration for an upstream server.
 | // Upstream represents the configuration for an upstream server.
 | ||||||
|  | @ -26,7 +26,7 @@ type UpstreamConfig struct { | ||||||
| type Upstream struct { | type Upstream struct { | ||||||
| 	// ID should be a unique identifier for the upstream.
 | 	// ID should be a unique identifier for the upstream.
 | ||||||
| 	// This value is required for all upstreams.
 | 	// This value is required for all upstreams.
 | ||||||
| 	ID string `json:"id,omitempty"` | 	ID string `yaml:"id,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// Path is used to map requests to the upstream server.
 | 	// Path is used to map requests to the upstream server.
 | ||||||
| 	// The closest match will take precedence and all Paths must be unique.
 | 	// The closest match will take precedence and all Paths must be unique.
 | ||||||
|  | @ -36,7 +36,7 @@ type Upstream struct { | ||||||
| 	// - `^/foo$`: Match only the explicit path `/foo`
 | 	// - `^/foo$`: Match only the explicit path `/foo`
 | ||||||
| 	// - `^/bar/$`: Match any path prefixed with `/bar/`
 | 	// - `^/bar/$`: Match any path prefixed with `/bar/`
 | ||||||
| 	// - `^/baz/(.*)$`: Match any path prefixed with `/baz` and capture the remaining path for use with RewriteTarget
 | 	// - `^/baz/(.*)$`: Match any path prefixed with `/baz` and capture the remaining path for use with RewriteTarget
 | ||||||
| 	Path string `json:"path,omitempty"` | 	Path string `yaml:"path,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// RewriteTarget allows users to rewrite the request path before it is sent to
 | 	// RewriteTarget allows users to rewrite the request path before it is sent to
 | ||||||
| 	// the upstream server (for an HTTP/HTTPS upstream) or mapped to the filesystem
 | 	// the upstream server (for an HTTP/HTTPS upstream) or mapped to the filesystem
 | ||||||
|  | @ -46,7 +46,7 @@ type Upstream struct { | ||||||
| 	// the request `/baz/abc/123` to `/foo/abc/123` before proxying to the
 | 	// the request `/baz/abc/123` to `/foo/abc/123` before proxying to the
 | ||||||
| 	// upstream server.  Or if the upstream were `file:///app`, a request for
 | 	// upstream server.  Or if the upstream were `file:///app`, a request for
 | ||||||
| 	// `/baz/info.html` would return the contents of the file `/app/foo/info.html`.
 | 	// `/baz/info.html` would return the contents of the file `/app/foo/info.html`.
 | ||||||
| 	RewriteTarget string `json:"rewriteTarget,omitempty"` | 	RewriteTarget string `yaml:"rewriteTarget,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// The URI of the upstream server. This may be an HTTP(S) server of a File
 | 	// The URI of the upstream server. This may be an HTTP(S) server of a File
 | ||||||
| 	// based URL. It may include a path, in which case all requests will be served
 | 	// based URL. It may include a path, in which case all requests will be served
 | ||||||
|  | @ -58,43 +58,43 @@ type Upstream struct { | ||||||
| 	// - file://host/path
 | 	// - file://host/path
 | ||||||
| 	// If the URI's path is "/base" and the incoming request was for "/dir",
 | 	// If the URI's path is "/base" and the incoming request was for "/dir",
 | ||||||
| 	// the upstream request will be for "/base/dir".
 | 	// the upstream request will be for "/base/dir".
 | ||||||
| 	URI string `json:"uri,omitempty"` | 	URI string `yaml:"uri,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// InsecureSkipTLSVerify will skip TLS verification of upstream HTTPS hosts.
 | 	// InsecureSkipTLSVerify will skip TLS verification of upstream HTTPS hosts.
 | ||||||
| 	// This option is insecure and will allow potential Man-In-The-Middle attacks
 | 	// This option is insecure and will allow potential Man-In-The-Middle attacks
 | ||||||
| 	// between OAuth2 Proxy and the upstream server.
 | 	// between OAuth2 Proxy and the upstream server.
 | ||||||
| 	// Defaults to false.
 | 	// Defaults to false.
 | ||||||
| 	InsecureSkipTLSVerify bool `json:"insecureSkipTLSVerify,omitempty"` | 	InsecureSkipTLSVerify *bool `yaml:"insecureSkipTLSVerify,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// Static will make all requests to this upstream have a static response.
 | 	// Static will make all requests to this upstream have a static response.
 | ||||||
| 	// The response will have a body of "Authenticated" and a response code
 | 	// The response will have a body of "Authenticated" and a response code
 | ||||||
| 	// matching StaticCode.
 | 	// matching StaticCode.
 | ||||||
| 	// If StaticCode is not set, the response will return a 200 response.
 | 	// If StaticCode is not set, the response will return a 200 response.
 | ||||||
| 	Static bool `json:"static,omitempty"` | 	Static *bool `yaml:"static,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// StaticCode determines the response code for the Static response.
 | 	// StaticCode determines the response code for the Static response.
 | ||||||
| 	// This option can only be used with Static enabled.
 | 	// This option can only be used with Static enabled.
 | ||||||
| 	StaticCode *int `json:"staticCode,omitempty"` | 	StaticCode *int `yaml:"staticCode,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// 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 `yaml:"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.
 | ||||||
| 	// Defaults to true.
 | 	// Defaults to true.
 | ||||||
| 	PassHostHeader *bool `json:"passHostHeader,omitempty"` | 	PassHostHeader *bool `yaml:"passHostHeader,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// ProxyWebSockets enables proxying of websockets to upstream servers
 | 	// ProxyWebSockets enables proxying of websockets to upstream servers
 | ||||||
| 	// Defaults to true.
 | 	// Defaults to true.
 | ||||||
| 	ProxyWebSockets *bool `json:"proxyWebSockets,omitempty"` | 	ProxyWebSockets *bool `yaml:"proxyWebSockets,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	// 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 `yaml:"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.
 | ||||||
| 	DisableKeepAlives bool `json:"disableKeepAlives,omitempty"` | 	DisableKeepAlives *bool `yaml:"disableKeepAlives,omitempty"` | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -27,7 +27,7 @@ func NewRequestHeaderInjector(headers []options.Header) (alice.Constructor, erro | ||||||
| func newStripHeaders(headers []options.Header) alice.Constructor { | func newStripHeaders(headers []options.Header) alice.Constructor { | ||||||
| 	headersToStrip := []string{} | 	headersToStrip := []string{} | ||||||
| 	for _, header := range headers { | 	for _, header := range headers { | ||||||
| 		if !header.PreserveRequestValue { | 		if !(*header.PreserveRequestValue) { | ||||||
| 			headersToStrip = append(headersToStrip, header.Name) | 			headersToStrip = append(headersToStrip, header.Name) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ import ( | ||||||
| 	middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware" | 	middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | ||||||
| 	sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions" | 	sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions" | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
| 	. "github.com/onsi/ginkgo/v2" | 	. "github.com/onsi/ginkgo/v2" | ||||||
| 	. "github.com/onsi/gomega" | 	. "github.com/onsi/gomega" | ||||||
| ) | ) | ||||||
|  | @ -115,7 +116,7 @@ var _ = Describe("Headers Suite", func() { | ||||||
| 			headers: []options.Header{ | 			headers: []options.Header{ | ||||||
| 				{ | 				{ | ||||||
| 					Name:                 "Claim", | 					Name:                 "Claim", | ||||||
| 					PreserveRequestValue: true, | 					PreserveRequestValue: ptr.Ptr(true), | ||||||
| 					Values: []options.HeaderValue{ | 					Values: []options.HeaderValue{ | ||||||
| 						{ | 						{ | ||||||
| 							ClaimSource: &options.ClaimSource{ | 							ClaimSource: &options.ClaimSource{ | ||||||
|  | @ -160,7 +161,7 @@ var _ = Describe("Headers Suite", func() { | ||||||
| 			headers: []options.Header{ | 			headers: []options.Header{ | ||||||
| 				{ | 				{ | ||||||
| 					Name:                 "Claim", | 					Name:                 "Claim", | ||||||
| 					PreserveRequestValue: true, | 					PreserveRequestValue: ptr.Ptr(true), | ||||||
| 					Values: []options.HeaderValue{ | 					Values: []options.HeaderValue{ | ||||||
| 						{ | 						{ | ||||||
| 							ClaimSource: &options.ClaimSource{ | 							ClaimSource: &options.ClaimSource{ | ||||||
|  | @ -341,7 +342,7 @@ var _ = Describe("Headers Suite", func() { | ||||||
| 			headers: []options.Header{ | 			headers: []options.Header{ | ||||||
| 				{ | 				{ | ||||||
| 					Name:                 "Claim", | 					Name:                 "Claim", | ||||||
| 					PreserveRequestValue: true, | 					PreserveRequestValue: ptr.Ptr(true), | ||||||
| 					Values: []options.HeaderValue{ | 					Values: []options.HeaderValue{ | ||||||
| 						{ | 						{ | ||||||
| 							ClaimSource: &options.ClaimSource{ | 							ClaimSource: &options.ClaimSource{ | ||||||
|  | @ -388,7 +389,7 @@ var _ = Describe("Headers Suite", func() { | ||||||
| 			headers: []options.Header{ | 			headers: []options.Header{ | ||||||
| 				{ | 				{ | ||||||
| 					Name:                 "Claim", | 					Name:                 "Claim", | ||||||
| 					PreserveRequestValue: true, | 					PreserveRequestValue: ptr.Ptr(true), | ||||||
| 					Values: []options.HeaderValue{ | 					Values: []options.HeaderValue{ | ||||||
| 						{ | 						{ | ||||||
| 							ClaimSource: &options.ClaimSource{ | 							ClaimSource: &options.ClaimSource{ | ||||||
|  |  | ||||||
|  | @ -104,8 +104,8 @@ var _ = Describe("Result suite", func() { | ||||||
| 
 | 
 | ||||||
| 	Context("UnmarshalInto", func() { | 	Context("UnmarshalInto", func() { | ||||||
| 		type testStruct struct { | 		type testStruct struct { | ||||||
| 			A string `json:"a"` | 			A string `yaml:"a"` | ||||||
| 			B int    `json:"b"` | 			B int    `yaml:"b"` | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		type unmarshalIntoTableInput struct { | 		type unmarshalIntoTableInput struct { | ||||||
|  |  | ||||||
|  | @ -54,7 +54,7 @@ func newHTTPUpstreamProxy(upstream options.Upstream, u *url.URL, sigData *option | ||||||
| 	// Set up a WebSocket proxy if required
 | 	// Set up a WebSocket proxy if required
 | ||||||
| 	var wsProxy http.Handler | 	var wsProxy http.Handler | ||||||
| 	if upstream.ProxyWebSockets == nil || *upstream.ProxyWebSockets { | 	if upstream.ProxyWebSockets == nil || *upstream.ProxyWebSockets { | ||||||
| 		wsProxy = newWebSocketReverseProxy(u, upstream.InsecureSkipTLSVerify) | 		wsProxy = newWebSocketReverseProxy(u, *upstream.InsecureSkipTLSVerify) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	var auth hmacauth.HmacAuth | 	var auth hmacauth.HmacAuth | ||||||
|  | @ -137,19 +137,19 @@ 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 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// InsecureSkipVerify is a configurable option we allow
 | 	// InsecureSkipVerify is a configurable option we allow
 | ||||||
| 	/* #nosec G402 */ | 	/* #nosec G402 */ | ||||||
| 	if upstream.InsecureSkipTLSVerify { | 	if *upstream.InsecureSkipTLSVerify { | ||||||
| 		transport.TLSClientConfig.InsecureSkipVerify = true | 		transport.TLSClientConfig.InsecureSkipVerify = true | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -168,7 +168,7 @@ func newReverseProxy(target *url.URL, upstream options.Upstream, errorHandler Pr | ||||||
| 
 | 
 | ||||||
| 	// Pass on DisableKeepAlives to the transport settings
 | 	// Pass on DisableKeepAlives to the transport settings
 | ||||||
| 	// to allow for disabling HTTP keep-alive connections
 | 	// to allow for disabling HTTP keep-alive connections
 | ||||||
| 	transport.DisableKeepAlives = upstream.DisableKeepAlives | 	transport.DisableKeepAlives = *upstream.DisableKeepAlives | ||||||
| 
 | 
 | ||||||
| 	// Apply the customized transport to our proxy before returning it
 | 	// Apply the customized transport to our proxy before returning it
 | ||||||
| 	proxy.Transport = transport | 	proxy.Transport = transport | ||||||
|  |  | ||||||
|  | @ -15,16 +15,15 @@ import ( | ||||||
| 	middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware" | 	middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/middleware" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/middleware" | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
| 	. "github.com/onsi/ginkgo/v2" | 	. "github.com/onsi/ginkgo/v2" | ||||||
| 	. "github.com/onsi/gomega" | 	. "github.com/onsi/gomega" | ||||||
| 	"golang.org/x/net/websocket" | 	"golang.org/x/net/websocket" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| 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 |  | ||||||
| 	falsum := false |  | ||||||
| 
 | 
 | ||||||
| 	type httpUpstreamTableInput struct { | 	type httpUpstreamTableInput struct { | ||||||
| 		id                     string | 		id                     string | ||||||
|  | @ -57,15 +56,15 @@ 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, | ||||||
| 				PassHostHeader:        &in.passUpstreamHostHeader, | 				PassHostHeader:        &in.passUpstreamHostHeader, | ||||||
| 				ProxyWebSockets:       &falsum, | 				ProxyWebSockets:       ptr.Ptr(false), | ||||||
| 				InsecureSkipTLSVerify: false, | 				InsecureSkipTLSVerify: ptr.Ptr(false), | ||||||
| 				FlushInterval:         &flush, | 				FlushInterval:         &flush, | ||||||
| 				Timeout:               &timeout, | 				Timeout:               &timeout, | ||||||
| 			} | 			} | ||||||
|  | @ -343,9 +342,9 @@ var _ = Describe("HTTP Upstream Suite", func() { | ||||||
| 
 | 
 | ||||||
| 		upstream := options.Upstream{ | 		upstream := options.Upstream{ | ||||||
| 			ID:                    "noPassHost", | 			ID:                    "noPassHost", | ||||||
| 			PassHostHeader:        &falsum, | 			PassHostHeader:        ptr.Ptr(false), | ||||||
| 			ProxyWebSockets:       &falsum, | 			ProxyWebSockets:       ptr.Ptr(false), | ||||||
| 			InsecureSkipTLSVerify: false, | 			InsecureSkipTLSVerify: ptr.Ptr(false), | ||||||
| 			FlushInterval:         &defaultFlushInterval, | 			FlushInterval:         &defaultFlushInterval, | ||||||
| 			Timeout:               &defaultTimeout, | 			Timeout:               &defaultTimeout, | ||||||
| 		} | 		} | ||||||
|  | @ -373,11 +372,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 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -389,10 +388,10 @@ var _ = Describe("HTTP Upstream Suite", func() { | ||||||
| 			upstream := options.Upstream{ | 			upstream := options.Upstream{ | ||||||
| 				ID:                    "foo123", | 				ID:                    "foo123", | ||||||
| 				FlushInterval:         &in.flushInterval, | 				FlushInterval:         &in.flushInterval, | ||||||
| 				InsecureSkipTLSVerify: in.skipVerify, | 				InsecureSkipTLSVerify: &in.skipVerify, | ||||||
| 				ProxyWebSockets:       &in.proxyWebSockets, | 				ProxyWebSockets:       &in.proxyWebSockets, | ||||||
| 				Timeout:               &in.timeout, | 				Timeout:               &in.timeout, | ||||||
| 				DisableKeepAlives:     in.disableKeepAlives, | 				DisableKeepAlives:     &in.disableKeepAlives, | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			handler := newHTTPUpstreamProxy(upstream, u, in.sigData, in.errorHandler) | 			handler := newHTTPUpstreamProxy(upstream, u, in.sigData, in.errorHandler) | ||||||
|  | @ -406,10 +405,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 +427,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 +465,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,13 +482,13 @@ 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:        ptr.Ptr(true), | ||||||
| 				ProxyWebSockets:       &truth, | 				ProxyWebSockets:       ptr.Ptr(true), | ||||||
| 				InsecureSkipTLSVerify: false, | 				InsecureSkipTLSVerify: ptr.Ptr(false), | ||||||
| 				FlushInterval:         &flush, | 				FlushInterval:         &flush, | ||||||
| 				Timeout:               &timeout, | 				Timeout:               &timeout, | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | @ -27,12 +27,12 @@ func NewProxy(upstreams options.UpstreamConfig, sigData *options.SignatureData, | ||||||
| 		serveMux: mux.NewRouter(), | 		serveMux: mux.NewRouter(), | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if upstreams.ProxyRawPath { | 	if *upstreams.ProxyRawPath { | ||||||
| 		m.serveMux.UseEncodedPath() | 		m.serveMux.UseEncodedPath() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, upstream := range sortByPathLongest(upstreams.Upstreams) { | 	for _, upstream := range sortByPathLongest(upstreams.Upstreams) { | ||||||
| 		if upstream.Static { | 		if *upstream.Static { | ||||||
| 			if err := m.registerStaticResponseHandler(upstream, writer); err != nil { | 			if err := m.registerStaticResponseHandler(upstream, writer); err != nil { | ||||||
| 				return nil, fmt.Errorf("could not register static upstream %q: %v", upstream.ID, err) | 				return nil, fmt.Errorf("could not register static upstream %q: %v", upstream.ID, err) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ import ( | ||||||
| 	middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware" | 	middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/app/pagewriter" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/app/pagewriter" | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
| 	. "github.com/onsi/ginkgo/v2" | 	. "github.com/onsi/ginkgo/v2" | ||||||
| 	. "github.com/onsi/gomega" | 	. "github.com/onsi/gomega" | ||||||
| ) | ) | ||||||
|  | @ -60,19 +61,19 @@ var _ = Describe("Proxy Suite", func() { | ||||||
| 						{ | 						{ | ||||||
| 							ID:         "static-backend", | 							ID:         "static-backend", | ||||||
| 							Path:       "/static/", | 							Path:       "/static/", | ||||||
| 							Static:     true, | 							Static:     ptr.Ptr(true), | ||||||
| 							StaticCode: &ok, | 							StaticCode: &ok, | ||||||
| 						}, | 						}, | ||||||
| 						{ | 						{ | ||||||
| 							ID:         "static-backend-no-trailing-slash", | 							ID:         "static-backend-no-trailing-slash", | ||||||
| 							Path:       "/static", | 							Path:       "/static", | ||||||
| 							Static:     true, | 							Static:     ptr.Ptr(true), | ||||||
| 							StaticCode: &accepted, | 							StaticCode: &accepted, | ||||||
| 						}, | 						}, | ||||||
| 						{ | 						{ | ||||||
| 							ID:         "static-backend-long", | 							ID:         "static-backend-long", | ||||||
| 							Path:       "/static/long", | 							Path:       "/static/long", | ||||||
| 							Static:     true, | 							Static:     ptr.Ptr(true), | ||||||
| 							StaticCode: &accepted, | 							StaticCode: &accepted, | ||||||
| 						}, | 						}, | ||||||
| 						{ | 						{ | ||||||
|  | @ -83,7 +84,7 @@ var _ = Describe("Proxy Suite", func() { | ||||||
| 						{ | 						{ | ||||||
| 							ID:         "single-path-backend", | 							ID:         "single-path-backend", | ||||||
| 							Path:       "/single-path", | 							Path:       "/single-path", | ||||||
| 							Static:     true, | 							Static:     ptr.Ptr(true), | ||||||
| 							StaticCode: &ok, | 							StaticCode: &ok, | ||||||
| 						}, | 						}, | ||||||
| 						{ | 						{ | ||||||
|  | @ -346,7 +347,7 @@ var _ = Describe("Proxy Suite", func() { | ||||||
| 				upstream: "", | 				upstream: "", | ||||||
| 			}), | 			}), | ||||||
| 			Entry("containing an escaped '/' with ProxyRawPath", &proxyTableInput{ | 			Entry("containing an escaped '/' with ProxyRawPath", &proxyTableInput{ | ||||||
| 				upstreams: options.UpstreamConfig{ProxyRawPath: true}, | 				upstreams: options.UpstreamConfig{ProxyRawPath: ptr.Ptr(true)}, | ||||||
| 				target:    "http://example.localhost/%2F/test1/%2F/test2", | 				target:    "http://example.localhost/%2F/test1/%2F/test2", | ||||||
| 				response: testHTTPResponse{ | 				response: testHTTPResponse{ | ||||||
| 					code: 404, | 					code: 404, | ||||||
|  |  | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | package ptr | ||||||
|  | 
 | ||||||
|  | // Ptr generically returns a pointer to the given value.
 | ||||||
|  | func Ptr[T any](v T) *T { | ||||||
|  | 	return &v | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Deref returns the value of the pointer or def(ault) if nil.
 | ||||||
|  | func Deref[T any](p *T, def T) T { | ||||||
|  | 	if p == nil { | ||||||
|  | 		return def | ||||||
|  | 	} | ||||||
|  | 	return *p | ||||||
|  | } | ||||||
|  | @ -0,0 +1,38 @@ | ||||||
|  | package ptr | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestPtr(t *testing.T) { | ||||||
|  | 	p := Ptr(42) | ||||||
|  | 	assert.NotNil(t, p) | ||||||
|  | 	assert.Equal(t, 42, *p) | ||||||
|  | 
 | ||||||
|  | 	s := Ptr("hello") | ||||||
|  | 	assert.NotNil(t, s) | ||||||
|  | 	assert.Equal(t, "hello", *s) | ||||||
|  | 
 | ||||||
|  | 	b := Ptr(true) | ||||||
|  | 	assert.NotNil(t, b) | ||||||
|  | 	assert.True(t, *b) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestDeref(t *testing.T) { | ||||||
|  | 	v := Deref(Ptr(99), 0) | ||||||
|  | 	assert.Equal(t, 99, v) | ||||||
|  | 
 | ||||||
|  | 	v = Deref[int](nil, 123) | ||||||
|  | 	assert.Equal(t, 123, v) | ||||||
|  | 
 | ||||||
|  | 	s := Deref[string](nil, "default") | ||||||
|  | 	assert.Equal(t, "default", s) | ||||||
|  | 
 | ||||||
|  | 	b := Deref(Ptr(true), false) | ||||||
|  | 	assert.True(t, b) | ||||||
|  | 
 | ||||||
|  | 	b = Deref[bool](nil, false) | ||||||
|  | 	assert.False(t, b) | ||||||
|  | } | ||||||
|  | @ -34,7 +34,7 @@ func Validate(o *options.Options) error { | ||||||
| 		transport := requests.DefaultTransport.(*http.Transport) | 		transport := requests.DefaultTransport.(*http.Transport) | ||||||
| 		transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} // #nosec G402 -- InsecureSkipVerify is a configurable option we allow
 | 		transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} // #nosec G402 -- InsecureSkipVerify is a configurable option we allow
 | ||||||
| 	} else if len(o.Providers[0].CAFiles) > 0 { | 	} else if len(o.Providers[0].CAFiles) > 0 { | ||||||
| 		pool, err := util.GetCertPool(o.Providers[0].CAFiles, o.Providers[0].UseSystemTrustStore) | 		pool, err := util.GetCertPool(o.Providers[0].CAFiles, *o.Providers[0].UseSystemTrustStore) | ||||||
| 		if err == nil { | 		if err == nil { | ||||||
| 			transport := requests.DefaultTransport.(*http.Transport) | 			transport := requests.DefaultTransport.(*http.Transport) | ||||||
| 			transport.TLSClientConfig = &tls.Config{ | 			transport.TLSClientConfig = &tls.Config{ | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ import ( | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -68,7 +69,7 @@ func TestGoogleGroupOptionsWithoutServiceAccountJSON(t *testing.T) { | ||||||
| 
 | 
 | ||||||
| func TestGoogleGroupOptionsWithoutAdminEmail(t *testing.T) { | func TestGoogleGroupOptionsWithoutAdminEmail(t *testing.T) { | ||||||
| 	o := testOptions() | 	o := testOptions() | ||||||
| 	o.Providers[0].GoogleConfig.UseApplicationDefaultCredentials = true | 	o.Providers[0].GoogleConfig.UseApplicationDefaultCredentials = ptr.Ptr(true) | ||||||
| 	err := Validate(o) | 	err := Validate(o) | ||||||
| 	assert.NotEqual(t, nil, err) | 	assert.NotEqual(t, nil, err) | ||||||
| 
 | 
 | ||||||
|  | @ -81,7 +82,7 @@ func TestGoogleGroupOptionsWithoutGroups(t *testing.T) { | ||||||
| 	o := testOptions() | 	o := testOptions() | ||||||
| 	// Set admin email and application default credentials but no groups - should still require them
 | 	// Set admin email and application default credentials but no groups - should still require them
 | ||||||
| 	o.Providers[0].GoogleConfig.AdminEmail = "admin@example.com" | 	o.Providers[0].GoogleConfig.AdminEmail = "admin@example.com" | ||||||
| 	o.Providers[0].GoogleConfig.UseApplicationDefaultCredentials = true | 	o.Providers[0].GoogleConfig.UseApplicationDefaultCredentials = ptr.Ptr(true) | ||||||
| 	err := Validate(o) | 	err := Validate(o) | ||||||
| 	// Should pass validation since google-group is now optional
 | 	// Should pass validation since google-group is now optional
 | ||||||
| 	assert.Equal(t, nil, err) | 	assert.Equal(t, nil, err) | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ import ( | ||||||
| 	"os" | 	"os" | ||||||
| 
 | 
 | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // validateProviders is the initial validation migration for multiple providrers
 | // validateProviders is the initial validation migration for multiple providrers
 | ||||||
|  | @ -64,7 +65,7 @@ func validateProvider(provider options.Provider, providerIDs map[string]struct{} | ||||||
| // providerRequiresClientSecret checks if provider requires client secret to be set
 | // providerRequiresClientSecret checks if provider requires client secret to be set
 | ||||||
| // or it can be omitted in favor of JWT token to authenticate oAuth client
 | // or it can be omitted in favor of JWT token to authenticate oAuth client
 | ||||||
| func providerRequiresClientSecret(provider options.Provider) bool { | func providerRequiresClientSecret(provider options.Provider) bool { | ||||||
| 	if provider.Type == "entra-id" && provider.MicrosoftEntraIDConfig.FederatedTokenAuth { | 	if provider.Type == "entra-id" && *provider.MicrosoftEntraIDConfig.FederatedTokenAuth { | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -96,7 +97,7 @@ func validateGoogleConfig(provider options.Provider) []string { | ||||||
| 
 | 
 | ||||||
| 	hasAdminEmail := provider.GoogleConfig.AdminEmail != "" | 	hasAdminEmail := provider.GoogleConfig.AdminEmail != "" | ||||||
| 	hasSAJSON := provider.GoogleConfig.ServiceAccountJSON != "" | 	hasSAJSON := provider.GoogleConfig.ServiceAccountJSON != "" | ||||||
| 	useADC := provider.GoogleConfig.UseApplicationDefaultCredentials | 	useADC := ptr.Deref(provider.GoogleConfig.UseApplicationDefaultCredentials, false) | ||||||
| 
 | 
 | ||||||
| 	if !hasAdminEmail && !hasSAJSON && !useADC { | 	if !hasAdminEmail && !hasSAJSON && !useADC { | ||||||
| 		return msgs | 		return msgs | ||||||
|  | @ -123,7 +124,7 @@ func validateGoogleConfig(provider options.Provider) []string { | ||||||
| func validateEntraConfig(provider options.Provider) []string { | func validateEntraConfig(provider options.Provider) []string { | ||||||
| 	msgs := []string{} | 	msgs := []string{} | ||||||
| 
 | 
 | ||||||
| 	if provider.MicrosoftEntraIDConfig.FederatedTokenAuth { | 	if *provider.MicrosoftEntraIDConfig.FederatedTokenAuth { | ||||||
| 		federatedTokenPath := os.Getenv("AZURE_FEDERATED_TOKEN_FILE") | 		federatedTokenPath := os.Getenv("AZURE_FEDERATED_TOKEN_FILE") | ||||||
| 
 | 
 | ||||||
| 		if federatedTokenPath == "" { | 		if federatedTokenPath == "" { | ||||||
|  |  | ||||||
|  | @ -54,22 +54,22 @@ func validateUpstream(upstream options.Upstream, ids, paths map[string]struct{}) | ||||||
| func validateStaticUpstream(upstream options.Upstream) []string { | func validateStaticUpstream(upstream options.Upstream) []string { | ||||||
| 	msgs := []string{} | 	msgs := []string{} | ||||||
| 
 | 
 | ||||||
| 	if !upstream.Static && upstream.StaticCode != nil { | 	if !*upstream.Static && upstream.StaticCode != nil { | ||||||
| 		msgs = append(msgs, fmt.Sprintf("upstream %q has staticCode (%d), but is not a static upstream, set 'static' for a static response", upstream.ID, *upstream.StaticCode)) | 		msgs = append(msgs, fmt.Sprintf("upstream %q has staticCode (%d), but is not a static upstream, set 'static' for a static response", upstream.ID, *upstream.StaticCode)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Checks after this only make sense when the upstream is static
 | 	// Checks after this only make sense when the upstream is static
 | ||||||
| 	if !upstream.Static { | 	if !*upstream.Static { | ||||||
| 		return msgs | 		return msgs | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if upstream.URI != "" { | 	if upstream.URI != "" { | ||||||
| 		msgs = append(msgs, fmt.Sprintf("upstream %q has uri, but is a static upstream, this will have no effect.", upstream.ID)) | 		msgs = append(msgs, fmt.Sprintf("upstream %q has uri, but is a static upstream, this will have no effect.", upstream.ID)) | ||||||
| 	} | 	} | ||||||
| 	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 { | ||||||
|  | @ -85,13 +85,13 @@ func validateStaticUpstream(upstream options.Upstream) []string { | ||||||
| func validateUpstreamURI(upstream options.Upstream) []string { | func validateUpstreamURI(upstream options.Upstream) []string { | ||||||
| 	msgs := []string{} | 	msgs := []string{} | ||||||
| 
 | 
 | ||||||
| 	if !upstream.Static && upstream.URI == "" { | 	if !*upstream.Static && upstream.URI == "" { | ||||||
| 		msgs = append(msgs, fmt.Sprintf("upstream %q has empty uri: uris are required for all non-static upstreams", upstream.ID)) | 		msgs = append(msgs, fmt.Sprintf("upstream %q has empty uri: uris are required for all non-static upstreams", upstream.ID)) | ||||||
| 		return msgs | 		return msgs | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Checks after this only make sense the upstream is not static
 | 	// Checks after this only make sense the upstream is not static
 | ||||||
| 	if upstream.Static { | 	if *upstream.Static { | ||||||
| 		return msgs | 		return msgs | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ import ( | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
| 	. "github.com/onsi/ginkgo/v2" | 	. "github.com/onsi/ginkgo/v2" | ||||||
| 	. "github.com/onsi/gomega" | 	. "github.com/onsi/gomega" | ||||||
| ) | ) | ||||||
|  | @ -14,9 +15,8 @@ var _ = Describe("Upstreams", func() { | ||||||
| 		errStrings []string | 		errStrings []string | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	flushInterval := options.Duration(5 * time.Second) | 	flushInterval := 5 * time.Second | ||||||
| 	staticCode200 := 200 | 	staticCode200 := 200 | ||||||
| 	truth := true |  | ||||||
| 
 | 
 | ||||||
| 	validHTTPUpstream := options.Upstream{ | 	validHTTPUpstream := options.Upstream{ | ||||||
| 		ID:   "validHTTPUpstream", | 		ID:   "validHTTPUpstream", | ||||||
|  | @ -26,7 +26,7 @@ var _ = Describe("Upstreams", func() { | ||||||
| 	validStaticUpstream := options.Upstream{ | 	validStaticUpstream := options.Upstream{ | ||||||
| 		ID:     "validStaticUpstream", | 		ID:     "validStaticUpstream", | ||||||
| 		Path:   "/validStaticUpstream", | 		Path:   "/validStaticUpstream", | ||||||
| 		Static: true, | 		Static: ptr.Ptr(true), | ||||||
| 	} | 	} | ||||||
| 	validFileUpstream := options.Upstream{ | 	validFileUpstream := options.Upstream{ | ||||||
| 		ID:   "validFileUpstream", | 		ID:   "validFileUpstream", | ||||||
|  | @ -145,11 +145,11 @@ var _ = Describe("Upstreams", func() { | ||||||
| 						ID:                    "foo", | 						ID:                    "foo", | ||||||
| 						Path:                  "/foo", | 						Path:                  "/foo", | ||||||
| 						URI:                   "ftp://foo", | 						URI:                   "ftp://foo", | ||||||
| 						Static:                true, | 						Static:                ptr.Ptr(true), | ||||||
| 						FlushInterval:         &flushInterval, | 						FlushInterval:         &flushInterval, | ||||||
| 						PassHostHeader:        &truth, | 						PassHostHeader:        ptr.Ptr(true), | ||||||
| 						ProxyWebSockets:       &truth, | 						ProxyWebSockets:       ptr.Ptr(true), | ||||||
| 						InsecureSkipTLSVerify: true, | 						InsecureSkipTLSVerify: ptr.Ptr(true), | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
|  |  | ||||||
|  | @ -50,7 +50,7 @@ func NewADFSProvider(p *ProviderData, opts options.Provider) *ADFSProvider { | ||||||
| 
 | 
 | ||||||
| 	return &ADFSProvider{ | 	return &ADFSProvider{ | ||||||
| 		OIDCProvider:    oidcProvider, | 		OIDCProvider:    oidcProvider, | ||||||
| 		skipScope:       opts.ADFSConfig.SkipScope, | 		skipScope:       *opts.ADFSConfig.SkipScope, | ||||||
| 		oidcEnrichFunc:  oidcProvider.EnrichSession, | 		oidcEnrichFunc:  oidcProvider.EnrichSession, | ||||||
| 		oidcRefreshFunc: oidcProvider.RefreshSession, | 		oidcRefreshFunc: oidcProvider.RefreshSession, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ import ( | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions" | ||||||
| 	internaloidc "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/providers/oidc" | 	internaloidc "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/providers/oidc" | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
| 	. "github.com/onsi/ginkgo/v2" | 	. "github.com/onsi/ginkgo/v2" | ||||||
| 	. "github.com/onsi/gomega" | 	. "github.com/onsi/gomega" | ||||||
| ) | ) | ||||||
|  | @ -172,7 +173,7 @@ var _ = Describe("ADFS Provider Tests", func() { | ||||||
| 				ProtectedResource: resource, | 				ProtectedResource: resource, | ||||||
| 				Scope:             "", | 				Scope:             "", | ||||||
| 			}, options.Provider{ | 			}, options.Provider{ | ||||||
| 				ADFSConfig: options.ADFSOptions{SkipScope: true}, | 				ADFSConfig: options.ADFSOptions{SkipScope: ptr.Ptr(true)}, | ||||||
| 			}) | 			}) | ||||||
| 
 | 
 | ||||||
| 			result := p.GetLoginURL("https://example.com/adfs/oauth2/", "", "", url.Values{}) | 			result := p.GetLoginURL("https://example.com/adfs/oauth2/", "", "", url.Values{}) | ||||||
|  |  | ||||||
|  | @ -102,7 +102,7 @@ func NewGoogleProvider(p *ProviderData, opts options.GoogleOptions) (*GoogleProv | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if opts.ServiceAccountJSON != "" || opts.UseApplicationDefaultCredentials { | 	if opts.ServiceAccountJSON != "" || *opts.UseApplicationDefaultCredentials { | ||||||
| 		provider.configureGroups(opts) | 		provider.configureGroups(opts) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -259,7 +259,7 @@ var possibleScopesList = [...]string{ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func getOauth2TokenSource(ctx context.Context, opts options.GoogleOptions, scope string) oauth2.TokenSource { | func getOauth2TokenSource(ctx context.Context, opts options.GoogleOptions, scope string) oauth2.TokenSource { | ||||||
| 	if opts.UseApplicationDefaultCredentials { | 	if *opts.UseApplicationDefaultCredentials { | ||||||
| 		ts, err := impersonate.CredentialsTokenSource(ctx, impersonate.CredentialsConfig{ | 		ts, err := impersonate.CredentialsTokenSource(ctx, impersonate.CredentialsConfig{ | ||||||
| 			TargetPrincipal: getTargetPrincipal(ctx, opts), | 			TargetPrincipal: getTargetPrincipal(ctx, opts), | ||||||
| 			Scopes:          []string{scope}, | 			Scopes:          []string{scope}, | ||||||
|  |  | ||||||
|  | @ -51,7 +51,7 @@ func NewMicrosoftEntraIDProvider(p *ProviderData, opts options.Provider) *Micros | ||||||
| 		OIDCProvider: NewOIDCProvider(p, opts.OIDCConfig), | 		OIDCProvider: NewOIDCProvider(p, opts.OIDCConfig), | ||||||
| 
 | 
 | ||||||
| 		multiTenantAllowedTenants: opts.MicrosoftEntraIDConfig.AllowedTenants, | 		multiTenantAllowedTenants: opts.MicrosoftEntraIDConfig.AllowedTenants, | ||||||
| 		federatedTokenAuth:        opts.MicrosoftEntraIDConfig.FederatedTokenAuth, | 		federatedTokenAuth:        *opts.MicrosoftEntraIDConfig.FederatedTokenAuth, | ||||||
| 		microsoftGraphURL:         microsoftGraphURL, | 		microsoftGraphURL:         microsoftGraphURL, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ import ( | ||||||
| 	"github.com/coreos/go-oidc/v3/oidc" | 	"github.com/coreos/go-oidc/v3/oidc" | ||||||
| 	"github.com/golang-jwt/jwt/v5" | 	"github.com/golang-jwt/jwt/v5" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| 
 | 
 | ||||||
| 	. "github.com/onsi/gomega" | 	. "github.com/onsi/gomega" | ||||||
|  | @ -24,7 +25,7 @@ func TestAzureEntraOIDCProviderNewMultiTenant(t *testing.T) { | ||||||
| 	provider := NewMicrosoftEntraIDProvider(&ProviderData{}, | 	provider := NewMicrosoftEntraIDProvider(&ProviderData{}, | ||||||
| 		options.Provider{OIDCConfig: options.OIDCOptions{ | 		options.Provider{OIDCConfig: options.OIDCOptions{ | ||||||
| 			IssuerURL:                      "https://login.microsoftonline.com/common/v2.0", | 			IssuerURL:                      "https://login.microsoftonline.com/common/v2.0", | ||||||
| 			InsecureSkipIssuerVerification: true, | 			InsecureSkipIssuerVerification: ptr.Ptr(true), | ||||||
| 		}}, | 		}}, | ||||||
| 	) | 	) | ||||||
| 	g.Expect(provider.Data().ProviderName).To(Equal("Microsoft Entra ID")) | 	g.Expect(provider.Data().ProviderName).To(Equal("Microsoft Entra ID")) | ||||||
|  | @ -90,8 +91,8 @@ func TestAzureEntraOIDCProviderValidateSessionAllowedTenants(t *testing.T) { | ||||||
| 		options.Provider{ | 		options.Provider{ | ||||||
| 			OIDCConfig: options.OIDCOptions{ | 			OIDCConfig: options.OIDCOptions{ | ||||||
| 				IssuerURL:                      "https://login.microsoftonline.com/common/v2.0", | 				IssuerURL:                      "https://login.microsoftonline.com/common/v2.0", | ||||||
| 				InsecureSkipIssuerVerification: true, | 				InsecureSkipIssuerVerification: ptr.Ptr(true), | ||||||
| 				InsecureSkipNonce:              true, | 				InsecureSkipNonce:              ptr.Ptr(true), | ||||||
| 			}, | 			}, | ||||||
| 			MicrosoftEntraIDConfig: options.MicrosoftEntraIDOptions{ | 			MicrosoftEntraIDConfig: options.MicrosoftEntraIDOptions{ | ||||||
| 				AllowedTenants: []string{"85d7d600-7804-4d92-8d43-9c33c21c130c"}, | 				AllowedTenants: []string{"85d7d600-7804-4d92-8d43-9c33c21c130c"}, | ||||||
|  |  | ||||||
|  | @ -50,7 +50,7 @@ func NewOIDCProvider(p *ProviderData, opts options.OIDCOptions) *OIDCProvider { | ||||||
| 
 | 
 | ||||||
| 	return &OIDCProvider{ | 	return &OIDCProvider{ | ||||||
| 		ProviderData: p, | 		ProviderData: p, | ||||||
| 		SkipNonce:    opts.InsecureSkipNonce, | 		SkipNonce:    *opts.InsecureSkipNonce, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -63,7 +63,7 @@ func newOIDCProvider(serverURL *url.URL, skipNonce bool) *OIDCProvider { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	p := NewOIDCProvider(providerData, options.OIDCOptions{ | 	p := NewOIDCProvider(providerData, options.OIDCOptions{ | ||||||
| 		InsecureSkipNonce: skipNonce, | 		InsecureSkipNonce: &skipNonce, | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| 	return p | 	return p | ||||||
|  |  | ||||||
|  | @ -98,8 +98,8 @@ func newProviderDataFromConfig(providerConfig options.Provider) (*ProviderData, | ||||||
| 			IssuerURL:              providerConfig.OIDCConfig.IssuerURL, | 			IssuerURL:              providerConfig.OIDCConfig.IssuerURL, | ||||||
| 			JWKsURL:                providerConfig.OIDCConfig.JwksURL, | 			JWKsURL:                providerConfig.OIDCConfig.JwksURL, | ||||||
| 			PublicKeyFiles:         providerConfig.OIDCConfig.PublicKeyFiles, | 			PublicKeyFiles:         providerConfig.OIDCConfig.PublicKeyFiles, | ||||||
| 			SkipDiscovery:          providerConfig.OIDCConfig.SkipDiscovery, | 			SkipDiscovery:          *providerConfig.OIDCConfig.SkipDiscovery, | ||||||
| 			SkipIssuerVerification: providerConfig.OIDCConfig.InsecureSkipIssuerVerification, | 			SkipIssuerVerification: *providerConfig.OIDCConfig.InsecureSkipIssuerVerification, | ||||||
| 		}) | 		}) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, fmt.Errorf("error building OIDC ProviderVerifier: %v", err) | 			return nil, fmt.Errorf("error building OIDC ProviderVerifier: %v", err) | ||||||
|  | @ -143,10 +143,10 @@ func newProviderDataFromConfig(providerConfig options.Provider) (*ProviderData, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Make the OIDC options available to all providers that support it
 | 	// Make the OIDC options available to all providers that support it
 | ||||||
| 	p.AllowUnverifiedEmail = providerConfig.OIDCConfig.InsecureAllowUnverifiedEmail | 	p.AllowUnverifiedEmail = *providerConfig.OIDCConfig.InsecureAllowUnverifiedEmail | ||||||
| 	p.EmailClaim = providerConfig.OIDCConfig.EmailClaim | 	p.EmailClaim = providerConfig.OIDCConfig.EmailClaim | ||||||
| 	p.GroupsClaim = providerConfig.OIDCConfig.GroupsClaim | 	p.GroupsClaim = providerConfig.OIDCConfig.GroupsClaim | ||||||
| 	p.SkipClaimsFromProfileURL = providerConfig.SkipClaimsFromProfileURL | 	p.SkipClaimsFromProfileURL = *providerConfig.SkipClaimsFromProfileURL | ||||||
| 
 | 
 | ||||||
| 	// Set PKCE enabled or disabled based on discovery and force options
 | 	// Set PKCE enabled or disabled based on discovery and force options
 | ||||||
| 	p.CodeChallengeMethod = parseCodeChallengeMethod(providerConfig) | 	p.CodeChallengeMethod = parseCodeChallengeMethod(providerConfig) | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ import ( | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | ||||||
|  | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr" | ||||||
| 	. "github.com/onsi/gomega" | 	. "github.com/onsi/gomega" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -81,7 +82,7 @@ func TestSkipOIDCDiscovery(t *testing.T) { | ||||||
| 		ClientSecretFile: clientSecret, | 		ClientSecretFile: clientSecret, | ||||||
| 		OIDCConfig: options.OIDCOptions{ | 		OIDCConfig: options.OIDCOptions{ | ||||||
| 			IssuerURL:     msIssuerURL, | 			IssuerURL:     msIssuerURL, | ||||||
| 			SkipDiscovery: true, | 			SkipDiscovery: ptr.Ptr(true), | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -108,7 +109,7 @@ func TestURLsCorrectlyParsed(t *testing.T) { | ||||||
| 		RedeemURL:        msTokenURL, | 		RedeemURL:        msTokenURL, | ||||||
| 		OIDCConfig: options.OIDCOptions{ | 		OIDCConfig: options.OIDCOptions{ | ||||||
| 			IssuerURL:     msIssuerURL, | 			IssuerURL:     msIssuerURL, | ||||||
| 			SkipDiscovery: true, | 			SkipDiscovery: ptr.Ptr(true), | ||||||
| 			JwksURL:       msKeysURL, | 			JwksURL:       msKeysURL, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  | @ -216,7 +217,7 @@ func TestScope(t *testing.T) { | ||||||
| 			AllowedGroups:    tc.allowedGroups, | 			AllowedGroups:    tc.allowedGroups, | ||||||
| 			OIDCConfig: options.OIDCOptions{ | 			OIDCConfig: options.OIDCOptions{ | ||||||
| 				IssuerURL:     msIssuerURL, | 				IssuerURL:     msIssuerURL, | ||||||
| 				SkipDiscovery: true, | 				SkipDiscovery: ptr.Ptr(true), | ||||||
| 				JwksURL:       msKeysURL, | 				JwksURL:       msKeysURL, | ||||||
| 			}, | 			}, | ||||||
| 		} | 		} | ||||||
|  | @ -297,7 +298,7 @@ func TestEmailClaimCorrectlySet(t *testing.T) { | ||||||
| 				RedeemURL:        msTokenURL, | 				RedeemURL:        msTokenURL, | ||||||
| 				OIDCConfig: options.OIDCOptions{ | 				OIDCConfig: options.OIDCOptions{ | ||||||
| 					IssuerURL:     msIssuerURL, | 					IssuerURL:     msIssuerURL, | ||||||
| 					SkipDiscovery: true, | 					SkipDiscovery: ptr.Ptr(true), | ||||||
| 					JwksURL:       msKeysURL, | 					JwksURL:       msKeysURL, | ||||||
| 					UserIDClaim:   tc.userIDClaim, | 					UserIDClaim:   tc.userIDClaim, | ||||||
| 					EmailClaim:    tc.emailClaim, | 					EmailClaim:    tc.emailClaim, | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue