Skip to content

Commit 5596f95

Browse files
code-asherEmyrk
andcommitted
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 <stevenmasley@gmail.com>
1 parent 76911f1 commit 5596f95

File tree

6 files changed

+88
-78
lines changed

6 files changed

+88
-78
lines changed

coderd/apikey.go

+11-11
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,13 @@ func (api *API) postToken(rw http.ResponseWriter, r *http.Request) {
8282
}
8383

8484
cookie, key, err := api.createAPIKey(ctx, apikey.CreateParams{
85-
UserID: user.ID,
86-
LoginType: database.LoginTypeToken,
87-
DeploymentValues: api.DeploymentValues,
88-
ExpiresAt: dbtime.Now().Add(lifeTime),
89-
Scope: scope,
90-
LifetimeSeconds: int64(lifeTime.Seconds()),
91-
TokenName: tokenName,
85+
UserID: user.ID,
86+
LoginType: database.LoginTypeToken,
87+
DefaultLifetime: api.DeploymentValues.SessionDuration.Value(),
88+
ExpiresAt: dbtime.Now().Add(lifeTime),
89+
Scope: scope,
90+
LifetimeSeconds: int64(lifeTime.Seconds()),
91+
TokenName: tokenName,
9292
})
9393
if err != nil {
9494
if database.IsUniqueViolation(err, database.UniqueIndexAPIKeyName) {
@@ -127,10 +127,10 @@ func (api *API) postAPIKey(rw http.ResponseWriter, r *http.Request) {
127127

128128
lifeTime := time.Hour * 24 * 7
129129
cookie, _, err := api.createAPIKey(ctx, apikey.CreateParams{
130-
UserID: user.ID,
131-
DeploymentValues: api.DeploymentValues,
132-
LoginType: database.LoginTypePassword,
133-
RemoteAddr: r.RemoteAddr,
130+
UserID: user.ID,
131+
DefaultLifetime: api.DeploymentValues.SessionDuration.Value(),
132+
LoginType: database.LoginTypePassword,
133+
RemoteAddr: r.RemoteAddr,
134134
// All api generated keys will last 1 week. Browser login tokens have
135135
// a shorter life.
136136
ExpiresAt: dbtime.Now().Add(lifeTime),

coderd/apikey/apikey.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ import (
1212

1313
"github.com/coder/coder/v2/coderd/database"
1414
"github.com/coder/coder/v2/coderd/database/dbtime"
15-
"github.com/coder/coder/v2/codersdk"
1615
"github.com/coder/coder/v2/cryptorand"
1716
)
1817

1918
type CreateParams struct {
20-
UserID uuid.UUID
21-
LoginType database.LoginType
22-
DeploymentValues *codersdk.DeploymentValues
19+
UserID uuid.UUID
20+
LoginType database.LoginType
21+
// DefaultLifetime is configured in DeploymentValues.
22+
// It is used if LifetimeSeconds is not set.
23+
DefaultLifetime time.Duration
2324

2425
// Optional.
2526
ExpiresAt time.Time
@@ -46,8 +47,8 @@ func Generate(params CreateParams) (database.InsertAPIKeyParams, string, error)
4647
if params.LifetimeSeconds != 0 {
4748
params.ExpiresAt = dbtime.Now().Add(time.Duration(params.LifetimeSeconds) * time.Second)
4849
} else {
49-
params.ExpiresAt = dbtime.Now().Add(params.DeploymentValues.SessionDuration.Value())
50-
params.LifetimeSeconds = int64(params.DeploymentValues.SessionDuration.Value().Seconds())
50+
params.ExpiresAt = dbtime.Now().Add(params.DefaultLifetime)
51+
params.LifetimeSeconds = int64(params.DefaultLifetime.Seconds())
5152
}
5253
}
5354
if params.LifetimeSeconds == 0 {

coderd/apikey/apikey_test.go

+51-42
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@ import (
1010
"github.com/stretchr/testify/assert"
1111
"github.com/stretchr/testify/require"
1212

13-
"github.com/coder/coder/v2/cli/clibase"
1413
"github.com/coder/coder/v2/coderd/apikey"
1514
"github.com/coder/coder/v2/coderd/database"
1615
"github.com/coder/coder/v2/coderd/database/dbtime"
17-
"github.com/coder/coder/v2/codersdk"
1816
)
1917

2018
func TestGenerate(t *testing.T) {
@@ -30,69 +28,80 @@ func TestGenerate(t *testing.T) {
3028
{
3129
name: "OK",
3230
params: apikey.CreateParams{
33-
UserID: uuid.New(),
34-
LoginType: database.LoginTypeOIDC,
35-
DeploymentValues: &codersdk.DeploymentValues{},
36-
ExpiresAt: time.Now().Add(time.Hour),
37-
LifetimeSeconds: int64(time.Hour.Seconds()),
38-
TokenName: "hello",
39-
RemoteAddr: "1.2.3.4",
40-
Scope: database.APIKeyScopeApplicationConnect,
31+
UserID: uuid.New(),
32+
LoginType: database.LoginTypeOIDC,
33+
DefaultLifetime: time.Duration(0),
34+
ExpiresAt: time.Now().Add(time.Hour),
35+
LifetimeSeconds: int64(time.Hour.Seconds()),
36+
TokenName: "hello",
37+
RemoteAddr: "1.2.3.4",
38+
Scope: database.APIKeyScopeApplicationConnect,
4139
},
4240
},
4341
{
4442
name: "InvalidScope",
4543
params: apikey.CreateParams{
46-
UserID: uuid.New(),
47-
LoginType: database.LoginTypeOIDC,
48-
DeploymentValues: &codersdk.DeploymentValues{},
49-
ExpiresAt: time.Now().Add(time.Hour),
50-
LifetimeSeconds: int64(time.Hour.Seconds()),
51-
TokenName: "hello",
52-
RemoteAddr: "1.2.3.4",
53-
Scope: database.APIKeyScope("test"),
44+
UserID: uuid.New(),
45+
LoginType: database.LoginTypeOIDC,
46+
DefaultLifetime: time.Duration(0),
47+
ExpiresAt: time.Now().Add(time.Hour),
48+
LifetimeSeconds: int64(time.Hour.Seconds()),
49+
TokenName: "hello",
50+
RemoteAddr: "1.2.3.4",
51+
Scope: database.APIKeyScope("test"),
5452
},
5553
fail: true,
5654
},
5755
{
5856
name: "DeploymentSessionDuration",
5957
params: apikey.CreateParams{
60-
UserID: uuid.New(),
61-
LoginType: database.LoginTypeOIDC,
62-
DeploymentValues: &codersdk.DeploymentValues{
63-
SessionDuration: clibase.Duration(time.Hour),
64-
},
58+
UserID: uuid.New(),
59+
LoginType: database.LoginTypeOIDC,
60+
DefaultLifetime: time.Hour,
6561
LifetimeSeconds: 0,
6662
ExpiresAt: time.Time{},
6763
TokenName: "hello",
6864
RemoteAddr: "1.2.3.4",
6965
Scope: database.APIKeyScopeApplicationConnect,
7066
},
7167
},
68+
{
69+
name: "LifetimeSeconds",
70+
params: apikey.CreateParams{
71+
UserID: uuid.New(),
72+
LoginType: database.LoginTypeOIDC,
73+
DefaultLifetime: time.Duration(0),
74+
LifetimeSeconds: int64(time.Hour.Seconds()),
75+
ExpiresAt: time.Time{},
76+
TokenName: "hello",
77+
RemoteAddr: "1.2.3.4",
78+
Scope: database.APIKeyScopeApplicationConnect,
79+
},
80+
},
7281
{
7382
name: "DefaultIP",
7483
params: apikey.CreateParams{
75-
UserID: uuid.New(),
76-
LoginType: database.LoginTypeOIDC,
77-
DeploymentValues: &codersdk.DeploymentValues{},
78-
ExpiresAt: time.Now().Add(time.Hour),
79-
LifetimeSeconds: int64(time.Hour.Seconds()),
80-
TokenName: "hello",
81-
RemoteAddr: "",
82-
Scope: database.APIKeyScopeApplicationConnect,
84+
UserID: uuid.New(),
85+
LoginType: database.LoginTypeOIDC,
86+
DefaultLifetime: time.Duration(0),
87+
ExpiresAt: time.Now().Add(time.Hour),
88+
LifetimeSeconds: int64(time.Hour.Seconds()),
89+
TokenName: "hello",
90+
RemoteAddr: "",
91+
Scope: database.APIKeyScopeApplicationConnect,
8392
},
8493
},
8594
{
8695
name: "DefaultScope",
8796
params: apikey.CreateParams{
88-
UserID: uuid.New(),
89-
LoginType: database.LoginTypeOIDC,
90-
DeploymentValues: &codersdk.DeploymentValues{},
91-
ExpiresAt: time.Now().Add(time.Hour),
92-
LifetimeSeconds: int64(time.Hour.Seconds()),
93-
TokenName: "hello",
94-
RemoteAddr: "1.2.3.4",
95-
Scope: "",
97+
UserID: uuid.New(),
98+
LoginType: database.LoginTypeOIDC,
99+
DefaultLifetime: time.Duration(0),
100+
ExpiresAt: time.Now().Add(time.Hour),
101+
LifetimeSeconds: int64(time.Hour.Seconds()),
102+
TokenName: "hello",
103+
RemoteAddr: "1.2.3.4",
104+
Scope: "",
96105
},
97106
},
98107
}
@@ -131,15 +140,15 @@ func TestGenerate(t *testing.T) {
131140
// Should not be a delta greater than 5 seconds.
132141
assert.InDelta(t, time.Until(tc.params.ExpiresAt).Seconds(), key.LifetimeSeconds, 5)
133142
} else {
134-
assert.Equal(t, int64(tc.params.DeploymentValues.SessionDuration.Value().Seconds()), key.LifetimeSeconds)
143+
assert.Equal(t, int64(tc.params.DefaultLifetime.Seconds()), key.LifetimeSeconds)
135144
}
136145

137146
if !tc.params.ExpiresAt.IsZero() {
138147
assert.Equal(t, tc.params.ExpiresAt.UTC(), key.ExpiresAt)
139148
} else if tc.params.LifetimeSeconds > 0 {
140-
assert.WithinDuration(t, dbtime.Now().Add(time.Duration(tc.params.LifetimeSeconds)), key.ExpiresAt, time.Second*5)
149+
assert.WithinDuration(t, dbtime.Now().Add(time.Duration(tc.params.LifetimeSeconds)*time.Second), key.ExpiresAt, time.Second*5)
141150
} else {
142-
assert.WithinDuration(t, dbtime.Now().Add(tc.params.DeploymentValues.SessionDuration.Value()), key.ExpiresAt, time.Second*5)
151+
assert.WithinDuration(t, dbtime.Now().Add(tc.params.DefaultLifetime), key.ExpiresAt, time.Second*5)
143152
}
144153

145154
if tc.params.RemoteAddr != "" {

coderd/provisionerdserver/provisionerdserver.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -1683,11 +1683,11 @@ func workspaceSessionTokenName(workspace database.Workspace) string {
16831683

16841684
func (s *server) regenerateSessionToken(ctx context.Context, user database.User, workspace database.Workspace) (string, error) {
16851685
newkey, sessionToken, err := apikey.Generate(apikey.CreateParams{
1686-
UserID: user.ID,
1687-
LoginType: user.LoginType,
1688-
DeploymentValues: s.DeploymentValues,
1689-
TokenName: workspaceSessionTokenName(workspace),
1690-
LifetimeSeconds: int64(s.DeploymentValues.MaxTokenLifetime.Value().Seconds()),
1686+
UserID: user.ID,
1687+
LoginType: user.LoginType,
1688+
DefaultLifetime: s.DeploymentValues.SessionDuration.Value(),
1689+
TokenName: workspaceSessionTokenName(workspace),
1690+
LifetimeSeconds: int64(s.DeploymentValues.MaxTokenLifetime.Value().Seconds()),
16911691
})
16921692
if err != nil {
16931693
return "", xerrors.Errorf("generate API key: %w", err)

coderd/userauth.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,10 @@ func (api *API) postLogin(rw http.ResponseWriter, r *http.Request) {
247247

248248
//nolint:gocritic // Creating the API key as the user instead of as system.
249249
cookie, key, err := api.createAPIKey(dbauthz.As(ctx, userSubj), apikey.CreateParams{
250-
UserID: user.ID,
251-
LoginType: database.LoginTypePassword,
252-
RemoteAddr: r.RemoteAddr,
253-
DeploymentValues: api.DeploymentValues,
250+
UserID: user.ID,
251+
LoginType: database.LoginTypePassword,
252+
RemoteAddr: r.RemoteAddr,
253+
DefaultLifetime: api.DeploymentValues.SessionDuration.Value(),
254254
})
255255
if err != nil {
256256
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
15451545
} else {
15461546
//nolint:gocritic
15471547
cookie, newKey, err := api.createAPIKey(dbauthz.AsSystemRestricted(ctx), apikey.CreateParams{
1548-
UserID: user.ID,
1549-
LoginType: params.LoginType,
1550-
DeploymentValues: api.DeploymentValues,
1551-
RemoteAddr: r.RemoteAddr,
1548+
UserID: user.ID,
1549+
LoginType: params.LoginType,
1550+
DefaultLifetime: api.DeploymentValues.SessionDuration.Value(),
1551+
RemoteAddr: r.RemoteAddr,
15521552
})
15531553
if err != nil {
15541554
return nil, database.APIKey{}, xerrors.Errorf("create API key: %w", err)

coderd/workspaceapps.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,12 @@ func (api *API) workspaceApplicationAuth(rw http.ResponseWriter, r *http.Request
107107
lifetimeSeconds = int64(api.DeploymentValues.SessionDuration.Value().Seconds())
108108
}
109109
cookie, _, err := api.createAPIKey(ctx, apikey.CreateParams{
110-
UserID: apiKey.UserID,
111-
LoginType: database.LoginTypePassword,
112-
DeploymentValues: api.DeploymentValues,
113-
ExpiresAt: exp,
114-
LifetimeSeconds: lifetimeSeconds,
115-
Scope: database.APIKeyScopeApplicationConnect,
110+
UserID: apiKey.UserID,
111+
LoginType: database.LoginTypePassword,
112+
DefaultLifetime: api.DeploymentValues.SessionDuration.Value(),
113+
ExpiresAt: exp,
114+
LifetimeSeconds: lifetimeSeconds,
115+
Scope: database.APIKeyScopeApplicationConnect,
116116
})
117117
if err != nil {
118118
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{

0 commit comments

Comments
 (0)