feat: add session expiry control flags (#5976)

Adds --session-duration which lets admins customize the default session
expiration for browser sessions.

Adds --disable-session-expiry-refresh which allows admins to prevent
session expiry from being automatically bumped upon the API key being
used.
This commit is contained in:
Dean Sheather
2023-02-04 04:38:36 +11:00
committed by GitHub
parent 2285a5e8a0
commit cf9abe3a6c
16 changed files with 225 additions and 37 deletions

View File

@ -2,12 +2,17 @@ package coderd_test
import (
"context"
"net/http"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/database/dbtestutil"
"github.com/coder/coder/codersdk"
"github.com/coder/coder/testutil"
)
@ -109,6 +114,58 @@ func TestTokenMaxLifetime(t *testing.T) {
require.ErrorContains(t, err, "lifetime must be less")
}
func TestSessionExpiry(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
dc := coderdtest.DeploymentConfig(t)
db, pubsub := dbtestutil.NewDB(t)
adminClient := coderdtest.New(t, &coderdtest.Options{
DeploymentConfig: dc,
Database: db,
Pubsub: pubsub,
})
adminUser := coderdtest.CreateFirstUser(t, adminClient)
// This is a hack, but we need the admin account to have a long expiry
// otherwise the test will flake, so we only update the expiry config after
// the admin account has been created.
//
// We don't support updating the deployment config after startup, but for
// this test it works because we don't copy the value (and we use pointers).
dc.SessionDuration.Value = time.Second
userClient := coderdtest.CreateAnotherUser(t, adminClient, adminUser.OrganizationID)
// Find the session cookie, and ensure it has the correct expiry.
token := userClient.SessionToken()
apiKey, err := db.GetAPIKeyByID(ctx, strings.Split(token, "-")[0])
require.NoError(t, err)
require.EqualValues(t, dc.SessionDuration.Value.Seconds(), apiKey.LifetimeSeconds)
require.WithinDuration(t, apiKey.CreatedAt.Add(dc.SessionDuration.Value), apiKey.ExpiresAt, 2*time.Second)
// Update the session token to be expired so we can test that it is
// rejected for extra points.
err = db.UpdateAPIKeyByID(ctx, database.UpdateAPIKeyByIDParams{
ID: apiKey.ID,
LastUsed: apiKey.LastUsed,
ExpiresAt: database.Now().Add(-time.Hour),
IPAddress: apiKey.IPAddress,
})
require.NoError(t, err)
_, err = userClient.User(ctx, codersdk.Me)
require.Error(t, err)
var sdkErr *codersdk.Error
if assert.ErrorAs(t, err, &sdkErr) {
require.Equal(t, http.StatusUnauthorized, sdkErr.StatusCode())
require.Contains(t, sdkErr.Message, "session has expired")
}
}
func TestAPIKey(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)