mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: remove refresh oauth logic on OIDC login (#8950)
* fix: do not do oauth refresh logic on oidc login
This commit is contained in:
+92
-3
@@ -9,6 +9,7 @@ import (
|
||||
"net/http/cookiejar"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/golang-jwt/jwt"
|
||||
@@ -24,12 +25,97 @@ import (
|
||||
"github.com/coder/coder/coderd/audit"
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/coderd/database"
|
||||
"github.com/coder/coder/coderd/database/dbauthz"
|
||||
"github.com/coder/coder/coderd/database/dbgen"
|
||||
"github.com/coder/coder/coderd/database/dbtestutil"
|
||||
"github.com/coder/coder/codersdk"
|
||||
"github.com/coder/coder/testutil"
|
||||
)
|
||||
|
||||
// This test specifically tests logging in with OIDC when an expired
|
||||
// OIDC session token exists.
|
||||
// The token refreshing should not happen since we are reauthenticating.
|
||||
func TestOIDCOauthLoginWithExisting(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
conf := coderdtest.NewOIDCConfig(t, "",
|
||||
// Provide a refresh token so we use the refresh token flow
|
||||
coderdtest.WithRefreshToken("refresh_token"),
|
||||
// We need to set the expire in the future for the first api calls.
|
||||
coderdtest.WithTokenExpires(func() time.Time {
|
||||
return time.Now().Add(time.Hour).UTC()
|
||||
}),
|
||||
// No refresh should actually happen in this test.
|
||||
coderdtest.WithTokenSource(func() (*oauth2.Token, error) {
|
||||
return nil, xerrors.New("token should not require refresh")
|
||||
}),
|
||||
)
|
||||
logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
|
||||
auditor := audit.NewMock()
|
||||
const username = "alice"
|
||||
claims := jwt.MapClaims{
|
||||
"email": "alice@coder.com",
|
||||
"email_verified": true,
|
||||
"preferred_username": username,
|
||||
}
|
||||
config := conf.OIDCConfig(t, claims)
|
||||
|
||||
config.AllowSignups = true
|
||||
config.IgnoreUserInfo = true
|
||||
client, _, api := coderdtest.NewWithAPI(t, &coderdtest.Options{
|
||||
Auditor: auditor,
|
||||
OIDCConfig: config,
|
||||
Logger: &logger,
|
||||
})
|
||||
|
||||
// Signup alice
|
||||
resp := oidcCallback(t, client, conf.EncodeClaims(t, claims))
|
||||
// Set the client to use this OIDC context
|
||||
authCookie := authCookieValue(resp.Cookies())
|
||||
client.SetSessionToken(authCookie)
|
||||
_ = resp.Body.Close()
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
// Verify the user and oauth link
|
||||
user, err := client.User(ctx, "me")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, username, user.Username)
|
||||
|
||||
// nolint:gocritic
|
||||
link, err := api.Database.GetUserLinkByUserIDLoginType(dbauthz.AsSystemRestricted(ctx), database.GetUserLinkByUserIDLoginTypeParams{
|
||||
UserID: user.ID,
|
||||
LoginType: database.LoginType(user.LoginType),
|
||||
})
|
||||
require.NoError(t, err, "failed to get user link")
|
||||
|
||||
// Expire the link
|
||||
// nolint:gocritic
|
||||
_, err = api.Database.UpdateUserLink(dbauthz.AsSystemRestricted(ctx), database.UpdateUserLinkParams{
|
||||
OAuthAccessToken: link.OAuthAccessToken,
|
||||
OAuthRefreshToken: link.OAuthRefreshToken,
|
||||
OAuthExpiry: time.Now().Add(time.Hour * -1).UTC(),
|
||||
UserID: link.UserID,
|
||||
LoginType: link.LoginType,
|
||||
})
|
||||
require.NoError(t, err, "failed to update user link")
|
||||
|
||||
// Log in again with OIDC
|
||||
loginAgain := oidcCallbackWithState(t, client, conf.EncodeClaims(t, claims), "seconds_login", func(req *http.Request) {
|
||||
req.AddCookie(&http.Cookie{
|
||||
Name: codersdk.SessionTokenCookie,
|
||||
Value: authCookie,
|
||||
Path: "/",
|
||||
})
|
||||
})
|
||||
require.Equal(t, http.StatusTemporaryRedirect, loginAgain.StatusCode)
|
||||
_ = loginAgain.Body.Close()
|
||||
|
||||
// Try to use new login
|
||||
client.SetSessionToken(authCookieValue(resp.Cookies()))
|
||||
_, err = client.User(ctx, "me")
|
||||
require.NoError(t, err, "use new session")
|
||||
}
|
||||
|
||||
func TestUserLogin(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
@@ -819,7 +905,7 @@ func TestUserOIDC(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
resp := oidcCallbackWithState(t, user, code, convertResponse.StateString)
|
||||
resp := oidcCallbackWithState(t, user, code, convertResponse.StateString, nil)
|
||||
require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
|
||||
})
|
||||
|
||||
@@ -1045,10 +1131,10 @@ func oauth2Callback(t *testing.T, client *codersdk.Client) *http.Response {
|
||||
}
|
||||
|
||||
func oidcCallback(t *testing.T, client *codersdk.Client, code string) *http.Response {
|
||||
return oidcCallbackWithState(t, client, code, "somestate")
|
||||
return oidcCallbackWithState(t, client, code, "somestate", nil)
|
||||
}
|
||||
|
||||
func oidcCallbackWithState(t *testing.T, client *codersdk.Client, code, state string) *http.Response {
|
||||
func oidcCallbackWithState(t *testing.T, client *codersdk.Client, code, state string, modify func(r *http.Request)) *http.Response {
|
||||
t.Helper()
|
||||
|
||||
client.HTTPClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||
@@ -1062,6 +1148,9 @@ func oidcCallbackWithState(t *testing.T, client *codersdk.Client, code, state st
|
||||
Name: codersdk.OAuth2StateCookie,
|
||||
Value: state,
|
||||
})
|
||||
if modify != nil {
|
||||
modify(req)
|
||||
}
|
||||
res, err := client.HTTPClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer res.Body.Close()
|
||||
|
||||
Reference in New Issue
Block a user