Skip to content

Commit a5ac710

Browse files
committed
Add unit test for expired refresh tokens used in refresh flow
1 parent 5246ff9 commit a5ac710

File tree

1 file changed

+63
-10
lines changed

1 file changed

+63
-10
lines changed

internal/oidc/token/token_handler_test.go

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ func TestTokenEndpointTokenExchange(t *testing.T) { // tests for grant_type "urn
747747
require.Len(t, parts, 2)
748748
// Find the storage Secret for the access token by using its signature to compute the Secret name.
749749
accessTokenSignature := parts[1]
750-
accessTokenSecretName := getSecretNameFromSignature(t, accessTokenSignature, "access-token")
750+
accessTokenSecretName := getSecretNameFromSignature(t, accessTokenSignature, "access-token") // "access-token" is the storage type used in the Secret's name
751751
accessTokenSecret, err := secrets.Get(context.Background(), accessTokenSecretName, metav1.GetOptions{})
752752
require.NoError(t, err)
753753
// Parse the session from the storage Secret.
@@ -1143,7 +1143,7 @@ func TestRefreshGrant(t *testing.T) {
11431143
idps *oidctestutil.UpstreamIDPListerBuilder
11441144
authcodeExchange authcodeExchangeInputs
11451145
refreshRequest refreshRequestInputs
1146-
modifyRefreshTokenStorage func(t *testing.T, oauthStore *oidc.KubeStorage, refreshToken string)
1146+
modifyRefreshTokenStorage func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string)
11471147
}{
11481148
{
11491149
name: "happy path refresh grant with openid scope granted (id token returned)",
@@ -1595,6 +1595,59 @@ func TestRefreshGrant(t *testing.T) {
15951595
),
15961596
},
15971597
},
1598+
{
1599+
name: "when a valid refresh token is sent in the refresh request, but the token has already expired",
1600+
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
1601+
authcodeExchange: authcodeExchangeInputs{
1602+
customSessionData: initialUpstreamOIDCRefreshTokenCustomSessionData(),
1603+
modifyAuthRequest: func(r *http.Request) { r.Form.Set("scope", "openid offline_access") },
1604+
want: happyAuthcodeExchangeTokenResponseForOpenIDAndOfflineAccess(initialUpstreamOIDCRefreshTokenCustomSessionData()),
1605+
},
1606+
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
1607+
// The fosite storage APIs don't offer a way to update a refresh token, so we will instead find the underlying
1608+
// storage Secret and update it in a more manual way. First get the refresh token's signature.
1609+
refreshTokenSignature := getFositeDataSignature(t, refreshToken)
1610+
// Find the storage Secret for the refresh token by using its signature to compute the Secret name.
1611+
refreshTokenSecretName := getSecretNameFromSignature(t, refreshTokenSignature, "refresh-token") // "refresh-token" is the storage type used in the Secret's name
1612+
refreshTokenSecret, err := secrets.Get(context.Background(), refreshTokenSecretName, metav1.GetOptions{})
1613+
require.NoError(t, err)
1614+
// Parse the session from the storage Secret.
1615+
savedSessionJSON := refreshTokenSecret.Data["pinniped-storage-data"]
1616+
// Declare the appropriate empty struct, similar to how our kubestorage implementation
1617+
// of GetRefreshTokenSession() does when parsing a session from a storage Secret.
1618+
refreshTokenSession := &refreshtoken.Session{
1619+
Request: &fosite.Request{
1620+
Client: &clientregistry.Client{},
1621+
Session: &psession.PinnipedSession{},
1622+
},
1623+
}
1624+
// Parse the session JSON and fill the empty struct with its data.
1625+
err = json.Unmarshal(savedSessionJSON, refreshTokenSession)
1626+
require.NoError(t, err)
1627+
// Change the refresh token's expiration time to be one hour ago, so it will be considered already expired.
1628+
oneHourAgoInUTC := time.Now().UTC().Add(-1 * time.Hour)
1629+
refreshTokenSession.Request.Session.(*psession.PinnipedSession).Fosite.SetExpiresAt(fosite.RefreshToken, oneHourAgoInUTC)
1630+
// Write the updated session back to the refresh token's storage Secret.
1631+
updatedSessionJSON, err := json.Marshal(refreshTokenSession)
1632+
require.NoError(t, err)
1633+
refreshTokenSecret.Data["pinniped-storage-data"] = updatedSessionJSON
1634+
_, err = secrets.Update(context.Background(), refreshTokenSecret, metav1.UpdateOptions{})
1635+
require.NoError(t, err)
1636+
// Just to be sure that this test setup is valid, confirm that the code above correctly updated the
1637+
// refresh token's expiration time by reading it again, this time performing the read using the
1638+
// kubestorage API instead of the manual/direct approach used above.
1639+
session, err := oauthStore.GetRefreshTokenSession(context.Background(), refreshTokenSignature, nil)
1640+
require.NoError(t, err)
1641+
expiresAt := session.GetSession().GetExpiresAt(fosite.RefreshToken)
1642+
require.Equal(t, oneHourAgoInUTC, expiresAt)
1643+
},
1644+
refreshRequest: refreshRequestInputs{
1645+
want: tokenEndpointResponseExpectedValues{
1646+
wantStatus: http.StatusBadRequest,
1647+
wantErrorResponseBody: fositeInvalidAuthCodeErrorBody,
1648+
},
1649+
},
1650+
},
15981651
{
15991652
name: "when a bad refresh token is sent in the refresh request",
16001653
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
@@ -2393,7 +2446,7 @@ func TestRefreshGrant(t *testing.T) {
23932446
happyLDAPCustomSessionData,
23942447
),
23952448
},
2396-
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, refreshToken string) {
2449+
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
23972450
refreshTokenSignature := getFositeDataSignature(t, refreshToken)
23982451
firstRequester, err := oauthStore.GetRefreshTokenSession(context.Background(), refreshTokenSignature, nil)
23992452
require.NoError(t, err)
@@ -2431,7 +2484,7 @@ func TestRefreshGrant(t *testing.T) {
24312484
happyLDAPCustomSessionData,
24322485
),
24332486
},
2434-
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, refreshToken string) {
2487+
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
24352488
refreshTokenSignature := getFositeDataSignature(t, refreshToken)
24362489
firstRequester, err := oauthStore.GetRefreshTokenSession(context.Background(), refreshTokenSignature, nil)
24372490
require.NoError(t, err)
@@ -2473,7 +2526,7 @@ func TestRefreshGrant(t *testing.T) {
24732526
happyLDAPCustomSessionData,
24742527
),
24752528
},
2476-
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, refreshToken string) {
2529+
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
24772530
refreshTokenSignature := getFositeDataSignature(t, refreshToken)
24782531
firstRequester, err := oauthStore.GetRefreshTokenSession(context.Background(), refreshTokenSignature, nil)
24792532
require.NoError(t, err)
@@ -2515,7 +2568,7 @@ func TestRefreshGrant(t *testing.T) {
25152568
happyLDAPCustomSessionData,
25162569
),
25172570
},
2518-
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, refreshToken string) {
2571+
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
25192572
refreshTokenSignature := getFositeDataSignature(t, refreshToken)
25202573
firstRequester, err := oauthStore.GetRefreshTokenSession(context.Background(), refreshTokenSignature, nil)
25212574
require.NoError(t, err)
@@ -2652,7 +2705,7 @@ func TestRefreshGrant(t *testing.T) {
26522705
happyLDAPCustomSessionData,
26532706
),
26542707
},
2655-
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, refreshToken string) {
2708+
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
26562709
refreshTokenSignature := getFositeDataSignature(t, refreshToken)
26572710
firstRequester, err := oauthStore.GetRefreshTokenSession(context.Background(), refreshTokenSignature, nil)
26582711
require.NoError(t, err)
@@ -2689,7 +2742,7 @@ func TestRefreshGrant(t *testing.T) {
26892742
happyLDAPCustomSessionData,
26902743
),
26912744
},
2692-
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, refreshToken string) {
2745+
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
26932746
refreshTokenSignature := getFositeDataSignature(t, refreshToken)
26942747
firstRequester, err := oauthStore.GetRefreshTokenSession(context.Background(), refreshTokenSignature, nil)
26952748
require.NoError(t, err)
@@ -2730,7 +2783,7 @@ func TestRefreshGrant(t *testing.T) {
27302783
happyLDAPCustomSessionData,
27312784
),
27322785
},
2733-
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, refreshToken string) {
2786+
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
27342787
refreshTokenSignature := getFositeDataSignature(t, refreshToken)
27352788
firstRequester, err := oauthStore.GetRefreshTokenSession(context.Background(), refreshTokenSignature, nil)
27362789
require.NoError(t, err)
@@ -2836,7 +2889,7 @@ func TestRefreshGrant(t *testing.T) {
28362889
require.NotEmpty(t, firstRefreshToken)
28372890

28382891
if test.modifyRefreshTokenStorage != nil {
2839-
test.modifyRefreshTokenStorage(t, oauthStore, firstRefreshToken)
2892+
test.modifyRefreshTokenStorage(t, oauthStore, secrets, firstRefreshToken)
28402893
}
28412894
reqContext := context.WithValue(context.Background(), struct{ name string }{name: "test"}, "request-context")
28422895
req := httptest.NewRequest("POST", "/path/shouldn't/matter",

0 commit comments

Comments
 (0)