@@ -10,6 +10,7 @@ import (
1010 "strings"
1111 "time"
1212
13+ "golang.org/x/exp/slices"
1314 "golang.org/x/xerrors"
1415
1516 "cdr.dev/slog"
@@ -100,7 +101,7 @@ func (p *DBTokenProvider) Issue(ctx context.Context, rw http.ResponseWriter, r *
100101 // Lookup workspace app details from DB.
101102 dbReq , err := appReq .getDatabase (dangerousSystemCtx , p .Database )
102103 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 ())
104105 return nil , "" , false
105106 } else if err != nil {
106107 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 *
114115 }
115116
116117 // 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 )
118119 if err != nil {
119120 WriteWorkspaceApp500 (p .Logger , p .DashboardURL , rw , r , & appReq , err , "verify authz" )
120121 return nil , "" , false
121122 }
122123 if ! authed {
123124 if apiKey != nil {
124125 // 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" )
126127 return nil , "" , false
127128 }
128129
@@ -218,7 +219,12 @@ func (p *DBTokenProvider) Issue(ctx context.Context, rw http.ResponseWriter, r *
218219 return & token , tokenStr , true
219220}
220221
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
222228 accessMethod := dbReq .AccessMethod
223229 if accessMethod == "" {
224230 accessMethod = AccessMethodPath
@@ -233,14 +239,22 @@ func (p *DBTokenProvider) authorizeRequest(ctx context.Context, roles *httpmw.Au
233239 // Dangerous.AllowPathAppSiteOwnerAccess flag is enabled in the check below.
234240 sharingLevel := dbReq .AppSharingLevel
235241 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+ }
236250 sharingLevel = database .AppSharingLevelOwner
237251 }
238252
239253 // Short circuit if not authenticated.
240254 if roles == nil {
241255 // The user is not authenticated, so they can only access the app if it
242256 // is public.
243- return sharingLevel == database .AppSharingLevelPublic , nil
257+ return sharingLevel == database .AppSharingLevelPublic , warnings , nil
244258 }
245259
246260 // 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
254268 sharingLevel == database .AppSharingLevelOwner &&
255269 dbReq .Workspace .OwnerID .String () != roles .Actor .ID &&
256270 ! 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
258278 }
259279
260280 // 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
280300 // scope allows it).
281301 err := p .Authorizer .Authorize (ctx , roles .Actor , rbacAction , rbacResource )
282302 if err == nil {
283- return true , nil
303+ return true , [] string {}, nil
284304 }
285305
286306 switch sharingLevel {
@@ -293,15 +313,15 @@ func (p *DBTokenProvider) authorizeRequest(ctx context.Context, roles *httpmw.Au
293313 // to connect to the actor's own workspace. This enforces scopes.
294314 err := p .Authorizer .Authorize (ctx , roles .Actor , rbacAction , rbacResourceOwned )
295315 if err == nil {
296- return true , nil
316+ return true , [] string {}, nil
297317 }
298318 case database .AppSharingLevelPublic :
299319 // We don't really care about scopes and stuff if it's public anyways.
300320 // Someone with a restricted-scope API key could just not submit the API
301321 // key cookie in the request and access the page.
302- return true , nil
322+ return true , [] string {}, nil
303323 }
304324
305325 // No checks were successful.
306- return false , nil
326+ return false , warnings , nil
307327}
0 commit comments