diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 3189ab66..89d97f30 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/vscode/devcontainers/go:1-1.22 +FROM mcr.microsoft.com/vscode/devcontainers/go:1-1.23 SHELL ["/bin/bash", "-o", "pipefail", "-c"] diff --git a/CHANGELOG.md b/CHANGELOG.md index 54518f75..a51aa773 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ ## Changes since v7.8.2 +- [#3001](https://github.com/oauth2-proxy/oauth2-proxy/pull/3001) Allow to set non-default authorization request response mode (@stieler-it) + # V7.8.2 ## Release Highlights diff --git a/docs/docs/configuration/alpha_config.md b/docs/docs/configuration/alpha_config.md index e833f53c..732100ed 100644 --- a/docs/docs/configuration/alpha_config.md +++ b/docs/docs/configuration/alpha_config.md @@ -445,6 +445,7 @@ Provider holds all configuration for a single provider | `useSystemTrustStore` | _bool_ | 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. | | `loginURL` | _string_ | LoginURL is the authentication endpoint | | `loginURLParameters` | _[[]LoginURLParameter](#loginurlparameter)_ | LoginURLParameters defines the parameters that can be passed from the start URL to the IdP login URL | +| `authRequestResponseMode` | _string_ | AuthRequestResponseMode defines the response mode to request during authorization request | | `redeemURL` | _string_ | RedeemURL is the token redemption endpoint | | `profileURL` | _string_ | ProfileURL is the profile access endpoint | | `skipClaimsFromProfileURL` | _bool_ | SkipClaimsFromProfileURL allows to skip request to Profile URL for resolving claims not present in id_token
default set to 'false' | diff --git a/docs/docs/configuration/overview.md b/docs/docs/configuration/overview.md index 69f218bf..52ead105 100644 --- a/docs/docs/configuration/overview.md +++ b/docs/docs/configuration/overview.md @@ -91,6 +91,7 @@ Provider specific options can be found on their respective subpages. | flag: `--jwt-key-file`
toml: `jwt_key_file` | string | path to the private key file in PEM format used to sign the JWT so that you can say something like `--jwt-key-file=/etc/ssl/private/jwt_signing_key.pem`: required by login.gov | | | flag: `--jwt-key`
toml: `jwt_key` | string | private key in PEM format used to sign JWT, so that you can say something like `--jwt-key="${OAUTH2_PROXY_JWT_KEY}"`: required by login.gov | | | flag: `--login-url`
toml: `login_url` | string | Authentication endpoint | | +| flag: `--auth-request-response-mode`
toml: `auth-request-response-mode` | string | Response mode to ask for during authentication request | | | flag: `--oidc-audience-claim`
toml: `oidc_audience_claims` | string | which OIDC claim contains the audience | `"aud"` | | flag: `--oidc-email-claim`
toml: `oidc_email_claim` | string | which OIDC claim contains the user's email | `"email"` | | flag: `--oidc-extra-audience`
toml: `oidc_extra_audiences` | string \| list | additional audiences which are allowed to pass verification | `"[]"` | diff --git a/pkg/apis/options/legacy_options.go b/pkg/apis/options/legacy_options.go index 163aaa2c..a2c5f4e3 100644 --- a/pkg/apis/options/legacy_options.go +++ b/pkg/apis/options/legacy_options.go @@ -524,6 +524,7 @@ type LegacyProvider struct { OIDCExtraAudiences []string `flag:"oidc-extra-audience" cfg:"oidc_extra_audiences"` OIDCPublicKeyFiles []string `flag:"oidc-public-key-file" cfg:"oidc_public_key_files"` LoginURL string `flag:"login-url" cfg:"login_url"` + AuthRequestResponseMode string `flag:"auth-request-response-mode" cfg:"auth_request_response_mode"` RedeemURL string `flag:"redeem-url" cfg:"redeem_url"` ProfileURL string `flag:"profile-url" cfg:"profile_url"` SkipClaimsFromProfileURL bool `flag:"skip-claims-from-profile-url" cfg:"skip_claims_from_profile_url"` @@ -586,6 +587,7 @@ func legacyProviderFlagSet() *pflag.FlagSet { flagSet.String("login-url", "", "Authentication endpoint") flagSet.String("redeem-url", "", "Token redemption endpoint") flagSet.String("profile-url", "", "Profile access endpoint") + flagSet.String("auth-request-response-mode", "", "Authorization request response mode") flagSet.Bool("skip-claims-from-profile-url", false, "Skip loading missing claims from profile URL") flagSet.String("resource", "", "The resource that is protected (Azure AD only)") flagSet.String("validate-url", "", "Access token validation endpoint") @@ -684,6 +686,7 @@ func (l *LegacyProvider) convert() (Providers, error) { AllowedGroups: l.AllowedGroups, CodeChallengeMethod: l.CodeChallengeMethod, BackendLogoutURL: l.BackendLogoutURL, + AuthRequestResponseMode: l.AuthRequestResponseMode, } // This part is out of the switch section for all providers that support OIDC diff --git a/pkg/apis/options/providers.go b/pkg/apis/options/providers.go index 94c23ce1..0aa9d15a 100644 --- a/pkg/apis/options/providers.go +++ b/pkg/apis/options/providers.go @@ -68,6 +68,8 @@ type Provider struct { LoginURL string `json:"loginURL,omitempty"` // LoginURLParameters defines the parameters that can be passed from the start URL to the IdP login URL LoginURLParameters []LoginURLParameter `json:"loginURLParameters,omitempty"` + // AuthRequestResponseMode defines the response mode to request during authorization request + AuthRequestResponseMode string `json:"authRequestResponseMode,omitempty"` // RedeemURL is the token redemption endpoint RedeemURL string `json:"redeemURL,omitempty"` // ProfileURL is the profile access endpoint diff --git a/providers/provider_data.go b/providers/provider_data.go index 3c59c6da..95de5c50 100644 --- a/providers/provider_data.go +++ b/providers/provider_data.go @@ -37,6 +37,8 @@ type ProviderData struct { ClientSecret string ClientSecretFile string Scope string + // The response mode requested from the provider or empty for default ("query") + AuthRequestResponseMode string // The picked CodeChallenge Method or empty if none. CodeChallengeMethod string // Code challenge methods supported by the Provider diff --git a/providers/provider_default.go b/providers/provider_default.go index 756b5f69..1735ddd3 100644 --- a/providers/provider_default.go +++ b/providers/provider_default.go @@ -36,6 +36,11 @@ var ( // codeChallenge and codeChallengeMethod are the PKCE challenge and method to append to the URL params. // they will be empty strings if no code challenge should be presented func (p *ProviderData) GetLoginURL(redirectURI, state, _ string, extraParams url.Values) string { + // Response mode should only be set if a non default mode is requested + if p.AuthRequestResponseMode != "" { + extraParams.Add("response_mode", p.AuthRequestResponseMode) + } + loginURL := makeLoginURL(p, redirectURI, state, extraParams) return loginURL.String() } diff --git a/providers/provider_default_test.go b/providers/provider_default_test.go index 80d5b4ce..f678d13d 100644 --- a/providers/provider_default_test.go +++ b/providers/provider_default_test.go @@ -119,3 +119,30 @@ func TestProviderDataAuthorize(t *testing.T) { }) } } + +func TestResponseModeConfigured(t *testing.T) { + p := &ProviderData{ + LoginURL: &url.URL{ + Scheme: "http", + Host: "my.test.idp", + Path: "/oauth/authorize", + }, + AuthRequestResponseMode: "form_post", + } + + result := p.GetLoginURL("https://my.test.app/oauth", "", "", url.Values{}) + assert.Contains(t, result, "response_mode=form_post") +} + +func TestResponseModeNotConfigured(t *testing.T) { + p := &ProviderData{ + LoginURL: &url.URL{ + Scheme: "http", + Host: "my.test.idp", + Path: "/oauth/authorize", + }, + } + + result := p.GetLoginURL("https://my.test.app/oauth", "", "", url.Values{}) + assert.NotContains(t, result, "response_mode") +} diff --git a/providers/providers.go b/providers/providers.go index 1e2d4044..3a125a24 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -74,10 +74,11 @@ func NewProvider(providerConfig options.Provider) (Provider, error) { func newProviderDataFromConfig(providerConfig options.Provider) (*ProviderData, error) { p := &ProviderData{ - Scope: providerConfig.Scope, - ClientID: providerConfig.ClientID, - ClientSecret: providerConfig.ClientSecret, - ClientSecretFile: providerConfig.ClientSecretFile, + Scope: providerConfig.Scope, + ClientID: providerConfig.ClientID, + ClientSecret: providerConfig.ClientSecret, + ClientSecretFile: providerConfig.ClientSecretFile, + AuthRequestResponseMode: providerConfig.AuthRequestResponseMode, } needsVerifier, err := providerRequiresOIDCProviderVerifier(providerConfig.Type)