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

Lines changed: 11 additions & 11 deletions
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

Lines changed: 7 additions & 6 deletions
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

Lines changed: 51 additions & 42 deletions
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

Lines changed: 5 additions & 5 deletions
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

Lines changed: 8 additions & 8 deletions
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

Lines changed: 6 additions & 6 deletions
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)
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