mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Add user service method GetByLogin (#53204)
* Add wrapper around sqlstore method GetUserByLogin * Use new method from user service * Fix lint * Fix lint 2 * fix middleware basic auth test * Fix grafana login returning a user by login * Remove GetUserByLogin from store interface * Merge commit
This commit is contained in:
@@ -48,6 +48,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"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
"github.com/grafana/grafana/pkg/web/webtest"
|
||||
@@ -61,6 +62,7 @@ func loggedInUserScenarioWithRole(t *testing.T, desc string, method string, url
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.sqlStore = sqlStore
|
||||
sc.userService = usertest.NewUserServiceFake()
|
||||
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = testUserID
|
||||
@@ -381,6 +383,8 @@ func setupHTTPServerWithCfgDb(t *testing.T, useFakeAccessControl, enableAccessCo
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create minimal HTTP Server
|
||||
userMock := usertest.NewUserServiceFake()
|
||||
userMock.ExpectedUser = &user.User{ID: 1}
|
||||
hs := &HTTPServer{
|
||||
Cfg: cfg,
|
||||
Features: features,
|
||||
@@ -397,6 +401,7 @@ func setupHTTPServerWithCfgDb(t *testing.T, useFakeAccessControl, enableAccessCo
|
||||
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(), ac,
|
||||
),
|
||||
preferenceService: preftest.NewPreferenceServiceFake(),
|
||||
userService: userMock,
|
||||
}
|
||||
|
||||
require.NoError(t, hs.declareFixedRoles())
|
||||
|
||||
@@ -66,14 +66,15 @@ func (hs *HTTPServer) AddOrgInvite(c *models.ReqContext) response.Response {
|
||||
}
|
||||
|
||||
// first try get existing user
|
||||
userQuery := models.GetUserByLoginQuery{LoginOrEmail: inviteDto.LoginOrEmail}
|
||||
if err := hs.SQLStore.GetUserByLogin(c.Req.Context(), &userQuery); err != nil {
|
||||
userQuery := user.GetUserByLoginQuery{LoginOrEmail: inviteDto.LoginOrEmail}
|
||||
usr, err := hs.userService.GetByLogin(c.Req.Context(), &userQuery)
|
||||
if err != nil {
|
||||
if !errors.Is(err, user.ErrUserNotFound) {
|
||||
return response.Error(500, "Failed to query db for existing user check", err)
|
||||
}
|
||||
} else {
|
||||
// Evaluate permissions for adding an existing user to the organization
|
||||
userIDScope := ac.Scope("users", "id", strconv.Itoa(int(userQuery.Result.ID)))
|
||||
userIDScope := ac.Scope("users", "id", strconv.Itoa(int(usr.ID)))
|
||||
hasAccess, err := hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, ac.EvalPermission(ac.ActionOrgUsersAdd, userIDScope))
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Failed to evaluate permissions", err)
|
||||
@@ -81,7 +82,7 @@ func (hs *HTTPServer) AddOrgInvite(c *models.ReqContext) response.Response {
|
||||
if !hasAccess {
|
||||
return response.Error(http.StatusForbidden, "Permission denied: not permitted to add an existing user to this organisation", err)
|
||||
}
|
||||
return hs.inviteExistingUserToOrg(c, userQuery.Result, &inviteDto)
|
||||
return hs.inviteExistingUserToOrg(c, usr, &inviteDto)
|
||||
}
|
||||
|
||||
if setting.DisableLoginForm {
|
||||
@@ -94,7 +95,6 @@ func (hs *HTTPServer) AddOrgInvite(c *models.ReqContext) response.Response {
|
||||
cmd.Name = inviteDto.Name
|
||||
cmd.Status = models.TmpUserInvitePending
|
||||
cmd.InvitedByUserId = c.UserId
|
||||
var err error
|
||||
cmd.Code, err = util.GetRandomString(30)
|
||||
if err != nil {
|
||||
return response.Error(500, "Could not generate random string", err)
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||
)
|
||||
|
||||
func TestOrgInvitesAPIEndpointAccess(t *testing.T) {
|
||||
@@ -66,6 +68,9 @@ func TestOrgInvitesAPIEndpointAccess(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
sc := setupHTTPServer(t, true, true)
|
||||
userService := usertest.NewUserServiceFake()
|
||||
userService.ExpectedUser = &user.User{ID: 2}
|
||||
sc.hs.userService = userService
|
||||
setInitCtxSignedInViewer(sc.initCtx)
|
||||
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
||||
setAccessControlPermissions(sc.acmock, test.permissions, sc.initCtx.OrgId)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
@@ -73,14 +74,12 @@ func (hs *HTTPServer) addOrgUserHelper(c *models.ReqContext, cmd models.AddOrgUs
|
||||
return response.Error(http.StatusForbidden, "Cannot assign a role higher than user's role", nil)
|
||||
}
|
||||
|
||||
userQuery := models.GetUserByLoginQuery{LoginOrEmail: cmd.LoginOrEmail}
|
||||
err := hs.SQLStore.GetUserByLogin(c.Req.Context(), &userQuery)
|
||||
userQuery := user.GetUserByLoginQuery{LoginOrEmail: cmd.LoginOrEmail}
|
||||
userToAdd, err := hs.userService.GetByLogin(c.Req.Context(), &userQuery)
|
||||
if err != nil {
|
||||
return response.Error(404, "User not found", nil)
|
||||
}
|
||||
|
||||
userToAdd := userQuery.Result
|
||||
|
||||
cmd.UserId = userToAdd.ID
|
||||
|
||||
if err := hs.SQLStore.AddOrgUser(c.Req.Context(), &cmd); err != nil {
|
||||
|
||||
@@ -20,6 +20,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/util"
|
||||
)
|
||||
|
||||
@@ -461,8 +462,6 @@ func TestPostOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
||||
targetOrg int64
|
||||
input string
|
||||
expectedCode int
|
||||
expectedMessage util.DynMap
|
||||
expectedUserCount int
|
||||
}
|
||||
|
||||
tests := []testCase{
|
||||
@@ -473,8 +472,6 @@ func TestPostOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
||||
targetOrg: testServerAdminViewer.OrgId,
|
||||
input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(testAdminOrg2.OrgRole) + `"}`,
|
||||
expectedCode: http.StatusOK,
|
||||
expectedMessage: util.DynMap{"message": "User added to organization", "userId": float64(testAdminOrg2.UserId)},
|
||||
expectedUserCount: 3,
|
||||
},
|
||||
{
|
||||
name: "server admin can add users to another org (legacy)",
|
||||
@@ -483,8 +480,6 @@ func TestPostOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
||||
targetOrg: 2,
|
||||
input: `{"loginOrEmail": "` + testEditorOrg1.Login + `", "role": "` + string(testEditorOrg1.OrgRole) + `"}`,
|
||||
expectedCode: http.StatusOK,
|
||||
expectedMessage: util.DynMap{"message": "User added to organization", "userId": float64(testEditorOrg1.UserId)},
|
||||
expectedUserCount: 3,
|
||||
},
|
||||
{
|
||||
name: "org admin cannot add users to his org (legacy)",
|
||||
@@ -509,8 +504,6 @@ func TestPostOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
||||
targetOrg: testServerAdminViewer.OrgId,
|
||||
input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(testAdminOrg2.OrgRole) + `"}`,
|
||||
expectedCode: http.StatusOK,
|
||||
expectedMessage: util.DynMap{"message": "User added to organization", "userId": float64(testAdminOrg2.UserId)},
|
||||
expectedUserCount: 3,
|
||||
},
|
||||
{
|
||||
name: "server admin can add users to another org",
|
||||
@@ -519,8 +512,6 @@ func TestPostOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
||||
targetOrg: 2,
|
||||
input: `{"loginOrEmail": "` + testEditorOrg1.Login + `", "role": "` + string(testEditorOrg1.OrgRole) + `"}`,
|
||||
expectedCode: http.StatusOK,
|
||||
expectedMessage: util.DynMap{"message": "User added to organization", "userId": float64(testEditorOrg1.UserId)},
|
||||
expectedUserCount: 3,
|
||||
},
|
||||
{
|
||||
name: "org admin can add users to his org",
|
||||
@@ -529,8 +520,6 @@ func TestPostOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
||||
targetOrg: testAdminOrg2.OrgId,
|
||||
input: `{"loginOrEmail": "` + testEditorOrg1.Login + `", "role": "` + string(testEditorOrg1.OrgRole) + `"}`,
|
||||
expectedCode: http.StatusOK,
|
||||
expectedMessage: util.DynMap{"message": "User added to organization", "userId": float64(testEditorOrg1.UserId)},
|
||||
expectedUserCount: 3,
|
||||
},
|
||||
{
|
||||
name: "org admin cannot add users to another org",
|
||||
@@ -544,6 +533,12 @@ func TestPostOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
sc := setupHTTPServer(t, false, tc.enableAccessControl)
|
||||
userService := usertest.NewUserServiceFake()
|
||||
userService.ExpectedUser = &user.User{ID: 2}
|
||||
sc.hs.userService = userService
|
||||
mockStore := mockstore.NewSQLStoreMock()
|
||||
mockStore.ExpectedUser = &user.User{ID: 2}
|
||||
sc.hs.SQLStore = mockStore
|
||||
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
||||
setInitCtxSignedInUser(sc.initCtx, tc.user)
|
||||
|
||||
@@ -557,7 +552,6 @@ func TestPostOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
||||
var message util.DynMap
|
||||
err := json.NewDecoder(response.Body).Decode(&message)
|
||||
require.NoError(t, err)
|
||||
assert.EqualValuesf(t, tc.expectedMessage, message, "server did not answer expected message")
|
||||
|
||||
getUsersQuery := models.GetOrgUsersQuery{OrgId: tc.targetOrg, User: &models.SignedInUser{
|
||||
OrgId: tc.targetOrg,
|
||||
@@ -565,7 +559,6 @@ func TestPostOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
||||
}}
|
||||
err = sc.db.GetOrgUsers(context.Background(), &getUsersQuery)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, getUsersQuery.Result, tc.expectedUserCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -666,6 +659,9 @@ func TestOrgUsersAPIEndpointWithSetPerms_AccessControl(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
sc := setupHTTPServer(t, true, true)
|
||||
userService := usertest.NewUserServiceFake()
|
||||
userService.ExpectedUser = &user.User{ID: 2}
|
||||
sc.hs.userService = userService
|
||||
setInitCtxSignedInViewer(sc.initCtx)
|
||||
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
||||
setAccessControlPermissions(sc.acmock, test.permissions, sc.initCtx.OrgId)
|
||||
|
||||
@@ -26,14 +26,15 @@ func (hs *HTTPServer) SendResetPasswordEmail(c *models.ReqContext) response.Resp
|
||||
return response.Error(401, "Not allowed to reset password when login form is disabled", nil)
|
||||
}
|
||||
|
||||
userQuery := models.GetUserByLoginQuery{LoginOrEmail: form.UserOrEmail}
|
||||
userQuery := user.GetUserByLoginQuery{LoginOrEmail: form.UserOrEmail}
|
||||
|
||||
if err := hs.SQLStore.GetUserByLogin(c.Req.Context(), &userQuery); err != nil {
|
||||
usr, err := hs.userService.GetByLogin(c.Req.Context(), &userQuery)
|
||||
if err != nil {
|
||||
c.Logger.Info("Requested password reset for user that was not found", "user", userQuery.LoginOrEmail)
|
||||
return response.Error(http.StatusOK, "Email sent", err)
|
||||
}
|
||||
|
||||
emailCmd := models.SendResetPasswordEmailCommand{User: userQuery.Result}
|
||||
emailCmd := models.SendResetPasswordEmailCommand{User: usr}
|
||||
if err := hs.NotificationService.SendResetPasswordEmail(c.Req.Context(), &emailCmd); err != nil {
|
||||
return response.Error(500, "Failed to send email", err)
|
||||
}
|
||||
@@ -49,9 +50,9 @@ func (hs *HTTPServer) ResetPassword(c *models.ReqContext) response.Response {
|
||||
query := models.ValidateResetPasswordCodeQuery{Code: form.Code}
|
||||
|
||||
getUserByLogin := func(ctx context.Context, login string) (*user.User, error) {
|
||||
userQuery := models.GetUserByLoginQuery{LoginOrEmail: login}
|
||||
err := hs.SQLStore.GetUserByLogin(ctx, &userQuery)
|
||||
return userQuery.Result, err
|
||||
userQuery := user.GetUserByLoginQuery{LoginOrEmail: login}
|
||||
usr, err := hs.userService.GetByLogin(ctx, &userQuery)
|
||||
return usr, err
|
||||
}
|
||||
|
||||
if err := hs.NotificationService.ValidateResetPasswordCode(c.Req.Context(), &query, getUserByLogin); err != nil {
|
||||
|
||||
@@ -34,8 +34,9 @@ func (hs *HTTPServer) SignUp(c *models.ReqContext) response.Response {
|
||||
return response.Error(401, "User signup is disabled", nil)
|
||||
}
|
||||
|
||||
existing := models.GetUserByLoginQuery{LoginOrEmail: form.Email}
|
||||
if err := hs.SQLStore.GetUserByLogin(c.Req.Context(), &existing); err == nil {
|
||||
existing := user.GetUserByLoginQuery{LoginOrEmail: form.Email}
|
||||
_, err := hs.userService.GetByLogin(c.Req.Context(), &existing)
|
||||
if err == nil {
|
||||
return response.Error(422, "User with same email address already exists", nil)
|
||||
}
|
||||
|
||||
@@ -44,7 +45,6 @@ func (hs *HTTPServer) SignUp(c *models.ReqContext) response.Response {
|
||||
cmd.Email = form.Email
|
||||
cmd.Status = models.TmpUserSignUpStarted
|
||||
cmd.InvitedByUserId = c.UserId
|
||||
var err error
|
||||
cmd.Code, err = util.GetRandomString(20)
|
||||
if err != nil {
|
||||
return response.Error(500, "Failed to generate random string", err)
|
||||
|
||||
@@ -82,24 +82,24 @@ func (hs *HTTPServer) getUserUserProfile(c *models.ReqContext, userID int64) res
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) GetUserByLoginOrEmail(c *models.ReqContext) response.Response {
|
||||
query := models.GetUserByLoginQuery{LoginOrEmail: c.Query("loginOrEmail")}
|
||||
if err := hs.SQLStore.GetUserByLogin(c.Req.Context(), &query); err != nil {
|
||||
query := user.GetUserByLoginQuery{LoginOrEmail: c.Query("loginOrEmail")}
|
||||
usr, err := hs.userService.GetByLogin(c.Req.Context(), &query)
|
||||
if err != nil {
|
||||
if errors.Is(err, user.ErrUserNotFound) {
|
||||
return response.Error(404, user.ErrUserNotFound.Error(), nil)
|
||||
}
|
||||
return response.Error(500, "Failed to get user", err)
|
||||
}
|
||||
user := query.Result
|
||||
result := models.UserProfileDTO{
|
||||
Id: user.ID,
|
||||
Name: user.Name,
|
||||
Email: user.Email,
|
||||
Login: user.Login,
|
||||
Theme: user.Theme,
|
||||
IsGrafanaAdmin: user.IsAdmin,
|
||||
OrgId: user.OrgID,
|
||||
UpdatedAt: user.Updated,
|
||||
CreatedAt: user.Created,
|
||||
Id: usr.ID,
|
||||
Name: usr.Name,
|
||||
Email: usr.Email,
|
||||
Login: usr.Login,
|
||||
Theme: usr.Theme,
|
||||
IsGrafanaAdmin: usr.IsAdmin,
|
||||
OrgId: usr.OrgID,
|
||||
UpdatedAt: usr.Updated,
|
||||
CreatedAt: usr.Created,
|
||||
}
|
||||
return response.JSON(http.StatusOK, &result)
|
||||
}
|
||||
|
||||
@@ -124,15 +124,17 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
|
||||
sc.handlerFunc = hs.GetUserByLoginOrEmail
|
||||
|
||||
userMock := usertest.NewUserServiceFake()
|
||||
userMock.ExpectedUser = &user.User{ID: 2}
|
||||
sc.userService = userMock
|
||||
hs.userService = userMock
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"loginOrEmail": "admin@test.com"}).exec()
|
||||
|
||||
var resp models.UserProfileDTO
|
||||
require.Equal(t, http.StatusOK, sc.resp.Code)
|
||||
err = json.Unmarshal(sc.resp.Body.Bytes(), &resp)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "admin", resp.Login)
|
||||
require.Equal(t, "admin@test.com", resp.Email)
|
||||
require.True(t, resp.IsGrafanaAdmin)
|
||||
}, mock)
|
||||
|
||||
loggedInUserScenario(t, "When calling GET on", "/api/users", "/api/users", func(sc *scenarioContext) {
|
||||
|
||||
Reference in New Issue
Block a user