From 0b0b03f365fcdf126f1fa6345f1f5133aee51939 Mon Sep 17 00:00:00 2001 From: Asher Date: Fri, 19 Jan 2024 11:54:17 -0900 Subject: [PATCH] chore: pass lifetime directly into api key generate Rather than passing all the deployment values. This is to make it easier to generate API keys as part of the oauth flow. I also added and fixed a test for when the lifetime is set and the default and expiration are unset. Co-authored-by: Steven Masley --- coderd/apikey.go | 22 ++--- coderd/apikey/apikey.go | 13 +-- coderd/apikey/apikey_test.go | 93 ++++++++++--------- .../provisionerdserver/provisionerdserver.go | 10 +- coderd/userauth.go | 16 ++-- coderd/workspaceapps.go | 12 +-- 6 files changed, 88 insertions(+), 78 deletions(-) diff --git a/coderd/apikey.go b/coderd/apikey.go index 02db2029d15db..b1d31ff613f65 100644 --- a/coderd/apikey.go +++ b/coderd/apikey.go @@ -82,13 +82,13 @@ func (api *API) postToken(rw http.ResponseWriter, r *http.Request) { } cookie, key, err := api.createAPIKey(ctx, apikey.CreateParams{ - UserID: user.ID, - LoginType: database.LoginTypeToken, - DeploymentValues: api.DeploymentValues, - ExpiresAt: dbtime.Now().Add(lifeTime), - Scope: scope, - LifetimeSeconds: int64(lifeTime.Seconds()), - TokenName: tokenName, + UserID: user.ID, + LoginType: database.LoginTypeToken, + DefaultLifetime: api.DeploymentValues.SessionDuration.Value(), + ExpiresAt: dbtime.Now().Add(lifeTime), + Scope: scope, + LifetimeSeconds: int64(lifeTime.Seconds()), + TokenName: tokenName, }) if err != nil { if database.IsUniqueViolation(err, database.UniqueIndexAPIKeyName) { @@ -127,10 +127,10 @@ func (api *API) postAPIKey(rw http.ResponseWriter, r *http.Request) { lifeTime := time.Hour * 24 * 7 cookie, _, err := api.createAPIKey(ctx, apikey.CreateParams{ - UserID: user.ID, - DeploymentValues: api.DeploymentValues, - LoginType: database.LoginTypePassword, - RemoteAddr: r.RemoteAddr, + UserID: user.ID, + DefaultLifetime: api.DeploymentValues.SessionDuration.Value(), + LoginType: database.LoginTypePassword, + RemoteAddr: r.RemoteAddr, // All api generated keys will last 1 week. Browser login tokens have // a shorter life. ExpiresAt: dbtime.Now().Add(lifeTime), diff --git a/coderd/apikey/apikey.go b/coderd/apikey/apikey.go index 3ae3c0d6e9bb8..ce6960dd53412 100644 --- a/coderd/apikey/apikey.go +++ b/coderd/apikey/apikey.go @@ -12,14 +12,15 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbtime" - "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/cryptorand" ) type CreateParams struct { - UserID uuid.UUID - LoginType database.LoginType - DeploymentValues *codersdk.DeploymentValues + UserID uuid.UUID + LoginType database.LoginType + // DefaultLifetime is configured in DeploymentValues. + // It is used if both ExpiresAt and LifetimeSeconds are not set. + DefaultLifetime time.Duration // Optional. ExpiresAt time.Time @@ -46,8 +47,8 @@ func Generate(params CreateParams) (database.InsertAPIKeyParams, string, error) if params.LifetimeSeconds != 0 { params.ExpiresAt = dbtime.Now().Add(time.Duration(params.LifetimeSeconds) * time.Second) } else { - params.ExpiresAt = dbtime.Now().Add(params.DeploymentValues.SessionDuration.Value()) - params.LifetimeSeconds = int64(params.DeploymentValues.SessionDuration.Value().Seconds()) + params.ExpiresAt = dbtime.Now().Add(params.DefaultLifetime) + params.LifetimeSeconds = int64(params.DefaultLifetime.Seconds()) } } if params.LifetimeSeconds == 0 { diff --git a/coderd/apikey/apikey_test.go b/coderd/apikey/apikey_test.go index b2d8a7768b76f..734a187219bf5 100644 --- a/coderd/apikey/apikey_test.go +++ b/coderd/apikey/apikey_test.go @@ -10,11 +10,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/coderd/apikey" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbtime" - "github.com/coder/coder/v2/codersdk" ) func TestGenerate(t *testing.T) { @@ -30,38 +28,36 @@ func TestGenerate(t *testing.T) { { name: "OK", params: apikey.CreateParams{ - UserID: uuid.New(), - LoginType: database.LoginTypeOIDC, - DeploymentValues: &codersdk.DeploymentValues{}, - ExpiresAt: time.Now().Add(time.Hour), - LifetimeSeconds: int64(time.Hour.Seconds()), - TokenName: "hello", - RemoteAddr: "1.2.3.4", - Scope: database.APIKeyScopeApplicationConnect, + UserID: uuid.New(), + LoginType: database.LoginTypeOIDC, + DefaultLifetime: time.Duration(0), + ExpiresAt: time.Now().Add(time.Hour), + LifetimeSeconds: int64(time.Hour.Seconds()), + TokenName: "hello", + RemoteAddr: "1.2.3.4", + Scope: database.APIKeyScopeApplicationConnect, }, }, { name: "InvalidScope", params: apikey.CreateParams{ - UserID: uuid.New(), - LoginType: database.LoginTypeOIDC, - DeploymentValues: &codersdk.DeploymentValues{}, - ExpiresAt: time.Now().Add(time.Hour), - LifetimeSeconds: int64(time.Hour.Seconds()), - TokenName: "hello", - RemoteAddr: "1.2.3.4", - Scope: database.APIKeyScope("test"), + UserID: uuid.New(), + LoginType: database.LoginTypeOIDC, + DefaultLifetime: time.Duration(0), + ExpiresAt: time.Now().Add(time.Hour), + LifetimeSeconds: int64(time.Hour.Seconds()), + TokenName: "hello", + RemoteAddr: "1.2.3.4", + Scope: database.APIKeyScope("test"), }, fail: true, }, { name: "DeploymentSessionDuration", params: apikey.CreateParams{ - UserID: uuid.New(), - LoginType: database.LoginTypeOIDC, - DeploymentValues: &codersdk.DeploymentValues{ - SessionDuration: clibase.Duration(time.Hour), - }, + UserID: uuid.New(), + LoginType: database.LoginTypeOIDC, + DefaultLifetime: time.Hour, LifetimeSeconds: 0, ExpiresAt: time.Time{}, TokenName: "hello", @@ -69,30 +65,43 @@ func TestGenerate(t *testing.T) { Scope: database.APIKeyScopeApplicationConnect, }, }, + { + name: "LifetimeSeconds", + params: apikey.CreateParams{ + UserID: uuid.New(), + LoginType: database.LoginTypeOIDC, + DefaultLifetime: time.Duration(0), + LifetimeSeconds: int64(time.Hour.Seconds()), + ExpiresAt: time.Time{}, + TokenName: "hello", + RemoteAddr: "1.2.3.4", + Scope: database.APIKeyScopeApplicationConnect, + }, + }, { name: "DefaultIP", params: apikey.CreateParams{ - UserID: uuid.New(), - LoginType: database.LoginTypeOIDC, - DeploymentValues: &codersdk.DeploymentValues{}, - ExpiresAt: time.Now().Add(time.Hour), - LifetimeSeconds: int64(time.Hour.Seconds()), - TokenName: "hello", - RemoteAddr: "", - Scope: database.APIKeyScopeApplicationConnect, + UserID: uuid.New(), + LoginType: database.LoginTypeOIDC, + DefaultLifetime: time.Duration(0), + ExpiresAt: time.Now().Add(time.Hour), + LifetimeSeconds: int64(time.Hour.Seconds()), + TokenName: "hello", + RemoteAddr: "", + Scope: database.APIKeyScopeApplicationConnect, }, }, { name: "DefaultScope", params: apikey.CreateParams{ - UserID: uuid.New(), - LoginType: database.LoginTypeOIDC, - DeploymentValues: &codersdk.DeploymentValues{}, - ExpiresAt: time.Now().Add(time.Hour), - LifetimeSeconds: int64(time.Hour.Seconds()), - TokenName: "hello", - RemoteAddr: "1.2.3.4", - Scope: "", + UserID: uuid.New(), + LoginType: database.LoginTypeOIDC, + DefaultLifetime: time.Duration(0), + ExpiresAt: time.Now().Add(time.Hour), + LifetimeSeconds: int64(time.Hour.Seconds()), + TokenName: "hello", + RemoteAddr: "1.2.3.4", + Scope: "", }, }, } @@ -131,15 +140,15 @@ func TestGenerate(t *testing.T) { // Should not be a delta greater than 5 seconds. assert.InDelta(t, time.Until(tc.params.ExpiresAt).Seconds(), key.LifetimeSeconds, 5) } else { - assert.Equal(t, int64(tc.params.DeploymentValues.SessionDuration.Value().Seconds()), key.LifetimeSeconds) + assert.Equal(t, int64(tc.params.DefaultLifetime.Seconds()), key.LifetimeSeconds) } if !tc.params.ExpiresAt.IsZero() { assert.Equal(t, tc.params.ExpiresAt.UTC(), key.ExpiresAt) } else if tc.params.LifetimeSeconds > 0 { - assert.WithinDuration(t, dbtime.Now().Add(time.Duration(tc.params.LifetimeSeconds)), key.ExpiresAt, time.Second*5) + assert.WithinDuration(t, dbtime.Now().Add(time.Duration(tc.params.LifetimeSeconds)*time.Second), key.ExpiresAt, time.Second*5) } else { - assert.WithinDuration(t, dbtime.Now().Add(tc.params.DeploymentValues.SessionDuration.Value()), key.ExpiresAt, time.Second*5) + assert.WithinDuration(t, dbtime.Now().Add(tc.params.DefaultLifetime), key.ExpiresAt, time.Second*5) } if tc.params.RemoteAddr != "" { diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index 0619e99f1cb76..9949e8dccf96e 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -1683,11 +1683,11 @@ func workspaceSessionTokenName(workspace database.Workspace) string { func (s *server) regenerateSessionToken(ctx context.Context, user database.User, workspace database.Workspace) (string, error) { newkey, sessionToken, err := apikey.Generate(apikey.CreateParams{ - UserID: user.ID, - LoginType: user.LoginType, - DeploymentValues: s.DeploymentValues, - TokenName: workspaceSessionTokenName(workspace), - LifetimeSeconds: int64(s.DeploymentValues.MaxTokenLifetime.Value().Seconds()), + UserID: user.ID, + LoginType: user.LoginType, + DefaultLifetime: s.DeploymentValues.SessionDuration.Value(), + TokenName: workspaceSessionTokenName(workspace), + LifetimeSeconds: int64(s.DeploymentValues.MaxTokenLifetime.Value().Seconds()), }) if err != nil { return "", xerrors.Errorf("generate API key: %w", err) diff --git a/coderd/userauth.go b/coderd/userauth.go index 4c160c883e6e1..e6819c3ffb721 100644 --- a/coderd/userauth.go +++ b/coderd/userauth.go @@ -247,10 +247,10 @@ func (api *API) postLogin(rw http.ResponseWriter, r *http.Request) { //nolint:gocritic // Creating the API key as the user instead of as system. cookie, key, err := api.createAPIKey(dbauthz.As(ctx, userSubj), apikey.CreateParams{ - UserID: user.ID, - LoginType: database.LoginTypePassword, - RemoteAddr: r.RemoteAddr, - DeploymentValues: api.DeploymentValues, + UserID: user.ID, + LoginType: database.LoginTypePassword, + RemoteAddr: r.RemoteAddr, + DefaultLifetime: api.DeploymentValues.SessionDuration.Value(), }) if err != nil { logger.Error(ctx, "unable to create API key", slog.Error(err)) @@ -1545,10 +1545,10 @@ func (api *API) oauthLogin(r *http.Request, params *oauthLoginParams) ([]*http.C } else { //nolint:gocritic cookie, newKey, err := api.createAPIKey(dbauthz.AsSystemRestricted(ctx), apikey.CreateParams{ - UserID: user.ID, - LoginType: params.LoginType, - DeploymentValues: api.DeploymentValues, - RemoteAddr: r.RemoteAddr, + UserID: user.ID, + LoginType: params.LoginType, + DefaultLifetime: api.DeploymentValues.SessionDuration.Value(), + RemoteAddr: r.RemoteAddr, }) if err != nil { return nil, database.APIKey{}, xerrors.Errorf("create API key: %w", err) diff --git a/coderd/workspaceapps.go b/coderd/workspaceapps.go index b519bc2a29028..d4a31e18224d3 100644 --- a/coderd/workspaceapps.go +++ b/coderd/workspaceapps.go @@ -107,12 +107,12 @@ func (api *API) workspaceApplicationAuth(rw http.ResponseWriter, r *http.Request lifetimeSeconds = int64(api.DeploymentValues.SessionDuration.Value().Seconds()) } cookie, _, err := api.createAPIKey(ctx, apikey.CreateParams{ - UserID: apiKey.UserID, - LoginType: database.LoginTypePassword, - DeploymentValues: api.DeploymentValues, - ExpiresAt: exp, - LifetimeSeconds: lifetimeSeconds, - Scope: database.APIKeyScopeApplicationConnect, + UserID: apiKey.UserID, + LoginType: database.LoginTypePassword, + DefaultLifetime: api.DeploymentValues.SessionDuration.Value(), + ExpiresAt: exp, + LifetimeSeconds: lifetimeSeconds, + Scope: database.APIKeyScopeApplicationConnect, }) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy