2022-06-28 14:32:25 +02:00
package userimpl
import (
"context"
2022-09-28 16:17:09 +02:00
"fmt"
2022-06-28 14:32:25 +02:00
"testing"
"time"
2022-10-04 12:17:55 +02:00
"github.com/stretchr/testify/assert"
2022-09-27 07:58:49 -04:00
"github.com/stretchr/testify/require"
2022-10-19 09:02:15 -04:00
"github.com/grafana/grafana/pkg/infra/db"
2022-10-05 09:34:36 +02:00
"github.com/grafana/grafana/pkg/services/accesscontrol"
2023-01-18 13:52:41 +01:00
"github.com/grafana/grafana/pkg/services/dashboards"
2022-10-04 12:17:55 +02:00
"github.com/grafana/grafana/pkg/services/org"
2022-11-22 18:02:39 +01:00
"github.com/grafana/grafana/pkg/services/org/orgimpl"
"github.com/grafana/grafana/pkg/services/quota/quotaimpl"
2022-09-28 13:18:19 +02:00
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
2023-02-06 17:50:03 +01:00
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
2022-06-28 14:32:25 +02:00
"github.com/grafana/grafana/pkg/services/user"
2022-09-27 07:58:49 -04:00
"github.com/grafana/grafana/pkg/setting"
2022-06-28 14:32:25 +02:00
)
func TestIntegrationUserDataAccess ( t * testing . T ) {
if testing . Short () {
t . Skip ( "skipping integration test" )
}
2022-10-19 09:02:15 -04:00
ss := db . InitTestDB ( t )
2022-11-22 18:02:39 +01:00
quotaService := quotaimpl . ProvideService ( ss , ss . Cfg )
orgService , err := orgimpl . ProvideService ( ss , ss . Cfg , quotaService )
require . NoError ( t , err )
2022-09-27 07:58:49 -04:00
userStore := ProvideStore ( ss , setting . NewCfg ())
2023-02-06 17:50:03 +01:00
usrSvc , err := ProvideService ( ss , orgService , ss . Cfg , nil , nil , quotaService , supportbundlestest . NewFakeBundleService ())
2022-12-07 17:03:22 +01:00
require . NoError ( t , err )
2022-10-05 09:34:36 +02:00
usr := & user . SignedInUser {
OrgID : 1 ,
Permissions : map [ int64 ] map [ string ][] string { 1 : { "users:read" : { "global.users:*" }}},
}
2022-06-28 14:32:25 +02:00
t . Run ( "user not found" , func ( t * testing . T ) {
_ , err := userStore . Get ( context . Background (),
& user . User {
Email : "test@email.com" ,
Name : "test1" ,
Login : "test1" ,
},
)
2022-07-20 14:50:06 +02:00
require . Error ( t , err , user . ErrUserNotFound )
2022-06-28 14:32:25 +02:00
})
t . Run ( "insert user" , func ( t * testing . T ) {
_ , err := userStore . Insert ( context . Background (),
& user . User {
Email : "test@email.com" ,
Name : "test1" ,
Login : "test1" ,
Created : time . Now (),
Updated : time . Now (),
},
)
require . NoError ( t , err )
})
t . Run ( "get user" , func ( t * testing . T ) {
_ , err := userStore . Get ( context . Background (),
& user . User {
Email : "test@email.com" ,
Name : "test1" ,
Login : "test1" ,
},
)
require . NoError ( t , err )
})
2022-09-28 13:18:19 +02:00
t . Run ( "Testing DB - creates and loads user" , func ( t * testing . T ) {
2022-10-19 09:02:15 -04:00
ss := db . InitTestDB ( t )
2022-12-07 17:03:22 +01:00
_ , usrSvc := createOrgAndUserSvc ( t , ss , ss . Cfg )
2022-09-28 13:18:19 +02:00
cmd := user . CreateUserCommand {
Email : "usertest@test.com" ,
Name : "user name" ,
Login : "user_test_login" ,
}
2022-12-07 17:03:22 +01:00
usr , err := usrSvc . Create ( context . Background (), & cmd )
2022-09-28 13:18:19 +02:00
require . NoError ( t , err )
result , err := userStore . GetByID ( context . Background (), usr . ID )
require . Nil ( t , err )
require . Equal ( t , result . Email , "usertest@test.com" )
require . Equal ( t , result . Password , "" )
require . Len ( t , result . Rands , 10 )
require . Len ( t , result . Salt , 10 )
require . False ( t , result . IsDisabled )
result , err = userStore . GetByID ( context . Background (), usr . ID )
require . Nil ( t , err )
require . Equal ( t , result . Email , "usertest@test.com" )
require . Equal ( t , result . Password , "" )
require . Len ( t , result . Rands , 10 )
require . Len ( t , result . Salt , 10 )
require . False ( t , result . IsDisabled )
t . Run ( "Get User by email case insensitive" , func ( t * testing . T ) {
userStore . cfg . CaseInsensitiveLogin = true
query := user . GetUserByEmailQuery { Email : "USERtest@TEST.COM" }
result , err := userStore . GetByEmail ( context . Background (), & query )
require . Nil ( t , err )
require . Equal ( t , result . Email , "usertest@test.com" )
require . Equal ( t , result . Password , "" )
require . Len ( t , result . Rands , 10 )
require . Len ( t , result . Salt , 10 )
require . False ( t , result . IsDisabled )
userStore . cfg . CaseInsensitiveLogin = false
})
t . Run ( "Testing DB - creates and loads user" , func ( t * testing . T ) {
result , err = userStore . GetByID ( context . Background (), usr . ID )
require . Nil ( t , err )
require . Equal ( t , result . Email , "usertest@test.com" )
require . Equal ( t , result . Password , "" )
require . Len ( t , result . Rands , 10 )
require . Len ( t , result . Salt , 10 )
require . False ( t , result . IsDisabled )
result , err = userStore . GetByID ( context . Background (), usr . ID )
require . Nil ( t , err )
require . Equal ( t , result . Email , "usertest@test.com" )
require . Equal ( t , result . Password , "" )
require . Len ( t , result . Rands , 10 )
require . Len ( t , result . Salt , 10 )
require . False ( t , result . IsDisabled )
ss . Cfg . CaseInsensitiveLogin = false
})
})
t . Run ( "Testing DB - error on case insensitive conflict" , func ( t * testing . T ) {
if ss . GetDBType () == migrator . MySQL {
t . Skip ( "Skipping on MySQL due to case insensitive indexes" )
}
userStore . cfg . CaseInsensitiveLogin = true
cmd := user . CreateUserCommand {
Email : "confusertest@test.com" ,
Name : "user name" ,
Login : "user_email_conflict" ,
}
// userEmailConflict
2022-12-07 17:03:22 +01:00
_ , err = usrSvc . Create ( context . Background (), & cmd )
2022-09-28 13:18:19 +02:00
require . NoError ( t , err )
cmd = user . CreateUserCommand {
Email : "confusertest@TEST.COM" ,
Name : "user name" ,
Login : "user_email_conflict_two" ,
}
2022-12-07 17:03:22 +01:00
_ , err := usrSvc . Create ( context . Background (), & cmd )
2022-09-28 13:18:19 +02:00
require . NoError ( t , err )
cmd = user . CreateUserCommand {
Email : "user_test_login_conflict@test.com" ,
Name : "user name" ,
Login : "user_test_login_conflict" ,
}
// userLoginConflict
2022-12-07 17:03:22 +01:00
_ , err = usrSvc . Create ( context . Background (), & cmd )
2022-09-28 13:18:19 +02:00
require . NoError ( t , err )
cmd = user . CreateUserCommand {
Email : "user_test_login_conflict_two@test.com" ,
Name : "user name" ,
Login : "user_test_login_CONFLICT" ,
}
2022-12-07 17:03:22 +01:00
_ , err = usrSvc . Create ( context . Background (), & cmd )
2022-09-28 13:18:19 +02:00
require . NoError ( t , err )
ss . Cfg . CaseInsensitiveLogin = true
t . Run ( "GetByEmail - email conflict" , func ( t * testing . T ) {
query := user . GetUserByEmailQuery { Email : "confusertest@test.com" }
_ , err = userStore . GetByEmail ( context . Background (), & query )
require . Error ( t , err )
})
t . Run ( "GetByEmail - login conflict" , func ( t * testing . T ) {
query := user . GetUserByEmailQuery { Email : "user_test_login_conflict@test.com" }
_ , err = userStore . GetByEmail ( context . Background (), & query )
require . Error ( t , err )
})
t . Run ( "GetByLogin - email conflict" , func ( t * testing . T ) {
query := user . GetUserByLoginQuery { LoginOrEmail : "user_email_conflict_two" }
_ , err = userStore . GetByLogin ( context . Background (), & query )
require . Error ( t , err )
})
t . Run ( "GetByLogin - login conflict" , func ( t * testing . T ) {
query := user . GetUserByLoginQuery { LoginOrEmail : "user_test_login_conflict" }
_ , err = userStore . GetByLogin ( context . Background (), & query )
require . Error ( t , err )
})
t . Run ( "GetByLogin - login conflict by email" , func ( t * testing . T ) {
query := user . GetUserByLoginQuery { LoginOrEmail : "user_test_login_conflict@test.com" }
_ , err = userStore . GetByLogin ( context . Background (), & query )
require . Error ( t , err )
})
2022-10-21 15:21:21 +02:00
t . Run ( "GetByLogin - user2 uses user1.email as login" , func ( t * testing . T ) {
// create user_1
user1 := & user . User {
Email : "user_1@mail.com" ,
Name : "user_1" ,
Login : "user_1" ,
Password : "user_1_password" ,
Created : time . Now (),
Updated : time . Now (),
IsDisabled : true ,
}
_ , err := userStore . Insert ( context . Background (), user1 )
require . Nil ( t , err )
// create user_2
user2 := & user . User {
Email : "user_2@mail.com" ,
Name : "user_2" ,
Login : "user_1@mail.com" ,
Password : "user_2_password" ,
Created : time . Now (),
Updated : time . Now (),
IsDisabled : true ,
}
_ , err = userStore . Insert ( context . Background (), user2 )
require . Nil ( t , err )
// query user database for user_1 email
query := user . GetUserByLoginQuery { LoginOrEmail : "user_1@mail.com" }
result , err := userStore . GetByLogin ( context . Background (), & query )
require . Nil ( t , err )
// expect user_1 as result
require . Equal ( t , user1 . Email , result . Email )
require . Equal ( t , user1 . Login , result . Login )
require . Equal ( t , user1 . Name , result . Name )
require . NotEqual ( t , user2 . Email , result . Email )
require . NotEqual ( t , user2 . Login , result . Login )
require . NotEqual ( t , user2 . Name , result . Name )
})
2022-09-28 13:18:19 +02:00
ss . Cfg . CaseInsensitiveLogin = false
})
2022-09-28 16:17:09 +02:00
t . Run ( "Change user password" , func ( t * testing . T ) {
err := userStore . ChangePassword ( context . Background (), & user . ChangeUserPasswordCommand {})
require . NoError ( t , err )
})
t . Run ( "update last seen at" , func ( t * testing . T ) {
err := userStore . UpdateLastSeenAt ( context . Background (), & user . UpdateUserLastSeenAtCommand {})
require . NoError ( t , err )
})
2022-10-04 12:17:55 +02:00
t . Run ( "get signed in user" , func ( t * testing . T ) {
2022-12-07 17:03:22 +01:00
ss := db . InitTestDB ( t )
orgService , usrSvc := createOrgAndUserSvc ( t , ss , ss . Cfg )
users := createFiveTestUsers ( t , usrSvc , func ( i int ) * user . CreateUserCommand {
2022-10-04 12:17:55 +02:00
return & user . CreateUserCommand {
Email : fmt . Sprint ( "user" , i , "@test.com" ),
Name : fmt . Sprint ( "user" , i ),
Login : fmt . Sprint ( "loginuser" , i ),
IsDisabled : false ,
}
})
2022-11-22 18:02:39 +01:00
err := orgService . AddOrgUser ( context . Background (), & org . AddOrgUserCommand {
2022-10-04 12:17:55 +02:00
LoginOrEmail : users [ 1 ]. Login , Role : org . RoleViewer ,
2022-11-22 18:02:39 +01:00
OrgID : users [ 0 ]. OrgID , UserID : users [ 1 ]. ID ,
2022-10-04 12:17:55 +02:00
})
require . Nil ( t , err )
2023-01-20 14:58:47 +01:00
err = updateDashboardACL ( t , ss , 1 , & dashboards . DashboardACL {
2022-10-04 12:17:55 +02:00
DashboardID : 1 , OrgID : users [ 0 ]. OrgID , UserID : users [ 1 ]. ID ,
2023-01-26 08:46:30 -05:00
Permission : dashboards . PERMISSION_EDIT ,
2022-10-04 12:17:55 +02:00
})
require . Nil ( t , err )
ss . CacheService . Flush ()
query := & user . GetSignedInUserQuery { OrgID : users [ 1 ]. OrgID , UserID : users [ 1 ]. ID }
result , err := userStore . GetSignedInUser ( context . Background (), query )
require . NoError ( t , err )
require . Equal ( t , result . Email , "user1@test.com" )
})
t . Run ( "update user" , func ( t * testing . T ) {
err := userStore . UpdateUser ( context . Background (), & user . User { ID : 1 , Name : "testtestest" , Login : "loginloginlogin" })
require . NoError ( t , err )
result , err := userStore . GetByID ( context . Background (), 1 )
require . NoError ( t , err )
assert . Equal ( t , result . Name , "testtestest" )
assert . Equal ( t , result . Login , "loginloginlogin" )
})
2022-10-04 14:14:32 +02:00
t . Run ( "Testing DB - grafana admin users" , func ( t * testing . T ) {
2022-12-07 17:03:22 +01:00
ss := db . InitTestDB ( t )
_ , usrSvc := createOrgAndUserSvc ( t , ss , ss . Cfg )
2022-10-04 14:14:32 +02:00
createUserCmd := user . CreateUserCommand {
Email : fmt . Sprint ( "admin" , "@test.com" ),
Name : "admin" ,
Login : "admin" ,
IsAdmin : true ,
}
2022-12-07 17:03:22 +01:00
usr , err := usrSvc . Create ( context . Background (), & createUserCmd )
2022-10-04 14:14:32 +02:00
require . Nil ( t , err )
// Cannot make themselves a non-admin
updatePermsError := userStore . UpdatePermissions ( context . Background (), usr . ID , false )
require . Equal ( t , user . ErrLastGrafanaAdmin , updatePermsError )
2022-10-27 11:44:09 +02:00
query := user . GetUserByIDQuery { ID : usr . ID }
queryResult , getUserError := userStore . GetByID ( context . Background (), query . ID )
2022-10-04 14:14:32 +02:00
require . Nil ( t , getUserError )
2022-10-27 11:44:09 +02:00
require . True ( t , queryResult . IsAdmin )
2022-10-04 14:14:32 +02:00
// One user
const email = "user@test.com"
const username = "user"
createUserCmd = user . CreateUserCommand {
Email : email ,
Name : "user" ,
Login : username ,
}
2022-12-07 17:03:22 +01:00
_ , err = usrSvc . Create ( context . Background (), & createUserCmd )
2022-10-04 14:14:32 +02:00
require . Nil ( t , err )
// When trying to create a new user with the same email, an error is returned
createUserCmd = user . CreateUserCommand {
Email : email ,
Name : "user2" ,
Login : "user2" ,
SkipOrgSetup : true ,
}
2022-12-07 17:03:22 +01:00
_ , err = usrSvc . Create ( context . Background (), & createUserCmd )
require . Equal ( t , user . ErrUserAlreadyExists , err )
2022-10-04 14:14:32 +02:00
// When trying to create a new user with the same login, an error is returned
createUserCmd = user . CreateUserCommand {
Email : "user2@test.com" ,
Name : "user2" ,
Login : username ,
SkipOrgSetup : true ,
}
2022-12-07 17:03:22 +01:00
_ , err = usrSvc . Create ( context . Background (), & createUserCmd )
require . Equal ( t , user . ErrUserAlreadyExists , err )
2022-10-04 14:14:32 +02:00
})
t . Run ( "GetProfile" , func ( t * testing . T ) {
_ , err := userStore . GetProfile ( context . Background (), & user . GetUserProfileQuery { UserID : 1 })
require . NoError ( t , err )
})
t . Run ( "SetHelpFlag" , func ( t * testing . T ) {
err := userStore . SetHelpFlag ( context . Background (), & user . SetUserHelpFlagCommand { UserID : 1 , HelpFlags1 : user . HelpFlags1 ( 1 )})
require . NoError ( t , err )
})
2022-10-05 09:34:36 +02:00
t . Run ( "Testing DB - return list users based on their is_disabled flag" , func ( t * testing . T ) {
2022-10-19 09:02:15 -04:00
ss = db . InitTestDB ( t )
2022-12-07 17:03:22 +01:00
_ , usrSvc := createOrgAndUserSvc ( t , ss , ss . Cfg )
userStore := ProvideStore ( ss , ss . Cfg )
createFiveTestUsers ( t , usrSvc , func ( i int ) * user . CreateUserCommand {
2022-10-05 09:34:36 +02:00
return & user . CreateUserCommand {
Email : fmt . Sprint ( "user" , i , "@test.com" ),
Name : fmt . Sprint ( "user" , i ),
Login : fmt . Sprint ( "loginuser" , i ),
IsDisabled : i % 2 == 0 ,
}
})
isDisabled := false
query := user . SearchUsersQuery { IsDisabled : & isDisabled , SignedInUser : usr }
result , err := userStore . Search ( context . Background (), & query )
require . Nil ( t , err )
require . Len ( t , result . Users , 2 )
first , third := false , false
for _ , user := range result . Users {
if user . Name == "user1" {
first = true
}
if user . Name == "user3" {
third = true
}
}
require . True ( t , first )
require . True ( t , third )
// Re-init DB
2022-12-07 17:03:22 +01:00
ss := db . InitTestDB ( t )
orgService , usrSvc = createOrgAndUserSvc ( t , ss , ss . Cfg )
users := createFiveTestUsers ( t , usrSvc , func ( i int ) * user . CreateUserCommand {
2022-10-05 09:34:36 +02:00
return & user . CreateUserCommand {
Email : fmt . Sprint ( "user" , i , "@test.com" ),
Name : fmt . Sprint ( "user" , i ),
Login : fmt . Sprint ( "loginuser" , i ),
IsDisabled : false ,
}
})
2022-11-22 18:02:39 +01:00
err = orgService . AddOrgUser ( context . Background (), & org . AddOrgUserCommand {
2022-10-05 09:34:36 +02:00
LoginOrEmail : users [ 1 ]. Login , Role : org . RoleViewer ,
2022-11-22 18:02:39 +01:00
OrgID : users [ 0 ]. OrgID , UserID : users [ 1 ]. ID ,
2022-10-05 09:34:36 +02:00
})
require . Nil ( t , err )
2023-01-20 14:58:47 +01:00
err = updateDashboardACL ( t , ss , 1 , & dashboards . DashboardACL {
2022-10-05 09:34:36 +02:00
DashboardID : 1 , OrgID : users [ 0 ]. OrgID , UserID : users [ 1 ]. ID ,
2023-01-26 08:46:30 -05:00
Permission : dashboards . PERMISSION_EDIT ,
2022-10-05 09:34:36 +02:00
})
require . Nil ( t , err )
// When the user is deleted
2022-11-23 11:15:48 +01:00
err = userStore . Delete ( context . Background (), users [ 1 ]. ID )
2022-10-05 09:34:36 +02:00
require . Nil ( t , err )
2023-01-20 14:58:47 +01:00
permQuery := & dashboards . GetDashboardACLInfoListQuery { DashboardID : 1 , OrgID : users [ 0 ]. OrgID }
2023-01-25 10:36:26 +01:00
permQueryResult , err := userStore . getDashboardACLInfoList ( permQuery )
2022-10-05 09:34:36 +02:00
require . Nil ( t , err )
2023-01-25 10:36:26 +01:00
require . Len ( t , permQueryResult , 0 )
2022-10-05 09:34:36 +02:00
// A user is an org member and has been assigned permissions
// Re-init DB
2022-10-19 09:02:15 -04:00
ss = db . InitTestDB ( t )
2022-12-07 17:03:22 +01:00
orgService , usrSvc = createOrgAndUserSvc ( t , ss , ss . Cfg )
users = createFiveTestUsers ( t , usrSvc , func ( i int ) * user . CreateUserCommand {
2022-10-05 09:34:36 +02:00
return & user . CreateUserCommand {
Email : fmt . Sprint ( "user" , i , "@test.com" ),
Name : fmt . Sprint ( "user" , i ),
Login : fmt . Sprint ( "loginuser" , i ),
IsDisabled : false ,
}
})
2022-11-22 18:02:39 +01:00
err = orgService . AddOrgUser ( context . Background (), & org . AddOrgUserCommand {
2022-10-05 09:34:36 +02:00
LoginOrEmail : users [ 1 ]. Login , Role : org . RoleViewer ,
2022-11-22 18:02:39 +01:00
OrgID : users [ 0 ]. OrgID , UserID : users [ 1 ]. ID ,
2022-10-05 09:34:36 +02:00
})
require . Nil ( t , err )
2023-01-20 14:58:47 +01:00
err = updateDashboardACL ( t , ss , 1 , & dashboards . DashboardACL {
2022-10-05 09:34:36 +02:00
DashboardID : 1 , OrgID : users [ 0 ]. OrgID , UserID : users [ 1 ]. ID ,
2023-01-26 08:46:30 -05:00
Permission : dashboards . PERMISSION_EDIT ,
2022-10-05 09:34:36 +02:00
})
require . Nil ( t , err )
ss . CacheService . Flush ()
2022-11-30 14:28:51 +01:00
query3 := & user . GetSignedInUserQuery { OrgID : users [ 1 ]. OrgID , UserID : users [ 1 ]. ID }
query3Result , err := userStore . GetSignedInUser ( context . Background (), query3 )
2022-10-05 09:34:36 +02:00
require . Nil ( t , err )
2022-11-30 14:28:51 +01:00
require . NotNil ( t , query3Result )
require . Equal ( t , query3 . OrgID , users [ 1 ]. OrgID )
2022-10-05 09:34:36 +02:00
disableCmd := user . BatchDisableUsersCommand {
UserIDs : [] int64 { users [ 0 ]. ID , users [ 1 ]. ID , users [ 2 ]. ID , users [ 3 ]. ID , users [ 4 ]. ID },
IsDisabled : true ,
}
err = userStore . BatchDisableUsers ( context . Background (), & disableCmd )
require . Nil ( t , err )
isDisabled = true
query5 := & user . SearchUsersQuery { IsDisabled : & isDisabled , SignedInUser : usr }
query5Result , err := userStore . Search ( context . Background (), query5 )
require . Nil ( t , err )
require . EqualValues ( t , query5Result . TotalCount , 5 )
// the user is deleted
2022-11-23 11:15:48 +01:00
err = userStore . Delete ( context . Background (), users [ 1 ]. ID )
2022-10-05 09:34:36 +02:00
require . Nil ( t , err )
2023-01-20 14:58:47 +01:00
permQuery = & dashboards . GetDashboardACLInfoListQuery { DashboardID : 1 , OrgID : users [ 0 ]. OrgID }
2023-01-25 10:36:26 +01:00
permQueryResult , err = userStore . getDashboardACLInfoList ( permQuery )
2022-10-05 09:34:36 +02:00
require . Nil ( t , err )
2023-01-25 10:36:26 +01:00
require . Len ( t , permQueryResult , 0 )
2022-10-05 09:34:36 +02:00
})
t . Run ( "Testing DB - return list of users that the SignedInUser has permission to read" , func ( t * testing . T ) {
2022-10-19 09:02:15 -04:00
ss := db . InitTestDB ( t )
2022-12-07 17:03:22 +01:00
orgService , err := orgimpl . ProvideService ( ss , ss . Cfg , quotaService )
require . NoError ( t , err )
2023-02-06 17:50:03 +01:00
usrSvc , err := ProvideService ( ss , orgService , ss . Cfg , nil , nil , quotaService , supportbundlestest . NewFakeBundleService ())
2022-12-07 17:03:22 +01:00
require . NoError ( t , err )
createFiveTestUsers ( t , usrSvc , func ( i int ) * user . CreateUserCommand {
2022-10-05 09:34:36 +02:00
return & user . CreateUserCommand {
Email : fmt . Sprint ( "user" , i , "@test.com" ),
Name : fmt . Sprint ( "user" , i ),
Login : fmt . Sprint ( "loginuser" , i ),
}
})
testUser := & user . SignedInUser {
OrgID : 1 ,
Permissions : map [ int64 ] map [ string ][] string { 1 : { "users:read" : { "global.users:id:1" , "global.users:id:3" }}},
}
query := user . SearchUsersQuery { SignedInUser : testUser }
queryResult , err := userStore . Search ( context . Background (), & query )
assert . Nil ( t , err )
assert . Len ( t , queryResult . Users , 2 )
})
2022-10-19 09:02:15 -04:00
ss = db . InitTestDB ( t )
2022-10-05 09:34:36 +02:00
t . Run ( "Testing DB - enable all users" , func ( t * testing . T ) {
2022-12-07 17:03:22 +01:00
users := createFiveTestUsers ( t , usrSvc , func ( i int ) * user . CreateUserCommand {
2022-10-05 09:34:36 +02:00
return & user . CreateUserCommand {
Email : fmt . Sprint ( "user" , i , "@test.com" ),
Name : fmt . Sprint ( "user" , i ),
Login : fmt . Sprint ( "loginuser" , i ),
IsDisabled : true ,
}
})
disableCmd := user . BatchDisableUsersCommand {
UserIDs : [] int64 { users [ 0 ]. ID , users [ 1 ]. ID , users [ 2 ]. ID , users [ 3 ]. ID , users [ 4 ]. ID },
IsDisabled : false ,
}
err := userStore . BatchDisableUsers ( context . Background (), & disableCmd )
require . Nil ( t , err )
isDisabled := false
query := & user . SearchUsersQuery { IsDisabled : & isDisabled , SignedInUser : usr }
queryResult , err := userStore . Search ( context . Background (), query )
require . Nil ( t , err )
require . EqualValues ( t , queryResult . TotalCount , 5 )
})
t . Run ( "Can search users" , func ( t * testing . T ) {
2022-10-19 09:02:15 -04:00
ss = db . InitTestDB ( t )
2022-10-05 09:34:36 +02:00
userStore . cfg . AutoAssignOrg = false
ac1cmd := user . CreateUserCommand { Login : "ac1" , Email : "ac1@test.com" , Name : "ac1 name" }
ac2cmd := user . CreateUserCommand { Login : "ac2" , Email : "ac2@test.com" , Name : "ac2 name" , IsAdmin : true }
serviceaccountcmd := user . CreateUserCommand { Login : "serviceaccount" , Email : "service@test.com" , Name : "serviceaccount name" , IsAdmin : true , IsServiceAccount : true }
2022-12-07 17:03:22 +01:00
_ , err := usrSvc . Create ( context . Background (), & ac1cmd )
2022-10-05 09:34:36 +02:00
require . NoError ( t , err )
2022-12-07 17:03:22 +01:00
_ , err = usrSvc . Create ( context . Background (), & ac2cmd )
2022-10-05 09:34:36 +02:00
require . NoError ( t , err )
// user only used for making sure we filter out the service accounts
2022-12-07 17:03:22 +01:00
_ , err = usrSvc . Create ( context . Background (), & serviceaccountcmd )
2022-10-05 09:34:36 +02:00
require . NoError ( t , err )
query := user . SearchUsersQuery { Query : "" , SignedInUser : & user . SignedInUser {
OrgID : 1 ,
Permissions : map [ int64 ] map [ string ][] string {
1 : { accesscontrol . ActionUsersRead : { accesscontrol . ScopeGlobalUsersAll }},
},
}}
queryResult , err := userStore . Search ( context . Background (), & query )
require . NoError ( t , err )
require . Len ( t , queryResult . Users , 2 )
require . Equal ( t , queryResult . Users [ 0 ]. Email , "ac1@test.com" )
require . Equal ( t , queryResult . Users [ 1 ]. Email , "ac2@test.com" )
})
2022-10-19 09:02:15 -04:00
ss = db . InitTestDB ( t )
2022-10-05 09:34:36 +02:00
t . Run ( "Testing DB - disable only specific users" , func ( t * testing . T ) {
2022-12-07 17:03:22 +01:00
users := createFiveTestUsers ( t , usrSvc , func ( i int ) * user . CreateUserCommand {
2022-10-05 09:34:36 +02:00
return & user . CreateUserCommand {
Email : fmt . Sprint ( "user" , i , "@test.com" ),
Name : fmt . Sprint ( "user" , i ),
Login : fmt . Sprint ( "loginuser" , i ),
IsDisabled : false ,
}
})
userIdsToDisable := [] int64 {}
for i := 0 ; i < 3 ; i ++ {
userIdsToDisable = append ( userIdsToDisable , users [ i ]. ID )
}
disableCmd := user . BatchDisableUsersCommand {
UserIDs : userIdsToDisable ,
IsDisabled : true ,
}
err := userStore . BatchDisableUsers ( context . Background (), & disableCmd )
require . Nil ( t , err )
query := user . SearchUsersQuery { SignedInUser : usr }
queryResult , err := userStore . Search ( context . Background (), & query )
require . Nil ( t , err )
require . EqualValues ( t , queryResult . TotalCount , 5 )
for _ , user := range queryResult . Users {
shouldBeDisabled := false
// Check if user id is in the userIdsToDisable list
for _ , disabledUserId := range userIdsToDisable {
if user . ID == disabledUserId {
require . True ( t , user . IsDisabled )
shouldBeDisabled = true
}
}
// Otherwise user shouldn't be disabled
if ! shouldBeDisabled {
require . False ( t , user . IsDisabled )
}
}
})
2022-10-19 09:02:15 -04:00
ss = db . InitTestDB ( t )
2022-10-05 09:34:36 +02:00
t . Run ( "Testing DB - search users" , func ( t * testing . T ) {
// Since previous tests were destructive
2022-12-07 17:03:22 +01:00
createFiveTestUsers ( t , usrSvc , func ( i int ) * user . CreateUserCommand {
2022-10-05 09:34:36 +02:00
return & user . CreateUserCommand {
Email : fmt . Sprint ( "user" , i , "@test.com" ),
Name : fmt . Sprint ( "user" , i ),
Login : fmt . Sprint ( "loginuser" , i ),
IsDisabled : false ,
}
})
})
t . Run ( "Disable user" , func ( t * testing . T ) {
id , err := userStore . Insert ( context . Background (), & user . User {
Name : "user111" ,
Created : time . Now (),
Updated : time . Now (),
})
require . NoError ( t , err )
err = userStore . Disable ( context . Background (), & user . DisableUserCommand { UserID : id })
require . NoError ( t , err )
})
t . Run ( "Testing DB - multiple users" , func ( t * testing . T ) {
2022-10-19 09:02:15 -04:00
ss = db . InitTestDB ( t )
2022-10-05 09:34:36 +02:00
2022-12-07 17:03:22 +01:00
createFiveTestUsers ( t , usrSvc , func ( i int ) * user . CreateUserCommand {
2022-10-05 09:34:36 +02:00
return & user . CreateUserCommand {
Email : fmt . Sprint ( "user" , i , "@test.com" ),
Name : fmt . Sprint ( "user" , i ),
Login : fmt . Sprint ( "loginuser" , i ),
IsDisabled : false ,
}
})
// Return the first page of users and a total count
query := user . SearchUsersQuery { Query : "" , Page : 1 , Limit : 3 , SignedInUser : usr }
queryResult , err := userStore . Search ( context . Background (), & query )
require . Nil ( t , err )
require . Len ( t , queryResult . Users , 3 )
require . EqualValues ( t , queryResult . TotalCount , 5 )
// Return the second page of users and a total count
query = user . SearchUsersQuery { Query : "" , Page : 2 , Limit : 3 , SignedInUser : usr }
queryResult , err = userStore . Search ( context . Background (), & query )
require . Nil ( t , err )
require . Len ( t , queryResult . Users , 2 )
require . EqualValues ( t , queryResult . TotalCount , 5 )
// Return list of users matching query on user name
query = user . SearchUsersQuery { Query : "use" , Page : 1 , Limit : 3 , SignedInUser : usr }
queryResult , err = userStore . Search ( context . Background (), & query )
require . Nil ( t , err )
require . Len ( t , queryResult . Users , 3 )
require . EqualValues ( t , queryResult . TotalCount , 5 )
query = user . SearchUsersQuery { Query : "ser1" , Page : 1 , Limit : 3 , SignedInUser : usr }
queryResult , err = userStore . Search ( context . Background (), & query )
require . Nil ( t , err )
require . Len ( t , queryResult . Users , 1 )
require . EqualValues ( t , queryResult . TotalCount , 1 )
query = user . SearchUsersQuery { Query : "USER1" , Page : 1 , Limit : 3 , SignedInUser : usr }
queryResult , err = userStore . Search ( context . Background (), & query )
require . Nil ( t , err )
require . Len ( t , queryResult . Users , 1 )
require . EqualValues ( t , queryResult . TotalCount , 1 )
query = user . SearchUsersQuery { Query : "idontexist" , Page : 1 , Limit : 3 , SignedInUser : usr }
queryResult , err = userStore . Search ( context . Background (), & query )
require . Nil ( t , err )
require . Len ( t , queryResult . Users , 0 )
require . EqualValues ( t , queryResult . TotalCount , 0 )
// Return list of users matching query on email
query = user . SearchUsersQuery { Query : "ser1@test.com" , Page : 1 , Limit : 3 , SignedInUser : usr }
queryResult , err = userStore . Search ( context . Background (), & query )
require . Nil ( t , err )
require . Len ( t , queryResult . Users , 1 )
require . EqualValues ( t , queryResult . TotalCount , 1 )
// Return list of users matching query on login name
query = user . SearchUsersQuery { Query : "loginuser1" , Page : 1 , Limit : 3 , SignedInUser : usr }
queryResult , err = userStore . Search ( context . Background (), & query )
require . Nil ( t , err )
require . Len ( t , queryResult . Users , 1 )
require . EqualValues ( t , queryResult . TotalCount , 1 )
})
2022-11-30 14:28:51 +01:00
t . Run ( "Can get logged in user projection" , func ( t * testing . T ) {
query := user . GetSignedInUserQuery { UserID : 2 }
queryResult , err := userStore . GetSignedInUser ( context . Background (), & query )
require . NoError ( t , err )
assert . Equal ( t , queryResult . Email , "user1@test.com" )
assert . EqualValues ( t , queryResult . OrgID , 2 )
assert . Equal ( t , queryResult . Name , "user1" )
assert . Equal ( t , queryResult . Login , "loginuser1" )
assert . EqualValues ( t , queryResult . OrgRole , "Admin" )
assert . Equal ( t , queryResult . OrgName , "user1@test.com" )
assert . Equal ( t , queryResult . IsGrafanaAdmin , false )
})
2022-09-28 16:17:09 +02:00
}
func TestIntegrationUserUpdate ( t * testing . T ) {
if testing . Short () {
t . Skip ( "skipping integration test" )
}
2022-10-19 09:02:15 -04:00
ss := db . InitTestDB ( t )
2022-09-28 16:17:09 +02:00
userStore := ProvideStore ( ss , setting . NewCfg ())
2022-12-07 17:03:22 +01:00
_ , usrSvc := createOrgAndUserSvc ( t , ss , ss . Cfg )
2022-09-28 16:17:09 +02:00
2022-12-07 17:03:22 +01:00
users := createFiveTestUsers ( t , usrSvc , func ( i int ) * user . CreateUserCommand {
2022-09-28 16:17:09 +02:00
return & user . CreateUserCommand {
Email : fmt . Sprint ( "USER" , i , "@test.com" ),
Name : fmt . Sprint ( "USER" , i ),
Login : fmt . Sprint ( "loginUSER" , i ),
IsDisabled : false ,
}
})
userStore . cfg . CaseInsensitiveLogin = true
t . Run ( "Testing DB - update generates duplicate user" , func ( t * testing . T ) {
err := userStore . Update ( context . Background (), & user . UpdateUserCommand {
Login : "loginuser2" ,
UserID : users [ 0 ]. ID ,
})
require . Error ( t , err )
})
t . Run ( "Testing DB - update lowercases existing user" , func ( t * testing . T ) {
err := userStore . Update ( context . Background (), & user . UpdateUserCommand {
Login : "loginUSER0" ,
Email : "USER0@test.com" ,
UserID : users [ 0 ]. ID ,
})
require . NoError ( t , err )
result , err := userStore . GetByID ( context . Background (), users [ 0 ]. ID )
require . NoError ( t , err )
require . Equal ( t , "loginuser0" , result . Login )
require . Equal ( t , "user0@test.com" , result . Email )
})
t . Run ( "Testing DB - no user info provided" , func ( t * testing . T ) {
err := userStore . Update ( context . Background (), & user . UpdateUserCommand {
Login : "" ,
Email : "" ,
Name : "Change Name" ,
UserID : users [ 3 ]. ID ,
})
require . NoError ( t , err )
// query := user.GetUserByIDQuery{ID: users[3].ID}
result , err := userStore . GetByID ( context . Background (), users [ 3 ]. ID )
require . NoError ( t , err )
// Changed
require . Equal ( t , "Change Name" , result . Name )
// Unchanged
require . Equal ( t , "loginUSER3" , result . Login )
require . Equal ( t , "USER3@test.com" , result . Email )
})
ss . Cfg . CaseInsensitiveLogin = false
}
2022-12-07 17:03:22 +01:00
func createFiveTestUsers ( t * testing . T , svc user . Service , fn func ( i int ) * user . CreateUserCommand ) [] user . User {
2022-09-28 16:17:09 +02:00
t . Helper ()
2022-12-07 17:03:22 +01:00
users := make ([] user . User , 5 )
2022-09-28 16:17:09 +02:00
for i := 0 ; i < 5 ; i ++ {
cmd := fn ( i )
2023-03-03 18:01:23 +02:00
user , err := svc . Create ( context . Background (), cmd )
2022-09-28 16:17:09 +02:00
require . Nil ( t , err )
2022-12-07 17:03:22 +01:00
users [ i ] = * user
2022-09-28 16:17:09 +02:00
}
return users
2022-06-28 14:32:25 +02:00
}
2022-10-04 12:17:55 +02:00
// TODO: Use FakeDashboardStore when org has its own service
2023-01-20 14:58:47 +01:00
func updateDashboardACL ( t * testing . T , sqlStore db . DB , dashboardID int64 , items ...* dashboards . DashboardACL ) error {
2022-10-04 12:17:55 +02:00
t . Helper ()
2022-10-19 09:02:15 -04:00
err := sqlStore . WithDbSession ( context . Background (), func ( sess * db . Session ) error {
2022-10-04 12:17:55 +02:00
_ , err := sess . Exec ( "DELETE FROM dashboard_acl WHERE dashboard_id=?" , dashboardID )
if err != nil {
return fmt . Errorf ( "deleting from dashboard_acl failed: %w" , err )
}
for _ , item := range items {
item . Created = time . Now ()
item . Updated = time . Now ()
if item . UserID == 0 && item . TeamID == 0 && ( item . Role == nil || ! item . Role . IsValid ()) {
2023-01-26 08:46:30 -05:00
return dashboards . ErrDashboardACLInfoMissing
2022-10-04 12:17:55 +02:00
}
if item . DashboardID == 0 {
2023-01-26 08:46:30 -05:00
return dashboards . ErrDashboardPermissionDashboardEmpty
2022-10-04 12:17:55 +02:00
}
sess . Nullable ( "user_id" , "team_id" )
if _ , err := sess . Insert ( item ); err != nil {
return err
}
}
// Update dashboard HasACL flag
2023-01-18 13:52:41 +01:00
dashboard := dashboards . Dashboard { HasACL : true }
2022-10-04 12:17:55 +02:00
_ , err = sess . Cols ( "has_acl" ). Where ( "id=?" , dashboardID ). Update ( & dashboard )
return err
})
return err
}
2022-10-05 09:34:36 +02:00
// This function was copied from pkg/services/dashboards/database to circumvent
// import cycles. When this org-related code is refactored into a service the
// tests can the real GetDashboardACLInfoList functions
2023-01-25 10:36:26 +01:00
func ( ss * sqlStore ) getDashboardACLInfoList ( query * dashboards . GetDashboardACLInfoListQuery ) ([] * dashboards . DashboardACLInfoDTO , error ) {
queryResult := make ([] * dashboards . DashboardACLInfoDTO , 0 )
2022-10-19 09:02:15 -04:00
outerErr := ss . db . WithDbSession ( context . Background (), func ( dbSession * db . Session ) error {
2022-10-05 09:34:36 +02:00
falseStr := ss . dialect . BooleanStr ( false )
if query . DashboardID == 0 {
sql := `SELECT
da.id,
da.org_id,
da.dashboard_id,
da.user_id,
da.team_id,
da.permission,
da.role,
da.created,
da.updated,
'' as user_login,
'' as user_email,
'' as team,
'' as title,
'' as slug,
'' as uid,` +
falseStr + ` AS is_folder,` +
falseStr + ` AS inherited
FROM dashboard_acl as da
WHERE da.dashboard_id = -1`
2023-01-25 10:36:26 +01:00
return dbSession . SQL ( sql ). Find ( & queryResult )
2022-10-05 09:34:36 +02:00
}
rawSQL := `
-- get permissions for the dashboard and its parent folder
SELECT
da.id,
da.org_id,
da.dashboard_id,
da.user_id,
da.team_id,
da.permission,
da.role,
da.created,
da.updated,
u.login AS user_login,
u.email AS user_email,
ug.name AS team,
ug.email AS team_email,
d.title,
d.slug,
d.uid,
d.is_folder,
CASE WHEN (da.dashboard_id = -1 AND d.folder_id > 0) OR da.dashboard_id = d.folder_id THEN ` + ss . dialect . BooleanStr ( true ) + ` ELSE ` + falseStr + ` END AS inherited
FROM dashboard as d
LEFT JOIN dashboard folder on folder.id = d.folder_id
LEFT JOIN dashboard_acl AS da ON
da.dashboard_id = d.id OR
da.dashboard_id = d.folder_id OR
(
-- include default permissions -->
da.org_id = -1 AND (
(folder.id IS NOT NULL AND folder.has_acl = ` + falseStr + `) OR
(folder.id IS NULL AND d.has_acl = ` + falseStr + `)
)
)
LEFT JOIN ` + ss . dialect . Quote ( "user" ) + ` AS u ON u.id = da.user_id
LEFT JOIN team ug on ug.id = da.team_id
WHERE d.org_id = ? AND d.id = ? AND da.id IS NOT NULL
ORDER BY da.id ASC
`
2023-01-25 10:36:26 +01:00
return dbSession . SQL ( rawSQL , query . OrgID , query . DashboardID ). Find ( & queryResult )
2022-10-05 09:34:36 +02:00
})
if outerErr != nil {
2023-01-25 10:36:26 +01:00
return nil , outerErr
2022-10-05 09:34:36 +02:00
}
2023-01-25 10:36:26 +01:00
for _ , p := range queryResult {
2022-10-05 09:34:36 +02:00
p . PermissionName = p . Permission . String ()
}
2023-01-25 10:36:26 +01:00
return queryResult , nil
2022-10-05 09:34:36 +02:00
}
2022-12-07 17:03:22 +01:00
func createOrgAndUserSvc ( t * testing . T , store db . DB , cfg * setting . Cfg ) ( org . Service , user . Service ) {
t . Helper ()
quotaService := quotaimpl . ProvideService ( store , cfg )
orgService , err := orgimpl . ProvideService ( store , cfg , quotaService )
require . NoError ( t , err )
2023-02-06 17:50:03 +01:00
usrSvc , err := ProvideService ( store , orgService , cfg , nil , nil , quotaService , supportbundlestest . NewFakeBundleService ())
2022-12-07 17:03:22 +01:00
require . NoError ( t , err )
return orgService , usrSvc
}