diff --git a/internal/oidc/auth/auth_handler.go b/internal/oidc/auth/auth_handler.go index ed6e1137..5ff4c1a9 100644 --- a/internal/oidc/auth/auth_handler.go +++ b/internal/oidc/auth/auth_handler.go @@ -30,6 +30,8 @@ import ( "go.pinniped.dev/pkg/oidcclient/pkce" ) +const promptParamNone = "none" + func NewHandler( downstreamIssuer string, idpLister oidc.UpstreamIdentityProvidersLister, @@ -220,15 +222,6 @@ func handleAuthRequestForOIDCUpstreamAuthcodeGrant( return err } - if csrfFromCookie == "" { - // We did not receive an incoming CSRF cookie, so write a new one. - err := addCSRFSetCookieHeader(w, csrfValue, cookieCodec) - if err != nil { - plog.Error("error setting CSRF cookie", err) - return err - } - } - authCodeOptions := []oauth2.AuthCodeOption{ oauth2.AccessTypeOffline, nonceValue.Param(), @@ -237,8 +230,17 @@ func handleAuthRequestForOIDCUpstreamAuthcodeGrant( } promptParam := r.Form.Get("prompt") - if promptParam != "" && oidc.ScopeWasRequested(authorizeRequester, coreosoidc.ScopeOpenID) { - authCodeOptions = append(authCodeOptions, oauth2.SetAuthURLParam("prompt", promptParam)) + if promptParam == promptParamNone && oidc.ScopeWasRequested(authorizeRequester, coreosoidc.ScopeOpenID) { + return writeAuthorizeError(w, oauthHelper, authorizeRequester, fosite.ErrLoginRequired) + } + + if csrfFromCookie == "" { + // We did not receive an incoming CSRF cookie, so write a new one. + err := addCSRFSetCookieHeader(w, csrfValue, cookieCodec) + if err != nil { + plog.Error("error setting CSRF cookie", err) + return err + } } http.Redirect(w, r, diff --git a/internal/oidc/auth/auth_handler_test.go b/internal/oidc/auth/auth_handler_test.go index c0198ee1..8762f9aa 100644 --- a/internal/oidc/auth/auth_handler_test.go +++ b/internal/oidc/auth/auth_handler_test.go @@ -181,6 +181,12 @@ func TestAuthorizationEndpoint(t *testing.T) { "error_description": "The resource owner or authorization server denied the request. Reason: required claim in upstream ID token has invalid format.", "state": happyState, } + + fositeLoginRequiredErrorQuery = map[string]string{ + "error": "login_required", + "error_description": "The Authorization Server requires End-User authentication.", + "state": happyState, + } ) hmacSecretFunc := func() []byte { return []byte("some secret - must have at least 32 bytes") } @@ -630,7 +636,7 @@ func TestAuthorizationEndpoint(t *testing.T) { wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod, }, { - name: "OIDC upstream browser flow happy path with prompt param login passed through to redirect uri", + name: "OIDC upstream browser flow happy path with prompt param other than none that gets ignored", idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()), generateCSRF: happyCSRFGenerator, generatePKCE: happyPKCEGenerator, @@ -645,9 +651,26 @@ func TestAuthorizationEndpoint(t *testing.T) { wantContentType: htmlContentType, wantBodyStringWithLocationInHref: true, wantCSRFValueInCookieHeader: happyCSRF, - wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(map[string]string{"prompt": "login"}, "", ""), "login"), + wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(map[string]string{"prompt": "login"}, "", ""), ""), wantUpstreamStateParamInLocationHeader: true, }, + { + name: "OIDC upstream browser flow with prompt param none throws an error because we want to independently decide the upstream prompt param", + idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()), + generateCSRF: happyCSRFGenerator, + generatePKCE: happyPKCEGenerator, + generateNonce: happyNonceGenerator, + stateEncoder: happyStateEncoder, + cookieEncoder: happyCookieEncoder, + method: http.MethodGet, + path: modifiedHappyGetRequestPath(map[string]string{"prompt": "none"}), + contentType: "application/x-www-form-urlencoded", + body: encodeQuery(happyGetRequestQueryMap), + wantStatus: http.StatusFound, + wantContentType: "application/json; charset=utf-8", + wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeLoginRequiredErrorQuery), + wantBodyString: "", + }, { name: "OIDC upstream browser flow with error while decoding CSRF cookie just generates a new cookie and succeeds as usual", idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),