callback_handler.go: assert nonce is stored correctly

I think we want to do this here since we are storing all of the
other ID token claims?

Signed-off-by: Andrew Keesler <akeesler@vmware.com>
This commit is contained in:
Andrew Keesler 2020-11-20 08:38:23 -05:00
parent b25696a1fb
commit f8d76066c5
No known key found for this signature in database
GPG Key ID: 27CE0444346F9413
2 changed files with 17 additions and 6 deletions

View File

@ -97,7 +97,13 @@ func NewHandler(
return err return err
} }
openIDSession := makeDownstreamSession(downstreamIssuer, downstreamAuthParams.Get("client_id"), username, groups) openIDSession := makeDownstreamSession(
downstreamIssuer,
downstreamAuthParams.Get("client_id"),
downstreamAuthParams.Get("nonce"),
username,
groups,
)
authorizeResponder, err := oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, openIDSession) authorizeResponder, err := oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, openIDSession)
if err != nil { if err != nil {
plog.WarningErr("error while generating and saving authcode", err, "upstreamName", upstreamIDPConfig.GetName()) plog.WarningErr("error while generating and saving authcode", err, "upstreamName", upstreamIDPConfig.GetName())
@ -291,7 +297,7 @@ func getGroupsFromUpstreamIDToken(
return groups, nil return groups, nil
} }
func makeDownstreamSession(issuer, clientID, username string, groups []string) *openid.DefaultSession { func makeDownstreamSession(issuer, clientID, nonce, username string, groups []string) *openid.DefaultSession {
now := time.Now() now := time.Now()
openIDSession := &openid.DefaultSession{ openIDSession := &openid.DefaultSession{
Claims: &jwt.IDTokenClaims{ Claims: &jwt.IDTokenClaims{
@ -302,6 +308,7 @@ func makeDownstreamSession(issuer, clientID, username string, groups []string) *
IssuedAt: now, IssuedAt: now,
RequestedAt: now, RequestedAt: now,
AuthTime: now, AuthTime: now,
Nonce: nonce,
}, },
} }
if groups != nil { if groups != nil {

View File

@ -49,6 +49,7 @@ const (
happyUpstreamAuthcode = "upstream-auth-code" happyUpstreamAuthcode = "upstream-auth-code"
downstreamRedirectURI = "http://127.0.0.1/callback" downstreamRedirectURI = "http://127.0.0.1/callback"
downstreamClientID = "pinniped-cli" downstreamClientID = "pinniped-cli"
downstreamNonce = "some-nonce-value"
timeComparisonFudgeFactor = time.Second * 15 timeComparisonFudgeFactor = time.Second * 15
) )
@ -62,7 +63,7 @@ var (
"scope": []string{strings.Join(happyDownstreamScopesRequested, " ")}, "scope": []string{strings.Join(happyDownstreamScopesRequested, " ")},
"client_id": []string{downstreamClientID}, "client_id": []string{downstreamClientID},
"state": []string{happyDownstreamState}, "state": []string{happyDownstreamState},
"nonce": []string{"some-nonce-value"}, "nonce": []string{downstreamNonce},
"code_challenge": []string{"some-challenge"}, "code_challenge": []string{"some-challenge"},
"code_challenge_method": []string{"S256"}, "code_challenge_method": []string{"S256"},
"redirect_uri": []string{downstreamRedirectURI}, "redirect_uri": []string{downstreamRedirectURI},
@ -119,6 +120,7 @@ func TestCallbackEndpoint(t *testing.T) {
wantDownstreamIDTokenSubject string wantDownstreamIDTokenSubject string
wantDownstreamIDTokenGroups []string wantDownstreamIDTokenGroups []string
wantDownstreamRequestedScopes []string wantDownstreamRequestedScopes []string
wantDownstreamNonce string
wantExchangeAndValidateTokensCall *oidctestutil.ExchangeAuthcodeAndValidateTokenArgs wantExchangeAndValidateTokensCall *oidctestutil.ExchangeAuthcodeAndValidateTokenArgs
}{ }{
@ -135,6 +137,7 @@ func TestCallbackEndpoint(t *testing.T) {
wantDownstreamIDTokenSubject: upstreamUsername, wantDownstreamIDTokenSubject: upstreamUsername,
wantDownstreamIDTokenGroups: upstreamGroupMembership, wantDownstreamIDTokenGroups: upstreamGroupMembership,
wantDownstreamRequestedScopes: happyDownstreamScopesRequested, wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
wantDownstreamNonce: downstreamNonce,
wantExchangeAndValidateTokensCall: happyExchangeAndValidateTokensArgs, wantExchangeAndValidateTokensCall: happyExchangeAndValidateTokensArgs,
}, },
{ {
@ -150,6 +153,7 @@ func TestCallbackEndpoint(t *testing.T) {
wantDownstreamIDTokenSubject: upstreamIssuer + "?sub=" + upstreamSubject, wantDownstreamIDTokenSubject: upstreamIssuer + "?sub=" + upstreamSubject,
wantDownstreamIDTokenGroups: nil, wantDownstreamIDTokenGroups: nil,
wantDownstreamRequestedScopes: happyDownstreamScopesRequested, wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
wantDownstreamNonce: downstreamNonce,
wantExchangeAndValidateTokensCall: happyExchangeAndValidateTokensArgs, wantExchangeAndValidateTokensCall: happyExchangeAndValidateTokensArgs,
}, },
{ {
@ -165,6 +169,7 @@ func TestCallbackEndpoint(t *testing.T) {
wantDownstreamIDTokenSubject: upstreamSubject, wantDownstreamIDTokenSubject: upstreamSubject,
wantDownstreamIDTokenGroups: upstreamGroupMembership, wantDownstreamIDTokenGroups: upstreamGroupMembership,
wantDownstreamRequestedScopes: happyDownstreamScopesRequested, wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
wantDownstreamNonce: downstreamNonce,
wantExchangeAndValidateTokensCall: happyExchangeAndValidateTokensArgs, wantExchangeAndValidateTokensCall: happyExchangeAndValidateTokensArgs,
}, },
@ -287,6 +292,7 @@ func TestCallbackEndpoint(t *testing.T) {
wantDownstreamIDTokenSubject: upstreamUsername, wantDownstreamIDTokenSubject: upstreamUsername,
wantDownstreamRequestedScopes: []string{"profile", "email"}, wantDownstreamRequestedScopes: []string{"profile", "email"},
wantDownstreamIDTokenGroups: upstreamGroupMembership, wantDownstreamIDTokenGroups: upstreamGroupMembership,
wantDownstreamNonce: downstreamNonce,
wantExchangeAndValidateTokensCall: happyExchangeAndValidateTokensArgs, wantExchangeAndValidateTokensCall: happyExchangeAndValidateTokensArgs,
}, },
{ {
@ -507,6 +513,7 @@ func TestCallbackEndpoint(t *testing.T) {
// Check the rest of the downstream ID token's claims. // Check the rest of the downstream ID token's claims.
require.Equal(t, downstreamIssuer, actualClaims.Issuer) require.Equal(t, downstreamIssuer, actualClaims.Issuer)
require.Equal(t, []string{downstreamClientID}, actualClaims.Audience) require.Equal(t, []string{downstreamClientID}, actualClaims.Audience)
require.Equal(t, test.wantDownstreamNonce, actualClaims.Nonce)
testutil.RequireTimeInDelta(t, time.Now().Add(time.Minute*5), actualClaims.ExpiresAt, timeComparisonFudgeFactor) testutil.RequireTimeInDelta(t, time.Now().Add(time.Minute*5), actualClaims.ExpiresAt, timeComparisonFudgeFactor)
testutil.RequireTimeInDelta(t, time.Now(), actualClaims.IssuedAt, timeComparisonFudgeFactor) testutil.RequireTimeInDelta(t, time.Now(), actualClaims.IssuedAt, timeComparisonFudgeFactor)
testutil.RequireTimeInDelta(t, time.Now(), actualClaims.RequestedAt, timeComparisonFudgeFactor) testutil.RequireTimeInDelta(t, time.Now(), actualClaims.RequestedAt, timeComparisonFudgeFactor)
@ -519,9 +526,6 @@ func TestCallbackEndpoint(t *testing.T) {
require.Empty(t, actualClaims.AuthenticationContextClassReference) require.Empty(t, actualClaims.AuthenticationContextClassReference)
require.Empty(t, actualClaims.AuthenticationMethodsReference) require.Empty(t, actualClaims.AuthenticationMethodsReference)
// TODO we should put the downstream request's nonce into the ID token, but maybe the token endpoint is responsible for that?
require.Empty(t, actualClaims.Nonce)
// TODO add thorough tests about what should be stored for PKCES and IDSessions // TODO add thorough tests about what should be stored for PKCES and IDSessions
} else { } else {
require.Empty(t, rsp.Header().Values("Location")) require.Empty(t, rsp.Header().Values("Location"))