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

Commitbc44107

Browse files
committed
chore: add OAuth2 device flow test scripts
Change-Id: Ic232851727e683ab3d8b7ce970c505588da2f827Signed-off-by: Thomas Kosiewski <tk@coder.com>
1 parent6b7cd46 commitbc44107

File tree

19 files changed

+761
-76
lines changed

19 files changed

+761
-76
lines changed

‎coderd/database/dbauthz/dbauthz.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ var (
399399
rbac.ResourceProvisionerJobs.Type: {policy.ActionRead,policy.ActionUpdate,policy.ActionCreate},
400400
rbac.ResourceOauth2App.Type: {policy.ActionCreate,policy.ActionRead,policy.ActionUpdate,policy.ActionDelete},
401401
rbac.ResourceOauth2AppSecret.Type: {policy.ActionCreate,policy.ActionRead,policy.ActionUpdate,policy.ActionDelete},
402+
rbac.ResourceOauth2AppCodeToken.Type: {policy.ActionCreate,policy.ActionRead,policy.ActionUpdate,policy.ActionDelete},
402403
}),
403404
Org:map[string][]rbac.Permission{},
404405
User: []rbac.Permission{},
@@ -1324,6 +1325,14 @@ func (q *querier) CleanTailnetTunnels(ctx context.Context) error {
13241325
returnq.db.CleanTailnetTunnels(ctx)
13251326
}
13261327

1328+
func (q*querier)ConsumeOAuth2ProviderAppCodeByPrefix(ctx context.Context,secretPrefix []byte) (database.OAuth2ProviderAppCode,error) {
1329+
returnupdateWithReturn(q.log,q.auth,q.db.GetOAuth2ProviderAppCodeByPrefix,q.db.ConsumeOAuth2ProviderAppCodeByPrefix)(ctx,secretPrefix)
1330+
}
1331+
1332+
func (q*querier)ConsumeOAuth2ProviderDeviceCodeByPrefix(ctx context.Context,deviceCodePrefixstring) (database.OAuth2ProviderDeviceCode,error) {
1333+
returnupdateWithReturn(q.log,q.auth,q.db.GetOAuth2ProviderDeviceCodeByPrefix,q.db.ConsumeOAuth2ProviderDeviceCodeByPrefix)(ctx,deviceCodePrefix)
1334+
}
1335+
13271336
func (q*querier)CountAuditLogs(ctx context.Context,arg database.CountAuditLogsParams) (int64,error) {
13281337
// Shortcut if the user is an owner. The SQL filter is noticeable,
13291338
// and this is an easy win for owners. Which is the common case.
@@ -2301,8 +2310,8 @@ func (q *querier) GetOAuth2ProviderDeviceCodeByUserCode(ctx context.Context, use
23012310
}
23022311

23032312
func (q*querier)GetOAuth2ProviderDeviceCodesByClientID(ctx context.Context,clientID uuid.UUID) ([]database.OAuth2ProviderDeviceCode,error) {
2304-
// This requires access to readtheOAuth2 app
2305-
iferr:=q.authorizeContext(ctx,policy.ActionRead,rbac.ResourceOauth2App);err!=nil {
2313+
// This requires access to read OAuth2 app code tokens
2314+
iferr:=q.authorizeContext(ctx,policy.ActionRead,rbac.ResourceOauth2AppCodeToken);err!=nil {
23062315
return []database.OAuth2ProviderDeviceCode{},err
23072316
}
23082317
returnq.db.GetOAuth2ProviderDeviceCodesByClientID(ctx,clientID)
@@ -3752,8 +3761,8 @@ func (q *querier) InsertOAuth2ProviderAppToken(ctx context.Context, arg database
37523761
}
37533762

37543763
func (q*querier)InsertOAuth2ProviderDeviceCode(ctx context.Context,arg database.InsertOAuth2ProviderDeviceCodeParams) (database.OAuth2ProviderDeviceCode,error) {
3755-
// Creating device codes requires OAuth2 app access
3756-
iferr:=q.authorizeContext(ctx,policy.ActionCreate,rbac.ResourceOauth2App);err!=nil {
3764+
// Creating device codes requires OAuth2 appcode token creationaccess
3765+
iferr:=q.authorizeContext(ctx,policy.ActionCreate,rbac.ResourceOauth2AppCodeToken);err!=nil {
37573766
return database.OAuth2ProviderDeviceCode{},err
37583767
}
37593768
returnq.db.InsertOAuth2ProviderDeviceCode(ctx,arg)
@@ -4432,13 +4441,10 @@ func (q *querier) UpdateOAuth2ProviderAppSecretByID(ctx context.Context, arg dat
44324441
}
44334442

44344443
func (q*querier)UpdateOAuth2ProviderDeviceCodeAuthorization(ctx context.Context,arg database.UpdateOAuth2ProviderDeviceCodeAuthorizationParams) (database.OAuth2ProviderDeviceCode,error) {
4435-
// Verify the user is authenticated for device code authorization
4436-
_,ok:=ActorFromContext(ctx)
4437-
if!ok {
4438-
return database.OAuth2ProviderDeviceCode{},ErrNoActor
4444+
fetch:=func(ctx context.Context,arg database.UpdateOAuth2ProviderDeviceCodeAuthorizationParams) (database.OAuth2ProviderDeviceCode,error) {
4445+
returnq.db.GetOAuth2ProviderDeviceCodeByID(ctx,arg.ID)
44394446
}
4440-
4441-
returnq.db.UpdateOAuth2ProviderDeviceCodeAuthorization(ctx,arg)
4447+
returnupdateWithReturn(q.log,q.auth,fetch,q.db.UpdateOAuth2ProviderDeviceCodeAuthorization)(ctx,arg)
44424448
}
44434449

44444450
func (q*querier)UpdateOrganization(ctx context.Context,arg database.UpdateOrganizationParams) (database.Organization,error) {

‎coderd/database/dbauthz/dbauthz_test.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5423,6 +5423,19 @@ func (s *MethodTestSuite) TestOAuth2ProviderAppCodes() {
54235423
UserID:user.ID,
54245424
}).Asserts(rbac.ResourceOauth2AppCodeToken.WithOwner(user.ID.String()),policy.ActionDelete)
54255425
}))
5426+
s.Run("ConsumeOAuth2ProviderAppCodeByPrefix",s.Subtest(func(db database.Store,check*expects) {
5427+
user:=dbgen.User(s.T(),db, database.User{})
5428+
app:=dbgen.OAuth2ProviderApp(s.T(),db, database.OAuth2ProviderApp{})
5429+
// Use unique prefix to avoid test isolation issues
5430+
uniquePrefix:=fmt.Sprintf("prefix-%s-%d",s.T().Name(),time.Now().UnixNano())
5431+
code:=dbgen.OAuth2ProviderAppCode(s.T(),db, database.OAuth2ProviderAppCode{
5432+
SecretPrefix: []byte(uniquePrefix),
5433+
UserID:user.ID,
5434+
AppID:app.ID,
5435+
ExpiresAt:time.Now().Add(24*time.Hour),// Extended expiry for test stability
5436+
})
5437+
check.Args(code.SecretPrefix).Asserts(code,policy.ActionUpdate).Returns(code)
5438+
}))
54265439
}
54275440

54285441
func (s*MethodTestSuite)TestOAuth2ProviderAppTokens() {
@@ -5498,6 +5511,110 @@ func (s *MethodTestSuite) TestOAuth2ProviderAppTokens() {
54985511
}))
54995512
}
55005513

5514+
func (s*MethodTestSuite)TestOAuth2ProviderDeviceCodes() {
5515+
s.Run("InsertOAuth2ProviderDeviceCode",s.Subtest(func(db database.Store,check*expects) {
5516+
app:=dbgen.OAuth2ProviderApp(s.T(),db, database.OAuth2ProviderApp{})
5517+
check.Args(database.InsertOAuth2ProviderDeviceCodeParams{
5518+
ClientID:app.ID,
5519+
}).Asserts(rbac.ResourceOauth2AppCodeToken,policy.ActionCreate)
5520+
}))
5521+
s.Run("GetOAuth2ProviderDeviceCodeByID",s.Subtest(func(db database.Store,check*expects) {
5522+
app:=dbgen.OAuth2ProviderApp(s.T(),db, database.OAuth2ProviderApp{})
5523+
deviceCode,err:=db.InsertOAuth2ProviderDeviceCode(context.Background(), database.InsertOAuth2ProviderDeviceCodeParams{
5524+
ClientID:app.ID,
5525+
DeviceCodePrefix:"test-prefix",
5526+
UserCode:"TEST1234",
5527+
VerificationUri:"http://example.com/device",
5528+
})
5529+
require.NoError(s.T(),err)
5530+
check.Args(deviceCode.ID).Asserts(deviceCode,policy.ActionRead).Returns(deviceCode)
5531+
}))
5532+
s.Run("GetOAuth2ProviderDeviceCodeByPrefix",s.Subtest(func(db database.Store,check*expects) {
5533+
app:=dbgen.OAuth2ProviderApp(s.T(),db, database.OAuth2ProviderApp{})
5534+
deviceCode,err:=db.InsertOAuth2ProviderDeviceCode(context.Background(), database.InsertOAuth2ProviderDeviceCodeParams{
5535+
ClientID:app.ID,
5536+
DeviceCodePrefix:"test-prefix",
5537+
UserCode:"TEST1234",
5538+
VerificationUri:"http://example.com/device",
5539+
})
5540+
require.NoError(s.T(),err)
5541+
check.Args(deviceCode.DeviceCodePrefix).Asserts(deviceCode,policy.ActionRead).Returns(deviceCode)
5542+
}))
5543+
s.Run("GetOAuth2ProviderDeviceCodeByUserCode",s.Subtest(func(db database.Store,check*expects) {
5544+
app:=dbgen.OAuth2ProviderApp(s.T(),db, database.OAuth2ProviderApp{})
5545+
deviceCode,err:=db.InsertOAuth2ProviderDeviceCode(context.Background(), database.InsertOAuth2ProviderDeviceCodeParams{
5546+
ClientID:app.ID,
5547+
DeviceCodePrefix:"test-prefix",
5548+
UserCode:"TEST1234",
5549+
VerificationUri:"http://example.com/device",
5550+
})
5551+
require.NoError(s.T(),err)
5552+
check.Args(deviceCode.UserCode).Asserts(deviceCode,policy.ActionRead).Returns(deviceCode)
5553+
}))
5554+
s.Run("GetOAuth2ProviderDeviceCodesByClientID",s.Subtest(func(db database.Store,check*expects) {
5555+
app:=dbgen.OAuth2ProviderApp(s.T(),db, database.OAuth2ProviderApp{})
5556+
deviceCode,err:=db.InsertOAuth2ProviderDeviceCode(context.Background(), database.InsertOAuth2ProviderDeviceCodeParams{
5557+
ClientID:app.ID,
5558+
DeviceCodePrefix:"test-prefix",
5559+
UserCode:"TEST1234",
5560+
VerificationUri:"http://example.com/device",
5561+
})
5562+
require.NoError(s.T(),err)
5563+
check.Args(app.ID).Asserts(rbac.ResourceOauth2AppCodeToken,policy.ActionRead).Returns([]database.OAuth2ProviderDeviceCode{deviceCode})
5564+
}))
5565+
s.Run("ConsumeOAuth2ProviderDeviceCodeByPrefix",s.Subtest(func(db database.Store,check*expects) {
5566+
app:=dbgen.OAuth2ProviderApp(s.T(),db, database.OAuth2ProviderApp{})
5567+
user:=dbgen.User(s.T(),db, database.User{})
5568+
// Use unique identifiers to avoid test isolation issues
5569+
uniquePrefix:=fmt.Sprintf("dev-prefix-%s-%d",s.T().Name(),time.Now().UnixNano())
5570+
uniqueUserCode:=fmt.Sprintf("USER%s-%d",s.T().Name(),time.Now().UnixNano())
5571+
// Create device code using dbgen (now available!)
5572+
deviceCode:=dbgen.OAuth2ProviderDeviceCode(s.T(),db, database.OAuth2ProviderDeviceCode{
5573+
DeviceCodePrefix:uniquePrefix,
5574+
UserCode:uniqueUserCode,
5575+
ClientID:app.ID,
5576+
ExpiresAt:time.Now().Add(24*time.Hour),// Extended expiry for test stability
5577+
})
5578+
// Authorize the device code so it can be consumed
5579+
deviceCode,err:=db.UpdateOAuth2ProviderDeviceCodeAuthorization(s.T().Context(), database.UpdateOAuth2ProviderDeviceCodeAuthorizationParams{
5580+
ID:deviceCode.ID,
5581+
UserID: uuid.NullUUID{UUID:user.ID,Valid:true},
5582+
Status:database.OAuth2DeviceStatusAuthorized,
5583+
})
5584+
require.NoError(s.T(),err)
5585+
require.Equal(s.T(),database.OAuth2DeviceStatusAuthorized,deviceCode.Status)
5586+
check.Args(uniquePrefix).Asserts(deviceCode,policy.ActionUpdate).Returns(deviceCode)
5587+
}))
5588+
s.Run("UpdateOAuth2ProviderDeviceCodeAuthorization",s.Subtest(func(db database.Store,check*expects) {
5589+
app:=dbgen.OAuth2ProviderApp(s.T(),db, database.OAuth2ProviderApp{})
5590+
user:=dbgen.User(s.T(),db, database.User{})
5591+
// Create device code using dbgen
5592+
deviceCode:=dbgen.OAuth2ProviderDeviceCode(s.T(),db, database.OAuth2ProviderDeviceCode{
5593+
ClientID:app.ID,
5594+
})
5595+
require.Equal(s.T(),database.OAuth2DeviceStatusPending,deviceCode.Status)
5596+
check.Args(database.UpdateOAuth2ProviderDeviceCodeAuthorizationParams{
5597+
ID:deviceCode.ID,
5598+
UserID: uuid.NullUUID{UUID:user.ID,Valid:true},
5599+
Status:database.OAuth2DeviceStatusAuthorized,
5600+
}).Asserts(deviceCode,policy.ActionUpdate)
5601+
}))
5602+
s.Run("DeleteOAuth2ProviderDeviceCodeByID",s.Subtest(func(db database.Store,check*expects) {
5603+
app:=dbgen.OAuth2ProviderApp(s.T(),db, database.OAuth2ProviderApp{})
5604+
deviceCode,err:=db.InsertOAuth2ProviderDeviceCode(context.Background(), database.InsertOAuth2ProviderDeviceCodeParams{
5605+
ClientID:app.ID,
5606+
DeviceCodePrefix:"test-prefix",
5607+
UserCode:"TEST1234",
5608+
VerificationUri:"http://example.com/device",
5609+
})
5610+
require.NoError(s.T(),err)
5611+
check.Args(deviceCode.ID).Asserts(deviceCode,policy.ActionDelete)
5612+
}))
5613+
s.Run("DeleteExpiredOAuth2ProviderDeviceCodes",s.Subtest(func(db database.Store,check*expects) {
5614+
check.Args().Asserts(rbac.ResourceSystem,policy.ActionDelete)
5615+
}))
5616+
}
5617+
55015618
func (s*MethodTestSuite)TestResourcesMonitor() {
55025619
createAgent:=func(t*testing.T,db database.Store) (database.WorkspaceAgent, database.WorkspaceTable) {
55035620
t.Helper()

‎coderd/database/dbgen/dbgen.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,7 +1199,7 @@ func OAuth2ProviderAppCode(t testing.TB, db database.Store, seed database.OAuth2
11991199
code,err:=db.InsertOAuth2ProviderAppCode(genCtx, database.InsertOAuth2ProviderAppCodeParams{
12001200
ID:takeFirst(seed.ID,uuid.New()),
12011201
CreatedAt:takeFirst(seed.CreatedAt,dbtime.Now()),
1202-
ExpiresAt:takeFirst(seed.CreatedAt,dbtime.Now()),
1202+
ExpiresAt:takeFirst(seed.ExpiresAt,dbtime.Now().Add(24*time.Hour)),
12031203
SecretPrefix:takeFirstSlice(seed.SecretPrefix, []byte("prefix")),
12041204
HashedSecret:takeFirstSlice(seed.HashedSecret, []byte("hashed-secret")),
12051205
AppID:takeFirst(seed.AppID,uuid.New()),
@@ -1216,7 +1216,7 @@ func OAuth2ProviderAppToken(t testing.TB, db database.Store, seed database.OAuth
12161216
token,err:=db.InsertOAuth2ProviderAppToken(genCtx, database.InsertOAuth2ProviderAppTokenParams{
12171217
ID:takeFirst(seed.ID,uuid.New()),
12181218
CreatedAt:takeFirst(seed.CreatedAt,dbtime.Now()),
1219-
ExpiresAt:takeFirst(seed.CreatedAt,dbtime.Now()),
1219+
ExpiresAt:takeFirst(seed.ExpiresAt,dbtime.Now().Add(24*time.Hour)),
12201220
HashPrefix:takeFirstSlice(seed.HashPrefix, []byte("prefix")),
12211221
RefreshHash:takeFirstSlice(seed.RefreshHash, []byte("hashed-secret")),
12221222
AppSecretID:takeFirst(seed.AppSecretID,uuid.New()),
@@ -1228,6 +1228,25 @@ func OAuth2ProviderAppToken(t testing.TB, db database.Store, seed database.OAuth
12281228
returntoken
12291229
}
12301230

1231+
funcOAuth2ProviderDeviceCode(t testing.TB,db database.Store,seed database.OAuth2ProviderDeviceCode) database.OAuth2ProviderDeviceCode {
1232+
deviceCode,err:=db.InsertOAuth2ProviderDeviceCode(genCtx, database.InsertOAuth2ProviderDeviceCodeParams{
1233+
ID:takeFirst(seed.ID,uuid.New()),
1234+
CreatedAt:takeFirst(seed.CreatedAt,dbtime.Now()),
1235+
ExpiresAt:takeFirst(seed.ExpiresAt,dbtime.Now().Add(24*time.Hour)),
1236+
DeviceCodeHash:takeFirstSlice(seed.DeviceCodeHash, []byte("device-hash")),
1237+
DeviceCodePrefix:takeFirst(seed.DeviceCodePrefix,testutil.GetRandomName(t)),
1238+
UserCode:takeFirst(seed.UserCode,testutil.GetRandomName(t)),
1239+
ClientID:takeFirst(seed.ClientID,uuid.New()),
1240+
VerificationUri:takeFirst(seed.VerificationUri,"https://example.com/device"),
1241+
VerificationUriComplete:seed.VerificationUriComplete,
1242+
Scope:seed.Scope,
1243+
ResourceUri:seed.ResourceUri,
1244+
PollingInterval:takeFirst(seed.PollingInterval,5),
1245+
})
1246+
require.NoError(t,err,"insert oauth2 device code")
1247+
returndeviceCode
1248+
}
1249+
12311250
funcWorkspaceAgentMemoryResourceMonitor(t testing.TB,db database.Store,seed database.WorkspaceAgentMemoryResourceMonitor) database.WorkspaceAgentMemoryResourceMonitor {
12321251
monitor,err:=db.InsertMemoryResourceMonitor(genCtx, database.InsertMemoryResourceMonitorParams{
12331252
AgentID:takeFirst(seed.AgentID,uuid.New()),

‎coderd/database/dbmetrics/querymetrics.go

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/dbmock/dbmock.go

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
INSERT INTO oauth2_provider_device_codes (
2+
id, created_at, expires_at, device_code_hash, device_code_prefix,
3+
user_code, client_id, user_id, status, verification_uri,
4+
verification_uri_complete, scope, resource_uri, polling_interval
5+
)VALUES (
6+
'c1eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
7+
'2023-06-15 10:23:54+00',
8+
'2023-06-15 10:33:54+00',
9+
CAST('abcdefg123'ASbytea),
10+
'abcdefg1',
11+
'ABCD1234',
12+
'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
13+
'0ed9befc-4911-4ccf-a8e2-559bf72daa94',
14+
'pending',
15+
'http://coder.com/oauth2/device',
16+
'http://coder.com/oauth2/device?user_code=ABCD1234',
17+
'read:user',
18+
'http://coder.com/api',
19+
5
20+
);

‎coderd/database/querier.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp