@@ -417,6 +417,35 @@ var (
417
417
rbac .ResourceProvisionerJobs .Type : {policy .ActionRead , policy .ActionUpdate , policy .ActionCreate },
418
418
rbac .ResourceOauth2App .Type : {policy .ActionCreate , policy .ActionRead , policy .ActionUpdate , policy .ActionDelete },
419
419
rbac .ResourceOauth2AppSecret .Type : {policy .ActionCreate , policy .ActionRead , policy .ActionUpdate , policy .ActionDelete },
420
+ rbac .ResourceOauth2AppCodeToken .Type : {policy .ActionCreate , policy .ActionRead , policy .ActionUpdate , policy .ActionDelete },
421
+ }),
422
+ Org : map [string ][]rbac.Permission {},
423
+ User : []rbac.Permission {},
424
+ },
425
+ }),
426
+ Scope : rbac .ScopeAll ,
427
+ }.WithCachedASTValue ()
428
+
429
+ subjectSystemOAuth2 = rbac.Subject {
430
+ Type : rbac .SubjectTypeSystemRestricted ,
431
+ FriendlyName : "System OAuth2" ,
432
+ ID : uuid .Nil .String (),
433
+ Roles : rbac .Roles ([]rbac.Role {
434
+ {
435
+ Identifier : rbac.RoleIdentifier {Name : "system-oauth2" },
436
+ DisplayName : "System OAuth2" ,
437
+ Site : rbac .Permissions (map [string ][]policy.Action {
438
+ // OAuth2 resources - full CRUD permissions
439
+ rbac .ResourceOauth2App .Type : rbac .ResourceOauth2App .AvailableActions (),
440
+ rbac .ResourceOauth2AppSecret .Type : rbac .ResourceOauth2AppSecret .AvailableActions (),
441
+ rbac .ResourceOauth2AppCodeToken .Type : rbac .ResourceOauth2AppCodeToken .AvailableActions (),
442
+
443
+ // API key permissions needed for OAuth2 token revocation
444
+ rbac .ResourceApiKey .Type : {policy .ActionRead , policy .ActionDelete },
445
+
446
+ // Minimal read permissions that might be needed for OAuth2 operations
447
+ rbac .ResourceUser .Type : {policy .ActionRead },
448
+ rbac .ResourceOrganization .Type : {policy .ActionRead },
420
449
}),
421
450
Org : map [string ][]rbac.Permission {},
422
451
User : []rbac.Permission {},
@@ -567,6 +596,12 @@ func AsSystemRestricted(ctx context.Context) context.Context {
567
596
return As (ctx , subjectSystemRestricted )
568
597
}
569
598
599
+ // AsSystemOAuth2 returns a context with an actor that has permissions
600
+ // required for OAuth2 provider operations (token revocation, device codes, registration).
601
+ func AsSystemOAuth2 (ctx context.Context ) context.Context {
602
+ return As (ctx , subjectSystemOAuth2 )
603
+ }
604
+
570
605
// AsSystemReadProvisionerDaemons returns a context with an actor that has permissions
571
606
// to read provisioner daemons.
572
607
func AsSystemReadProvisionerDaemons (ctx context.Context ) context.Context {
@@ -1346,6 +1381,14 @@ func (q *querier) CleanTailnetTunnels(ctx context.Context) error {
1346
1381
return q .db .CleanTailnetTunnels (ctx )
1347
1382
}
1348
1383
1384
+ func (q * querier ) ConsumeOAuth2ProviderAppCodeByPrefix (ctx context.Context , secretPrefix []byte ) (database.OAuth2ProviderAppCode , error ) {
1385
+ return updateWithReturn (q .log , q .auth , q .db .GetOAuth2ProviderAppCodeByPrefix , q .db .ConsumeOAuth2ProviderAppCodeByPrefix )(ctx , secretPrefix )
1386
+ }
1387
+
1388
+ func (q * querier ) ConsumeOAuth2ProviderDeviceCodeByPrefix (ctx context.Context , deviceCodePrefix string ) (database.OAuth2ProviderDeviceCode , error ) {
1389
+ return updateWithReturn (q .log , q .auth , q .db .GetOAuth2ProviderDeviceCodeByPrefix , q .db .ConsumeOAuth2ProviderDeviceCodeByPrefix )(ctx , deviceCodePrefix )
1390
+ }
1391
+
1349
1392
func (q * querier ) CountAuditLogs (ctx context.Context , arg database.CountAuditLogsParams ) (int64 , error ) {
1350
1393
// Shortcut if the user is an owner. The SQL filter is noticeable,
1351
1394
// and this is an easy win for owners. Which is the common case.
@@ -1489,7 +1532,7 @@ func (q *querier) DeleteExpiredOAuth2ProviderDeviceCodes(ctx context.Context) er
1489
1532
func (q * querier ) DeleteExternalAuthLink (ctx context.Context , arg database.DeleteExternalAuthLinkParams ) error {
1490
1533
return fetchAndExec (q .log , q .auth , policy .ActionUpdatePersonal , func (ctx context.Context , arg database.DeleteExternalAuthLinkParams ) (database.ExternalAuthLink , error ) {
1491
1534
//nolint:gosimple
1492
- return q .db .GetExternalAuthLink (ctx , database.GetExternalAuthLinkParams { UserID : arg . UserID , ProviderID : arg . ProviderID } )
1535
+ return q .db .GetExternalAuthLink (ctx , database .GetExternalAuthLinkParams ( arg ) )
1493
1536
}, q .db .DeleteExternalAuthLink )(ctx , arg )
1494
1537
}
1495
1538
@@ -1568,27 +1611,30 @@ func (q *querier) DeleteOAuth2ProviderAppTokensByAppAndUserID(ctx context.Contex
1568
1611
return q .db .DeleteOAuth2ProviderAppTokensByAppAndUserID (ctx , arg )
1569
1612
}
1570
1613
1571
- func (q * querier ) DeleteOldAuditLogConnectionEvents (ctx context.Context , threshold database.DeleteOldAuditLogConnectionEventsParams ) error {
1572
- // `ResourceSystem` is deprecated, but it doesn't make sense to add
1573
- // `policy.ActionDelete` to `ResourceAuditLog`, since this is the one and
1574
- // only time we'll be deleting from the audit log.
1575
- if err := q .authorizeContext (ctx , policy .ActionDelete , rbac .ResourceSystem ); err != nil {
1576
- return err
1577
- }
1578
- return q .db .DeleteOldAuditLogConnectionEvents (ctx , threshold )
1579
- }
1580
-
1581
1614
func (q * querier ) DeleteOAuth2ProviderDeviceCodeByID (ctx context.Context , id uuid.UUID ) error {
1582
1615
// Fetch the device code first to check authorization
1583
1616
deviceCode , err := q .db .GetOAuth2ProviderDeviceCodeByID (ctx , id )
1584
1617
if err != nil {
1585
- return err
1618
+ return xerrors . Errorf ( "get oauth2 provider device code: %w" , err )
1586
1619
}
1587
1620
if err := q .authorizeContext (ctx , policy .ActionDelete , deviceCode ); err != nil {
1588
- return err
1621
+ return xerrors . Errorf ( "authorize oauth2 provider device code deletion: %w" , err )
1589
1622
}
1590
1623
1591
- return q .db .DeleteOAuth2ProviderDeviceCodeByID (ctx , id )
1624
+ if err := q .db .DeleteOAuth2ProviderDeviceCodeByID (ctx , id ); err != nil {
1625
+ return xerrors .Errorf ("delete oauth2 provider device code: %w" , err )
1626
+ }
1627
+ return nil
1628
+ }
1629
+
1630
+ func (q * querier ) DeleteOldAuditLogConnectionEvents (ctx context.Context , threshold database.DeleteOldAuditLogConnectionEventsParams ) error {
1631
+ // `ResourceSystem` is deprecated, but it doesn't make sense to add
1632
+ // `policy.ActionDelete` to `ResourceAuditLog`, since this is the one and
1633
+ // only time we'll be deleting from the audit log.
1634
+ if err := q .authorizeContext (ctx , policy .ActionDelete , rbac .ResourceSystem ); err != nil {
1635
+ return err
1636
+ }
1637
+ return q .db .DeleteOldAuditLogConnectionEvents (ctx , threshold )
1592
1638
}
1593
1639
1594
1640
func (q * querier ) DeleteOldNotificationMessages (ctx context.Context ) error {
@@ -1620,7 +1666,7 @@ func (q *querier) DeleteOldWorkspaceAgentStats(ctx context.Context) error {
1620
1666
}
1621
1667
1622
1668
func (q * querier ) DeleteOrganizationMember (ctx context.Context , arg database.DeleteOrganizationMemberParams ) error {
1623
- return deleteQ [database. OrganizationMember ] (q .log , q .auth , func (ctx context.Context , arg database.DeleteOrganizationMemberParams ) (database.OrganizationMember , error ) {
1669
+ return deleteQ (q .log , q .auth , func (ctx context.Context , arg database.DeleteOrganizationMemberParams ) (database.OrganizationMember , error ) {
1624
1670
member , err := database .ExpectOne (q .OrganizationMembers (ctx , database.OrganizationMembersParams {
1625
1671
OrganizationID : arg .OrganizationID ,
1626
1672
UserID : arg .UserID ,
@@ -2213,7 +2259,7 @@ func (q *querier) GetLicenseByID(ctx context.Context, id int32) (database.Licens
2213
2259
}
2214
2260
2215
2261
func (q * querier ) GetLicenses (ctx context.Context ) ([]database.License , error ) {
2216
- fetch := func (ctx context.Context , _ interface {} ) ([]database.License , error ) {
2262
+ fetch := func (ctx context.Context , _ any ) ([]database.License , error ) {
2217
2263
return q .db .GetLicenses (ctx )
2218
2264
}
2219
2265
return fetchWithPostFilter (q .auth , policy .ActionRead , fetch )(ctx , nil )
@@ -2377,8 +2423,8 @@ func (q *querier) GetOAuth2ProviderDeviceCodeByUserCode(ctx context.Context, use
2377
2423
}
2378
2424
2379
2425
func (q * querier ) GetOAuth2ProviderDeviceCodesByClientID (ctx context.Context , clientID uuid.UUID ) ([]database.OAuth2ProviderDeviceCode , error ) {
2380
- // This requires access to read the OAuth2 app
2381
- if err := q .authorizeContext (ctx , policy .ActionRead , rbac .ResourceOauth2App ); err != nil {
2426
+ // This requires access to read OAuth2 app code tokens
2427
+ if err := q .authorizeContext (ctx , policy .ActionRead , rbac .ResourceOauth2AppCodeToken ); err != nil {
2382
2428
return []database.OAuth2ProviderDeviceCode {}, err
2383
2429
}
2384
2430
return q .db .GetOAuth2ProviderDeviceCodesByClientID (ctx , clientID )
@@ -2435,7 +2481,7 @@ func (q *querier) GetOrganizationResourceCountByID(ctx context.Context, organiza
2435
2481
}
2436
2482
2437
2483
func (q * querier ) GetOrganizations (ctx context.Context , args database.GetOrganizationsParams ) ([]database.Organization , error ) {
2438
- fetch := func (ctx context.Context , _ interface {} ) ([]database.Organization , error ) {
2484
+ fetch := func (ctx context.Context , _ any ) ([]database.Organization , error ) {
2439
2485
return q .db .GetOrganizations (ctx , args )
2440
2486
}
2441
2487
return fetchWithPostFilter (q .auth , policy .ActionRead , fetch )(ctx , nil )
@@ -2563,7 +2609,7 @@ func (q *querier) GetPreviousTemplateVersion(ctx context.Context, arg database.G
2563
2609
}
2564
2610
2565
2611
func (q * querier ) GetProvisionerDaemons (ctx context.Context ) ([]database.ProvisionerDaemon , error ) {
2566
- fetch := func (ctx context.Context , _ interface {} ) ([]database.ProvisionerDaemon , error ) {
2612
+ fetch := func (ctx context.Context , _ any ) ([]database.ProvisionerDaemon , error ) {
2567
2613
return q .db .GetProvisionerDaemons (ctx )
2568
2614
}
2569
2615
return fetchWithPostFilter (q .auth , policy .ActionRead , fetch )(ctx , nil )
@@ -3554,7 +3600,7 @@ func (q *querier) GetWorkspaceModulesCreatedAfter(ctx context.Context, createdAt
3554
3600
}
3555
3601
3556
3602
func (q * querier ) GetWorkspaceProxies (ctx context.Context ) ([]database.WorkspaceProxy , error ) {
3557
- return fetchWithPostFilter (q .auth , policy .ActionRead , func (ctx context.Context , _ interface {} ) ([]database.WorkspaceProxy , error ) {
3603
+ return fetchWithPostFilter (q .auth , policy .ActionRead , func (ctx context.Context , _ any ) ([]database.WorkspaceProxy , error ) {
3558
3604
return q .db .GetWorkspaceProxies (ctx )
3559
3605
})(ctx , nil )
3560
3606
}
@@ -3848,8 +3894,8 @@ func (q *querier) InsertOAuth2ProviderAppToken(ctx context.Context, arg database
3848
3894
}
3849
3895
3850
3896
func (q * querier ) InsertOAuth2ProviderDeviceCode (ctx context.Context , arg database.InsertOAuth2ProviderDeviceCodeParams ) (database.OAuth2ProviderDeviceCode , error ) {
3851
- // Creating device codes requires OAuth2 app access
3852
- if err := q .authorizeContext (ctx , policy .ActionCreate , rbac .ResourceOauth2App ); err != nil {
3897
+ // Creating device codes requires OAuth2 app code token creation access
3898
+ if err := q .authorizeContext (ctx , policy .ActionCreate , rbac .ResourceOauth2AppCodeToken ); err != nil {
3853
3899
return database.OAuth2ProviderDeviceCode {}, err
3854
3900
}
3855
3901
return q .db .InsertOAuth2ProviderDeviceCode (ctx , arg )
@@ -4156,10 +4202,11 @@ func (q *querier) InsertWorkspaceBuild(ctx context.Context, arg database.InsertW
4156
4202
return xerrors .Errorf ("get workspace by id: %w" , err )
4157
4203
}
4158
4204
4159
- var action policy.Action = policy .ActionWorkspaceStart
4160
- if arg .Transition == database .WorkspaceTransitionDelete {
4205
+ action := policy .ActionWorkspaceStart
4206
+ switch arg .Transition {
4207
+ case database .WorkspaceTransitionDelete :
4161
4208
action = policy .ActionDelete
4162
- } else if arg . Transition == database .WorkspaceTransitionStop {
4209
+ case database .WorkspaceTransitionStop :
4163
4210
action = policy .ActionWorkspaceStop
4164
4211
}
4165
4212
@@ -4536,13 +4583,10 @@ func (q *querier) UpdateOAuth2ProviderAppSecretByID(ctx context.Context, arg dat
4536
4583
}
4537
4584
4538
4585
func (q * querier ) UpdateOAuth2ProviderDeviceCodeAuthorization (ctx context.Context , arg database.UpdateOAuth2ProviderDeviceCodeAuthorizationParams ) (database.OAuth2ProviderDeviceCode , error ) {
4539
- // Verify the user is authenticated for device code authorization
4540
- _ , ok := ActorFromContext (ctx )
4541
- if ! ok {
4542
- return database.OAuth2ProviderDeviceCode {}, ErrNoActor
4586
+ fetch := func (ctx context.Context , arg database.UpdateOAuth2ProviderDeviceCodeAuthorizationParams ) (database.OAuth2ProviderDeviceCode , error ) {
4587
+ return q .db .GetOAuth2ProviderDeviceCodeByID (ctx , arg .ID )
4543
4588
}
4544
-
4545
- return q .db .UpdateOAuth2ProviderDeviceCodeAuthorization (ctx , arg )
4589
+ return updateWithReturn (q .log , q .auth , fetch , q .db .UpdateOAuth2ProviderDeviceCodeAuthorization )(ctx , arg )
4546
4590
}
4547
4591
4548
4592
func (q * querier ) UpdateOrganization (ctx context.Context , arg database.UpdateOrganizationParams ) (database.Organization , error ) {
0 commit comments