Chore: Split get user by ID (#52442)
* Remove user from preferences, stars, orguser, team member * Fix lint * Add Delete user from org and dashboard acl * Delete user from user auth * Add DeleteUser to quota * Add test files and adjust user auth store * Rename package in wire for user auth * Import Quota Service interface in other services * do the same in tests * fix lint tests * Fix tests * Add some tests * Rename InsertUser and DeleteUser to InsertOrgUser and DeleteOrgUser * Rename DeleteUser to DeleteByUser in quota * changing a method name in few additional places * Fix in other places * Fix lint * Fix tests * Chore: Split Delete User method * Add fakes for userauth * Add mock for access control Delete User permossion, use interface * Use interface for ream guardian * Add simple fake for dashboard acl * Add go routines, clean up, use interfaces * fix lint * Update pkg/services/user/userimpl/user_test.go Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> * Update pkg/services/user/userimpl/user_test.go Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> * Update pkg/services/user/userimpl/user_test.go Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> * Split get user by ID * Use new method in api * Add tests * Aplly emthod in auth info service * Fix lint and some tests * Fix get user by ID * Fix lint Remove unused fakes * Use split get user id in admin users * Use GetbyID in cli commands * Clean up after merge * Remove commented out code * Clena up imports * add back ) * Fix wire generation for runner after merge with main Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com>
This commit is contained in:
co-authored by
Sofia Papagiannaki
parent
64488f6b90
commit
fab6c38c95
@@ -109,13 +109,14 @@ func (hs *HTTPServer) AdminUpdateUserPassword(c *models.ReqContext) response.Res
|
||||
return response.Error(400, "New password too short", nil)
|
||||
}
|
||||
|
||||
userQuery := models.GetUserByIdQuery{Id: userID}
|
||||
userQuery := user.GetUserByIDQuery{ID: userID}
|
||||
|
||||
if err := hs.SQLStore.GetUserById(c.Req.Context(), &userQuery); err != nil {
|
||||
usr, err := hs.userService.GetByID(c.Req.Context(), &userQuery)
|
||||
if err != nil {
|
||||
return response.Error(500, "Could not read user from database", err)
|
||||
}
|
||||
|
||||
passwordHashed, err := util.EncodePassword(form.Password, userQuery.Result.Salt)
|
||||
passwordHashed, err := util.EncodePassword(form.Password, usr.Salt)
|
||||
if err != nil {
|
||||
return response.Error(500, "Could not encode password", err)
|
||||
}
|
||||
|
||||
+26
-27
@@ -4,6 +4,9 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
@@ -15,9 +18,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -29,7 +31,7 @@ const (
|
||||
|
||||
func TestAdminAPIEndpoint(t *testing.T) {
|
||||
const role = models.ROLE_ADMIN
|
||||
|
||||
userService := usertest.NewUserServiceFake()
|
||||
t.Run("Given a server admin attempts to remove themselves as an admin", func(t *testing.T) {
|
||||
updateCmd := dtos.AdminUpdateUserPermissionsForm{
|
||||
IsGrafanaAdmin: false,
|
||||
@@ -45,46 +47,43 @@ func TestAdminAPIEndpoint(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("When a server admin attempts to logout himself from all devices", func(t *testing.T) {
|
||||
mock := mockstore.NewSQLStoreMock()
|
||||
adminLogoutUserScenario(t, "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()
|
||||
assert.Equal(t, 400, sc.resp.Code)
|
||||
}, mock)
|
||||
}, userService)
|
||||
})
|
||||
|
||||
t.Run("When a server admin attempts to logout a non-existing user from all devices", func(t *testing.T) {
|
||||
mock := &mockstore.SQLStoreMock{
|
||||
ExpectedError: user.ErrUserNotFound,
|
||||
}
|
||||
mockUserService := usertest.NewUserServiceFake()
|
||||
mockUserService.ExpectedError = user.ErrUserNotFound
|
||||
|
||||
adminLogoutUserScenario(t, "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()
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
}, mock)
|
||||
}, mockUserService)
|
||||
})
|
||||
|
||||
t.Run("When a server admin attempts to revoke an auth token for a non-existing user", func(t *testing.T) {
|
||||
cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
|
||||
mock := &mockstore.SQLStoreMock{
|
||||
ExpectedError: user.ErrUserNotFound,
|
||||
}
|
||||
mockUser := usertest.NewUserServiceFake()
|
||||
mockUser.ExpectedError = user.ErrUserNotFound
|
||||
adminRevokeUserAuthTokenScenario(t, "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()
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
}, mock)
|
||||
}, mockUser)
|
||||
})
|
||||
|
||||
t.Run("When a server admin gets auth tokens for a non-existing user", func(t *testing.T) {
|
||||
mock := &mockstore.SQLStoreMock{
|
||||
ExpectedError: user.ErrUserNotFound,
|
||||
}
|
||||
mockUserService := usertest.NewUserServiceFake()
|
||||
mockUserService.ExpectedError = user.ErrUserNotFound
|
||||
adminGetUserAuthTokensScenario(t, "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()
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
}, mock)
|
||||
}, mockUserService)
|
||||
})
|
||||
|
||||
t.Run("When a server admin attempts to enable/disable a nonexistent user", func(t *testing.T) {
|
||||
@@ -154,17 +153,15 @@ func TestAdminAPIEndpoint(t *testing.T) {
|
||||
adminDeleteUserScenario(t, "Should return user not found error", "/api/admin/users/42",
|
||||
"/api/admin/users/:id", func(sc *scenarioContext) {
|
||||
sc.sqlStore.(*mockstore.SQLStoreMock).ExpectedError = user.ErrUserNotFound
|
||||
sc.userService.(*usertest.FakeUserService).ExpectedError = user.ErrUserNotFound
|
||||
sc.authInfoService.ExpectedError = user.ErrUserNotFound
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
userID := sc.sqlStore.(*mockstore.SQLStoreMock).LatestUserId
|
||||
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "user not found", respJSON.Get("message").MustString())
|
||||
|
||||
assert.Equal(t, int64(42), userID)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -266,11 +263,11 @@ func putAdminScenario(t *testing.T, desc string, url string, routePattern string
|
||||
})
|
||||
}
|
||||
|
||||
func adminLogoutUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, sqlStore sqlstore.Store) {
|
||||
func adminLogoutUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, userService *usertest.FakeUserService) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
hs := HTTPServer{
|
||||
AuthTokenService: auth.NewFakeUserAuthTokenService(),
|
||||
SQLStore: sqlStore,
|
||||
userService: userService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, url)
|
||||
@@ -291,13 +288,13 @@ func adminLogoutUserScenario(t *testing.T, desc string, url string, routePattern
|
||||
})
|
||||
}
|
||||
|
||||
func adminRevokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePattern string, cmd models.RevokeAuthTokenCmd, fn scenarioFunc, sqlStore sqlstore.Store) {
|
||||
func adminRevokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePattern string, cmd models.RevokeAuthTokenCmd, fn scenarioFunc, userService user.Service) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
|
||||
hs := HTTPServer{
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
SQLStore: sqlStore,
|
||||
userService: userService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, url)
|
||||
@@ -319,13 +316,13 @@ func adminRevokeUserAuthTokenScenario(t *testing.T, desc string, url string, rou
|
||||
})
|
||||
}
|
||||
|
||||
func adminGetUserAuthTokensScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, sqlStore sqlstore.Store) {
|
||||
func adminGetUserAuthTokensScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, userService *usertest.FakeUserService) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
|
||||
hs := HTTPServer{
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
SQLStore: sqlStore,
|
||||
userService: userService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, url)
|
||||
@@ -379,7 +376,8 @@ func adminDisableUserScenario(t *testing.T, desc string, action string, url stri
|
||||
|
||||
func adminDeleteUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc) {
|
||||
hs := HTTPServer{
|
||||
SQLStore: mockstore.NewSQLStoreMock(),
|
||||
SQLStore: mockstore.NewSQLStoreMock(),
|
||||
userService: usertest.NewUserServiceFake(),
|
||||
}
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
sc := setupScenarioContext(t, url)
|
||||
@@ -391,6 +389,7 @@ func adminDeleteUserScenario(t *testing.T, desc string, url string, routePattern
|
||||
|
||||
return hs.AdminDeleteUser(c)
|
||||
})
|
||||
sc.userService = hs.userService
|
||||
|
||||
sc.m.Delete(routePattern, sc.defaultHandler)
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/searchusers"
|
||||
"github.com/grafana/grafana/pkg/services/searchusers/filters"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
"github.com/grafana/grafana/pkg/web/webtest"
|
||||
@@ -168,6 +169,7 @@ type scenarioContext struct {
|
||||
sqlStore sqlstore.Store
|
||||
authInfoService *logintest.AuthInfoServiceFake
|
||||
dashboardVersionService dashver.Service
|
||||
userService user.Service
|
||||
}
|
||||
|
||||
func (sc *scenarioContext) exec() {
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
pref "github.com/grafana/grafana/pkg/services/preference"
|
||||
"github.com/grafana/grafana/pkg/services/star"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
@@ -250,12 +251,12 @@ func (hs *HTTPServer) getAnnotationPermissionsByScope(c *models.ReqContext, acti
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) getUserLogin(ctx context.Context, userID int64) string {
|
||||
query := models.GetUserByIdQuery{Id: userID}
|
||||
err := hs.SQLStore.GetUserById(ctx, &query)
|
||||
query := user.GetUserByIDQuery{ID: userID}
|
||||
user, err := hs.userService.GetByID(ctx, &query)
|
||||
if err != nil {
|
||||
return anonString
|
||||
}
|
||||
return query.Result.Login
|
||||
return user.Login
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) getDashboardHelper(ctx context.Context, orgID int64, id int64, uid string) (*models.Dashboard, response.Response) {
|
||||
|
||||
+10
-9
@@ -209,9 +209,10 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) response.Respon
|
||||
return response.Error(http.StatusBadRequest, "id is invalid", err)
|
||||
}
|
||||
|
||||
query := models.GetUserByIdQuery{Id: userId}
|
||||
query := user.GetUserByIDQuery{ID: userId}
|
||||
|
||||
if err := hs.SQLStore.GetUserById(c.Req.Context(), &query); err != nil { // validate the userId exists
|
||||
usr, err := hs.userService.GetByID(c.Req.Context(), &query)
|
||||
if err != nil { // validate the userId exists
|
||||
if errors.Is(err, user.ErrUserNotFound) {
|
||||
return response.Error(404, user.ErrUserNotFound.Error(), nil)
|
||||
}
|
||||
@@ -219,7 +220,7 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) response.Respon
|
||||
return response.Error(500, "Failed to get user", err)
|
||||
}
|
||||
|
||||
authModuleQuery := &models.GetAuthInfoQuery{UserId: query.Result.ID, AuthModule: models.AuthModuleLDAP}
|
||||
authModuleQuery := &models.GetAuthInfoQuery{UserId: usr.ID, AuthModule: models.AuthModuleLDAP}
|
||||
if err := hs.authInfoService.GetAuthInfo(c.Req.Context(), authModuleQuery); err != nil { // validate the userId comes from LDAP
|
||||
if errors.Is(err, user.ErrUserNotFound) {
|
||||
return response.Error(404, user.ErrUserNotFound.Error(), nil)
|
||||
@@ -229,17 +230,17 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) response.Respon
|
||||
}
|
||||
|
||||
ldapServer := newLDAP(ldapConfig.Servers)
|
||||
user, _, err := ldapServer.User(query.Result.Login)
|
||||
userInfo, _, err := ldapServer.User(usr.Login)
|
||||
if err != nil {
|
||||
if errors.Is(err, multildap.ErrDidNotFindUser) { // User was not in the LDAP server - we need to take action:
|
||||
if hs.Cfg.AdminUser == query.Result.Login { // User is *the* Grafana Admin. We cannot disable it.
|
||||
errMsg := fmt.Sprintf(`Refusing to sync grafana super admin "%s" - it would be disabled`, query.Result.Login)
|
||||
if hs.Cfg.AdminUser == usr.Login { // User is *the* Grafana Admin. We cannot disable it.
|
||||
errMsg := fmt.Sprintf(`Refusing to sync grafana super admin "%s" - it would be disabled`, usr.Login)
|
||||
ldapLogger.Error(errMsg)
|
||||
return response.Error(http.StatusBadRequest, errMsg, err)
|
||||
}
|
||||
|
||||
// Since the user was not in the LDAP server. Let's disable it.
|
||||
err := hs.Login.DisableExternalUser(c.Req.Context(), query.Result.Login)
|
||||
err := hs.Login.DisableExternalUser(c.Req.Context(), usr.Login)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Failed to disable the user", err)
|
||||
}
|
||||
@@ -258,10 +259,10 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) response.Respon
|
||||
|
||||
upsertCmd := &models.UpsertUserCommand{
|
||||
ReqContext: c,
|
||||
ExternalUser: user,
|
||||
ExternalUser: userInfo,
|
||||
SignupAllowed: hs.Cfg.LDAPAllowSignup,
|
||||
UserLookupParams: models.UserLookupParams{
|
||||
UserID: &query.Result.ID, // Upsert by ID only
|
||||
UserID: &usr.ID, // Upsert by ID only
|
||||
Email: nil,
|
||||
Login: nil,
|
||||
},
|
||||
|
||||
+23
-19
@@ -8,22 +8,22 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/login/loginservice"
|
||||
"github.com/grafana/grafana/pkg/services/login/logintest"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
"github.com/grafana/grafana/pkg/services/ldap"
|
||||
"github.com/grafana/grafana/pkg/services/login/loginservice"
|
||||
"github.com/grafana/grafana/pkg/services/login/logintest"
|
||||
"github.com/grafana/grafana/pkg/services/multildap"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type LDAPMock struct {
|
||||
@@ -363,7 +363,7 @@ func TestGetLDAPStatusAPIEndpoint(t *testing.T) {
|
||||
// PostSyncUserWithLDAP tests
|
||||
// ***
|
||||
|
||||
func postSyncUserWithLDAPContext(t *testing.T, requestURL string, preHook func(*testing.T, *scenarioContext), sqlstoremock sqlstore.Store) *scenarioContext {
|
||||
func postSyncUserWithLDAPContext(t *testing.T, requestURL string, preHook func(*testing.T, *scenarioContext), userService user.Service) *scenarioContext {
|
||||
t.Helper()
|
||||
|
||||
sc := setupScenarioContext(t, requestURL)
|
||||
@@ -378,9 +378,9 @@ func postSyncUserWithLDAPContext(t *testing.T, requestURL string, preHook func(*
|
||||
hs := &HTTPServer{
|
||||
Cfg: sc.cfg,
|
||||
AuthTokenService: auth.NewFakeUserAuthTokenService(),
|
||||
SQLStore: sqlstoremock,
|
||||
Login: loginservice.LoginServiceMock{},
|
||||
authInfoService: sc.authInfoService,
|
||||
userService: userService,
|
||||
}
|
||||
|
||||
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
|
||||
@@ -403,8 +403,8 @@ func postSyncUserWithLDAPContext(t *testing.T, requestURL string, preHook func(*
|
||||
}
|
||||
|
||||
func TestPostSyncUserWithLDAPAPIEndpoint_Success(t *testing.T) {
|
||||
sqlstoremock := mockstore.SQLStoreMock{}
|
||||
sqlstoremock.ExpectedUser = &user.User{Login: "ldap-daniel", ID: 34}
|
||||
userServiceMock := usertest.NewUserServiceFake()
|
||||
userServiceMock.ExpectedUser = &user.User{Login: "ldap-daniel", ID: 34}
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T, sc *scenarioContext) {
|
||||
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
@@ -417,7 +417,7 @@ func TestPostSyncUserWithLDAPAPIEndpoint_Success(t *testing.T) {
|
||||
userSearchResult = &models.ExternalUserInfo{
|
||||
Login: "ldap-daniel",
|
||||
}
|
||||
}, &sqlstoremock)
|
||||
}, userServiceMock)
|
||||
|
||||
assert.Equal(t, http.StatusOK, sc.resp.Code)
|
||||
|
||||
@@ -431,7 +431,8 @@ func TestPostSyncUserWithLDAPAPIEndpoint_Success(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotFound(t *testing.T) {
|
||||
sqlstoremock := mockstore.SQLStoreMock{ExpectedError: user.ErrUserNotFound}
|
||||
userServiceMock := usertest.NewUserServiceFake()
|
||||
userServiceMock.ExpectedError = user.ErrUserNotFound
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T, sc *scenarioContext) {
|
||||
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
@@ -440,7 +441,7 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotFound(t *testing.T) {
|
||||
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
|
||||
return &LDAPMock{}
|
||||
}
|
||||
}, &sqlstoremock)
|
||||
}, userServiceMock)
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, sc.resp.Code)
|
||||
|
||||
@@ -454,7 +455,8 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotFound(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostSyncUserWithLDAPAPIEndpoint_WhenGrafanaAdmin(t *testing.T) {
|
||||
sqlstoremock := mockstore.SQLStoreMock{ExpectedUser: &user.User{Login: "ldap-daniel", ID: 34}}
|
||||
userServiceMock := usertest.NewUserServiceFake()
|
||||
userServiceMock.ExpectedUser = &user.User{Login: "ldap-daniel", ID: 34}
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T, sc *scenarioContext) {
|
||||
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
@@ -467,7 +469,7 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenGrafanaAdmin(t *testing.T) {
|
||||
userSearchError = multildap.ErrDidNotFindUser
|
||||
|
||||
sc.cfg.AdminUser = "ldap-daniel"
|
||||
}, &sqlstoremock)
|
||||
}, userServiceMock)
|
||||
assert.Equal(t, http.StatusBadRequest, sc.resp.Code)
|
||||
|
||||
var res map[string]interface{}
|
||||
@@ -478,7 +480,8 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenGrafanaAdmin(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotInLDAP(t *testing.T) {
|
||||
sqlstoremock := mockstore.SQLStoreMock{ExpectedUser: &user.User{Login: "ldap-daniel", ID: 34}}
|
||||
userServiceMock := usertest.NewUserServiceFake()
|
||||
userServiceMock.ExpectedUser = &user.User{Login: "ldap-daniel", ID: 34}
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T, sc *scenarioContext) {
|
||||
sc.authInfoService.ExpectedExternalUser = &models.ExternalUserInfo{IsDisabled: true, UserId: 34}
|
||||
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
|
||||
@@ -491,7 +494,7 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotInLDAP(t *testing.T) {
|
||||
|
||||
userSearchResult = nil
|
||||
userSearchError = multildap.ErrDidNotFindUser
|
||||
}, &sqlstoremock)
|
||||
}, userServiceMock)
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, sc.resp.Code)
|
||||
|
||||
@@ -603,6 +606,7 @@ func TestLDAP_AccessControl(t *testing.T) {
|
||||
cfg.LDAPEnabled = true
|
||||
sc, hs := setupAccessControlScenarioContext(t, cfg, test.url, test.permissions)
|
||||
hs.SQLStore = &mockstore.SQLStoreMock{ExpectedUser: &user.User{}}
|
||||
hs.userService = &usertest.FakeUserService{ExpectedUser: &user.User{}}
|
||||
hs.authInfoService = &logintest.AuthInfoServiceFake{}
|
||||
hs.Login = &loginservice.LoginServiceMock{}
|
||||
sc.resp = httptest.NewRecorder()
|
||||
|
||||
+6
-5
@@ -387,17 +387,18 @@ func (hs *HTTPServer) ChangeUserPassword(c *models.ReqContext) response.Response
|
||||
return response.Error(400, "Not allowed to change password when LDAP or Auth Proxy is enabled", nil)
|
||||
}
|
||||
|
||||
userQuery := models.GetUserByIdQuery{Id: c.UserId}
|
||||
userQuery := user.GetUserByIDQuery{ID: c.UserId}
|
||||
|
||||
if err := hs.SQLStore.GetUserById(c.Req.Context(), &userQuery); err != nil {
|
||||
user, err := hs.userService.GetByID(c.Req.Context(), &userQuery)
|
||||
if err != nil {
|
||||
return response.Error(500, "Could not read user from database", err)
|
||||
}
|
||||
|
||||
passwordHashed, err := util.EncodePassword(cmd.OldPassword, userQuery.Result.Salt)
|
||||
passwordHashed, err := util.EncodePassword(cmd.OldPassword, user.Salt)
|
||||
if err != nil {
|
||||
return response.Error(500, "Failed to encode password", err)
|
||||
}
|
||||
if passwordHashed != userQuery.Result.Password {
|
||||
if passwordHashed != user.Password {
|
||||
return response.Error(401, "Invalid old password", nil)
|
||||
}
|
||||
|
||||
@@ -407,7 +408,7 @@ func (hs *HTTPServer) ChangeUserPassword(c *models.ReqContext) response.Response
|
||||
}
|
||||
|
||||
cmd.UserId = c.UserId
|
||||
cmd.NewPassword, err = util.EncodePassword(cmd.NewPassword, userQuery.Result.Salt)
|
||||
cmd.NewPassword, err = util.EncodePassword(cmd.NewPassword, user.Salt)
|
||||
if err != nil {
|
||||
return response.Error(500, "Failed to encode password", err)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
@@ -49,7 +50,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
|
||||
loggedInUserScenario(t, "When calling GET on", "api/users/1", "api/users/:id", func(sc *scenarioContext) {
|
||||
fakeNow := time.Date(2019, 2, 11, 17, 30, 40, 0, time.UTC)
|
||||
secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(sqlStore))
|
||||
authInfoStore := authinfostore.ProvideAuthInfoStore(sqlStore, secretsService)
|
||||
authInfoStore := authinfostore.ProvideAuthInfoStore(sqlStore, secretsService, usertest.NewUserServiceFake())
|
||||
srv := authinfoservice.ProvideAuthInfoService(
|
||||
&authinfoservice.OSSUserProtectionImpl{},
|
||||
authInfoStore,
|
||||
|
||||
+10
-7
@@ -51,16 +51,17 @@ func (hs *HTTPServer) RevokeUserAuthToken(c *models.ReqContext) response.Respons
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) logoutUserFromAllDevicesInternal(ctx context.Context, userID int64) response.Response {
|
||||
userQuery := models.GetUserByIdQuery{Id: userID}
|
||||
userQuery := user.GetUserByIDQuery{ID: userID}
|
||||
|
||||
if err := hs.SQLStore.GetUserById(ctx, &userQuery); err != nil {
|
||||
_, err := hs.userService.GetByID(ctx, &userQuery)
|
||||
if err != nil {
|
||||
if errors.Is(err, user.ErrUserNotFound) {
|
||||
return response.Error(404, "User not found", err)
|
||||
}
|
||||
return response.Error(500, "Could not read user from database", err)
|
||||
}
|
||||
|
||||
err := hs.AuthTokenService.RevokeAllUserTokens(ctx, userID)
|
||||
err = hs.AuthTokenService.RevokeAllUserTokens(ctx, userID)
|
||||
if err != nil {
|
||||
return response.Error(500, "Failed to logout user", err)
|
||||
}
|
||||
@@ -71,9 +72,10 @@ func (hs *HTTPServer) logoutUserFromAllDevicesInternal(ctx context.Context, user
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) getUserAuthTokensInternal(c *models.ReqContext, userID int64) response.Response {
|
||||
userQuery := models.GetUserByIdQuery{Id: userID}
|
||||
userQuery := user.GetUserByIDQuery{ID: userID}
|
||||
|
||||
if err := hs.SQLStore.GetUserById(c.Req.Context(), &userQuery); err != nil {
|
||||
_, err := hs.userService.GetByID(c.Req.Context(), &userQuery)
|
||||
if err != nil {
|
||||
if errors.Is(err, user.ErrUserNotFound) {
|
||||
return response.Error(http.StatusNotFound, "User not found", err)
|
||||
} else if errors.Is(err, user.ErrCaseInsensitive) {
|
||||
@@ -142,8 +144,9 @@ func (hs *HTTPServer) getUserAuthTokensInternal(c *models.ReqContext, userID int
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) revokeUserAuthTokenInternal(c *models.ReqContext, userID int64, cmd models.RevokeAuthTokenCmd) response.Response {
|
||||
userQuery := models.GetUserByIdQuery{Id: userID}
|
||||
if err := hs.SQLStore.GetUserById(c.Req.Context(), &userQuery); err != nil {
|
||||
userQuery := user.GetUserByIDQuery{ID: userID}
|
||||
_, err := hs.userService.GetByID(c.Req.Context(), &userQuery)
|
||||
if err != nil {
|
||||
if errors.Is(err, user.ErrUserNotFound) {
|
||||
return response.Error(404, "User not found", err)
|
||||
}
|
||||
|
||||
+28
-29
@@ -6,62 +6,61 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||
)
|
||||
|
||||
func TestUserTokenAPIEndpoint(t *testing.T) {
|
||||
mock := mockstore.NewSQLStoreMock()
|
||||
userMock := usertest.NewUserServiceFake()
|
||||
t.Run("When current user attempts to revoke an auth token for a non-existing user", func(t *testing.T) {
|
||||
cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
|
||||
mock.ExpectedError = user.ErrUserNotFound
|
||||
userMock.ExpectedError = user.ErrUserNotFound
|
||||
revokeUserAuthTokenScenario(t, "Should return not found when calling POST on", "/api/user/revoke-auth-token",
|
||||
"/api/user/revoke-auth-token", cmd, 200, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
}, mock)
|
||||
}, userMock)
|
||||
})
|
||||
|
||||
t.Run("When current user gets auth tokens for a non-existing user", func(t *testing.T) {
|
||||
mock := &mockstore.SQLStoreMock{
|
||||
mockUser := &usertest.FakeUserService{
|
||||
ExpectedUser: &user.User{ID: 200},
|
||||
ExpectedError: user.ErrUserNotFound,
|
||||
}
|
||||
getUserAuthTokensScenario(t, "Should return not found when calling GET on", "/api/user/auth-tokens", "/api/user/auth-tokens", 200, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
}, mock)
|
||||
}, mockUser)
|
||||
})
|
||||
|
||||
t.Run("When logging out an existing user from all devices", func(t *testing.T) {
|
||||
mock := &mockstore.SQLStoreMock{
|
||||
userMock := &usertest.FakeUserService{
|
||||
ExpectedUser: &user.User{ID: 200},
|
||||
}
|
||||
logoutUserFromAllDevicesInternalScenario(t, "Should be successful", 1, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
}, mock)
|
||||
}, userMock)
|
||||
})
|
||||
|
||||
t.Run("When logout a non-existing user from all devices", func(t *testing.T) {
|
||||
logoutUserFromAllDevicesInternalScenario(t, "Should return not found", testUserID, func(sc *scenarioContext) {
|
||||
mock.ExpectedError = user.ErrUserNotFound
|
||||
|
||||
userMock.ExpectedError = user.ErrUserNotFound
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
}, mock)
|
||||
}, userMock)
|
||||
})
|
||||
|
||||
t.Run("When revoke an auth token for a user", func(t *testing.T) {
|
||||
cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
|
||||
token := &models.UserToken{Id: 1}
|
||||
mock := &mockstore.SQLStoreMock{
|
||||
mockUser := &usertest.FakeUserService{
|
||||
ExpectedUser: &user.User{ID: 200},
|
||||
}
|
||||
|
||||
@@ -71,25 +70,25 @@ func TestUserTokenAPIEndpoint(t *testing.T) {
|
||||
}
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
}, mock)
|
||||
}, mockUser)
|
||||
})
|
||||
|
||||
t.Run("When revoke the active auth token used by himself", func(t *testing.T) {
|
||||
cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
|
||||
token := &models.UserToken{Id: 2}
|
||||
mock := mockstore.NewSQLStoreMock()
|
||||
mockUser := usertest.NewUserServiceFake()
|
||||
revokeUserAuthTokenInternalScenario(t, "Should not be successful", cmd, testUserID, token, func(sc *scenarioContext) {
|
||||
sc.userAuthTokenService.GetUserTokenProvider = func(ctx context.Context, userId, userTokenId int64) (*models.UserToken, error) {
|
||||
return token, nil
|
||||
}
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 400, sc.resp.Code)
|
||||
}, mock)
|
||||
}, mockUser)
|
||||
})
|
||||
|
||||
t.Run("When gets auth tokens for a user", func(t *testing.T) {
|
||||
currentToken := &models.UserToken{Id: 1}
|
||||
mock := mockstore.NewSQLStoreMock()
|
||||
mockUser := usertest.NewUserServiceFake()
|
||||
getUserAuthTokensInternalScenario(t, "Should be successful", currentToken, func(sc *scenarioContext) {
|
||||
tokens := []*models.UserToken{
|
||||
{
|
||||
@@ -141,18 +140,18 @@ func TestUserTokenAPIEndpoint(t *testing.T) {
|
||||
assert.Equal(t, "11.0", resultTwo.Get("browserVersion").MustString())
|
||||
assert.Equal(t, "iOS", resultTwo.Get("os").MustString())
|
||||
assert.Equal(t, "11.0", resultTwo.Get("osVersion").MustString())
|
||||
}, mock)
|
||||
}, mockUser)
|
||||
})
|
||||
}
|
||||
|
||||
func revokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePattern string, cmd models.RevokeAuthTokenCmd,
|
||||
userId int64, fn scenarioFunc, sqlStore sqlstore.Store) {
|
||||
userId int64, fn scenarioFunc, userService user.Service) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
|
||||
hs := HTTPServer{
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
SQLStore: sqlStore,
|
||||
userService: userService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, url)
|
||||
@@ -173,13 +172,13 @@ func revokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePat
|
||||
})
|
||||
}
|
||||
|
||||
func getUserAuthTokensScenario(t *testing.T, desc string, url string, routePattern string, userId int64, fn scenarioFunc, sqlStore sqlstore.Store) {
|
||||
func getUserAuthTokensScenario(t *testing.T, desc string, url string, routePattern string, userId int64, fn scenarioFunc, userService user.Service) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
|
||||
hs := HTTPServer{
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
SQLStore: sqlStore,
|
||||
userService: userService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, url)
|
||||
@@ -199,11 +198,11 @@ func getUserAuthTokensScenario(t *testing.T, desc string, url string, routePatte
|
||||
})
|
||||
}
|
||||
|
||||
func logoutUserFromAllDevicesInternalScenario(t *testing.T, desc string, userId int64, fn scenarioFunc, sqlStore sqlstore.Store) {
|
||||
func logoutUserFromAllDevicesInternalScenario(t *testing.T, desc string, userId int64, fn scenarioFunc, userService user.Service) {
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
hs := HTTPServer{
|
||||
AuthTokenService: auth.NewFakeUserAuthTokenService(),
|
||||
SQLStore: sqlStore,
|
||||
userService: userService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, "/")
|
||||
@@ -223,13 +222,13 @@ func logoutUserFromAllDevicesInternalScenario(t *testing.T, desc string, userId
|
||||
}
|
||||
|
||||
func revokeUserAuthTokenInternalScenario(t *testing.T, desc string, cmd models.RevokeAuthTokenCmd, userId int64,
|
||||
token *models.UserToken, fn scenarioFunc, sqlStore sqlstore.Store) {
|
||||
token *models.UserToken, fn scenarioFunc, userService user.Service) {
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
|
||||
hs := HTTPServer{
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
SQLStore: sqlStore,
|
||||
userService: userService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, "/")
|
||||
@@ -248,13 +247,13 @@ func revokeUserAuthTokenInternalScenario(t *testing.T, desc string, cmd models.R
|
||||
})
|
||||
}
|
||||
|
||||
func getUserAuthTokensInternalScenario(t *testing.T, desc string, token *models.UserToken, fn scenarioFunc, sqlStore sqlstore.Store) {
|
||||
func getUserAuthTokensInternalScenario(t *testing.T, desc string, token *models.UserToken, fn scenarioFunc, userService user.Service) {
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
|
||||
hs := HTTPServer{
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
SQLStore: sqlStore,
|
||||
userService: userService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, "/")
|
||||
|
||||
Reference in New Issue
Block a user