Skip to content

feat: failed update refresh should redirect to login #9442

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 30, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add unit test to verify 401 on expired refresh
  • Loading branch information
Emyrk committed Aug 30, 2023
commit a04fd7b0ab6ebd8d4fdfd73ff984d52c690c73f8
52 changes: 46 additions & 6 deletions enterprise/coderd/userauth_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package coderd_test

import (
"context"
"net/http"
"regexp"
"testing"

"github.com/golang-jwt/jwt/v4"
"github.com/stretchr/testify/require"
"golang.org/x/xerrors"

"github.com/coder/coder/v2/coderd"
"github.com/coder/coder/v2/coderd/coderdtest"
Expand Down Expand Up @@ -357,6 +359,37 @@ func TestUserOIDC(t *testing.T) {
runner.ForceRefresh(t, client, claims)
}
})

t.Run("FailedRefresh", func(t *testing.T) {
t.Parallel()

runner := setupOIDCTest(t, oidcTestConfig{
FakeOpts: []oidctest.FakeIDPOpt{
oidctest.WithRefreshHook(func(_ string) error {
// Always "expired" refresh token.
return xerrors.New("refresh token is expired")
}),
},
Config: func(cfg *coderd.OIDCConfig) {
cfg.AllowSignups = true
cfg.UserRoleField = "roles"
},
})

claims := jwt.MapClaims{
"email": "alice@coder.com",
}
// Login a new client that signs up
client, resp := runner.Login(t, claims)
require.Equal(t, http.StatusOK, resp.StatusCode)

runner.ExpireOauthToken(t, client)
_, err := client.User(context.Background(), codersdk.Me)
require.Error(t, err)
var apiError *codersdk.Error
require.ErrorAs(t, err, &apiError)
require.Equal(t, http.StatusUnauthorized, apiError.StatusCode())
})
})
}

Expand Down Expand Up @@ -576,14 +609,16 @@ type oidcTestRunner struct {
// ForceRefresh will use an authenticated codersdk.Client, and force their
// OIDC token to be expired and require a refresh. The refresh will use the claims provided.
// It just calls the /users/me endpoint to trigger the refresh.
ForceRefresh func(t *testing.T, client *codersdk.Client, idToken jwt.MapClaims)
ForceRefresh func(t *testing.T, client *codersdk.Client, idToken jwt.MapClaims)
ExpireOauthToken func(t *testing.T, client *codersdk.Client)
}

type oidcTestConfig struct {
Userinfo jwt.MapClaims

// Config allows modifying the Coderd OIDC configuration.
Config func(cfg *coderd.OIDCConfig)
Config func(cfg *coderd.OIDCConfig)
FakeOpts []oidctest.FakeIDPOpt
}

func (r *oidcTestRunner) AssertRoles(t *testing.T, userIdent string, roles []string) {
Expand Down Expand Up @@ -633,10 +668,12 @@ func setupOIDCTest(t *testing.T, settings oidcTestConfig) *oidcTestRunner {
t.Helper()

fake := oidctest.NewFakeIDP(t,
oidctest.WithStaticUserInfo(settings.Userinfo),
oidctest.WithLogging(t, nil),
// Run fake IDP on a real webserver
oidctest.WithServing(),
append([]oidctest.FakeIDPOpt{
oidctest.WithStaticUserInfo(settings.Userinfo),
oidctest.WithLogging(t, nil),
// Run fake IDP on a real webserver
oidctest.WithServing(),
}, settings.FakeOpts...)...,
)

ctx := testutil.Context(t, testutil.WaitMedium)
Expand Down Expand Up @@ -665,5 +702,8 @@ func setupOIDCTest(t *testing.T, settings oidcTestConfig) *oidcTestRunner {
ForceRefresh: func(t *testing.T, client *codersdk.Client, idToken jwt.MapClaims) {
helper.ForceRefresh(t, api.Database, client, idToken)
},
ExpireOauthToken: func(t *testing.T, client *codersdk.Client) {
helper.ExpireOauthToken(t, api.Database, client)
},
}
}