2018-12-01 12:28:10 -05:00
package api
import (
"testing"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
2019-05-21 14:52:49 +03:00
"github.com/grafana/grafana/pkg/components/simplejson"
2020-03-04 12:57:20 +01:00
"github.com/grafana/grafana/pkg/models"
2019-03-08 15:15:38 +01:00
"github.com/grafana/grafana/pkg/services/auth"
2018-12-01 12:28:10 -05:00
. "github.com/smartystreets/goconvey/convey"
)
2020-04-15 05:11:45 -04:00
const (
TestLogin = "test@example.com"
TestPassword = "password"
nonExistingOrgID = 1000
)
2018-12-01 12:28:10 -05:00
func TestAdminApiEndpoint ( t * testing . T ) {
2020-03-04 12:57:20 +01:00
role := models . ROLE_ADMIN
2018-12-01 12:28:10 -05:00
Convey ( "Given a server admin attempts to remove themself as an admin" , t , func () {
updateCmd := dtos . AdminUpdateUserPermissionsForm {
IsGrafanaAdmin : false ,
}
2020-03-04 12:57:20 +01:00
bus . AddHandler ( "test" , func ( cmd * models . UpdateUserPermissionsCommand ) error {
return models . ErrLastGrafanaAdmin
2018-12-01 12:28:10 -05:00
})
putAdminScenario ( "When calling PUT on" , "/api/admin/users/1/permissions" , "/api/admin/users/:id/permissions" , role , updateCmd , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "PUT" , sc . url , map [ string ] string {}). exec ()
So ( sc . resp . Code , ShouldEqual , 400 )
})
})
2019-03-08 15:15:38 +01:00
Convey ( "When a server admin attempts to logout himself from all devices" , t , func () {
2020-03-04 12:57:20 +01:00
bus . AddHandler ( "test" , func ( cmd * models . GetUserByIdQuery ) error {
cmd . Result = & models . User { Id : TestUserID }
2019-03-08 15:15:38 +01:00
return nil
})
adminLogoutUserScenario ( "Should not be allowed when calling POST on" , "/api/admin/users/1/logout" , "/api/admin/users/:id/logout" , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string {}). exec ()
So ( sc . resp . Code , ShouldEqual , 400 )
})
})
Convey ( "When a server admin attempts to logout a non-existing user from all devices" , t , func () {
userId := int64 ( 0 )
2020-03-04 12:57:20 +01:00
bus . AddHandler ( "test" , func ( cmd * models . GetUserByIdQuery ) error {
2019-03-08 15:15:38 +01:00
userId = cmd . Id
2020-03-04 12:57:20 +01:00
return models . ErrUserNotFound
2019-03-08 15:15:38 +01:00
})
adminLogoutUserScenario ( "Should return not found when calling POST on" , "/api/admin/users/200/logout" , "/api/admin/users/:id/logout" , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string {}). exec ()
So ( sc . resp . Code , ShouldEqual , 404 )
So ( userId , ShouldEqual , 200 )
})
})
Convey ( "When a server admin attempts to revoke an auth token for a non-existing user" , t , func () {
userId := int64 ( 0 )
2020-03-04 12:57:20 +01:00
bus . AddHandler ( "test" , func ( cmd * models . GetUserByIdQuery ) error {
2019-03-08 15:15:38 +01:00
userId = cmd . Id
2020-03-04 12:57:20 +01:00
return models . ErrUserNotFound
2019-03-08 15:15:38 +01:00
})
2020-03-04 12:57:20 +01:00
cmd := models . RevokeAuthTokenCmd { AuthTokenId : 2 }
2019-03-08 15:15:38 +01:00
adminRevokeUserAuthTokenScenario ( "Should return not found when calling POST on" , "/api/admin/users/200/revoke-auth-token" , "/api/admin/users/:id/revoke-auth-token" , cmd , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string {}). exec ()
So ( sc . resp . Code , ShouldEqual , 404 )
So ( userId , ShouldEqual , 200 )
})
})
Convey ( "When a server admin gets auth tokens for a non-existing user" , t , func () {
userId := int64 ( 0 )
2020-03-04 12:57:20 +01:00
bus . AddHandler ( "test" , func ( cmd * models . GetUserByIdQuery ) error {
2019-03-08 15:15:38 +01:00
userId = cmd . Id
2020-03-04 12:57:20 +01:00
return models . ErrUserNotFound
2019-03-08 15:15:38 +01:00
})
adminGetUserAuthTokensScenario ( "Should return not found when calling GET on" , "/api/admin/users/200/auth-tokens" , "/api/admin/users/:id/auth-tokens" , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "GET" , sc . url , map [ string ] string {}). exec ()
So ( sc . resp . Code , ShouldEqual , 404 )
So ( userId , ShouldEqual , 200 )
})
})
2019-05-21 14:52:49 +03:00
2020-01-10 12:43:44 +02:00
Convey ( "When a server admin attempts to enable/disable a nonexistent user" , t , func () {
var userId int64
isDisabled := false
2020-03-04 12:57:20 +01:00
bus . AddHandler ( "test" , func ( cmd * models . GetAuthInfoQuery ) error {
return models . ErrUserNotFound
2020-01-10 12:43:44 +02:00
})
2020-03-04 12:57:20 +01:00
bus . AddHandler ( "test" , func ( cmd * models . DisableUserCommand ) error {
2020-01-10 12:43:44 +02:00
userId = cmd . UserId
isDisabled = cmd . IsDisabled
2020-03-04 12:57:20 +01:00
return models . ErrUserNotFound
2020-01-10 12:43:44 +02:00
})
adminDisableUserScenario ( "Should return user not found on a POST request" , "enable" , "/api/admin/users/42/enable" , "/api/admin/users/:id/enable" , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string {}). exec ()
So ( sc . resp . Code , ShouldEqual , 404 )
respJSON , err := simplejson . NewJson ( sc . resp . Body . Bytes ())
So ( err , ShouldBeNil )
So ( respJSON . Get ( "message" ). MustString (), ShouldEqual , "User not found" )
So ( userId , ShouldEqual , 42 )
So ( isDisabled , ShouldEqual , false )
})
adminDisableUserScenario ( "Should return user not found on a POST request" , "disable" , "/api/admin/users/42/disable" , "/api/admin/users/:id/disable" , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string {}). exec ()
So ( sc . resp . Code , ShouldEqual , 404 )
respJSON , err := simplejson . NewJson ( sc . resp . Body . Bytes ())
So ( err , ShouldBeNil )
So ( respJSON . Get ( "message" ). MustString (), ShouldEqual , "User not found" )
So ( userId , ShouldEqual , 42 )
So ( isDisabled , ShouldEqual , true )
})
})
2019-05-21 14:52:49 +03:00
Convey ( "When a server admin attempts to disable/enable external user" , t , func () {
userId := int64 ( 0 )
2020-03-04 12:57:20 +01:00
bus . AddHandler ( "test" , func ( cmd * models . GetAuthInfoQuery ) error {
2019-05-21 14:52:49 +03:00
userId = cmd . UserId
return nil
})
adminDisableUserScenario ( "Should return Could not disable external user error" , "disable" , "/api/admin/users/42/disable" , "/api/admin/users/:id/disable" , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string {}). exec ()
So ( sc . resp . Code , ShouldEqual , 500 )
respJSON , err := simplejson . NewJson ( sc . resp . Body . Bytes ())
So ( err , ShouldBeNil )
So ( respJSON . Get ( "message" ). MustString (), ShouldEqual , "Could not disable external user" )
So ( userId , ShouldEqual , 42 )
})
adminDisableUserScenario ( "Should return Could not enable external user error" , "enable" , "/api/admin/users/42/enable" , "/api/admin/users/:id/enable" , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string {}). exec ()
So ( sc . resp . Code , ShouldEqual , 500 )
respJSON , err := simplejson . NewJson ( sc . resp . Body . Bytes ())
So ( err , ShouldBeNil )
So ( respJSON . Get ( "message" ). MustString (), ShouldEqual , "Could not enable external user" )
So ( userId , ShouldEqual , 42 )
})
})
2020-01-10 12:43:44 +02:00
Convey ( "When a server admin attempts to delete a nonexistent user" , t , func () {
var userId int64
2020-03-04 12:57:20 +01:00
bus . AddHandler ( "test" , func ( cmd * models . DeleteUserCommand ) error {
2020-01-10 12:43:44 +02:00
userId = cmd . UserId
2020-03-04 12:57:20 +01:00
return models . ErrUserNotFound
2020-01-10 12:43:44 +02:00
})
adminDeleteUserScenario ( "Should return user not found error" , "/api/admin/users/42" , "/api/admin/users/:id" , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "DELETE" , sc . url , map [ string ] string {}). exec ()
So ( sc . resp . Code , ShouldEqual , 404 )
respJSON , err := simplejson . NewJson ( sc . resp . Body . Bytes ())
So ( err , ShouldBeNil )
So ( respJSON . Get ( "message" ). MustString (), ShouldEqual , "User not found" )
So ( userId , ShouldEqual , 42 )
})
})
2020-04-15 05:11:45 -04:00
Convey ( "When a server admin attempts to create a user" , t , func () {
var userLogin string
var orgId int64
bus . AddHandler ( "test" , func ( cmd * models . CreateUserCommand ) error {
userLogin = cmd . Login
orgId = cmd . OrgId
if orgId == nonExistingOrgID {
return models . ErrOrgNotFound
}
cmd . Result = models . User { Id : TestUserID }
return nil
})
Convey ( "Without an organization" , func () {
createCmd := dtos . AdminCreateUserForm {
Login : TestLogin ,
Password : TestPassword ,
}
adminCreateUserScenario ( "Should create the user" , "/api/admin/users" , "/api/admin/users" , createCmd , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string {}). exec ()
So ( sc . resp . Code , ShouldEqual , 200 )
respJSON , err := simplejson . NewJson ( sc . resp . Body . Bytes ())
So ( err , ShouldBeNil )
So ( respJSON . Get ( "id" ). MustInt64 (), ShouldEqual , TestUserID )
So ( respJSON . Get ( "message" ). MustString (), ShouldEqual , "User created" )
// test that userLogin and orgId were transmitted correctly to the handler
So ( userLogin , ShouldEqual , TestLogin )
So ( orgId , ShouldEqual , 0 )
})
})
Convey ( "With an organization" , func () {
createCmd := dtos . AdminCreateUserForm {
Login : TestLogin ,
Password : TestPassword ,
OrgId : TestOrgID ,
}
adminCreateUserScenario ( "Should create the user" , "/api/admin/users" , "/api/admin/users" , createCmd , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string {}). exec ()
So ( sc . resp . Code , ShouldEqual , 200 )
respJSON , err := simplejson . NewJson ( sc . resp . Body . Bytes ())
So ( err , ShouldBeNil )
So ( respJSON . Get ( "id" ). MustInt64 (), ShouldEqual , TestUserID )
So ( respJSON . Get ( "message" ). MustString (), ShouldEqual , "User created" )
So ( userLogin , ShouldEqual , TestLogin )
So ( orgId , ShouldEqual , TestOrgID )
})
})
Convey ( "With a nonexistent organization" , func () {
createCmd := dtos . AdminCreateUserForm {
Login : TestLogin ,
Password : TestPassword ,
OrgId : nonExistingOrgID ,
}
adminCreateUserScenario ( "Should create the user" , "/api/admin/users" , "/api/admin/users" , createCmd , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string {}). exec ()
So ( sc . resp . Code , ShouldEqual , 400 )
respJSON , err := simplejson . NewJson ( sc . resp . Body . Bytes ())
So ( err , ShouldBeNil )
So ( respJSON . Get ( "message" ). MustString (), ShouldEqual , "Organization not found" )
So ( userLogin , ShouldEqual , TestLogin )
So ( orgId , ShouldEqual , 1000 )
})
})
})
2018-12-01 12:28:10 -05:00
}
2020-03-04 12:57:20 +01:00
func putAdminScenario ( desc string , url string , routePattern string , role models . RoleType , cmd dtos . AdminUpdateUserPermissionsForm , fn scenarioFunc ) {
2018-12-01 12:28:10 -05:00
Convey ( desc + " " + url , func () {
defer bus . ClearBusHandlers ()
sc := setupScenarioContext ( url )
2020-03-04 12:57:20 +01:00
sc . defaultHandler = Wrap ( func ( c * models . ReqContext ) {
2018-12-01 12:28:10 -05:00
sc . context = c
sc . context . UserId = TestUserID
sc . context . OrgId = TestOrgID
sc . context . OrgRole = role
AdminUpdateUserPermissions ( c , cmd )
})
sc . m . Put ( routePattern , sc . defaultHandler )
fn ( sc )
})
}
2019-03-08 15:15:38 +01:00
func adminLogoutUserScenario ( desc string , url string , routePattern string , fn scenarioFunc ) {
Convey ( desc + " " + url , func () {
defer bus . ClearBusHandlers ()
hs := HTTPServer {
Bus : bus . GetBus (),
AuthTokenService : auth . NewFakeUserAuthTokenService (),
}
sc := setupScenarioContext ( url )
2020-03-04 12:57:20 +01:00
sc . defaultHandler = Wrap ( func ( c * models . ReqContext ) Response {
2019-03-08 15:15:38 +01:00
sc . context = c
sc . context . UserId = TestUserID
sc . context . OrgId = TestOrgID
2020-03-04 12:57:20 +01:00
sc . context . OrgRole = models . ROLE_ADMIN
2019-03-08 15:15:38 +01:00
return hs . AdminLogoutUser ( c )
})
sc . m . Post ( routePattern , sc . defaultHandler )
fn ( sc )
})
}
2020-03-04 12:57:20 +01:00
func adminRevokeUserAuthTokenScenario ( desc string , url string , routePattern string , cmd models . RevokeAuthTokenCmd , fn scenarioFunc ) {
2019-03-08 15:15:38 +01:00
Convey ( desc + " " + url , func () {
defer bus . ClearBusHandlers ()
fakeAuthTokenService := auth . NewFakeUserAuthTokenService ()
hs := HTTPServer {
Bus : bus . GetBus (),
AuthTokenService : fakeAuthTokenService ,
}
sc := setupScenarioContext ( url )
sc . userAuthTokenService = fakeAuthTokenService
2020-03-04 12:57:20 +01:00
sc . defaultHandler = Wrap ( func ( c * models . ReqContext ) Response {
2019-03-08 15:15:38 +01:00
sc . context = c
sc . context . UserId = TestUserID
sc . context . OrgId = TestOrgID
2020-03-04 12:57:20 +01:00
sc . context . OrgRole = models . ROLE_ADMIN
2019-03-08 15:15:38 +01:00
return hs . AdminRevokeUserAuthToken ( c , cmd )
})
sc . m . Post ( routePattern , sc . defaultHandler )
fn ( sc )
})
}
func adminGetUserAuthTokensScenario ( desc string , url string , routePattern string , fn scenarioFunc ) {
Convey ( desc + " " + url , func () {
defer bus . ClearBusHandlers ()
fakeAuthTokenService := auth . NewFakeUserAuthTokenService ()
hs := HTTPServer {
Bus : bus . GetBus (),
AuthTokenService : fakeAuthTokenService ,
}
sc := setupScenarioContext ( url )
sc . userAuthTokenService = fakeAuthTokenService
2020-03-04 12:57:20 +01:00
sc . defaultHandler = Wrap ( func ( c * models . ReqContext ) Response {
2019-03-08 15:15:38 +01:00
sc . context = c
sc . context . UserId = TestUserID
sc . context . OrgId = TestOrgID
2020-03-04 12:57:20 +01:00
sc . context . OrgRole = models . ROLE_ADMIN
2019-03-08 15:15:38 +01:00
return hs . AdminGetUserAuthTokens ( c )
})
sc . m . Get ( routePattern , sc . defaultHandler )
fn ( sc )
})
}
2019-05-21 14:52:49 +03:00
func adminDisableUserScenario ( desc string , action string , url string , routePattern string , fn scenarioFunc ) {
Convey ( desc + " " + url , func () {
defer bus . ClearBusHandlers ()
2019-05-23 15:54:47 +03:00
fakeAuthTokenService := auth . NewFakeUserAuthTokenService ()
hs := HTTPServer {
Bus : bus . GetBus (),
AuthTokenService : fakeAuthTokenService ,
}
2019-05-21 14:52:49 +03:00
sc := setupScenarioContext ( url )
2020-03-04 12:57:20 +01:00
sc . defaultHandler = Wrap ( func ( c * models . ReqContext ) Response {
2019-05-21 14:52:49 +03:00
sc . context = c
sc . context . UserId = TestUserID
if action == "enable" {
2019-05-23 15:54:47 +03:00
return AdminEnableUser ( c )
2019-05-21 14:52:49 +03:00
}
2019-05-23 15:54:47 +03:00
return hs . AdminDisableUser ( c )
2019-05-21 14:52:49 +03:00
})
sc . m . Post ( routePattern , sc . defaultHandler )
fn ( sc )
})
}
2020-01-10 12:43:44 +02:00
func adminDeleteUserScenario ( desc string , url string , routePattern string , fn scenarioFunc ) {
Convey ( desc + " " + url , func () {
defer bus . ClearBusHandlers ()
sc := setupScenarioContext ( url )
2020-03-04 12:57:20 +01:00
sc . defaultHandler = Wrap ( func ( c * models . ReqContext ) {
2020-01-10 12:43:44 +02:00
sc . context = c
sc . context . UserId = TestUserID
AdminDeleteUser ( c )
})
sc . m . Delete ( routePattern , sc . defaultHandler )
fn ( sc )
})
}
2020-04-15 05:11:45 -04:00
func adminCreateUserScenario ( desc string , url string , routePattern string , cmd dtos . AdminCreateUserForm , fn scenarioFunc ) {
Convey ( desc + " " + url , func () {
defer bus . ClearBusHandlers ()
sc := setupScenarioContext ( url )
sc . defaultHandler = Wrap ( func ( c * models . ReqContext ) {
sc . context = c
sc . context . UserId = TestUserID
AdminCreateUser ( c , cmd )
})
sc . m . Post ( routePattern , sc . defaultHandler )
fn ( sc )
})
}