MM-32471: Use created user to update roles (#16895)
During user creation via CLI, we would create the user, but pass the user ID instead when updating the roles. This falls into the category of read-after-write within a single request. We fix this by passing the already created user and directly update the roles. https://mattermost.atlassian.net/browse/MM-32471 ```release-note NONE ```
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
1e3b6b56a6
Коммит
d8b94836cf
@@ -1023,6 +1023,7 @@ type AppIface interface {
|
|||||||
UpdateUserAuth(userID string, userAuth *model.UserAuth) (*model.UserAuth, *model.AppError)
|
UpdateUserAuth(userID string, userAuth *model.UserAuth) (*model.UserAuth, *model.AppError)
|
||||||
UpdateUserNotifyProps(userID string, props map[string]string, sendNotifications bool) (*model.User, *model.AppError)
|
UpdateUserNotifyProps(userID string, props map[string]string, sendNotifications bool) (*model.User, *model.AppError)
|
||||||
UpdateUserRoles(userID string, newRoles string, sendWebSocketEvent bool) (*model.User, *model.AppError)
|
UpdateUserRoles(userID string, newRoles string, sendWebSocketEvent bool) (*model.User, *model.AppError)
|
||||||
|
UpdateUserRolesWithUser(user *model.User, newRoles string, sendWebSocketEvent bool) (*model.User, *model.AppError)
|
||||||
UploadData(us *model.UploadSession, rd io.Reader) (*model.FileInfo, *model.AppError)
|
UploadData(us *model.UploadSession, rd io.Reader) (*model.FileInfo, *model.AppError)
|
||||||
UploadEmojiImage(id string, imageData *multipart.FileHeader) *model.AppError
|
UploadEmojiImage(id string, imageData *multipart.FileHeader) *model.AppError
|
||||||
UploadMultipartFiles(teamID string, channelId string, userID string, fileHeaders []*multipart.FileHeader, clientIds []string, now time.Time) (*model.FileUploadResponse, *model.AppError)
|
UploadMultipartFiles(teamID string, channelId string, userID string, fileHeaders []*multipart.FileHeader, clientIds []string, now time.Time) (*model.FileUploadResponse, *model.AppError)
|
||||||
|
|||||||
@@ -15732,6 +15732,28 @@ func (a *OpenTracingAppLayer) UpdateUserRoles(userID string, newRoles string, se
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) UpdateUserRolesWithUser(user *model.User, newRoles string, sendWebSocketEvent bool) (*model.User, *model.AppError) {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateUserRolesWithUser")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := a.app.UpdateUserRolesWithUser(user, newRoles, sendWebSocketEvent)
|
||||||
|
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) UpdateViewedProductNotices(userID string, noticeIds []string) *model.AppError {
|
func (a *OpenTracingAppLayer) UpdateViewedProductNotices(userID string, noticeIds []string) *model.AppError {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateViewedProductNotices")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateViewedProductNotices")
|
||||||
|
|||||||
@@ -1547,6 +1547,11 @@ func (a *App) UpdateUserRoles(userID string, newRoles string, sendWebSocketEvent
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return a.UpdateUserRolesWithUser(user, newRoles, sendWebSocketEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) UpdateUserRolesWithUser(user *model.User, newRoles string, sendWebSocketEvent bool) (*model.User, *model.AppError) {
|
||||||
|
|
||||||
if err := a.CheckRolesExist(strings.Fields(newRoles)); err != nil {
|
if err := a.CheckRolesExist(strings.Fields(newRoles)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1586,7 +1591,7 @@ func (a *App) UpdateUserRoles(userID string, newRoles string, sendWebSocketEvent
|
|||||||
mlog.Warn("Failed during updating user roles", mlog.Err(result.NErr))
|
mlog.Warn("Failed during updating user roles", mlog.Err(result.NErr))
|
||||||
}
|
}
|
||||||
|
|
||||||
a.InvalidateCacheForUser(userID)
|
a.InvalidateCacheForUser(user.Id)
|
||||||
a.ClearSessionCacheForUser(user.Id)
|
a.ClearSessionCacheForUser(user.Id)
|
||||||
|
|
||||||
if sendWebSocketEvent {
|
if sendWebSocketEvent {
|
||||||
|
|||||||
@@ -1374,3 +1374,23 @@ func TestDeactivateGuests(t *testing.T) {
|
|||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, int64(0), user.DeleteAt)
|
assert.Equal(t, int64(0), user.DeleteAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateUserRolesWithUser(t *testing.T) {
|
||||||
|
// InitBasic is used to let the first CreateUser call not be
|
||||||
|
// a system_admin
|
||||||
|
th := Setup(t).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
// Create normal user.
|
||||||
|
user := th.CreateUser()
|
||||||
|
assert.Equal(t, user.Roles, model.SYSTEM_USER_ROLE_ID)
|
||||||
|
|
||||||
|
// Upgrade to sysadmin.
|
||||||
|
user, err := th.App.UpdateUserRolesWithUser(user, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_ADMIN_ROLE_ID, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Equal(t, user.Roles, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_ADMIN_ROLE_ID)
|
||||||
|
|
||||||
|
// Test bad role.
|
||||||
|
_, err = th.App.UpdateUserRolesWithUser(user, "does not exist", false)
|
||||||
|
require.NotNil(t, err)
|
||||||
|
}
|
||||||
|
|||||||
@@ -377,13 +377,13 @@ func userCreateCmdF(command *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if systemAdmin {
|
if systemAdmin {
|
||||||
if _, err := a.UpdateUserRoles(ruser.Id, "system_user system_admin", false); err != nil {
|
if _, err := a.UpdateUserRolesWithUser(ruser, "system_user system_admin", false); err != nil {
|
||||||
return errors.New("Unable to make user system admin. Error: " + err.Error())
|
return errors.New("Unable to make user system admin. Error: " + err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This else case exists to prevent the first user created from being
|
// This else case exists to prevent the first user created from being
|
||||||
// created as a system admin unless explicitly specified.
|
// created as a system admin unless explicitly specified.
|
||||||
if _, err := a.UpdateUserRoles(ruser.Id, "system_user", false); err != nil {
|
if _, err := a.UpdateUserRolesWithUser(ruser, "system_user", false); err != nil {
|
||||||
return errors.New("If this is the first user: Unable to prevent user from being system admin. Error: " + err.Error())
|
return errors.New("If this is the first user: Unable to prevent user from being system admin. Error: " + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user