2020-11-24 05:10:32 -06:00
package api
import (
2021-05-12 07:10:35 -05:00
"context"
2020-11-24 05:10:32 -06:00
"encoding/json"
2021-11-17 03:12:28 -06:00
"fmt"
2023-02-02 08:33:25 -06:00
"io"
2020-11-24 05:10:32 -06:00
"net/http"
2021-11-17 03:12:28 -06:00
"strings"
2020-11-24 05:10:32 -06:00
"testing"
2021-11-17 03:12:28 -06:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2021-09-29 05:51:49 -05:00
2020-11-24 05:10:32 -06:00
"github.com/grafana/grafana/pkg/api/dtos"
2022-10-19 08:02:15 -05:00
"github.com/grafana/grafana/pkg/infra/db"
2023-01-18 09:01:25 -06:00
"github.com/grafana/grafana/pkg/infra/db/dbtest"
2023-03-22 12:41:59 -05:00
"github.com/grafana/grafana/pkg/models/roletype"
2021-09-17 02:19:36 -05:00
"github.com/grafana/grafana/pkg/services/accesscontrol"
2023-02-02 08:33:25 -06:00
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
2022-01-26 11:44:20 -06:00
"github.com/grafana/grafana/pkg/services/featuremgmt"
2023-03-22 12:41:59 -05:00
"github.com/grafana/grafana/pkg/services/login"
2023-02-02 08:33:25 -06:00
"github.com/grafana/grafana/pkg/services/login/logintest"
2022-08-10 04:56:48 -05:00
"github.com/grafana/grafana/pkg/services/org"
2022-09-26 03:27:38 -05:00
"github.com/grafana/grafana/pkg/services/org/orgimpl"
"github.com/grafana/grafana/pkg/services/org/orgtest"
2022-12-07 10:03:22 -06:00
"github.com/grafana/grafana/pkg/services/quota/quotaimpl"
2021-05-12 07:10:35 -05:00
"github.com/grafana/grafana/pkg/services/sqlstore"
2023-02-06 10:50:03 -06:00
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
2022-06-28 07:32:25 -05:00
"github.com/grafana/grafana/pkg/services/user"
2022-08-16 09:08:59 -05:00
"github.com/grafana/grafana/pkg/services/user/userimpl"
2023-02-02 08:33:25 -06:00
"github.com/grafana/grafana/pkg/services/user/usertest"
2022-08-11 08:37:31 -05:00
"github.com/grafana/grafana/pkg/setting"
2023-02-02 08:33:25 -06:00
"github.com/grafana/grafana/pkg/web/webtest"
2020-11-24 05:10:32 -06:00
)
2021-05-12 07:10:35 -05:00
func setUpGetOrgUsersDB ( t * testing . T , sqlStore * sqlstore . SQLStore ) {
2022-06-07 08:49:18 -05:00
sqlStore . Cfg . AutoAssignOrg = true
sqlStore . Cfg . AutoAssignOrgId = int ( testOrgID )
2021-05-12 07:10:35 -05:00
2022-12-07 10:03:22 -06:00
quotaService := quotaimpl . ProvideService ( sqlStore , sqlStore . Cfg )
orgService , err := orgimpl . ProvideService ( sqlStore , sqlStore . Cfg , quotaService )
2021-05-12 07:10:35 -05:00
require . NoError ( t , err )
2023-02-06 10:50:03 -06:00
usrSvc , err := userimpl . ProvideService ( sqlStore , orgService , sqlStore . Cfg , nil , nil , quotaService , supportbundlestest . NewFakeBundleService ( ) )
2021-05-12 07:10:35 -05:00
require . NoError ( t , err )
2022-12-07 10:03:22 -06:00
2023-02-24 11:08:44 -06:00
id , err := orgService . GetOrCreate ( context . Background ( ) , "testOrg" )
require . NoError ( t , err )
require . Equal ( t , testOrgID , id )
2022-12-07 10:03:22 -06:00
_ , err = usrSvc . Create ( context . Background ( ) , & user . CreateUserCommand { Email : "testUser@grafana.com" , Login : testUserLogin } )
require . NoError ( t , err )
_ , err = usrSvc . Create ( context . Background ( ) , & user . CreateUserCommand { Email : "user1@grafana.com" , Login : "user1" } )
require . NoError ( t , err )
_ , err = usrSvc . Create ( context . Background ( ) , & user . CreateUserCommand { Email : "user2@grafana.com" , Login : "user2" } )
2021-05-12 07:10:35 -05:00
require . NoError ( t , err )
}
2020-11-24 05:10:32 -06:00
func TestOrgUsersAPIEndpoint_userLoggedIn ( t * testing . T ) {
2022-01-26 11:44:20 -06:00
hs := setupSimpleHTTPServer ( featuremgmt . WithFeatures ( ) )
settings := hs . Cfg
2020-11-24 05:10:32 -06:00
2022-10-19 08:02:15 -05:00
sqlStore := db . InitTestDB ( t )
2022-01-13 07:40:32 -06:00
sqlStore . Cfg = settings
2021-09-27 09:43:16 -05:00
hs . SQLStore = sqlStore
2022-09-26 03:27:38 -05:00
orgService := orgtest . NewOrgServiceFake ( )
2022-09-26 11:53:17 -05:00
orgService . ExpectedSearchOrgUsersResult = & org . SearchOrgUsersQueryResult { }
2022-09-26 03:27:38 -05:00
hs . orgService = orgService
2023-08-09 08:17:59 -05:00
setUpGetOrgUsersDB ( t , sqlStore )
2023-01-18 09:01:25 -06:00
mock := dbtest . NewFakeDB ( )
2023-01-09 02:54:33 -06:00
2022-01-14 10:55:57 -06:00
loggedInUserScenario ( t , "When calling GET on" , "api/org/users" , "api/org/users" , func ( sc * scenarioContext ) {
2023-01-09 02:54:33 -06:00
orgService . ExpectedSearchOrgUsersResult = & org . SearchOrgUsersQueryResult {
OrgUsers : [ ] * org . OrgUserDTO {
{ Login : testUserLogin , Email : "testUser@grafana.com" } ,
{ Login : "user1" , Email : "user1@grafana.com" } ,
{ Login : "user2" , Email : "user2@grafana.com" } ,
} ,
2022-09-26 03:27:38 -05:00
}
2020-11-24 05:10:32 -06:00
sc . handlerFunc = hs . GetOrgUsersForCurrentOrg
sc . fakeReqWithParams ( "GET" , sc . url , map [ string ] string { } ) . exec ( )
require . Equal ( t , http . StatusOK , sc . resp . Code )
2023-01-09 07:39:53 -06:00
var resp [ ] org . OrgUserDTO
2020-11-24 05:10:32 -06:00
err := json . Unmarshal ( sc . resp . Body . Bytes ( ) , & resp )
require . NoError ( t , err )
assert . Len ( t , resp , 3 )
2022-02-03 02:20:20 -06:00
} , mock )
2020-11-24 05:10:32 -06:00
2022-01-14 10:55:57 -06:00
loggedInUserScenario ( t , "When calling GET on" , "api/org/users/search" , "api/org/users/search" , func ( sc * scenarioContext ) {
2022-09-26 11:53:17 -05:00
orgService . ExpectedSearchOrgUsersResult = & org . SearchOrgUsersQueryResult {
OrgUsers : [ ] * org . OrgUserDTO {
{
Login : "user1" ,
} ,
{
Login : "user2" ,
} ,
{
Login : "user3" ,
} ,
} ,
TotalCount : 3 ,
PerPage : 1000 ,
Page : 1 ,
}
2021-11-29 03:18:01 -06:00
sc . handlerFunc = hs . SearchOrgUsersWithPaging
2021-05-12 07:10:35 -05:00
sc . fakeReqWithParams ( "GET" , sc . url , map [ string ] string { } ) . exec ( )
require . Equal ( t , http . StatusOK , sc . resp . Code )
2022-09-26 11:53:17 -05:00
var resp org . SearchOrgUsersQueryResult
2021-05-12 07:10:35 -05:00
err := json . Unmarshal ( sc . resp . Body . Bytes ( ) , & resp )
require . NoError ( t , err )
assert . Len ( t , resp . OrgUsers , 3 )
assert . Equal ( t , int64 ( 3 ) , resp . TotalCount )
assert . Equal ( t , 1000 , resp . PerPage )
assert . Equal ( t , 1 , resp . Page )
2022-02-03 02:20:20 -06:00
} , mock )
2021-05-12 07:10:35 -05:00
2022-01-14 10:55:57 -06:00
loggedInUserScenario ( t , "When calling GET with page and limit query parameters on" , "api/org/users/search" , "api/org/users/search" , func ( sc * scenarioContext ) {
2022-09-26 11:53:17 -05:00
orgService . ExpectedSearchOrgUsersResult = & org . SearchOrgUsersQueryResult {
OrgUsers : [ ] * org . OrgUserDTO {
{
Login : "user1" ,
} ,
} ,
TotalCount : 3 ,
PerPage : 2 ,
Page : 2 ,
}
2021-11-29 03:18:01 -06:00
sc . handlerFunc = hs . SearchOrgUsersWithPaging
2021-05-12 07:10:35 -05:00
sc . fakeReqWithParams ( "GET" , sc . url , map [ string ] string { "perpage" : "2" , "page" : "2" } ) . exec ( )
require . Equal ( t , http . StatusOK , sc . resp . Code )
2022-09-26 11:53:17 -05:00
var resp org . SearchOrgUsersQueryResult
2021-05-12 07:10:35 -05:00
err := json . Unmarshal ( sc . resp . Body . Bytes ( ) , & resp )
require . NoError ( t , err )
assert . Len ( t , resp . OrgUsers , 1 )
assert . Equal ( t , int64 ( 3 ) , resp . TotalCount )
assert . Equal ( t , 2 , resp . PerPage )
assert . Equal ( t , 2 , resp . Page )
2022-02-03 02:20:20 -06:00
} , mock )
2021-05-12 07:10:35 -05:00
2021-09-17 02:19:36 -05:00
t . Run ( "Given there are two hidden users" , func ( t * testing . T ) {
2020-11-24 05:10:32 -06:00
settings . HiddenUsers = map [ string ] struct { } {
"user1" : { } ,
testUserLogin : { } ,
}
t . Cleanup ( func ( ) { settings . HiddenUsers = make ( map [ string ] struct { } ) } )
2022-01-14 10:55:57 -06:00
loggedInUserScenario ( t , "When calling GET on" , "api/org/users" , "api/org/users" , func ( sc * scenarioContext ) {
2023-01-09 02:54:33 -06:00
orgService . ExpectedSearchOrgUsersResult = & org . SearchOrgUsersQueryResult {
OrgUsers : [ ] * org . OrgUserDTO {
{ Login : testUserLogin , Email : "testUser@grafana.com" } ,
{ Login : "user1" , Email : "user1@grafana.com" } ,
{ Login : "user2" , Email : "user2@grafana.com" } ,
} ,
}
2020-11-24 05:10:32 -06:00
sc . handlerFunc = hs . GetOrgUsersForCurrentOrg
sc . fakeReqWithParams ( "GET" , sc . url , map [ string ] string { } ) . exec ( )
require . Equal ( t , http . StatusOK , sc . resp . Code )
2023-01-09 07:39:53 -06:00
var resp [ ] org . OrgUserDTO
2020-11-24 05:10:32 -06:00
err := json . Unmarshal ( sc . resp . Body . Bytes ( ) , & resp )
require . NoError ( t , err )
assert . Len ( t , resp , 2 )
assert . Equal ( t , testUserLogin , resp [ 0 ] . Login )
assert . Equal ( t , "user2" , resp [ 1 ] . Login )
2022-02-03 02:20:20 -06:00
} , mock )
2020-11-24 05:10:32 -06:00
loggedInUserScenarioWithRole ( t , "When calling GET as an admin on" , "GET" , "api/org/users/lookup" ,
2022-08-10 04:56:48 -05:00
"api/org/users/lookup" , org . RoleAdmin , func ( sc * scenarioContext ) {
2020-11-24 05:10:32 -06:00
sc . handlerFunc = hs . GetOrgUsersForCurrentOrgLookup
sc . fakeReqWithParams ( "GET" , sc . url , map [ string ] string { } ) . exec ( )
require . Equal ( t , http . StatusOK , sc . resp . Code )
var resp [ ] dtos . UserLookupDTO
err := json . Unmarshal ( sc . resp . Body . Bytes ( ) , & resp )
require . NoError ( t , err )
assert . Len ( t , resp , 2 )
assert . Equal ( t , testUserLogin , resp [ 0 ] . Login )
assert . Equal ( t , "user2" , resp [ 1 ] . Login )
2022-02-03 02:20:20 -06:00
} , mock )
2020-11-24 05:10:32 -06:00
} )
}
2021-09-17 02:19:36 -05:00
2023-03-22 12:41:59 -05:00
func TestOrgUsersAPIEndpoint_updateOrgRole ( t * testing . T ) {
type testCase struct {
2023-07-25 07:27:02 -05:00
desc string
SkipOrgRoleSync bool
GcomOnlyExternalOrgRoleSync bool
AuthEnabled bool
AuthModule string
expectedCode int
2023-03-22 12:41:59 -05:00
}
permissions := [ ] accesscontrol . Permission {
{ Action : accesscontrol . ActionOrgUsersRead , Scope : "users:*" } ,
{ Action : accesscontrol . ActionOrgUsersWrite , Scope : "users:*" } ,
{ Action : accesscontrol . ActionOrgUsersAdd , Scope : "users:*" } ,
{ Action : accesscontrol . ActionOrgUsersRemove , Scope : "users:*" } ,
}
tests := [ ] testCase {
{
desc : "should be able to change basicRole when skip_org_role_sync true" ,
SkipOrgRoleSync : true ,
AuthEnabled : true ,
AuthModule : login . LDAPAuthModule ,
expectedCode : http . StatusOK ,
} ,
{
desc : "should not be able to change basicRole when skip_org_role_sync false" ,
SkipOrgRoleSync : false ,
AuthEnabled : true ,
AuthModule : login . LDAPAuthModule ,
expectedCode : http . StatusForbidden ,
} ,
{
desc : "should not be able to change basicRole with a different provider" ,
SkipOrgRoleSync : false ,
AuthEnabled : true ,
AuthModule : login . GenericOAuthModule ,
expectedCode : http . StatusForbidden ,
} ,
2023-07-25 07:27:02 -05:00
{
desc : "should be able to change basicRole for a user synced through GCom if GcomOnlyExternalOrgRoleSync flag is set to false" ,
SkipOrgRoleSync : false ,
GcomOnlyExternalOrgRoleSync : false ,
AuthEnabled : true ,
AuthModule : login . GrafanaComAuthModule ,
expectedCode : http . StatusOK ,
} ,
{
desc : "should not be able to change basicRole for a user synced through GCom if GcomOnlyExternalOrgRoleSync flag is set to true" ,
SkipOrgRoleSync : false ,
GcomOnlyExternalOrgRoleSync : true ,
AuthEnabled : true ,
AuthModule : login . GrafanaComAuthModule ,
expectedCode : http . StatusForbidden ,
} ,
2023-03-22 12:41:59 -05:00
{
desc : "should be able to change basicRole with a basic Auth" ,
SkipOrgRoleSync : false ,
AuthEnabled : false ,
AuthModule : "" ,
expectedCode : http . StatusOK ,
} ,
{
desc : "should be able to change basicRole with a basic Auth" ,
SkipOrgRoleSync : true ,
AuthEnabled : true ,
AuthModule : "" ,
expectedCode : http . StatusOK ,
} ,
}
userWithPermissions := userWithPermissions ( 1 , permissions )
userRequesting := & user . User { ID : 2 , OrgID : 1 }
reqBody := ` { "userId": "1", "role": "Admin", "orgId": "1"} `
for _ , tt := range tests {
t . Run ( tt . desc , func ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
hs . Cfg = setting . NewCfg ( )
hs . Cfg . LDAPAuthEnabled = tt . AuthEnabled
if tt . AuthModule == login . LDAPAuthModule {
hs . Cfg . LDAPAuthEnabled = tt . AuthEnabled
hs . Cfg . LDAPSkipOrgRoleSync = tt . SkipOrgRoleSync
} else if tt . AuthModule == login . GenericOAuthModule {
hs . Cfg . GenericOAuthAuthEnabled = tt . AuthEnabled
hs . Cfg . GenericOAuthSkipOrgRoleSync = tt . SkipOrgRoleSync
2023-07-25 07:27:02 -05:00
} else if tt . AuthModule == login . GrafanaComAuthModule {
hs . Cfg . GrafanaNetAuthEnabled = tt . AuthEnabled
hs . Cfg . GrafanaComSkipOrgRoleSync = tt . SkipOrgRoleSync
2023-03-22 12:41:59 -05:00
} else if tt . AuthModule == "" {
// authmodule empty means basic auth
} else {
t . Errorf ( "invalid auth module for test: %s" , tt . AuthModule )
}
hs . authInfoService = & logintest . AuthInfoServiceFake {
ExpectedUserAuth : & login . UserAuth { AuthModule : tt . AuthModule } ,
}
2023-07-25 07:27:02 -05:00
hs . Features = featuremgmt . WithFeatures ( featuremgmt . FlagGcomOnlyExternalOrgRoleSync , tt . GcomOnlyExternalOrgRoleSync )
2023-03-22 12:41:59 -05:00
hs . userService = & usertest . FakeUserService { ExpectedSignedInUser : userWithPermissions }
hs . orgService = & orgtest . FakeOrgService { }
hs . accesscontrolService = & actest . FakeService {
ExpectedPermissions : permissions ,
}
} )
req := server . NewRequest ( http . MethodPatch , fmt . Sprintf ( "/api/orgs/%d/users/%d" , userRequesting . OrgID , userRequesting . ID ) , strings . NewReader ( reqBody ) )
req . Header . Set ( "Content-Type" , "application/json" )
userWithPermissions . OrgRole = roletype . RoleAdmin
res , err := server . Send ( webtest . RequestWithSignedInUser ( req , userWithPermissions ) )
require . NoError ( t , err )
assert . Equal ( t , tt . expectedCode , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
} )
}
}
2023-05-23 09:29:20 -05:00
func TestOrgUsersAPIEndpoint ( t * testing . T ) {
2023-02-02 08:33:25 -06:00
type testCase struct {
desc string
permissions [ ] accesscontrol . Permission
expectedCode int
}
tests := [ ] testCase {
2021-09-17 02:19:36 -05:00
{
expectedCode : http . StatusOK ,
desc : "UsersLookupGet should return 200 for user with correct permissions" ,
2022-06-14 03:17:48 -05:00
permissions : [ ] accesscontrol . Permission { { Action : accesscontrol . ActionOrgUsersRead , Scope : accesscontrol . ScopeUsersAll } } ,
2021-09-17 02:19:36 -05:00
} ,
{
expectedCode : http . StatusForbidden ,
desc : "UsersLookupGet should return 403 for user without required permissions" ,
2022-06-14 03:17:48 -05:00
permissions : [ ] accesscontrol . Permission { { Action : "wrong" } } ,
2021-09-17 02:19:36 -05:00
} ,
}
2023-02-02 08:33:25 -06:00
for _ , tt := range tests {
t . Run ( tt . desc , func ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
hs . Cfg = setting . NewCfg ( )
hs . orgService = & orgtest . FakeOrgService { ExpectedSearchOrgUsersResult : & org . SearchOrgUsersQueryResult { } }
hs . authInfoService = & logintest . AuthInfoServiceFake { }
} )
res , err := server . Send ( webtest . RequestWithSignedInUser ( server . NewGetRequest ( "/api/org/users/lookup" ) , userWithPermissions ( 1 , tt . permissions ) ) )
require . NoError ( t , err )
assert . Equal ( t , tt . expectedCode , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
2021-11-17 03:12:28 -06:00
} )
}
}
2021-12-22 11:46:33 -06:00
func TestGetOrgUsersAPIEndpoint_AccessControlMetadata ( t * testing . T ) {
type testCase struct {
2023-02-02 08:33:25 -06:00
desc string
permissions [ ] accesscontrol . Permission
includeMetadata bool
expectedCode int
expectedMetadata map [ string ] bool
2021-12-22 11:46:33 -06:00
}
tests := [ ] testCase {
{
2023-02-02 08:33:25 -06:00
desc : "should not get access control metadata" ,
includeMetadata : false ,
permissions : [ ] accesscontrol . Permission {
{ Action : accesscontrol . ActionOrgUsersRead , Scope : "users:*" } ,
{ Action : accesscontrol . ActionOrgUsersWrite , Scope : "users:*" } ,
{ Action : accesscontrol . ActionOrgUsersAdd , Scope : "users:*" } ,
{ Action : accesscontrol . ActionOrgUsersRemove , Scope : "users:*" } ,
} ,
expectedCode : http . StatusOK ,
expectedMetadata : nil ,
2021-12-22 11:46:33 -06:00
} ,
{
2023-02-02 08:33:25 -06:00
desc : "should get access control metadata" ,
includeMetadata : true ,
permissions : [ ] accesscontrol . Permission {
{ Action : accesscontrol . ActionOrgUsersRead , Scope : "users:*" } ,
{ Action : accesscontrol . ActionOrgUsersWrite , Scope : "users:*" } ,
{ Action : accesscontrol . ActionOrgUsersAdd , Scope : "users:*" } ,
{ Action : accesscontrol . ActionOrgUsersRemove , Scope : "users:*" } ,
} ,
expectedCode : http . StatusOK ,
2021-12-22 11:46:33 -06:00
expectedMetadata : map [ string ] bool {
2023-02-02 08:33:25 -06:00
"org.users:write" : true ,
"org.users:add" : true ,
"org.users:read" : true ,
"org.users:remove" : true ,
} ,
2021-12-22 11:46:33 -06:00
} ,
}
2023-02-02 08:33:25 -06:00
for _ , tt := range tests {
t . Run ( tt . desc , func ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
hs . Cfg = setting . NewCfg ( )
hs . orgService = & orgtest . FakeOrgService {
ExpectedSearchOrgUsersResult : & org . SearchOrgUsersQueryResult { OrgUsers : [ ] * org . OrgUserDTO { { UserID : 1 } } } ,
}
hs . authInfoService = & logintest . AuthInfoServiceFake { }
hs . userService = & usertest . FakeUserService { ExpectedSignedInUser : userWithPermissions ( 1 , tt . permissions ) }
2022-08-16 09:08:59 -05:00
} )
2021-12-22 11:46:33 -06:00
2023-02-02 08:33:25 -06:00
url := "/api/orgs/1/users"
if tt . includeMetadata {
url += "?accesscontrol=true"
}
res , err := server . Send ( webtest . RequestWithSignedInUser ( server . NewGetRequest ( url ) , userWithPermissions ( 1 , tt . permissions ) ) )
require . NoError ( t , err )
assert . Equal ( t , tt . expectedCode , res . StatusCode )
2021-12-22 11:46:33 -06:00
2023-01-09 07:39:53 -06:00
var userList [ ] * org . OrgUserDTO
2023-02-02 08:33:25 -06:00
err = json . NewDecoder ( res . Body ) . Decode ( & userList )
2021-12-22 11:46:33 -06:00
require . NoError ( t , err )
2023-02-02 08:33:25 -06:00
if tt . expectedMetadata != nil {
assert . Equal ( t , tt . expectedMetadata , userList [ 0 ] . AccessControl )
2021-12-22 11:46:33 -06:00
} else {
assert . Nil ( t , userList [ 0 ] . AccessControl )
}
2023-02-02 08:33:25 -06:00
require . NoError ( t , res . Body . Close ( ) )
2021-12-22 11:46:33 -06:00
} )
}
}
2021-11-17 03:12:28 -06:00
func TestGetOrgUsersAPIEndpoint_AccessControl ( t * testing . T ) {
type testCase struct {
2023-05-23 09:29:20 -05:00
name string
permissions [ ] accesscontrol . Permission
expectedCode int
targetOrg int64
2021-11-17 03:12:28 -06:00
}
tests := [ ] testCase {
{
2023-05-23 09:29:20 -05:00
name : "user with permissions can get users in org" ,
2023-02-02 08:33:25 -06:00
permissions : [ ] accesscontrol . Permission {
{ Action : accesscontrol . ActionOrgUsersRead , Scope : "users:*" } ,
} ,
expectedCode : http . StatusOK ,
targetOrg : 1 ,
2021-11-17 03:12:28 -06:00
} ,
{
2023-05-23 09:29:20 -05:00
name : "user without permissions cannot get users in org" ,
expectedCode : http . StatusForbidden ,
targetOrg : 1 ,
2021-11-17 03:12:28 -06:00
} ,
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
2023-02-02 08:33:25 -06:00
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
hs . Cfg = setting . NewCfg ( )
hs . orgService = & orgtest . FakeOrgService {
ExpectedSearchOrgUsersResult : & org . SearchOrgUsersQueryResult { } ,
}
hs . authInfoService = & logintest . AuthInfoServiceFake { }
hs . userService = & usertest . FakeUserService { ExpectedSignedInUser : userWithPermissions ( 1 , tc . permissions ) }
2022-08-16 09:08:59 -05:00
} )
2021-11-17 03:12:28 -06:00
2023-02-02 08:33:25 -06:00
u := userWithPermissions ( 1 , tc . permissions )
2021-11-17 03:12:28 -06:00
2023-02-02 08:33:25 -06:00
res , err := server . Send ( webtest . RequestWithSignedInUser ( server . NewGetRequest ( fmt . Sprintf ( "/api/orgs/%d/users/" , tc . targetOrg ) ) , u ) )
require . NoError ( t , err )
assert . Equal ( t , tc . expectedCode , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
2021-11-17 03:12:28 -06:00
} )
}
}
func TestPostOrgUsersAPIEndpoint_AccessControl ( t * testing . T ) {
type testCase struct {
2023-05-23 09:29:20 -05:00
desc string
permissions [ ] accesscontrol . Permission
input string
expectedCode int
2021-11-17 03:12:28 -06:00
}
tests := [ ] testCase {
{
2023-05-23 09:29:20 -05:00
desc : "user with permissions can add users to org" ,
2023-02-02 08:33:25 -06:00
permissions : [ ] accesscontrol . Permission {
{ Action : accesscontrol . ActionOrgUsersAdd , Scope : "users:*" } ,
} ,
input : ` { "loginOrEmail": "user", "role": "Viewer"} ` ,
expectedCode : http . StatusOK ,
2021-11-17 03:12:28 -06:00
} ,
{
2023-05-23 09:29:20 -05:00
desc : "user without permissions cannot add users to org" ,
expectedCode : http . StatusForbidden ,
input : ` { "loginOrEmail": "user", "role": "Viewer"} ` ,
2021-11-17 03:12:28 -06:00
} ,
}
2023-02-02 08:33:25 -06:00
for _ , tt := range tests {
t . Run ( tt . desc , func ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
hs . Cfg = setting . NewCfg ( )
hs . orgService = & orgtest . FakeOrgService { }
hs . authInfoService = & logintest . AuthInfoServiceFake { }
hs . userService = & usertest . FakeUserService {
ExpectedUser : & user . User { } ,
ExpectedSignedInUser : userWithPermissions ( 1 , tt . permissions ) ,
}
2022-08-16 09:08:59 -05:00
} )
2022-09-27 06:58:49 -05:00
2023-02-02 08:33:25 -06:00
u := userWithPermissions ( 1 , tt . permissions )
2021-11-17 03:12:28 -06:00
2023-02-02 08:33:25 -06:00
res , err := server . SendJSON ( webtest . RequestWithSignedInUser ( server . NewPostRequest ( "/api/orgs/1/users" , strings . NewReader ( tt . input ) ) , u ) )
require . NoError ( t , err )
assert . Equal ( t , tt . expectedCode , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
2021-11-17 03:12:28 -06:00
} )
}
}
2021-09-17 02:19:36 -05:00
2022-06-27 11:40:12 -05:00
func TestOrgUsersAPIEndpointWithSetPerms_AccessControl ( t * testing . T ) {
2023-02-02 08:33:25 -06:00
type testCase struct {
2022-06-27 11:40:12 -05:00
expectedCode int
desc string
url string
method string
2023-02-02 08:33:25 -06:00
role org . RoleType
2022-06-27 11:40:12 -05:00
permissions [ ] accesscontrol . Permission
input string
}
2023-02-02 08:33:25 -06:00
tests := [ ] testCase {
2022-06-27 11:40:12 -05:00
{
expectedCode : http . StatusOK ,
desc : "org viewer with the correct permissions can add a user as a viewer to his org" ,
url : "/api/org/users" ,
method : http . MethodPost ,
2023-02-02 08:33:25 -06:00
role : org . RoleViewer ,
2022-06-27 11:40:12 -05:00
permissions : [ ] accesscontrol . Permission { { Action : accesscontrol . ActionOrgUsersAdd , Scope : accesscontrol . ScopeUsersAll } } ,
2023-02-02 08:33:25 -06:00
input : ` { "loginOrEmail": "user", "role": "Viewer"} ` ,
2022-06-27 11:40:12 -05:00
} ,
{
expectedCode : http . StatusForbidden ,
desc : "org viewer with the correct permissions cannot add a user as an editor to his org" ,
url : "/api/org/users" ,
2023-02-02 08:33:25 -06:00
role : org . RoleViewer ,
2022-06-27 11:40:12 -05:00
method : http . MethodPost ,
permissions : [ ] accesscontrol . Permission { { Action : accesscontrol . ActionOrgUsersAdd , Scope : accesscontrol . ScopeUsersAll } } ,
2023-02-02 08:33:25 -06:00
input : ` { "loginOrEmail": "user", "role": "Editor"} ` ,
2022-06-27 11:40:12 -05:00
} ,
{
expectedCode : http . StatusOK ,
desc : "org viewer with the correct permissions can add a user as a viewer to his org" ,
url : "/api/orgs/1/users" ,
method : http . MethodPost ,
2023-02-02 08:33:25 -06:00
role : org . RoleViewer ,
2022-06-27 11:40:12 -05:00
permissions : [ ] accesscontrol . Permission { { Action : accesscontrol . ActionOrgUsersAdd , Scope : accesscontrol . ScopeUsersAll } } ,
2023-02-02 08:33:25 -06:00
input : ` { "loginOrEmail": "user", "role": "Viewer"} ` ,
2022-06-27 11:40:12 -05:00
} ,
{
expectedCode : http . StatusForbidden ,
desc : "org viewer with the correct permissions cannot add a user as an editor to his org" ,
url : "/api/orgs/1/users" ,
method : http . MethodPost ,
2023-02-02 08:33:25 -06:00
role : org . RoleViewer ,
2022-06-27 11:40:12 -05:00
permissions : [ ] accesscontrol . Permission { { Action : accesscontrol . ActionOrgUsersAdd , Scope : accesscontrol . ScopeUsersAll } } ,
2023-02-02 08:33:25 -06:00
input : ` { "loginOrEmail": "user", "role": "Editor"} ` ,
2022-06-27 11:40:12 -05:00
} ,
{
expectedCode : http . StatusOK ,
desc : "org viewer with the correct permissions can update a user's role to a viewer in his org" ,
2023-02-02 08:33:25 -06:00
url : fmt . Sprintf ( "/api/org/users/%d" , 1 ) ,
2022-06-27 11:40:12 -05:00
method : http . MethodPatch ,
2023-02-02 08:33:25 -06:00
role : org . RoleViewer ,
2022-06-27 11:40:12 -05:00
permissions : [ ] accesscontrol . Permission { { Action : accesscontrol . ActionOrgUsersWrite , Scope : accesscontrol . ScopeUsersAll } } ,
2023-02-02 08:33:25 -06:00
input : ` { "role": "Viewer"} ` ,
2022-06-27 11:40:12 -05:00
} ,
{
expectedCode : http . StatusForbidden ,
2023-02-02 08:33:25 -06:00
desc : "org viewer with the correct permissions cannot update a user's role to a Editorin his org" ,
url : fmt . Sprintf ( "/api/org/users/%d" , 1 ) ,
2022-06-27 11:40:12 -05:00
method : http . MethodPatch ,
permissions : [ ] accesscontrol . Permission { { Action : accesscontrol . ActionOrgUsersWrite , Scope : accesscontrol . ScopeUsersAll } } ,
2023-02-02 08:33:25 -06:00
input : ` { "role": "Editor"} ` ,
2022-06-27 11:40:12 -05:00
} ,
{
expectedCode : http . StatusOK ,
desc : "org viewer with the correct permissions can update a user's role to a viewer in his org" ,
2023-02-02 08:33:25 -06:00
url : fmt . Sprintf ( "/api/orgs/1/users/%d" , 1 ) ,
2022-06-27 11:40:12 -05:00
method : http . MethodPatch ,
2023-02-02 08:33:25 -06:00
role : org . RoleViewer ,
2022-06-27 11:40:12 -05:00
permissions : [ ] accesscontrol . Permission { { Action : accesscontrol . ActionOrgUsersWrite , Scope : accesscontrol . ScopeUsersAll } } ,
2023-02-02 08:33:25 -06:00
input : ` { "role": "Viewer"} ` ,
2022-06-27 11:40:12 -05:00
} ,
{
expectedCode : http . StatusForbidden ,
2023-02-02 08:33:25 -06:00
desc : "org viewer with the correct permissions cannot update a user's role to a editor in his org" ,
url : fmt . Sprintf ( "/api/orgs/1/users/%d" , 1 ) ,
2022-06-27 11:40:12 -05:00
method : http . MethodPatch ,
2023-02-02 08:33:25 -06:00
role : org . RoleViewer ,
2022-06-27 11:40:12 -05:00
permissions : [ ] accesscontrol . Permission { { Action : accesscontrol . ActionOrgUsersWrite , Scope : accesscontrol . ScopeUsersAll } } ,
2023-02-02 08:33:25 -06:00
input : ` { "role": "Editor"} ` ,
2022-06-27 11:40:12 -05:00
} ,
{
expectedCode : http . StatusOK ,
desc : "org viewer with the correct permissions can invite a user as a viewer in his org" ,
url : "/api/org/invites" ,
method : http . MethodPost ,
2023-02-02 08:33:25 -06:00
role : org . RoleViewer ,
2022-07-27 11:37:27 -05:00
permissions : [ ] accesscontrol . Permission { { Action : accesscontrol . ActionOrgUsersAdd , Scope : accesscontrol . ScopeUsersAll } } ,
2023-02-02 08:33:25 -06:00
input : ` { "loginOrEmail": "newUserEmail@test.com", "sendEmail": false, "role": "Viewer"} ` ,
2022-06-27 11:40:12 -05:00
} ,
{
expectedCode : http . StatusForbidden ,
desc : "org viewer with the correct permissions cannot invite a user as an editor in his org" ,
url : "/api/org/invites" ,
method : http . MethodPost ,
2023-02-02 08:33:25 -06:00
role : org . RoleEditor ,
2022-06-27 11:40:12 -05:00
permissions : [ ] accesscontrol . Permission { { Action : accesscontrol . ActionUsersCreate } } ,
2023-02-02 08:33:25 -06:00
input : ` { "loginOrEmail": "newUserEmail@test.com", "sendEmail": false, "role": "Editor"} ` ,
2022-06-27 11:40:12 -05:00
} ,
}
2023-02-02 08:33:25 -06:00
for _ , tt := range tests {
t . Run ( tt . desc , func ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
hs . Cfg = setting . NewCfg ( )
hs . orgService = & orgtest . FakeOrgService { }
2023-03-22 12:41:59 -05:00
hs . authInfoService = & logintest . AuthInfoServiceFake {
ExpectedUserAuth : & login . UserAuth {
AuthModule : "" ,
} ,
}
2023-02-02 08:33:25 -06:00
hs . userService = & usertest . FakeUserService {
ExpectedUser : & user . User { } ,
ExpectedSignedInUser : userWithPermissions ( 1 , tt . permissions ) ,
}
2023-02-03 07:37:41 -06:00
hs . accesscontrolService = & actest . FakeService { }
2022-08-16 09:08:59 -05:00
} )
2022-06-27 11:40:12 -05:00
2023-02-02 08:33:25 -06:00
u := userWithPermissions ( 1 , tt . permissions )
var reader io . Reader
if tt . input != "" {
reader = strings . NewReader ( tt . input )
}
res , err := server . SendJSON ( webtest . RequestWithSignedInUser ( server . NewRequest ( tt . method , tt . url , reader ) , u ) )
require . NoError ( t , err )
assert . Equal ( t , tt . expectedCode , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
2022-06-27 11:40:12 -05:00
} )
}
}
2021-11-17 03:12:28 -06:00
func TestPatchOrgUsersAPIEndpoint_AccessControl ( t * testing . T ) {
type testCase struct {
2023-05-23 09:29:20 -05:00
name string
role org . RoleType
permissions [ ] accesscontrol . Permission
input string
expectedCode int
2021-11-17 03:12:28 -06:00
}
2021-09-17 02:19:36 -05:00
2021-11-17 03:12:28 -06:00
tests := [ ] testCase {
{
2023-05-23 09:29:20 -05:00
name : "user with permissions can update org role" ,
permissions : [ ] accesscontrol . Permission { { Action : accesscontrol . ActionOrgUsersWrite , Scope : "users:*" } } ,
role : org . RoleAdmin ,
input : ` { "role": "Viewer"} ` ,
expectedCode : http . StatusOK ,
2021-11-17 03:12:28 -06:00
} ,
{
2023-05-23 09:29:20 -05:00
name : "user without permissions cannot update org role" ,
permissions : [ ] accesscontrol . Permission { } ,
input : ` { "role": "Editor"} ` ,
expectedCode : http . StatusForbidden ,
2021-11-17 03:12:28 -06:00
} ,
{
2023-05-23 09:29:20 -05:00
name : "user with permissions cannot update org role with more privileges" ,
permissions : [ ] accesscontrol . Permission { { Action : accesscontrol . ActionOrgUsersWrite , Scope : "users:*" } } ,
role : org . RoleViewer ,
input : ` { "role": "Admin"} ` ,
expectedCode : http . StatusForbidden ,
2021-11-17 03:12:28 -06:00
} ,
}
2023-02-02 08:33:25 -06:00
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
hs . Cfg = setting . NewCfg ( )
hs . orgService = & orgtest . FakeOrgService { }
2023-03-22 12:41:59 -05:00
hs . authInfoService = & logintest . AuthInfoServiceFake {
ExpectedUserAuth : & login . UserAuth {
AuthModule : "" ,
} ,
}
2023-02-03 07:37:41 -06:00
hs . accesscontrolService = & actest . FakeService { }
2023-02-02 08:33:25 -06:00
hs . userService = & usertest . FakeUserService {
ExpectedUser : & user . User { } ,
ExpectedSignedInUser : userWithPermissions ( 1 , tt . permissions ) ,
}
2022-08-16 09:08:59 -05:00
} )
2021-09-17 02:19:36 -05:00
2023-02-02 08:33:25 -06:00
u := userWithPermissions ( 1 , tt . permissions )
res , err := server . SendJSON ( webtest . RequestWithSignedInUser ( server . NewRequest ( http . MethodPatch , "/api/orgs/1/users/1" , strings . NewReader ( tt . input ) ) , u ) )
require . NoError ( t , err )
assert . Equal ( t , tt . expectedCode , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
2021-11-17 03:12:28 -06:00
} )
}
}
func TestDeleteOrgUsersAPIEndpoint_AccessControl ( t * testing . T ) {
type testCase struct {
2023-05-23 09:29:20 -05:00
name string
permissions [ ] accesscontrol . Permission
isGrafanaAdmin bool
expectedCode int
2021-11-17 03:12:28 -06:00
}
tests := [ ] testCase {
{
2023-05-23 09:29:20 -05:00
name : "user with permissions can remove user from org" ,
2023-02-02 08:33:25 -06:00
permissions : [ ] accesscontrol . Permission {
{ Action : accesscontrol . ActionOrgUsersRemove , Scope : "users:*" } ,
} ,
expectedCode : http . StatusOK ,
2021-11-17 03:12:28 -06:00
} ,
{
2023-05-23 09:29:20 -05:00
name : "user without permissions cannot remove user from org" ,
expectedCode : http . StatusForbidden ,
2021-11-17 03:12:28 -06:00
} ,
}
2023-02-02 08:33:25 -06:00
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
hs . Cfg = setting . NewCfg ( )
hs . accesscontrolService = actest . FakeService { }
hs . orgService = & orgtest . FakeOrgService {
ExpectedOrgListResponse : orgtest . OrgListResponse { struct {
OrgID int64
Response error
} { OrgID : 1 , Response : nil } } ,
}
hs . authInfoService = & logintest . AuthInfoServiceFake { }
hs . userService = & usertest . FakeUserService {
ExpectedUser : & user . User { } ,
ExpectedSignedInUser : userWithPermissions ( 1 , tt . permissions ) ,
}
2022-08-16 09:08:59 -05:00
} )
2021-11-17 03:12:28 -06:00
2023-02-02 08:33:25 -06:00
u := userWithPermissions ( 1 , tt . permissions )
u . IsGrafanaAdmin = tt . isGrafanaAdmin
res , err := server . SendJSON ( webtest . RequestWithSignedInUser ( server . NewRequest ( http . MethodDelete , "/api/orgs/1/users/1" , nil ) , u ) )
require . NoError ( t , err )
assert . Equal ( t , tt . expectedCode , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
2021-09-17 02:19:36 -05:00
} )
}
}