8
8
"strconv"
9
9
"strings"
10
10
"testing"
11
+ "time"
11
12
12
13
"github.com/coder/coder/coderd/database/databasefake"
13
14
@@ -32,9 +33,10 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
32
33
_ , isMemoryDB := a .api .Database .(databasefake.FakeDatabase )
33
34
34
35
// Some quick reused objects
35
- workspaceRBACObj := rbac .ResourceWorkspace .InOrg (a .Organization .ID ).WithOwner (a .Workspace .OwnerID .String ())
36
- workspaceExecObj := rbac .ResourceWorkspaceExecution .InOrg (a .Organization .ID ).WithOwner (a .Workspace .OwnerID .String ())
37
- applicationConnectObj := rbac .ResourceWorkspaceApplicationConnect .InOrg (a .Organization .ID ).WithOwner (a .Workspace .OwnerID .String ())
36
+ workspaceRBACObj := rbac .ResourceWorkspace .WithID (a .Workspace .ID ).InOrg (a .Organization .ID ).WithOwner (a .Workspace .OwnerID .String ())
37
+ workspaceExecObj := rbac .ResourceWorkspaceExecution .WithID (a .Workspace .ID ).InOrg (a .Organization .ID ).WithOwner (a .Workspace .OwnerID .String ())
38
+ applicationConnectObj := rbac .ResourceWorkspaceApplicationConnect .WithID (a .Workspace .ID ).InOrg (a .Organization .ID ).WithOwner (a .Workspace .OwnerID .String ())
39
+ templateObj := rbac .ResourceTemplate .WithID (a .Template .ID ).InOrg (a .Template .OrganizationID )
38
40
39
41
// skipRoutes allows skipping routes from being checked.
40
42
skipRoutes := map [string ]string {
@@ -75,7 +77,7 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
75
77
"POST:/api/v2/workspaceagents/me/report-stats" : {NoAuthorize : true },
76
78
77
79
// These endpoints have more assertions. This is good, add more endpoints to assert if you can!
78
- "GET:/api/v2/organizations/{organization}" : {AssertObject : rbac .ResourceOrganization .InOrg (a .Admin .OrganizationID )},
80
+ "GET:/api/v2/organizations/{organization}" : {AssertObject : rbac .ResourceOrganization .WithID ( a . Admin . OrganizationID ). InOrg (a .Admin .OrganizationID )},
79
81
"GET:/api/v2/users/{user}/organizations" : {StatusCode : http .StatusOK , AssertObject : rbac .ResourceOrganization },
80
82
"GET:/api/v2/users/{user}/workspace/{workspacename}" : {
81
83
AssertObject : rbac .ResourceWorkspace ,
@@ -85,6 +87,15 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
85
87
AssertObject : rbac .ResourceWorkspace ,
86
88
AssertAction : rbac .ActionRead ,
87
89
},
90
+ "GET:/api/v2/users/{user}/keys/tokens" : {
91
+ AssertObject : rbac .ResourceAPIKey ,
92
+ AssertAction : rbac .ActionRead ,
93
+ StatusCode : http .StatusOK ,
94
+ },
95
+ "GET:/api/v2/users/{user}/keys/{keyid}" : {
96
+ AssertObject : rbac .ResourceAPIKey ,
97
+ AssertAction : rbac .ActionRead ,
98
+ },
88
99
"GET:/api/v2/workspacebuilds/{workspacebuild}" : {
89
100
AssertAction : rbac .ActionRead ,
90
101
AssertObject : workspaceRBACObj ,
@@ -139,11 +150,11 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
139
150
},
140
151
"DELETE:/api/v2/templates/{template}" : {
141
152
AssertAction : rbac .ActionDelete ,
142
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Template . OrganizationID ) ,
153
+ AssertObject : templateObj ,
143
154
},
144
155
"GET:/api/v2/templates/{template}" : {
145
156
AssertAction : rbac .ActionRead ,
146
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Template . OrganizationID ) ,
157
+ AssertObject : templateObj ,
147
158
},
148
159
"POST:/api/v2/files" : {AssertAction : rbac .ActionCreate , AssertObject : rbac .ResourceFile },
149
160
"GET:/api/v2/files/{fileID}" : {
@@ -152,64 +163,64 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
152
163
},
153
164
"GET:/api/v2/templates/{template}/versions" : {
154
165
AssertAction : rbac .ActionRead ,
155
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Template . OrganizationID ) ,
166
+ AssertObject : templateObj ,
156
167
},
157
168
"PATCH:/api/v2/templates/{template}/versions" : {
158
169
AssertAction : rbac .ActionUpdate ,
159
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Template . OrganizationID ) ,
170
+ AssertObject : templateObj ,
160
171
},
161
172
"GET:/api/v2/templates/{template}/versions/{templateversionname}" : {
162
173
AssertAction : rbac .ActionRead ,
163
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Template . OrganizationID ) ,
174
+ AssertObject : templateObj ,
164
175
},
165
176
"GET:/api/v2/templateversions/{templateversion}" : {
166
177
AssertAction : rbac .ActionRead ,
167
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Template . OrganizationID ) ,
178
+ AssertObject : templateObj ,
168
179
},
169
180
"PATCH:/api/v2/templateversions/{templateversion}/cancel" : {
170
181
AssertAction : rbac .ActionUpdate ,
171
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Template . OrganizationID ) ,
182
+ AssertObject : templateObj ,
172
183
},
173
184
"GET:/api/v2/templateversions/{templateversion}/logs" : {
174
185
AssertAction : rbac .ActionRead ,
175
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Template . OrganizationID ) ,
186
+ AssertObject : templateObj ,
176
187
},
177
188
"GET:/api/v2/templateversions/{templateversion}/parameters" : {
178
189
AssertAction : rbac .ActionRead ,
179
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Template . OrganizationID ) ,
190
+ AssertObject : templateObj ,
180
191
},
181
192
"GET:/api/v2/templateversions/{templateversion}/rich-parameters" : {
182
193
AssertAction : rbac .ActionRead ,
183
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Template . OrganizationID ) ,
194
+ AssertObject : templateObj ,
184
195
},
185
196
"GET:/api/v2/templateversions/{templateversion}/resources" : {
186
197
AssertAction : rbac .ActionRead ,
187
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Template . OrganizationID ) ,
198
+ AssertObject : templateObj ,
188
199
},
189
200
"GET:/api/v2/templateversions/{templateversion}/schema" : {
190
201
AssertAction : rbac .ActionRead ,
191
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Template . OrganizationID ) ,
202
+ AssertObject : templateObj ,
192
203
},
193
204
"POST:/api/v2/templateversions/{templateversion}/dry-run" : {
194
205
// The first check is to read the template
195
206
AssertAction : rbac .ActionRead ,
196
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Version . OrganizationID ) ,
207
+ AssertObject : templateObj ,
197
208
},
198
209
"GET:/api/v2/templateversions/{templateversion}/dry-run/{jobID}" : {
199
210
AssertAction : rbac .ActionRead ,
200
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Version . OrganizationID ) ,
211
+ AssertObject : templateObj ,
201
212
},
202
213
"GET:/api/v2/templateversions/{templateversion}/dry-run/{jobID}/resources" : {
203
214
AssertAction : rbac .ActionRead ,
204
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Version . OrganizationID ) ,
215
+ AssertObject : templateObj ,
205
216
},
206
217
"GET:/api/v2/templateversions/{templateversion}/dry-run/{jobID}/logs" : {
207
218
AssertAction : rbac .ActionRead ,
208
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Version . OrganizationID ) ,
219
+ AssertObject : templateObj ,
209
220
},
210
221
"PATCH:/api/v2/templateversions/{templateversion}/dry-run/{jobID}/cancel" : {
211
222
AssertAction : rbac .ActionRead ,
212
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Version . OrganizationID ) ,
223
+ AssertObject : templateObj ,
213
224
},
214
225
"POST:/api/v2/parameters/{scope}/{id}" : {
215
226
AssertAction : rbac .ActionUpdate ,
@@ -225,7 +236,7 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
225
236
},
226
237
"GET:/api/v2/organizations/{organization}/templates/{templatename}" : {
227
238
AssertAction : rbac .ActionRead ,
228
- AssertObject : rbac . ResourceTemplate . InOrg ( a . Template . OrganizationID ) ,
239
+ AssertObject : templateObj ,
229
240
},
230
241
"POST:/api/v2/organizations/{organization}/members/{user}/workspaces" : {
231
242
AssertAction : rbac .ActionCreate ,
@@ -317,6 +328,15 @@ func NewAuthTester(ctx context.Context, t *testing.T, client *codersdk.Client, a
317
328
if ! ok {
318
329
t .Fail ()
319
330
}
331
+ _ , err := client .CreateToken (ctx , admin .UserID .String (), codersdk.CreateTokenRequest {
332
+ Lifetime : time .Hour ,
333
+ Scope : codersdk .APIKeyScopeAll ,
334
+ })
335
+ require .NoError (t , err , "create token" )
336
+
337
+ apiKeys , err := client .GetTokens (ctx , admin .UserID .String ())
338
+ require .NoError (t , err , "get tokens" )
339
+ apiKey := apiKeys [0 ]
320
340
321
341
organization , err := client .Organization (ctx , admin .OrganizationID )
322
342
require .NoError (t , err , "fetch org" )
@@ -383,6 +403,7 @@ func NewAuthTester(ctx context.Context, t *testing.T, client *codersdk.Client, a
383
403
"{jobID}" : templateVersionDryRun .ID .String (),
384
404
"{templatename}" : template .Name ,
385
405
"{workspace_and_agent}" : workspace .Name + "." + workspace .LatestBuild .Resources [0 ].Agents [0 ].Name ,
406
+ "{keyid}" : apiKey .ID ,
386
407
// Only checking template scoped params here
387
408
"parameters/{scope}/{id}" : fmt .Sprintf ("parameters/%s/%s" ,
388
409
string (templateParam .Scope ), templateParam .ScopeID .String ()),
@@ -507,7 +528,7 @@ type authCall struct {
507
528
SubjectID string
508
529
Roles []string
509
530
Groups []string
510
- Scope rbac.Scope
531
+ Scope rbac.ScopeName
511
532
Action rbac.Action
512
533
Object rbac.Object
513
534
}
@@ -521,11 +542,11 @@ var _ rbac.Authorizer = (*RecordingAuthorizer)(nil)
521
542
522
543
// ByRoleNameSQL does not record the call. This matches the postgres behavior
523
544
// of not calling Authorize()
524
- func (r * RecordingAuthorizer ) ByRoleNameSQL (_ context.Context , _ string , _ []string , _ rbac.Scope , _ []string , _ rbac.Action , _ rbac.Object ) error {
545
+ func (r * RecordingAuthorizer ) ByRoleNameSQL (_ context.Context , _ string , _ []string , _ rbac.ScopeName , _ []string , _ rbac.Action , _ rbac.Object ) error {
525
546
return r .AlwaysReturn
526
547
}
527
548
528
- func (r * RecordingAuthorizer ) ByRoleName (_ context.Context , subjectID string , roleNames []string , scope rbac.Scope , groups []string , action rbac.Action , object rbac.Object ) error {
549
+ func (r * RecordingAuthorizer ) ByRoleName (_ context.Context , subjectID string , roleNames []string , scope rbac.ScopeName , groups []string , action rbac.Action , object rbac.Object ) error {
529
550
r .Called = & authCall {
530
551
SubjectID : subjectID ,
531
552
Roles : roleNames ,
@@ -537,7 +558,7 @@ func (r *RecordingAuthorizer) ByRoleName(_ context.Context, subjectID string, ro
537
558
return r .AlwaysReturn
538
559
}
539
560
540
- func (r * RecordingAuthorizer ) PrepareByRoleName (_ context.Context , subjectID string , roles []string , scope rbac.Scope , groups []string , action rbac.Action , _ string ) (rbac.PreparedAuthorized , error ) {
561
+ func (r * RecordingAuthorizer ) PrepareByRoleName (_ context.Context , subjectID string , roles []string , scope rbac.ScopeName , groups []string , action rbac.Action , _ string ) (rbac.PreparedAuthorized , error ) {
541
562
return & fakePreparedAuthorizer {
542
563
Original : r ,
543
564
SubjectID : subjectID ,
@@ -557,7 +578,7 @@ type fakePreparedAuthorizer struct {
557
578
Original * RecordingAuthorizer
558
579
SubjectID string
559
580
Roles []string
560
- Scope rbac.Scope
581
+ Scope rbac.ScopeName
561
582
Action rbac.Action
562
583
Groups []string
563
584
HardCodedSQLString string
0 commit comments