@@ -10,6 +10,7 @@ import (
10
10
"strings"
11
11
"time"
12
12
13
+ "golang.org/x/exp/slices"
13
14
"golang.org/x/xerrors"
14
15
15
16
"cdr.dev/slog"
@@ -100,7 +101,7 @@ func (p *DBTokenProvider) Issue(ctx context.Context, rw http.ResponseWriter, r *
100
101
// Lookup workspace app details from DB.
101
102
dbReq , err := appReq .getDatabase (dangerousSystemCtx , p .Database )
102
103
if xerrors .Is (err , sql .ErrNoRows ) {
103
- WriteWorkspaceApp404 (p .Logger , p .DashboardURL , rw , r , & appReq , err .Error ())
104
+ WriteWorkspaceApp404 (p .Logger , p .DashboardURL , rw , r , & appReq , nil , err .Error ())
104
105
return nil , "" , false
105
106
} else if err != nil {
106
107
WriteWorkspaceApp500 (p .Logger , p .DashboardURL , rw , r , & appReq , err , "get app details from database" )
@@ -114,15 +115,15 @@ func (p *DBTokenProvider) Issue(ctx context.Context, rw http.ResponseWriter, r *
114
115
}
115
116
116
117
// Verify the user has access to the app.
117
- authed , err := p .authorizeRequest (r .Context (), authz , dbReq )
118
+ authed , warnings , err := p .authorizeRequest (r .Context (), authz , dbReq )
118
119
if err != nil {
119
120
WriteWorkspaceApp500 (p .Logger , p .DashboardURL , rw , r , & appReq , err , "verify authz" )
120
121
return nil , "" , false
121
122
}
122
123
if ! authed {
123
124
if apiKey != nil {
124
125
// The request has a valid API key but insufficient permissions.
125
- WriteWorkspaceApp404 (p .Logger , p .DashboardURL , rw , r , & appReq , "insufficient permissions" )
126
+ WriteWorkspaceApp404 (p .Logger , p .DashboardURL , rw , r , & appReq , warnings , "insufficient permissions" )
126
127
return nil , "" , false
127
128
}
128
129
@@ -218,7 +219,12 @@ func (p *DBTokenProvider) Issue(ctx context.Context, rw http.ResponseWriter, r *
218
219
return & token , tokenStr , true
219
220
}
220
221
221
- func (p * DBTokenProvider ) authorizeRequest (ctx context.Context , roles * httpmw.Authorization , dbReq * databaseRequest ) (bool , error ) {
222
+ // authorizeRequest returns true/false if the request is authorized. The returned []string
223
+ // are warnings that aid in debugging. These messages do not prevent authorization,
224
+ // but may indicate that the request is not configured correctly.
225
+ // If an error is returned, the request should be aborted with a 500 error.
226
+ func (p * DBTokenProvider ) authorizeRequest (ctx context.Context , roles * httpmw.Authorization , dbReq * databaseRequest ) (bool , []string , error ) {
227
+ var warnings []string
222
228
accessMethod := dbReq .AccessMethod
223
229
if accessMethod == "" {
224
230
accessMethod = AccessMethodPath
@@ -233,14 +239,22 @@ func (p *DBTokenProvider) authorizeRequest(ctx context.Context, roles *httpmw.Au
233
239
// Dangerous.AllowPathAppSiteOwnerAccess flag is enabled in the check below.
234
240
sharingLevel := dbReq .AppSharingLevel
235
241
if isPathApp && ! p .DeploymentValues .Dangerous .AllowPathAppSharing .Value () {
242
+ if dbReq .AppSharingLevel != database .AppSharingLevelOwner {
243
+ // This is helpful for debugging, and ok to leak to the user.
244
+ // This is because the app has the sharing level set to something that
245
+ // should be shared, but we are disabling it from a deployment wide
246
+ // flag. So the template should be fixed to set the sharing level to
247
+ // "owner" instead and this will not appear.
248
+ warnings = append (warnings , fmt .Sprintf ("unable to use configured sharing level %q because path-based app sharing is disabled (see --dangerous-allow-path-app-sharing), using sharing level \" owner\" instead" , sharingLevel ))
249
+ }
236
250
sharingLevel = database .AppSharingLevelOwner
237
251
}
238
252
239
253
// Short circuit if not authenticated.
240
254
if roles == nil {
241
255
// The user is not authenticated, so they can only access the app if it
242
256
// is public.
243
- return sharingLevel == database .AppSharingLevelPublic , nil
257
+ return sharingLevel == database .AppSharingLevelPublic , warnings , nil
244
258
}
245
259
246
260
// Block anyone from accessing workspaces they don't own in path-based apps
@@ -254,7 +268,13 @@ func (p *DBTokenProvider) authorizeRequest(ctx context.Context, roles *httpmw.Au
254
268
sharingLevel == database .AppSharingLevelOwner &&
255
269
dbReq .Workspace .OwnerID .String () != roles .Actor .ID &&
256
270
! p .DeploymentValues .Dangerous .AllowPathAppSiteOwnerAccess .Value () {
257
- return false , nil
271
+ // This is not ideal to check for the 'owner' role, but we are only checking
272
+ // to determine whether to show a warning for debugging reasons. This does
273
+ // not do any authz checks, so it is ok.
274
+ if roles != nil && slices .Contains (roles .Actor .Roles .Names (), rbac .RoleOwner ()) {
275
+ warnings = append (warnings , "path-based apps with \" owner\" share level are only accessible by the workspace owner (see --dangerous-allow-path-app-site-owner-access)" )
276
+ }
277
+ return false , warnings , nil
258
278
}
259
279
260
280
// Figure out which RBAC resource to check. For terminals we use execution
@@ -280,7 +300,7 @@ func (p *DBTokenProvider) authorizeRequest(ctx context.Context, roles *httpmw.Au
280
300
// scope allows it).
281
301
err := p .Authorizer .Authorize (ctx , roles .Actor , rbacAction , rbacResource )
282
302
if err == nil {
283
- return true , nil
303
+ return true , [] string {}, nil
284
304
}
285
305
286
306
switch sharingLevel {
@@ -293,15 +313,15 @@ func (p *DBTokenProvider) authorizeRequest(ctx context.Context, roles *httpmw.Au
293
313
// to connect to the actor's own workspace. This enforces scopes.
294
314
err := p .Authorizer .Authorize (ctx , roles .Actor , rbacAction , rbacResourceOwned )
295
315
if err == nil {
296
- return true , nil
316
+ return true , [] string {}, nil
297
317
}
298
318
case database .AppSharingLevelPublic :
299
319
// We don't really care about scopes and stuff if it's public anyways.
300
320
// Someone with a restricted-scope API key could just not submit the API
301
321
// key cookie in the request and access the page.
302
- return true , nil
322
+ return true , [] string {}, nil
303
323
}
304
324
305
325
// No checks were successful.
306
- return false , nil
326
+ return false , warnings , nil
307
327
}
0 commit comments