diff --git a/config.go b/config.go index cd4410afb2da5c25c3b7c28bd4088ad521d5f528..d49d4bdb957ade9609cf087a90d1340381cbddc1 100644 --- a/config.go +++ b/config.go @@ -35,6 +35,7 @@ func newDefaultConfig() *Config { return &Config{ AccessTokenDuration: time.Duration(720) * time.Hour, + ClientAuthMethod: authMethodBasic, CookieAccessName: accessCookie, CookieRefreshName: refreshCookie, EnableAuthorizationCookies: true, @@ -189,6 +190,9 @@ func (r *Config) isValid() error { return fmt.Errorf("the store url is invalid, error: %s", err) } } + if r.ClientAuthMethod != authMethodBasic && r.ClientAuthMethod != authMethodBody { + return fmt.Errorf("invalid client auth method %q (valid values: %s, %s)", r.ClientAuthMethod, authMethodBasic, authMethodBody) + } } // check: ensure each of the resource are valid for _, resource := range r.Resources { diff --git a/config_test.go b/config_test.go index 523429183340a33604aeabdeca4a7a9640ad412e..8f6064da703b39a0be14199792695b311bf0bfc8 100644 --- a/config_test.go +++ b/config_test.go @@ -35,39 +35,44 @@ func TestIsConfig(t *testing.T) { }, { Config: &Config{ - DiscoveryURL: "http://127.0.0.1:8080", + DiscoveryURL: "http://127.0.0.1:8080", + ClientAuthMethod: "secret-basic", }, }, { Config: &Config{ - DiscoveryURL: "http://127.0.0.1:8080", - ClientID: "client", - ClientSecret: "client", + DiscoveryURL: "http://127.0.0.1:8080", + ClientAuthMethod: "secret-basic", + ClientID: "client", + ClientSecret: "client", }, }, { Config: &Config{ - Listen: ":8080", - DiscoveryURL: "http://127.0.0.1:8080", - ClientID: "client", - ClientSecret: "client", - RedirectionURL: "http://120.0.0.1", + Listen: ":8080", + DiscoveryURL: "http://127.0.0.1:8080", + ClientAuthMethod: "secret-basic", + ClientID: "client", + ClientSecret: "client", + RedirectionURL: "http://120.0.0.1", }, }, { Config: &Config{ - Listen: ":8080", - DiscoveryURL: "http://127.0.0.1:8080", - ClientID: "client", - ClientSecret: "client", - RedirectionURL: "http://120.0.0.1", - Upstream: "http://120.0.0.1", + Listen: ":8080", + DiscoveryURL: "http://127.0.0.1:8080", + ClientAuthMethod: "secret-basic", + ClientID: "client", + ClientSecret: "client", + RedirectionURL: "http://120.0.0.1", + Upstream: "http://120.0.0.1", }, }, { Config: &Config{ Listen: ":8080", DiscoveryURL: "http://127.0.0.1:8080", + ClientAuthMethod: "secret-basic", ClientID: "client", ClientSecret: "client", RedirectionURL: "http://120.0.0.1", @@ -81,6 +86,7 @@ func TestIsConfig(t *testing.T) { Config: &Config{ Listen: ":8080", DiscoveryURL: "http://127.0.0.1:8080", + ClientAuthMethod: "secret-basic", ClientID: "client", ClientSecret: "client", RedirectionURL: "http://120.0.0.1", @@ -93,6 +99,7 @@ func TestIsConfig(t *testing.T) { Config: &Config{ Listen: ":8080", DiscoveryURL: "http://127.0.0.1:8080", + ClientAuthMethod: "secret-basic", ClientID: "client", ClientSecret: "client", RedirectionURL: "http://120.0.0.1", @@ -103,12 +110,13 @@ func TestIsConfig(t *testing.T) { }, { Config: &Config{ - Listen: ":8080", - DiscoveryURL: "http://127.0.0.1:8080", - ClientID: "client", - ClientSecret: "client", - RedirectionURL: "http://120.0.0.1", - Upstream: "http://120.0.0.1", + Listen: ":8080", + DiscoveryURL: "http://127.0.0.1:8080", + ClientAuthMethod: "secret-basic", + ClientID: "client", + ClientSecret: "client", + RedirectionURL: "http://120.0.0.1", + Upstream: "http://120.0.0.1", MatchClaims: map[string]string{ "test": "&&&[", }, @@ -129,6 +137,7 @@ func TestIsConfig(t *testing.T) { { Config: &Config{ DiscoveryURL: "http://127.0.0.1:8080", + ClientAuthMethod: "secret-basic", ClientID: "client", ClientSecret: "client", RedirectionURL: "http://120.0.0.1", @@ -141,6 +150,7 @@ func TestIsConfig(t *testing.T) { Config: &Config{ Listen: ":8080", DiscoveryURL: "http://127.0.0.1:8080", + ClientAuthMethod: "secret-basic", ClientID: "client", ClientSecret: "client", RedirectionURL: "http://120.0.0.1", @@ -152,6 +162,7 @@ func TestIsConfig(t *testing.T) { Config: &Config{ Listen: ":8080", DiscoveryURL: "http://127.0.0.1:8080", + ClientAuthMethod: "secret-basic", ClientID: "client", ClientSecret: "client", RedirectionURL: "http://120.0.0.1", @@ -164,6 +175,7 @@ func TestIsConfig(t *testing.T) { Config: &Config{ Listen: ":8080", DiscoveryURL: "http://127.0.0.1:8080", + ClientAuthMethod: "secret-basic", ClientID: "client", ClientSecret: "client", RedirectionURL: "http://120.0.0.1", @@ -177,6 +189,7 @@ func TestIsConfig(t *testing.T) { Config: &Config{ Listen: ":8080", DiscoveryURL: "http://127.0.0.1:8080", + ClientAuthMethod: "secret-basic", ClientID: "client", ClientSecret: "client", RedirectionURL: "https://120.0.0.1", diff --git a/doc.go b/doc.go index 0b11c4b8dcdaedccc7b0ccf478d5d8cc8c433296..cfa461d43099ed7bcac2a75bc938c2f406cd5a6b 100644 --- a/doc.go +++ b/doc.go @@ -70,6 +70,8 @@ const ( unsecureScheme = "http" secureScheme = "https" anyMethod = "ANY" + authMethodBasic = "secret-basic" + authMethodBody = "secret-body" _ contextKey = iota contextScopeName @@ -248,6 +250,8 @@ type Config struct { // AccessTokenDuration is default duration applied to the access token cookie AccessTokenDuration time.Duration `json:"access-token-duration" yaml:"access-token-duration" usage:"fallback cookie duration for the access token when using refresh tokens"` + // ClientAuthMethod defines the method for authenticating the oauth client to the server + ClientAuthMethod string `json:"client-auth-method" yaml:"client-auth-method" usage:"the auth method to use with oauth (secret-basic, secret-body)" env:"CLIENT_AUTH_METHOD"` // CookieDomain is a list of domains the cookie is available to CookieDomain string `json:"cookie-domain" yaml:"cookie-domain" usage:"domain the access cookie is available to, defaults host header"` // CookieAccessName is the name of the access cookie holding the access token diff --git a/handlers.go b/handlers.go index 0c5520ecef54b1179c1aaff135ba3eeba8041637..a635b56a1011130358746aa8a629ee857a70a767 100644 --- a/handlers.go +++ b/handlers.go @@ -71,7 +71,7 @@ func (r *oauthProxy) oauthAuthorizationHandler(w http.ResponseWriter, req *http. w.WriteHeader(http.StatusNotAcceptable) return } - client, err := r.getOAuthClient(r.getRedirectionURL(w, req)) + client, err := r.getOAuthClient(r.getRedirectionURL(w, req), getClientAuthMethod(r.config.ClientAuthMethod)) if err != nil { r.log.Error("failed to retrieve the oauth client for authorization", zap.Error(err)) w.WriteHeader(http.StatusInternalServerError) @@ -103,6 +103,18 @@ func (r *oauthProxy) oauthAuthorizationHandler(w http.ResponseWriter, req *http. r.redirectToURL(authURL, w, req, http.StatusTemporaryRedirect) } +// getClientAuthMethod maps the config value CLIENT_AUTH_METHOD to valid OAuth2 auth method keys +func getClientAuthMethod(authMethod string) string { + switch authMethod { + case authMethodBasic: + return oauth2.AuthMethodClientSecretBasic + case authMethodBody: + return oauth2.AuthMethodClientSecretPost + default: + return "" + } +} + // oauthCallbackHandler is responsible for handling the response from oauth service func (r *oauthProxy) oauthCallbackHandler(w http.ResponseWriter, req *http.Request) { if r.config.SkipTokenVerification { @@ -116,7 +128,7 @@ func (r *oauthProxy) oauthCallbackHandler(w http.ResponseWriter, req *http.Reque return } - client, err := r.getOAuthClient(r.getRedirectionURL(w, req)) + client, err := r.getOAuthClient(r.getRedirectionURL(w, req), getClientAuthMethod(r.config.ClientAuthMethod)) if err != nil { r.log.Error("unable to create a oauth2 client", zap.Error(err)) w.WriteHeader(http.StatusInternalServerError) diff --git a/oauth.go b/oauth.go index 4261b1b626952b0957a1642b07cba2bab67001a9..5e1a53b651ff14bba2473b2a20f8451f049cd23c 100644 --- a/oauth.go +++ b/oauth.go @@ -30,13 +30,13 @@ import ( ) // getOAuthClient returns a oauth2 client from the openid client -func (r *oauthProxy) getOAuthClient(redirectionURL string) (*oauth2.Client, error) { +func (r *oauthProxy) getOAuthClient(redirectionURL string, clientAuthMethod string) (*oauth2.Client, error) { return oauth2.NewClient(r.idpClient, oauth2.Config{ Credentials: oauth2.ClientCredentials{ ID: r.config.ClientID, Secret: r.config.ClientSecret, }, - AuthMethod: oauth2.AuthMethodClientSecretBasic, + AuthMethod: clientAuthMethod, AuthURL: r.idp.AuthEndpoint.String(), RedirectURL: redirectionURL, Scope: append(r.config.Scopes, oidc.DefaultScope...),