1package guardian 2 3import ( 4 "context" 5 "errors" 6 "fmt" 7 "runtime" 8 "testing" 9 10 "github.com/grafana/grafana/pkg/bus" 11 "github.com/grafana/grafana/pkg/models" 12 "github.com/grafana/grafana/pkg/setting" 13 14 "github.com/stretchr/testify/require" 15) 16 17const ( 18 orgID = int64(1) 19 defaultDashboardID = int64(-1) 20 dashboardID = int64(1) 21 parentFolderID = int64(2) 22 childDashboardID = int64(3) 23 userID = int64(1) 24 otherUserID = int64(2) 25 teamID = int64(1) 26 otherTeamID = int64(2) 27) 28 29var ( 30 adminRole = models.ROLE_ADMIN 31 editorRole = models.ROLE_EDITOR 32 viewerRole = models.ROLE_VIEWER 33) 34 35func TestGuardianAdmin(t *testing.T) { 36 orgRoleScenario("Given user has admin org role", t, models.ROLE_ADMIN, func(sc *scenarioContext) { 37 // dashboard has default permissions 38 sc.defaultPermissionScenario(USER, FULL_ACCESS) 39 40 // dashboard has user with permission 41 sc.dashboardPermissionScenario(USER, models.PERMISSION_ADMIN, FULL_ACCESS) 42 sc.dashboardPermissionScenario(USER, models.PERMISSION_EDIT, FULL_ACCESS) 43 sc.dashboardPermissionScenario(USER, models.PERMISSION_VIEW, FULL_ACCESS) 44 45 // dashboard has team with permission 46 sc.dashboardPermissionScenario(TEAM, models.PERMISSION_ADMIN, FULL_ACCESS) 47 sc.dashboardPermissionScenario(TEAM, models.PERMISSION_EDIT, FULL_ACCESS) 48 sc.dashboardPermissionScenario(TEAM, models.PERMISSION_VIEW, FULL_ACCESS) 49 50 // dashboard has editor role with permission 51 sc.dashboardPermissionScenario(EDITOR, models.PERMISSION_ADMIN, FULL_ACCESS) 52 sc.dashboardPermissionScenario(EDITOR, models.PERMISSION_EDIT, FULL_ACCESS) 53 sc.dashboardPermissionScenario(EDITOR, models.PERMISSION_VIEW, FULL_ACCESS) 54 55 // dashboard has viewer role with permission 56 sc.dashboardPermissionScenario(VIEWER, models.PERMISSION_ADMIN, FULL_ACCESS) 57 sc.dashboardPermissionScenario(VIEWER, models.PERMISSION_EDIT, FULL_ACCESS) 58 sc.dashboardPermissionScenario(VIEWER, models.PERMISSION_VIEW, FULL_ACCESS) 59 60 // parent folder has user with permission 61 sc.parentFolderPermissionScenario(USER, models.PERMISSION_ADMIN, FULL_ACCESS) 62 sc.parentFolderPermissionScenario(USER, models.PERMISSION_EDIT, FULL_ACCESS) 63 sc.parentFolderPermissionScenario(USER, models.PERMISSION_VIEW, FULL_ACCESS) 64 65 // parent folder has team with permission 66 sc.parentFolderPermissionScenario(TEAM, models.PERMISSION_ADMIN, FULL_ACCESS) 67 sc.parentFolderPermissionScenario(TEAM, models.PERMISSION_EDIT, FULL_ACCESS) 68 sc.parentFolderPermissionScenario(TEAM, models.PERMISSION_VIEW, FULL_ACCESS) 69 70 // parent folder has editor role with permission 71 sc.parentFolderPermissionScenario(EDITOR, models.PERMISSION_ADMIN, FULL_ACCESS) 72 sc.parentFolderPermissionScenario(EDITOR, models.PERMISSION_EDIT, FULL_ACCESS) 73 sc.parentFolderPermissionScenario(EDITOR, models.PERMISSION_VIEW, FULL_ACCESS) 74 75 // parent folder has viewer role with permission 76 sc.parentFolderPermissionScenario(VIEWER, models.PERMISSION_ADMIN, FULL_ACCESS) 77 sc.parentFolderPermissionScenario(VIEWER, models.PERMISSION_EDIT, FULL_ACCESS) 78 sc.parentFolderPermissionScenario(VIEWER, models.PERMISSION_VIEW, FULL_ACCESS) 79 }) 80} 81 82func TestGuardianEditor(t *testing.T) { 83 orgRoleScenario("Given user has editor org role", t, models.ROLE_EDITOR, func(sc *scenarioContext) { 84 // dashboard has default permissions 85 sc.defaultPermissionScenario(USER, EDITOR_ACCESS) 86 87 // dashboard has user with permission 88 sc.dashboardPermissionScenario(USER, models.PERMISSION_ADMIN, FULL_ACCESS) 89 sc.dashboardPermissionScenario(USER, models.PERMISSION_EDIT, EDITOR_ACCESS) 90 sc.dashboardPermissionScenario(USER, models.PERMISSION_VIEW, CAN_VIEW) 91 92 // dashboard has team with permission 93 sc.dashboardPermissionScenario(TEAM, models.PERMISSION_ADMIN, FULL_ACCESS) 94 sc.dashboardPermissionScenario(TEAM, models.PERMISSION_EDIT, EDITOR_ACCESS) 95 sc.dashboardPermissionScenario(TEAM, models.PERMISSION_VIEW, CAN_VIEW) 96 97 // dashboard has editor role with permission 98 sc.dashboardPermissionScenario(EDITOR, models.PERMISSION_ADMIN, FULL_ACCESS) 99 sc.dashboardPermissionScenario(EDITOR, models.PERMISSION_EDIT, EDITOR_ACCESS) 100 sc.dashboardPermissionScenario(EDITOR, models.PERMISSION_VIEW, VIEWER_ACCESS) 101 102 // dashboard has viewer role with permission 103 sc.dashboardPermissionScenario(VIEWER, models.PERMISSION_ADMIN, NO_ACCESS) 104 sc.dashboardPermissionScenario(VIEWER, models.PERMISSION_EDIT, NO_ACCESS) 105 sc.dashboardPermissionScenario(VIEWER, models.PERMISSION_VIEW, NO_ACCESS) 106 107 // parent folder has user with permission 108 sc.parentFolderPermissionScenario(USER, models.PERMISSION_ADMIN, FULL_ACCESS) 109 sc.parentFolderPermissionScenario(USER, models.PERMISSION_EDIT, EDITOR_ACCESS) 110 sc.parentFolderPermissionScenario(USER, models.PERMISSION_VIEW, VIEWER_ACCESS) 111 112 // parent folder has team with permission 113 sc.parentFolderPermissionScenario(TEAM, models.PERMISSION_ADMIN, FULL_ACCESS) 114 sc.parentFolderPermissionScenario(TEAM, models.PERMISSION_EDIT, EDITOR_ACCESS) 115 sc.parentFolderPermissionScenario(TEAM, models.PERMISSION_VIEW, VIEWER_ACCESS) 116 117 // parent folder has editor role with permission 118 sc.parentFolderPermissionScenario(EDITOR, models.PERMISSION_ADMIN, FULL_ACCESS) 119 sc.parentFolderPermissionScenario(EDITOR, models.PERMISSION_EDIT, EDITOR_ACCESS) 120 sc.parentFolderPermissionScenario(EDITOR, models.PERMISSION_VIEW, VIEWER_ACCESS) 121 122 // parent folder has viewer role with permission 123 sc.parentFolderPermissionScenario(VIEWER, models.PERMISSION_ADMIN, NO_ACCESS) 124 sc.parentFolderPermissionScenario(VIEWER, models.PERMISSION_EDIT, NO_ACCESS) 125 sc.parentFolderPermissionScenario(VIEWER, models.PERMISSION_VIEW, NO_ACCESS) 126 }) 127} 128 129func TestGuardianViewer(t *testing.T) { 130 orgRoleScenario("Given user has viewer org role", t, models.ROLE_VIEWER, func(sc *scenarioContext) { 131 // dashboard has default permissions 132 sc.defaultPermissionScenario(USER, VIEWER_ACCESS) 133 134 // dashboard has user with permission 135 sc.dashboardPermissionScenario(USER, models.PERMISSION_ADMIN, FULL_ACCESS) 136 sc.dashboardPermissionScenario(USER, models.PERMISSION_EDIT, EDITOR_ACCESS) 137 sc.dashboardPermissionScenario(USER, models.PERMISSION_VIEW, VIEWER_ACCESS) 138 139 // dashboard has team with permission 140 sc.dashboardPermissionScenario(TEAM, models.PERMISSION_ADMIN, FULL_ACCESS) 141 sc.dashboardPermissionScenario(TEAM, models.PERMISSION_EDIT, EDITOR_ACCESS) 142 sc.dashboardPermissionScenario(TEAM, models.PERMISSION_VIEW, VIEWER_ACCESS) 143 144 // dashboard has editor role with permission 145 sc.dashboardPermissionScenario(EDITOR, models.PERMISSION_ADMIN, NO_ACCESS) 146 sc.dashboardPermissionScenario(EDITOR, models.PERMISSION_EDIT, NO_ACCESS) 147 sc.dashboardPermissionScenario(EDITOR, models.PERMISSION_VIEW, NO_ACCESS) 148 149 // dashboard has viewer role with permission 150 sc.dashboardPermissionScenario(VIEWER, models.PERMISSION_ADMIN, FULL_ACCESS) 151 sc.dashboardPermissionScenario(VIEWER, models.PERMISSION_EDIT, EDITOR_ACCESS) 152 sc.dashboardPermissionScenario(VIEWER, models.PERMISSION_VIEW, VIEWER_ACCESS) 153 154 // parent folder has user with permission 155 sc.parentFolderPermissionScenario(USER, models.PERMISSION_ADMIN, FULL_ACCESS) 156 sc.parentFolderPermissionScenario(USER, models.PERMISSION_EDIT, EDITOR_ACCESS) 157 sc.parentFolderPermissionScenario(USER, models.PERMISSION_VIEW, VIEWER_ACCESS) 158 159 // parent folder has team with permission 160 sc.parentFolderPermissionScenario(TEAM, models.PERMISSION_ADMIN, FULL_ACCESS) 161 sc.parentFolderPermissionScenario(TEAM, models.PERMISSION_EDIT, EDITOR_ACCESS) 162 sc.parentFolderPermissionScenario(TEAM, models.PERMISSION_VIEW, VIEWER_ACCESS) 163 164 // parent folder has editor role with permission 165 sc.parentFolderPermissionScenario(EDITOR, models.PERMISSION_ADMIN, NO_ACCESS) 166 sc.parentFolderPermissionScenario(EDITOR, models.PERMISSION_EDIT, NO_ACCESS) 167 sc.parentFolderPermissionScenario(EDITOR, models.PERMISSION_VIEW, NO_ACCESS) 168 169 // parent folder has viewer role with permission 170 sc.parentFolderPermissionScenario(VIEWER, models.PERMISSION_ADMIN, FULL_ACCESS) 171 sc.parentFolderPermissionScenario(VIEWER, models.PERMISSION_EDIT, EDITOR_ACCESS) 172 sc.parentFolderPermissionScenario(VIEWER, models.PERMISSION_VIEW, VIEWER_ACCESS) 173 }) 174 175 apiKeyScenario("Given api key with viewer role", t, models.ROLE_VIEWER, func(sc *scenarioContext) { 176 // dashboard has default permissions 177 sc.defaultPermissionScenario(VIEWER, VIEWER_ACCESS) 178 }) 179} 180 181func (sc *scenarioContext) defaultPermissionScenario(pt permissionType, flag permissionFlags) { 182 _, callerFile, callerLine, _ := runtime.Caller(1) 183 sc.callerFile = callerFile 184 sc.callerLine = callerLine 185 existingPermissions := []*models.DashboardAclInfoDTO{ 186 toDto(newEditorRolePermission(defaultDashboardID, models.PERMISSION_EDIT)), 187 toDto(newViewerRolePermission(defaultDashboardID, models.PERMISSION_VIEW)), 188 } 189 190 permissionScenario("and existing permissions are the default permissions (everyone with editor role can edit, everyone with viewer role can view)", 191 dashboardID, sc, existingPermissions, func(sc *scenarioContext) { 192 sc.expectedFlags = flag 193 sc.verifyExpectedPermissionsFlags() 194 sc.verifyDuplicatePermissionsShouldNotBeAllowed() 195 sc.verifyUpdateDashboardPermissionsShouldBeAllowed(pt) 196 sc.verifyUpdateDashboardPermissionsShouldNotBeAllowed(pt) 197 }) 198} 199 200func (sc *scenarioContext) dashboardPermissionScenario(pt permissionType, permission models.PermissionType, flag permissionFlags) { 201 _, callerFile, callerLine, _ := runtime.Caller(1) 202 sc.callerFile = callerFile 203 sc.callerLine = callerLine 204 var existingPermissions []*models.DashboardAclInfoDTO 205 206 switch pt { 207 case USER: 208 existingPermissions = []*models.DashboardAclInfoDTO{{OrgId: orgID, DashboardId: dashboardID, UserId: userID, Permission: permission}} 209 case TEAM: 210 existingPermissions = []*models.DashboardAclInfoDTO{{OrgId: orgID, DashboardId: dashboardID, TeamId: teamID, Permission: permission}} 211 case EDITOR: 212 existingPermissions = []*models.DashboardAclInfoDTO{{OrgId: orgID, DashboardId: dashboardID, Role: &editorRole, Permission: permission}} 213 case VIEWER: 214 existingPermissions = []*models.DashboardAclInfoDTO{{OrgId: orgID, DashboardId: dashboardID, Role: &viewerRole, Permission: permission}} 215 } 216 217 permissionScenario(fmt.Sprintf("and %s has permission to %s dashboard", pt.String(), permission.String()), 218 dashboardID, sc, existingPermissions, func(sc *scenarioContext) { 219 sc.expectedFlags = flag 220 sc.verifyExpectedPermissionsFlags() 221 sc.verifyDuplicatePermissionsShouldNotBeAllowed() 222 sc.verifyUpdateDashboardPermissionsShouldBeAllowed(pt) 223 sc.verifyUpdateDashboardPermissionsShouldNotBeAllowed(pt) 224 }) 225} 226 227func (sc *scenarioContext) parentFolderPermissionScenario(pt permissionType, permission models.PermissionType, flag permissionFlags) { 228 _, callerFile, callerLine, _ := runtime.Caller(1) 229 sc.callerFile = callerFile 230 sc.callerLine = callerLine 231 var folderPermissionList []*models.DashboardAclInfoDTO 232 233 switch pt { 234 case USER: 235 folderPermissionList = []*models.DashboardAclInfoDTO{{OrgId: orgID, DashboardId: parentFolderID, 236 UserId: userID, Permission: permission, Inherited: true}} 237 case TEAM: 238 folderPermissionList = []*models.DashboardAclInfoDTO{{OrgId: orgID, DashboardId: parentFolderID, TeamId: teamID, 239 Permission: permission, Inherited: true}} 240 case EDITOR: 241 folderPermissionList = []*models.DashboardAclInfoDTO{{OrgId: orgID, DashboardId: parentFolderID, 242 Role: &editorRole, Permission: permission, Inherited: true}} 243 case VIEWER: 244 folderPermissionList = []*models.DashboardAclInfoDTO{{OrgId: orgID, DashboardId: parentFolderID, 245 Role: &viewerRole, Permission: permission, Inherited: true}} 246 } 247 248 permissionScenario(fmt.Sprintf("and parent folder has %s with permission to %s", pt.String(), permission.String()), 249 childDashboardID, sc, folderPermissionList, func(sc *scenarioContext) { 250 sc.expectedFlags = flag 251 sc.verifyExpectedPermissionsFlags() 252 sc.verifyDuplicatePermissionsShouldNotBeAllowed() 253 sc.verifyUpdateChildDashboardPermissionsShouldBeAllowed(pt, permission) 254 sc.verifyUpdateChildDashboardPermissionsShouldNotBeAllowed(pt, permission) 255 sc.verifyUpdateChildDashboardPermissionsWithOverrideShouldBeAllowed(pt, permission) 256 sc.verifyUpdateChildDashboardPermissionsWithOverrideShouldNotBeAllowed(pt, permission) 257 }) 258} 259 260func (sc *scenarioContext) verifyExpectedPermissionsFlags() { 261 tc := fmt.Sprintf("should have permissions to %s", sc.expectedFlags.String()) 262 sc.t.Run(tc, func(t *testing.T) { 263 canAdmin, err := sc.g.CanAdmin() 264 require.NoError(t, err) 265 canEdit, err := sc.g.CanEdit() 266 require.NoError(t, err) 267 canSave, err := sc.g.CanSave() 268 require.NoError(t, err) 269 canView, err := sc.g.CanView() 270 require.NoError(t, err) 271 272 var actualFlag permissionFlags 273 274 if canAdmin { 275 actualFlag |= CAN_ADMIN 276 } 277 278 if canEdit { 279 actualFlag |= CAN_EDIT 280 } 281 282 if canSave { 283 actualFlag |= CAN_SAVE 284 } 285 286 if canView { 287 actualFlag |= CAN_VIEW 288 } 289 290 if actualFlag.noAccess() { 291 actualFlag = NO_ACCESS 292 } 293 294 if actualFlag&sc.expectedFlags != actualFlag { 295 sc.reportFailure(tc, sc.expectedFlags.String(), actualFlag.String()) 296 } 297 298 sc.reportSuccess() 299 }) 300} 301 302func (sc *scenarioContext) verifyDuplicatePermissionsShouldNotBeAllowed() { 303 if !sc.expectedFlags.canAdmin() { 304 return 305 } 306 307 tc := "When updating dashboard permissions with duplicate permission for user should not be allowed" 308 sc.t.Run(tc, func(t *testing.T) { 309 p := []*models.DashboardAcl{ 310 newDefaultUserPermission(dashboardID, models.PERMISSION_VIEW), 311 newDefaultUserPermission(dashboardID, models.PERMISSION_ADMIN), 312 } 313 sc.updatePermissions = p 314 _, err := sc.g.CheckPermissionBeforeUpdate(models.PERMISSION_ADMIN, p) 315 316 if !errors.Is(err, ErrGuardianPermissionExists) { 317 sc.reportFailure(tc, ErrGuardianPermissionExists, err) 318 } 319 sc.reportSuccess() 320 }) 321 322 tc = "When updating dashboard permissions with duplicate permission for team should not be allowed" 323 sc.t.Run(tc, func(t *testing.T) { 324 p := []*models.DashboardAcl{ 325 newDefaultTeamPermission(dashboardID, models.PERMISSION_VIEW), 326 newDefaultTeamPermission(dashboardID, models.PERMISSION_ADMIN), 327 } 328 sc.updatePermissions = p 329 _, err := sc.g.CheckPermissionBeforeUpdate(models.PERMISSION_ADMIN, p) 330 if !errors.Is(err, ErrGuardianPermissionExists) { 331 sc.reportFailure(tc, ErrGuardianPermissionExists, err) 332 } 333 sc.reportSuccess() 334 }) 335 336 tc = "When updating dashboard permissions with duplicate permission for editor role should not be allowed" 337 sc.t.Run(tc, func(t *testing.T) { 338 p := []*models.DashboardAcl{ 339 newEditorRolePermission(dashboardID, models.PERMISSION_VIEW), 340 newEditorRolePermission(dashboardID, models.PERMISSION_ADMIN), 341 } 342 sc.updatePermissions = p 343 _, err := sc.g.CheckPermissionBeforeUpdate(models.PERMISSION_ADMIN, p) 344 345 if !errors.Is(err, ErrGuardianPermissionExists) { 346 sc.reportFailure(tc, ErrGuardianPermissionExists, err) 347 } 348 sc.reportSuccess() 349 }) 350 351 tc = "When updating dashboard permissions with duplicate permission for viewer role should not be allowed" 352 sc.t.Run(tc, func(t *testing.T) { 353 p := []*models.DashboardAcl{ 354 newViewerRolePermission(dashboardID, models.PERMISSION_VIEW), 355 newViewerRolePermission(dashboardID, models.PERMISSION_ADMIN), 356 } 357 sc.updatePermissions = p 358 _, err := sc.g.CheckPermissionBeforeUpdate(models.PERMISSION_ADMIN, p) 359 if !errors.Is(err, ErrGuardianPermissionExists) { 360 sc.reportFailure(tc, ErrGuardianPermissionExists, err) 361 } 362 sc.reportSuccess() 363 }) 364 365 tc = "When updating dashboard permissions with duplicate permission for admin role should not be allowed" 366 sc.t.Run(tc, func(t *testing.T) { 367 p := []*models.DashboardAcl{ 368 newAdminRolePermission(dashboardID, models.PERMISSION_ADMIN), 369 } 370 sc.updatePermissions = p 371 _, err := sc.g.CheckPermissionBeforeUpdate(models.PERMISSION_ADMIN, p) 372 if !errors.Is(err, ErrGuardianPermissionExists) { 373 sc.reportFailure(tc, ErrGuardianPermissionExists, err) 374 } 375 sc.reportSuccess() 376 }) 377} 378 379func (sc *scenarioContext) verifyUpdateDashboardPermissionsShouldBeAllowed(pt permissionType) { 380 if !sc.expectedFlags.canAdmin() { 381 return 382 } 383 384 for _, p := range []models.PermissionType{models.PERMISSION_ADMIN, models.PERMISSION_EDIT, models.PERMISSION_VIEW} { 385 tc := fmt.Sprintf("When updating dashboard permissions with %s permissions should be allowed", p.String()) 386 sc.t.Run(tc, func(t *testing.T) { 387 permissionList := []*models.DashboardAcl{} 388 switch pt { 389 case USER: 390 permissionList = []*models.DashboardAcl{ 391 newEditorRolePermission(dashboardID, p), 392 newViewerRolePermission(dashboardID, p), 393 newCustomUserPermission(dashboardID, otherUserID, p), 394 newDefaultTeamPermission(dashboardID, p), 395 } 396 case TEAM: 397 permissionList = []*models.DashboardAcl{ 398 newEditorRolePermission(dashboardID, p), 399 newViewerRolePermission(dashboardID, p), 400 newDefaultUserPermission(dashboardID, p), 401 newCustomTeamPermission(dashboardID, otherTeamID, p), 402 } 403 case EDITOR, VIEWER: 404 permissionList = []*models.DashboardAcl{ 405 newEditorRolePermission(dashboardID, p), 406 newViewerRolePermission(dashboardID, p), 407 newDefaultUserPermission(dashboardID, p), 408 newDefaultTeamPermission(dashboardID, p), 409 } 410 } 411 412 sc.updatePermissions = permissionList 413 ok, err := sc.g.CheckPermissionBeforeUpdate(models.PERMISSION_ADMIN, permissionList) 414 if err != nil { 415 sc.reportFailure(tc, nil, err) 416 } 417 if !ok { 418 sc.reportFailure(tc, false, true) 419 } 420 sc.reportSuccess() 421 }) 422 } 423} 424 425func (sc *scenarioContext) verifyUpdateDashboardPermissionsShouldNotBeAllowed(pt permissionType) { 426 if sc.expectedFlags.canAdmin() { 427 return 428 } 429 430 for _, p := range []models.PermissionType{models.PERMISSION_ADMIN, models.PERMISSION_EDIT, models.PERMISSION_VIEW} { 431 tc := fmt.Sprintf("When updating dashboard permissions with %s permissions should NOT be allowed", p.String()) 432 sc.t.Run(tc, func(t *testing.T) { 433 permissionList := []*models.DashboardAcl{ 434 newEditorRolePermission(dashboardID, p), 435 newViewerRolePermission(dashboardID, p), 436 } 437 switch pt { 438 case USER: 439 permissionList = append(permissionList, []*models.DashboardAcl{ 440 newCustomUserPermission(dashboardID, otherUserID, p), 441 newDefaultTeamPermission(dashboardID, p), 442 }...) 443 case TEAM: 444 permissionList = append(permissionList, []*models.DashboardAcl{ 445 newDefaultUserPermission(dashboardID, p), 446 newCustomTeamPermission(dashboardID, otherTeamID, p), 447 }...) 448 default: 449 // TODO: Handle other cases? 450 } 451 452 sc.updatePermissions = permissionList 453 ok, err := sc.g.CheckPermissionBeforeUpdate(models.PERMISSION_ADMIN, permissionList) 454 if err != nil { 455 sc.reportFailure(tc, nil, err) 456 } 457 if ok { 458 sc.reportFailure(tc, true, false) 459 } 460 sc.reportSuccess() 461 }) 462 } 463} 464 465func (sc *scenarioContext) verifyUpdateChildDashboardPermissionsShouldBeAllowed(pt permissionType, parentFolderPermission models.PermissionType) { 466 if !sc.expectedFlags.canAdmin() { 467 return 468 } 469 470 for _, p := range []models.PermissionType{models.PERMISSION_ADMIN, models.PERMISSION_EDIT, models.PERMISSION_VIEW} { 471 tc := fmt.Sprintf("When updating child dashboard permissions with %s permissions should be allowed", p.String()) 472 sc.t.Run(tc, func(t *testing.T) { 473 permissionList := []*models.DashboardAcl{} 474 switch pt { 475 case USER: 476 permissionList = []*models.DashboardAcl{ 477 newEditorRolePermission(childDashboardID, p), 478 newViewerRolePermission(childDashboardID, p), 479 newCustomUserPermission(childDashboardID, otherUserID, p), 480 newDefaultTeamPermission(childDashboardID, p), 481 } 482 case TEAM: 483 permissionList = []*models.DashboardAcl{ 484 newEditorRolePermission(childDashboardID, p), 485 newViewerRolePermission(childDashboardID, p), 486 newDefaultUserPermission(childDashboardID, p), 487 newCustomTeamPermission(childDashboardID, otherTeamID, p), 488 } 489 case EDITOR: 490 permissionList = []*models.DashboardAcl{ 491 newViewerRolePermission(childDashboardID, p), 492 newDefaultUserPermission(childDashboardID, p), 493 newDefaultTeamPermission(childDashboardID, p), 494 } 495 496 // permission to update is higher than parent folder permission 497 if p > parentFolderPermission { 498 permissionList = append(permissionList, newEditorRolePermission(childDashboardID, p)) 499 } 500 case VIEWER: 501 permissionList = []*models.DashboardAcl{ 502 newEditorRolePermission(childDashboardID, p), 503 newDefaultUserPermission(childDashboardID, p), 504 newDefaultTeamPermission(childDashboardID, p), 505 } 506 507 // permission to update is higher than parent folder permission 508 if p > parentFolderPermission { 509 permissionList = append(permissionList, newViewerRolePermission(childDashboardID, p)) 510 } 511 } 512 513 sc.updatePermissions = permissionList 514 ok, err := sc.g.CheckPermissionBeforeUpdate(models.PERMISSION_ADMIN, permissionList) 515 if err != nil { 516 sc.reportFailure(tc, nil, err) 517 } 518 if !ok { 519 sc.reportFailure(tc, false, true) 520 } 521 sc.reportSuccess() 522 }) 523 } 524} 525 526func (sc *scenarioContext) verifyUpdateChildDashboardPermissionsShouldNotBeAllowed(pt permissionType, parentFolderPermission models.PermissionType) { 527 if sc.expectedFlags.canAdmin() { 528 return 529 } 530 531 for _, p := range []models.PermissionType{models.PERMISSION_ADMIN, models.PERMISSION_EDIT, models.PERMISSION_VIEW} { 532 tc := fmt.Sprintf("When updating child dashboard permissions with %s permissions should NOT be allowed", p.String()) 533 sc.t.Run(tc, func(t *testing.T) { 534 permissionList := []*models.DashboardAcl{} 535 switch pt { 536 case USER: 537 permissionList = []*models.DashboardAcl{ 538 newEditorRolePermission(childDashboardID, p), 539 newViewerRolePermission(childDashboardID, p), 540 newCustomUserPermission(childDashboardID, otherUserID, p), 541 newDefaultTeamPermission(childDashboardID, p), 542 } 543 case TEAM: 544 permissionList = []*models.DashboardAcl{ 545 newEditorRolePermission(childDashboardID, p), 546 newViewerRolePermission(childDashboardID, p), 547 newDefaultUserPermission(childDashboardID, p), 548 newCustomTeamPermission(childDashboardID, otherTeamID, p), 549 } 550 case EDITOR: 551 permissionList = []*models.DashboardAcl{ 552 newViewerRolePermission(childDashboardID, p), 553 newDefaultUserPermission(childDashboardID, p), 554 newDefaultTeamPermission(childDashboardID, p), 555 } 556 557 // permission to update is higher than parent folder permission 558 if p > parentFolderPermission { 559 permissionList = append(permissionList, newEditorRolePermission(childDashboardID, p)) 560 } 561 case VIEWER: 562 permissionList = []*models.DashboardAcl{ 563 newEditorRolePermission(childDashboardID, p), 564 newDefaultUserPermission(childDashboardID, p), 565 newDefaultTeamPermission(childDashboardID, p), 566 } 567 568 // permission to update is higher than parent folder permission 569 if p > parentFolderPermission { 570 permissionList = append(permissionList, newViewerRolePermission(childDashboardID, p)) 571 } 572 } 573 574 sc.updatePermissions = permissionList 575 ok, err := sc.g.CheckPermissionBeforeUpdate(models.PERMISSION_ADMIN, permissionList) 576 if err != nil { 577 sc.reportFailure(tc, nil, err) 578 } 579 if ok { 580 sc.reportFailure(tc, true, false) 581 } 582 sc.reportSuccess() 583 }) 584 } 585} 586 587func (sc *scenarioContext) verifyUpdateChildDashboardPermissionsWithOverrideShouldBeAllowed(pt permissionType, parentFolderPermission models.PermissionType) { 588 if !sc.expectedFlags.canAdmin() { 589 return 590 } 591 592 for _, p := range []models.PermissionType{models.PERMISSION_ADMIN, models.PERMISSION_EDIT, models.PERMISSION_VIEW} { 593 // permission to update is higher than parent folder permission 594 if p > parentFolderPermission { 595 continue 596 } 597 598 tc := fmt.Sprintf("When updating child dashboard permissions overriding parent %s permission with %s permission should NOT be allowed", pt.String(), p.String()) 599 sc.t.Run(tc, func(t *testing.T) { 600 permissionList := []*models.DashboardAcl{} 601 switch pt { 602 case USER: 603 permissionList = []*models.DashboardAcl{ 604 newDefaultUserPermission(childDashboardID, p), 605 } 606 case TEAM: 607 permissionList = []*models.DashboardAcl{ 608 newDefaultTeamPermission(childDashboardID, p), 609 } 610 case EDITOR: 611 permissionList = []*models.DashboardAcl{ 612 newEditorRolePermission(childDashboardID, p), 613 } 614 case VIEWER: 615 permissionList = []*models.DashboardAcl{ 616 newViewerRolePermission(childDashboardID, p), 617 } 618 } 619 620 sc.updatePermissions = permissionList 621 _, err := sc.g.CheckPermissionBeforeUpdate(models.PERMISSION_ADMIN, permissionList) 622 if !errors.Is(err, ErrGuardianOverride) { 623 sc.reportFailure(tc, ErrGuardianOverride, err) 624 } 625 sc.reportSuccess() 626 }) 627 } 628} 629 630func (sc *scenarioContext) verifyUpdateChildDashboardPermissionsWithOverrideShouldNotBeAllowed(pt permissionType, parentFolderPermission models.PermissionType) { 631 if !sc.expectedFlags.canAdmin() { 632 return 633 } 634 635 for _, p := range []models.PermissionType{models.PERMISSION_ADMIN, models.PERMISSION_EDIT, models.PERMISSION_VIEW} { 636 // permission to update is lower than or equal to parent folder permission 637 if p <= parentFolderPermission { 638 continue 639 } 640 641 tc := fmt.Sprintf( 642 "When updating child dashboard permissions overriding parent %s permission with %s permission should be allowed", 643 pt.String(), p.String(), 644 ) 645 sc.t.Run(tc, func(t *testing.T) { 646 permissionList := []*models.DashboardAcl{} 647 switch pt { 648 case USER: 649 permissionList = []*models.DashboardAcl{ 650 newDefaultUserPermission(childDashboardID, p), 651 } 652 case TEAM: 653 permissionList = []*models.DashboardAcl{ 654 newDefaultTeamPermission(childDashboardID, p), 655 } 656 case EDITOR: 657 permissionList = []*models.DashboardAcl{ 658 newEditorRolePermission(childDashboardID, p), 659 } 660 case VIEWER: 661 permissionList = []*models.DashboardAcl{ 662 newViewerRolePermission(childDashboardID, p), 663 } 664 } 665 666 _, err := sc.g.CheckPermissionBeforeUpdate(models.PERMISSION_ADMIN, permissionList) 667 if err != nil { 668 sc.reportFailure(tc, nil, err) 669 } 670 sc.updatePermissions = permissionList 671 ok, err := sc.g.CheckPermissionBeforeUpdate(models.PERMISSION_ADMIN, permissionList) 672 if err != nil { 673 sc.reportFailure(tc, nil, err) 674 } 675 if !ok { 676 sc.reportFailure(tc, false, true) 677 } 678 sc.reportSuccess() 679 }) 680 } 681} 682 683func TestGuardianGetHiddenACL(t *testing.T) { 684 t.Run("Get hidden ACL tests", func(t *testing.T) { 685 bus.ClearBusHandlers() 686 687 bus.AddHandler("test", func(query *models.GetDashboardAclInfoListQuery) error { 688 query.Result = []*models.DashboardAclInfoDTO{ 689 {Inherited: false, UserId: 1, UserLogin: "user1", Permission: models.PERMISSION_EDIT}, 690 {Inherited: false, UserId: 2, UserLogin: "user2", Permission: models.PERMISSION_ADMIN}, 691 {Inherited: true, UserId: 3, UserLogin: "user3", Permission: models.PERMISSION_VIEW}, 692 } 693 return nil 694 }) 695 696 cfg := setting.NewCfg() 697 cfg.HiddenUsers = map[string]struct{}{"user2": {}} 698 699 t.Run("Should get hidden acl", func(t *testing.T) { 700 user := &models.SignedInUser{ 701 OrgId: orgID, 702 UserId: 1, 703 Login: "user1", 704 } 705 g := New(context.Background(), dashboardID, orgID, user) 706 707 hiddenACL, err := g.GetHiddenACL(cfg) 708 require.NoError(t, err) 709 710 require.Equal(t, len(hiddenACL), 1) 711 require.Equal(t, hiddenACL[0].UserID, int64(2)) 712 }) 713 714 t.Run("Grafana admin should not get hidden acl", func(t *testing.T) { 715 user := &models.SignedInUser{ 716 OrgId: orgID, 717 UserId: 1, 718 Login: "user1", 719 IsGrafanaAdmin: true, 720 } 721 g := New(context.Background(), dashboardID, orgID, user) 722 723 hiddenACL, err := g.GetHiddenACL(cfg) 724 require.NoError(t, err) 725 726 require.Equal(t, len(hiddenACL), 0) 727 }) 728 }) 729} 730 731func TestGuardianGetAclWithoutDuplicates(t *testing.T) { 732 t.Run("Get hidden ACL tests", func(t *testing.T) { 733 t.Cleanup(bus.ClearBusHandlers) 734 735 bus.AddHandler("test", func(query *models.GetDashboardAclInfoListQuery) error { 736 query.Result = []*models.DashboardAclInfoDTO{ 737 {Inherited: true, UserId: 3, UserLogin: "user3", Permission: models.PERMISSION_EDIT}, 738 {Inherited: false, UserId: 3, UserLogin: "user3", Permission: models.PERMISSION_VIEW}, 739 {Inherited: false, UserId: 2, UserLogin: "user2", Permission: models.PERMISSION_ADMIN}, 740 {Inherited: true, UserId: 4, UserLogin: "user4", Permission: models.PERMISSION_ADMIN}, 741 {Inherited: false, UserId: 4, UserLogin: "user4", Permission: models.PERMISSION_ADMIN}, 742 {Inherited: false, UserId: 5, UserLogin: "user5", Permission: models.PERMISSION_EDIT}, 743 {Inherited: true, UserId: 6, UserLogin: "user6", Permission: models.PERMISSION_VIEW}, 744 {Inherited: false, UserId: 6, UserLogin: "user6", Permission: models.PERMISSION_EDIT}, 745 } 746 return nil 747 }) 748 749 t.Run("Should get acl without duplicates", func(t *testing.T) { 750 user := &models.SignedInUser{ 751 OrgId: orgID, 752 UserId: 1, 753 Login: "user1", 754 } 755 g := New(context.Background(), dashboardID, orgID, user) 756 757 acl, err := g.GetACLWithoutDuplicates() 758 require.NoError(t, err) 759 require.NotNil(t, acl) 760 require.Len(t, acl, 6) 761 require.ElementsMatch(t, []*models.DashboardAclInfoDTO{ 762 {Inherited: true, UserId: 3, UserLogin: "user3", Permission: models.PERMISSION_EDIT}, 763 {Inherited: true, UserId: 4, UserLogin: "user4", Permission: models.PERMISSION_ADMIN}, 764 {Inherited: true, UserId: 6, UserLogin: "user6", Permission: models.PERMISSION_VIEW}, 765 {Inherited: false, UserId: 2, UserLogin: "user2", Permission: models.PERMISSION_ADMIN}, 766 {Inherited: false, UserId: 5, UserLogin: "user5", Permission: models.PERMISSION_EDIT}, 767 {Inherited: false, UserId: 6, UserLogin: "user6", Permission: models.PERMISSION_EDIT}, 768 }, acl) 769 }) 770 }) 771} 772