mirror of
https://github.com/mattermost/mattermost.git
synced 2026-05-28 04:35:04 -04:00
[MM-63355] Add AuthData to mmctl user search output (#30478)
This commit is contained in:
parent
04a60b6609
commit
cfc1503d62
7 changed files with 138 additions and 72 deletions
|
|
@ -1638,6 +1638,38 @@ func TestSearchUsers(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, users[0].Id, th.BasicUser.Id)
|
||||
})
|
||||
|
||||
// Create LDAP user
|
||||
authData := "some auth data"
|
||||
ldapUser := &model.User{
|
||||
Email: th.GenerateTestEmail(),
|
||||
Username: GenerateTestUsername(),
|
||||
EmailVerified: true,
|
||||
AuthService: model.UserAuthServiceLdap,
|
||||
AuthData: &authData,
|
||||
}
|
||||
ldapUser, appErr = th.App.CreateUser(th.Context, ldapUser)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
t.Run("LDAP authdata field is returned appropriately", func(t *testing.T) {
|
||||
// Search as regular user
|
||||
search := &model.UserSearch{Term: ldapUser.Username}
|
||||
users, resp, err := th.Client.SearchUsers(context.Background(), search)
|
||||
require.NoError(t, err)
|
||||
CheckOKStatus(t, resp)
|
||||
require.Len(t, users, 1, "should find the ldap user")
|
||||
require.Equal(t, ldapUser.Id, users[0].Id)
|
||||
require.Empty(t, users[0].AuthData, "regular user should not see AuthData")
|
||||
|
||||
// Search as system admin
|
||||
users, resp, err = th.SystemAdminClient.SearchUsers(context.Background(), search)
|
||||
require.NoError(t, err)
|
||||
CheckOKStatus(t, resp)
|
||||
require.Len(t, users, 1, "should find the ldap user")
|
||||
require.Equal(t, ldapUser.Id, users[0].Id)
|
||||
require.NotNil(t, users[0].AuthData, "admin should see AuthData")
|
||||
require.Equal(t, *ldapUser.AuthData, *users[0].AuthData)
|
||||
})
|
||||
}
|
||||
|
||||
func findUserInList(id string, users []*model.User) bool { //nolint:unused
|
||||
|
|
@ -2993,6 +3025,27 @@ func TestGetUsers(t *testing.T) {
|
|||
require.Equal(t, err.Error(), "Invalid or missing role in request body.")
|
||||
})
|
||||
|
||||
th.TestForSystemAdminAndLocal(t, func(t *testing.T, c *model.Client4) {
|
||||
user := &model.User{
|
||||
Email: th.GenerateTestEmail(),
|
||||
Username: GenerateTestUsername(),
|
||||
AuthService: model.UserAuthServiceLdap,
|
||||
AuthData: model.NewPointer(model.NewId()),
|
||||
}
|
||||
u, resp, err := c.CreateUser(context.Background(), user)
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
require.NotNil(t, u)
|
||||
|
||||
u, resp, err = c.GetUser(context.Background(), u.Id, "")
|
||||
require.NoError(t, err)
|
||||
CheckOKStatus(t, resp)
|
||||
require.NotNil(t, u)
|
||||
|
||||
assert.Equal(t, user.AuthService, u.AuthService)
|
||||
assert.Equal(t, user.AuthData, u.AuthData)
|
||||
}, "AuthData is returned for admins")
|
||||
|
||||
_, err := th.Client.Logout(context.Background())
|
||||
require.NoError(t, err)
|
||||
_, resp, err := th.Client.GetUsers(context.Background(), 0, 60, "")
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ func (us *UserService) GetSanitizeOptions(asAdmin bool) map[string]bool {
|
|||
options["email"] = true
|
||||
options["fullname"] = true
|
||||
options["authservice"] = true
|
||||
options["authdata"] = true
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2795,13 +2795,6 @@ func testUserStoreSearch(t *testing.T, rctx request.CTX, ss store.Store) {
|
|||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }()
|
||||
|
||||
// The users returned from the database will have AuthData as an empty string.
|
||||
nilAuthData := new(string)
|
||||
*nilAuthData = ""
|
||||
u1.AuthData = nilAuthData
|
||||
u2.AuthData = nilAuthData
|
||||
u3.AuthData = nilAuthData
|
||||
|
||||
t1id := model.NewId()
|
||||
_, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: t1id, UserId: u1.Id, SchemeAdmin: true, SchemeUser: true}, -1)
|
||||
require.NoError(t, nErr)
|
||||
|
|
@ -2981,14 +2974,6 @@ func testUserStoreSearchNotInChannel(t *testing.T, rctx request.CTX, ss store.St
|
|||
_, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: tid, UserId: u3.Id}, -1)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
// The users returned from the database will have AuthData as an empty string.
|
||||
nilAuthData := new(string)
|
||||
*nilAuthData = ""
|
||||
|
||||
u1.AuthData = nilAuthData
|
||||
u2.AuthData = nilAuthData
|
||||
u3.AuthData = nilAuthData
|
||||
|
||||
ch1 := model.Channel{
|
||||
TeamId: tid,
|
||||
DisplayName: "NameName",
|
||||
|
|
@ -3210,14 +3195,6 @@ func testUserStoreSearchInChannel(t *testing.T, rctx request.CTX, ss store.Store
|
|||
_, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: tid, UserId: u3.Id}, -1)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
// The users returned from the database will have AuthData as an empty string.
|
||||
nilAuthData := new(string)
|
||||
*nilAuthData = ""
|
||||
|
||||
u1.AuthData = nilAuthData
|
||||
u2.AuthData = nilAuthData
|
||||
u3.AuthData = nilAuthData
|
||||
|
||||
ch1 := model.Channel{
|
||||
TeamId: tid,
|
||||
DisplayName: "NameName",
|
||||
|
|
@ -3481,17 +3458,6 @@ func testUserStoreSearchNotInTeam(t *testing.T, rctx request.CTX, ss store.Store
|
|||
_, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID2, UserId: u4.Id}, -1)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
// The users returned from the database will have AuthData as an empty string.
|
||||
nilAuthData := new(string)
|
||||
*nilAuthData = ""
|
||||
|
||||
u1.AuthData = nilAuthData
|
||||
u2.AuthData = nilAuthData
|
||||
u3.AuthData = nilAuthData
|
||||
u4.AuthData = nilAuthData
|
||||
u5.AuthData = nilAuthData
|
||||
u6.AuthData = nilAuthData
|
||||
|
||||
testCases := []struct {
|
||||
Description string
|
||||
TeamID string
|
||||
|
|
@ -3629,14 +3595,6 @@ func testUserStoreSearchWithoutTeam(t *testing.T, rctx request.CTX, ss store.Sto
|
|||
_, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: tid, UserId: u3.Id}, -1)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
// The users returned from the database will have AuthData as an empty string.
|
||||
nilAuthData := new(string)
|
||||
*nilAuthData = ""
|
||||
|
||||
u1.AuthData = nilAuthData
|
||||
u2.AuthData = nilAuthData
|
||||
u3.AuthData = nilAuthData
|
||||
|
||||
testCases := []struct {
|
||||
Description string
|
||||
Term string
|
||||
|
|
@ -3721,13 +3679,6 @@ func testUserStoreSearchInGroup(t *testing.T, rctx request.CTX, ss store.Store)
|
|||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }()
|
||||
|
||||
// The users returned from the database will have AuthData as an empty string.
|
||||
nilAuthData := model.NewPointer("")
|
||||
|
||||
u1.AuthData = nilAuthData
|
||||
u2.AuthData = nilAuthData
|
||||
u3.AuthData = nilAuthData
|
||||
|
||||
g1 := &model.Group{
|
||||
Name: model.NewPointer(NewTestID()),
|
||||
DisplayName: NewTestID(),
|
||||
|
|
@ -3864,13 +3815,6 @@ func testUserStoreSearchNotInGroup(t *testing.T, rctx request.CTX, ss store.Stor
|
|||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }()
|
||||
|
||||
// The users returned from the database will have AuthData as an empty string.
|
||||
nilAuthData := model.NewPointer("")
|
||||
|
||||
u1.AuthData = nilAuthData
|
||||
u2.AuthData = nilAuthData
|
||||
u3.AuthData = nilAuthData
|
||||
|
||||
g1 := &model.Group{
|
||||
Name: model.NewPointer(NewTestID()),
|
||||
DisplayName: NewTestID(),
|
||||
|
|
|
|||
|
|
@ -779,6 +779,7 @@ func deleteAllUsersCmdF(c client.Client, cmd *cobra.Command, args []string) erro
|
|||
type userOut struct {
|
||||
*model.User
|
||||
Deactivated bool
|
||||
AuthData string
|
||||
}
|
||||
|
||||
func searchUserCmdF(c client.Client, cmd *cobra.Command, args []string) error {
|
||||
|
|
@ -799,6 +800,10 @@ func searchUserCmdF(c client.Client, cmd *cobra.Command, args []string) error {
|
|||
User: user,
|
||||
Deactivated: !(user.DeleteAt == 0),
|
||||
}
|
||||
if user.AuthData != nil {
|
||||
uout.AuthData = *user.AuthData
|
||||
}
|
||||
|
||||
tpl := `id: {{.Id}}
|
||||
deactivated: {{.Deactivated}}
|
||||
username: {{.Username}}
|
||||
|
|
@ -807,7 +812,8 @@ position: {{.Position}}
|
|||
first_name: {{.FirstName}}
|
||||
last_name: {{.LastName}}
|
||||
email: {{.Email}}
|
||||
auth_service: {{.AuthService}}`
|
||||
auth_service: {{.AuthService}}
|
||||
auth_data: {{.AuthData}}`
|
||||
if i > 0 {
|
||||
tpl = "------------------------------\n" + tpl
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,6 +128,8 @@ func (s *MmctlE2ETestSuite) TestSearchUserCmd() {
|
|||
user := printer.GetLines()[0].(userOut)
|
||||
s.Equal(s.th.BasicUser.Username, user.Username)
|
||||
s.False(user.Deactivated)
|
||||
s.Empty(user.AuthData)
|
||||
s.Empty(user.AuthService)
|
||||
s.Len(printer.GetErrorLines(), 0)
|
||||
})
|
||||
|
||||
|
|
@ -149,6 +151,44 @@ func (s *MmctlE2ETestSuite) TestSearchUserCmd() {
|
|||
user := printer.GetLines()[0].(userOut)
|
||||
s.Equal(disabledUser.Username, user.Username)
|
||||
s.True(user.Deactivated) // Verify user shows as deactivated
|
||||
s.Empty(user.AuthData)
|
||||
s.Empty(user.AuthService)
|
||||
s.Len(printer.GetErrorLines(), 0)
|
||||
})
|
||||
|
||||
// Create a LDAP user
|
||||
ldapUser, appErr := s.th.App.CreateUser(s.th.Context, &model.User{
|
||||
Email: s.th.GenerateTestEmail(),
|
||||
Username: model.NewUsername(),
|
||||
AuthData: model.NewPointer("1234"),
|
||||
AuthService: model.UserAuthServiceLdap,
|
||||
})
|
||||
s.Require().Nil(appErr)
|
||||
|
||||
s.RunForSystemAdminAndLocal("Search for a user with authData", func(c client.Client) {
|
||||
printer.Clean()
|
||||
err := searchUserCmdF(c, &cobra.Command{}, []string{ldapUser.Email})
|
||||
s.Require().Nil(err)
|
||||
s.Len(printer.GetLines(), 1)
|
||||
user := printer.GetLines()[0].(userOut)
|
||||
s.Equal(ldapUser.Username, user.Username)
|
||||
s.False(user.Deactivated)
|
||||
s.Equal(*ldapUser.AuthData, user.AuthData)
|
||||
s.Equal(ldapUser.AuthService, user.AuthService)
|
||||
s.Len(printer.GetErrorLines(), 0)
|
||||
})
|
||||
|
||||
s.Run("Search for a user with authData/Client", func() {
|
||||
printer.Clean()
|
||||
// Non-admin should not be able to see AuthData or AuthService
|
||||
err := searchUserCmdF(s.th.Client, &cobra.Command{}, []string{ldapUser.Email})
|
||||
s.Require().Nil(err)
|
||||
s.Len(printer.GetLines(), 1)
|
||||
user := printer.GetLines()[0].(userOut)
|
||||
s.Equal(ldapUser.Username, user.Username)
|
||||
s.False(user.Deactivated)
|
||||
s.Equal("", user.AuthData)
|
||||
s.Equal("", user.AuthService)
|
||||
s.Len(printer.GetErrorLines(), 0)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -628,6 +628,24 @@ func (s *MmctlUnitTestSuite) TestSearchUserCmd() {
|
|||
s.Require().Len(printer.GetErrorLines(), 0)
|
||||
})
|
||||
|
||||
s.Run("Search for a user with authData", func() {
|
||||
printer.Clean()
|
||||
emailArg := "example@example.com"
|
||||
mockUser := &model.User{Username: "ExampleUser", Email: emailArg, AuthData: model.NewPointer("1234"), AuthService: model.UserAuthServiceLdap}
|
||||
|
||||
s.client.
|
||||
EXPECT().
|
||||
GetUserByEmail(context.TODO(), emailArg, "").
|
||||
Return(mockUser, &model.Response{}, nil).
|
||||
Times(1)
|
||||
|
||||
err := searchUserCmdF(s.client, &cobra.Command{}, []string{emailArg})
|
||||
s.Require().Nil(err)
|
||||
s.Require().Len(printer.GetLines(), 1)
|
||||
s.Require().Equal(userOut{User: mockUser, Deactivated: false, AuthData: "1234"}, printer.GetLines()[0])
|
||||
s.Require().Len(printer.GetErrorLines(), 0)
|
||||
})
|
||||
|
||||
s.Run("Search for a nonexistent user", func() {
|
||||
printer.Clean()
|
||||
arg := "example@example.com"
|
||||
|
|
|
|||
|
|
@ -659,24 +659,28 @@ func (u *User) Etag(showFullName, showEmail bool) string {
|
|||
// Remove any private data from the user object
|
||||
func (u *User) Sanitize(options map[string]bool) {
|
||||
u.Password = ""
|
||||
u.AuthData = NewPointer("")
|
||||
u.MfaSecret = ""
|
||||
u.MfaUsedTimestamps = nil
|
||||
u.LastLogin = 0
|
||||
|
||||
if len(options) != 0 && !options["email"] {
|
||||
u.Email = ""
|
||||
delete(u.Props, UserPropsKeyRemoteEmail)
|
||||
}
|
||||
if len(options) != 0 && !options["fullname"] {
|
||||
u.FirstName = ""
|
||||
u.LastName = ""
|
||||
}
|
||||
if len(options) != 0 && !options["passwordupdate"] {
|
||||
u.LastPasswordUpdate = 0
|
||||
}
|
||||
if len(options) != 0 && !options["authservice"] {
|
||||
u.AuthService = ""
|
||||
if len(options) != 0 {
|
||||
if !options["email"] {
|
||||
u.Email = ""
|
||||
delete(u.Props, UserPropsKeyRemoteEmail)
|
||||
}
|
||||
if !options["fullname"] {
|
||||
u.FirstName = ""
|
||||
u.LastName = ""
|
||||
}
|
||||
if !options["passwordupdate"] {
|
||||
u.LastPasswordUpdate = 0
|
||||
}
|
||||
if !options["authservice"] {
|
||||
u.AuthService = ""
|
||||
}
|
||||
if !options["authdata"] {
|
||||
u.AuthData = NewPointer("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -703,7 +707,6 @@ func (u *User) SanitizeInput(isAdmin bool) {
|
|||
|
||||
func (u *User) ClearNonProfileFields(asAdmin bool) {
|
||||
u.Password = ""
|
||||
u.AuthData = NewPointer("")
|
||||
u.MfaSecret = ""
|
||||
u.MfaUsedTimestamps = nil
|
||||
u.EmailVerified = false
|
||||
|
|
@ -711,6 +714,7 @@ func (u *User) ClearNonProfileFields(asAdmin bool) {
|
|||
u.LastPasswordUpdate = 0
|
||||
|
||||
if !asAdmin {
|
||||
u.AuthData = NewPointer("")
|
||||
u.NotifyProps = StringMap{}
|
||||
u.FailedAttempts = 0
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue