@ -1,193 +1,21 @@
package api
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/db/dbtest"
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/licensing"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/org/orgimpl"
"github.com/grafana/grafana/pkg/services/quota/quotaimpl"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
"github.com/grafana/grafana/pkg/services/team"
"github.com/grafana/grafana/pkg/services/team/teamimpl"
"github.com/grafana/grafana/pkg/services/team/teamtest"
"github.com/grafana/grafana/pkg/services/teamguardian/database"
"github.com/grafana/grafana/pkg/services/teamguardian/manager"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/user/userimpl"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web/webtest"
)
type TeamGuardianMock struct {
result error
}
func ( t * TeamGuardianMock ) CanAdmin ( ctx context . Context , orgId int64 , teamId int64 , user * user . SignedInUser ) error {
return t . result
}
func ( t * TeamGuardianMock ) DeleteByUser ( ctx context . Context , userID int64 ) error {
return t . result
}
func setUpGetTeamMembersHandler ( t * testing . T , sqlStore * sqlstore . SQLStore ) {
const testOrgID int64 = 1
var userCmd user . CreateUserCommand
teamSvc := teamimpl . ProvideService ( sqlStore , setting . NewCfg ( ) )
team , err := teamSvc . CreateTeam ( "group1 name" , "test1@test.com" , testOrgID )
require . NoError ( t , err )
quotaService := quotaimpl . ProvideService ( sqlStore , sqlStore . Cfg )
orgService , err := orgimpl . ProvideService ( sqlStore , sqlStore . Cfg , quotaService )
require . NoError ( t , err )
usrSvc , err := userimpl . ProvideService ( sqlStore , orgService , sqlStore . Cfg , nil , nil , quotaService , supportbundlestest . NewFakeBundleService ( ) )
require . NoError ( t , err )
for i := 0 ; i < 3 ; i ++ {
userCmd = user . CreateUserCommand {
Email : fmt . Sprint ( "user" , i , "@test.com" ) ,
Name : fmt . Sprint ( "user" , i ) ,
Login : fmt . Sprint ( "loginuser" , i ) ,
}
// user
user , err := usrSvc . Create ( context . Background ( ) , & userCmd )
require . NoError ( t , err )
err = teamSvc . AddTeamMember ( user . ID , testOrgID , team . ID , false , 1 )
require . NoError ( t , err )
}
}
func TestTeamMembersAPIEndpoint_userLoggedIn ( t * testing . T ) {
hs := setupSimpleHTTPServer ( nil )
settings := hs . Cfg
sqlStore := db . InitTestDB ( t )
sqlStore . Cfg = settings
hs . SQLStore = sqlStore
hs . teamService = teamimpl . ProvideService ( sqlStore , settings )
hs . License = & licensing . OSSLicensingService { }
hs . teamGuardian = & TeamGuardianMock { }
mock := dbtest . NewFakeDB ( )
loggedInUserScenarioWithRole ( t , "When calling GET on" , "GET" , "api/teams/1/members" ,
"api/teams/:teamId/members" , org . RoleAdmin , func ( sc * scenarioContext ) {
setUpGetTeamMembersHandler ( t , sqlStore )
sc . handlerFunc = hs . GetTeamMembers
sc . fakeReqWithParams ( "GET" , sc . url , map [ string ] string { } ) . exec ( )
require . Equal ( t , http . StatusOK , sc . resp . Code )
var resp [ ] team . TeamMemberDTO
err := json . Unmarshal ( sc . resp . Body . Bytes ( ) , & resp )
require . NoError ( t , err )
assert . Len ( t , resp , 3 )
} , mock )
t . Run ( "Given there is two hidden users" , func ( t * testing . T ) {
settings . HiddenUsers = map [ string ] struct { } {
"user1" : { } ,
testUserLogin : { } ,
}
t . Cleanup ( func ( ) { settings . HiddenUsers = make ( map [ string ] struct { } ) } )
loggedInUserScenarioWithRole ( t , "When calling GET on" , "GET" , "api/teams/1/members" ,
"api/teams/:teamId/members" , org . RoleAdmin , func ( sc * scenarioContext ) {
setUpGetTeamMembersHandler ( t , sqlStore )
sc . handlerFunc = hs . GetTeamMembers
sc . fakeReqWithParams ( "GET" , sc . url , map [ string ] string { } ) . exec ( )
require . Equal ( t , http . StatusOK , sc . resp . Code )
var resp [ ] team . TeamMemberDTO
err := json . Unmarshal ( sc . resp . Body . Bytes ( ) , & resp )
require . NoError ( t , err )
assert . Len ( t , resp , 3 )
assert . Equal ( t , "loginuser0" , resp [ 0 ] . Login )
assert . Equal ( t , "loginuser1" , resp [ 1 ] . Login )
assert . Equal ( t , "loginuser2" , resp [ 2 ] . Login )
} , mock )
} )
}
func TestAddTeamMembersAPIEndpoint_LegacyAccessControl ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
cfg := setting . NewCfg ( )
cfg . RBACEnabled = false
cfg . EditorsCanAdmin = true
hs . Cfg = cfg
hs . teamService = teamtest . NewFakeService ( )
store := & database . TeamGuardianStoreMock { }
store . On ( "GetTeamMembers" , mock . Anything , mock . Anything ) . Return ( [ ] * team . TeamMemberDTO {
{ UserID : 2 , Permission : dashboards . PERMISSION_ADMIN } ,
{ UserID : 3 , Permission : dashboards . PERMISSION_VIEW } ,
} , nil ) . Maybe ( )
hs . teamGuardian = manager . ProvideService ( store )
hs . teamPermissionsService = & actest . FakePermissionsService { }
} )
t . Run ( "Admin can add team member" , func ( t * testing . T ) {
req := webtest . RequestWithSignedInUser (
server . NewRequest ( http . MethodPost , "/api/teams/1/members" , strings . NewReader ( "{\"userId\": 1}" ) ) ,
& user . SignedInUser { OrgID : 1 , OrgRole : org . RoleAdmin } ,
)
res , err := server . SendJSON ( req )
require . NoError ( t , err )
assert . Equal ( t , http . StatusOK , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
} )
t . Run ( "Editor cannot add team member" , func ( t * testing . T ) {
req := webtest . RequestWithSignedInUser (
server . NewRequest ( http . MethodPost , "/api/teams/1/members" , strings . NewReader ( "{\"userId\": 1}" ) ) ,
& user . SignedInUser { OrgID : 1 , OrgRole : org . RoleEditor } ,
)
res , err := server . SendJSON ( req )
require . NoError ( t , err )
assert . Equal ( t , http . StatusForbidden , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
} )
t . Run ( "team member cannot add members" , func ( t * testing . T ) {
req := webtest . RequestWithSignedInUser (
server . NewRequest ( http . MethodPost , "/api/teams/1/members" , strings . NewReader ( "{\"userId\": 1}" ) ) ,
& user . SignedInUser { UserID : 3 , OrgID : 1 , OrgRole : org . RoleViewer } ,
)
res , err := server . SendJSON ( req )
require . NoError ( t , err )
assert . Equal ( t , http . StatusForbidden , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
} )
t . Run ( "team admin can add members" , func ( t * testing . T ) {
req := webtest . RequestWithSignedInUser (
server . NewRequest ( http . MethodPost , "/api/teams/1/members" , strings . NewReader ( "{\"userId\": 1}" ) ) ,
& user . SignedInUser { UserID : 2 , OrgID : 1 , OrgRole : org . RoleEditor } ,
)
res , err := server . SendJSON ( req )
require . NoError ( t , err )
assert . Equal ( t , http . StatusOK , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
} )
}
func TestAddTeamMembersAPIEndpoint_RBAC ( t * testing . T ) {
func TestAddTeamMembersAPIEndpoint ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
hs . Cfg = setting . NewCfg ( )
hs . teamService = teamtest . NewFakeService ( )
@ -217,7 +45,7 @@ func TestAddTeamMembersAPIEndpoint_RBAC(t *testing.T) {
} )
}
func TestGetTeamMembersAPIEndpoint_RBAC ( t * testing . T ) {
func TestGetTeamMembersAPIEndpoint ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
hs . Cfg = setting . NewCfg ( )
hs . teamService = teamtest . NewFakeService ( )
@ -246,68 +74,7 @@ func TestGetTeamMembersAPIEndpoint_RBAC(t *testing.T) {
} )
}
func TestUpdateTeamMembersAPIEndpoint_LegacyAccessControl ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
cfg := setting . NewCfg ( )
cfg . RBACEnabled = false
cfg . EditorsCanAdmin = true
hs . Cfg = cfg
hs . teamService = & teamtest . FakeService { ExpectedIsMember : true }
store := & database . TeamGuardianStoreMock { }
store . On ( "GetTeamMembers" , mock . Anything , mock . Anything ) . Return ( [ ] * team . TeamMemberDTO {
{ UserID : 2 , Permission : dashboards . PERMISSION_ADMIN } ,
{ UserID : 3 , Permission : dashboards . PERMISSION_VIEW } ,
} , nil ) . Maybe ( )
hs . teamGuardian = manager . ProvideService ( store )
hs . teamPermissionsService = & actest . FakePermissionsService { }
} )
t . Run ( "Admin can update team member" , func ( t * testing . T ) {
req := webtest . RequestWithSignedInUser (
server . NewRequest ( http . MethodPut , "/api/teams/1/members/1" , strings . NewReader ( "{\"permission\": 4}" ) ) ,
& user . SignedInUser { OrgID : 1 , OrgRole : org . RoleAdmin } ,
)
res , err := server . SendJSON ( req )
require . NoError ( t , err )
assert . Equal ( t , http . StatusOK , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
} )
t . Run ( "Editor cannot update team member" , func ( t * testing . T ) {
req := webtest . RequestWithSignedInUser (
server . NewRequest ( http . MethodPut , "/api/teams/1/members/1" , strings . NewReader ( "{\"permission\": 4}" ) ) ,
& user . SignedInUser { OrgID : 1 , OrgRole : org . RoleEditor } ,
)
res , err := server . SendJSON ( req )
require . NoError ( t , err )
assert . Equal ( t , http . StatusForbidden , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
} )
t . Run ( "team member cannot update member" , func ( t * testing . T ) {
req := webtest . RequestWithSignedInUser (
server . NewRequest ( http . MethodPut , "/api/teams/1/members/1" , strings . NewReader ( "{\"permission\": 4}" ) ) ,
& user . SignedInUser { UserID : 3 , OrgID : 1 , OrgRole : org . RoleViewer } ,
)
res , err := server . SendJSON ( req )
require . NoError ( t , err )
assert . Equal ( t , http . StatusForbidden , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
} )
t . Run ( "team admin can add members" , func ( t * testing . T ) {
req := webtest . RequestWithSignedInUser (
server . NewRequest ( http . MethodPut , "/api/teams/1/members/1" , strings . NewReader ( "{\"permission\": 4}" ) ) ,
& user . SignedInUser { UserID : 2 , OrgID : 1 , OrgRole : org . RoleEditor } ,
)
res , err := server . SendJSON ( req )
require . NoError ( t , err )
assert . Equal ( t , http . StatusOK , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
} )
}
func TestUpdateTeamMembersAPIEndpoint_RBAC ( t * testing . T ) {
func TestUpdateTeamMembersAPIEndpoint ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
hs . Cfg = setting . NewCfg ( )
hs . teamService = & teamtest . FakeService { ExpectedIsMember : true }
@ -336,68 +103,7 @@ func TestUpdateTeamMembersAPIEndpoint_RBAC(t *testing.T) {
} )
}
func TestDeleteTeamMembersAPIEndpoint_LegacyAccessControl ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
cfg := setting . NewCfg ( )
cfg . RBACEnabled = false
cfg . EditorsCanAdmin = true
hs . Cfg = cfg
hs . teamService = & teamtest . FakeService { ExpectedIsMember : true }
store := & database . TeamGuardianStoreMock { }
store . On ( "GetTeamMembers" , mock . Anything , mock . Anything ) . Return ( [ ] * team . TeamMemberDTO {
{ UserID : 2 , Permission : dashboards . PERMISSION_ADMIN } ,
{ UserID : 3 , Permission : dashboards . PERMISSION_VIEW } ,
} , nil ) . Maybe ( )
hs . teamGuardian = manager . ProvideService ( store )
hs . teamPermissionsService = & actest . FakePermissionsService { }
} )
t . Run ( "Admin can delete team member" , func ( t * testing . T ) {
req := webtest . RequestWithSignedInUser (
server . NewRequest ( http . MethodDelete , "/api/teams/1/members/1" , nil ) ,
& user . SignedInUser { OrgID : 1 , OrgRole : org . RoleAdmin } ,
)
res , err := server . SendJSON ( req )
require . NoError ( t , err )
assert . Equal ( t , http . StatusOK , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
} )
t . Run ( "Editor cannot delete team member" , func ( t * testing . T ) {
req := webtest . RequestWithSignedInUser (
server . NewRequest ( http . MethodDelete , "/api/teams/1/members/1" , nil ) ,
& user . SignedInUser { OrgID : 1 , OrgRole : org . RoleEditor } ,
)
res , err := server . SendJSON ( req )
require . NoError ( t , err )
assert . Equal ( t , http . StatusForbidden , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
} )
t . Run ( "team member cannot delete member" , func ( t * testing . T ) {
req := webtest . RequestWithSignedInUser (
server . NewRequest ( http . MethodDelete , "/api/teams/1/members/1" , nil ) ,
& user . SignedInUser { UserID : 3 , OrgID : 1 , OrgRole : org . RoleViewer } ,
)
res , err := server . SendJSON ( req )
require . NoError ( t , err )
assert . Equal ( t , http . StatusForbidden , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
} )
t . Run ( "team admin can delete members" , func ( t * testing . T ) {
req := webtest . RequestWithSignedInUser (
server . NewRequest ( http . MethodDelete , "/api/teams/1/members/1" , nil ) ,
& user . SignedInUser { UserID : 2 , OrgID : 1 , OrgRole : org . RoleEditor } ,
)
res , err := server . SendJSON ( req )
require . NoError ( t , err )
assert . Equal ( t , http . StatusOK , res . StatusCode )
require . NoError ( t , res . Body . Close ( ) )
} )
}
func TestDeleteTeamMembersAPIEndpoint_RBAC ( t * testing . T ) {
func TestDeleteTeamMembersAPIEndpoint ( t * testing . T ) {
server := SetupAPITestServer ( t , func ( hs * HTTPServer ) {
hs . Cfg = setting . NewCfg ( )
hs . teamService = & teamtest . FakeService { ExpectedIsMember : true }