Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitec5ef51

Browse files
authored
feat: add session token injection to provisioner (#7461)
1 parent00a2413 commitec5ef51

File tree

13 files changed

+577
-218
lines changed

13 files changed

+577
-218
lines changed

‎coderd/apikey.go

Lines changed: 19 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,24 @@ package coderd
22

33
import (
44
"context"
5-
"crypto/sha256"
65
"fmt"
7-
"net"
86
"net/http"
97
"strconv"
108
"time"
119

1210
"github.com/go-chi/chi/v5"
1311
"github.com/google/uuid"
1412
"github.com/moby/moby/pkg/namesgenerator"
15-
"github.com/tabbed/pqtype"
1613
"golang.org/x/xerrors"
1714

15+
"github.com/coder/coder/coderd/apikey"
1816
"github.com/coder/coder/coderd/audit"
1917
"github.com/coder/coder/coderd/database"
2018
"github.com/coder/coder/coderd/httpapi"
2119
"github.com/coder/coder/coderd/httpmw"
2220
"github.com/coder/coder/coderd/rbac"
2321
"github.com/coder/coder/coderd/telemetry"
2422
"github.com/coder/coder/codersdk"
25-
"github.com/coder/coder/cryptorand"
2623
)
2724

2825
// Creates a new token API key that effectively doesn't expire.
@@ -83,13 +80,14 @@ func (api *API) postToken(rw http.ResponseWriter, r *http.Request) {
8380
return
8481
}
8582

86-
cookie,key,err:=api.createAPIKey(ctx,createAPIKeyParams{
87-
UserID:user.ID,
88-
LoginType:database.LoginTypeToken,
89-
ExpiresAt:database.Now().Add(lifeTime),
90-
Scope:scope,
91-
LifetimeSeconds:int64(lifeTime.Seconds()),
92-
TokenName:tokenName,
83+
cookie,key,err:=api.createAPIKey(ctx, apikey.CreateParams{
84+
UserID:user.ID,
85+
LoginType:database.LoginTypeToken,
86+
DeploymentValues:api.DeploymentValues,
87+
ExpiresAt:database.Now().Add(lifeTime),
88+
Scope:scope,
89+
LifetimeSeconds:int64(lifeTime.Seconds()),
90+
TokenName:tokenName,
9391
})
9492
iferr!=nil {
9593
ifdatabase.IsUniqueViolation(err,database.UniqueIndexApiKeyName) {
@@ -127,10 +125,11 @@ func (api *API) postAPIKey(rw http.ResponseWriter, r *http.Request) {
127125
user:=httpmw.UserParam(r)
128126

129127
lifeTime:=time.Hour*24*7
130-
cookie,_,err:=api.createAPIKey(ctx,createAPIKeyParams{
131-
UserID:user.ID,
132-
LoginType:database.LoginTypePassword,
133-
RemoteAddr:r.RemoteAddr,
128+
cookie,_,err:=api.createAPIKey(ctx, apikey.CreateParams{
129+
UserID:user.ID,
130+
DeploymentValues:api.DeploymentValues,
131+
LoginType:database.LoginTypePassword,
132+
RemoteAddr:r.RemoteAddr,
134133
// All api generated keys will last 1 week. Browser login tokens have
135134
// a shorter life.
136135
ExpiresAt:database.Now().Add(lifeTime),
@@ -359,33 +358,6 @@ func (api *API) tokenConfig(rw http.ResponseWriter, r *http.Request) {
359358
)
360359
}
361360

362-
// Generates a new ID and secret for an API key.
363-
funcGenerateAPIKeyIDSecret() (idstring,secretstring,errerror) {
364-
// Length of an API Key ID.
365-
id,err=cryptorand.String(10)
366-
iferr!=nil {
367-
return"","",err
368-
}
369-
// Length of an API Key secret.
370-
secret,err=cryptorand.String(22)
371-
iferr!=nil {
372-
return"","",err
373-
}
374-
returnid,secret,nil
375-
}
376-
377-
typecreateAPIKeyParamsstruct {
378-
UserID uuid.UUID
379-
RemoteAddrstring
380-
LoginType database.LoginType
381-
382-
// Optional.
383-
ExpiresAt time.Time
384-
LifetimeSecondsint64
385-
Scope database.APIKeyScope
386-
TokenNamestring
387-
}
388-
389361
func (api*API)validateAPIKeyLifetime(lifetime time.Duration)error {
390362
iflifetime<=0 {
391363
returnxerrors.New("lifetime must be positive number greater than 0")
@@ -401,79 +373,27 @@ func (api *API) validateAPIKeyLifetime(lifetime time.Duration) error {
401373
returnnil
402374
}
403375

404-
func (api*API)createAPIKey(ctx context.Context,paramscreateAPIKeyParams) (*http.Cookie,*database.APIKey,error) {
405-
keyID,keySecret,err:=GenerateAPIKeyIDSecret()
376+
func (api*API)createAPIKey(ctx context.Context,paramsapikey.CreateParams) (*http.Cookie,*database.APIKey,error) {
377+
key,sessionToken,err:=apikey.Generate(params)
406378
iferr!=nil {
407379
returnnil,nil,xerrors.Errorf("generate API key: %w",err)
408380
}
409-
hashed:=sha256.Sum256([]byte(keySecret))
410-
411-
// Default expires at to now+lifetime, or use the configured value if not
412-
// set.
413-
ifparams.ExpiresAt.IsZero() {
414-
ifparams.LifetimeSeconds!=0 {
415-
params.ExpiresAt=database.Now().Add(time.Duration(params.LifetimeSeconds)*time.Second)
416-
}else {
417-
params.ExpiresAt=database.Now().Add(api.DeploymentValues.SessionDuration.Value())
418-
params.LifetimeSeconds=int64(api.DeploymentValues.SessionDuration.Value().Seconds())
419-
}
420-
}
421-
ifparams.LifetimeSeconds==0 {
422-
params.LifetimeSeconds=int64(time.Until(params.ExpiresAt).Seconds())
423-
}
424-
425-
ip:=net.ParseIP(params.RemoteAddr)
426-
ifip==nil {
427-
ip=net.IPv4(0,0,0,0)
428-
}
429-
bitlen:=len(ip)*8
430381

431-
scope:=database.APIKeyScopeAll
432-
ifparams.Scope!="" {
433-
scope=params.Scope
434-
}
435-
switchscope {
436-
casedatabase.APIKeyScopeAll,database.APIKeyScopeApplicationConnect:
437-
default:
438-
returnnil,nil,xerrors.Errorf("invalid API key scope: %q",scope)
439-
}
440-
441-
key,err:=api.Database.InsertAPIKey(ctx, database.InsertAPIKeyParams{
442-
ID:keyID,
443-
UserID:params.UserID,
444-
LifetimeSeconds:params.LifetimeSeconds,
445-
IPAddress: pqtype.Inet{
446-
IPNet: net.IPNet{
447-
IP:ip,
448-
Mask:net.CIDRMask(bitlen,bitlen),
449-
},
450-
Valid:true,
451-
},
452-
// Make sure in UTC time for common time zone
453-
ExpiresAt:params.ExpiresAt.UTC(),
454-
CreatedAt:database.Now(),
455-
UpdatedAt:database.Now(),
456-
HashedSecret:hashed[:],
457-
LoginType:params.LoginType,
458-
Scope:scope,
459-
TokenName:params.TokenName,
460-
})
382+
newkey,err:=api.Database.InsertAPIKey(ctx,key)
461383
iferr!=nil {
462384
returnnil,nil,xerrors.Errorf("insert API key: %w",err)
463385
}
464386

465387
api.Telemetry.Report(&telemetry.Snapshot{
466-
APIKeys: []telemetry.APIKey{telemetry.ConvertAPIKey(key)},
388+
APIKeys: []telemetry.APIKey{telemetry.ConvertAPIKey(newkey)},
467389
})
468390

469-
// This format is consumed by the APIKey middleware.
470-
sessionToken:=fmt.Sprintf("%s-%s",keyID,keySecret)
471391
return&http.Cookie{
472392
Name:codersdk.SessionTokenCookie,
473393
Value:sessionToken,
474394
Path:"/",
475395
HttpOnly:true,
476396
SameSite:http.SameSiteLaxMode,
477397
Secure:api.SecureAuthCookie,
478-
},&key,nil
398+
},&newkey,nil
479399
}

‎coderd/apikey/apikey.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package apikey
2+
3+
import (
4+
"crypto/sha256"
5+
"fmt"
6+
"net"
7+
"time"
8+
9+
"github.com/google/uuid"
10+
"github.com/tabbed/pqtype"
11+
"golang.org/x/xerrors"
12+
13+
"github.com/coder/coder/coderd/database"
14+
"github.com/coder/coder/codersdk"
15+
"github.com/coder/coder/cryptorand"
16+
)
17+
18+
typeCreateParamsstruct {
19+
UserID uuid.UUID
20+
LoginType database.LoginType
21+
DeploymentValues*codersdk.DeploymentValues
22+
23+
// Optional.
24+
ExpiresAt time.Time
25+
LifetimeSecondsint64
26+
Scope database.APIKeyScope
27+
TokenNamestring
28+
RemoteAddrstring
29+
}
30+
31+
// Generate generates an API key, returning the key as a string as well as the
32+
// database representation. It is the responsibility of the caller to insert it
33+
// into the database.
34+
funcGenerate(paramsCreateParams) (database.InsertAPIKeyParams,string,error) {
35+
keyID,keySecret,err:=generateKey()
36+
iferr!=nil {
37+
return database.InsertAPIKeyParams{},"",xerrors.Errorf("generate API key: %w",err)
38+
}
39+
40+
hashed:=sha256.Sum256([]byte(keySecret))
41+
42+
// Default expires at to now+lifetime, or use the configured value if not
43+
// set.
44+
ifparams.ExpiresAt.IsZero() {
45+
ifparams.LifetimeSeconds!=0 {
46+
params.ExpiresAt=database.Now().Add(time.Duration(params.LifetimeSeconds)*time.Second)
47+
}else {
48+
params.ExpiresAt=database.Now().Add(params.DeploymentValues.SessionDuration.Value())
49+
params.LifetimeSeconds=int64(params.DeploymentValues.SessionDuration.Value().Seconds())
50+
}
51+
}
52+
ifparams.LifetimeSeconds==0 {
53+
params.LifetimeSeconds=int64(time.Until(params.ExpiresAt).Seconds())
54+
}
55+
56+
ip:=net.ParseIP(params.RemoteAddr)
57+
ifip==nil {
58+
ip=net.IPv4(0,0,0,0)
59+
}
60+
61+
bitlen:=len(ip)*8
62+
63+
scope:=database.APIKeyScopeAll
64+
ifparams.Scope!="" {
65+
scope=params.Scope
66+
}
67+
switchscope {
68+
casedatabase.APIKeyScopeAll,database.APIKeyScopeApplicationConnect:
69+
default:
70+
return database.InsertAPIKeyParams{},"",xerrors.Errorf("invalid API key scope: %q",scope)
71+
}
72+
73+
token:=fmt.Sprintf("%s-%s",keyID,keySecret)
74+
75+
return database.InsertAPIKeyParams{
76+
ID:keyID,
77+
UserID:params.UserID,
78+
LifetimeSeconds:params.LifetimeSeconds,
79+
IPAddress: pqtype.Inet{
80+
IPNet: net.IPNet{
81+
IP:ip,
82+
Mask:net.CIDRMask(bitlen,bitlen),
83+
},
84+
Valid:true,
85+
},
86+
// Make sure in UTC time for common time zone
87+
ExpiresAt:params.ExpiresAt.UTC(),
88+
CreatedAt:database.Now(),
89+
UpdatedAt:database.Now(),
90+
HashedSecret:hashed[:],
91+
LoginType:params.LoginType,
92+
Scope:scope,
93+
TokenName:params.TokenName,
94+
},token,nil
95+
}
96+
97+
// generateKey a new ID and secret for an API key.
98+
funcgenerateKey() (idstring,secretstring,errerror) {
99+
// Length of an API Key ID.
100+
id,err=cryptorand.String(10)
101+
iferr!=nil {
102+
return"","",err
103+
}
104+
// Length of an API Key secret.
105+
secret,err=cryptorand.String(22)
106+
iferr!=nil {
107+
return"","",err
108+
}
109+
returnid,secret,nil
110+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp