Pass prompt through to upstream login request
Signed-off-by: Ryan Richard <rrichard@vmware.com>
This commit is contained in:
parent
ded28dff15
commit
2a19dd0d2e
@ -121,13 +121,22 @@ func NewHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Redirect(w, r,
|
authCodeOptions := []oauth2.AuthCodeOption{
|
||||||
upstreamOAuthConfig.AuthCodeURL(
|
|
||||||
encodedStateParamValue,
|
|
||||||
oauth2.AccessTypeOffline,
|
oauth2.AccessTypeOffline,
|
||||||
nonceValue.Param(),
|
nonceValue.Param(),
|
||||||
pkceValue.Challenge(),
|
pkceValue.Challenge(),
|
||||||
pkceValue.Method(),
|
pkceValue.Method(),
|
||||||
|
}
|
||||||
|
|
||||||
|
promptParam := r.Form.Get("prompt")
|
||||||
|
if promptParam != "" && oidc.ScopeWasRequested(authorizeRequester, coreosoidc.ScopeOpenID) {
|
||||||
|
authCodeOptions = append(authCodeOptions, oauth2.SetAuthURLParam("prompt", promptParam))
|
||||||
|
}
|
||||||
|
|
||||||
|
http.Redirect(w, r,
|
||||||
|
upstreamOAuthConfig.AuthCodeURL(
|
||||||
|
encodedStateParamValue,
|
||||||
|
authCodeOptions...,
|
||||||
),
|
),
|
||||||
302,
|
302,
|
||||||
)
|
)
|
||||||
|
@ -57,8 +57,8 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
|
|
||||||
fositePromptHasNoneAndOtherValueErrorQuery = map[string]string{
|
fositePromptHasNoneAndOtherValueErrorQuery = map[string]string{
|
||||||
"error": "invalid_request",
|
"error": "invalid_request",
|
||||||
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed\n\nUsed unknown value \"[none login]\" for prompt parameter",
|
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed\n\nParameter \"prompt\" was set to \"none\", but contains other values as well which is not allowed.",
|
||||||
"error_hint": "Used unknown value \"[none login]\" for prompt parameter",
|
"error_hint": "Parameter \"prompt\" was set to \"none\", but contains other values as well which is not allowed.",
|
||||||
"state": "some-state-value-that-is-32-byte",
|
"state": "some-state-value-that-is-32-byte",
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,8 +99,8 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
|
|
||||||
fositeInvalidStateErrorQuery = map[string]string{
|
fositeInvalidStateErrorQuery = map[string]string{
|
||||||
"error": "invalid_state",
|
"error": "invalid_state",
|
||||||
"error_description": "The state is missing or does not have enough characters and is therefore considered too weak\n\nRequest parameter \"state\" must be at least be 32 characters long to ensure sufficient entropy.",
|
"error_description": "The state is missing or does not have enough characters and is therefore considered too weak\n\nRequest parameter \"state\" must be at least be 8 characters long to ensure sufficient entropy.",
|
||||||
"error_hint": `Request parameter "state" must be at least be 32 characters long to ensure sufficient entropy.`,
|
"error_hint": `Request parameter "state" must be at least be 8 characters long to ensure sufficient entropy.`,
|
||||||
"state": "short",
|
"state": "short",
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,8 +229,8 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
return encoded
|
return encoded
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedRedirectLocation := func(expectedUpstreamState string) string {
|
expectedRedirectLocation := func(expectedUpstreamState string, expectedPrompt string) string {
|
||||||
return urlWithQuery(upstreamAuthURL.String(), map[string]string{
|
query := map[string]string{
|
||||||
"response_type": "code",
|
"response_type": "code",
|
||||||
"access_type": "offline",
|
"access_type": "offline",
|
||||||
"scope": "scope1 scope2",
|
"scope": "scope1 scope2",
|
||||||
@ -240,7 +240,11 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
"code_challenge": expectedUpstreamCodeChallenge,
|
"code_challenge": expectedUpstreamCodeChallenge,
|
||||||
"code_challenge_method": "S256",
|
"code_challenge_method": "S256",
|
||||||
"redirect_uri": downstreamIssuer + "/callback",
|
"redirect_uri": downstreamIssuer + "/callback",
|
||||||
})
|
}
|
||||||
|
if expectedPrompt != "" {
|
||||||
|
query["prompt"] = expectedPrompt
|
||||||
|
}
|
||||||
|
return urlWithQuery(upstreamAuthURL.String(), query)
|
||||||
}
|
}
|
||||||
|
|
||||||
incomingCookieCSRFValue := "csrf-value-from-cookie"
|
incomingCookieCSRFValue := "csrf-value-from-cookie"
|
||||||
@ -288,7 +292,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantStatus: http.StatusFound,
|
wantStatus: http.StatusFound,
|
||||||
wantContentType: "text/html; charset=utf-8",
|
wantContentType: "text/html; charset=utf-8",
|
||||||
wantCSRFValueInCookieHeader: happyCSRF,
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(nil, "", "")),
|
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(nil, "", ""), ""),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
wantBodyStringWithLocationInHref: true,
|
wantBodyStringWithLocationInHref: true,
|
||||||
},
|
},
|
||||||
@ -306,7 +310,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
csrfCookie: "__Host-pinniped-csrf=" + encodedIncomingCookieCSRFValue + " ",
|
csrfCookie: "__Host-pinniped-csrf=" + encodedIncomingCookieCSRFValue + " ",
|
||||||
wantStatus: http.StatusFound,
|
wantStatus: http.StatusFound,
|
||||||
wantContentType: "text/html; charset=utf-8",
|
wantContentType: "text/html; charset=utf-8",
|
||||||
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(nil, incomingCookieCSRFValue, "")),
|
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(nil, incomingCookieCSRFValue, ""), ""),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
wantBodyStringWithLocationInHref: true,
|
wantBodyStringWithLocationInHref: true,
|
||||||
},
|
},
|
||||||
@ -327,7 +331,27 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantContentType: "",
|
wantContentType: "",
|
||||||
wantBodyString: "",
|
wantBodyString: "",
|
||||||
wantCSRFValueInCookieHeader: happyCSRF,
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(nil, "", "")),
|
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(nil, "", ""), ""),
|
||||||
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "happy path with prompt param login passed through to redirect uri",
|
||||||
|
issuer: downstreamIssuer,
|
||||||
|
idpListGetter: oidctestutil.NewIDPListGetter(&upstreamOIDCIdentityProvider),
|
||||||
|
generateCSRF: happyCSRFGenerator,
|
||||||
|
generatePKCE: happyPKCEGenerator,
|
||||||
|
generateNonce: happyNonceGenerator,
|
||||||
|
stateEncoder: happyStateEncoder,
|
||||||
|
cookieEncoder: happyCookieEncoder,
|
||||||
|
method: http.MethodGet,
|
||||||
|
path: modifiedHappyGetRequestPath(map[string]string{"prompt": "login"}),
|
||||||
|
contentType: "application/x-www-form-urlencoded",
|
||||||
|
body: encodeQuery(happyGetRequestQueryMap),
|
||||||
|
wantStatus: http.StatusFound,
|
||||||
|
wantContentType: "text/html; charset=utf-8",
|
||||||
|
wantBodyStringWithLocationInHref: true,
|
||||||
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
|
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(map[string]string{"prompt": "login"}, "", ""), "login"),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -346,7 +370,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantContentType: "text/html; charset=utf-8",
|
wantContentType: "text/html; charset=utf-8",
|
||||||
// Generated a new CSRF cookie and set it in the response.
|
// Generated a new CSRF cookie and set it in the response.
|
||||||
wantCSRFValueInCookieHeader: happyCSRF,
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(nil, "", "")),
|
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(nil, "", ""), ""),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
wantBodyStringWithLocationInHref: true,
|
wantBodyStringWithLocationInHref: true,
|
||||||
},
|
},
|
||||||
@ -368,7 +392,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantCSRFValueInCookieHeader: happyCSRF,
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(map[string]string{
|
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(map[string]string{
|
||||||
"redirect_uri": downstreamRedirectURIWithDifferentPort, // not the same port number that is registered for the client
|
"redirect_uri": downstreamRedirectURIWithDifferentPort, // not the same port number that is registered for the client
|
||||||
}, "", "")),
|
}, "", ""), ""),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
wantBodyStringWithLocationInHref: true,
|
wantBodyStringWithLocationInHref: true,
|
||||||
},
|
},
|
||||||
@ -388,7 +412,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantCSRFValueInCookieHeader: happyCSRF,
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(map[string]string{
|
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(map[string]string{
|
||||||
"scope": "openid offline_access",
|
"scope": "openid offline_access",
|
||||||
}, "", "")),
|
}, "", ""), ""),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
wantBodyStringWithLocationInHref: true,
|
wantBodyStringWithLocationInHref: true,
|
||||||
},
|
},
|
||||||
@ -586,7 +610,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantCSRFValueInCookieHeader: happyCSRF,
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(
|
wantLocationHeader: expectedRedirectLocation(expectedUpstreamStateParam(
|
||||||
map[string]string{"prompt": "none login", "scope": "email"}, "", "",
|
map[string]string{"prompt": "none login", "scope": "email"}, "", "",
|
||||||
)),
|
), ""),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
wantBodyStringWithLocationInHref: true,
|
wantBodyStringWithLocationInHref: true,
|
||||||
},
|
},
|
||||||
|
@ -259,9 +259,16 @@ type IDPListGetter interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GrantScopeIfRequested(authorizeRequester fosite.AuthorizeRequester, scopeName string) {
|
func GrantScopeIfRequested(authorizeRequester fosite.AuthorizeRequester, scopeName string) {
|
||||||
for _, scope := range authorizeRequester.GetRequestedScopes() {
|
if ScopeWasRequested(authorizeRequester, scopeName) {
|
||||||
if scope == scopeName {
|
authorizeRequester.GrantScope(scopeName)
|
||||||
authorizeRequester.GrantScope(scope)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ScopeWasRequested(authorizeRequester fosite.AuthorizeRequester, scopeName string) bool {
|
||||||
|
for _, scope := range authorizeRequester.GetRequestedScopes() {
|
||||||
|
if scope == scopeName {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user