mirror of
https://github.com/mattermost/mattermost.git
synced 2026-02-03 20:40:00 -05:00
* fix account authorization type switch * improve test clarity * refactor tests for clarity
9457 lines
341 KiB
Go
9457 lines
341 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package api4
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"image/png"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/dgryski/dgoogauth"
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
"github.com/mattermost/mattermost/server/public/shared/request"
|
|
"github.com/mattermost/mattermost/server/v8/channels/app"
|
|
"github.com/mattermost/mattermost/server/v8/channels/utils/testutils"
|
|
"github.com/mattermost/mattermost/server/v8/einterfaces/mocks"
|
|
"github.com/mattermost/mattermost/server/v8/platform/shared/mail"
|
|
|
|
_ "github.com/mattermost/mattermost/server/v8/channels/app/oauthproviders/gitlab"
|
|
)
|
|
|
|
func TestCreateUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
user := model.User{
|
|
Id: model.NewId(),
|
|
Email: th.GenerateTestEmail(),
|
|
Nickname: "Corey Hulen",
|
|
Password: "hello1",
|
|
Username: GenerateTestUsername(),
|
|
}
|
|
_, resp, err := th.Client.CreateUser(context.Background(), &user)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
user = model.User{
|
|
Email: th.GenerateTestEmail(),
|
|
Nickname: "Corey Hulen",
|
|
Password: "hello1",
|
|
Username: GenerateTestUsername(),
|
|
Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId,
|
|
EmailVerified: true,
|
|
DeleteAt: 1,
|
|
CreateAt: 1,
|
|
UpdateAt: 1,
|
|
LastActivityAt: 1,
|
|
}
|
|
|
|
ruser, resp, err := th.Client.CreateUser(context.Background(), &user)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
// Creating a user as a regular user with verified flag should not verify the new user.
|
|
require.False(t, ruser.EmailVerified)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, user.Nickname, ruser.Nickname, "nickname didn't match")
|
|
require.Equal(t, model.SystemUserRoleId, ruser.Roles, "did not clear roles")
|
|
require.Equal(t, int64(0), ruser.DeleteAt, "did not reset deleteAt")
|
|
require.NotEqual(t, user.UpdateAt, ruser.UpdateAt, "did not reset updateAt")
|
|
require.NotEqual(t, user.CreateAt, ruser.CreateAt, "did not reset createAt")
|
|
require.NotEqual(t, user.LastActivityAt, ruser.LastActivityAt, "did not reset LastActivityAt")
|
|
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
_, resp, err = th.Client.CreateUser(context.Background(), ruser)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
ruser.Id = ""
|
|
ruser.Username = GenerateTestUsername()
|
|
ruser.Password = "passwd1"
|
|
_, resp, err = th.Client.CreateUser(context.Background(), ruser)
|
|
CheckErrorID(t, err, "app.user.save.email_exists.app_error")
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
ruser.Email = th.GenerateTestEmail()
|
|
ruser.Username = user.Username
|
|
_, resp, err = th.Client.CreateUser(context.Background(), ruser)
|
|
CheckErrorID(t, err, "app.user.save.username_exists.app_error")
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
ruser.Email = ""
|
|
_, resp, err = th.Client.CreateUser(context.Background(), ruser)
|
|
CheckErrorID(t, err, "model.user.is_valid.email.app_error")
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
ruser.Username = "testinvalid+++"
|
|
_, resp, err = th.Client.CreateUser(context.Background(), ruser)
|
|
CheckErrorID(t, err, "model.user.is_valid.username.app_error")
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableOpenServer = false })
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableUserCreation = false })
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
user2 := &model.User{Email: th.GenerateTestEmail(), Password: "Password1", Username: GenerateTestUsername(), EmailVerified: true}
|
|
ruser2, _, err2 := client.CreateUser(context.Background(), user2)
|
|
require.NoError(t, err2)
|
|
// Creating a user as sysadmin should verify the user with the EmailVerified flag.
|
|
require.True(t, ruser2.EmailVerified)
|
|
|
|
r, err2 := client.DoAPIPost(context.Background(), "/users", "garbage")
|
|
require.Error(t, err2, "should have errored")
|
|
assert.Equal(t, http.StatusBadRequest, r.StatusCode)
|
|
})
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
email := th.GenerateTestEmail()
|
|
user2 := &model.User{Email: email, Password: "Password1", Username: GenerateTestUsername(), EmailVerified: true}
|
|
_, _, err = client.CreateUser(context.Background(), user2)
|
|
require.NoError(t, err)
|
|
_, appErr := th.App.GetUserByUsername(user2.Username)
|
|
require.Nil(t, appErr)
|
|
|
|
user3 := &model.User{Email: fmt.Sprintf(" %s ", email), Password: "Password1", Username: GenerateTestUsername(), EmailVerified: true}
|
|
_, resp, err = client.CreateUser(context.Background(), user3)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
_, appErr = th.App.GetUserByUsername(user3.Username)
|
|
require.NotNil(t, appErr)
|
|
}, "Should not be able to create two users with the same email but spaces in it")
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
email := th.GenerateTestEmail()
|
|
newUser := &model.User{
|
|
Id: model.NewId(),
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
Email: email,
|
|
Password: "Password1",
|
|
Username: GenerateTestUsername(),
|
|
EmailVerified: true,
|
|
}
|
|
|
|
_, resp, err = client.CreateUser(context.Background(), newUser)
|
|
require.Error(t, err)
|
|
require.ErrorContains(t, err, "Must call update for existing user")
|
|
CheckBadRequestStatus(t, resp)
|
|
_, appErr := th.App.GetUserByEmail(email)
|
|
require.NotNil(t, appErr)
|
|
|
|
newUser.Id = ""
|
|
_, resp, err = client.CreateUser(context.Background(), newUser)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
createdUser, appErr := th.App.GetUserByEmail(email)
|
|
require.Nil(t, appErr)
|
|
require.Zero(t, *createdUser.RemoteId)
|
|
}, "Should not be able to define the RemoteID of a user through the API")
|
|
}
|
|
|
|
func TestCreateUserPasswordValidation(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
ruser := model.User{
|
|
Nickname: "Corey Hulen",
|
|
Password: "hello1",
|
|
Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId,
|
|
EmailVerified: true,
|
|
}
|
|
|
|
for name, tc := range map[string]struct {
|
|
Password string
|
|
Settings *model.PasswordSettings
|
|
ExpectedError string
|
|
}{
|
|
"Short": {
|
|
Password: strings.Repeat("x", 5),
|
|
Settings: &model.PasswordSettings{
|
|
MinimumLength: model.NewPointer(5),
|
|
Lowercase: model.NewPointer(false),
|
|
Uppercase: model.NewPointer(false),
|
|
Number: model.NewPointer(false),
|
|
Symbol: model.NewPointer(false),
|
|
},
|
|
},
|
|
"Long": {
|
|
Password: strings.Repeat("x", model.PasswordMaximumLength),
|
|
Settings: &model.PasswordSettings{
|
|
Lowercase: model.NewPointer(false),
|
|
Uppercase: model.NewPointer(false),
|
|
Number: model.NewPointer(false),
|
|
Symbol: model.NewPointer(false),
|
|
},
|
|
},
|
|
"TooShort": {
|
|
Password: strings.Repeat("x", 2),
|
|
Settings: &model.PasswordSettings{
|
|
MinimumLength: model.NewPointer(5),
|
|
Lowercase: model.NewPointer(false),
|
|
Uppercase: model.NewPointer(false),
|
|
Number: model.NewPointer(false),
|
|
Symbol: model.NewPointer(false),
|
|
},
|
|
ExpectedError: "model.user.is_valid.pwd_min_length.app_error",
|
|
},
|
|
"TooLong": {
|
|
Password: strings.Repeat("x", model.PasswordMaximumLength+1),
|
|
Settings: &model.PasswordSettings{
|
|
Lowercase: model.NewPointer(false),
|
|
Uppercase: model.NewPointer(false),
|
|
Number: model.NewPointer(false),
|
|
Symbol: model.NewPointer(false),
|
|
},
|
|
ExpectedError: "model.user.is_valid.pwd_max_length.app_error",
|
|
},
|
|
"MissingLower": {
|
|
Password: "AAAAAAAAAAASD123!@#",
|
|
Settings: &model.PasswordSettings{
|
|
Lowercase: model.NewPointer(true),
|
|
Uppercase: model.NewPointer(false),
|
|
Number: model.NewPointer(false),
|
|
Symbol: model.NewPointer(false),
|
|
},
|
|
ExpectedError: "model.user.is_valid.pwd_lowercase.app_error",
|
|
},
|
|
"MissingUpper": {
|
|
Password: "aaaaaaaaaaaaasd123!@#",
|
|
Settings: &model.PasswordSettings{
|
|
Uppercase: model.NewPointer(true),
|
|
Lowercase: model.NewPointer(false),
|
|
Number: model.NewPointer(false),
|
|
Symbol: model.NewPointer(false),
|
|
},
|
|
ExpectedError: "model.user.is_valid.pwd_uppercase.app_error",
|
|
},
|
|
"MissingNumber": {
|
|
Password: "asasdasdsadASD!@#",
|
|
Settings: &model.PasswordSettings{
|
|
Number: model.NewPointer(true),
|
|
Lowercase: model.NewPointer(false),
|
|
Uppercase: model.NewPointer(false),
|
|
Symbol: model.NewPointer(false),
|
|
},
|
|
ExpectedError: "model.user.is_valid.pwd_number.app_error",
|
|
},
|
|
"MissingSymbol": {
|
|
Password: "asdasdasdasdasdASD123",
|
|
Settings: &model.PasswordSettings{
|
|
Symbol: model.NewPointer(true),
|
|
Lowercase: model.NewPointer(false),
|
|
Uppercase: model.NewPointer(false),
|
|
Number: model.NewPointer(false),
|
|
},
|
|
ExpectedError: "model.user.is_valid.pwd_symbol.app_error",
|
|
},
|
|
"MissingMultiple": {
|
|
Password: "asdasdasdasdasdasd",
|
|
Settings: &model.PasswordSettings{
|
|
Lowercase: model.NewPointer(true),
|
|
Uppercase: model.NewPointer(true),
|
|
Number: model.NewPointer(true),
|
|
Symbol: model.NewPointer(true),
|
|
},
|
|
ExpectedError: "model.user.is_valid.pwd_uppercase_number_symbol.app_error",
|
|
},
|
|
"Everything": {
|
|
Password: "asdASD!@#123",
|
|
Settings: &model.PasswordSettings{
|
|
Lowercase: model.NewPointer(true),
|
|
Uppercase: model.NewPointer(true),
|
|
Number: model.NewPointer(true),
|
|
Symbol: model.NewPointer(true),
|
|
},
|
|
},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { cfg.PasswordSettings = *tc.Settings })
|
|
ruser.Email = th.GenerateTestEmail()
|
|
ruser.Password = tc.Password
|
|
ruser.Username = GenerateTestUsername()
|
|
if _, resp, err := th.Client.CreateUser(context.Background(), &ruser); tc.ExpectedError == "" {
|
|
assert.NoError(t, err)
|
|
} else {
|
|
CheckErrorID(t, err, tc.ExpectedError)
|
|
CheckBadRequestStatus(t, resp)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateUserAudit(t *testing.T) {
|
|
logFile, err := os.CreateTemp("", "adv.log")
|
|
require.NoError(t, err)
|
|
defer os.Remove(logFile.Name())
|
|
|
|
os.Setenv("MM_EXPERIMENTALAUDITSETTINGS_FILEENABLED", "true")
|
|
os.Setenv("MM_EXPERIMENTALAUDITSETTINGS_FILENAME", logFile.Name())
|
|
defer os.Unsetenv("MM_EXPERIMENTALAUDITSETTINGS_FILEENABLED")
|
|
defer os.Unsetenv("MM_EXPERIMENTALAUDITSETTINGS_FILENAME")
|
|
|
|
options := []app.Option{app.WithLicense(model.NewTestLicense("advanced_logging"))}
|
|
th := SetupWithServerOptions(t, options)
|
|
|
|
email := th.GenerateTestEmail()
|
|
password := "this_is_the_password"
|
|
user := model.User{
|
|
Email: email,
|
|
Password: password,
|
|
Username: GenerateTestUsername(),
|
|
}
|
|
_, resp, err := th.Client.CreateUser(context.Background(), &user)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
// Forcing a flush before attempting to read log's content.
|
|
err = th.Server.Audit.Flush()
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, logFile.Sync())
|
|
|
|
data, err := io.ReadAll(logFile)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, data)
|
|
|
|
require.Contains(t, string(data), email)
|
|
require.NotContains(t, string(data), password)
|
|
}
|
|
|
|
func TestUserLoginAudit(t *testing.T) {
|
|
logFile, err := os.CreateTemp("", "adv.log")
|
|
require.NoError(t, err)
|
|
defer os.Remove(logFile.Name())
|
|
|
|
os.Setenv("MM_EXPERIMENTALAUDITSETTINGS_FILEENABLED", "true")
|
|
os.Setenv("MM_EXPERIMENTALAUDITSETTINGS_FILENAME", logFile.Name())
|
|
defer os.Unsetenv("MM_EXPERIMENTALAUDITSETTINGS_FILEENABLED")
|
|
defer os.Unsetenv("MM_EXPERIMENTALAUDITSETTINGS_FILENAME")
|
|
|
|
options := []app.Option{app.WithLicense(model.NewTestLicense("advanced_logging"))}
|
|
th := SetupWithServerOptions(t, options)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
user, resp, err := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.Equal(t, th.BasicUser.Id, user.Id)
|
|
|
|
sess, resp, err := th.Client.GetSessions(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.Len(t, sess, 1)
|
|
assert.Equal(t, th.BasicUser.Id, sess[0].UserId)
|
|
|
|
// Forcing a flush before attempting to read log's content.
|
|
err = th.Server.Audit.Flush()
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, logFile.Sync())
|
|
|
|
data, err := io.ReadAll(logFile)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, data)
|
|
|
|
// ensure we are auditing the user_id and session_id
|
|
require.Contains(t, string(data), fmt.Sprintf("\"event_name\":\"login\",\"status\":\"success\",\"actor\":{\"user_id\":\"%s\",\"session_id\":\"%s\"", user.Id, sess[0].Id))
|
|
}
|
|
|
|
func TestCreateUserInputFilter(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
t.Run("DomainRestriction", func(t *testing.T) {
|
|
enableAPIUserDeletion := th.App.Config().ServiceSettings.EnableAPIUserDeletion
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.TeamSettings.EnableOpenServer = true
|
|
*cfg.TeamSettings.EnableUserCreation = true
|
|
*cfg.TeamSettings.RestrictCreationToDomains = "mattermost.com"
|
|
*cfg.ServiceSettings.EnableAPIUserDeletion = true
|
|
})
|
|
|
|
defer th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.TeamSettings.RestrictCreationToDomains = ""
|
|
*cfg.ServiceSettings.EnableAPIUserDeletion = *enableAPIUserDeletion
|
|
})
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
user := &model.User{Email: "foobar+testdomainrestriction@mattermost.com", Password: "Password1", Username: GenerateTestUsername()}
|
|
u, _, err := client.CreateUser(context.Background(), user) // we need the returned created user to use its Id for deletion.
|
|
require.NoError(t, err)
|
|
_, err = client.PermanentDeleteUser(context.Background(), u.Id)
|
|
require.NoError(t, err)
|
|
}, "ValidUser")
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
user := &model.User{Email: "foobar+testdomainrestriction@mattermost.org", Password: "Password1", Username: GenerateTestUsername()}
|
|
_, resp, err := client.CreateUser(context.Background(), user)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
}, "InvalidEmail")
|
|
|
|
t.Run("ValidAuthServiceFilter", func(t *testing.T) {
|
|
t.Run("SystemAdminClient", func(t *testing.T) {
|
|
user := &model.User{
|
|
Email: "foobar+testdomainrestriction@mattermost.org",
|
|
Username: GenerateTestUsername(),
|
|
AuthService: "ldap",
|
|
AuthData: model.NewPointer("999099"),
|
|
}
|
|
u, _, err := th.SystemAdminClient.CreateUser(context.Background(), user)
|
|
require.NoError(t, err)
|
|
_, err = th.SystemAdminClient.PermanentDeleteUser(context.Background(), u.Id)
|
|
require.NoError(t, err)
|
|
})
|
|
t.Run("LocalClient", func(t *testing.T) {
|
|
user := &model.User{
|
|
Email: "foobar+testdomainrestrictionlocalclient@mattermost.org",
|
|
Username: GenerateTestUsername(),
|
|
AuthService: "ldap",
|
|
AuthData: model.NewPointer("999100"),
|
|
}
|
|
u, _, err := th.LocalClient.CreateUser(context.Background(), user)
|
|
require.NoError(t, err)
|
|
_, err = th.LocalClient.PermanentDeleteUser(context.Background(), u.Id)
|
|
require.NoError(t, err)
|
|
})
|
|
})
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
user := &model.User{Email: "foobar+testdomainrestriction@mattermost.org", Password: "Password1", Username: GenerateTestUsername(), AuthService: "ldap"}
|
|
_, resp, err := th.Client.CreateUser(context.Background(), user)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
}, "InvalidAuthServiceFilter")
|
|
})
|
|
|
|
t.Run("Roles", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.TeamSettings.EnableOpenServer = true
|
|
*cfg.TeamSettings.EnableUserCreation = true
|
|
*cfg.TeamSettings.RestrictCreationToDomains = ""
|
|
*cfg.ServiceSettings.EnableAPIUserDeletion = true
|
|
})
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
emailAddr := "foobar+testinvalidrole@mattermost.com"
|
|
user := &model.User{Email: emailAddr, Password: "Password1", Username: GenerateTestUsername(), Roles: "system_user system_admin"}
|
|
_, _, err := client.CreateUser(context.Background(), user)
|
|
require.NoError(t, err)
|
|
ruser, appErr := th.App.GetUserByEmail(emailAddr)
|
|
require.Nil(t, appErr)
|
|
assert.NotEqual(t, ruser.Roles, "system_user system_admin")
|
|
_, err = client.PermanentDeleteUser(context.Background(), ruser.Id)
|
|
require.NoError(t, err)
|
|
}, "InvalidRole")
|
|
})
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.TeamSettings.EnableOpenServer = true
|
|
*cfg.TeamSettings.EnableUserCreation = true
|
|
})
|
|
user := &model.User{Id: "AAAAAAAAAAAAAAAAAAAAAAAAAA", Email: "foobar+testinvalidid@mattermost.com", Password: "Password1", Username: GenerateTestUsername(), Roles: "system_user system_admin"}
|
|
_, resp, err := client.CreateUser(context.Background(), user)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
}, "InvalidId")
|
|
}
|
|
|
|
func TestCreateUserWithToken(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
t.Run("CreateWithTokenHappyPath", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
token := model.NewToken(
|
|
model.TokenTypeTeamInvitation,
|
|
model.MapToJSON(map[string]string{"teamId": th.BasicTeam.Id, "email": user.Email}),
|
|
)
|
|
require.NoError(t, th.App.Srv().Store().Token().Save(token))
|
|
|
|
ruser, resp, err := th.Client.CreateUserWithToken(context.Background(), &user, token.Token)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
require.Equal(t, user.Nickname, ruser.Nickname)
|
|
require.Equal(t, model.SystemUserRoleId, ruser.Roles, "should clear roles")
|
|
CheckUserSanitization(t, ruser)
|
|
_, err = th.App.Srv().Store().Token().GetByToken(token.Token)
|
|
require.Error(t, err, "The token must be deleted after being used")
|
|
|
|
teams, appErr := th.App.GetTeamsForUser(ruser.Id)
|
|
require.Nil(t, appErr)
|
|
require.NotEmpty(t, teams, "The user must have teams")
|
|
require.Equal(t, th.BasicTeam.Id, teams[0].Id, "The user joined team must be the team provided.")
|
|
})
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
token := model.NewToken(
|
|
model.TokenTypeTeamInvitation,
|
|
model.MapToJSON(map[string]string{"teamId": th.BasicTeam.Id, "email": user.Email}),
|
|
)
|
|
require.NoError(t, th.App.Srv().Store().Token().Save(token))
|
|
|
|
ruser, resp, err := client.CreateUserWithToken(context.Background(), &user, token.Token)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
require.Equal(t, user.Nickname, ruser.Nickname)
|
|
require.Equal(t, model.SystemUserRoleId, ruser.Roles, "should clear roles")
|
|
CheckUserSanitization(t, ruser)
|
|
_, err = th.App.Srv().Store().Token().GetByToken(token.Token)
|
|
require.Error(t, err, "The token must be deleted after being used")
|
|
|
|
teams, appErr := th.App.GetTeamsForUser(ruser.Id)
|
|
require.Nil(t, appErr)
|
|
require.NotEmpty(t, teams, "The user must have teams")
|
|
require.Equal(t, th.BasicTeam.Id, teams[0].Id, "The user joined team must be the team provided.")
|
|
}, "CreateWithTokenHappyPath")
|
|
|
|
t.Run("NoToken", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
token := model.NewToken(
|
|
model.TokenTypeTeamInvitation,
|
|
model.MapToJSON(map[string]string{"teamId": th.BasicTeam.Id, "email": user.Email}),
|
|
)
|
|
require.NoError(t, th.App.Srv().Store().Token().Save(token))
|
|
defer func() {
|
|
appErr := th.App.DeleteToken(token)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
_, _, err := th.Client.CreateUserWithToken(context.Background(), &user, "")
|
|
require.Error(t, err)
|
|
assert.ErrorContains(t, err, "token ID is required")
|
|
})
|
|
|
|
t.Run("TokenExpired", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
timeNow := time.Now()
|
|
past49Hours := timeNow.Add(-49*time.Hour).UnixNano() / int64(time.Millisecond)
|
|
token := model.NewToken(
|
|
model.TokenTypeTeamInvitation,
|
|
model.MapToJSON(map[string]string{"teamId": th.BasicTeam.Id, "email": user.Email}),
|
|
)
|
|
token.CreateAt = past49Hours
|
|
require.NoError(t, th.App.Srv().Store().Token().Save(token))
|
|
defer func() {
|
|
appErr := th.App.DeleteToken(token)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
_, resp, err := th.Client.CreateUserWithToken(context.Background(), &user, token.Token)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
CheckErrorID(t, err, "api.user.create_user.signup_link_expired.app_error")
|
|
})
|
|
|
|
t.Run("WrongToken", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
_, resp, err := th.Client.CreateUserWithToken(context.Background(), &user, "wrong")
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
CheckErrorID(t, err, "api.user.create_user.signup_link_invalid.app_error")
|
|
})
|
|
|
|
t.Run("EnableUserCreationDisable", func(t *testing.T) {
|
|
enableUserCreation := th.App.Config().TeamSettings.EnableUserCreation
|
|
defer func() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.EnableUserCreation = enableUserCreation })
|
|
}()
|
|
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
token := model.NewToken(
|
|
model.TokenTypeTeamInvitation,
|
|
model.MapToJSON(map[string]string{"teamId": th.BasicTeam.Id, "email": user.Email}),
|
|
)
|
|
require.NoError(t, th.App.Srv().Store().Token().Save(token))
|
|
defer func() {
|
|
appErr := th.App.DeleteToken(token)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableUserCreation = false })
|
|
|
|
_, resp, err := th.Client.CreateUserWithToken(context.Background(), &user, token.Token)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, resp)
|
|
CheckErrorID(t, err, "api.user.create_user.signup_email_disabled.app_error")
|
|
})
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
enableUserCreation := th.App.Config().TeamSettings.EnableUserCreation
|
|
defer th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.EnableUserCreation = enableUserCreation })
|
|
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
token := model.NewToken(
|
|
model.TokenTypeTeamInvitation,
|
|
model.MapToJSON(map[string]string{"teamId": th.BasicTeam.Id, "email": user.Email}),
|
|
)
|
|
require.NoError(t, th.App.Srv().Store().Token().Save(token))
|
|
defer func() {
|
|
appErr := th.App.DeleteToken(token)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableUserCreation = false })
|
|
|
|
_, resp, err := client.CreateUserWithToken(context.Background(), &user, token.Token)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, resp)
|
|
CheckErrorID(t, err, "api.user.create_user.signup_email_disabled.app_error")
|
|
}, "EnableUserCreationDisable")
|
|
|
|
t.Run("EnableOpenServerDisable", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
token := model.NewToken(
|
|
model.TokenTypeTeamInvitation,
|
|
model.MapToJSON(map[string]string{"teamId": th.BasicTeam.Id, "email": user.Email}),
|
|
)
|
|
require.NoError(t, th.App.Srv().Store().Token().Save(token))
|
|
|
|
enableOpenServer := th.App.Config().TeamSettings.EnableOpenServer
|
|
defer func() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.EnableOpenServer = enableOpenServer })
|
|
}()
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableOpenServer = false })
|
|
|
|
ruser, resp, err := th.Client.CreateUserWithToken(context.Background(), &user, token.Token)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
require.Equal(t, user.Nickname, ruser.Nickname)
|
|
require.Equal(t, model.SystemUserRoleId, ruser.Roles, "should clear roles")
|
|
CheckUserSanitization(t, ruser)
|
|
_, err = th.App.Srv().Store().Token().GetByToken(token.Token)
|
|
require.Error(t, err, "The token must be deleted after be used")
|
|
})
|
|
|
|
t.Run("Validate inviter user has permissions on channels he is inviting", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemUserRoleId}
|
|
channelIdWithoutPermissions := th.BasicPrivateChannel2.Id
|
|
channelIds := th.BasicChannel.Id + " " + channelIdWithoutPermissions
|
|
token := model.NewToken(
|
|
model.TokenTypeTeamInvitation,
|
|
model.MapToJSON(map[string]string{"teamId": th.BasicTeam.Id, "email": user.Email, "senderId": th.BasicUser.Id, "channels": channelIds}),
|
|
)
|
|
require.NoError(t, th.App.Srv().Store().Token().Save(token))
|
|
|
|
ruser, resp, err := th.Client.CreateUserWithToken(context.Background(), &user, token.Token)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
require.Equal(t, user.Nickname, ruser.Nickname)
|
|
require.Equal(t, model.SystemUserRoleId, ruser.Roles, "should clear roles")
|
|
CheckUserSanitization(t, ruser)
|
|
_, err = th.App.Srv().Store().Token().GetByToken(token.Token)
|
|
require.Error(t, err, "The token must be deleted after being used")
|
|
|
|
teams, appErr := th.App.GetTeamsForUser(ruser.Id)
|
|
require.Nil(t, appErr)
|
|
require.NotEmpty(t, teams, "The user must have teams")
|
|
require.Equal(t, th.BasicTeam.Id, teams[0].Id, "The user joined team must be the team provided.")
|
|
|
|
// Now we get all the channels for the just created user
|
|
channelList, cErr := th.App.GetChannelsForTeamForUser(th.Context, th.BasicTeam.Id, ruser.Id, &model.ChannelSearchOpts{
|
|
IncludeDeleted: false,
|
|
LastDeleteAt: 0,
|
|
})
|
|
require.Nil(t, cErr)
|
|
|
|
// basicUser has no permissions on BasicPrivateChannel2 so the new invited user should be able to only access
|
|
// one channel from the two he was invited (plus the two default channels)
|
|
require.Len(t, channelList, 3)
|
|
})
|
|
|
|
t.Run("Validate inviterUser permissions on channels he is inviting, when inviting guests", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Guest User", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemUserRoleId}
|
|
channelIdWithoutPermissions := th.BasicPrivateChannel2.Id
|
|
channelIds := th.BasicChannel.Id + " " + channelIdWithoutPermissions
|
|
token := model.NewToken(
|
|
model.TokenTypeTeamInvitation,
|
|
model.MapToJSON(map[string]string{"guest": "true", "teamId": th.BasicTeam.Id, "email": user.Email, "senderId": th.BasicUser.Id, "channels": channelIds}),
|
|
)
|
|
require.NoError(t, th.App.Srv().Store().Token().Save(token))
|
|
|
|
ruser, resp, err := th.Client.CreateUserWithToken(context.Background(), &user, token.Token)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
require.Equal(t, user.Nickname, ruser.Nickname)
|
|
require.Equal(t, model.SystemUserRoleId, ruser.Roles, "should clear roles")
|
|
CheckUserSanitization(t, ruser)
|
|
_, err = th.App.Srv().Store().Token().GetByToken(token.Token)
|
|
require.Error(t, err, "The token must be deleted after being used")
|
|
|
|
teams, appErr := th.App.GetTeamsForUser(ruser.Id)
|
|
require.Nil(t, appErr)
|
|
require.NotEmpty(t, teams, "The guest must have teams")
|
|
require.Equal(t, th.BasicTeam.Id, teams[0].Id, "The guest joined team must be the team provided.")
|
|
|
|
// Now we get all the channels for the just created guest
|
|
channelList, cErr := th.App.GetChannelsForTeamForUser(th.Context, th.BasicTeam.Id, ruser.Id, &model.ChannelSearchOpts{
|
|
IncludeDeleted: false,
|
|
LastDeleteAt: 0,
|
|
})
|
|
require.Nil(t, cErr)
|
|
|
|
// basicUser has no permissions on BasicPrivateChannel2 so the new invited guest should be able to only access
|
|
// one channel from the two he was invited (plus the two default channels)
|
|
require.Len(t, channelList, 3)
|
|
})
|
|
}
|
|
|
|
func TestCreateUserWebSocketEvent(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
t.Run("guest should not received new_user event but user should", func(t *testing.T) {
|
|
th.App.Srv().SetLicense(model.NewTestLicense("guests"))
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.AllowEmailAccounts = true })
|
|
|
|
id := model.NewId()
|
|
guestPassword := "Pa$$word11"
|
|
guest := &model.User{
|
|
Email: "success+" + id + "@simulator.amazonses.com",
|
|
Username: "un_" + id,
|
|
Nickname: "nn_" + id,
|
|
Password: guestPassword,
|
|
EmailVerified: true,
|
|
}
|
|
|
|
guest, errr := th.App.CreateGuest(th.Context, guest)
|
|
require.Nil(t, errr)
|
|
|
|
_, _, errr = th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, guest.Id, "")
|
|
require.Nil(t, errr)
|
|
|
|
_, errr = th.App.AddUserToChannel(th.Context, guest, th.BasicChannel, false)
|
|
require.Nil(t, errr)
|
|
|
|
guestClient := th.CreateClient()
|
|
|
|
_, _, err := guestClient.Login(context.Background(), guest.Email, guestPassword)
|
|
require.NoError(t, err)
|
|
|
|
guestWSClient := th.CreateConnectedWebSocketClientWithClient(t, guestClient)
|
|
userWSClient := th.CreateConnectedWebSocketClient(t)
|
|
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
inviteId := th.BasicTeam.InviteId
|
|
|
|
_, resp, err := th.Client.CreateUserWithInviteId(context.Background(), &user, inviteId)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
var userHasReceived bool
|
|
var guestHasReceived bool
|
|
|
|
func() {
|
|
for {
|
|
select {
|
|
case ev := <-userWSClient.EventChannel:
|
|
if ev.EventType() == model.WebsocketEventNewUser {
|
|
userHasReceived = true
|
|
}
|
|
case ev := <-guestWSClient.EventChannel:
|
|
if ev.EventType() == model.WebsocketEventNewUser {
|
|
guestHasReceived = true
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
require.Truef(t, userHasReceived, "User should have received %s event", model.WebsocketEventNewUser)
|
|
require.Falsef(t, guestHasReceived, "Guest should not have received %s event", model.WebsocketEventNewUser)
|
|
})
|
|
}
|
|
|
|
func TestCreateUserWithInviteId(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
t.Run("CreateWithInviteIdHappyPath", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
inviteId := th.BasicTeam.InviteId
|
|
|
|
ruser, resp, err := th.Client.CreateUserWithInviteId(context.Background(), &user, inviteId)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
require.Equal(t, user.Nickname, ruser.Nickname)
|
|
require.Equal(t, model.SystemUserRoleId, ruser.Roles, "should clear roles")
|
|
CheckUserSanitization(t, ruser)
|
|
})
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
inviteId := th.BasicTeam.InviteId
|
|
|
|
ruser, resp, err := client.CreateUserWithInviteId(context.Background(), &user, inviteId)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
require.Equal(t, user.Nickname, ruser.Nickname)
|
|
require.Equal(t, model.SystemUserRoleId, ruser.Roles, "should clear roles")
|
|
CheckUserSanitization(t, ruser)
|
|
}, "CreateWithInviteIdHappyPath")
|
|
|
|
t.Run("GroupConstrainedTeam", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
th.BasicTeam.GroupConstrained = model.NewPointer(true)
|
|
team, appErr := th.App.UpdateTeam(th.BasicTeam)
|
|
require.Nil(t, appErr)
|
|
|
|
defer func() {
|
|
th.BasicTeam.GroupConstrained = model.NewPointer(false)
|
|
_, appErr = th.App.UpdateTeam(th.BasicTeam)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
inviteID := team.InviteId
|
|
|
|
_, _, err := th.Client.CreateUserWithInviteId(context.Background(), &user, inviteID)
|
|
CheckErrorID(t, err, "app.team.invite_id.group_constrained.error")
|
|
})
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
th.BasicTeam.GroupConstrained = model.NewPointer(true)
|
|
team, appErr := th.App.UpdateTeam(th.BasicTeam)
|
|
require.Nil(t, appErr)
|
|
|
|
defer func() {
|
|
th.BasicTeam.GroupConstrained = model.NewPointer(false)
|
|
_, appErr = th.App.UpdateTeam(th.BasicTeam)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
inviteID := team.InviteId
|
|
|
|
_, _, err := client.CreateUserWithInviteId(context.Background(), &user, inviteID)
|
|
CheckErrorID(t, err, "app.team.invite_id.group_constrained.error")
|
|
}, "GroupConstrainedTeam")
|
|
|
|
t.Run("WrongInviteId", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
inviteId := model.NewId()
|
|
|
|
_, resp, err := th.Client.CreateUserWithInviteId(context.Background(), &user, inviteId)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
CheckErrorID(t, err, "app.team.get_by_invite_id.finding.app_error")
|
|
})
|
|
|
|
t.Run("NoInviteId", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
_, _, err := th.Client.CreateUserWithInviteId(context.Background(), &user, "")
|
|
require.Error(t, err)
|
|
assert.ErrorContains(t, err, "invite ID is required")
|
|
})
|
|
|
|
t.Run("ExpiredInviteId", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
inviteId := th.BasicTeam.InviteId
|
|
|
|
_, _, err := th.SystemAdminClient.RegenerateTeamInviteId(context.Background(), th.BasicTeam.Id)
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := th.Client.CreateUserWithInviteId(context.Background(), &user, inviteId)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
CheckErrorID(t, err, "app.team.get_by_invite_id.finding.app_error")
|
|
})
|
|
|
|
t.Run("EnableUserCreationDisable", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
enableUserCreation := th.App.Config().TeamSettings.EnableUserCreation
|
|
defer func() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.EnableUserCreation = enableUserCreation })
|
|
}()
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableUserCreation = false })
|
|
|
|
inviteId := th.BasicTeam.InviteId
|
|
|
|
_, resp, err := th.Client.CreateUserWithInviteId(context.Background(), &user, inviteId)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, resp)
|
|
CheckErrorID(t, err, "api.user.create_user.signup_email_disabled.app_error")
|
|
})
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
enableUserCreation := th.App.Config().TeamSettings.EnableUserCreation
|
|
defer th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.EnableUserCreation = enableUserCreation })
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableUserCreation = false })
|
|
|
|
inviteId := th.BasicTeam.InviteId
|
|
_, resp, err := client.CreateUserWithInviteId(context.Background(), &user, inviteId)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, resp)
|
|
CheckErrorID(t, err, "api.user.create_user.signup_email_disabled.app_error")
|
|
}, "EnableUserCreationDisable")
|
|
|
|
t.Run("EnableOpenServerDisable", func(t *testing.T) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
enableOpenServer := th.App.Config().TeamSettings.EnableOpenServer
|
|
defer func() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.EnableOpenServer = enableOpenServer })
|
|
}()
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableOpenServer = false })
|
|
|
|
team, _, err := th.SystemAdminClient.RegenerateTeamInviteId(context.Background(), th.BasicTeam.Id)
|
|
assert.NoError(t, err)
|
|
inviteId := team.InviteId
|
|
|
|
ruser, resp, err := th.Client.CreateUserWithInviteId(context.Background(), &user, inviteId)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
require.Equal(t, user.Nickname, ruser.Nickname)
|
|
require.Equal(t, model.SystemUserRoleId, ruser.Roles, "should clear roles")
|
|
CheckUserSanitization(t, ruser)
|
|
})
|
|
}
|
|
|
|
func TestGetMe(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
ruser, _, err := th.Client.GetMe(context.Background(), "")
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, th.BasicUser.Id, ruser.Id)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err := th.Client.GetMe(context.Background(), "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
}
|
|
|
|
func TestGetUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
user := th.CreateUser(t)
|
|
user.Props = map[string]string{"testpropkey": "testpropvalue"}
|
|
|
|
_, appErr := th.App.UpdateUser(th.Context, user, false)
|
|
require.Nil(t, appErr)
|
|
|
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
|
ruser, resp, err := client.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, user.Email, ruser.Email)
|
|
|
|
assert.NotNil(t, ruser.Props)
|
|
assert.Equal(t, ruser.Props["testpropkey"], "testpropvalue")
|
|
require.False(t, ruser.IsBot)
|
|
|
|
ruser, resp, _ = client.GetUser(context.Background(), user.Id, resp.Etag)
|
|
CheckEtag(t, ruser, resp)
|
|
|
|
_, resp, err = client.GetUser(context.Background(), "junk", "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
_, resp, err = client.GetUser(context.Background(), model.NewId(), "")
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
// Check against privacy config settings
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PrivacySettings.ShowEmailAddress = false })
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PrivacySettings.ShowFullName = false })
|
|
|
|
ruser, _, err := th.Client.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, ruser.Email, "email should be blank")
|
|
require.Empty(t, ruser.FirstName, "first name should be blank")
|
|
require.Empty(t, ruser.LastName, "last name should be blank")
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err := th.Client.GetUser(context.Background(), user.Id, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
// System admins should ignore privacy settings
|
|
ruser, _, _ = th.SystemAdminClient.GetUser(context.Background(), user.Id, resp.Etag)
|
|
require.NotEmpty(t, ruser.Email, "email should not be blank")
|
|
require.NotEmpty(t, ruser.FirstName, "first name should not be blank")
|
|
require.NotEmpty(t, ruser.LastName, "last name should not be blank")
|
|
}
|
|
|
|
func TestGetUserWithAcceptedTermsOfServiceForOtherUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
user := th.CreateUser(t)
|
|
|
|
tos, _ := th.App.CreateTermsOfService("Dummy TOS", user.Id)
|
|
|
|
_, appErr := th.App.UpdateUser(th.Context, user, false)
|
|
require.Nil(t, appErr)
|
|
|
|
ruser, _, err := th.Client.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, user.Email, ruser.Email)
|
|
|
|
assert.Empty(t, ruser.TermsOfServiceId)
|
|
|
|
appErr = th.App.SaveUserTermsOfService(user.Id, tos.Id, true)
|
|
require.Nil(t, appErr)
|
|
|
|
ruser, _, err = th.Client.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, user.Email, ruser.Email)
|
|
|
|
// user TOS data cannot be fetched for other users by non-admin users
|
|
assert.Empty(t, ruser.TermsOfServiceId)
|
|
}
|
|
|
|
func TestGetUserWithAcceptedTermsOfService(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user := th.BasicUser
|
|
|
|
tos, _ := th.App.CreateTermsOfService("Dummy TOS", user.Id)
|
|
|
|
ruser, _, err := th.Client.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, user.Email, ruser.Email)
|
|
|
|
assert.Empty(t, ruser.TermsOfServiceId)
|
|
|
|
appErr := th.App.SaveUserTermsOfService(user.Id, tos.Id, true)
|
|
require.Nil(t, appErr)
|
|
|
|
ruser, _, err = th.Client.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, user.Email, ruser.Email)
|
|
|
|
// a user can view their own TOS details
|
|
assert.Equal(t, tos.Id, ruser.TermsOfServiceId)
|
|
}
|
|
|
|
func TestGetUserWithAcceptedTermsOfServiceWithAdminUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.LoginSystemAdmin(t)
|
|
user := th.BasicUser
|
|
|
|
tos, appErr := th.App.CreateTermsOfService("Dummy TOS", user.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
ruser, _, err := th.SystemAdminClient.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, user.Email, ruser.Email)
|
|
|
|
assert.Empty(t, ruser.TermsOfServiceId)
|
|
|
|
appErr = th.App.SaveUserTermsOfService(user.Id, tos.Id, true)
|
|
require.Nil(t, appErr)
|
|
|
|
ruser, _, err = th.SystemAdminClient.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, user.Email, ruser.Email)
|
|
|
|
// admin can view anyone's TOS details
|
|
assert.Equal(t, tos.Id, ruser.TermsOfServiceId)
|
|
}
|
|
|
|
func TestGetBotUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
defaultPerms := th.SaveDefaultRolePermissions(t)
|
|
defer th.RestoreDefaultRolePermissions(t, defaultPerms)
|
|
|
|
th.AddPermissionToRole(t, model.PermissionCreateBot.Id, model.TeamUserRoleId)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.TeamUserRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
bot := &model.Bot{
|
|
Username: GenerateTestUsername(),
|
|
DisplayName: "a bot",
|
|
Description: "bot",
|
|
}
|
|
|
|
createdBot, resp, err := th.Client.CreateBot(context.Background(), bot)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
botUser, _, err := th.Client.GetUser(context.Background(), createdBot.UserId, "")
|
|
require.NoError(t, err)
|
|
require.Equal(t, bot.Username, botUser.Username)
|
|
require.True(t, botUser.IsBot)
|
|
}
|
|
|
|
func TestGetUserByUsername(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user := th.BasicUser
|
|
|
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
|
ruser, resp, err := client.GetUserByUsername(context.Background(), user.Username, "")
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, user.Email, ruser.Email)
|
|
|
|
ruser, resp, _ = client.GetUserByUsername(context.Background(), user.Username, resp.Etag)
|
|
CheckEtag(t, ruser, resp)
|
|
|
|
_, resp, err = client.GetUserByUsername(context.Background(), GenerateTestUsername(), "")
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
// Check against privacy config settings
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PrivacySettings.ShowEmailAddress = false })
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PrivacySettings.ShowFullName = false })
|
|
|
|
ruser, _, err := th.Client.GetUserByUsername(context.Background(), th.BasicUser2.Username, "")
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, ruser.Email, "email should be blank")
|
|
require.Empty(t, ruser.FirstName, "first name should be blank")
|
|
require.Empty(t, ruser.LastName, "last name should be blank")
|
|
|
|
ruser, _, err = th.Client.GetUserByUsername(context.Background(), th.BasicUser.Username, "")
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, ruser.NotifyProps, "notify props should be sent")
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err := th.Client.GetUserByUsername(context.Background(), user.Username, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
// System admins should ignore privacy settings
|
|
ruser, _, _ = client.GetUserByUsername(context.Background(), user.Username, resp.Etag)
|
|
require.NotEmpty(t, ruser.Email, "email should not be blank")
|
|
require.NotEmpty(t, ruser.FirstName, "first name should not be blank")
|
|
require.NotEmpty(t, ruser.LastName, "last name should not be blank")
|
|
})
|
|
}
|
|
|
|
func TestGetUserByUsernameWithAcceptedTermsOfService(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user := th.BasicUser
|
|
|
|
ruser, _, err := th.Client.GetUserByUsername(context.Background(), user.Username, "")
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, user.Email, ruser.Email)
|
|
|
|
tos, appErr := th.App.CreateTermsOfService("Dummy TOS", user.Id)
|
|
require.Nil(t, appErr)
|
|
appErr = th.App.SaveUserTermsOfService(ruser.Id, tos.Id, true)
|
|
require.Nil(t, appErr)
|
|
|
|
ruser, _, err = th.Client.GetUserByUsername(context.Background(), user.Username, "")
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, user.Email, ruser.Email)
|
|
|
|
require.Equal(t, tos.Id, ruser.TermsOfServiceId, "Terms of service ID should match")
|
|
}
|
|
|
|
func TestSaveUserTermsOfService(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
t.Run("Invalid data", func(t *testing.T) {
|
|
resp, err := th.Client.DoAPIPost(context.Background(), "/users/"+th.BasicUser.Id+"/terms_of_service", "{}")
|
|
require.Error(t, err)
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
})
|
|
}
|
|
|
|
func TestGetUserByEmail(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
user := th.CreateUser(t)
|
|
userWithSlash, _, err := th.SystemAdminClient.CreateUser(context.Background(), &model.User{
|
|
Email: "email/with/slashes@example.com",
|
|
Username: GenerateTestUsername(),
|
|
Password: "Pa$$word11",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.PrivacySettings.ShowEmailAddress = true
|
|
*cfg.PrivacySettings.ShowFullName = true
|
|
})
|
|
|
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
|
t.Run("should be able to get another user by email", func(t *testing.T) {
|
|
ruser, _, err := client.GetUserByEmail(context.Background(), user.Email, "")
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, user.Email, ruser.Email)
|
|
})
|
|
|
|
t.Run("Get user with a / character in the email", func(t *testing.T) {
|
|
ruser, _, err := client.GetUserByEmail(context.Background(), userWithSlash.Email, "")
|
|
require.NoError(t, err)
|
|
require.Equal(t, ruser.Id, userWithSlash.Id)
|
|
})
|
|
|
|
t.Run("should return not modified when provided with a matching etag", func(t *testing.T) {
|
|
_, resp, err := client.GetUserByEmail(context.Background(), user.Email, "")
|
|
require.NoError(t, err)
|
|
|
|
ruser, resp, _ := client.GetUserByEmail(context.Background(), user.Email, resp.Etag)
|
|
CheckEtag(t, ruser, resp)
|
|
})
|
|
|
|
t.Run("should return bad request when given an invalid email", func(t *testing.T) {
|
|
_, resp, err := client.GetUserByEmail(context.Background(), GenerateTestUsername(), "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("should return 404 when given a non-existent email", func(t *testing.T) {
|
|
_, resp, err := client.GetUserByEmail(context.Background(), th.GenerateTestEmail(), "")
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
})
|
|
|
|
t.Run("should sanitize full name for non-admin based on privacy settings", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.PrivacySettings.ShowEmailAddress = true
|
|
*cfg.PrivacySettings.ShowFullName = false
|
|
})
|
|
|
|
ruser, _, err := th.Client.GetUserByEmail(context.Background(), user.Email, "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "", ruser.FirstName, "first name should be blank")
|
|
assert.Equal(t, "", ruser.LastName, "last name should be blank")
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.PrivacySettings.ShowFullName = true
|
|
})
|
|
|
|
ruser, _, err = th.Client.GetUserByEmail(context.Background(), user.Email, "")
|
|
require.NoError(t, err)
|
|
assert.NotEqual(t, "", ruser.FirstName, "first name should be set")
|
|
assert.NotEqual(t, "", ruser.LastName, "last name should be set")
|
|
})
|
|
|
|
t.Run("should return forbidden for non-admin when privacy settings hide email", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.PrivacySettings.ShowEmailAddress = false
|
|
})
|
|
|
|
_, resp, err := th.Client.GetUserByEmail(context.Background(), user.Email, "")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.PrivacySettings.ShowEmailAddress = true
|
|
})
|
|
|
|
ruser, _, err := th.Client.GetUserByEmail(context.Background(), user.Email, "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, user.Email, ruser.Email, "email should be set")
|
|
})
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
t.Run("should not sanitize full name for admin, regardless of privacy settings", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.PrivacySettings.ShowEmailAddress = true
|
|
*cfg.PrivacySettings.ShowFullName = false
|
|
})
|
|
|
|
ruser, _, err := client.GetUserByEmail(context.Background(), user.Email, "")
|
|
require.NoError(t, err)
|
|
assert.NotEqual(t, "", ruser.FirstName, "first name should be set")
|
|
assert.NotEqual(t, "", ruser.LastName, "last name should be set")
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.PrivacySettings.ShowFullName = true
|
|
})
|
|
|
|
ruser, _, err = client.GetUserByEmail(context.Background(), user.Email, "")
|
|
require.NoError(t, err)
|
|
assert.NotEqual(t, "", ruser.FirstName, "first name should be set")
|
|
assert.NotEqual(t, "", ruser.LastName, "last name should be set")
|
|
})
|
|
|
|
t.Run("should always return email for admin, regardless of privacy settings", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.PrivacySettings.ShowEmailAddress = false
|
|
})
|
|
|
|
ruser, _, err := client.GetUserByEmail(context.Background(), user.Email, "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, user.Email, ruser.Email, "email should be set")
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.PrivacySettings.ShowEmailAddress = true
|
|
})
|
|
|
|
ruser, _, err = client.GetUserByEmail(context.Background(), user.Email, "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, user.Email, ruser.Email, "email should be set")
|
|
})
|
|
})
|
|
}
|
|
|
|
// This test can flake if two calls to model.NewId can return the same value.
|
|
// Not much can be done about it.
|
|
func TestSearchUsers(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
search := &model.UserSearch{Term: th.BasicUser.Username}
|
|
|
|
users, _, err := th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, findUserInList(th.BasicUser.Id, users), "should have found user")
|
|
|
|
_, appErr := th.App.UpdateActive(th.Context, th.BasicUser2, false)
|
|
require.Nil(t, appErr)
|
|
|
|
search.Term = th.BasicUser2.Username
|
|
search.AllowInactive = false
|
|
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
|
|
require.False(t, findUserInList(th.BasicUser2.Id, users), "should not have found user")
|
|
|
|
search.AllowInactive = true
|
|
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, findUserInList(th.BasicUser2.Id, users), "should have found user")
|
|
|
|
search.Term = th.BasicUser.Username
|
|
search.AllowInactive = false
|
|
search.TeamId = th.BasicTeam.Id
|
|
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, findUserInList(th.BasicUser.Id, users), "should have found user")
|
|
|
|
search.NotInChannelId = th.BasicChannel.Id
|
|
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
|
|
require.False(t, findUserInList(th.BasicUser.Id, users), "should not have found user")
|
|
|
|
search.TeamId = ""
|
|
search.NotInChannelId = ""
|
|
search.InChannelId = th.BasicChannel.Id
|
|
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, findUserInList(th.BasicUser.Id, users), "should have found user")
|
|
|
|
search.InChannelId = ""
|
|
search.NotInChannelId = th.BasicChannel.Id
|
|
_, resp, err := th.Client.SearchUsers(context.Background(), search)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
search.NotInChannelId = model.NewId()
|
|
search.TeamId = model.NewId()
|
|
_, resp, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
search.NotInChannelId = ""
|
|
search.TeamId = model.NewId()
|
|
_, resp, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
search.InChannelId = model.NewId()
|
|
search.TeamId = ""
|
|
_, resp, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
// Test search for users not in any team
|
|
search.TeamId = ""
|
|
search.NotInChannelId = ""
|
|
search.InChannelId = ""
|
|
search.NotInTeamId = th.BasicTeam.Id
|
|
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
|
|
require.False(t, findUserInList(th.BasicUser.Id, users), "should not have found user")
|
|
|
|
oddUser := th.CreateUser(t)
|
|
search.Term = oddUser.Username
|
|
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, findUserInList(oddUser.Id, users), "should have found user")
|
|
|
|
_, _, err = th.SystemAdminClient.AddTeamMember(context.Background(), th.BasicTeam.Id, oddUser.Id)
|
|
require.NoError(t, err)
|
|
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
|
|
require.False(t, findUserInList(oddUser.Id, users), "should not have found user")
|
|
|
|
search.NotInTeamId = model.NewId()
|
|
_, resp, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
search.Term = th.BasicUser.Username
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PrivacySettings.ShowEmailAddress = false })
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PrivacySettings.ShowFullName = false })
|
|
|
|
_, appErr = th.App.UpdateActive(th.Context, th.BasicUser2, true)
|
|
require.Nil(t, appErr)
|
|
|
|
search.InChannelId = ""
|
|
search.NotInTeamId = ""
|
|
search.Term = th.BasicUser2.Email
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
|
|
require.False(t, findUserInList(th.BasicUser2.Id, users), "should not have found user")
|
|
|
|
search.Term = th.BasicUser2.FirstName
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
|
|
require.False(t, findUserInList(th.BasicUser2.Id, users), "should not have found user")
|
|
|
|
search.Term = th.BasicUser2.LastName
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
|
|
require.False(t, findUserInList(th.BasicUser2.Id, users), "should not have found user")
|
|
|
|
search.Term = th.BasicUser.FirstName
|
|
search.InChannelId = th.BasicChannel.Id
|
|
search.NotInChannelId = th.BasicChannel.Id
|
|
search.TeamId = th.BasicTeam.Id
|
|
users, _, err = th.SystemAdminClient.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, findUserInList(th.BasicUser.Id, users), "should have found user")
|
|
|
|
id := model.NewId()
|
|
group, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
search = &model.UserSearch{Term: th.BasicUser.Username, InGroupId: group.Id}
|
|
t.Run("Requires ldap license when searching in group", func(t *testing.T) {
|
|
_, resp, err = th.SystemAdminClient.SearchUsers(context.Background(), search)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
t.Run("Requires manage system permission when searching for users in a group", func(t *testing.T) {
|
|
_, resp, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Returns empty list when no users found searching for users in a group", func(t *testing.T) {
|
|
users, _, err = th.SystemAdminClient.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
require.Empty(t, users)
|
|
})
|
|
|
|
_, appErr = th.App.UpsertGroupMember(group.Id, th.BasicUser.Id)
|
|
assert.Nil(t, appErr)
|
|
|
|
t.Run("Returns user in group user found in group", func(t *testing.T) {
|
|
users, _, err = th.SystemAdminClient.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
require.Equal(t, users[0].Id, th.BasicUser.Id)
|
|
})
|
|
|
|
id = model.NewId()
|
|
group, appErr = th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceCustom,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional, "ldap"))
|
|
|
|
search = &model.UserSearch{Term: th.BasicUser.Username, NotInGroupId: group.Id}
|
|
t.Run("Returns users not in group", func(t *testing.T) {
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
require.Equal(t, users[0].Id, th.BasicUser.Id)
|
|
})
|
|
|
|
_, appErr = th.App.UpsertGroupMember(group.Id, th.BasicUser.Id)
|
|
assert.Nil(t, appErr)
|
|
|
|
t.Run("Returns empty list for not in group", func(t *testing.T) {
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
require.NoError(t, err)
|
|
assert.Len(t, users, 0)
|
|
})
|
|
|
|
members := &model.GroupModifyMembers{
|
|
UserIds: []string{th.BasicUser.Id},
|
|
}
|
|
|
|
_, _, delErr := th.Client.DeleteGroupMembers(context.Background(), group.Id, members)
|
|
require.NoError(t, delErr)
|
|
|
|
t.Run("Returns user not in group after they were deleted from group", func(t *testing.T) {
|
|
users, _, err = th.Client.SearchUsers(context.Background(), search)
|
|
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
|
|
for _, user := range users {
|
|
if user.Id == id {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func TestAutocompleteUsersInChannel(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
teamId := th.BasicTeam.Id
|
|
channelId := th.BasicChannel.Id
|
|
username := th.BasicUser.Username
|
|
newUser := th.CreateUser(t)
|
|
|
|
tt := []struct {
|
|
Name string
|
|
TeamId string
|
|
ChannelId string
|
|
Username string
|
|
ExpectedResults int
|
|
MoreThan bool
|
|
ShouldFail bool
|
|
}{
|
|
{
|
|
"Autocomplete in channel for specific username",
|
|
teamId,
|
|
channelId,
|
|
username,
|
|
1,
|
|
false,
|
|
false,
|
|
},
|
|
{
|
|
"Search for not valid username",
|
|
teamId,
|
|
channelId,
|
|
"amazonses",
|
|
0,
|
|
false,
|
|
false,
|
|
},
|
|
{
|
|
"Search for all users",
|
|
teamId,
|
|
channelId,
|
|
"",
|
|
2,
|
|
true,
|
|
false,
|
|
},
|
|
{
|
|
"Fail when the teamId is not provided",
|
|
"",
|
|
channelId,
|
|
"",
|
|
2,
|
|
true,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.Name, func(t *testing.T) {
|
|
th.LoginBasic(t)
|
|
rusers, _, err := th.Client.AutocompleteUsersInChannel(context.Background(), tc.TeamId, tc.ChannelId, tc.Username, model.UserSearchDefaultLimit, "")
|
|
if tc.ShouldFail {
|
|
CheckErrorID(t, err, "api.user.autocomplete_users.missing_team_id.app_error")
|
|
} else {
|
|
require.NoError(t, err)
|
|
if tc.MoreThan {
|
|
assert.True(t, len(rusers.Users) >= tc.ExpectedResults)
|
|
} else {
|
|
assert.Len(t, rusers.Users, tc.ExpectedResults)
|
|
}
|
|
}
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err := th.Client.AutocompleteUsersInChannel(context.Background(), tc.TeamId, tc.ChannelId, tc.Username, model.UserSearchDefaultLimit, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), newUser.Email, newUser.Password)
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.AutocompleteUsersInChannel(context.Background(), tc.TeamId, tc.ChannelId, tc.Username, model.UserSearchDefaultLimit, "")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
t.Run("Check against privacy config settings", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PrivacySettings.ShowFullName = false })
|
|
|
|
th.LoginBasic(t)
|
|
rusers, _, err := th.Client.AutocompleteUsersInChannel(context.Background(), teamId, channelId, username, model.UserSearchDefaultLimit, "")
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, rusers.Users[0].FirstName, "", "should not show first/last name")
|
|
assert.Equal(t, rusers.Users[0].LastName, "", "should not show first/last name")
|
|
})
|
|
|
|
t.Run("Check OutOfChannel results with/without VIEW_MEMBERS permissions", func(t *testing.T) {
|
|
t.Skip("https://mattermost.atlassian.net/browse/MM-61041")
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
|
|
th.App.Srv().SetLicense(model.NewTestLicense())
|
|
defer func() {
|
|
appErr := th.App.Srv().RemoveLicense()
|
|
require.Nil(t, appErr)
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = false })
|
|
}()
|
|
permissionsUser := th.CreateUser(t)
|
|
_, err := th.SystemAdminClient.DemoteUserToGuest(context.Background(), permissionsUser.Id)
|
|
require.NoError(t, err)
|
|
permissionsUser.Roles = "system_guest"
|
|
th.LinkUserToTeam(t, permissionsUser, th.BasicTeam)
|
|
th.AddUserToChannel(t, permissionsUser, th.BasicChannel)
|
|
|
|
otherUser := th.CreateUser(t)
|
|
th.LinkUserToTeam(t, otherUser, th.BasicTeam)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), permissionsUser.Email, permissionsUser.Password)
|
|
require.NoError(t, err)
|
|
|
|
rusers, _, err := th.Client.AutocompleteUsersInChannel(context.Background(), teamId, channelId, "", model.UserSearchDefaultLimit, "")
|
|
require.NoError(t, err)
|
|
assert.Len(t, rusers.OutOfChannel, 1)
|
|
|
|
defaultRolePermissions := th.SaveDefaultRolePermissions(t)
|
|
defer func() {
|
|
th.RestoreDefaultRolePermissions(t, defaultRolePermissions)
|
|
}()
|
|
|
|
th.RemovePermissionFromRole(t, model.PermissionViewMembers.Id, model.SystemUserRoleId)
|
|
th.RemovePermissionFromRole(t, model.PermissionViewMembers.Id, model.TeamUserRoleId)
|
|
|
|
rusers, _, err = th.Client.AutocompleteUsersInChannel(context.Background(), teamId, channelId, "", model.UserSearchDefaultLimit, "")
|
|
require.NoError(t, err)
|
|
assert.Empty(t, rusers.OutOfChannel)
|
|
|
|
_, appErr := th.App.GetOrCreateDirectChannel(th.Context, permissionsUser.Id, otherUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
rusers, _, err = th.Client.AutocompleteUsersInChannel(context.Background(), teamId, channelId, "", model.UserSearchDefaultLimit, "")
|
|
require.NoError(t, err)
|
|
assert.Len(t, rusers.OutOfChannel, 1)
|
|
})
|
|
|
|
t.Run("user must have access to team id, especially when it does not match channel's team id", func(t *testing.T) {
|
|
_, _, err := th.Client.AutocompleteUsersInChannel(context.Background(), "otherTeamId", channelId, username, model.UserSearchDefaultLimit, "")
|
|
CheckErrorID(t, err, "api.context.permissions.app_error")
|
|
})
|
|
}
|
|
|
|
func TestAutocompleteUsersInTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
teamId := th.BasicTeam.Id
|
|
username := th.BasicUser.Username
|
|
newUser := th.CreateUser(t)
|
|
|
|
tt := []struct {
|
|
Name string
|
|
TeamId string
|
|
Username string
|
|
ExpectedResults int
|
|
MoreThan bool
|
|
}{
|
|
{
|
|
"specific username",
|
|
teamId,
|
|
username,
|
|
1,
|
|
false,
|
|
},
|
|
{
|
|
"not valid username",
|
|
teamId,
|
|
"amazonses",
|
|
0,
|
|
false,
|
|
},
|
|
{
|
|
"all users in team",
|
|
teamId,
|
|
"",
|
|
2,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.Name, func(t *testing.T) {
|
|
th.LoginBasic(t)
|
|
rusers, _, err := th.Client.AutocompleteUsersInTeam(context.Background(), tc.TeamId, tc.Username, model.UserSearchDefaultLimit, "")
|
|
require.NoError(t, err)
|
|
if tc.MoreThan {
|
|
assert.True(t, len(rusers.Users) >= tc.ExpectedResults)
|
|
} else {
|
|
assert.Len(t, rusers.Users, tc.ExpectedResults)
|
|
}
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err := th.Client.AutocompleteUsersInTeam(context.Background(), tc.TeamId, tc.Username, model.UserSearchDefaultLimit, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), newUser.Email, newUser.Password)
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.AutocompleteUsersInTeam(context.Background(), tc.TeamId, tc.Username, model.UserSearchDefaultLimit, "")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
t.Run("Check against privacy config settings", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PrivacySettings.ShowFullName = false })
|
|
|
|
th.LoginBasic(t)
|
|
rusers, _, err := th.Client.AutocompleteUsersInTeam(context.Background(), teamId, username, model.UserSearchDefaultLimit, "")
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, rusers.Users[0].FirstName, "", "should not show first/last name")
|
|
assert.Equal(t, rusers.Users[0].LastName, "", "should not show first/last name")
|
|
})
|
|
}
|
|
|
|
func TestAutocompleteUsers(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
username := th.BasicUser.Username
|
|
newUser := th.CreateUser(t)
|
|
|
|
tt := []struct {
|
|
Name string
|
|
Username string
|
|
ExpectedResults int
|
|
MoreThan bool
|
|
}{
|
|
{
|
|
"specific username",
|
|
username,
|
|
1,
|
|
false,
|
|
},
|
|
{
|
|
"not valid username",
|
|
"amazonses",
|
|
0,
|
|
false,
|
|
},
|
|
{
|
|
"all users in team",
|
|
"",
|
|
2,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.Name, func(t *testing.T) {
|
|
th.LoginBasic(t)
|
|
rusers, _, err := th.Client.AutocompleteUsers(context.Background(), tc.Username, model.UserSearchDefaultLimit, "")
|
|
require.NoError(t, err)
|
|
if tc.MoreThan {
|
|
assert.True(t, len(rusers.Users) >= tc.ExpectedResults)
|
|
} else {
|
|
assert.Len(t, rusers.Users, tc.ExpectedResults)
|
|
}
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err := th.Client.AutocompleteUsers(context.Background(), tc.Username, model.UserSearchDefaultLimit, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), newUser.Email, newUser.Password)
|
|
require.NoError(t, err)
|
|
_, _, err = th.Client.AutocompleteUsers(context.Background(), tc.Username, model.UserSearchDefaultLimit, "")
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
t.Run("Check against privacy config settings", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PrivacySettings.ShowFullName = false })
|
|
|
|
th.LoginBasic(t)
|
|
rusers, _, err := th.Client.AutocompleteUsers(context.Background(), username, model.UserSearchDefaultLimit, "")
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, rusers.Users[0].FirstName, "", "should not show first/last name")
|
|
assert.Equal(t, rusers.Users[0].LastName, "", "should not show first/last name")
|
|
})
|
|
}
|
|
|
|
func TestGetProfileImage(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
// recreate basic user
|
|
th.BasicUser = th.CreateUser(t)
|
|
th.LoginBasic(t)
|
|
user := th.BasicUser
|
|
|
|
data, resp, err := th.Client.GetProfileImage(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, data, "should not be empty")
|
|
|
|
_, resp, _ = th.Client.GetProfileImage(context.Background(), user.Id, resp.Etag)
|
|
require.NotEqual(t, http.StatusNotModified, resp.StatusCode, "should not hit etag")
|
|
|
|
_, resp, err = th.Client.GetProfileImage(context.Background(), "junk", "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
_, resp, err = th.Client.GetProfileImage(context.Background(), model.NewId(), "")
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.GetProfileImage(context.Background(), user.Id, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
_, _, err = th.SystemAdminClient.GetProfileImage(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
|
|
info := &model.FileInfo{Path: "/users/" + user.Id + "/profile.png"}
|
|
err = th.cleanupTestFile(info)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetUsersByIds(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
|
t.Run("should return the user", func(t *testing.T) {
|
|
users, _, err := client.GetUsersByIds(context.Background(), []string{th.BasicUser.Id})
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, th.BasicUser.Id, users[0].Id)
|
|
CheckUserSanitization(t, users[0])
|
|
})
|
|
|
|
t.Run("should return error when no IDs are specified", func(t *testing.T) {
|
|
_, resp, err := client.GetUsersByIds(context.Background(), []string{})
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("should not return an error for invalid IDs", func(t *testing.T) {
|
|
users, _, err := client.GetUsersByIds(context.Background(), []string{"junk"})
|
|
require.NoError(t, err)
|
|
require.Empty(t, users, "no users should be returned")
|
|
})
|
|
|
|
t.Run("should still return users for valid IDs when invalid IDs are specified", func(t *testing.T) {
|
|
users, _, err := client.GetUsersByIds(context.Background(), []string{"junk", th.BasicUser.Id})
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, users, 1, "1 user should be returned")
|
|
})
|
|
|
|
t.Run("should only return unique users when multiple IDs are requested", func(t *testing.T) {
|
|
users, _, err := client.GetUsersByIds(context.Background(), []string{th.BasicUser.Id, th.BasicUser.Id, th.BasicUser.Id})
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, users, 1, "1 user should be returned")
|
|
})
|
|
})
|
|
|
|
t.Run("should return error when not logged in", func(t *testing.T) {
|
|
_, err := th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := th.Client.GetUsersByIds(context.Background(), []string{th.BasicUser.Id})
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestGetUsersByIdsWithOptions(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
t.Run("should only return specified users that have been updated since the given time", func(t *testing.T) {
|
|
th := Setup(t)
|
|
|
|
// Users before the timestamp shouldn't be returned
|
|
user1, appErr := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Username: model.NewUsername(), Password: model.NewId()})
|
|
require.Nil(t, appErr)
|
|
|
|
user2, appErr := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Username: model.NewUsername(), Password: model.NewId()})
|
|
require.Nil(t, appErr)
|
|
|
|
// Users not in the list of IDs shouldn't be returned
|
|
_, appErr = th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Username: model.NewUsername(), Password: model.NewId()})
|
|
require.Nil(t, appErr)
|
|
|
|
users, _, err := th.Client.GetUsersByIdsWithOptions(context.Background(), []string{user1.Id, user2.Id}, &model.UserGetByIdsOptions{
|
|
Since: user2.UpdateAt - 1,
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
assert.Len(t, users, 1)
|
|
assert.Equal(t, users[0].Id, user2.Id)
|
|
})
|
|
}
|
|
|
|
func TestGetUsersByGroupChannelIds(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
gc1, appErr := th.App.CreateGroupChannel(th.Context, []string{th.BasicUser.Id, th.SystemAdminUser.Id, th.TeamAdminUser.Id}, th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
usersByChannelId, _, err := th.Client.GetUsersByGroupChannelIds(context.Background(), []string{gc1.Id})
|
|
require.NoError(t, err)
|
|
|
|
users, ok := usersByChannelId[gc1.Id]
|
|
assert.True(t, ok)
|
|
userIds := []string{}
|
|
for _, user := range users {
|
|
userIds = append(userIds, user.Id)
|
|
}
|
|
|
|
require.ElementsMatch(t, []string{th.SystemAdminUser.Id, th.TeamAdminUser.Id}, userIds)
|
|
|
|
th.LoginBasic2(t)
|
|
usersByChannelId, _, err = th.Client.GetUsersByGroupChannelIds(context.Background(), []string{gc1.Id})
|
|
require.NoError(t, err)
|
|
|
|
_, ok = usersByChannelId[gc1.Id]
|
|
require.False(t, ok)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err := th.Client.GetUsersByGroupChannelIds(context.Background(), []string{gc1.Id})
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
}
|
|
|
|
func TestGetUsersByUsernames(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
users, _, err := th.Client.GetUsersByUsernames(context.Background(), []string{th.BasicUser.Username})
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, th.BasicUser.Id, users[0].Id)
|
|
CheckUserSanitization(t, users[0])
|
|
|
|
_, resp, err := th.Client.GetUsersByIds(context.Background(), []string{})
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
users, _, err = th.Client.GetUsersByUsernames(context.Background(), []string{"junk"})
|
|
require.NoError(t, err)
|
|
require.Empty(t, users, "no users should be returned")
|
|
|
|
users, _, err = th.Client.GetUsersByUsernames(context.Background(), []string{"junk", th.BasicUser.Username})
|
|
require.NoError(t, err)
|
|
require.Len(t, users, 1, "1 user should be returned")
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.GetUsersByUsernames(context.Background(), []string{th.BasicUser.Username})
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
}
|
|
|
|
func TestGetTotalUsersStat(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
total, _ := th.Server.Store().User().Count(model.UserCountOptions{
|
|
IncludeDeleted: false,
|
|
IncludeBotAccounts: true,
|
|
})
|
|
|
|
rstats, _, err := th.Client.GetTotalUsersStats(context.Background(), "")
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, total, rstats.TotalUsersCount)
|
|
}
|
|
|
|
func TestUpdateUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
user := th.CreateUser(t)
|
|
_, _, err := th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
user.Nickname = "Joram Wilander"
|
|
user.Roles = model.SystemUserRoleId
|
|
user.LastPasswordUpdate = 123
|
|
|
|
ruser, _, err := th.Client.UpdateUser(context.Background(), user)
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, "Joram Wilander", ruser.Nickname, "Nickname should update properly")
|
|
require.Equal(t, model.SystemUserRoleId, ruser.Roles, "Roles should not update")
|
|
require.NotEqual(t, 123, ruser.LastPasswordUpdate, "LastPasswordUpdate should not update")
|
|
|
|
ruser.Email = th.GenerateTestEmail()
|
|
_, resp, err := th.Client.UpdateUser(context.Background(), ruser)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
ruser.Email = th.GenerateTestEmail()
|
|
_, _, err = client.UpdateUser(context.Background(), user)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
ruser.Password = user.Password
|
|
ruser, _, err = th.Client.UpdateUser(context.Background(), ruser)
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
ruser.Id = "junk"
|
|
_, resp, err = th.Client.UpdateUser(context.Background(), ruser)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
ruser.Id = model.NewId()
|
|
_, resp, err = th.Client.UpdateUser(context.Background(), ruser)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
r, err := th.Client.DoAPIPut(context.Background(), "/users/"+ruser.Id, "garbage")
|
|
require.Error(t, err)
|
|
require.Equal(t, http.StatusBadRequest, r.StatusCode)
|
|
|
|
session, _ := th.App.GetSession(th.Client.AuthToken)
|
|
session.IsOAuth = true
|
|
th.App.AddSessionToCache(session)
|
|
|
|
ruser.Id = user.Id
|
|
ruser.Email = th.GenerateTestEmail()
|
|
_, resp, err = th.Client.UpdateUser(context.Background(), ruser)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.UpdateUser(context.Background(), user)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
th.LoginBasic(t)
|
|
_, resp, err = th.Client.UpdateUser(context.Background(), user)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
_, _, err = client.UpdateUser(context.Background(), user)
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestUpdateAdminUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user := th.CreateUser(t)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, user.Id, model.SystemUserRoleId+" "+model.SystemAdminRoleId, false)
|
|
require.Nil(t, appErr)
|
|
user.Email = th.GenerateTestEmail()
|
|
|
|
th.AddPermissionToRole(t, model.PermissionEditOtherUsers.Id, model.SystemUserManagerRoleId)
|
|
_, appErr = th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserManagerRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
_, resp, err := th.Client.UpdateUser(context.Background(), user)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
u2, _, err := th.SystemAdminClient.UpdateUser(context.Background(), user)
|
|
require.NoError(t, err)
|
|
require.Equal(t, user.Email, u2.Email)
|
|
}
|
|
|
|
func TestUpdateBotUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(c *model.Config) {
|
|
*c.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
bot := th.CreateBotWithSystemAdminClient(t)
|
|
botUser, _, err := th.SystemAdminClient.GetUser(context.Background(), bot.UserId, "")
|
|
require.NoError(t, err)
|
|
|
|
updateUser, _, err := th.SystemAdminClient.UpdateUser(context.Background(), botUser)
|
|
require.NoError(t, err)
|
|
require.Equal(t, botUser.Id, updateUser.Id)
|
|
|
|
_, resp, err := th.Client.UpdateUser(context.Background(), botUser)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
}
|
|
|
|
func TestPatchUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user := th.CreateUser(t)
|
|
_, _, err := th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("Timezone limit error", func(t *testing.T) {
|
|
patch := &model.UserPatch{}
|
|
patch.Timezone = model.StringMap{}
|
|
patch.Timezone["manualTimezone"] = string(make([]byte, model.UserTimezoneMaxRunes))
|
|
var resp *model.Response
|
|
var ruser *model.User
|
|
ruser, resp, err = th.Client.PatchUser(context.Background(), user.Id, patch)
|
|
CheckBadRequestStatus(t, resp)
|
|
CheckErrorID(t, err, "model.user.is_valid.timezone_limit.app_error")
|
|
require.Nil(t, ruser)
|
|
})
|
|
|
|
patch := &model.UserPatch{}
|
|
patch.Password = model.NewPointer("testpassword")
|
|
patch.Nickname = model.NewPointer("Joram Wilander")
|
|
patch.FirstName = model.NewPointer("Joram")
|
|
patch.LastName = model.NewPointer("Wilander")
|
|
patch.Position = new(string)
|
|
patch.NotifyProps = model.StringMap{}
|
|
patch.NotifyProps["comment"] = "somethingrandom"
|
|
patch.Timezone = model.StringMap{}
|
|
patch.Timezone["useAutomaticTimezone"] = "true"
|
|
patch.Timezone["automaticTimezone"] = "America/New_York"
|
|
patch.Timezone["manualTimezone"] = ""
|
|
|
|
ruser, _, err := th.Client.PatchUser(context.Background(), user.Id, patch)
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, "Joram Wilander", ruser.Nickname, "Nickname should update properly")
|
|
require.Equal(t, "Joram", ruser.FirstName, "FirstName should update properly")
|
|
require.Equal(t, "Wilander", ruser.LastName, "LastName should update properly")
|
|
require.Empty(t, ruser.Position, "Position should update properly")
|
|
require.Equal(t, user.Username, ruser.Username, "Username should not update")
|
|
require.Empty(t, ruser.Password, "Password should not be returned")
|
|
require.Equal(t, "somethingrandom", ruser.NotifyProps["comment"], "NotifyProps should update properly")
|
|
require.Equal(t, "true", ruser.Timezone["useAutomaticTimezone"], "useAutomaticTimezone should update properly")
|
|
require.Equal(t, "America/New_York", ruser.Timezone["automaticTimezone"], "automaticTimezone should update properly")
|
|
require.Empty(t, ruser.Timezone["manualTimezone"], "manualTimezone should update properly")
|
|
|
|
appErr := th.App.CheckPasswordAndAllCriteria(th.Context, user.Id, *patch.Password, "")
|
|
require.NotNil(t, appErr, "Password should not match")
|
|
|
|
currentPassword := user.Password
|
|
user, appErr = th.App.GetUser(ruser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
appErr = th.App.CheckPasswordAndAllCriteria(th.Context, user.Id, currentPassword, "")
|
|
require.Nil(t, appErr, "Password should still match")
|
|
|
|
patch = &model.UserPatch{}
|
|
patch.Email = model.NewPointer(th.GenerateTestEmail())
|
|
|
|
_, resp, err := th.Client.PatchUser(context.Background(), user.Id, patch)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
patch.Password = model.NewPointer(currentPassword)
|
|
ruser, _, err = th.Client.PatchUser(context.Background(), user.Id, patch)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, *patch.Email, ruser.Email, "Email should update properly")
|
|
|
|
patch.Username = model.NewPointer(th.BasicUser2.Username)
|
|
_, resp, err = th.Client.PatchUser(context.Background(), user.Id, patch)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
patch.Username = nil
|
|
|
|
_, resp, err = th.Client.PatchUser(context.Background(), "junk", patch)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
ruser.Id = model.NewId()
|
|
_, resp, err = th.Client.PatchUser(context.Background(), model.NewId(), patch)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
r, err := th.Client.DoAPIPut(context.Background(), "/users/"+user.Id+"/patch", "garbage")
|
|
require.Error(t, err)
|
|
require.Equal(t, http.StatusBadRequest, r.StatusCode)
|
|
|
|
session, _ := th.App.GetSession(th.Client.AuthToken)
|
|
session.IsOAuth = true
|
|
th.App.AddSessionToCache(session)
|
|
|
|
patch.Email = model.NewPointer(th.GenerateTestEmail())
|
|
_, resp, err = th.Client.PatchUser(context.Background(), user.Id, patch)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.PatchUser(context.Background(), user.Id, patch)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
th.LoginBasic(t)
|
|
_, resp, err = th.Client.PatchUser(context.Background(), user.Id, patch)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, _, err = th.SystemAdminClient.PatchUser(context.Background(), user.Id, patch)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestPatchBotUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(c *model.Config) {
|
|
*c.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
bot := th.CreateBotWithSystemAdminClient(t)
|
|
patch := &model.UserPatch{}
|
|
patch.Email = model.NewPointer("newemail@test.com")
|
|
|
|
user, _, err := th.SystemAdminClient.PatchUser(context.Background(), bot.UserId, patch)
|
|
require.NoError(t, err)
|
|
require.Equal(t, bot.UserId, user.Id)
|
|
|
|
_, resp, err := th.Client.PatchUser(context.Background(), bot.UserId, patch)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
}
|
|
|
|
func TestPatchAdminUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user := th.CreateUser(t)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, user.Id, model.SystemUserRoleId+" "+model.SystemAdminRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
patch := &model.UserPatch{}
|
|
patch.Email = model.NewPointer(th.GenerateTestEmail())
|
|
|
|
th.AddPermissionToRole(t, model.PermissionEditOtherUsers.Id, model.SystemUserManagerRoleId)
|
|
_, appErr = th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserManagerRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
_, resp, err := th.Client.PatchUser(context.Background(), user.Id, patch)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, _, err = th.SystemAdminClient.PatchUser(context.Background(), user.Id, patch)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestUserUnicodeNames(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
client := th.Client
|
|
|
|
t.Run("create user unicode", func(t *testing.T) {
|
|
user := model.User{
|
|
Email: th.GenerateTestEmail(),
|
|
FirstName: "Andrew\u202e",
|
|
LastName: "\ufeffWiggin",
|
|
Nickname: "Ender\u2028 Wiggin",
|
|
Password: "hello1",
|
|
Username: "\ufeffwiggin77",
|
|
Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId,
|
|
}
|
|
|
|
ruser, resp, err := client.CreateUser(context.Background(), &user)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
_, _, err = client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "wiggin77", ruser.Username, "Bad Unicode not filtered from username")
|
|
require.Equal(t, "Andrew Wiggin", ruser.GetDisplayName(model.ShowFullName), "Bad Unicode not filtered from displayname")
|
|
require.Equal(t, "Ender Wiggin", ruser.Nickname, "Bad Unicode not filtered from nickname")
|
|
})
|
|
|
|
t.Run("update user unicode", func(t *testing.T) {
|
|
user := th.CreateUser(t)
|
|
_, _, err := client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
user.Username = "wiggin\ufff9"
|
|
user.Nickname = "Ender\u0340 \ufffcWiggin"
|
|
user.FirstName = "Andrew\ufff9"
|
|
user.LastName = "Wig\u206fgin"
|
|
|
|
ruser, _, err := client.UpdateUser(context.Background(), user)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "wiggin", ruser.Username, "bad unicode should be filtered from username")
|
|
require.Equal(t, "Ender Wiggin", ruser.Nickname, "bad unicode should be filtered from nickname")
|
|
require.Equal(t, "Andrew Wiggin", ruser.GetDisplayName(model.ShowFullName), "bad unicode should be filtered from display name")
|
|
})
|
|
|
|
t.Run("patch user unicode", func(t *testing.T) {
|
|
user := th.CreateUser(t)
|
|
_, _, err := client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
patch := &model.UserPatch{}
|
|
patch.Nickname = model.NewPointer("\U000E0000Ender\u206d Wiggin\U000E007F")
|
|
patch.FirstName = model.NewPointer("\U0001d173Andrew\U0001d17a")
|
|
patch.LastName = model.NewPointer("\u2028Wiggin\u2029")
|
|
|
|
ruser, _, err := client.PatchUser(context.Background(), user.Id, patch)
|
|
require.NoError(t, err)
|
|
CheckUserSanitization(t, ruser)
|
|
|
|
require.Equal(t, "Ender Wiggin", ruser.Nickname, "Bad unicode should be filtered from nickname")
|
|
require.Equal(t, "Andrew", ruser.FirstName, "Bad unicode should be filtered from first name")
|
|
require.Equal(t, "Wiggin", ruser.LastName, "Bad unicode should be filtered from last name")
|
|
require.Equal(t, "Andrew Wiggin", ruser.GetDisplayName(model.ShowFullName), "Bad unicode should be filtered from display name")
|
|
})
|
|
}
|
|
|
|
func TestUpdateUserAuth(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
team := th.CreateTeamWithClient(t, th.SystemAdminClient)
|
|
|
|
user := th.CreateUser(t)
|
|
|
|
th.LinkUserToTeam(t, user, team)
|
|
_, err := th.App.Srv().Store().User().VerifyEmail(user.Id, user.Email)
|
|
require.NoError(t, err)
|
|
|
|
userAuth := &model.UserAuth{}
|
|
userAuth.AuthData = user.AuthData
|
|
userAuth.AuthService = user.AuthService
|
|
|
|
// Regular user can not use endpoint
|
|
_, respErr, _ := th.SystemAdminClient.UpdateUserAuth(context.Background(), user.Id, userAuth)
|
|
require.NotNil(t, respErr, "Shouldn't have permissions. Only Admins")
|
|
|
|
userAuth.AuthData = model.NewPointer("test@test.com")
|
|
userAuth.AuthService = model.UserAuthServiceSaml
|
|
ruser, _, err := th.SystemAdminClient.UpdateUserAuth(context.Background(), user.Id, userAuth)
|
|
require.NoError(t, err)
|
|
|
|
// AuthData and AuthService are set, password is set to empty
|
|
require.Equal(t, *userAuth.AuthData, *ruser.AuthData)
|
|
require.Equal(t, model.UserAuthServiceSaml, ruser.AuthService)
|
|
|
|
// When AuthData or AuthService are empty, password must be valid
|
|
userAuth.AuthData = user.AuthData
|
|
userAuth.AuthService = ""
|
|
_, _, err = th.SystemAdminClient.UpdateUserAuth(context.Background(), user.Id, userAuth)
|
|
require.Error(t, err)
|
|
|
|
// Regular user can not use endpoint
|
|
user2 := th.CreateUser(t)
|
|
th.LinkUserToTeam(t, user2, team)
|
|
_, err = th.App.Srv().Store().User().VerifyEmail(user2.Id, user2.Email)
|
|
require.NoError(t, err)
|
|
|
|
_, _, err = th.SystemAdminClient.Login(context.Background(), user2.Email, "Pa$$word11")
|
|
require.NoError(t, err)
|
|
|
|
userAuth.AuthData = user.AuthData
|
|
userAuth.AuthService = user.AuthService
|
|
_, _, err = th.SystemAdminClient.UpdateUserAuth(context.Background(), user.Id, userAuth)
|
|
require.Error(t, err, "Should have errored")
|
|
}
|
|
|
|
func TestDeleteUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.LoginBasic(t)
|
|
resp, err := th.Client.DeleteUser(context.Background(), th.SystemAdminUser.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
resp, err = th.Client.DeleteUser(context.Background(), th.BasicUser.Id)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, c *model.Client4) {
|
|
resp, err = c.DeleteUser(context.Background(), model.NewId())
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
|
|
resp, err = c.DeleteUser(context.Background(), "junk")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
userToDelete := th.CreateUser(t)
|
|
_, err = c.DeleteUser(context.Background(), userToDelete.Id)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
selfDeleteUser := th.CreateUser(t)
|
|
th.LoginBasic(t)
|
|
resp, err = th.Client.DeleteUser(context.Background(), selfDeleteUser.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), selfDeleteUser.Email, selfDeleteUser.Password)
|
|
require.NoError(t, err)
|
|
th.App.UpdateConfig(func(c *model.Config) {
|
|
*c.TeamSettings.EnableUserDeactivation = false
|
|
})
|
|
resp, err = th.Client.DeleteUser(context.Background(), selfDeleteUser.Id)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
th.App.UpdateConfig(func(c *model.Config) {
|
|
*c.TeamSettings.EnableUserDeactivation = true
|
|
})
|
|
_, err = th.Client.DeleteUser(context.Background(), selfDeleteUser.Id)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestDeleteBotUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(c *model.Config) {
|
|
*c.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
bot := th.CreateBotWithSystemAdminClient(t)
|
|
|
|
_, err := th.Client.DeleteUser(context.Background(), bot.UserId)
|
|
require.Error(t, err)
|
|
require.Equal(t, err.Error(), "You do not have the appropriate permissions.")
|
|
}
|
|
|
|
func TestPermanentDeleteUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
enableAPIUserDeletion := *th.App.Config().ServiceSettings.EnableAPIUserDeletion
|
|
defer func() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableAPIUserDeletion = &enableAPIUserDeletion })
|
|
}()
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableAPIUserDeletion = false })
|
|
|
|
userToDelete := th.CreateUser(t)
|
|
|
|
t.Run("Permanent deletion not available through API if EnableAPIUserDeletion is not set", func(t *testing.T) {
|
|
resp, err := th.SystemAdminClient.PermanentDeleteUser(context.Background(), userToDelete.Id)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Permanent deletion available through local mode even if EnableAPIUserDeletion is not set", func(t *testing.T) {
|
|
_, err := th.LocalClient.PermanentDeleteUser(context.Background(), userToDelete.Id)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableAPIUserDeletion = true })
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, c *model.Client4) {
|
|
userToDelete = th.CreateUser(t)
|
|
_, err := c.PermanentDeleteUser(context.Background(), userToDelete.Id)
|
|
require.NoError(t, err)
|
|
|
|
_, appErr := th.App.GetTeam(userToDelete.Id)
|
|
assert.NotNil(t, appErr)
|
|
|
|
resp, err := c.PermanentDeleteUser(context.Background(), "junk")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
}, "Permanent deletion with EnableAPIUserDeletion set")
|
|
}
|
|
|
|
func TestPermanentDeleteAllUsers(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
t.Run("The endpoint should not be available for neither normal nor sysadmin users", func(t *testing.T) {
|
|
resp, err := th.Client.PermanentDeleteAllUsers(context.Background())
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
|
|
resp, err = th.SystemAdminClient.PermanentDeleteAllUsers(context.Background())
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("The endpoint should permanently delete all users", func(t *testing.T) {
|
|
// Basic user creates a team and a channel
|
|
team, appErr := th.App.CreateTeamWithUser(th.Context, &model.Team{
|
|
DisplayName: "User Created Team",
|
|
Name: "user-created-team",
|
|
Email: "usercreatedteam@test.com",
|
|
Type: model.TeamOpen,
|
|
}, th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
channel, appErr := th.App.CreateChannelWithUser(th.Context, &model.Channel{
|
|
DisplayName: "User Created Channel",
|
|
Name: "user-created-channel",
|
|
Type: model.ChannelTypeOpen,
|
|
TeamId: team.Id,
|
|
}, th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
// Check that we have users and posts in the database
|
|
users, err := th.App.Srv().Store().User().GetAll()
|
|
require.NoError(t, err)
|
|
require.Greater(t, len(users), 0)
|
|
|
|
require.NoError(t, th.App.Srv().Store().Post().RefreshPostStats())
|
|
postCount, err := th.App.Srv().Store().Post().AnalyticsPostCount(&model.PostCountOptions{})
|
|
require.NoError(t, err)
|
|
require.Greater(t, postCount, int64(0))
|
|
|
|
// Delete all users and their posts
|
|
_, err = th.LocalClient.PermanentDeleteAllUsers(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
// Check that both user and post tables are empty
|
|
users, err = th.App.Srv().Store().User().GetAll()
|
|
require.NoError(t, err)
|
|
require.Len(t, users, 0)
|
|
|
|
require.NoError(t, th.App.Srv().Store().Post().RefreshPostStats())
|
|
postCount, err = th.App.Srv().Store().Post().AnalyticsPostCount(&model.PostCountOptions{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, postCount, int64(0))
|
|
|
|
// Check that the channel and team created by the user were not deleted
|
|
rTeam, appErr := th.App.GetTeam(team.Id)
|
|
require.Nil(t, appErr)
|
|
require.NotNil(t, rTeam)
|
|
|
|
rChannel, appErr := th.App.GetChannel(th.Context, channel.Id)
|
|
require.Nil(t, appErr)
|
|
require.NotNil(t, rChannel)
|
|
})
|
|
}
|
|
|
|
func TestUpdateUserRoles(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
resp, err := th.Client.UpdateUserRoles(context.Background(), th.SystemAdminUser.Id, model.SystemUserRoleId)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
_, err = client.UpdateUserRoles(context.Background(), th.BasicUser.Id, model.SystemUserRoleId)
|
|
require.NoError(t, err)
|
|
|
|
_, err = client.UpdateUserRoles(context.Background(), th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemAdminRoleId)
|
|
require.NoError(t, err)
|
|
|
|
resp, err = client.UpdateUserRoles(context.Background(), th.BasicUser.Id, "junk")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
resp, err = client.UpdateUserRoles(context.Background(), "junk", model.SystemUserRoleId)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
resp, err = client.UpdateUserRoles(context.Background(), model.NewId(), model.SystemUserRoleId)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func assertExpectedWebsocketEvent(t *testing.T, client *model.WebSocketClient, event model.WebsocketEventType, test func(*model.WebSocketEvent)) {
|
|
for {
|
|
select {
|
|
case resp, ok := <-client.EventChannel:
|
|
require.Truef(t, ok, "channel closed before receiving expected event %s", string(event))
|
|
if resp.EventType() == event {
|
|
test(resp)
|
|
return
|
|
}
|
|
case <-time.After(5 * time.Second):
|
|
require.Failf(t, "failed to receive expected event %s", string(event))
|
|
}
|
|
}
|
|
}
|
|
|
|
func assertWebsocketEventUserUpdatedWithEmail(t *testing.T, client *model.WebSocketClient, email string) {
|
|
assertExpectedWebsocketEvent(t, client, model.WebsocketEventUserUpdated, func(event *model.WebSocketEvent) {
|
|
eventUser, ok := event.GetData()["user"].(*model.User)
|
|
require.True(t, ok, "expected user")
|
|
assert.Equal(t, email, eventUser.Email)
|
|
})
|
|
}
|
|
|
|
func TestUpdateUserActive(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
t.Run("basic tests", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user := th.BasicUser
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableUserDeactivation = true })
|
|
_, err := th.Client.UpdateUserActive(context.Background(), user.Id, false)
|
|
require.NoError(t, err)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableUserDeactivation = false })
|
|
resp, err := th.Client.UpdateUserActive(context.Background(), user.Id, false)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableUserDeactivation = true })
|
|
resp, err = th.Client.UpdateUserActive(context.Background(), user.Id, false)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
th.LoginBasic2(t)
|
|
|
|
resp, err = th.Client.UpdateUserActive(context.Background(), user.Id, true)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
resp, err = th.Client.UpdateUserActive(context.Background(), GenerateTestID(), true)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
resp, err = th.Client.UpdateUserActive(context.Background(), "junk", true)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
resp, err = th.Client.UpdateUserActive(context.Background(), user.Id, true)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
_, err = client.UpdateUserActive(context.Background(), user.Id, true)
|
|
require.NoError(t, err)
|
|
|
|
_, err = client.UpdateUserActive(context.Background(), user.Id, false)
|
|
require.NoError(t, err)
|
|
|
|
authData := model.NewId()
|
|
_, err := th.App.Srv().Store().User().UpdateAuthData(user.Id, "random", &authData, "", true)
|
|
require.NoError(t, err)
|
|
|
|
_, err = client.UpdateUserActive(context.Background(), user.Id, false)
|
|
require.NoError(t, err)
|
|
})
|
|
})
|
|
|
|
t.Run("websocket events", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user := th.BasicUser2
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableUserDeactivation = true })
|
|
|
|
webSocketClient := th.CreateConnectedWebSocketClient(t)
|
|
|
|
resp := <-webSocketClient.ResponseChannel
|
|
require.Equal(t, model.StatusOk, resp.Status)
|
|
|
|
adminWebSocketClient := th.CreateConnectedWebSocketClientWithClient(t, th.SystemAdminClient)
|
|
|
|
// Verify that both admins and regular users see the email when privacy settings allow same,
|
|
// and confirm event is fired for SystemAdmin and Local mode
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PrivacySettings.ShowEmailAddress = true })
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
_, err := client.UpdateUserActive(context.Background(), user.Id, false)
|
|
require.NoError(t, err)
|
|
|
|
assertWebsocketEventUserUpdatedWithEmail(t, webSocketClient, user.Email)
|
|
assertWebsocketEventUserUpdatedWithEmail(t, adminWebSocketClient, user.Email)
|
|
})
|
|
|
|
// Verify that only admins see the email when privacy settings hide emails,
|
|
// and confirm event is fired for SystemAdmin and Local mode
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PrivacySettings.ShowEmailAddress = false })
|
|
_, err := client.UpdateUserActive(context.Background(), user.Id, true)
|
|
require.NoError(t, err)
|
|
|
|
assertWebsocketEventUserUpdatedWithEmail(t, webSocketClient, "")
|
|
assertWebsocketEventUserUpdatedWithEmail(t, adminWebSocketClient, user.Email)
|
|
})
|
|
})
|
|
|
|
t.Run("activate guest should fail when guests feature is disable", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
guest := &model.User{
|
|
Email: "success+" + id + "@simulator.amazonses.com",
|
|
Username: "un_" + id,
|
|
Nickname: "nn_" + id,
|
|
Password: "Password1",
|
|
EmailVerified: true,
|
|
}
|
|
user, err := th.App.CreateGuest(th.Context, guest)
|
|
require.Nil(t, err)
|
|
_, appErr := th.App.UpdateActive(th.Context, user, false)
|
|
require.Nil(t, appErr)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = false })
|
|
defer th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
resp, err := client.UpdateUserActive(context.Background(), user.Id, true)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
})
|
|
|
|
t.Run("activate guest should work when guests feature is enabled", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
guest := &model.User{
|
|
Email: "success+" + id + "@simulator.amazonses.com",
|
|
Username: "un_" + id,
|
|
Nickname: "nn_" + id,
|
|
Password: "Password1",
|
|
EmailVerified: true,
|
|
}
|
|
user, appErr := th.App.CreateGuest(th.Context, guest)
|
|
require.Nil(t, appErr)
|
|
_, appErr = th.App.UpdateActive(th.Context, user, false)
|
|
require.Nil(t, appErr)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
_, err := client.UpdateUserActive(context.Background(), user.Id, true)
|
|
require.NoError(t, err)
|
|
})
|
|
})
|
|
|
|
t.Run("update active status of LDAP user should fail", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
ldapUser := &model.User{
|
|
Email: "ldapuser@mattermost-customer.com",
|
|
Username: "ldapuser",
|
|
Password: "Password123",
|
|
AuthService: model.UserAuthServiceLdap,
|
|
EmailVerified: true,
|
|
}
|
|
user, appErr := th.App.CreateUser(th.Context, ldapUser)
|
|
require.Nil(t, appErr)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
resp, err := client.UpdateUserActive(context.Background(), user.Id, false)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
resp, err = client.UpdateUserActive(context.Background(), user.Id, true)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestGetUsers(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
|
rusers, _, err := client.GetUsers(context.Background(), 0, 60, "")
|
|
require.NoError(t, err)
|
|
for _, u := range rusers {
|
|
CheckUserSanitization(t, u)
|
|
}
|
|
|
|
rusers, _, err = client.GetUsers(context.Background(), 0, 1, "")
|
|
require.NoError(t, err)
|
|
require.Len(t, rusers, 1, "should be 1 per page")
|
|
|
|
rusers, _, err = client.GetUsers(context.Background(), 1, 1, "")
|
|
require.NoError(t, err)
|
|
require.Len(t, rusers, 1, "should be 1 per page")
|
|
|
|
rusers, _, err = client.GetUsers(context.Background(), 10000, 100, "")
|
|
require.NoError(t, err)
|
|
require.Empty(t, rusers, "should be no users")
|
|
|
|
// Check default params for page and per_page
|
|
_, err = client.DoAPIGet(context.Background(), "/users", "")
|
|
require.NoError(t, err)
|
|
|
|
// Check role params validity
|
|
_, _, err = client.GetUsersWithCustomQueryParameters(context.Background(), 0, 5, "in_channel=random_channel_id&channel_roles=random_role_doesnt_exist", "")
|
|
require.Error(t, err)
|
|
require.Equal(t, err.Error(), "Invalid or missing channelRoles in request body.")
|
|
_, _, err = client.GetUsersWithCustomQueryParameters(context.Background(), 0, 5, "in_team=random_channel_id&team_roles=random_role_doesnt_exist", "")
|
|
require.Error(t, err)
|
|
require.Equal(t, err.Error(), "Invalid or missing teamRoles in request body.")
|
|
_, _, err = client.GetUsersWithCustomQueryParameters(context.Background(), 0, 5, "roles=random_role_doesnt_exist%2Csystem_user", "")
|
|
require.Error(t, err)
|
|
require.Equal(t, err.Error(), "Invalid or missing roles in request body.")
|
|
_, _, err = client.GetUsersWithCustomQueryParameters(context.Background(), 0, 5, "role=random_role_doesnt_exist", "")
|
|
require.Error(t, err)
|
|
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, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
}
|
|
|
|
func TestGetNewUsersInTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
teamId := th.BasicTeam.Id
|
|
|
|
rusers, _, err := th.Client.GetNewUsersInTeam(context.Background(), teamId, 0, 60, "")
|
|
require.NoError(t, err)
|
|
|
|
lastCreateAt := model.GetMillis()
|
|
for _, u := range rusers {
|
|
require.LessOrEqual(t, u.CreateAt, lastCreateAt, "right sorting")
|
|
lastCreateAt = u.CreateAt
|
|
CheckUserSanitization(t, u)
|
|
}
|
|
|
|
rusers, _, err = th.Client.GetNewUsersInTeam(context.Background(), teamId, 1, 1, "")
|
|
require.NoError(t, err)
|
|
require.Len(t, rusers, 1, "should be 1 per page")
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err := th.Client.GetNewUsersInTeam(context.Background(), teamId, 1, 1, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
}
|
|
|
|
func TestGetRecentlyActiveUsersInTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
teamId := th.BasicTeam.Id
|
|
|
|
th.App.SetStatusOnline(th.BasicUser.Id, true)
|
|
|
|
rusers, _, err := th.Client.GetRecentlyActiveUsersInTeam(context.Background(), teamId, 0, 60, "")
|
|
require.NoError(t, err)
|
|
|
|
for _, u := range rusers {
|
|
require.NotZero(t, u.LastActivityAt, "should return last activity at")
|
|
CheckUserSanitization(t, u)
|
|
}
|
|
|
|
rusers, _, err = th.Client.GetRecentlyActiveUsersInTeam(context.Background(), teamId, 0, 1, "")
|
|
require.NoError(t, err)
|
|
require.Len(t, rusers, 1, "should be 1 per page")
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err := th.Client.GetRecentlyActiveUsersInTeam(context.Background(), teamId, 0, 1, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
}
|
|
|
|
func TestGetActiveUsersInTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
teamId := th.BasicTeam.Id
|
|
|
|
_, err := th.SystemAdminClient.UpdateUserActive(context.Background(), th.BasicUser2.Id, false)
|
|
require.NoError(t, err)
|
|
rusers, _, err := th.Client.GetActiveUsersInTeam(context.Background(), teamId, 0, 60, "")
|
|
require.NoError(t, err)
|
|
|
|
require.NotZero(t, len(rusers))
|
|
for _, u := range rusers {
|
|
require.Zero(t, u.DeleteAt, "should not be deleted")
|
|
require.NotEqual(t, th.BasicUser2.Id, "should not include deactivated user")
|
|
CheckUserSanitization(t, u)
|
|
}
|
|
|
|
rusers, _, err = th.Client.GetActiveUsersInTeam(context.Background(), teamId, 0, 1, "")
|
|
require.NoError(t, err)
|
|
require.Len(t, rusers, 1, "should be 1 per page")
|
|
|
|
// Check case where we have supplied both active and inactive flags
|
|
_, err = th.Client.DoAPIGet(context.Background(), "/users?inactive=true&active=true", "")
|
|
require.Error(t, err)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err := th.Client.GetActiveUsersInTeam(context.Background(), teamId, 0, 1, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
}
|
|
|
|
func TestGetUsersWithoutTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
_, _, err := th.Client.GetUsersWithoutTeam(context.Background(), 0, 100, "")
|
|
require.Error(t, err, "should prevent non-admin user from getting users without a team")
|
|
|
|
// These usernames need to appear in the first 100 users for this to work
|
|
|
|
user, _, err := th.Client.CreateUser(context.Background(), &model.User{
|
|
Username: "a000000000" + model.NewId(),
|
|
Email: "success+" + model.NewId() + "@simulator.amazonses.com",
|
|
Password: "Password1",
|
|
})
|
|
require.NoError(t, err)
|
|
th.LinkUserToTeam(t, user, th.BasicTeam)
|
|
defer func() {
|
|
err = th.App.Srv().Store().User().PermanentDelete(th.Context, user.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
user2, _, err := th.Client.CreateUser(context.Background(), &model.User{
|
|
Username: "a000000001" + model.NewId(),
|
|
Email: "success+" + model.NewId() + "@simulator.amazonses.com",
|
|
Password: "Password1",
|
|
})
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
err = th.App.Srv().Store().User().PermanentDelete(th.Context, user2.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
rusers, _, err := th.SystemAdminClient.GetUsersWithoutTeam(context.Background(), 0, 100, "")
|
|
require.NoError(t, err)
|
|
|
|
found1 := false
|
|
found2 := false
|
|
|
|
for _, u := range rusers {
|
|
if u.Id == user.Id {
|
|
found1 = true
|
|
} else if u.Id == user2.Id {
|
|
found2 = true
|
|
}
|
|
}
|
|
|
|
require.False(t, found1, "should not return user that as a team")
|
|
require.True(t, found2, "should return user that has no teams")
|
|
}
|
|
|
|
func TestGetUsersInTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
teamId := th.BasicTeam.Id
|
|
|
|
rusers, resp, err := th.Client.GetUsersInTeam(context.Background(), teamId, 0, 60, "")
|
|
require.NoError(t, err)
|
|
for _, u := range rusers {
|
|
CheckUserSanitization(t, u)
|
|
}
|
|
|
|
rusers, resp, _ = th.Client.GetUsersInTeam(context.Background(), teamId, 0, 60, resp.Etag)
|
|
CheckEtag(t, rusers, resp)
|
|
|
|
rusers, _, err = th.Client.GetUsersInTeam(context.Background(), teamId, 0, 1, "")
|
|
require.NoError(t, err)
|
|
require.Len(t, rusers, 1, "should be 1 per page")
|
|
|
|
rusers, _, err = th.Client.GetUsersInTeam(context.Background(), teamId, 1, 1, "")
|
|
require.NoError(t, err)
|
|
require.Len(t, rusers, 1, "should be 1 per page")
|
|
|
|
rusers, _, err = th.Client.GetUsersInTeam(context.Background(), teamId, 10000, 100, "")
|
|
require.NoError(t, err)
|
|
require.Empty(t, rusers, "should be no users")
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.GetUsersInTeam(context.Background(), teamId, 0, 60, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
user := th.CreateUser(t)
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.GetUsersInTeam(context.Background(), teamId, 0, 60, "")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, _, err = th.SystemAdminClient.GetUsersInTeam(context.Background(), teamId, 0, 60, "")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetUsersNotInTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t).DeleteBots(t)
|
|
|
|
teamId := th.BasicTeam.Id
|
|
|
|
rusers, resp, err := th.Client.GetUsersNotInTeam(context.Background(), teamId, 0, 60, "")
|
|
require.NoError(t, err)
|
|
for _, u := range rusers {
|
|
CheckUserSanitization(t, u)
|
|
}
|
|
require.Len(t, rusers, 2, "should be 2 users in total")
|
|
|
|
rusers, resp, _ = th.Client.GetUsersNotInTeam(context.Background(), teamId, 0, 60, resp.Etag)
|
|
CheckEtag(t, rusers, resp)
|
|
|
|
rusers, _, err = th.Client.GetUsersNotInTeam(context.Background(), teamId, 0, 1, "")
|
|
require.NoError(t, err)
|
|
require.Len(t, rusers, 1, "should be 1 per page")
|
|
|
|
rusers, _, err = th.Client.GetUsersNotInTeam(context.Background(), teamId, 2, 1, "")
|
|
require.NoError(t, err)
|
|
require.Empty(t, rusers, "should be no users")
|
|
|
|
rusers, _, err = th.Client.GetUsersNotInTeam(context.Background(), teamId, 10000, 100, "")
|
|
require.NoError(t, err)
|
|
require.Empty(t, rusers, "should be no users")
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.GetUsersNotInTeam(context.Background(), teamId, 0, 60, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
user := th.CreateUser(t)
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.GetUsersNotInTeam(context.Background(), teamId, 0, 60, "")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, _, err = th.SystemAdminClient.GetUsersNotInTeam(context.Background(), teamId, 0, 60, "")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetUsersInChannel(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
channelId := th.BasicChannel.Id
|
|
|
|
rusers, _, err := th.Client.GetUsersInChannel(context.Background(), channelId, 0, 60, "")
|
|
require.NoError(t, err)
|
|
for _, u := range rusers {
|
|
CheckUserSanitization(t, u)
|
|
}
|
|
|
|
rusers, _, err = th.Client.GetUsersInChannel(context.Background(), channelId, 0, 1, "")
|
|
require.NoError(t, err)
|
|
require.Len(t, rusers, 1, "should be 1 per page")
|
|
|
|
rusers, _, err = th.Client.GetUsersInChannel(context.Background(), channelId, 1, 1, "")
|
|
require.NoError(t, err)
|
|
require.Len(t, rusers, 1, "should be 1 per page")
|
|
|
|
rusers, _, err = th.Client.GetUsersInChannel(context.Background(), channelId, 10000, 100, "")
|
|
require.NoError(t, err)
|
|
require.Empty(t, rusers, "should be no users")
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err := th.Client.GetUsersInChannel(context.Background(), channelId, 0, 60, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
user := th.CreateUser(t)
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.GetUsersInChannel(context.Background(), channelId, 0, 60, "")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, _, err = th.SystemAdminClient.GetUsersInChannel(context.Background(), channelId, 0, 60, "")
|
|
require.NoError(t, err)
|
|
|
|
t.Run("Should allow getting the members of an archived channel", func(t *testing.T) {
|
|
th.LoginBasic(t)
|
|
channel, _, appErr := th.SystemAdminClient.CreateChannel(context.Background(), &model.Channel{
|
|
DisplayName: "User Created Channel",
|
|
Name: model.NewId(),
|
|
Type: model.ChannelTypeOpen,
|
|
TeamId: th.BasicTeam.Id,
|
|
})
|
|
require.NoError(t, appErr)
|
|
_, aErr := th.App.AddUserToChannel(th.Context, th.BasicUser, channel, false)
|
|
require.Nil(t, aErr)
|
|
_, aErr = th.App.AddUserToChannel(th.Context, th.BasicUser2, channel, false)
|
|
require.Nil(t, aErr)
|
|
_, err = th.SystemAdminClient.DeleteChannel(context.Background(), channel.Id)
|
|
require.NoError(t, err)
|
|
|
|
for _, client := range []*model.Client4{th.SystemAdminClient, th.Client, th.LocalClient} {
|
|
users, _, userErr := client.GetUsersInChannel(context.Background(), channel.Id, 0, 1000, "")
|
|
require.NoError(t, userErr)
|
|
require.Len(t, users, 3)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGetUsersNotInChannel(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
teamId := th.BasicTeam.Id
|
|
channelId := th.BasicChannel.Id
|
|
|
|
user := th.CreateUser(t)
|
|
th.LinkUserToTeam(t, user, th.BasicTeam)
|
|
|
|
rusers, _, err := th.Client.GetUsersNotInChannel(context.Background(), teamId, channelId, 0, 60, "")
|
|
require.NoError(t, err)
|
|
for _, u := range rusers {
|
|
CheckUserSanitization(t, u)
|
|
}
|
|
|
|
rusers, _, err = th.Client.GetUsersNotInChannel(context.Background(), teamId, channelId, 0, 1, "")
|
|
require.NoError(t, err)
|
|
require.Len(t, rusers, 1, "should be 1 per page")
|
|
|
|
rusers, _, err = th.Client.GetUsersNotInChannel(context.Background(), teamId, channelId, 10000, 100, "")
|
|
require.NoError(t, err)
|
|
require.Empty(t, rusers, "should be no users")
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err := th.Client.GetUsersNotInChannel(context.Background(), teamId, channelId, 0, 60, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.GetUsersNotInChannel(context.Background(), teamId, channelId, 0, 60, "")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, _, err = th.SystemAdminClient.GetUsersNotInChannel(context.Background(), teamId, channelId, 0, 60, "")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetUsersInGroup(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
group, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
cid := model.NewId()
|
|
customGroup, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + cid,
|
|
Name: model.NewPointer("name" + cid),
|
|
Source: model.GroupSourceCustom,
|
|
Description: "description_" + cid,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
user1, err := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Nickname: "test user1", Password: "test-password-1", Username: "test-user-1", Roles: model.SystemUserRoleId})
|
|
assert.Nil(t, err)
|
|
|
|
t.Run("Requires ldap license", func(t *testing.T) {
|
|
_, response, err := th.SystemAdminClient.GetUsersInGroup(context.Background(), group.Id, 0, 60, "")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
})
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
|
|
|
t.Run("Requires manage system permission to access users in group", func(t *testing.T) {
|
|
_, _, err := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
var response *model.Response
|
|
_, response, err = th.Client.GetUsersInGroup(context.Background(), group.Id, 0, 60, "")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
})
|
|
|
|
_, err = th.App.UpsertGroupMember(group.Id, user1.Id)
|
|
assert.Nil(t, err)
|
|
|
|
t.Run("Returns users in group when called by system admin", func(t *testing.T) {
|
|
users, _, err := th.SystemAdminClient.GetUsersInGroup(context.Background(), group.Id, 0, 60, "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, users[0].Id, user1.Id)
|
|
})
|
|
|
|
t.Run("Returns no users when pagination out of range", func(t *testing.T) {
|
|
users, _, err := th.SystemAdminClient.GetUsersInGroup(context.Background(), group.Id, 5, 60, "")
|
|
require.NoError(t, err)
|
|
assert.Empty(t, users)
|
|
})
|
|
|
|
_, err = th.App.UpsertGroupMember(customGroup.Id, user1.Id)
|
|
assert.Nil(t, err)
|
|
|
|
t.Run("Returns users in custom group when called by regular user", func(t *testing.T) {
|
|
_, _, err := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
users, _, err := th.Client.GetUsersInGroup(context.Background(), customGroup.Id, 0, 60, "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, users[0].Id, user1.Id)
|
|
})
|
|
|
|
t.Run("Returns no users in custom group when called by guest user", func(t *testing.T) {
|
|
_, _, err := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
appErr := th.App.DemoteUserToGuest(th.Context, th.BasicUser)
|
|
require.Nil(t, appErr)
|
|
|
|
users, _, err := th.Client.GetUsersInGroup(context.Background(), customGroup.Id, 0, 60, "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, len(users), 0)
|
|
})
|
|
}
|
|
|
|
func TestGetUsersInGroupByDisplayName(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
group, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
user1, err := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Nickname: "aaa", Password: "test-password-1", Username: "zzz", Roles: model.SystemUserRoleId})
|
|
assert.Nil(t, err)
|
|
|
|
user2, err := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Password: "test-password-2", Username: "bbb", Roles: model.SystemUserRoleId})
|
|
assert.Nil(t, err)
|
|
|
|
_, err = th.App.UpsertGroupMember(group.Id, user1.Id)
|
|
assert.Nil(t, err)
|
|
_, err = th.App.UpsertGroupMember(group.Id, user2.Id)
|
|
assert.Nil(t, err)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.PrivacySettings.ShowFullName = true
|
|
})
|
|
|
|
preference := model.Preference{
|
|
UserId: th.SystemAdminUser.Id,
|
|
Category: model.PreferenceCategoryDisplaySettings,
|
|
Name: model.PreferenceNameNameFormat,
|
|
Value: model.ShowUsername,
|
|
}
|
|
|
|
err = th.App.UpdatePreferences(th.Context, th.SystemAdminUser.Id, model.Preferences{preference})
|
|
assert.Nil(t, err)
|
|
|
|
t.Run("Returns users in group in right order for username", func(t *testing.T) {
|
|
users, _, err := th.SystemAdminClient.GetUsersInGroupByDisplayName(context.Background(), group.Id, 0, 1, "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, users[0].Id, user2.Id)
|
|
})
|
|
|
|
preference.Value = model.ShowNicknameFullName
|
|
err = th.App.UpdatePreferences(th.Context, th.SystemAdminUser.Id, model.Preferences{preference})
|
|
assert.Nil(t, err)
|
|
|
|
t.Run("Returns users in group in right order for nickname", func(t *testing.T) {
|
|
users, _, err := th.SystemAdminClient.GetUsersInGroupByDisplayName(context.Background(), group.Id, 0, 1, "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, users[0].Id, user1.Id)
|
|
})
|
|
}
|
|
|
|
func TestUpdateUserMfa(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("mfa"))
|
|
t.Run("Without enforcing", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })
|
|
|
|
session, _ := th.App.GetSession(th.Client.AuthToken)
|
|
session.IsOAuth = true
|
|
th.App.AddSessionToCache(session)
|
|
|
|
defer th.Server.Platform().ClearUserSessionCacheLocal(th.BasicUser.Id)
|
|
|
|
resp, err := th.Client.UpdateUserMfa(context.Background(), th.BasicUser.Id, "12345", false)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
_, err := client.UpdateUserMfa(context.Background(), th.BasicUser.Id, "12345", false)
|
|
require.NoError(t, err)
|
|
})
|
|
})
|
|
|
|
t.Run("Enforcing", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableMultifactorAuthentication = true
|
|
*cfg.ServiceSettings.EnforceMultifactorAuthentication = true
|
|
})
|
|
|
|
resp, err := th.Client.UpdateUserMfa(context.Background(), th.BasicUser.Id, "12345", false)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
resp, err = th.LocalClient.UpdateUserMfa(context.Background(), th.BasicUser.Id, "12345", false)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
resp, err = th.SystemAdminClient.UpdateUserMfa(context.Background(), th.BasicUser.Id, "12345", false)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
CheckErrorID(t, err, "api.context.mfa_required.app_error")
|
|
})
|
|
}
|
|
|
|
func TestUserLoginMFAFlow(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(c *model.Config) {
|
|
*c.ServiceSettings.EnableMultifactorAuthentication = true
|
|
})
|
|
|
|
t.Run("WithoutMFA", func(t *testing.T) {
|
|
_, _, err := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("WithInvalidMFA", func(t *testing.T) {
|
|
secret, appErr := th.App.GenerateMfaSecret(th.BasicUser.Id)
|
|
assert.Nil(t, appErr)
|
|
|
|
// Fake user has MFA enabled
|
|
err := th.Server.Store().User().UpdateMfaActive(th.BasicUser.Id, true)
|
|
require.NoError(t, err)
|
|
|
|
err = th.Server.Store().User().UpdateMfaActive(th.BasicUser.Id, true)
|
|
require.NoError(t, err)
|
|
|
|
err = th.Server.Store().User().UpdateMfaSecret(th.BasicUser.Id, secret.Secret)
|
|
require.NoError(t, err)
|
|
|
|
user, _, err := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
CheckErrorID(t, err, "mfa.validate_token.authenticate.app_error")
|
|
assert.Nil(t, user)
|
|
|
|
user, _, err = th.Client.LoginWithMFA(context.Background(), th.BasicUser.Email, th.BasicUser.Password, "")
|
|
CheckErrorID(t, err, "mfa.validate_token.authenticate.app_error")
|
|
assert.Nil(t, user)
|
|
|
|
user, _, err = th.Client.LoginWithMFA(context.Background(), th.BasicUser.Email, th.BasicUser.Password, "abcdefgh")
|
|
CheckErrorID(t, err, "mfa.validate_token.authenticate.app_error")
|
|
assert.Nil(t, user)
|
|
|
|
secret2, appErr := th.App.GenerateMfaSecret(th.BasicUser2.Id)
|
|
assert.Nil(t, appErr)
|
|
user, _, err = th.Client.LoginWithMFA(context.Background(), th.BasicUser.Email, th.BasicUser.Password, secret2.Secret)
|
|
CheckErrorID(t, err, "mfa.validate_token.authenticate.app_error")
|
|
assert.Nil(t, user)
|
|
})
|
|
|
|
t.Run("WithCorrectMFA", func(t *testing.T) {
|
|
secret, appErr := th.App.GenerateMfaSecret(th.BasicUser.Id)
|
|
assert.Nil(t, appErr)
|
|
|
|
// Fake user has MFA enabled
|
|
err := th.Server.Store().User().UpdateMfaActive(th.BasicUser.Id, true)
|
|
require.NoError(t, err)
|
|
|
|
err = th.Server.Store().User().UpdateMfaSecret(th.BasicUser.Id, secret.Secret)
|
|
require.NoError(t, err)
|
|
|
|
code := dgoogauth.ComputeCode(secret.Secret, time.Now().UTC().Unix()/30)
|
|
|
|
user, _, err := th.Client.LoginWithMFA(context.Background(), th.BasicUser.Email, th.BasicUser.Password, fmt.Sprintf("%06d", code))
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, user)
|
|
})
|
|
}
|
|
|
|
func TestGenerateMfaSecret(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = false })
|
|
|
|
_, resp, err := th.Client.GenerateMfaSecret(context.Background(), th.BasicUser.Id)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, resp)
|
|
|
|
_, resp, err = th.SystemAdminClient.GenerateMfaSecret(context.Background(), th.BasicUser.Id)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, resp)
|
|
|
|
_, resp, err = th.Client.GenerateMfaSecret(context.Background(), "junk")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("mfa"))
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })
|
|
|
|
_, resp, err = th.Client.GenerateMfaSecret(context.Background(), model.NewId())
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
session, _ := th.App.GetSession(th.Client.AuthToken)
|
|
session.IsOAuth = true
|
|
th.App.AddSessionToCache(session)
|
|
|
|
_, resp, err = th.Client.GenerateMfaSecret(context.Background(), th.BasicUser.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err = th.Client.GenerateMfaSecret(context.Background(), th.BasicUser.Id)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
}
|
|
|
|
func TestUpdateUserPassword(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
password := "newpassword1"
|
|
_, err := th.Client.UpdateUserPassword(context.Background(), th.BasicUser.Id, th.BasicUser.Password, password)
|
|
require.NoError(t, err)
|
|
|
|
resp, err := th.Client.UpdateUserPassword(context.Background(), th.BasicUser.Id, password, "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
resp, err = th.Client.UpdateUserPassword(context.Background(), th.BasicUser.Id, password, "junk")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
resp, err = th.Client.UpdateUserPassword(context.Background(), "junk", password, password)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
resp, err = th.Client.UpdateUserPassword(context.Background(), th.BasicUser.Id, "", password)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
resp, err = th.Client.UpdateUserPassword(context.Background(), th.BasicUser.Id, "junk", password)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
_, err = th.Client.UpdateUserPassword(context.Background(), th.BasicUser.Id, password, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
resp, err = th.Client.UpdateUserPassword(context.Background(), th.BasicUser.Id, password, password)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
th.LoginBasic2(t)
|
|
resp, err = th.Client.UpdateUserPassword(context.Background(), th.BasicUser.Id, password, password)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
th.LoginBasic(t)
|
|
|
|
// Test lockout
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.MaximumLoginAttempts = 2 })
|
|
|
|
// Fail twice
|
|
resp, err = th.Client.UpdateUserPassword(context.Background(), th.BasicUser.Id, "badpwd", "newpwd")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
resp, err = th.Client.UpdateUserPassword(context.Background(), th.BasicUser.Id, "badpwd", "newpwd")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
// Should fail because account is locked out
|
|
resp, err = th.Client.UpdateUserPassword(context.Background(), th.BasicUser.Id, th.BasicUser.Password, "newpwd")
|
|
CheckErrorID(t, err, "api.user.check_user_login_attempts.too_many.app_error")
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
// System admin can update another user's password
|
|
adminSetPassword := "pwdsetbyadmin"
|
|
_, err = th.SystemAdminClient.UpdateUserPassword(context.Background(), th.BasicUser.Id, "", adminSetPassword)
|
|
require.NoError(t, err)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, adminSetPassword)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestUpdateUserHashedPassword(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
client := th.Client
|
|
|
|
password := "SuperSecurePass23!"
|
|
passwordHash := "$2a$10$CiS1iWVPUj7rQNdY6XW53.DmaPLsETIvmW2p0asp4Dqpofs10UL5W"
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
_, err := client.UpdateUserHashedPassword(context.Background(), th.BasicUser.Id, passwordHash)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
_, _, err := client.Login(context.Background(), th.BasicUser.Email, password)
|
|
require.NoError(t, err)
|
|
|
|
// Standard users should never be updating their passwords with already-
|
|
// hashed passwords.
|
|
resp, err := client.UpdateUserHashedPassword(context.Background(), th.BasicUser.Id, passwordHash)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
}
|
|
|
|
func TestResetPassword(t *testing.T) {
|
|
t.Skip("test disabled during old build server changes, should be investigated")
|
|
|
|
th := Setup(t).InitBasic(t)
|
|
_, err := th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
user := th.BasicUser
|
|
// Delete all the messages before check the reset password
|
|
err = mail.DeleteMailBox(user.Email)
|
|
require.NoError(t, err)
|
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
|
_, err = client.SendPasswordResetEmail(context.Background(), user.Email)
|
|
require.NoError(t, err)
|
|
var resp *model.Response
|
|
resp, err = client.SendPasswordResetEmail(context.Background(), "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
// Should not leak whether the email is attached to an account or not
|
|
_, err = client.SendPasswordResetEmail(context.Background(), "notreal@example.com")
|
|
require.NoError(t, err)
|
|
})
|
|
// Check if the email was send to the right email address and the recovery key match
|
|
var resultsMailbox mail.JSONMessageHeaderInbucket
|
|
err = mail.RetryInbucket(5, func() error {
|
|
resultsMailbox, err = mail.GetMailBox(user.Email)
|
|
return err
|
|
})
|
|
if err != nil {
|
|
t.Log(err)
|
|
t.Log("No email was received, maybe due load on the server. Disabling this verification")
|
|
}
|
|
var recoveryTokenString string
|
|
if err == nil && len(resultsMailbox) > 0 {
|
|
require.Contains(t, resultsMailbox[0].To[0], user.Email, "Correct To recipient")
|
|
resultsEmail, mailErr := mail.GetMessageFromMailbox(user.Email, resultsMailbox[0].ID)
|
|
require.NoError(t, mailErr)
|
|
loc := strings.Index(resultsEmail.Body.Text, "token=")
|
|
require.NotEqual(t, -1, loc, "Code should be found in email")
|
|
loc += 6
|
|
recoveryTokenString = resultsEmail.Body.Text[loc : loc+model.TokenSize]
|
|
}
|
|
recoveryToken, err := th.App.Srv().Store().Token().GetByToken(recoveryTokenString)
|
|
require.NoError(t, err, "Recovery token not found (%s)", recoveryTokenString)
|
|
|
|
resp, err := th.Client.ResetPassword(context.Background(), recoveryToken.Token, "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
resp, err = th.Client.ResetPassword(context.Background(), recoveryToken.Token, "newp")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
resp, err = th.Client.ResetPassword(context.Background(), "", "newpwd")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
resp, err = th.Client.ResetPassword(context.Background(), "junk", "newpwd")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
var code strings.Builder
|
|
for range model.TokenSize {
|
|
code.WriteString("a")
|
|
}
|
|
resp, err = th.Client.ResetPassword(context.Background(), code.String(), "newpwd")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
_, err = th.Client.ResetPassword(context.Background(), recoveryToken.Token, "newpwd")
|
|
require.NoError(t, err)
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, "newpwd")
|
|
require.NoError(t, err)
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
resp, err = th.Client.ResetPassword(context.Background(), recoveryToken.Token, "newpwd")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
authData := model.NewId()
|
|
_, err = th.App.Srv().Store().User().UpdateAuthData(user.Id, "random", &authData, "", true)
|
|
require.NoError(t, err)
|
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
|
resp, err = client.SendPasswordResetEmail(context.Background(), user.Email)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestGetSessions(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user := th.BasicUser
|
|
|
|
_, _, err := th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
sessions, _, err := th.Client.GetSessions(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
for _, session := range sessions {
|
|
require.Equal(t, user.Id, session.UserId, "user id should match session user id")
|
|
}
|
|
|
|
resp, err := th.Client.RevokeSession(context.Background(), "junk", model.NewId())
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
_, resp, err = th.Client.GetSessions(context.Background(), th.BasicUser2.Id, "")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, resp, err = th.Client.GetSessions(context.Background(), model.NewId(), "")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.GetSessions(context.Background(), th.BasicUser2.Id, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
_, _, err = th.SystemAdminClient.GetSessions(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
|
|
_, _, err = th.SystemAdminClient.GetSessions(context.Background(), th.BasicUser2.Id, "")
|
|
require.NoError(t, err)
|
|
|
|
_, _, err = th.SystemAdminClient.GetSessions(context.Background(), model.NewId(), "")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestRevokeSessions(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user := th.BasicUser
|
|
_, _, err := th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
sessions, _, _ := th.Client.GetSessions(context.Background(), user.Id, "")
|
|
require.NotZero(t, len(sessions), "sessions should exist")
|
|
for _, session := range sessions {
|
|
require.Equal(t, user.Id, session.UserId, "user id does not match session user id")
|
|
}
|
|
session := sessions[0]
|
|
|
|
resp, err := th.Client.RevokeSession(context.Background(), user.Id, model.NewId())
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
resp, err = th.Client.RevokeSession(context.Background(), th.BasicUser2.Id, model.NewId())
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
resp, err = th.Client.RevokeSession(context.Background(), "junk", model.NewId())
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
_, err = th.Client.RevokeSession(context.Background(), user.Id, session.Id)
|
|
require.NoError(t, err)
|
|
|
|
th.LoginBasic(t)
|
|
|
|
sessions, _ = th.App.GetSessions(th.Context, th.SystemAdminUser.Id)
|
|
session = sessions[0]
|
|
|
|
resp, err = th.Client.RevokeSession(context.Background(), user.Id, session.Id)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
resp, err = th.Client.RevokeSession(context.Background(), user.Id, model.NewId())
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
resp, err = th.SystemAdminClient.RevokeSession(context.Background(), user.Id, model.NewId())
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
sessions, _, _ = th.SystemAdminClient.GetSessions(context.Background(), th.SystemAdminUser.Id, "")
|
|
require.NotEmpty(t, sessions, "sessions should exist")
|
|
for _, session := range sessions {
|
|
require.Equal(t, th.SystemAdminUser.Id, session.UserId, "user id should match session user id")
|
|
}
|
|
session = sessions[0]
|
|
|
|
_, err = th.SystemAdminClient.RevokeSession(context.Background(), th.SystemAdminUser.Id, session.Id)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestRevokeAllSessions(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user := th.BasicUser
|
|
_, _, err := th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
resp, err := th.Client.RevokeAllSessions(context.Background(), th.BasicUser2.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
resp, err = th.Client.RevokeAllSessions(context.Background(), "junk"+user.Id)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
_, err = th.Client.RevokeAllSessions(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
resp, err = th.Client.RevokeAllSessions(context.Background(), user.Id)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
sessions, _, _ := th.Client.GetSessions(context.Background(), user.Id, "")
|
|
require.NotEmpty(t, sessions, "session should exist")
|
|
|
|
_, err = th.Client.RevokeAllSessions(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
|
|
sessions, _, _ = th.SystemAdminClient.GetSessions(context.Background(), user.Id, "")
|
|
require.Empty(t, sessions, "no sessions should exist for user")
|
|
|
|
resp, err = th.Client.RevokeAllSessions(context.Background(), user.Id)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
}
|
|
|
|
func TestRevokeSessionsFromAllUsers(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user := th.BasicUser
|
|
_, _, err := th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
resp, err := th.Client.RevokeSessionsFromAllUsers(context.Background())
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
resp, err = th.Client.RevokeSessionsFromAllUsers(context.Background())
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
admin := th.SystemAdminUser
|
|
_, _, err = th.Client.Login(context.Background(), admin.Email, admin.Password)
|
|
require.NoError(t, err)
|
|
sessions, err := th.Server.Store().Session().GetSessions(th.Context, user.Id)
|
|
require.NotEmpty(t, sessions)
|
|
require.NoError(t, err)
|
|
sessions, err = th.Server.Store().Session().GetSessions(th.Context, admin.Id)
|
|
require.NotEmpty(t, sessions)
|
|
require.NoError(t, err)
|
|
_, err = th.Client.RevokeSessionsFromAllUsers(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
// All sessions were revoked, so making the same call
|
|
// again will fail due to lack of a session.
|
|
resp, err = th.Client.RevokeSessionsFromAllUsers(context.Background())
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
sessions, err = th.Server.Store().Session().GetSessions(th.Context, user.Id)
|
|
require.Empty(t, sessions)
|
|
require.NoError(t, err)
|
|
|
|
sessions, err = th.Server.Store().Session().GetSessions(th.Context, admin.Id)
|
|
require.Empty(t, sessions)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestAttachDeviceId(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
deviceId := model.PushNotifyApple + ":1234567890"
|
|
|
|
t.Run("success", func(t *testing.T) {
|
|
testCases := []struct {
|
|
Description string
|
|
SiteURL string
|
|
ExpectedSetCookieHeaderRegexp string
|
|
}{
|
|
{"no subpath", "http://localhost:8065", "^MMAUTHTOKEN=[a-z0-9]+; Path=/"},
|
|
{"subpath", "http://localhost:8065/subpath", "^MMAUTHTOKEN=[a-z0-9]+; Path=/subpath"},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.Description, func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.SiteURL = tc.SiteURL
|
|
})
|
|
|
|
resp, err := th.Client.AttachDeviceProps(context.Background(), map[string]string{"device_id": deviceId})
|
|
require.NoError(t, err)
|
|
|
|
cookies := resp.Header.Get("Set-Cookie")
|
|
assert.Regexp(t, tc.ExpectedSetCookieHeaderRegexp, cookies)
|
|
|
|
sessions, appErr := th.App.GetSessions(th.Context, th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
assert.Equal(t, deviceId, sessions[0].DeviceId, "Missing device Id")
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("not logged in", func(t *testing.T) {
|
|
_, err := th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
resp, err := th.Client.AttachDeviceProps(context.Background(), map[string]string{})
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
|
|
// Props related tests
|
|
|
|
client := th.CreateClient()
|
|
th.LoginBasicWithClient(t, client)
|
|
|
|
resetSession := func(session *model.Session) {
|
|
session.AddProp(model.SessionPropDeviceNotificationDisabled, "")
|
|
session.AddProp(model.SessionPropMobileVersion, "")
|
|
err := th.Server.Store().Session().UpdateProps(session)
|
|
require.NoError(t, err)
|
|
th.App.ClearSessionCacheForUser(session.UserId)
|
|
}
|
|
|
|
t.Run("No props will return ok and no changes in the session", func(t *testing.T) {
|
|
session, _ := th.App.GetSession(client.AuthToken)
|
|
defer resetSession(session)
|
|
res, err := client.AttachDeviceProps(context.Background(), map[string]string{})
|
|
assert.NoError(t, err)
|
|
|
|
updatedSession, _ := th.App.GetSession(client.AuthToken)
|
|
storeSession, _ := th.Server.Store().Session().Get(th.Context, session.Id)
|
|
assert.Equal(t, http.StatusOK, res.StatusCode)
|
|
assert.Equal(t, session.Props, updatedSession.Props)
|
|
assert.Equal(t, session.Props, storeSession.Props)
|
|
})
|
|
t.Run("Unknown props will be ignored, returning ok and no changes in the session", func(t *testing.T) {
|
|
session, _ := th.App.GetSession(client.AuthToken)
|
|
defer resetSession(session)
|
|
res, err := client.AttachDeviceProps(context.Background(), map[string]string{"unknownProp": "foo"})
|
|
assert.NoError(t, err)
|
|
|
|
updatedSession, _ := th.App.GetSession(client.AuthToken)
|
|
storeSession, _ := th.Server.Store().Session().Get(th.Context, session.Id)
|
|
assert.Equal(t, http.StatusOK, res.StatusCode)
|
|
assert.Equal(t, session.Props, updatedSession.Props)
|
|
assert.Equal(t, session.Props, storeSession.Props)
|
|
})
|
|
t.Run("Invalid disabled notification prop will return an error and no changes in the session", func(t *testing.T) {
|
|
session, _ := th.App.GetSession(client.AuthToken)
|
|
defer resetSession(session)
|
|
res, err := client.AttachDeviceProps(context.Background(), map[string]string{model.SessionPropDeviceNotificationDisabled: "foo"})
|
|
assert.Error(t, err)
|
|
|
|
updatedSession, _ := th.App.GetSession(client.AuthToken)
|
|
storeSession, _ := th.Server.Store().Session().Get(th.Context, session.Id)
|
|
assert.Equal(t, http.StatusBadRequest, res.StatusCode)
|
|
assert.Equal(t, session.Props, updatedSession.Props)
|
|
assert.Equal(t, session.Props, storeSession.Props)
|
|
})
|
|
t.Run("Invalid version will return an error and no changes in the session", func(t *testing.T) {
|
|
session, _ := th.App.GetSession(client.AuthToken)
|
|
defer resetSession(session)
|
|
res, err := client.AttachDeviceProps(context.Background(), map[string]string{model.SessionPropMobileVersion: "foo"})
|
|
assert.Error(t, err)
|
|
|
|
updatedSession, _ := th.App.GetSession(client.AuthToken)
|
|
storeSession, _ := th.Server.Store().Session().Get(th.Context, session.Id)
|
|
assert.Equal(t, http.StatusBadRequest, res.StatusCode)
|
|
assert.Equal(t, session.Props, updatedSession.Props)
|
|
assert.Equal(t, session.Props, storeSession.Props)
|
|
})
|
|
t.Run("Will update props", func(t *testing.T) {
|
|
session, _ := th.App.GetSession(client.AuthToken)
|
|
defer resetSession(session)
|
|
res, err := client.AttachDeviceProps(context.Background(), map[string]string{model.SessionPropDeviceNotificationDisabled: "true", model.SessionPropMobileVersion: "2.19.0"})
|
|
assert.NoError(t, err)
|
|
|
|
updatedSession, _ := th.App.GetSession(client.AuthToken)
|
|
storeSession, _ := th.Server.Store().Session().Get(th.Context, session.Id)
|
|
assert.Equal(t, http.StatusOK, res.StatusCode)
|
|
assert.Equal(t, "true", updatedSession.Props[model.SessionPropDeviceNotificationDisabled])
|
|
assert.Equal(t, "true", storeSession.Props[model.SessionPropDeviceNotificationDisabled])
|
|
assert.Equal(t, "2.19.0", updatedSession.Props[model.SessionPropMobileVersion])
|
|
assert.Equal(t, "2.19.0", storeSession.Props[model.SessionPropMobileVersion])
|
|
})
|
|
}
|
|
|
|
func TestGetUserAudits(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
user := th.BasicUser
|
|
|
|
audits, _, err := th.Client.GetUserAudits(context.Background(), user.Id, 0, 100, "")
|
|
for _, audit := range audits {
|
|
require.Equal(t, user.Id, audit.UserId, "user id should match audit user id")
|
|
}
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := th.Client.GetUserAudits(context.Background(), th.BasicUser2.Id, 0, 100, "")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.GetUserAudits(context.Background(), user.Id, 0, 100, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
_, _, err = th.SystemAdminClient.GetUserAudits(context.Background(), user.Id, 0, 100, "")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestVerifyUserEmail(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
email := th.GenerateTestEmail()
|
|
user := model.User{Email: email, Nickname: "Darth Vader", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId}
|
|
|
|
ruser, _, _ := th.Client.CreateUser(context.Background(), &user)
|
|
|
|
token, err := th.App.Srv().EmailService.CreateVerifyEmailToken(ruser.Id, email)
|
|
require.NoError(t, err, "Unable to create email verify token")
|
|
|
|
_, err = th.Client.VerifyUserEmail(context.Background(), token.Token)
|
|
require.NoError(t, err)
|
|
|
|
resp, err := th.Client.VerifyUserEmail(context.Background(), GenerateTestID())
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
resp, err = th.Client.VerifyUserEmail(context.Background(), "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
}
|
|
|
|
func TestSendVerificationEmail(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
_, err := th.Client.SendVerificationEmail(context.Background(), th.BasicUser.Email)
|
|
require.NoError(t, err)
|
|
|
|
resp, err := th.Client.SendVerificationEmail(context.Background(), "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
// Even non-existent emails should return 200 OK
|
|
_, err = th.Client.SendVerificationEmail(context.Background(), th.GenerateTestEmail())
|
|
require.NoError(t, err)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, err = th.Client.SendVerificationEmail(context.Background(), th.BasicUser.Email)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestSetProfileImage(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
user := th.BasicUser
|
|
|
|
data, err := testutils.ReadTestFile("test.png")
|
|
require.NoError(t, err)
|
|
|
|
_, err = th.Client.SetProfileImage(context.Background(), user.Id, data)
|
|
require.NoError(t, err)
|
|
|
|
resp, err := th.Client.SetProfileImage(context.Background(), model.NewId(), data)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
// status code returns either forbidden or unauthorized
|
|
// note: forbidden is set as default at Client4.SetProfileImage when request is terminated early by server
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
resp, err = th.Client.SetProfileImage(context.Background(), user.Id, data)
|
|
require.Error(t, err)
|
|
if resp.StatusCode == http.StatusForbidden {
|
|
CheckForbiddenStatus(t, resp)
|
|
} else if resp.StatusCode == http.StatusUnauthorized {
|
|
CheckUnauthorizedStatus(t, resp)
|
|
} else {
|
|
require.Fail(t, "Should have failed either forbidden or unauthorized")
|
|
}
|
|
|
|
buser, appErr := th.App.GetUser(user.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
_, err = th.SystemAdminClient.SetProfileImage(context.Background(), user.Id, data)
|
|
require.NoError(t, err)
|
|
|
|
ruser, appErr := th.App.GetUser(user.Id)
|
|
require.Nil(t, appErr)
|
|
assert.True(t, buser.LastPictureUpdate == ruser.LastPictureUpdate, "Same picture should not have updated")
|
|
|
|
data2, err := testutils.ReadTestFile("testjpg.jpg")
|
|
require.NoError(t, err)
|
|
|
|
_, err = th.SystemAdminClient.SetProfileImage(context.Background(), user.Id, data2)
|
|
require.NoError(t, err)
|
|
|
|
ruser, appErr = th.App.GetUser(user.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
assert.True(t, buser.LastPictureUpdate < ruser.LastPictureUpdate, "Picture should have updated for user")
|
|
|
|
info := &model.FileInfo{Path: "users/" + user.Id + "/profile.png"}
|
|
err = th.cleanupTestFile(info)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestSetDefaultProfileImage(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
user := th.BasicUser
|
|
|
|
startTime := model.GetMillis()
|
|
time.Sleep(time.Millisecond)
|
|
|
|
_, err := th.Client.SetDefaultProfileImage(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
|
|
iuser, getUserErr := th.App.GetUser(user.Id)
|
|
require.Nil(t, getUserErr)
|
|
assert.Less(t, iuser.LastPictureUpdate, -startTime, "LastPictureUpdate should be set to -(current time in milliseconds)")
|
|
|
|
resp, err := th.Client.SetDefaultProfileImage(context.Background(), model.NewId())
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
// status code returns either forbidden or unauthorized
|
|
// note: forbidden is set as default at Client4.SetDefaultProfileImage when request is terminated early by server
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
resp, err = th.Client.SetDefaultProfileImage(context.Background(), user.Id)
|
|
require.Error(t, err)
|
|
if resp.StatusCode == http.StatusForbidden {
|
|
CheckForbiddenStatus(t, resp)
|
|
} else if resp.StatusCode == http.StatusUnauthorized {
|
|
CheckUnauthorizedStatus(t, resp)
|
|
} else {
|
|
require.Fail(t, "Should have failed either forbidden or unauthorized")
|
|
}
|
|
|
|
time.Sleep(time.Millisecond)
|
|
|
|
_, err = th.SystemAdminClient.SetDefaultProfileImage(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
|
|
// Check that a system admin can set the default profile image for another system admin
|
|
anotherAdmin := th.CreateUser(t)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, anotherAdmin.Id, model.SystemAdminRoleId+" "+model.SystemUserRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
_, err = th.SystemAdminClient.SetDefaultProfileImage(context.Background(), anotherAdmin.Id)
|
|
require.NoError(t, err)
|
|
|
|
ruser, appErr := th.App.GetUser(user.Id)
|
|
require.Nil(t, appErr)
|
|
assert.Less(t, ruser.LastPictureUpdate, iuser.LastPictureUpdate, "LastPictureUpdate should be updated to a lower negative number")
|
|
|
|
info := &model.FileInfo{Path: "users/" + user.Id + "/profile.png"}
|
|
err = th.cleanupTestFile(info)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestLogin(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
_, err := th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
t.Run("missing password", func(t *testing.T) {
|
|
_, _, err := th.Client.Login(context.Background(), th.BasicUser.Email, "")
|
|
CheckErrorID(t, err, "api.user.login.blank_pwd.app_error")
|
|
})
|
|
|
|
t.Run("unknown user", func(t *testing.T) {
|
|
_, _, err := th.Client.Login(context.Background(), "unknown", th.BasicUser.Password)
|
|
CheckErrorID(t, err, "api.user.login.invalid_credentials_email_username")
|
|
})
|
|
|
|
t.Run("valid login", func(t *testing.T) {
|
|
user, _, err := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, user.Id, th.BasicUser.Id)
|
|
})
|
|
|
|
t.Run("bot login rejected", func(t *testing.T) {
|
|
bot, _, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{
|
|
Username: "bot",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
botUser, _, err := th.SystemAdminClient.GetUser(context.Background(), bot.UserId, "")
|
|
require.NoError(t, err)
|
|
|
|
_, err = th.SystemAdminClient.UpdateUserPassword(context.Background(), bot.UserId, "", "password")
|
|
require.NoError(t, err)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), botUser.Email, "password")
|
|
CheckErrorID(t, err, "api.user.login.bot_login_forbidden.app_error")
|
|
})
|
|
|
|
t.Run("remote user login rejected", func(t *testing.T) {
|
|
email := th.GenerateTestEmail()
|
|
user := model.User{Email: email, Nickname: "Darth Vader", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId, RemoteId: model.NewPointer("remote-id")}
|
|
ruser, appErr := th.App.CreateUser(th.Context, &user)
|
|
require.Nil(t, appErr)
|
|
|
|
// remote user cannot reset password
|
|
_, err := th.SystemAdminClient.UpdateUserPassword(context.Background(), ruser.Id, "", "password")
|
|
require.Error(t, err)
|
|
|
|
_, _, err = th.Client.Login(context.Background(), ruser.Email, "hello1")
|
|
CheckErrorID(t, err, "api.user.login.remote_users.login.error")
|
|
})
|
|
|
|
t.Run("login with terms_of_service set", func(t *testing.T) {
|
|
termsOfService, appErr := th.App.CreateTermsOfService("terms of service", th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
_, err := th.Client.RegisterTermsOfServiceAction(context.Background(), th.BasicUser.Id, termsOfService.Id, true)
|
|
require.NoError(t, err)
|
|
|
|
userTermsOfService, _, err := th.Client.GetUserTermsOfService(context.Background(), th.BasicUser.Id, "")
|
|
require.NoError(t, err)
|
|
|
|
user, _, err := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, user.Id, th.BasicUser.Id)
|
|
assert.Equal(t, user.TermsOfServiceId, userTermsOfService.TermsOfServiceId)
|
|
assert.Equal(t, user.TermsOfServiceCreateAt, userTermsOfService.CreateAt)
|
|
})
|
|
}
|
|
|
|
func TestLoginCookies(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
t.Run("should return cookies with X-Requested-With header", func(t *testing.T) {
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.Client.HTTPHeader[model.HeaderRequestedWith] = model.HeaderRequestedWithXML
|
|
|
|
user, resp, _ := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
|
|
sessionCookie := ""
|
|
userCookie := ""
|
|
csrfCookie := ""
|
|
|
|
for _, cookie := range resp.Header["Set-Cookie"] {
|
|
if match := regexp.MustCompile("^" + model.SessionCookieToken + "=([a-z0-9]+)").FindStringSubmatch(cookie); match != nil {
|
|
sessionCookie = match[1]
|
|
} else if match := regexp.MustCompile("^" + model.SessionCookieUser + "=([a-z0-9]+)").FindStringSubmatch(cookie); match != nil {
|
|
userCookie = match[1]
|
|
} else if match := regexp.MustCompile("^" + model.SessionCookieCsrf + "=([a-z0-9]+)").FindStringSubmatch(cookie); match != nil {
|
|
csrfCookie = match[1]
|
|
}
|
|
}
|
|
|
|
session, _ := th.App.GetSession(th.Client.AuthToken)
|
|
|
|
assert.Equal(t, th.Client.AuthToken, sessionCookie)
|
|
assert.Equal(t, user.Id, userCookie)
|
|
assert.Equal(t, session.GetCSRF(), csrfCookie)
|
|
})
|
|
|
|
t.Run("should not return cookies without X-Requested-With header", func(t *testing.T) {
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
_, resp, _ := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
|
|
assert.Empty(t, resp.Header.Get("Set-Cookie"))
|
|
})
|
|
|
|
t.Run("should include subpath in path", func(t *testing.T) {
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.Client.HTTPHeader[model.HeaderRequestedWith] = model.HeaderRequestedWithXML
|
|
|
|
testCases := []struct {
|
|
Description string
|
|
SiteURL string
|
|
ExpectedSetCookieHeaderRegexp string
|
|
}{
|
|
{"no subpath", "http://localhost:8065", "^MMAUTHTOKEN=[a-z0-9]+; Path=/"},
|
|
{"subpath", "http://localhost:8065/subpath", "^MMAUTHTOKEN=[a-z0-9]+; Path=/subpath"},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.Description, func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.SiteURL = tc.SiteURL
|
|
})
|
|
|
|
user, resp, err := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, user.Id, th.BasicUser.Id)
|
|
|
|
cookies := resp.Header.Get("Set-Cookie")
|
|
assert.Regexp(t, tc.ExpectedSetCookieHeaderRegexp, cookies)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("should return cookie with MMCLOUDURL for cloud installations", func(t *testing.T) {
|
|
updateConfig := func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.SiteURL = "https://testchips.cloud.mattermost.com"
|
|
}
|
|
th := SetupAndApplyConfigBeforeLogin(t, updateConfig).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
|
|
|
|
th.Client.HTTPHeader[model.HeaderRequestedWith] = model.HeaderRequestedWithXML
|
|
_, resp, _ := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
|
|
found := false
|
|
cookies := resp.Header.Values("Set-Cookie")
|
|
for i := range cookies {
|
|
if strings.Contains(cookies[i], "MMCLOUDURL") {
|
|
found = true
|
|
assert.Contains(t, cookies[i], "MMCLOUDURL=testchips;", "should contain MMCLOUDURL")
|
|
assert.Contains(t, cookies[i], "Domain=mattermost.com;", "should contain Domain=mattermost.com")
|
|
break
|
|
}
|
|
}
|
|
assert.True(t, found, "Did not find MMCLOUDURL cookie")
|
|
})
|
|
|
|
t.Run("should return cookie with MMCLOUDURL for cloud installations when doing cws login", func(t *testing.T) {
|
|
token := model.NewRandomString(64)
|
|
os.Setenv("CWS_CLOUD_TOKEN", token)
|
|
|
|
updateConfig := func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.SiteURL = "https://testchips.cloud.mattermost.com"
|
|
}
|
|
th := SetupAndApplyConfigBeforeLogin(t, updateConfig).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
|
|
|
|
form := url.Values{}
|
|
form.Add("login_id", th.SystemAdminUser.Email)
|
|
form.Add("cws_token", token)
|
|
|
|
th.Client.HTTPClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
|
return http.ErrUseLastResponse
|
|
}
|
|
|
|
r, _ := th.Client.DoAPIRequestWithHeaders(context.Background(),
|
|
http.MethodPost,
|
|
"/users/login/cws",
|
|
form.Encode(),
|
|
map[string]string{
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
},
|
|
)
|
|
defer closeBody(r)
|
|
|
|
cookies := r.Cookies()
|
|
found := false
|
|
for i := range cookies {
|
|
if cookies[i].Name == model.SessionCookieCloudUrl {
|
|
found = true
|
|
assert.Equal(t, "testchips", cookies[i].Value)
|
|
}
|
|
}
|
|
assert.True(t, found, "should have found cookie")
|
|
})
|
|
|
|
t.Run("should NOT return cookie with MMCLOUDURL for cloud installations without expected format of cloud URL", func(t *testing.T) {
|
|
updateConfig := func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.SiteURL = "https://testchips.com" // correct cloud URL would be https://testchips.cloud.mattermost.com
|
|
}
|
|
th := SetupAndApplyConfigBeforeLogin(t, updateConfig).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
|
|
|
|
_, resp, _ := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
|
|
cloudSessionCookie := ""
|
|
for _, cookie := range resp.Header["Set-Cookie"] {
|
|
if match := regexp.MustCompile("^" + model.SessionCookieCloudUrl + "=([a-z0-9]+)").FindStringSubmatch(cookie); match != nil {
|
|
cloudSessionCookie = match[1]
|
|
}
|
|
}
|
|
// no cookie set
|
|
assert.Equal(t, "", cloudSessionCookie)
|
|
})
|
|
|
|
t.Run("should NOT return cookie with MMCLOUDURL for NON cloud installations", func(t *testing.T) {
|
|
updateConfig := func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.SiteURL = "https://testchips.com"
|
|
}
|
|
th := SetupAndApplyConfigBeforeLogin(t, updateConfig).InitBasic(t)
|
|
|
|
_, resp, _ := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
|
|
cloudSessionCookie := ""
|
|
for _, cookie := range resp.Header["Set-Cookie"] {
|
|
if match := regexp.MustCompile("^" + model.SessionCookieCloudUrl + "=([a-z0-9]+)").FindStringSubmatch(cookie); match != nil {
|
|
cloudSessionCookie = match[1]
|
|
}
|
|
}
|
|
// no cookie set
|
|
assert.Equal(t, "", cloudSessionCookie)
|
|
})
|
|
}
|
|
|
|
func TestSwitchAccount(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GitLabSettings.Enable = true })
|
|
|
|
// setupUserAuth configures the test user's auth state and session.
|
|
// Pass empty string for authService to reset to email/password auth.
|
|
// If loggedIn is true, ensures the user has a valid session.
|
|
setupUserAuth := func(t *testing.T, authService string, loggedIn bool) {
|
|
t.Helper()
|
|
|
|
// Always start by resetting to email auth so we can login
|
|
_, err := th.App.Srv().Store().User().UpdateAuthData(th.BasicUser.Id, "", nil, "", true)
|
|
require.NoError(t, err)
|
|
|
|
user, appErr := th.App.GetUser(th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
appErr = th.App.UpdatePassword(th.Context, user, th.BasicUser.Password)
|
|
require.Nil(t, appErr)
|
|
|
|
if loggedIn {
|
|
// Login while user is still email auth
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
} else {
|
|
_, _ = th.Client.Logout(context.Background())
|
|
}
|
|
|
|
// Now change auth service if needed (session remains valid)
|
|
if authService != "" {
|
|
fakeAuthData := model.NewId()
|
|
_, err = th.App.Srv().Store().User().UpdateAuthData(th.BasicUser.Id, authService, &fakeAuthData, th.BasicUser.Email, true)
|
|
require.NoError(t, err)
|
|
}
|
|
}
|
|
|
|
t.Run("Email to GitLab switch returns OAuth link", func(t *testing.T) {
|
|
setupUserAuth(t, "", false)
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceEmail,
|
|
NewService: model.UserAuthServiceGitlab,
|
|
Email: th.BasicUser.Email,
|
|
Password: th.BasicUser.Password,
|
|
}
|
|
|
|
link, _, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, link, "expected OAuth link")
|
|
})
|
|
|
|
t.Run("Auth transfer disabled", func(t *testing.T) {
|
|
th.App.Srv().SetLicense(model.NewTestLicense())
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ExperimentalEnableAuthenticationTransfer = false })
|
|
t.Cleanup(func() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ExperimentalEnableAuthenticationTransfer = true })
|
|
})
|
|
|
|
t.Run("Email to GitLab forbidden", func(t *testing.T) {
|
|
setupUserAuth(t, "", false)
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceEmail,
|
|
NewService: model.UserAuthServiceGitlab,
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("SAML to Email forbidden", func(t *testing.T) {
|
|
setupUserAuth(t, "", true)
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceSaml,
|
|
NewService: model.UserAuthServiceEmail,
|
|
Email: th.BasicUser.Email,
|
|
NewPassword: th.BasicUser.Password,
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Email to LDAP forbidden", func(t *testing.T) {
|
|
setupUserAuth(t, "", true)
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceEmail,
|
|
NewService: model.UserAuthServiceLdap,
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("LDAP to Email forbidden", func(t *testing.T) {
|
|
setupUserAuth(t, "", true)
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceLdap,
|
|
NewService: model.UserAuthServiceEmail,
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
})
|
|
|
|
t.Run("OAuth to Email", func(t *testing.T) {
|
|
t.Run("Email user cannot switch claiming OAuth auth", func(t *testing.T) {
|
|
// MM-67202: Verify that an email/password user cannot bypass password confirmation
|
|
setupUserAuth(t, "", true)
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceGitlab,
|
|
NewService: model.UserAuthServiceEmail,
|
|
Email: th.BasicUser.Email,
|
|
NewPassword: "NewPassword123!",
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
assert.Equal(t, "api.user.oauth_to_email.not_oauth_user.app_error", err.(*model.AppError).Id)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("GitLab user can switch to email", func(t *testing.T) {
|
|
setupUserAuth(t, model.UserAuthServiceGitlab, true)
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceGitlab,
|
|
NewService: model.UserAuthServiceEmail,
|
|
Email: th.BasicUser.Email,
|
|
NewPassword: th.BasicUser.Password,
|
|
}
|
|
|
|
link, _, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "/login?extra=signin_change", link)
|
|
})
|
|
|
|
t.Run("Disabled if EnableSignUpWithEmail is false", func(t *testing.T) {
|
|
setupUserAuth(t, model.UserAuthServiceGitlab, true)
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.EmailSettings.EnableSignUpWithEmail = false })
|
|
t.Cleanup(func() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.EmailSettings.EnableSignUpWithEmail = true })
|
|
})
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceGitlab,
|
|
NewService: model.UserAuthServiceEmail,
|
|
Email: th.BasicUser.Email,
|
|
NewPassword: th.BasicUser.Password,
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
assert.Equal(t, "api.user.auth_switch.not_available.email_signup_disabled.app_error", err.(*model.AppError).Id)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Disabled if EnableSignInWithEmail and EnableSignInWithUsername are false", func(t *testing.T) {
|
|
setupUserAuth(t, model.UserAuthServiceGitlab, true)
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.EmailSettings.EnableSignInWithEmail = false
|
|
*cfg.EmailSettings.EnableSignInWithUsername = false
|
|
})
|
|
t.Cleanup(func() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.EmailSettings.EnableSignInWithEmail = true
|
|
*cfg.EmailSettings.EnableSignInWithUsername = true
|
|
})
|
|
})
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceGitlab,
|
|
NewService: model.UserAuthServiceEmail,
|
|
Email: th.BasicUser.Email,
|
|
NewPassword: th.BasicUser.Password,
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
assert.Equal(t, "api.user.auth_switch.not_available.login_disabled.app_error", err.(*model.AppError).Id)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Without session returns unauthorized", func(t *testing.T) {
|
|
setupUserAuth(t, model.UserAuthServiceGitlab, false)
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceGitlab,
|
|
NewService: model.UserAuthServiceEmail,
|
|
Email: th.BasicUser.Email,
|
|
NewPassword: th.BasicUser.Password,
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
})
|
|
|
|
t.Run("LDAP to Email", func(t *testing.T) {
|
|
t.Run("Non-LDAP user cannot switch claiming LDAP auth", func(t *testing.T) {
|
|
// MM-67202: Verify that a non-LDAP user cannot bypass password confirmation
|
|
setupUserAuth(t, model.ServiceOpenid, true)
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceLdap,
|
|
NewService: model.UserAuthServiceEmail,
|
|
Email: th.BasicUser.Email,
|
|
NewPassword: th.BasicUser.Password,
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
assert.Equal(t, "api.user.ldap_to_email.not_ldap_account.app_error", err.(*model.AppError).Id)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Disabled if EnableSignUpWithEmail is false", func(t *testing.T) {
|
|
setupUserAuth(t, model.UserAuthServiceLdap, true)
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.EmailSettings.EnableSignUpWithEmail = false })
|
|
t.Cleanup(func() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.EmailSettings.EnableSignUpWithEmail = true })
|
|
})
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceLdap,
|
|
NewService: model.UserAuthServiceEmail,
|
|
Email: th.BasicUser.Email,
|
|
NewPassword: th.BasicUser.Password,
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
assert.Equal(t, "api.user.auth_switch.not_available.email_signup_disabled.app_error", err.(*model.AppError).Id)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Disabled if EnableSignInWithEmail and EnableSignInWithUsername are false", func(t *testing.T) {
|
|
setupUserAuth(t, model.UserAuthServiceLdap, true)
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.EmailSettings.EnableSignInWithEmail = false
|
|
*cfg.EmailSettings.EnableSignInWithUsername = false
|
|
})
|
|
t.Cleanup(func() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.EmailSettings.EnableSignInWithEmail = true
|
|
*cfg.EmailSettings.EnableSignInWithUsername = true
|
|
})
|
|
})
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceLdap,
|
|
NewService: model.UserAuthServiceEmail,
|
|
Email: th.BasicUser.Email,
|
|
NewPassword: th.BasicUser.Password,
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
assert.Equal(t, "api.user.auth_switch.not_available.login_disabled.app_error", err.(*model.AppError).Id)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
})
|
|
|
|
t.Run("OAuth to OAuth switch is invalid", func(t *testing.T) {
|
|
setupUserAuth(t, model.UserAuthServiceGitlab, true)
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceGitlab,
|
|
NewService: model.ServiceGoogle,
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Email to OAuth without email returns not found", func(t *testing.T) {
|
|
setupUserAuth(t, "", true)
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceEmail,
|
|
NewService: model.UserAuthServiceGitlab,
|
|
Password: th.BasicUser.Password,
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Email to OAuth without password returns unauthorized", func(t *testing.T) {
|
|
setupUserAuth(t, "", true)
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceEmail,
|
|
NewService: model.UserAuthServiceGitlab,
|
|
Email: th.BasicUser.Email,
|
|
}
|
|
|
|
_, resp, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Email to SAML switch succeeds", func(t *testing.T) {
|
|
setupUserAuth(t, "", true)
|
|
|
|
sr := &model.SwitchRequest{
|
|
CurrentService: model.UserAuthServiceEmail,
|
|
NewService: model.UserAuthServiceSaml,
|
|
Email: th.BasicUser.Email,
|
|
Password: th.BasicUser.Password,
|
|
}
|
|
|
|
link, _, err := th.Client.SwitchAccountType(context.Background(), sr)
|
|
require.NoError(t, err)
|
|
|
|
values, parseErr := url.ParseQuery(link)
|
|
require.NoError(t, parseErr)
|
|
|
|
appToken, tokenErr := th.App.Srv().Store().Token().GetByToken(values.Get("email_token"))
|
|
require.NoError(t, tokenErr)
|
|
require.Equal(t, th.BasicUser.Email, appToken.Extra)
|
|
})
|
|
}
|
|
|
|
func assertToken(t *testing.T, th *TestHelper, token *model.UserAccessToken, expectedUserId string) {
|
|
t.Helper()
|
|
|
|
oldSessionToken := th.Client.AuthToken
|
|
defer func() { th.Client.AuthToken = oldSessionToken }()
|
|
|
|
th.Client.AuthToken = token.Token
|
|
ruser, _, err := th.Client.GetMe(context.Background(), "")
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, expectedUserId, ruser.Id, "returned wrong user")
|
|
}
|
|
|
|
func assertInvalidToken(t *testing.T, th *TestHelper, token *model.UserAccessToken) {
|
|
t.Helper()
|
|
|
|
oldSessionToken := th.Client.AuthToken
|
|
defer func() { th.Client.AuthToken = oldSessionToken }()
|
|
|
|
th.Client.AuthToken = token.Token
|
|
_, resp, err := th.Client.GetMe(context.Background(), "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
}
|
|
|
|
func TestCreateUserAccessToken(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
t.Run("create token without permission", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, resp, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("system admin and local mode can create access token", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
rtoken, _, err := client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token")
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, th.BasicUser.Id, rtoken.UserId, "wrong user id")
|
|
assert.NotEmpty(t, rtoken.Token, "token should not be empty")
|
|
assert.NotEmpty(t, rtoken.Id, "id should not be empty")
|
|
assert.Equal(t, "test token", rtoken.Description, "description did not match")
|
|
assert.True(t, rtoken.IsActive, "token should be active")
|
|
assertToken(t, th, rtoken, th.BasicUser.Id)
|
|
})
|
|
})
|
|
|
|
t.Run("create token for invalid user id", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
|
_, resp, err := client.CreateUserAccessToken(context.Background(), "notarealuserid", "test token")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
})
|
|
|
|
t.Run("create token with invalid value", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
|
_, resp, err := client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
})
|
|
|
|
t.Run("create token with user access tokens disabled", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = false })
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
|
_, resp, err := client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token")
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, resp)
|
|
})
|
|
})
|
|
|
|
t.Run("create user access token", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
rtoken, _, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token")
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, th.BasicUser.Id, rtoken.UserId, "wrong user id")
|
|
assert.NotEmpty(t, rtoken.Token, "token should not be empty")
|
|
assert.NotEmpty(t, rtoken.Id, "id should not be empty")
|
|
assert.Equal(t, "test token", rtoken.Description, "description did not match")
|
|
assert.True(t, rtoken.IsActive, "token should be active")
|
|
|
|
assertToken(t, th, rtoken, th.BasicUser.Id)
|
|
})
|
|
|
|
t.Run("create user access token as second user, without permission", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, resp, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser2.Id, "test token")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("create user access token for another user, with permission", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
th.AddPermissionToRole(t, model.PermissionEditOtherUsers.Id, model.SystemUserManagerRoleId)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserManagerRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
rtoken, _, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser2.Id, "test token")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, th.BasicUser2.Id, rtoken.UserId)
|
|
|
|
oldSessionToken := th.Client.AuthToken
|
|
defer func() { th.Client.AuthToken = oldSessionToken }()
|
|
|
|
assertToken(t, th, rtoken, th.BasicUser2.Id)
|
|
})
|
|
|
|
t.Run("create user access token for system admin, as system user manager", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
th.AddPermissionToRole(t, model.PermissionEditOtherUsers.Id, model.SystemUserManagerRoleId)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserManagerRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
_, resp, err := th.Client.CreateUserAccessToken(context.Background(), th.SystemAdminUser.Id, "test token")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("create user access token for basic user as a system admin", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
rtoken, _, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, th.BasicUser.Id, rtoken.UserId)
|
|
|
|
oldSessionToken := th.Client.AuthToken
|
|
defer func() { th.Client.AuthToken = oldSessionToken }()
|
|
|
|
assertToken(t, th, rtoken, th.BasicUser.Id)
|
|
})
|
|
|
|
t.Run("create user access token for remote user as a system admin", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
// make a remote user
|
|
remoteUser, appErr := th.App.CreateUser(request.TestContext(t), &model.User{
|
|
Username: "remoteuser",
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
Password: model.NewId(),
|
|
Email: "remoteuser@example.com",
|
|
})
|
|
require.Nil(t, appErr)
|
|
|
|
_, resp, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), remoteUser.Id, "test token")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp) // remote users are not allowed to have access tokens
|
|
})
|
|
|
|
t.Run("create access token as oauth session", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
session, _ := th.App.GetSession(th.Client.AuthToken)
|
|
session.IsOAuth = true
|
|
th.App.AddSessionToCache(session)
|
|
|
|
_, resp, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("create access token for bot created by user", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
defaultPerms := th.SaveDefaultRolePermissions(t)
|
|
defer th.RestoreDefaultRolePermissions(t, defaultPerms)
|
|
th.AddPermissionToRole(t, model.PermissionCreateBot.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionCreateUserAccessToken.Id, model.TeamUserRoleId)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.TeamUserRoleId, false)
|
|
require.Nil(t, appErr)
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
createdBot, resp, err := th.Client.CreateBot(context.Background(), &model.Bot{
|
|
Username: GenerateTestUsername(),
|
|
DisplayName: "a bot",
|
|
Description: "bot",
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
t.Run("without MANAGE_BOT permission", func(t *testing.T) {
|
|
th.RemovePermissionFromRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
|
|
_, resp, err = th.Client.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("with MANAGE_BOTS permission", func(t *testing.T) {
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
|
|
token, _, err := th.Client.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, createdBot.UserId, token.UserId)
|
|
assertToken(t, th, token, createdBot.UserId)
|
|
})
|
|
})
|
|
|
|
t.Run("create access token for bot created by another user, only having MANAGE_BOTS permission", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
defaultPerms := th.SaveDefaultRolePermissions(t)
|
|
defer th.RestoreDefaultRolePermissions(t, defaultPerms)
|
|
th.AddPermissionToRole(t, model.PermissionCreateBot.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionCreateUserAccessToken.Id, model.TeamUserRoleId)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.TeamUserRoleId, false)
|
|
require.Nil(t, appErr)
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
createdBot, resp, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{
|
|
Username: GenerateTestUsername(),
|
|
DisplayName: "a bot",
|
|
Description: "bot",
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
t.Run("only having MANAGE_BOTS permission", func(t *testing.T) {
|
|
_, resp, err = th.Client.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("with MANAGE_OTHERS_BOTS permission", func(t *testing.T) {
|
|
th.AddPermissionToRole(t, model.PermissionManageOthersBots.Id, model.TeamUserRoleId)
|
|
|
|
rtoken, _, err := th.Client.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, createdBot.UserId, rtoken.UserId)
|
|
|
|
assertToken(t, th, rtoken, createdBot.UserId)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestGetUserAccessToken(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
t.Run("get for invalid user id", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, resp, err := th.Client.GetUserAccessToken(context.Background(), "123")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("get for unknown user id", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, resp, err := th.Client.GetUserAccessToken(context.Background(), model.NewId())
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("get my token", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
token, _, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token")
|
|
require.NoError(t, err)
|
|
|
|
rtoken, _, err := th.Client.GetUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, th.BasicUser.Id, rtoken.UserId, "wrong user id")
|
|
assert.Empty(t, rtoken.Token, "token should be blank")
|
|
assert.NotEmpty(t, rtoken.Id, "id should not be empty")
|
|
assert.Equal(t, "test token", rtoken.Description, "description did not match")
|
|
})
|
|
|
|
t.Run("get user token as system admin", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
token, _, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token")
|
|
require.NoError(t, err)
|
|
|
|
rtoken, _, err := th.SystemAdminClient.GetUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, th.BasicUser.Id, rtoken.UserId, "wrong user id")
|
|
assert.Empty(t, rtoken.Token, "token should be blank")
|
|
assert.NotEmpty(t, rtoken.Id, "id should not be empty")
|
|
assert.Equal(t, "test token", rtoken.Description, "description did not match")
|
|
})
|
|
|
|
t.Run("get token for bot created by user", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
defaultPerms := th.SaveDefaultRolePermissions(t)
|
|
defer th.RestoreDefaultRolePermissions(t, defaultPerms)
|
|
th.AddPermissionToRole(t, model.PermissionCreateBot.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionCreateUserAccessToken.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionReadUserAccessToken.Id, model.TeamUserRoleId)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.TeamUserRoleId, false)
|
|
require.Nil(t, appErr)
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
createdBot, resp, err := th.Client.CreateBot(context.Background(), &model.Bot{
|
|
Username: GenerateTestUsername(),
|
|
DisplayName: "a bot",
|
|
Description: "bot",
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
token, _, err := th.Client.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
|
require.NoError(t, err)
|
|
|
|
t.Run("without MANAGE_BOTS permission", func(t *testing.T) {
|
|
th.RemovePermissionFromRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
|
|
_, resp, err := th.Client.GetUserAccessToken(context.Background(), token.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("with MANAGE_BOTS permission", func(t *testing.T) {
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
|
|
returnedToken, _, err := th.Client.GetUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
|
|
// Actual token won't be returned.
|
|
returnedToken.Token = token.Token
|
|
assert.Equal(t, token, returnedToken)
|
|
})
|
|
})
|
|
|
|
t.Run("get token for bot created by another user", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
defaultPerms := th.SaveDefaultRolePermissions(t)
|
|
defer th.RestoreDefaultRolePermissions(t, defaultPerms)
|
|
th.AddPermissionToRole(t, model.PermissionCreateBot.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionCreateUserAccessToken.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionReadUserAccessToken.Id, model.TeamUserRoleId)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.TeamUserRoleId, false)
|
|
require.Nil(t, appErr)
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
createdBot, resp, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{
|
|
Username: GenerateTestUsername(),
|
|
DisplayName: "a bot",
|
|
Description: "bot",
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
token, _, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
|
require.NoError(t, err)
|
|
|
|
t.Run("only having MANAGE_BOTS permission", func(t *testing.T) {
|
|
_, resp, err := th.Client.GetUserAccessToken(context.Background(), token.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("with MANAGE_OTHERS_BOTS permission", func(t *testing.T) {
|
|
th.AddPermissionToRole(t, model.PermissionManageOthersBots.Id, model.TeamUserRoleId)
|
|
|
|
returnedToken, _, err := th.Client.GetUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
|
|
// Actual token won't be returned.
|
|
returnedToken.Token = token.Token
|
|
assert.Equal(t, token, returnedToken)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestGetUserAccessTokensForUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
t.Run("multiple tokens, offset 0, limit 100", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
_, _, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token")
|
|
require.NoError(t, err)
|
|
|
|
_, _, err = th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token 2")
|
|
require.NoError(t, err)
|
|
|
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
|
rtokens, _, err := client.GetUserAccessTokensForUser(context.Background(), th.BasicUser.Id, 0, 100)
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, rtokens, 2, "should have 2 tokens")
|
|
for _, uat := range rtokens {
|
|
assert.Equal(t, th.BasicUser.Id, uat.UserId, "wrong user id")
|
|
}
|
|
})
|
|
})
|
|
|
|
t.Run("multiple tokens, offset 1, limit 1", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
_, _, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token")
|
|
require.NoError(t, err)
|
|
|
|
_, _, err = th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token 2")
|
|
require.NoError(t, err)
|
|
|
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
|
rtokens, _, err := client.GetUserAccessTokensForUser(context.Background(), th.BasicUser.Id, 1, 1)
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, rtokens, 1, "should have 1 tokens")
|
|
for _, uat := range rtokens {
|
|
assert.Equal(t, th.BasicUser.Id, uat.UserId, "wrong user id")
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestGetUserAccessTokens(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
t.Run("GetUserAccessTokens, not a system admin", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
_, resp, err := th.Client.GetUserAccessTokens(context.Background(), 0, 100)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("GetUserAccessTokens, as a system admin, page 1, perPage 1", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
_, _, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token 2")
|
|
require.NoError(t, err)
|
|
|
|
_, _, err = th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token 2")
|
|
require.NoError(t, err)
|
|
|
|
rtokens, _, err := th.SystemAdminClient.GetUserAccessTokens(context.Background(), 1, 1)
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, rtokens, 1, "should have 1 token")
|
|
})
|
|
|
|
t.Run("GetUserAccessTokens, as a system admin, page 0, perPage 2", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
_, _, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token 2")
|
|
require.NoError(t, err)
|
|
|
|
_, _, err = th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token 2")
|
|
require.NoError(t, err)
|
|
|
|
rtokens, _, err := th.SystemAdminClient.GetUserAccessTokens(context.Background(), 0, 2)
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, rtokens, 2, "should have 2 tokens")
|
|
})
|
|
}
|
|
|
|
func TestSearchUserAccessToken(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
testDescription := "test token"
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
token, _, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, testDescription)
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := th.Client.SearchUserAccessTokens(context.Background(), &model.UserAccessTokenSearch{Term: token.Id})
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
rtokens, _, err := th.SystemAdminClient.SearchUserAccessTokens(context.Background(), &model.UserAccessTokenSearch{Term: th.BasicUser.Id})
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, rtokens, 1, "should have 1 token")
|
|
|
|
rtokens, _, err = th.SystemAdminClient.SearchUserAccessTokens(context.Background(), &model.UserAccessTokenSearch{Term: token.Id})
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, rtokens, 1, "should have 1 token")
|
|
|
|
rtokens, _, err = th.SystemAdminClient.SearchUserAccessTokens(context.Background(), &model.UserAccessTokenSearch{Term: th.BasicUser.Username})
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, rtokens, 1, "should have 1 token")
|
|
|
|
rtokens, _, err = th.SystemAdminClient.SearchUserAccessTokens(context.Background(), &model.UserAccessTokenSearch{Term: "not found"})
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, rtokens, "should have 1 tokens")
|
|
}
|
|
|
|
func TestRevokeUserAccessToken(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
t.Run("revoke user token", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
|
token, _, err := client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token")
|
|
require.NoError(t, err)
|
|
assertToken(t, th, token, th.BasicUser.Id)
|
|
|
|
_, err = client.RevokeUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
|
|
assertInvalidToken(t, th, token)
|
|
})
|
|
})
|
|
|
|
t.Run("revoke token belonging to another user", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
token, _, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), th.BasicUser2.Id, "test token")
|
|
require.NoError(t, err)
|
|
|
|
resp, err := th.Client.RevokeUserAccessToken(context.Background(), token.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("revoke token for bot created by user", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
defaultPerms := th.SaveDefaultRolePermissions(t)
|
|
defer th.RestoreDefaultRolePermissions(t, defaultPerms)
|
|
th.AddPermissionToRole(t, model.PermissionCreateBot.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionCreateUserAccessToken.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionRevokeUserAccessToken.Id, model.TeamUserRoleId)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.TeamUserRoleId, false)
|
|
require.Nil(t, appErr)
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
createdBot, resp, err := th.Client.CreateBot(context.Background(), &model.Bot{
|
|
Username: GenerateTestUsername(),
|
|
DisplayName: "a bot",
|
|
Description: "bot",
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
token, _, err := th.Client.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
|
require.NoError(t, err)
|
|
|
|
t.Run("without MANAGE_BOTS permission", func(t *testing.T) {
|
|
th.RemovePermissionFromRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
|
|
resp, err := th.Client.RevokeUserAccessToken(context.Background(), token.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("with MANAGE_BOTS permission", func(t *testing.T) {
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
|
|
_, err := th.Client.RevokeUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
})
|
|
})
|
|
|
|
t.Run("revoke token for bot created by another user", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
defaultPerms := th.SaveDefaultRolePermissions(t)
|
|
defer th.RestoreDefaultRolePermissions(t, defaultPerms)
|
|
th.AddPermissionToRole(t, model.PermissionCreateBot.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionCreateUserAccessToken.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionRevokeUserAccessToken.Id, model.TeamUserRoleId)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.TeamUserRoleId, false)
|
|
require.Nil(t, appErr)
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
createdBot, resp, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{
|
|
Username: GenerateTestUsername(),
|
|
DisplayName: "a bot",
|
|
Description: "bot",
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
token, _, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
|
require.NoError(t, err)
|
|
|
|
t.Run("only having MANAGE_BOTS permission", func(t *testing.T) {
|
|
resp, err = th.Client.RevokeUserAccessToken(context.Background(), token.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("with MANAGE_OTHERS_BOTS permission", func(t *testing.T) {
|
|
th.AddPermissionToRole(t, model.PermissionManageOthersBots.Id, model.TeamUserRoleId)
|
|
|
|
_, err := th.Client.RevokeUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestDisableUserAccessToken(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
t.Run("disable user token", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
token, _, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token")
|
|
require.NoError(t, err)
|
|
assertToken(t, th, token, th.BasicUser.Id)
|
|
|
|
_, err = th.Client.DisableUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
|
|
assertInvalidToken(t, th, token)
|
|
})
|
|
|
|
t.Run("disable token belonging to another user", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
token, _, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), th.BasicUser2.Id, "test token")
|
|
require.NoError(t, err)
|
|
|
|
resp, err := th.Client.DisableUserAccessToken(context.Background(), token.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("disable token for bot created by user", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
defaultPerms := th.SaveDefaultRolePermissions(t)
|
|
defer th.RestoreDefaultRolePermissions(t, defaultPerms)
|
|
th.AddPermissionToRole(t, model.PermissionCreateBot.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionCreateUserAccessToken.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionRevokeUserAccessToken.Id, model.TeamUserRoleId)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.TeamUserRoleId, false)
|
|
require.Nil(t, appErr)
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
createdBot, resp, err := th.Client.CreateBot(context.Background(), &model.Bot{
|
|
Username: GenerateTestUsername(),
|
|
DisplayName: "a bot",
|
|
Description: "bot",
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
token, _, err := th.Client.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
|
require.NoError(t, err)
|
|
|
|
t.Run("without MANAGE_BOTS permission", func(t *testing.T) {
|
|
th.RemovePermissionFromRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
|
|
resp, err := th.Client.DisableUserAccessToken(context.Background(), token.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("with MANAGE_BOTS permission", func(t *testing.T) {
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
|
|
_, err := th.Client.DisableUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
})
|
|
})
|
|
|
|
t.Run("disable token for bot created by another user", func(t *testing.T) {
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
defaultPerms := th.SaveDefaultRolePermissions(t)
|
|
defer th.RestoreDefaultRolePermissions(t, defaultPerms)
|
|
th.AddPermissionToRole(t, model.PermissionCreateBot.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionCreateUserAccessToken.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionRevokeUserAccessToken.Id, model.TeamUserRoleId)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.TeamUserRoleId, false)
|
|
require.Nil(t, appErr)
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
createdBot, resp, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{
|
|
Username: GenerateTestUsername(),
|
|
DisplayName: "a bot",
|
|
Description: "bot",
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
token, _, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
|
require.NoError(t, err)
|
|
|
|
t.Run("only having MANAGE_BOTS permission", func(t *testing.T) {
|
|
resp, err = th.Client.DisableUserAccessToken(context.Background(), token.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("with MANAGE_OTHERS_BOTS permission", func(t *testing.T) {
|
|
th.AddPermissionToRole(t, model.PermissionManageOthersBots.Id, model.TeamUserRoleId)
|
|
|
|
_, err := th.Client.DisableUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestEnableUserAccessToken(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
t.Run("enable user token", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
token, _, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, "test token")
|
|
require.NoError(t, err)
|
|
assertToken(t, th, token, th.BasicUser.Id)
|
|
|
|
_, err = th.Client.DisableUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
|
|
assertInvalidToken(t, th, token)
|
|
|
|
_, err = th.Client.EnableUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
|
|
assertToken(t, th, token, th.BasicUser.Id)
|
|
})
|
|
|
|
t.Run("enable token belonging to another user", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
token, _, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), th.BasicUser2.Id, "test token")
|
|
require.NoError(t, err)
|
|
|
|
_, err = th.SystemAdminClient.DisableUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
|
|
resp, err := th.Client.DisableUserAccessToken(context.Background(), token.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("enable token for bot created by user", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
defaultPerms := th.SaveDefaultRolePermissions(t)
|
|
defer th.RestoreDefaultRolePermissions(t, defaultPerms)
|
|
th.AddPermissionToRole(t, model.PermissionCreateBot.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionCreateUserAccessToken.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionRevokeUserAccessToken.Id, model.TeamUserRoleId)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.TeamUserRoleId, false)
|
|
require.Nil(t, appErr)
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
createdBot, resp, err := th.Client.CreateBot(context.Background(), &model.Bot{
|
|
Username: GenerateTestUsername(),
|
|
DisplayName: "a bot",
|
|
Description: "bot",
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
token, _, err := th.Client.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
|
require.NoError(t, err)
|
|
|
|
_, err = th.Client.DisableUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("without MANAGE_BOTS permission", func(t *testing.T) {
|
|
th.RemovePermissionFromRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
|
|
resp, err2 := th.Client.EnableUserAccessToken(context.Background(), token.Id)
|
|
require.Error(t, err2)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("with MANAGE_BOTS permission", func(t *testing.T) {
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
|
|
_, err = th.Client.EnableUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
})
|
|
})
|
|
|
|
t.Run("enable token for bot created by another user", func(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
defaultPerms := th.SaveDefaultRolePermissions(t)
|
|
defer th.RestoreDefaultRolePermissions(t, defaultPerms)
|
|
th.AddPermissionToRole(t, model.PermissionCreateBot.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionManageBots.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionCreateUserAccessToken.Id, model.TeamUserRoleId)
|
|
th.AddPermissionToRole(t, model.PermissionRevokeUserAccessToken.Id, model.TeamUserRoleId)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.TeamUserRoleId, false)
|
|
require.Nil(t, appErr)
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableBotAccountCreation = true
|
|
})
|
|
|
|
createdBot, resp, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{
|
|
Username: GenerateTestUsername(),
|
|
DisplayName: "a bot",
|
|
Description: "bot",
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
token, _, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
|
require.NoError(t, err)
|
|
|
|
_, err = th.SystemAdminClient.DisableUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("only having MANAGE_BOTS permission", func(t *testing.T) {
|
|
resp, err2 := th.Client.EnableUserAccessToken(context.Background(), token.Id)
|
|
require.Error(t, err2)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("with MANAGE_OTHERS_BOTS permission", func(t *testing.T) {
|
|
th.AddPermissionToRole(t, model.PermissionManageOthersBots.Id, model.TeamUserRoleId)
|
|
|
|
_, err = th.Client.EnableUserAccessToken(context.Background(), token.Id)
|
|
require.NoError(t, err)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestUserAccessTokenInactiveUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
testDescription := "test token"
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
token, _, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, testDescription)
|
|
require.NoError(t, err)
|
|
|
|
th.Client.AuthToken = token.Token
|
|
_, _, err = th.Client.GetMe(context.Background(), "")
|
|
require.NoError(t, err)
|
|
|
|
_, appErr = th.App.UpdateActive(th.Context, th.BasicUser, false)
|
|
require.Nil(t, appErr)
|
|
|
|
_, resp, err := th.Client.GetMe(context.Background(), "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
}
|
|
|
|
func TestUserAccessTokenDisableConfig(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
testDescription := "test token"
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = true })
|
|
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.SystemUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
|
require.Nil(t, appErr)
|
|
token, _, err := th.Client.CreateUserAccessToken(context.Background(), th.BasicUser.Id, testDescription)
|
|
require.NoError(t, err)
|
|
|
|
oldSessionToken := th.Client.AuthToken
|
|
th.Client.AuthToken = token.Token
|
|
_, _, err = th.Client.GetMe(context.Background(), "")
|
|
require.NoError(t, err)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableUserAccessTokens = false })
|
|
|
|
_, resp, err := th.Client.GetMe(context.Background(), "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
|
|
th.Client.AuthToken = oldSessionToken
|
|
_, _, err = th.Client.GetMe(context.Background(), "")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestUserAccessTokenDisableConfigBotsExcluded(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableBotAccountCreation = true
|
|
*cfg.ServiceSettings.EnableUserAccessTokens = false
|
|
})
|
|
|
|
bot, resp, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{
|
|
Username: GenerateTestUsername(),
|
|
DisplayName: "a bot",
|
|
Description: "bot",
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
rtoken, _, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), bot.UserId, "test token")
|
|
th.Client.AuthToken = rtoken.Token
|
|
require.NoError(t, err)
|
|
|
|
_, _, err = th.Client.GetMe(context.Background(), "")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetUsersByStatus(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t)
|
|
|
|
team, appErr := th.App.CreateTeam(th.Context, &model.Team{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: GenerateTestTeamName(),
|
|
Email: th.GenerateTestEmail(),
|
|
Type: model.TeamOpen,
|
|
})
|
|
|
|
require.Nil(t, appErr, "failed to create team")
|
|
|
|
channel, appErr := th.App.CreateChannel(th.Context, &model.Channel{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: "name_" + model.NewId(),
|
|
Type: model.ChannelTypeOpen,
|
|
TeamId: team.Id,
|
|
CreatorId: model.NewId(),
|
|
}, false)
|
|
require.Nil(t, appErr, "failed to create channel")
|
|
|
|
createUserWithStatus := func(username string, status string) *model.User {
|
|
id := model.NewId()
|
|
|
|
user, err := th.App.CreateUser(th.Context, &model.User{
|
|
Email: "success+" + id + "@simulator.amazonses.com",
|
|
Username: "un_" + username + "_" + id,
|
|
Nickname: "nn_" + id,
|
|
Password: "Password1",
|
|
})
|
|
require.Nil(t, err, "failed to create user")
|
|
|
|
th.LinkUserToTeam(t, user, team)
|
|
th.AddUserToChannel(t, user, channel)
|
|
|
|
th.App.Srv().Platform().SaveAndBroadcastStatus(&model.Status{
|
|
UserId: user.Id,
|
|
Status: status,
|
|
Manual: true,
|
|
})
|
|
|
|
return user
|
|
}
|
|
|
|
// Creating these out of order in case that affects results
|
|
offlineUser1 := createUserWithStatus("offline1", model.StatusOffline)
|
|
offlineUser2 := createUserWithStatus("offline2", model.StatusOffline)
|
|
awayUser1 := createUserWithStatus("away1", model.StatusAway)
|
|
awayUser2 := createUserWithStatus("away2", model.StatusAway)
|
|
onlineUser1 := createUserWithStatus("online1", model.StatusOnline)
|
|
onlineUser2 := createUserWithStatus("online2", model.StatusOnline)
|
|
dndUser1 := createUserWithStatus("dnd1", model.StatusDnd)
|
|
dndUser2 := createUserWithStatus("dnd2", model.StatusDnd)
|
|
|
|
client := th.CreateClient()
|
|
_, _, err := client.Login(context.Background(), onlineUser2.Username, "Password1")
|
|
require.NoError(t, err)
|
|
|
|
t.Run("sorting by status then alphabetical", func(t *testing.T) {
|
|
usersByStatus, _, err := client.GetUsersInChannelByStatus(context.Background(), channel.Id, 0, 8, "")
|
|
require.NoError(t, err)
|
|
|
|
expectedUsersByStatus := []*model.User{
|
|
onlineUser1,
|
|
onlineUser2,
|
|
awayUser1,
|
|
awayUser2,
|
|
dndUser1,
|
|
dndUser2,
|
|
offlineUser1,
|
|
offlineUser2,
|
|
}
|
|
require.Equal(t, len(expectedUsersByStatus), len(usersByStatus))
|
|
|
|
for i := range usersByStatus {
|
|
require.Equal(t, expectedUsersByStatus[i].Id, usersByStatus[i].Id)
|
|
}
|
|
})
|
|
|
|
t.Run("paging", func(t *testing.T) {
|
|
usersByStatus, _, err := client.GetUsersInChannelByStatus(context.Background(), channel.Id, 0, 3, "")
|
|
require.NoError(t, err)
|
|
require.Len(t, usersByStatus, 3)
|
|
require.Equal(t, onlineUser1.Id, usersByStatus[0].Id, "online users first")
|
|
require.Equal(t, onlineUser2.Id, usersByStatus[1].Id, "online users first")
|
|
require.Equal(t, awayUser1.Id, usersByStatus[2].Id, "expected to receive away users second")
|
|
|
|
usersByStatus, _, err = client.GetUsersInChannelByStatus(context.Background(), channel.Id, 1, 3, "")
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, awayUser2.Id, usersByStatus[0].Id, "expected to receive away users second")
|
|
require.Equal(t, dndUser1.Id, usersByStatus[1].Id, "expected to receive dnd users third")
|
|
require.Equal(t, dndUser2.Id, usersByStatus[2].Id, "expected to receive dnd users third")
|
|
|
|
usersByStatus, _, err = client.GetUsersInChannelByStatus(context.Background(), channel.Id, 1, 4, "")
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, usersByStatus, 4)
|
|
require.Equal(t, dndUser1.Id, usersByStatus[0].Id, "expected to receive dnd users third")
|
|
require.Equal(t, dndUser2.Id, usersByStatus[1].Id, "expected to receive dnd users third")
|
|
|
|
require.Equal(t, offlineUser1.Id, usersByStatus[2].Id, "expected to receive offline users last")
|
|
require.Equal(t, offlineUser2.Id, usersByStatus[3].Id, "expected to receive offline users last")
|
|
})
|
|
}
|
|
|
|
func TestRegisterTermsOfServiceAction(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
_, err := th.Client.RegisterTermsOfServiceAction(context.Background(), th.BasicUser.Id, "st_1", true)
|
|
CheckErrorID(t, err, "app.terms_of_service.get.no_rows.app_error")
|
|
|
|
termsOfService, appErr := th.App.CreateTermsOfService("terms of service", th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
_, err = th.Client.RegisterTermsOfServiceAction(context.Background(), th.BasicUser.Id, termsOfService.Id, true)
|
|
require.NoError(t, err)
|
|
|
|
_, appErr = th.App.GetUser(th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
}
|
|
|
|
func TestGetUserTermsOfService(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
_, _, err := th.Client.GetUserTermsOfService(context.Background(), th.BasicUser.Id, "")
|
|
CheckErrorID(t, err, "app.user_terms_of_service.get_by_user.no_rows.app_error")
|
|
|
|
termsOfService, appErr := th.App.CreateTermsOfService("terms of service", th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
_, err = th.Client.RegisterTermsOfServiceAction(context.Background(), th.BasicUser.Id, termsOfService.Id, true)
|
|
require.NoError(t, err)
|
|
|
|
userTermsOfService, _, err := th.Client.GetUserTermsOfService(context.Background(), th.BasicUser.Id, "")
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, th.BasicUser.Id, userTermsOfService.UserId)
|
|
assert.Equal(t, termsOfService.Id, userTermsOfService.TermsOfServiceId)
|
|
assert.NotEmpty(t, userTermsOfService.CreateAt)
|
|
}
|
|
|
|
func TestLoginErrorMessage(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
_, err := th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
// Email and Username enabled
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.EmailSettings.EnableSignInWithEmail = true
|
|
*cfg.EmailSettings.EnableSignInWithUsername = true
|
|
})
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, "wrong")
|
|
CheckErrorID(t, err, "api.user.login.invalid_credentials_email_username")
|
|
|
|
// Email enabled
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.EmailSettings.EnableSignInWithEmail = true
|
|
*cfg.EmailSettings.EnableSignInWithUsername = false
|
|
})
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, "wrong")
|
|
CheckErrorID(t, err, "api.user.login.invalid_credentials_email")
|
|
|
|
// Username enabled
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.EmailSettings.EnableSignInWithEmail = false
|
|
*cfg.EmailSettings.EnableSignInWithUsername = true
|
|
})
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, "wrong")
|
|
CheckErrorID(t, err, "api.user.login.invalid_credentials_username")
|
|
|
|
// SAML/SSO enabled
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.SamlSettings.Enable = true
|
|
*cfg.SamlSettings.Verify = false
|
|
*cfg.SamlSettings.Encrypt = false
|
|
*cfg.SamlSettings.IdpURL = "https://localhost/adfs/ls"
|
|
*cfg.SamlSettings.IdpDescriptorURL = "https://localhost/adfs/services/trust"
|
|
*cfg.SamlSettings.IdpMetadataURL = "https://localhost/adfs/metadata"
|
|
*cfg.SamlSettings.ServiceProviderIdentifier = "https://localhost/login/sso/saml"
|
|
*cfg.SamlSettings.AssertionConsumerServiceURL = "https://localhost/login/sso/saml"
|
|
*cfg.SamlSettings.IdpCertificateFile = app.SamlIdpCertificateName
|
|
*cfg.SamlSettings.PrivateKeyFile = app.SamlPrivateKeyName
|
|
*cfg.SamlSettings.PublicCertificateFile = app.SamlPublicCertificateName
|
|
*cfg.SamlSettings.EmailAttribute = "Email"
|
|
*cfg.SamlSettings.UsernameAttribute = "Username"
|
|
*cfg.SamlSettings.FirstNameAttribute = "FirstName"
|
|
*cfg.SamlSettings.LastNameAttribute = "LastName"
|
|
*cfg.SamlSettings.NicknameAttribute = ""
|
|
*cfg.SamlSettings.PositionAttribute = ""
|
|
*cfg.SamlSettings.LocaleAttribute = ""
|
|
})
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, "wrong")
|
|
CheckErrorID(t, err, "api.user.login.invalid_credentials_sso")
|
|
}
|
|
|
|
func TestLoginLockout(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
_, err := th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.MaximumLoginAttempts = 3 })
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })
|
|
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, "wrong")
|
|
CheckErrorID(t, err, "api.user.login.invalid_credentials_email_username")
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, "wrong")
|
|
CheckErrorID(t, err, "api.user.login.invalid_credentials_email_username")
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, "wrong")
|
|
CheckErrorID(t, err, "api.user.login.invalid_credentials_email_username")
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, "wrong")
|
|
CheckErrorID(t, err, "api.user.check_user_login_attempts.too_many.app_error")
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, "wrong")
|
|
CheckErrorID(t, err, "api.user.check_user_login_attempts.too_many.app_error")
|
|
|
|
// Check if lock is active
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
CheckErrorID(t, err, "api.user.check_user_login_attempts.too_many.app_error")
|
|
|
|
// Fake user has MFA enabled
|
|
err = th.Server.Store().User().UpdateMfaActive(th.BasicUser2.Id, true)
|
|
require.NoError(t, err)
|
|
_, _, err = th.Client.LoginWithMFA(context.Background(), th.BasicUser2.Email, th.BasicUser2.Password, "000000")
|
|
CheckErrorID(t, err, "api.user.check_user_mfa.bad_code.app_error")
|
|
_, _, err = th.Client.LoginWithMFA(context.Background(), th.BasicUser2.Email, th.BasicUser2.Password, "000000")
|
|
CheckErrorID(t, err, "api.user.check_user_mfa.bad_code.app_error")
|
|
_, _, err = th.Client.LoginWithMFA(context.Background(), th.BasicUser2.Email, th.BasicUser2.Password, "000000")
|
|
CheckErrorID(t, err, "api.user.check_user_mfa.bad_code.app_error")
|
|
_, _, err = th.Client.LoginWithMFA(context.Background(), th.BasicUser2.Email, th.BasicUser2.Password, "000000")
|
|
CheckErrorID(t, err, "api.user.check_user_login_attempts.too_many.app_error")
|
|
_, _, err = th.Client.LoginWithMFA(context.Background(), th.BasicUser2.Email, th.BasicUser2.Password, "000000")
|
|
CheckErrorID(t, err, "api.user.check_user_login_attempts.too_many.app_error")
|
|
|
|
// Fake user has MFA disabled
|
|
err = th.Server.Store().User().UpdateMfaActive(th.BasicUser2.Id, false)
|
|
require.NoError(t, err)
|
|
|
|
// Check if lock is active
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser2.Email, th.BasicUser2.Password)
|
|
CheckErrorID(t, err, "api.user.check_user_login_attempts.too_many.app_error")
|
|
}
|
|
|
|
func TestDemoteUserToGuest(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
enableGuestAccounts := *th.App.Config().GuestAccountsSettings.Enable
|
|
defer func() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = enableGuestAccounts })
|
|
appErr := th.App.Srv().RemoveLicense()
|
|
require.Nil(t, appErr)
|
|
}()
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
|
|
th.App.Srv().SetLicense(model.NewTestLicense())
|
|
|
|
user := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
t.Run("Guest Account not available in license returns forbidden", func(t *testing.T) {
|
|
th.App.Srv().SetLicense(model.NewTestLicenseWithFalseDefaults("guest_accounts"))
|
|
|
|
res, err := th.SystemAdminClient.DoAPIPost(context.Background(), "/users/"+user2.Id+"/demote", "")
|
|
|
|
require.Equal(t, http.StatusForbidden, res.StatusCode)
|
|
require.True(t, strings.Contains(err.Error(), "Guest accounts are disabled"))
|
|
require.Error(t, err)
|
|
})
|
|
|
|
t.Run("Guest Account available in license returns OK", func(t *testing.T) {
|
|
th.App.Srv().SetLicense(model.NewTestLicense("guest_accounts"))
|
|
|
|
res, err := th.SystemAdminClient.DoAPIPost(context.Background(), "/users/"+user2.Id+"/demote", "")
|
|
|
|
require.Equal(t, http.StatusOK, res.StatusCode)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, c *model.Client4) {
|
|
_, _, err := c.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
|
|
_, err = c.DemoteUserToGuest(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
|
|
defer require.Nil(t, th.App.PromoteGuestToUser(th.Context, user, ""))
|
|
}, "demote a user to guest")
|
|
|
|
t.Run("websocket update user event", func(t *testing.T) {
|
|
webSocketClient := th.CreateConnectedWebSocketClient(t)
|
|
resp := <-webSocketClient.ResponseChannel
|
|
require.Equal(t, model.StatusOk, resp.Status)
|
|
|
|
adminWebSocketClient := th.CreateConnectedWebSocketClientWithClient(t, th.SystemAdminClient)
|
|
|
|
_, _, err := th.SystemAdminClient.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
_, err = th.SystemAdminClient.DemoteUserToGuest(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
_, err = th.SystemAdminClient.PromoteGuestToUser(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
assertExpectedWebsocketEvent(t, webSocketClient, model.WebsocketEventUserUpdated, func(event *model.WebSocketEvent) {
|
|
eventUser, ok := event.GetData()["user"].(*model.User)
|
|
require.True(t, ok, "expected user")
|
|
assert.Equal(t, "system_guest", eventUser.Roles)
|
|
})
|
|
assertExpectedWebsocketEvent(t, adminWebSocketClient, model.WebsocketEventUserUpdated, func(event *model.WebSocketEvent) {
|
|
eventUser, ok := event.GetData()["user"].(*model.User)
|
|
require.True(t, ok, "expected user")
|
|
assert.Equal(t, "system_guest", eventUser.Roles)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestPromoteGuestToUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
enableGuestAccounts := *th.App.Config().GuestAccountsSettings.Enable
|
|
defer func() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = enableGuestAccounts })
|
|
appErr := th.App.Srv().RemoveLicense()
|
|
require.Nil(t, appErr)
|
|
}()
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
|
|
th.App.Srv().SetLicense(model.NewTestLicense())
|
|
|
|
user := th.CreateGuestUser(t)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, c *model.Client4) {
|
|
_, _, err := c.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
|
|
_, err = c.PromoteGuestToUser(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
|
|
defer require.Nil(t, th.App.DemoteUserToGuest(th.Context, user))
|
|
}, "promote a guest to user")
|
|
|
|
t.Run("websocket update user event", func(t *testing.T) {
|
|
webSocketClient := th.CreateConnectedWebSocketClient(t)
|
|
|
|
resp := <-webSocketClient.ResponseChannel
|
|
require.Equal(t, model.StatusOk, resp.Status)
|
|
|
|
adminWebSocketClient := th.CreateConnectedWebSocketClientWithClient(t, th.SystemAdminClient)
|
|
|
|
_, _, err := th.SystemAdminClient.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
_, err = th.SystemAdminClient.PromoteGuestToUser(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
_, err = th.SystemAdminClient.DemoteUserToGuest(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
assertExpectedWebsocketEvent(t, webSocketClient, model.WebsocketEventUserUpdated, func(event *model.WebSocketEvent) {
|
|
eventUser, ok := event.GetData()["user"].(*model.User)
|
|
require.True(t, ok, "expected user")
|
|
assert.Equal(t, "system_user", eventUser.Roles)
|
|
})
|
|
assertExpectedWebsocketEvent(t, adminWebSocketClient, model.WebsocketEventUserUpdated, func(event *model.WebSocketEvent) {
|
|
eventUser, ok := event.GetData()["user"].(*model.User)
|
|
require.True(t, ok, "expected user")
|
|
assert.Equal(t, "system_user", eventUser.Roles)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestVerifyUserEmailWithoutToken(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
email := th.GenerateTestEmail()
|
|
user := model.User{Email: email, Nickname: "Darth Vader", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SystemUserRoleId}
|
|
ruser, _, _ := th.Client.CreateUser(context.Background(), &user)
|
|
|
|
vuser, _, err := client.VerifyUserEmailWithoutToken(context.Background(), ruser.Id)
|
|
require.NoError(t, err)
|
|
require.Equal(t, ruser.Id, vuser.Id)
|
|
}, "Should verify a new user")
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
// Enable MFA for this test
|
|
th.App.Srv().SetLicense(model.NewTestLicense("mfa"))
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })
|
|
|
|
email := th.GenerateTestEmail()
|
|
user := model.User{Email: email, Nickname: "Test User", Password: "password123", Username: GenerateTestUsername(), Roles: model.SystemUserRoleId}
|
|
ruser, _, _ := th.Client.CreateUser(context.Background(), &user)
|
|
|
|
// Set some NotifyProps to ensure we have data to verify is preserved
|
|
ruser.NotifyProps = map[string]string{
|
|
"email": "true",
|
|
"push": "mention",
|
|
"desktop": "mention",
|
|
"channel": "true",
|
|
}
|
|
_, appErr := th.App.UpdateUser(th.Context, ruser, false)
|
|
require.Nil(t, appErr)
|
|
|
|
// Set up MFA secret for the user
|
|
secret, appErr := th.App.GenerateMfaSecret(ruser.Id)
|
|
require.Nil(t, appErr)
|
|
err := th.Server.Store().User().UpdateMfaSecret(ruser.Id, secret.Secret)
|
|
require.NoError(t, err)
|
|
|
|
// Verify the user has a password hash and MFA secret in the database
|
|
dbUser, appErr := th.App.GetUser(ruser.Id)
|
|
require.Nil(t, appErr)
|
|
require.NotEmpty(t, dbUser.Password, "User should have a password hash in database")
|
|
require.NotEmpty(t, dbUser.MfaSecret, "User should have MFA secret in database")
|
|
|
|
// Call the API endpoint
|
|
vuser, _, err := client.VerifyUserEmailWithoutToken(context.Background(), ruser.Id)
|
|
require.NoError(t, err)
|
|
require.Equal(t, ruser.Id, vuser.Id)
|
|
|
|
// Verify sensitive fields are sanitized in the response
|
|
require.Empty(t, vuser.Password, "Password hash should be sanitized from response")
|
|
require.Empty(t, vuser.MfaSecret, "MFA secret should be sanitized from response")
|
|
|
|
// Verify admin-level fields like NotifyProps are preserved for system admin
|
|
require.NotEmpty(t, vuser.NotifyProps, "NotifyProps should be preserved for system admin")
|
|
require.Equal(t, "true", vuser.NotifyProps["email"], "NotifyProps data should be preserved for system admin")
|
|
}, "Should sanitize password hash and MFA secret from response")
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
vuser, _, err := client.VerifyUserEmailWithoutToken(context.Background(), "randomId")
|
|
require.Error(t, err)
|
|
CheckErrorID(t, err, "api.context.invalid_url_param.app_error")
|
|
require.Nil(t, vuser)
|
|
}, "Should not be able to find user")
|
|
|
|
t.Run("Should not be able to verify user due to permissions", func(t *testing.T) {
|
|
user := th.CreateUser(t)
|
|
vuser, _, err := th.Client.VerifyUserEmailWithoutToken(context.Background(), user.Id)
|
|
require.Error(t, err)
|
|
CheckErrorID(t, err, "api.context.permissions.app_error")
|
|
require.Nil(t, vuser)
|
|
})
|
|
}
|
|
|
|
func TestGetKnownUsers(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
t1, err := th.App.CreateTeam(th.Context, &model.Team{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: GenerateTestTeamName(),
|
|
Email: th.GenerateTestEmail(),
|
|
Type: model.TeamOpen,
|
|
})
|
|
require.Nil(t, err, "failed to create team")
|
|
|
|
t2, err := th.App.CreateTeam(th.Context, &model.Team{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: GenerateTestTeamName(),
|
|
Email: th.GenerateTestEmail(),
|
|
Type: model.TeamOpen,
|
|
})
|
|
require.Nil(t, err, "failed to create team")
|
|
|
|
t3, err := th.App.CreateTeam(th.Context, &model.Team{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: GenerateTestTeamName(),
|
|
Email: th.GenerateTestEmail(),
|
|
Type: model.TeamOpen,
|
|
})
|
|
require.Nil(t, err, "failed to create team")
|
|
|
|
c1, err := th.App.CreateChannel(th.Context, &model.Channel{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: "name_" + model.NewId(),
|
|
Type: model.ChannelTypeOpen,
|
|
TeamId: t1.Id,
|
|
CreatorId: model.NewId(),
|
|
}, false)
|
|
require.Nil(t, err, "failed to create channel")
|
|
|
|
c2, err := th.App.CreateChannel(th.Context, &model.Channel{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: "name_" + model.NewId(),
|
|
Type: model.ChannelTypeOpen,
|
|
TeamId: t2.Id,
|
|
CreatorId: model.NewId(),
|
|
}, false)
|
|
require.Nil(t, err, "failed to create channel")
|
|
|
|
c3, err := th.App.CreateChannel(th.Context, &model.Channel{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: "name_" + model.NewId(),
|
|
Type: model.ChannelTypeOpen,
|
|
TeamId: t3.Id,
|
|
CreatorId: model.NewId(),
|
|
}, false)
|
|
require.Nil(t, err, "failed to create channel")
|
|
|
|
u1 := th.CreateUser(t)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteUser(th.Context, u1)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
u2 := th.CreateUser(t)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteUser(th.Context, u2)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
u3 := th.CreateUser(t)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteUser(th.Context, u3)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
u4 := th.CreateUser(t)
|
|
defer func() {
|
|
appErr := th.App.PermanentDeleteUser(th.Context, u4)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
th.LinkUserToTeam(t, u1, t1)
|
|
th.LinkUserToTeam(t, u1, t2)
|
|
th.LinkUserToTeam(t, u2, t1)
|
|
th.LinkUserToTeam(t, u3, t2)
|
|
th.LinkUserToTeam(t, u4, t3)
|
|
|
|
_, appErr := th.App.AddUserToChannel(th.Context, u1, c1, false)
|
|
require.Nil(t, appErr)
|
|
_, appErr = th.App.AddUserToChannel(th.Context, u1, c2, false)
|
|
require.Nil(t, appErr)
|
|
_, appErr = th.App.AddUserToChannel(th.Context, u2, c1, false)
|
|
require.Nil(t, appErr)
|
|
_, appErr = th.App.AddUserToChannel(th.Context, u3, c2, false)
|
|
require.Nil(t, appErr)
|
|
_, appErr = th.App.AddUserToChannel(th.Context, u4, c3, false)
|
|
require.Nil(t, appErr)
|
|
|
|
t.Run("get know users sharing no channels", func(t *testing.T) {
|
|
_, _, _ = th.Client.Login(context.Background(), u4.Email, u4.Password)
|
|
userIds, _, err := th.Client.GetKnownUsers(context.Background())
|
|
require.NoError(t, err)
|
|
assert.Empty(t, userIds)
|
|
})
|
|
|
|
t.Run("get know users sharing one channel", func(t *testing.T) {
|
|
_, _, _ = th.Client.Login(context.Background(), u3.Email, u3.Password)
|
|
userIds, _, err := th.Client.GetKnownUsers(context.Background())
|
|
require.NoError(t, err)
|
|
assert.Len(t, userIds, 1)
|
|
assert.Equal(t, userIds[0], u1.Id)
|
|
})
|
|
|
|
t.Run("get know users sharing multiple channels", func(t *testing.T) {
|
|
_, _, _ = th.Client.Login(context.Background(), u1.Email, u1.Password)
|
|
userIds, _, err := th.Client.GetKnownUsers(context.Background())
|
|
require.NoError(t, err)
|
|
assert.Len(t, userIds, 2)
|
|
assert.ElementsMatch(t, userIds, []string{u2.Id, u3.Id})
|
|
})
|
|
}
|
|
|
|
func TestPublishUserTyping(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
tr := model.TypingRequest{
|
|
ChannelId: th.BasicChannel.Id,
|
|
ParentId: "randomparentid",
|
|
}
|
|
|
|
t.Run("should return ok for non-system admin when triggering typing event for own user", func(t *testing.T) {
|
|
_, err := th.Client.PublishUserTyping(context.Background(), th.BasicUser.Id, tr)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("should return ok for system admin when triggering typing event for own user", func(t *testing.T) {
|
|
th.LinkUserToTeam(t, th.SystemAdminUser, th.BasicTeam)
|
|
th.AddUserToChannel(t, th.SystemAdminUser, th.BasicChannel)
|
|
|
|
_, err := th.SystemAdminClient.PublishUserTyping(context.Background(), th.SystemAdminUser.Id, tr)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("should return forbidden for non-system admin when triggering a typing event for a different user", func(t *testing.T) {
|
|
resp, err := th.Client.PublishUserTyping(context.Background(), th.BasicUser2.Id, tr)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("should return bad request when triggering a typing event for an invalid user id", func(t *testing.T) {
|
|
resp, err := th.Client.PublishUserTyping(context.Background(), "invalid", tr)
|
|
require.Error(t, err)
|
|
CheckErrorID(t, err, "api.context.invalid_url_param.app_error")
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("should send typing event via websocket when triggering a typing event for a user with a common channel", func(t *testing.T) {
|
|
webSocketClient := th.CreateConnectedWebSocketClient(t)
|
|
|
|
wsResp := <-webSocketClient.ResponseChannel
|
|
require.Equal(t, model.StatusOk, wsResp.Status)
|
|
|
|
_, err := th.SystemAdminClient.PublishUserTyping(context.Background(), th.BasicUser2.Id, tr)
|
|
require.NoError(t, err)
|
|
|
|
assertExpectedWebsocketEvent(t, webSocketClient, model.WebsocketEventTyping, func(resp *model.WebSocketEvent) {
|
|
assert.Equal(t, th.BasicChannel.Id, resp.GetBroadcast().ChannelId)
|
|
|
|
eventUserId, ok := resp.GetData()["user_id"].(string)
|
|
require.True(t, ok, "expected user_id")
|
|
assert.Equal(t, th.BasicUser2.Id, eventUserId)
|
|
|
|
eventParentId, ok := resp.GetData()["parent_id"].(string)
|
|
require.True(t, ok, "expected parent_id")
|
|
assert.Equal(t, "randomparentid", eventParentId)
|
|
})
|
|
})
|
|
|
|
th.Server.Platform().Busy.Set(time.Second * 10)
|
|
|
|
t.Run("should return service unavailable for non-system admin user when triggering a typing event and server busy", func(t *testing.T) {
|
|
resp, err := th.Client.PublishUserTyping(context.Background(), "invalid", tr)
|
|
require.Error(t, err)
|
|
CheckErrorID(t, err, "api.context.server_busy.app_error")
|
|
CheckServiceUnavailableStatus(t, resp)
|
|
})
|
|
|
|
t.Run("should return service unavailable for system admin user when triggering a typing event and server busy", func(t *testing.T) {
|
|
resp, err := th.SystemAdminClient.PublishUserTyping(context.Background(), th.SystemAdminUser.Id, tr)
|
|
require.Error(t, err)
|
|
CheckErrorID(t, err, "api.context.server_busy.app_error")
|
|
CheckServiceUnavailableStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestConvertUserToBot(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
bot, resp, err := th.Client.ConvertUserToBot(context.Background(), th.BasicUser.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
require.Nil(t, bot)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
user := model.User{Email: th.GenerateTestEmail(), Username: GenerateTestUsername(), Password: "password"}
|
|
|
|
ruser, resp, err := client.CreateUser(context.Background(), &user)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
bot, _, err = client.ConvertUserToBot(context.Background(), ruser.Id)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, bot)
|
|
require.Equal(t, bot.UserId, ruser.Id)
|
|
|
|
bot, _, err = client.GetBot(context.Background(), bot.UserId, "")
|
|
require.NoError(t, err)
|
|
require.NotNil(t, bot)
|
|
})
|
|
|
|
t.Run("user cannot login after being converted to bot", func(t *testing.T) {
|
|
// Create a new user
|
|
user := th.CreateUser(t)
|
|
|
|
// Login as the new user to verify login works initially
|
|
_, _, err := th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
// Convert user to bot
|
|
_, _, err = th.SystemAdminClient.ConvertUserToBot(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
|
|
// Try to login again - should fail
|
|
_, resp, err := th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.Error(t, err)
|
|
CheckErrorID(t, err, "api.user.login.bot_login_forbidden.app_error")
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestGetChannelMembersWithTeamData(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
channels, resp, err := th.Client.GetChannelMembersWithTeamData(context.Background(), th.BasicUser.Id, 0, 5)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.Len(t, channels, 5)
|
|
for _, ch := range channels {
|
|
assert.Equal(t, th.BasicTeam.DisplayName, ch.TeamDisplayName)
|
|
}
|
|
|
|
channels, resp, err = th.Client.GetChannelMembersWithTeamData(context.Background(), th.BasicUser.Id, 0, 5000)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.Len(t, channels, 6)
|
|
for _, ch := range channels {
|
|
assert.Equal(t, th.BasicTeam.DisplayName, ch.TeamDisplayName)
|
|
}
|
|
|
|
// perPage doesn't matter if page=-1
|
|
channels, resp, err = th.Client.GetChannelMembersWithTeamData(context.Background(), th.BasicUser.Id, -1, 2)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.Equal(t, "application/x-ndjson", resp.Header.Get("Content-Type"))
|
|
assert.Len(t, channels, 6)
|
|
for _, ch := range channels {
|
|
assert.Equal(t, th.BasicTeam.DisplayName, ch.TeamDisplayName)
|
|
}
|
|
}
|
|
|
|
func TestMigrateAuthToLDAP(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
resp, err := th.Client.MigrateAuthToLdap(context.Background(), "email", "a", false)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
resp, err = client.MigrateAuthToLdap(context.Background(), "email", "a", false)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestMigrateAuthToSAML(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
resp, err := th.Client.MigrateAuthToSaml(context.Background(), "email", map[string]string{"1": "a"}, true)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
resp, err = client.MigrateAuthToSaml(context.Background(), "email", map[string]string{"1": "a"}, true)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestUpdatePassword(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
t.Run("Forbidden when request performed by system user on a system admin", func(t *testing.T) {
|
|
res, err := th.Client.UpdatePassword(context.Background(), th.SystemAdminUser.Id, "Pa$$word11", "foobar")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, res)
|
|
})
|
|
|
|
t.Run("OK when request performed by system user with requisite system permission, except if requested user is system admin", func(t *testing.T) {
|
|
th.AddPermissionToRole(t, model.PermissionSysconsoleWriteUserManagementUsers.Id, model.SystemUserRoleId)
|
|
defer th.RemovePermissionFromRole(t, model.PermissionSysconsoleWriteUserManagementUsers.Id, model.SystemUserRoleId)
|
|
|
|
res, _ := th.Client.UpdatePassword(context.Background(), th.TeamAdminUser.Id, "Pa$$word11", "foobar")
|
|
CheckOKStatus(t, res)
|
|
|
|
res, err := th.Client.UpdatePassword(context.Background(), th.SystemAdminUser.Id, "Pa$$word11", "foobar")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, res)
|
|
})
|
|
|
|
t.Run("OK when request performed by system admin, even if requested user is system admin", func(t *testing.T) {
|
|
res, _ := th.SystemAdminClient.UpdatePassword(context.Background(), th.SystemAdminUser.Id, "Pa$$word11", "foobar")
|
|
CheckOKStatus(t, res)
|
|
})
|
|
}
|
|
|
|
func TestUpdatePasswordAudit(t *testing.T) {
|
|
logFile, err := os.CreateTemp("", "adv.log")
|
|
require.NoError(t, err)
|
|
defer os.Remove(logFile.Name())
|
|
|
|
os.Setenv("MM_EXPERIMENTALAUDITSETTINGS_FILEENABLED", "true")
|
|
os.Setenv("MM_EXPERIMENTALAUDITSETTINGS_FILENAME", logFile.Name())
|
|
defer os.Unsetenv("MM_EXPERIMENTALAUDITSETTINGS_FILEENABLED")
|
|
defer os.Unsetenv("MM_EXPERIMENTALAUDITSETTINGS_FILENAME")
|
|
|
|
options := []app.Option{app.WithLicense(model.NewTestLicense("advanced_logging"))}
|
|
th := SetupWithServerOptions(t, options)
|
|
|
|
password := "this_is_the_password"
|
|
th.LoginBasic(t)
|
|
resp, err := th.Client.UpdatePassword(context.Background(), th.BasicUser.Id, th.BasicUser.Password, password)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
// Forcing a flush before attempting to read log's content.
|
|
err = th.Server.Audit.Flush()
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, logFile.Sync())
|
|
|
|
data, err := io.ReadAll(logFile)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, data)
|
|
|
|
require.Contains(t, string(data), th.BasicUser.Id)
|
|
require.NotContains(t, string(data), password)
|
|
}
|
|
|
|
func TestGetThreadsForUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.ThreadAutoFollow = true
|
|
*cfg.ServiceSettings.CollapsedThreads = model.CollapsedThreadsDefaultOn
|
|
})
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
|
|
|
t.Run("empty", func(t *testing.T) {
|
|
client := th.Client
|
|
|
|
_, resp, err := client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
defer func() {
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
uss, _, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 0)
|
|
})
|
|
|
|
t.Run("no params, 1 thread", func(t *testing.T) {
|
|
client := th.Client
|
|
|
|
rpost, resp, err := client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
_, resp, err = client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
defer func() {
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
uss, _, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 1)
|
|
require.Equal(t, uss.Threads[0].PostId, rpost.Id)
|
|
require.Equal(t, uss.Threads[0].ReplyCount, int64(1))
|
|
})
|
|
|
|
t.Run("extended, 1 thread", func(t *testing.T) {
|
|
client := th.Client
|
|
|
|
rpost, resp, err := client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
_, resp, err = client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
defer func() {
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
uss, _, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Extended: true,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 1)
|
|
require.Equal(t, uss.Threads[0].PostId, rpost.Id)
|
|
require.Equal(t, uss.Threads[0].ReplyCount, int64(1))
|
|
require.Equal(t, uss.Threads[0].Participants[0].Id, th.BasicUser.Id)
|
|
})
|
|
|
|
t.Run("deleted, 1 thread", func(t *testing.T) {
|
|
client := th.Client
|
|
|
|
rpost, resp, err := client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
_, resp, err = client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
defer func() {
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
uss, _, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 1)
|
|
require.Equal(t, uss.Threads[0].PostId, rpost.Id)
|
|
require.Equal(t, uss.Threads[0].ReplyCount, int64(1))
|
|
require.Equal(t, uss.Threads[0].Participants[0].Id, th.BasicUser.Id)
|
|
|
|
_, err = th.Client.DeletePost(context.Background(), rpost.Id)
|
|
require.NoError(t, err)
|
|
|
|
uss, _, err = th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 0)
|
|
|
|
uss, _, err = th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: true,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 1)
|
|
require.Greater(t, uss.Threads[0].Post.DeleteAt, int64(0))
|
|
})
|
|
|
|
t.Run("throw error when post-priority service-setting is off", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.PostPriority = false
|
|
})
|
|
|
|
client := th.Client
|
|
|
|
_, resp, err := client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "testMsg",
|
|
Metadata: &model.PostMetadata{
|
|
Priority: &model.PostPriority{
|
|
Priority: model.NewPointer(model.PostPriorityUrgent),
|
|
},
|
|
},
|
|
})
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("throw error when post-priority is set for a reply", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.PostPriority = true
|
|
})
|
|
|
|
client := th.Client
|
|
|
|
defer func() {
|
|
err := th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
rpost, resp, err := client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
_, resp, err = client.CreatePost(context.Background(), &model.Post{
|
|
RootId: rpost.Id,
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "testReply",
|
|
Metadata: &model.PostMetadata{
|
|
Priority: &model.PostPriority{
|
|
Priority: model.NewPointer(model.PostPriorityUrgent),
|
|
},
|
|
},
|
|
})
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("isUrgent, 1 thread", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.PostPriority = true
|
|
})
|
|
|
|
client := th.Client
|
|
|
|
rpost, resp, err := client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "testMsg",
|
|
Metadata: &model.PostMetadata{
|
|
Priority: &model.PostPriority{
|
|
Priority: model.NewPointer(model.PostPriorityUrgent),
|
|
},
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
_, resp, err = client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
defer func() {
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
uss, _, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 1)
|
|
require.Equal(t, true, uss.Threads[0].IsUrgent)
|
|
})
|
|
|
|
t.Run("paged, 30 threads", func(t *testing.T) {
|
|
client := th.Client
|
|
|
|
var rootIds []*model.Post
|
|
for range 30 {
|
|
rpost, resp, err := client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
rootIds = append(rootIds, rpost)
|
|
_, resp, err = client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
}
|
|
|
|
defer func() {
|
|
err := th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
uss, _, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
PageSize: 30,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 30)
|
|
require.Len(t, rootIds, 30)
|
|
require.Equal(t, uss.Threads[0].PostId, rootIds[29].Id)
|
|
require.Equal(t, uss.Threads[0].ReplyCount, int64(1))
|
|
require.Equal(t, uss.Threads[0].Participants[0].Id, th.BasicUser.Id)
|
|
})
|
|
|
|
t.Run("paged, 10 threads before/after", func(t *testing.T) {
|
|
client := th.Client
|
|
|
|
var rootIds []*model.Post
|
|
for i := range 30 {
|
|
rpost, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: fmt.Sprintf("testMsg-%d", i)})
|
|
rootIds = append(rootIds, rpost)
|
|
postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: fmt.Sprintf("testReply-%d", i), RootId: rpost.Id})
|
|
}
|
|
rootId := rootIds[15].Id // middle point
|
|
rootIdBefore := rootIds[14].Id
|
|
rootIdAfter := rootIds[16].Id
|
|
|
|
defer func() {
|
|
err := th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
uss, _, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
PageSize: 10,
|
|
Before: rootId,
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 10)
|
|
require.Equal(t, rootIdBefore, uss.Threads[0].PostId)
|
|
|
|
uss2, _, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
PageSize: 10,
|
|
After: rootId,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss2.Threads, 10)
|
|
|
|
require.Equal(t, rootIdAfter, uss2.Threads[0].PostId)
|
|
|
|
uss3, _, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
PageSize: 10,
|
|
After: rootId + "__bad",
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, uss3.Threads)
|
|
require.Len(t, uss3.Threads, 0)
|
|
})
|
|
|
|
t.Run("totalsOnly param", func(t *testing.T) {
|
|
client := th.Client
|
|
sysadminClient := th.SystemAdminClient
|
|
|
|
var rootIds []*model.Post
|
|
for i := range 10 {
|
|
rpost, resp, err := client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
rootIds = append(rootIds, rpost)
|
|
if i%2 == 0 {
|
|
_, resp, err = client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
|
} else {
|
|
_, resp, err = sysadminClient.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply @" + th.BasicUser.Username, RootId: rpost.Id})
|
|
}
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
}
|
|
|
|
defer func() {
|
|
err := th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.SystemAdminUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
uss, _, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
TotalsOnly: true,
|
|
PageSize: 30,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 0)
|
|
require.Len(t, rootIds, 10)
|
|
require.Equal(t, int64(10), uss.Total)
|
|
require.Equal(t, int64(5), uss.TotalUnreadThreads)
|
|
require.Equal(t, int64(5), uss.TotalUnreadMentions)
|
|
})
|
|
|
|
t.Run("threadsOnly param", func(t *testing.T) {
|
|
client := th.Client
|
|
sysadminClient := th.SystemAdminClient
|
|
|
|
var rootIds []*model.Post
|
|
for i := range 10 {
|
|
rpost, resp, err := client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
rootIds = append(rootIds, rpost)
|
|
if i%2 == 0 {
|
|
_, resp, err = client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
|
} else {
|
|
_, resp, err = sysadminClient.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply @" + th.BasicUser.Username, RootId: rpost.Id})
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
}
|
|
|
|
defer func() {
|
|
err := th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.SystemAdminUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
uss, _, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
ThreadsOnly: true,
|
|
PageSize: 30,
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
require.Len(t, rootIds, 10)
|
|
require.Len(t, uss.Threads, 10)
|
|
require.Equal(t, int64(0), uss.Total)
|
|
require.Equal(t, int64(0), uss.TotalUnreadThreads)
|
|
require.Equal(t, int64(0), uss.TotalUnreadMentions)
|
|
require.Equal(t, int64(1), uss.Threads[0].ReplyCount)
|
|
|
|
require.Equal(t, rootIds[9].Id, uss.Threads[0].PostId)
|
|
require.Equal(t, th.SystemAdminUser.Id, uss.Threads[0].Participants[0].Id)
|
|
require.Equal(t, th.BasicUser.Id, uss.Threads[1].Participants[0].Id)
|
|
})
|
|
|
|
t.Run("setting both threadsOnly, and totalsOnly params is not allowed", func(t *testing.T) {
|
|
defer func() {
|
|
err := th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
_, resp, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
ThreadsOnly: true,
|
|
TotalsOnly: true,
|
|
PageSize: 30,
|
|
})
|
|
|
|
require.Error(t, err)
|
|
checkHTTPStatus(t, resp, http.StatusBadRequest)
|
|
})
|
|
|
|
t.Run("editing or reacting to reply post does not make thread unread", func(t *testing.T) {
|
|
client := th.Client
|
|
|
|
rootPost, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "root post"})
|
|
replyPost, _ := postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel.Id, Message: "reply post", RootId: rootPost.Id})
|
|
uss, _, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, uss.TotalUnreadThreads, int64(1))
|
|
require.Equal(t, uss.Threads[0].PostId, rootPost.Id)
|
|
|
|
_, _, err = th.Client.UpdateThreadReadForUser(context.Background(), th.BasicUser.Id, th.BasicChannel.TeamId, rootPost.Id, model.GetMillis())
|
|
require.NoError(t, err)
|
|
uss, _, err = th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, uss.TotalUnreadThreads, int64(0))
|
|
|
|
// edit post
|
|
editedReplyPostMessage := "edited " + replyPost.Message
|
|
_, _, err = th.SystemAdminClient.PatchPost(context.Background(), replyPost.Id, &model.PostPatch{Message: &editedReplyPostMessage})
|
|
require.NoError(t, err)
|
|
uss, _, err = th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, uss.TotalUnreadThreads, int64(0))
|
|
|
|
// react to post
|
|
reaction := &model.Reaction{
|
|
UserId: th.SystemAdminUser.Id,
|
|
PostId: replyPost.Id,
|
|
EmojiName: "smile",
|
|
}
|
|
_, _, err = th.SystemAdminClient.SaveReaction(context.Background(), reaction)
|
|
require.NoError(t, err)
|
|
uss, _, err = th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, uss.TotalUnreadThreads, int64(0))
|
|
})
|
|
|
|
t.Run("Since should return threads with new replies and updated memberships", func(t *testing.T) {
|
|
client := th.Client
|
|
|
|
// Create "thread 1"
|
|
rootPost1, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "Thread 1"})
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel.Id, Message: "Thread 1, reply 1", RootId: rootPost1.Id})
|
|
uss, _, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Since: uint64(rootPost1.CreateAt),
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 1)
|
|
|
|
// Should not fetch any threads since there are no new replies/new threads since the membership is updated
|
|
threadMembership, _ := th.App.GetThreadMembershipForUser(th.BasicUser.Id, rootPost1.Id)
|
|
uss, _, err = th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Since: uint64(threadMembership.LastUpdated) + 1,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 0)
|
|
|
|
// Create "thread 2"
|
|
rootPost2, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "Thread 2"})
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel.Id, Message: "Thread 2, reply 1", RootId: rootPost2.Id})
|
|
|
|
// Add a reply to "thread 1"
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel.Id, Message: "Thread 1, Reply 2", RootId: rootPost1.Id})
|
|
|
|
// Should fetch "thread 1" & "thread 2"
|
|
uss, _, err = th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Since: uint64(threadMembership.LastUpdated) + 1,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, uss.TotalUnreadThreads, int64(2))
|
|
})
|
|
|
|
t.Run("should error when not a team member", func(t *testing.T) {
|
|
th.UnlinkUserFromTeam(t, th.BasicUser, th.BasicTeam)
|
|
defer th.LinkUserToTeam(t, th.BasicUser, th.BasicTeam)
|
|
|
|
_, resp, err := th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{})
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestThreadSocketEvents(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.ConfigStore.SetReadOnlyFF(false)
|
|
defer th.ConfigStore.SetReadOnlyFF(true)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.ThreadAutoFollow = true
|
|
*cfg.ServiceSettings.CollapsedThreads = model.CollapsedThreadsDefaultOn
|
|
})
|
|
|
|
userWSClient := th.CreateConnectedWebSocketClient(t)
|
|
|
|
client := th.Client
|
|
|
|
rpost, resp, err := client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
replyPost, _, appErr := th.App.CreatePostAsUser(th.Context, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply @" + th.BasicUser.Username, UserId: th.BasicUser2.Id, RootId: rpost.Id}, th.Context.Session().Id, false)
|
|
require.Nil(t, appErr)
|
|
defer func() {
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser2.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
t.Run("Listed for update event", func(t *testing.T) {
|
|
var caught bool
|
|
func() {
|
|
for {
|
|
select {
|
|
case ev := <-userWSClient.EventChannel:
|
|
if ev.EventType() == model.WebsocketEventThreadUpdated {
|
|
caught = true
|
|
var thread model.ThreadResponse
|
|
jsonErr := json.Unmarshal([]byte(ev.GetData()["thread"].(string)), &thread)
|
|
require.NoError(t, jsonErr)
|
|
for _, p := range thread.Participants {
|
|
if p.Id != th.BasicUser.Id && p.Id != th.BasicUser2.Id {
|
|
require.Fail(t, "invalid participants")
|
|
}
|
|
}
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
require.Truef(t, caught, "User should have received %s event", model.WebsocketEventThreadUpdated)
|
|
})
|
|
|
|
_, resp, err = th.Client.UpdateThreadReadForUser(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, rpost.Id, replyPost.CreateAt+1)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
t.Run("Listed for read event", func(t *testing.T) {
|
|
var caught bool
|
|
func() {
|
|
for {
|
|
select {
|
|
case ev := <-userWSClient.EventChannel:
|
|
if ev.EventType() == model.WebsocketEventThreadReadChanged {
|
|
caught = true
|
|
|
|
data := ev.GetData()
|
|
require.EqualValues(t, replyPost.CreateAt+1, data["timestamp"])
|
|
require.EqualValues(t, float64(1), data["previous_unread_replies"])
|
|
require.EqualValues(t, float64(1), data["previous_unread_mentions"])
|
|
require.EqualValues(t, float64(0), data["unread_replies"])
|
|
require.EqualValues(t, float64(0), data["unread_mentions"])
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
require.Truef(t, caught, "User should have received %s event", model.WebsocketEventThreadReadChanged)
|
|
})
|
|
|
|
resp, err = th.Client.UpdateThreadFollowForUser(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, rpost.Id, false)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
t.Run("Listed for follow event", func(t *testing.T) {
|
|
var caught bool
|
|
func() {
|
|
for {
|
|
select {
|
|
case ev := <-userWSClient.EventChannel:
|
|
if ev.EventType() == model.WebsocketEventThreadFollowChanged {
|
|
caught = true
|
|
require.Equal(t, ev.GetData()["state"], false)
|
|
require.Equal(t, ev.GetData()["reply_count"], float64(1))
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
require.Truef(t, caught, "User should have received %s event", model.WebsocketEventThreadFollowChanged)
|
|
})
|
|
|
|
_, err = th.Client.UpdateThreadFollowForUser(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, rpost.Id, true)
|
|
require.NoError(t, err)
|
|
_, resp, err = th.Client.SetThreadUnreadByPostId(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, rpost.Id, rpost.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
t.Run("Listen for read event 2", func(t *testing.T) {
|
|
var caught bool
|
|
func() {
|
|
for {
|
|
select {
|
|
case ev := <-userWSClient.EventChannel:
|
|
if ev.EventType() == model.WebsocketEventThreadReadChanged {
|
|
caught = true
|
|
|
|
data := ev.GetData()
|
|
require.EqualValues(t, rpost.CreateAt-1, data["timestamp"])
|
|
require.EqualValues(t, float64(0), data["previous_unread_replies"])
|
|
require.EqualValues(t, float64(0), data["previous_unread_mentions"])
|
|
require.EqualValues(t, float64(1), data["unread_replies"])
|
|
require.EqualValues(t, float64(1), data["unread_mentions"])
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
require.Truef(t, caught, "User should have received %s event", model.WebsocketEventThreadReadChanged)
|
|
})
|
|
|
|
// read the thread
|
|
_, resp, err = th.Client.UpdateThreadReadForUser(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, rpost.Id, replyPost.CreateAt+1)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
t.Run("Listen for thread updated event after create post", func(t *testing.T) {
|
|
testCases := []struct {
|
|
post *model.Post
|
|
preReplies int64
|
|
preMentions int64
|
|
replies int64
|
|
mentions int64
|
|
}{
|
|
{
|
|
post: &model.Post{ChannelId: th.BasicChannel.Id, Message: "simple reply", UserId: th.BasicUser2.Id, RootId: rpost.Id},
|
|
preReplies: 0,
|
|
preMentions: 0,
|
|
replies: 1,
|
|
mentions: 0,
|
|
},
|
|
{
|
|
post: &model.Post{ChannelId: th.BasicChannel.Id, Message: "mention reply 1 @" + th.BasicUser.Username, UserId: th.BasicUser2.Id, RootId: rpost.Id},
|
|
preReplies: 1,
|
|
preMentions: 0,
|
|
replies: 2,
|
|
mentions: 1,
|
|
},
|
|
{
|
|
post: &model.Post{ChannelId: th.BasicChannel.Id, Message: "mention reply 2 @" + th.BasicUser.Username, UserId: th.BasicUser2.Id, RootId: rpost.Id},
|
|
preReplies: 2,
|
|
preMentions: 1,
|
|
replies: 3,
|
|
mentions: 2,
|
|
},
|
|
{
|
|
// posting as current user will read the thread
|
|
post: &model.Post{ChannelId: th.BasicChannel.Id, Message: "self reply", UserId: th.BasicUser.Id, RootId: rpost.Id},
|
|
preReplies: 3,
|
|
preMentions: 2,
|
|
replies: 0,
|
|
mentions: 0,
|
|
},
|
|
{
|
|
post: &model.Post{ChannelId: th.BasicChannel.Id, Message: "simple reply", UserId: th.BasicUser2.Id, RootId: rpost.Id},
|
|
preReplies: 0,
|
|
preMentions: 0,
|
|
replies: 1,
|
|
mentions: 0,
|
|
},
|
|
{
|
|
post: &model.Post{ChannelId: th.BasicChannel.Id, Message: "mention reply 3 @" + th.BasicUser.Username, UserId: th.BasicUser2.Id, RootId: rpost.Id},
|
|
preReplies: 1,
|
|
preMentions: 0,
|
|
replies: 2,
|
|
mentions: 1,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
// post a reply on the thread
|
|
_, _, appErr = th.App.CreatePostAsUser(th.Context, tc.post, th.Context.Session().Id, false)
|
|
require.Nil(t, appErr)
|
|
|
|
var caught bool
|
|
func() {
|
|
for {
|
|
select {
|
|
case ev := <-userWSClient.EventChannel:
|
|
if ev.EventType() == model.WebsocketEventThreadUpdated {
|
|
caught = true
|
|
data := ev.GetData()
|
|
var thread model.ThreadResponse
|
|
jsonErr := json.Unmarshal([]byte(data["thread"].(string)), &thread)
|
|
require.NoError(t, jsonErr)
|
|
|
|
require.Equal(t, tc.preReplies, int64(data["previous_unread_replies"].(float64)))
|
|
require.Equal(t, tc.preMentions, int64(data["previous_unread_mentions"].(float64)))
|
|
require.Equal(t, tc.replies, thread.UnreadReplies)
|
|
require.Equal(t, tc.mentions, thread.UnreadMentions)
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
require.Truef(t, caught, "User should have received %s event", model.WebsocketEventThreadUpdated)
|
|
}
|
|
})
|
|
|
|
t.Run("Listen for thread updated event after create post when not previously following the thread", func(t *testing.T) {
|
|
rpost2 := &model.Post{ChannelId: th.BasicChannel.Id, UserId: th.BasicUser2.Id, Message: "root post"}
|
|
|
|
var appErr *model.AppError
|
|
rpost2, _, appErr = th.App.CreatePostAsUser(th.Context, rpost2, th.Context.Session().Id, false)
|
|
require.Nil(t, appErr)
|
|
|
|
reply1 := &model.Post{ChannelId: th.BasicChannel.Id, UserId: th.BasicUser2.Id, Message: "reply 1", RootId: rpost2.Id}
|
|
reply2 := &model.Post{ChannelId: th.BasicChannel.Id, UserId: th.BasicUser2.Id, Message: "reply 2", RootId: rpost2.Id}
|
|
reply3 := &model.Post{ChannelId: th.BasicChannel.Id, UserId: th.BasicUser2.Id, Message: "mention @" + th.BasicUser.Username, RootId: rpost2.Id}
|
|
|
|
_, _, appErr = th.App.CreatePostAsUser(th.Context, reply1, th.Context.Session().Id, false)
|
|
require.Nil(t, appErr)
|
|
_, _, appErr = th.App.CreatePostAsUser(th.Context, reply2, th.Context.Session().Id, false)
|
|
require.Nil(t, appErr)
|
|
_, _, appErr = th.App.CreatePostAsUser(th.Context, reply3, th.Context.Session().Id, false)
|
|
require.Nil(t, appErr)
|
|
|
|
count := 0
|
|
func() {
|
|
for {
|
|
select {
|
|
case ev := <-userWSClient.EventChannel:
|
|
if ev.EventType() == model.WebsocketEventThreadUpdated {
|
|
count++
|
|
data := ev.GetData()
|
|
var thread model.ThreadResponse
|
|
jsonErr := json.Unmarshal([]byte(data["thread"].(string)), &thread)
|
|
require.NoError(t, jsonErr)
|
|
|
|
require.Equal(t, int64(0), int64(data["previous_unread_replies"].(float64)))
|
|
require.Equal(t, int64(0), int64(data["previous_unread_mentions"].(float64)))
|
|
require.Equal(t, int64(3), thread.UnreadReplies)
|
|
require.Equal(t, int64(1), thread.UnreadMentions)
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
require.Equalf(t, 1, count, "User should have received 1 %s event", model.WebsocketEventThreadUpdated)
|
|
})
|
|
}
|
|
|
|
func TestFollowThreads(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.ThreadAutoFollow = true
|
|
*cfg.ServiceSettings.CollapsedThreads = model.CollapsedThreadsDefaultOn
|
|
})
|
|
|
|
t.Run("1 thread", func(t *testing.T) {
|
|
client := th.Client
|
|
|
|
rpost, resp, err := client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
_, resp, err = client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
defer func() {
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
var uss *model.Threads
|
|
uss, _, err = th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 1)
|
|
|
|
resp, err = th.Client.UpdateThreadFollowForUser(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, rpost.Id, false)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
uss, _, err = th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 0)
|
|
|
|
resp, err = th.Client.UpdateThreadFollowForUser(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, rpost.Id, true)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
uss, _, err = th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 1)
|
|
require.GreaterOrEqual(t, uss.Threads[0].LastViewedAt, uss.Threads[0].LastReplyAt)
|
|
})
|
|
|
|
t.Run("No permission to channel", func(t *testing.T) {
|
|
// Add user1 to private channel
|
|
_, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, th.BasicPrivateChannel2, false)
|
|
require.Nil(t, appErr)
|
|
defer func() {
|
|
appErr = th.App.RemoveUserFromChannel(th.Context, th.BasicUser.Id, "", th.BasicPrivateChannel2)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
// create thread in private channel
|
|
rpost, resp, err := th.Client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicPrivateChannel2.Id, Message: "root post"})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
_, resp, err = th.Client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicPrivateChannel2.Id, Message: "testReply", RootId: rpost.Id})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
// Try to follow thread as other user who is not in the private channel
|
|
resp, err = th.Client.UpdateThreadFollowForUser(context.Background(), th.BasicUser2.Id, th.BasicTeam.Id, rpost.Id, true)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
// Try to unfollow thread as other user who is not in the private channel
|
|
resp, err = th.Client.UpdateThreadFollowForUser(context.Background(), th.BasicUser2.Id, th.BasicTeam.Id, rpost.Id, false)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func checkThreadListReplies(t *testing.T, th *TestHelper, client *model.Client4, userId string, expectedReplies, expectedThreads int, options *model.GetUserThreadsOpts) (*model.Threads, *model.Response) {
|
|
opts := model.GetUserThreadsOpts{}
|
|
if options != nil {
|
|
opts = *options
|
|
}
|
|
u, resp, err := client.GetUserThreads(context.Background(), userId, th.BasicTeam.Id, opts)
|
|
require.NoError(t, err)
|
|
require.Len(t, u.Threads, expectedThreads)
|
|
|
|
count := int64(0)
|
|
sum := int64(0)
|
|
for _, thr := range u.Threads {
|
|
if thr.UnreadReplies > 0 {
|
|
count += 1
|
|
}
|
|
sum += thr.UnreadReplies
|
|
}
|
|
require.EqualValues(t, expectedReplies, sum, "expectedReplies don't match")
|
|
require.Equal(t, count, u.TotalUnreadThreads, "TotalUnreadThreads don't match")
|
|
|
|
return u, resp
|
|
}
|
|
|
|
func postAndCheck(t *testing.T, client *model.Client4, post *model.Post) (*model.Post, *model.Response) {
|
|
p, resp, err := client.CreatePost(context.Background(), post)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
return p, resp
|
|
}
|
|
|
|
func TestMaintainUnreadRepliesInThread(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
|
|
th := Setup(t).InitBasic(t)
|
|
th.LinkUserToTeam(t, th.SystemAdminUser, th.BasicTeam)
|
|
defer th.UnlinkUserFromTeam(t, th.SystemAdminUser, th.BasicTeam)
|
|
th.AddUserToChannel(t, th.SystemAdminUser, th.BasicChannel)
|
|
defer th.RemoveUserFromChannel(t, th.SystemAdminUser, th.BasicChannel)
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.ThreadAutoFollow = true
|
|
*cfg.ServiceSettings.CollapsedThreads = model.CollapsedThreadsDefaultOn
|
|
})
|
|
|
|
client := th.Client
|
|
defer func() {
|
|
err := th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.SystemAdminUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
// create a post by regular user
|
|
rpost, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
// reply with another
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
|
|
|
// regular user should have one thread with one reply
|
|
checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 1, 1, nil)
|
|
|
|
// add another reply by regular user
|
|
postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply2", RootId: rpost.Id})
|
|
|
|
// replying to the thread clears reply count, so it should be 0
|
|
checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 0, 1, nil)
|
|
|
|
// the other user should have 1 reply - the reply from the regular user
|
|
checkThreadListReplies(t, th, th.SystemAdminClient, th.SystemAdminUser.Id, 1, 1, nil)
|
|
|
|
// mark all as read for user
|
|
resp, err := th.Client.UpdateThreadsReadForUser(context.Background(), th.BasicUser.Id, th.BasicTeam.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
// reply count should be 0
|
|
checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 0, 1, nil)
|
|
|
|
// mark other user's read state
|
|
_, resp, err = th.SystemAdminClient.UpdateThreadReadForUser(context.Background(), th.SystemAdminUser.Id, th.BasicTeam.Id, rpost.Id, model.GetMillis())
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
// get unread only, should return nothing
|
|
checkThreadListReplies(t, th, th.SystemAdminClient, th.SystemAdminUser.Id, 0, 0, &model.GetUserThreadsOpts{Unread: true})
|
|
|
|
// restore unread to an old date
|
|
_, resp, err = th.SystemAdminClient.UpdateThreadReadForUser(context.Background(), th.SystemAdminUser.Id, th.BasicTeam.Id, rpost.Id, 123)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
// should have 2 unread replies now
|
|
checkThreadListReplies(t, th, th.SystemAdminClient, th.SystemAdminUser.Id, 2, 1, &model.GetUserThreadsOpts{Unread: true})
|
|
}
|
|
|
|
func TestThreadCounts(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.ThreadAutoFollow = true
|
|
*cfg.ServiceSettings.CollapsedThreads = model.CollapsedThreadsDefaultOn
|
|
})
|
|
|
|
client := th.Client
|
|
defer func() {
|
|
err := th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.SystemAdminUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
// create a post by regular user
|
|
rpost, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
// reply with another
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
|
|
|
// create another post by regular user
|
|
rpost2, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel2.Id, Message: "testMsg1"})
|
|
// reply with another 2 times
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel2.Id, Message: "testReply2", RootId: rpost2.Id})
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel2.Id, Message: "testReply22", RootId: rpost2.Id})
|
|
|
|
// regular user should have two threads with 3 replies total
|
|
checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 3, 2, &model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
|
|
// delete first thread
|
|
err := th.App.Srv().Store().Post().Delete(th.Context, rpost.Id, model.GetMillis(), th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
|
|
// we should now have 1 thread with 2 replies
|
|
checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 2, 1, &model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
// with Deleted we should get the same as before deleting
|
|
checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 3, 2, &model.GetUserThreadsOpts{
|
|
Deleted: true,
|
|
})
|
|
}
|
|
|
|
func TestSingleThreadGet(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.ThreadAutoFollow = true
|
|
*cfg.ServiceSettings.CollapsedThreads = model.CollapsedThreadsDefaultOn
|
|
*cfg.ServiceSettings.PostPriority = true
|
|
})
|
|
|
|
client := th.Client
|
|
|
|
t.Run("get single thread", func(t *testing.T) {
|
|
defer func() {
|
|
err := th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.SystemAdminUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
// create a post by regular user
|
|
rpost, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
// reply with another
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
|
|
|
// create another thread to check that we are not returning it by mistake
|
|
rpost2, _ := postAndCheck(t, client, &model.Post{
|
|
ChannelId: th.BasicChannel2.Id,
|
|
Message: "testMsg2",
|
|
Metadata: &model.PostMetadata{
|
|
Priority: &model.PostPriority{
|
|
Priority: model.NewPointer(model.PostPriorityUrgent),
|
|
},
|
|
},
|
|
})
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel2.Id, Message: "testReply", RootId: rpost2.Id})
|
|
|
|
// regular user should have two threads with 3 replies total
|
|
threads, _ := checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 2, 2, nil)
|
|
|
|
tr, _, err := th.Client.GetUserThread(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, threads.Threads[0].PostId, false)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, tr)
|
|
require.Equal(t, threads.Threads[0].PostId, tr.PostId)
|
|
require.Empty(t, tr.Participants[0].Username)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.PostPriority = false
|
|
})
|
|
|
|
tr, _, err = th.Client.GetUserThread(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, threads.Threads[0].PostId, true)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, tr.Participants[0].Username)
|
|
require.Equal(t, false, tr.IsUrgent)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.PostPriority = true
|
|
})
|
|
|
|
tr, _, err = th.Client.GetUserThread(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, threads.Threads[0].PostId, true)
|
|
require.NoError(t, err)
|
|
require.Equal(t, true, tr.IsUrgent)
|
|
})
|
|
|
|
t.Run("should error when not a team member", func(t *testing.T) {
|
|
th.UnlinkUserFromTeam(t, th.BasicUser, th.BasicTeam)
|
|
defer th.LinkUserToTeam(t, th.BasicUser, th.BasicTeam)
|
|
|
|
_, resp, err := th.Client.GetUserThread(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.NewId(), false)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestMaintainUnreadMentionsInThread(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
th.LinkUserToTeam(t, th.SystemAdminUser, th.BasicTeam)
|
|
defer th.UnlinkUserFromTeam(t, th.SystemAdminUser, th.BasicTeam)
|
|
th.AddUserToChannel(t, th.SystemAdminUser, th.BasicChannel)
|
|
defer th.RemoveUserFromChannel(t, th.SystemAdminUser, th.BasicChannel)
|
|
client := th.Client
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.ThreadAutoFollow = true
|
|
*cfg.ServiceSettings.CollapsedThreads = model.CollapsedThreadsDefaultOn
|
|
})
|
|
checkThreadList := func(client *model.Client4, userId string, expectedMentions, expectedThreads int) (*model.Threads, *model.Response) {
|
|
uss, resp, err := client.GetUserThreads(context.Background(), userId, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, uss.Threads, expectedThreads)
|
|
sum := int64(0)
|
|
for _, thr := range uss.Threads {
|
|
sum += thr.UnreadMentions
|
|
}
|
|
require.Equal(t, sum, uss.TotalUnreadMentions)
|
|
require.EqualValues(t, expectedMentions, uss.TotalUnreadMentions)
|
|
|
|
return uss, resp
|
|
}
|
|
|
|
defer func() {
|
|
err := th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.SystemAdminUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
// create regular post
|
|
rpost, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
// create reply and mention the original poster and another user
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply @" + th.BasicUser.Username + " and @" + th.BasicUser2.Username, RootId: rpost.Id})
|
|
|
|
// basic user 1 was mentioned 1 time
|
|
checkThreadList(th.Client, th.BasicUser.Id, 1, 1)
|
|
// basic user 2 was mentioned 1 time
|
|
checkThreadList(th.SystemAdminClient, th.BasicUser2.Id, 1, 1)
|
|
|
|
// test self mention, shouldn't increase mention count
|
|
postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply @" + th.BasicUser.Username, RootId: rpost.Id})
|
|
// mention should be 0 after self reply
|
|
checkThreadList(th.Client, th.BasicUser.Id, 0, 1)
|
|
|
|
// test DM
|
|
dm := th.CreateDmChannel(t, th.SystemAdminUser)
|
|
dm_root_post, _ := postAndCheck(t, client, &model.Post{ChannelId: dm.Id, Message: "hi @" + th.SystemAdminUser.Username})
|
|
|
|
// no changes
|
|
checkThreadList(th.Client, th.BasicUser.Id, 0, 1)
|
|
|
|
// post reply by the same user
|
|
postAndCheck(t, client, &model.Post{ChannelId: dm.Id, Message: "how are you", RootId: dm_root_post.Id})
|
|
|
|
// thread created
|
|
checkThreadList(th.Client, th.BasicUser.Id, 0, 2)
|
|
|
|
// post two replies by another user, without mentions. mention count should still increase since this is a DM
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: dm.Id, Message: "msg1", RootId: dm_root_post.Id})
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: dm.Id, Message: "msg2", RootId: dm_root_post.Id})
|
|
// expect increment by two mentions
|
|
checkThreadList(th.Client, th.BasicUser.Id, 2, 2)
|
|
}
|
|
|
|
func TestReadThreads(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.ThreadAutoFollow = true
|
|
*cfg.ServiceSettings.CollapsedThreads = model.CollapsedThreadsDefaultOn
|
|
})
|
|
client := th.Client
|
|
t.Run("all threads", func(t *testing.T) {
|
|
rpost, resp, err := client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
_, resp, err = client.CreatePost(context.Background(), &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
defer func() {
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
var uss, uss2 *model.Threads
|
|
uss, _, err = th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss.Threads, 1)
|
|
|
|
resp, err = th.Client.UpdateThreadsReadForUser(context.Background(), th.BasicUser.Id, th.BasicTeam.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
uss2, _, err = th.Client.GetUserThreads(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
|
Deleted: false,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, uss2.Threads, 1)
|
|
require.Greater(t, uss2.Threads[0].LastViewedAt, uss.Threads[0].LastViewedAt)
|
|
})
|
|
|
|
t.Run("1 thread by timestamp", func(t *testing.T) {
|
|
defer func() {
|
|
err := th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.SystemAdminUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
rpost, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsgC1"})
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReplyC1", RootId: rpost.Id})
|
|
|
|
rrpost, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel2.Id, Message: "testMsgC2"})
|
|
postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel2.Id, Message: "testReplyC2", RootId: rrpost.Id})
|
|
|
|
uss, _ := checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 2, 2, nil)
|
|
|
|
_, resp, err := th.Client.UpdateThreadReadForUser(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, rrpost.Id, model.GetMillis()+10)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
uss2, _ := checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 1, 2, nil)
|
|
require.Greater(t, uss2.Threads[0].LastViewedAt, uss.Threads[0].LastViewedAt)
|
|
|
|
timestamp := model.GetMillis()
|
|
_, resp, err = th.Client.UpdateThreadReadForUser(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, rrpost.Id, timestamp)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
uss3, _ := checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 1, 2, nil)
|
|
require.Equal(t, uss3.Threads[0].LastViewedAt, timestamp)
|
|
})
|
|
|
|
t.Run("1 thread by post id", func(t *testing.T) {
|
|
defer func() {
|
|
err := th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
err = th.App.Srv().Store().Post().PermanentDeleteByUser(th.Context, th.SystemAdminUser.Id)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
rpost, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsgC1"})
|
|
reply1, _ := postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReplyC1", RootId: rpost.Id})
|
|
reply2, _ := postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReplyC1", RootId: rpost.Id})
|
|
reply3, _ := postAndCheck(t, th.SystemAdminClient, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReplyC1", RootId: rpost.Id})
|
|
|
|
checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 3, 1, nil)
|
|
|
|
_, resp, err := th.Client.UpdateThreadReadForUser(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, rpost.Id, reply3.CreateAt+1)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 0, 1, nil)
|
|
|
|
_, resp, err = th.Client.SetThreadUnreadByPostId(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, rpost.Id, reply1.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 3, 1, nil)
|
|
|
|
_, resp, err = th.Client.SetThreadUnreadByPostId(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, rpost.Id, reply2.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 2, 1, nil)
|
|
|
|
_, resp, err = th.Client.SetThreadUnreadByPostId(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, rpost.Id, reply3.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 1, 1, nil)
|
|
})
|
|
|
|
t.Run("should error when not a team member", func(t *testing.T) {
|
|
th.UnlinkUserFromTeam(t, th.BasicUser, th.BasicTeam)
|
|
defer th.LinkUserToTeam(t, th.BasicUser, th.BasicTeam)
|
|
|
|
_, resp, err := th.Client.UpdateThreadReadForUser(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.NewId(), model.GetMillis())
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
_, resp, err = th.Client.SetThreadUnreadByPostId(context.Background(), th.BasicUser.Id, th.BasicTeam.Id, model.NewId(), model.NewId())
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
resp, err = th.Client.UpdateThreadsReadForUser(context.Background(), th.BasicUser.Id, th.BasicTeam.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestMarkThreadUnreadMentionCount(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.ThreadAutoFollow = true
|
|
*cfg.ServiceSettings.CollapsedThreads = model.CollapsedThreadsDefaultOn
|
|
})
|
|
client := th.Client
|
|
|
|
channel := th.BasicChannel
|
|
user := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
appErr := th.App.JoinChannel(th.Context, channel, user.Id)
|
|
require.Nil(t, appErr)
|
|
appErr = th.App.JoinChannel(th.Context, channel, user2.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
rpost, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg @" + th.BasicUser2.Username})
|
|
reply1, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply1 @" + th.BasicUser2.Username, RootId: rpost.Id})
|
|
reply2, _ := postAndCheck(t, client, &model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply2", RootId: rpost.Id})
|
|
|
|
_, _, err := th.SystemAdminClient.UpdateThreadReadForUser(context.Background(), th.BasicUser2.Id, th.BasicTeam.Id, rpost.Id, model.GetMillis())
|
|
require.NoError(t, err)
|
|
|
|
u, _, _ := th.SystemAdminClient.GetUserThreads(context.Background(), th.BasicUser2.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{})
|
|
require.EqualValues(t, 0, u.TotalUnreadMentions)
|
|
|
|
_, _, err = th.SystemAdminClient.UpdateThreadReadForUser(context.Background(), th.BasicUser2.Id, th.BasicTeam.Id, rpost.Id, rpost.CreateAt)
|
|
require.NoError(t, err)
|
|
|
|
u, _, _ = th.SystemAdminClient.GetUserThreads(context.Background(), th.BasicUser2.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{})
|
|
require.EqualValues(t, 1, u.TotalUnreadMentions)
|
|
|
|
_, _, err = th.SystemAdminClient.UpdateThreadReadForUser(context.Background(), th.BasicUser2.Id, th.BasicTeam.Id, rpost.Id, reply1.CreateAt)
|
|
require.NoError(t, err)
|
|
|
|
u, _, _ = th.SystemAdminClient.GetUserThreads(context.Background(), th.BasicUser2.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{})
|
|
require.EqualValues(t, 1, u.TotalUnreadMentions)
|
|
|
|
_, _, err = th.SystemAdminClient.UpdateThreadReadForUser(context.Background(), th.BasicUser2.Id, th.BasicTeam.Id, rpost.Id, reply2.CreateAt)
|
|
require.NoError(t, err)
|
|
|
|
u, _, _ = th.SystemAdminClient.GetUserThreads(context.Background(), th.BasicUser2.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{})
|
|
require.EqualValues(t, 0, u.TotalUnreadMentions)
|
|
}
|
|
|
|
func TestPatchAndUpdateWithProviderAttributes(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
t.Run("LDAP user", func(t *testing.T) {
|
|
th := SetupEnterprise(t).InitBasic(t)
|
|
|
|
user := th.CreateUserWithAuth(t, model.UserAuthServiceLdap)
|
|
ldapMock := &mocks.LdapInterface{}
|
|
ldapMock.Mock.On(
|
|
"CheckProviderAttributes",
|
|
mock.AnythingOfType("*request.Context"),
|
|
mock.AnythingOfType("*model.LdapSettings"),
|
|
mock.AnythingOfType("*model.User"),
|
|
mock.AnythingOfType("*model.UserPatch"),
|
|
).Return("")
|
|
th.App.Channels().Ldap = ldapMock
|
|
// CheckProviderAttributes should be called for both Patch and Update
|
|
_, _, err := th.SystemAdminClient.PatchUser(context.Background(), user.Id, &model.UserPatch{})
|
|
require.NoError(t, err)
|
|
ldapMock.AssertNumberOfCalls(t, "CheckProviderAttributes", 1)
|
|
_, _, err = th.SystemAdminClient.UpdateUser(context.Background(), user)
|
|
require.NoError(t, err)
|
|
ldapMock.AssertNumberOfCalls(t, "CheckProviderAttributes", 2)
|
|
})
|
|
t.Run("SAML user", func(t *testing.T) {
|
|
t.Run("with LDAP sync", func(t *testing.T) {
|
|
th := SetupEnterprise(t).InitBasic(t)
|
|
th.SetupLdapConfig()
|
|
th.SetupSamlConfig()
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.SamlSettings.EnableSyncWithLdap = true
|
|
})
|
|
|
|
user := th.CreateUserWithAuth(t, model.UserAuthServiceSaml)
|
|
ldapMock := &mocks.LdapInterface{}
|
|
ldapMock.Mock.On(
|
|
"CheckProviderAttributes", mock.AnythingOfType("*request.Context"), mock.AnythingOfType("*model.LdapSettings"), mock.AnythingOfType("*model.User"), mock.AnythingOfType("*model.UserPatch"),
|
|
).Return("")
|
|
th.App.Channels().Ldap = ldapMock
|
|
_, _, err := th.SystemAdminClient.PatchUser(context.Background(), user.Id, &model.UserPatch{})
|
|
require.NoError(t, err)
|
|
ldapMock.AssertNumberOfCalls(t, "CheckProviderAttributes", 1)
|
|
_, _, err = th.SystemAdminClient.UpdateUser(context.Background(), user)
|
|
require.NoError(t, err)
|
|
ldapMock.AssertNumberOfCalls(t, "CheckProviderAttributes", 2)
|
|
})
|
|
t.Run("without LDAP sync", func(t *testing.T) {
|
|
th := SetupEnterprise(t).InitBasic(t)
|
|
|
|
user := th.CreateUserWithAuth(t, model.UserAuthServiceSaml)
|
|
samlMock := &mocks.SamlInterface{}
|
|
samlMock.Mock.On(
|
|
"CheckProviderAttributes", mock.AnythingOfType("*request.Context"), mock.AnythingOfType("*model.SamlSettings"), mock.AnythingOfType("*model.User"), mock.AnythingOfType("*model.UserPatch"),
|
|
).Return("")
|
|
th.App.Channels().Saml = samlMock
|
|
_, _, err := th.SystemAdminClient.PatchUser(context.Background(), user.Id, &model.UserPatch{})
|
|
require.NoError(t, err)
|
|
samlMock.AssertNumberOfCalls(t, "CheckProviderAttributes", 1)
|
|
_, _, err = th.SystemAdminClient.UpdateUser(context.Background(), user)
|
|
require.NoError(t, err)
|
|
samlMock.AssertNumberOfCalls(t, "CheckProviderAttributes", 2)
|
|
})
|
|
})
|
|
t.Run("OpenID user", func(t *testing.T) {
|
|
th := SetupEnterprise(t).InitBasic(t)
|
|
|
|
user := th.CreateUserWithAuth(t, model.ServiceOpenid)
|
|
// OAUTH users cannot change these fields
|
|
for _, fieldName := range []string{
|
|
"FirstName",
|
|
"LastName",
|
|
} {
|
|
patch := user.ToPatch()
|
|
patch.SetField(fieldName, "something new")
|
|
conflictField := th.App.CheckProviderAttributes(th.Context, user, patch)
|
|
require.NotEqual(t, "", conflictField)
|
|
}
|
|
})
|
|
t.Run("Patch username", func(t *testing.T) {
|
|
th := SetupEnterprise(t).InitBasic(t)
|
|
|
|
// For non-email users, the username must be changed through the provider
|
|
for _, authService := range []string{
|
|
model.UserAuthServiceLdap,
|
|
model.UserAuthServiceSaml,
|
|
model.ServiceOpenid,
|
|
} {
|
|
user := th.CreateUserWithAuth(t, authService)
|
|
patch := &model.UserPatch{Username: model.NewPointer("something new")}
|
|
conflictField := th.App.CheckProviderAttributes(th.Context, user, patch)
|
|
require.NotEqual(t, "", conflictField)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestSetProfileImageWithProviderAttributes(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
data, err := testutils.ReadTestFile("test.png")
|
|
require.NoError(t, err)
|
|
|
|
type imageTestCase struct {
|
|
testName string
|
|
ldapAttrIsSet bool
|
|
shouldPass bool
|
|
}
|
|
|
|
doImageTest := func(t *testing.T, th *TestHelper, user *model.User, testCase imageTestCase) {
|
|
client := th.SystemAdminClient
|
|
t.Run(testCase.testName, func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
if testCase.ldapAttrIsSet {
|
|
*cfg.LdapSettings.PictureAttribute = "jpegPhoto"
|
|
} else {
|
|
*cfg.LdapSettings.PictureAttribute = ""
|
|
}
|
|
})
|
|
resp, err2 := client.SetProfileImage(context.Background(), user.Id, data)
|
|
if testCase.shouldPass {
|
|
require.NoError(t, err2)
|
|
} else {
|
|
require.Error(t, err2)
|
|
checkHTTPStatus(t, resp, http.StatusConflict)
|
|
}
|
|
})
|
|
}
|
|
doCleanup := func(t *testing.T, th *TestHelper, user *model.User) {
|
|
info := &model.FileInfo{Path: "users/" + user.Id + "/profile.png"}
|
|
err = th.cleanupTestFile(info)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
t.Run("LDAP user", func(t *testing.T) {
|
|
testCases := []imageTestCase{
|
|
{"profile picture attribute is set", true, false},
|
|
{"profile picture attribute is not set", false, true},
|
|
}
|
|
th := SetupEnterprise(t).InitBasic(t)
|
|
th.SetupLdapConfig()
|
|
|
|
user := th.CreateUserWithAuth(t, model.UserAuthServiceLdap)
|
|
for _, testCase := range testCases {
|
|
doImageTest(t, th, user, testCase)
|
|
}
|
|
doCleanup(t, th, user)
|
|
})
|
|
|
|
t.Run("SAML user", func(t *testing.T) {
|
|
th := SetupEnterprise(t).InitBasic(t)
|
|
th.SetupLdapConfig()
|
|
th.SetupSamlConfig()
|
|
user := th.CreateUserWithAuth(t, model.UserAuthServiceSaml)
|
|
|
|
t.Run("with LDAP sync", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.SamlSettings.EnableSyncWithLdap = true
|
|
})
|
|
testCases := []imageTestCase{
|
|
{"profile picture attribute is set", true, false},
|
|
{"profile picture attribute is not set", false, true},
|
|
}
|
|
for _, testCase := range testCases {
|
|
doImageTest(t, th, user, testCase)
|
|
}
|
|
})
|
|
t.Run("without LDAP sync", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.SamlSettings.EnableSyncWithLdap = false
|
|
})
|
|
testCases := []imageTestCase{
|
|
{"profile picture attribute is set", true, true},
|
|
{"profile picture attribute is not set", false, true},
|
|
}
|
|
for _, testCase := range testCases {
|
|
doImageTest(t, th, user, testCase)
|
|
}
|
|
})
|
|
doCleanup(t, th, user)
|
|
})
|
|
}
|
|
|
|
func TestGetUsersWithInvalidEmails(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
client := th.SystemAdminClient
|
|
|
|
user := model.User{
|
|
Email: "ben@invalid.mattermost.com",
|
|
Nickname: "Ben Cooke",
|
|
Password: "hello1",
|
|
Username: GenerateTestUsername(),
|
|
Roles: model.SystemAdminRoleId + " " + model.SystemUserRoleId,
|
|
}
|
|
|
|
_, resp, err := client.CreateUser(context.Background(), &user)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.TeamSettings.EnableOpenServer = false
|
|
*cfg.TeamSettings.RestrictCreationToDomains = "localhost,simulator.amazonses.com"
|
|
})
|
|
|
|
users, _, err := client.GetUsersWithInvalidEmails(context.Background(), 0, 50)
|
|
require.NoError(t, err)
|
|
assert.Len(t, users, 1)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.TeamSettings.EnableOpenServer = true
|
|
})
|
|
|
|
_, resp, err = client.GetUsersWithInvalidEmails(context.Background(), 0, 50)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.TeamSettings.EnableOpenServer = false
|
|
*cfg.TeamSettings.RestrictCreationToDomains = "localhost,simulator.amazonses.com,invalid.mattermost.com"
|
|
})
|
|
|
|
users, _, err = client.GetUsersWithInvalidEmails(context.Background(), 0, 50)
|
|
require.NoError(t, err)
|
|
assert.Len(t, users, 0)
|
|
|
|
_, resp, err = th.Client.GetUsersWithInvalidEmails(context.Background(), 0, 50)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
}
|
|
|
|
func TestUserUpdateEvents(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
client1 := th.CreateClient()
|
|
th.LoginBasicWithClient(t, client1)
|
|
wsClient1 := th.CreateConnectedWebSocketClientWithClient(t, client1)
|
|
|
|
client2 := th.CreateClient()
|
|
th.LoginBasic2WithClient(t, client2)
|
|
wsClient2 := th.CreateConnectedWebSocketClientWithClient(t, client2)
|
|
|
|
t.Run("nickname", func(t *testing.T) {
|
|
assertUpdated := func(t *testing.T, event *model.WebSocketEvent, expectedNickname string) *model.User {
|
|
eventUser, ok := event.GetData()["user"].(*model.User)
|
|
require.True(t, ok, "expected user")
|
|
assert.Equal(t, th.BasicUser.Id, eventUser.Id)
|
|
assert.Equal(t, expectedNickname, eventUser.Nickname)
|
|
|
|
// Some fields must always be sanitized
|
|
CheckUserSanitization(t, eventUser)
|
|
|
|
return eventUser
|
|
}
|
|
|
|
t.Run("update", func(t *testing.T) {
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
newNickname := model.NewUsername()
|
|
th.BasicUser.Nickname = newNickname
|
|
_, _, err := client1.UpdateUser(context.Background(), th.BasicUser)
|
|
require.NoError(t, err)
|
|
|
|
assertExpectedWebsocketEvent(t, wsClient1, model.WebsocketEventUserUpdated, func(event *model.WebSocketEvent) {
|
|
eventUser := assertUpdated(t, event, newNickname)
|
|
assert.NotEmpty(t, eventUser.NotifyProps, "source user should keep notify_props")
|
|
})
|
|
|
|
assertExpectedWebsocketEvent(t, wsClient2, model.WebsocketEventUserUpdated, func(event *model.WebSocketEvent) {
|
|
eventUser := assertUpdated(t, event, newNickname)
|
|
assert.Empty(t, eventUser.NotifyProps, "non-source users should have sanitized notify_props")
|
|
})
|
|
})
|
|
})
|
|
|
|
t.Run("patch", func(t *testing.T) {
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
newNickname := model.NewUsername()
|
|
|
|
_, _, err := client1.PatchUser(context.Background(), th.BasicUser.Id, &model.UserPatch{
|
|
Nickname: &newNickname,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
assertExpectedWebsocketEvent(t, wsClient1, model.WebsocketEventUserUpdated, func(event *model.WebSocketEvent) {
|
|
eventUser := assertUpdated(t, event, newNickname)
|
|
assert.NotEmpty(t, eventUser.NotifyProps, "source user should keep notify_props")
|
|
})
|
|
|
|
assertExpectedWebsocketEvent(t, wsClient2, model.WebsocketEventUserUpdated, func(event *model.WebSocketEvent) {
|
|
eventUser := assertUpdated(t, event, newNickname)
|
|
assert.Empty(t, eventUser.NotifyProps, "non-source users should have sanitized notify_props")
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
t.Run("username", func(t *testing.T) {
|
|
assertUpdated := func(t *testing.T, event *model.WebSocketEvent, expectedUsername string) *model.User {
|
|
eventUser, ok := event.GetData()["user"].(*model.User)
|
|
require.True(t, ok, "expected user")
|
|
assert.Equal(t, th.BasicUser.Id, eventUser.Id)
|
|
assert.Equal(t, expectedUsername, eventUser.Username)
|
|
|
|
// Some fields must always be sanitized
|
|
CheckUserSanitization(t, eventUser)
|
|
|
|
return eventUser
|
|
}
|
|
|
|
t.Run("update", func(t *testing.T) {
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
newUsername := model.NewUsername()
|
|
|
|
th.BasicUser.Username = newUsername
|
|
_, _, err := client1.UpdateUser(context.Background(), th.BasicUser)
|
|
require.NoError(t, err)
|
|
|
|
assertExpectedWebsocketEvent(t, wsClient1, model.WebsocketEventUserUpdated, func(event *model.WebSocketEvent) {
|
|
eventUser := assertUpdated(t, event, newUsername)
|
|
assert.NotEmpty(t, eventUser.NotifyProps, "source user should keep notify_props")
|
|
})
|
|
|
|
assertExpectedWebsocketEvent(t, wsClient2, model.WebsocketEventUserUpdated, func(event *model.WebSocketEvent) {
|
|
eventUser := assertUpdated(t, event, newUsername)
|
|
assert.Empty(t, eventUser.NotifyProps, "non-source users should have sanitized notify_props")
|
|
})
|
|
})
|
|
})
|
|
|
|
t.Run("patch", func(t *testing.T) {
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
newUsername := model.NewUsername()
|
|
|
|
_, _, err := client1.PatchUser(context.Background(), th.BasicUser.Id, &model.UserPatch{
|
|
Username: &newUsername,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
assertExpectedWebsocketEvent(t, wsClient1, model.WebsocketEventUserUpdated, func(event *model.WebSocketEvent) {
|
|
eventUser := assertUpdated(t, event, newUsername)
|
|
assert.NotEmpty(t, eventUser.NotifyProps, "source user should keep notify_props")
|
|
})
|
|
|
|
assertExpectedWebsocketEvent(t, wsClient2, model.WebsocketEventUserUpdated, func(event *model.WebSocketEvent) {
|
|
eventUser := assertUpdated(t, event, newUsername)
|
|
assert.Empty(t, eventUser.NotifyProps, "non-source users should have sanitized notify_props")
|
|
})
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestLoginWithDesktopToken(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
t.Run("login SAML User with desktop token", func(t *testing.T) {
|
|
samlUser := th.CreateUserWithAuth(t, model.UserAuthServiceSaml)
|
|
|
|
token, appErr := th.App.GenerateAndSaveDesktopToken(time.Now().Unix(), samlUser)
|
|
assert.Nil(t, appErr)
|
|
|
|
user, _, err := th.Client.LoginWithDesktopToken(context.Background(), *token, "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, samlUser.Id, user.Id)
|
|
|
|
sessions, _, err := th.SystemAdminClient.GetSessions(context.Background(), samlUser.Id, "")
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, sessions, 1)
|
|
assert.Equal(t, "true", sessions[0].Props["isSaml"])
|
|
assert.Equal(t, "false", sessions[0].Props["isOAuthUser"])
|
|
})
|
|
|
|
t.Run("login OAuth User with desktop token", func(t *testing.T) {
|
|
gitlabUser := th.CreateUserWithAuth(t, model.UserAuthServiceGitlab)
|
|
|
|
token, appErr := th.App.GenerateAndSaveDesktopToken(time.Now().Unix(), gitlabUser)
|
|
assert.Nil(t, appErr)
|
|
|
|
user, _, err := th.Client.LoginWithDesktopToken(context.Background(), *token, "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, gitlabUser.Id, user.Id)
|
|
|
|
sessions, _, err := th.SystemAdminClient.GetSessions(context.Background(), gitlabUser.Id, "")
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, sessions, 1)
|
|
assert.Equal(t, "false", sessions[0].Props["isSaml"])
|
|
assert.Equal(t, "true", sessions[0].Props["isOAuthUser"])
|
|
})
|
|
|
|
t.Run("login email user with desktop token", func(t *testing.T) {
|
|
// Sleep to avoid rate limit error
|
|
time.Sleep(time.Second)
|
|
user := th.CreateUser(t)
|
|
|
|
token, appErr := th.App.GenerateAndSaveDesktopToken(time.Now().Unix(), user)
|
|
assert.Nil(t, appErr)
|
|
|
|
_, resp, err := th.Client.LoginWithDesktopToken(context.Background(), *token, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
|
|
t.Run("invalid desktop token on login", func(t *testing.T) {
|
|
user := th.CreateUser(t)
|
|
|
|
_, appErr := th.App.GenerateAndSaveDesktopToken(time.Now().Unix(), user)
|
|
assert.Nil(t, appErr)
|
|
|
|
invalidToken := "testinvalidToken"
|
|
token := &invalidToken
|
|
|
|
_, _, err := th.Client.LoginWithDesktopToken(context.Background(), *token, "")
|
|
require.Error(t, err)
|
|
|
|
sessions, _, err := th.SystemAdminClient.GetSessions(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, sessions, 0)
|
|
})
|
|
}
|
|
|
|
func TestLoginSSOCodeExchange(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
t.Run("wrong token type cannot be used for code exchange", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
cfg.FeatureFlags.MobileSSOCodeExchange = true
|
|
})
|
|
|
|
token := model.NewToken(model.TokenTypeOAuth, "extra-data")
|
|
require.NoError(t, th.App.Srv().Store().Token().Save(token))
|
|
defer func() {
|
|
_ = th.App.Srv().Store().Token().Delete(token.Token)
|
|
}()
|
|
|
|
props := map[string]string{
|
|
"login_code": token.Token,
|
|
"code_verifier": "test_verifier",
|
|
"state": "test_state",
|
|
}
|
|
|
|
resp, err := th.Client.DoAPIPost(context.Background(), "/users/login/sso/code-exchange", model.MapToJSON(props))
|
|
require.Error(t, err)
|
|
require.Equal(t, http.StatusNotFound, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("successful code exchange with S256 challenge", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
cfg.FeatureFlags.MobileSSOCodeExchange = true
|
|
})
|
|
|
|
samlUser := th.CreateUserWithAuth(t, model.UserAuthServiceSaml)
|
|
|
|
codeVerifier := "test_code_verifier_123456789"
|
|
state := "test_state_value"
|
|
|
|
sum := sha256.Sum256([]byte(codeVerifier))
|
|
codeChallenge := base64.RawURLEncoding.EncodeToString(sum[:])
|
|
|
|
extra := map[string]string{
|
|
"user_id": samlUser.Id,
|
|
"code_challenge": codeChallenge,
|
|
"code_challenge_method": "S256",
|
|
"state": state,
|
|
}
|
|
|
|
token := model.NewToken(model.TokenTypeSSOCodeExchange, model.MapToJSON(extra))
|
|
require.NoError(t, th.App.Srv().Store().Token().Save(token))
|
|
|
|
props := map[string]string{
|
|
"login_code": token.Token,
|
|
"code_verifier": codeVerifier,
|
|
"state": state,
|
|
}
|
|
|
|
resp, err := th.Client.DoAPIPost(context.Background(), "/users/login/sso/code-exchange", model.MapToJSON(props))
|
|
require.NoError(t, err)
|
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
var result map[string]string
|
|
require.NoError(t, json.NewDecoder(resp.Body).Decode(&result))
|
|
assert.NotEmpty(t, result["token"])
|
|
assert.NotEmpty(t, result["csrf"])
|
|
|
|
_, err = th.App.Srv().Store().Token().GetByToken(token.Token)
|
|
require.Error(t, err)
|
|
|
|
authenticatedClient := model.NewAPIv4Client(th.Client.URL)
|
|
authenticatedClient.SetToken(result["token"])
|
|
|
|
user, _, err := authenticatedClient.GetMe(context.Background(), "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, samlUser.Id, user.Id)
|
|
assert.Equal(t, samlUser.Email, user.Email)
|
|
assert.Equal(t, samlUser.Username, user.Username)
|
|
})
|
|
}
|
|
|
|
func TestGetUsersByNames(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
t.Run("Get users by valid usernames", func(t *testing.T) {
|
|
users, _, err := th.Client.GetUsersByUsernames(context.Background(), []string{th.BasicUser.Username, th.BasicUser2.Username})
|
|
require.NoError(t, err)
|
|
require.ElementsMatch(t, []string{th.BasicUser.Username, th.BasicUser2.Username}, []string{users[0].Username, users[1].Username})
|
|
|
|
for _, user := range users {
|
|
CheckUserSanitization(t, user)
|
|
}
|
|
})
|
|
|
|
t.Run("Get users by invalid usernames", func(t *testing.T) {
|
|
users, resp, err := th.Client.GetUsersByUsernames(context.Background(), []string{"invalid1", "invalid2"})
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Empty(t, users)
|
|
})
|
|
|
|
t.Run("Get users by mixed valid and invalid usernames", func(t *testing.T) {
|
|
users, resp, err := th.Client.GetUsersByUsernames(context.Background(), []string{th.BasicUser.Username, "invalid"})
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.ElementsMatch(t, []string{th.BasicUser.Username}, []string{users[0].Username})
|
|
|
|
for _, user := range users {
|
|
CheckUserSanitization(t, user)
|
|
}
|
|
})
|
|
|
|
t.Run("Get users by empty slice", func(t *testing.T) {
|
|
_, resp, err := th.Client.GetUsersByUsernames(context.Background(), []string{})
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Get users without permissions", func(t *testing.T) {
|
|
_, err := th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
defer th.LoginBasic(t) // Ensure the client is logged back in after the test
|
|
|
|
_, resp, err := th.Client.GetUsersByUsernames(context.Background(), []string{th.BasicUser.Username})
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Get users as system admin", func(t *testing.T) {
|
|
users, resp, err := th.SystemAdminClient.GetUsersByUsernames(context.Background(), []string{th.BasicUser.Username})
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.ElementsMatch(t, []string{th.BasicUser.Username}, []string{users[0].Username})
|
|
require.Len(t, users, 1)
|
|
CheckUserSanitization(t, users[0])
|
|
})
|
|
}
|
|
|
|
func TestGetFilteredUsersStats(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
t.Run("Get filtered users stats as system admin", func(t *testing.T) {
|
|
// Create an additional user and link them to the team
|
|
regularUser := th.CreateUser(t)
|
|
th.LinkUserToTeam(t, regularUser, th.BasicTeam)
|
|
|
|
options := &model.UserCountOptions{
|
|
TeamId: th.BasicTeam.Id,
|
|
IncludeDeleted: false,
|
|
IncludeBotAccounts: false,
|
|
IncludeRemoteUsers: false,
|
|
}
|
|
|
|
stats, resp, err := th.SystemAdminClient.GetFilteredUsersStats(context.Background(), options)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.NotNil(t, stats)
|
|
|
|
// We expect 4 users: BasicUser, BasicUser2, the newly created regularUser, and possibly a system admin or other pre-existing user
|
|
expectedCount := int64(4)
|
|
assert.Equal(t, expectedCount, stats.TotalUsersCount, "Unexpected user count")
|
|
})
|
|
|
|
t.Run("Get filtered users stats as regular user", func(t *testing.T) {
|
|
options := &model.UserCountOptions{
|
|
TeamId: th.BasicTeam.Id,
|
|
IncludeDeleted: false,
|
|
IncludeBotAccounts: false,
|
|
IncludeRemoteUsers: false,
|
|
}
|
|
_, resp, err := th.Client.GetFilteredUsersStats(context.Background(), options)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Get filtered users stats with invalid team id", func(t *testing.T) {
|
|
options := &model.UserCountOptions{
|
|
TeamId: "invalid_team_id",
|
|
IncludeDeleted: false,
|
|
IncludeBotAccounts: false,
|
|
IncludeRemoteUsers: false,
|
|
}
|
|
stats, resp, err := th.SystemAdminClient.GetFilteredUsersStats(context.Background(), options)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.NotNil(t, stats)
|
|
// The server seems to return stats even with an invalid team ID
|
|
// We should check that the returned stats make sense in this context
|
|
require.Equal(t, int64(0), stats.TotalUsersCount, "Expected 0 users for an invalid team ID")
|
|
})
|
|
|
|
t.Run("Get filtered users stats with roles", func(t *testing.T) {
|
|
options := model.UserCountOptions{
|
|
TeamId: th.BasicTeam.Id,
|
|
IncludeDeleted: false,
|
|
IncludeBotAccounts: false,
|
|
IncludeRemoteUsers: false,
|
|
Roles: []string{model.SystemUserRoleId},
|
|
}
|
|
|
|
// Get the actual count from the server
|
|
actualCount, err := th.App.Srv().Store().User().Count(options)
|
|
require.NoError(t, err)
|
|
|
|
// Get the count from the client
|
|
stats, resp, err := th.SystemAdminClient.GetFilteredUsersStats(context.Background(), &options)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.NotNil(t, stats)
|
|
|
|
// Compare the counts
|
|
assert.Equal(t, actualCount, stats.TotalUsersCount, "Client-side count should match server-side count")
|
|
assert.True(t, stats.TotalUsersCount > 0, "There should be at least one user")
|
|
})
|
|
|
|
t.Run("Get filtered users stats with team roles", func(t *testing.T) {
|
|
options := model.UserCountOptions{
|
|
TeamId: th.BasicTeam.Id,
|
|
IncludeDeleted: false,
|
|
IncludeBotAccounts: false,
|
|
IncludeRemoteUsers: false,
|
|
TeamRoles: []string{model.TeamUserRoleId},
|
|
}
|
|
|
|
// Get the actual count from the server
|
|
actualCount, err := th.App.Srv().Store().User().Count(options)
|
|
require.NoError(t, err)
|
|
|
|
// Get the count from the client
|
|
stats, resp, err := th.SystemAdminClient.GetFilteredUsersStats(context.Background(), &options)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.NotNil(t, stats)
|
|
|
|
// Compare the counts
|
|
assert.Equal(t, actualCount, stats.TotalUsersCount, "Client-side count should match server-side count")
|
|
assert.True(t, stats.TotalUsersCount > 0, "There should be at least one user with the specified team role")
|
|
})
|
|
}
|
|
|
|
func TestGetDefaultProfileImage(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
t.Run("Get default profile image for existing user", func(t *testing.T) {
|
|
user := th.BasicUser
|
|
|
|
img, resp, err := th.Client.GetDefaultProfileImage(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, img)
|
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
// Check if the image is a valid PNG
|
|
_, err = png.Decode(bytes.NewReader(img))
|
|
require.NoError(t, err, "Image should be a valid PNG")
|
|
})
|
|
|
|
t.Run("Get default profile image for non-existent user", func(t *testing.T) {
|
|
nonExistentUserId := model.NewId()
|
|
|
|
_, resp, err := th.Client.GetDefaultProfileImage(context.Background(), nonExistentUserId)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Get default profile image without proper permissions", func(t *testing.T) {
|
|
user := th.CreateUser(t)
|
|
|
|
_, err := th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, resp, err := th.Client.GetDefaultProfileImage(context.Background(), user.Id)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Get default profile image as system admin", func(t *testing.T) {
|
|
user := th.CreateUser(t)
|
|
|
|
img, resp, err := th.SystemAdminClient.GetDefaultProfileImage(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, img)
|
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
_, err = png.Decode(bytes.NewReader(img))
|
|
require.NoError(t, err, "Image should be a valid PNG")
|
|
})
|
|
|
|
t.Run("Consistent default image for the same user", func(t *testing.T) {
|
|
user := th.CreateUser(t)
|
|
|
|
// Login as the newly created user
|
|
_, _, err := th.Client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
img1, resp, err := th.Client.GetDefaultProfileImage(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
img2, resp, err := th.Client.GetDefaultProfileImage(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
require.Equal(t, img1, img2, "Default profile images should be consistent for the same user")
|
|
|
|
// Logout after the test
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestGetUserThread(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
client := th.Client
|
|
user := th.BasicUser
|
|
team := th.BasicTeam
|
|
|
|
t.Run("get thread for user", func(t *testing.T) {
|
|
// Create a post
|
|
post, _, err := client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "Root message",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Create a reply to ensure thread membership
|
|
_, _, err = client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
RootId: post.Id,
|
|
Message: "Reply",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Get the thread
|
|
thread, resp, err := client.GetUserThread(context.Background(), user.Id, team.Id, post.Id, false)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.NotNil(t, thread)
|
|
require.Equal(t, post.Id, thread.PostId)
|
|
require.Equal(t, int64(1), thread.ReplyCount)
|
|
})
|
|
|
|
t.Run("get thread for user with extended info", func(t *testing.T) {
|
|
post, _, err := client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "Root message for extended info",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Create a reply to ensure thread membership
|
|
_, _, err = client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
RootId: post.Id,
|
|
Message: "Reply for extended info",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
thread, resp, err := client.GetUserThread(context.Background(), user.Id, team.Id, post.Id, true)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.NotNil(t, thread)
|
|
require.NotNil(t, thread.Participants)
|
|
})
|
|
|
|
t.Run("get thread for non-existent post", func(t *testing.T) {
|
|
_, resp, err := client.GetUserThread(context.Background(), user.Id, team.Id, model.NewId(), false)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("get thread without permissions", func(t *testing.T) {
|
|
post, _, err := client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "Root message for permissions test",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Log out
|
|
_, err = client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := client.GetUserThread(context.Background(), user.Id, team.Id, post.Id, false)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
|
|
t.Run("get thread for different user", func(t *testing.T) {
|
|
// Log back in
|
|
_, _, err := client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
post, _, err := client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "Root message for different user test",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Try to get thread for a different user
|
|
_, resp, err := client.GetUserThread(context.Background(), th.BasicUser2.Id, team.Id, post.Id, false)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("get thread as system admin", func(t *testing.T) {
|
|
// Create a post as the system admin
|
|
post, _, err := th.SystemAdminClient.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "Root message for system admin test",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Have the basic user reply to the post to create a thread membership
|
|
_, _, err = client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
RootId: post.Id,
|
|
Message: "Reply from basic user",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Now try to get the thread as the system admin
|
|
thread, resp, err := th.SystemAdminClient.GetUserThread(context.Background(), user.Id, team.Id, post.Id, false)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.NotNil(t, thread)
|
|
require.Equal(t, post.Id, thread.PostId)
|
|
require.Equal(t, int64(1), thread.ReplyCount)
|
|
})
|
|
}
|
|
|
|
func TestUpdateReadStateThreadByUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
client := th.Client
|
|
user := th.BasicUser
|
|
team := th.BasicTeam
|
|
|
|
t.Run("update read state for thread", func(t *testing.T) {
|
|
// Create a post
|
|
post, _, err := client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "Root message",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Create a reply to ensure thread membership
|
|
_, _, err = client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
RootId: post.Id,
|
|
Message: "Reply",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Update read state for the thread
|
|
timestamp := model.GetMillis()
|
|
thread, resp, err := client.UpdateThreadReadForUser(context.Background(), user.Id, team.Id, post.Id, timestamp)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.NotNil(t, thread)
|
|
require.Equal(t, post.Id, thread.PostId)
|
|
require.Equal(t, timestamp, thread.LastViewedAt)
|
|
})
|
|
|
|
t.Run("update read state for non-existent thread", func(t *testing.T) {
|
|
// Attempting to update read state for a non-existent thread results in a Forbidden error
|
|
// This is likely because the user doesn't have permission to access the non-existent thread
|
|
nonExistentPostId := model.NewId()
|
|
_, resp, err := client.UpdateThreadReadForUser(context.Background(), user.Id, team.Id, nonExistentPostId, model.GetMillis())
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
t.Run("update read state without permissions", func(t *testing.T) {
|
|
// Create a post
|
|
post, _, err := client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "Root message for permissions test",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Log out
|
|
_, err = client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := client.UpdateThreadReadForUser(context.Background(), user.Id, team.Id, post.Id, model.GetMillis())
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
|
|
t.Run("update read state for different user", func(t *testing.T) {
|
|
// Log back in
|
|
_, _, err := client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
post, _, err := client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "Root message for different user test",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Try to update read state for a different user
|
|
_, resp, err := client.UpdateThreadReadForUser(context.Background(), th.BasicUser2.Id, team.Id, post.Id, model.GetMillis())
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestSetUnreadThreadByPostId(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
client := th.Client
|
|
user := th.BasicUser
|
|
team := th.BasicTeam
|
|
|
|
t.Run("set unread state for thread", func(t *testing.T) {
|
|
// Create a post
|
|
post, _, err := client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "Root message",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Create a reply to ensure thread membership
|
|
reply, _, err := client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
RootId: post.Id,
|
|
Message: "Reply",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Set unread state for the thread
|
|
thread, resp, err := client.SetThreadUnreadByPostId(context.Background(), user.Id, team.Id, post.Id, reply.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.NotNil(t, thread)
|
|
require.Equal(t, post.Id, thread.PostId)
|
|
|
|
// Check that LastReplyAt matches the creation time of the last reply
|
|
require.Equal(t, reply.CreateAt, thread.LastReplyAt, "LastReplyAt should match the creation time of the last reply")
|
|
|
|
// Check if the thread is marked as unread
|
|
require.True(t, thread.UnreadReplies > 0, "Thread should have unread replies")
|
|
|
|
// Check that UnreadMentions is 0 (assuming the reply didn't mention the user)
|
|
require.Equal(t, int64(0), thread.UnreadMentions, "UnreadMentions should be 0 if the reply didn't mention the user")
|
|
})
|
|
|
|
t.Run("set unread state for non-existent thread", func(t *testing.T) {
|
|
nonExistentPostId := model.NewId()
|
|
_, resp, err := client.SetThreadUnreadByPostId(context.Background(), user.Id, team.Id, nonExistentPostId, nonExistentPostId)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("set unread state without permissions", func(t *testing.T) {
|
|
// Create a post
|
|
post, _, err := client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "Root message for permissions test",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Log out
|
|
_, err = client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := client.SetThreadUnreadByPostId(context.Background(), user.Id, team.Id, post.Id, post.Id)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
|
|
t.Run("set unread state for different user", func(t *testing.T) {
|
|
// Log back in
|
|
_, _, err := client.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
post, _, err := client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "Root message for different user test",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Try to set unread state for a different user
|
|
_, resp, err := client.SetThreadUnreadByPostId(context.Background(), th.BasicUser2.Id, team.Id, post.Id, post.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("set unread state as system admin", func(t *testing.T) {
|
|
post, _, err := th.SystemAdminClient.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "Root message for system admin test",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
reply, _, err := th.SystemAdminClient.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
RootId: post.Id,
|
|
Message: "Reply for system admin test",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
thread, resp, err := th.SystemAdminClient.SetThreadUnreadByPostId(context.Background(), user.Id, team.Id, post.Id, reply.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.NotNil(t, thread)
|
|
require.Equal(t, post.Id, thread.PostId)
|
|
|
|
// Check that LastReplyAt is a recent timestamp
|
|
require.Greater(t, thread.LastReplyAt, int64(0))
|
|
require.LessOrEqual(t, thread.LastReplyAt, model.GetMillis())
|
|
|
|
// Check if the thread is marked as unread
|
|
require.True(t, thread.UnreadReplies > 0, "Thread should have unread replies")
|
|
|
|
require.InDelta(t, model.GetMillis(), thread.LastReplyAt, float64(5000), "LastReplyAt should be within 5 seconds of current time")
|
|
})
|
|
}
|
|
|
|
func TestRevokeAllSessionsForUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user := th.BasicUser
|
|
user2 := th.BasicUser2 // Additional user for permission testing
|
|
|
|
// Create multiple sessions for the primary user
|
|
client1 := th.CreateClient()
|
|
_, _, err := client1.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
client2 := th.CreateClient()
|
|
_, _, err = client2.Login(context.Background(), user.Email, user.Password)
|
|
require.NoError(t, err)
|
|
|
|
// Create a session for the second user (non-admin)
|
|
nonAdminClient := th.CreateClient()
|
|
_, _, err = nonAdminClient.Login(context.Background(), user2.Email, user2.Password)
|
|
require.NoError(t, err)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
resp, err := th.SystemAdminClient.RevokeAllSessions(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
// Use SystemAdminClient to verify that all sessions are revoked
|
|
sessions, _, err := th.SystemAdminClient.GetSessions(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
require.Empty(t, sessions, "All sessions should be revoked")
|
|
}, "Revoke all sessions as admin and local")
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
fakeUserId := "invalid_user_id"
|
|
resp, err := client.RevokeAllSessions(context.Background(), fakeUserId)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
}, "Revoke all sessions for non-existent user")
|
|
|
|
t.Run("Revoke all sessions without permissions", func(t *testing.T) {
|
|
// Attempt to revoke sessions of the primary user using a non-admin client
|
|
resp, err := nonAdminClient.RevokeAllSessions(context.Background(), user.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestResetPasswordFailedAttempts(t *testing.T) {
|
|
th := SetupEnterprise(t).InitBasic(t)
|
|
th.SetupLdapConfig()
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
t.Run("Reset password failed attempts for regular user", func(t *testing.T) {
|
|
client := th.CreateClient()
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.MaximumLoginAttempts = 10
|
|
})
|
|
maxAttempts := th.App.Config().ServiceSettings.MaximumLoginAttempts
|
|
|
|
user := th.CreateUser(t)
|
|
|
|
for i := 0; i < *maxAttempts; i++ {
|
|
_, _, err := client.Login(context.Background(), user.Email, "wrongpassword")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
user, resp, err := th.SystemAdminClient.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, *maxAttempts, user.FailedAttempts)
|
|
|
|
resp, err = th.SystemAdminClient.ResetFailedAttempts(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
user, resp, err = th.SystemAdminClient.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, int(0), user.FailedAttempts)
|
|
})
|
|
|
|
t.Run("Reset password failed attempts for ldap user", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.LdapSettings.MaximumLoginAttempts = 5
|
|
})
|
|
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
|
|
mockLdap := &mocks.LdapInterface{}
|
|
|
|
username := GenerateTestUsername()
|
|
|
|
ldapUser := &model.User{
|
|
Email: "foobar+testdomainrestriction@mattermost.org",
|
|
Username: username,
|
|
AuthService: "ldap",
|
|
AuthData: &username,
|
|
EmailVerified: true,
|
|
}
|
|
ldapUser, appErr := th.App.CreateUser(th.Context, ldapUser)
|
|
require.Nil(t, appErr)
|
|
|
|
client := th.CreateClient()
|
|
mockLdap.Mock.On("GetUser", mock.AnythingOfType("*request.Context"), mock.AnythingOfType("string")).Return(ldapUser, nil).Times(5)
|
|
|
|
th.App.Channels().Ldap = mockLdap
|
|
|
|
for i := range 5 {
|
|
mockedLdapUser := ldapUser
|
|
mockedLdapUser.FailedAttempts = i
|
|
mockLdap.Mock.On("DoLogin", mock.AnythingOfType("*request.Context"), mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(mockedLdapUser, &model.AppError{Id: "ent.ldap.do_login.invalid_password.app_error"})
|
|
_, _, err := client.LoginByLdap(context.Background(), *ldapUser.AuthData, "wrongpassword")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
user, resp, err := th.SystemAdminClient.GetUser(context.Background(), ldapUser.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, int(5), user.FailedAttempts)
|
|
|
|
resp, err = th.SystemAdminClient.ResetFailedAttempts(context.Background(), ldapUser.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
user, resp, err = th.SystemAdminClient.GetUser(context.Background(), ldapUser.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, int(0), user.FailedAttempts)
|
|
})
|
|
|
|
t.Run("Regular user unable to reset failed attempts", func(t *testing.T) {
|
|
client := th.CreateClient()
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.MaximumLoginAttempts = 10
|
|
})
|
|
maxAttempts := th.App.Config().ServiceSettings.MaximumLoginAttempts
|
|
|
|
user := th.CreateUser(t)
|
|
|
|
for i := 0; i < *maxAttempts; i++ {
|
|
_, _, err := client.Login(context.Background(), user.Email, "wrongpassword")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
user, resp, err := th.SystemAdminClient.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, *maxAttempts, user.FailedAttempts)
|
|
|
|
resp, err = th.Client.ResetFailedAttempts(context.Background(), user.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
user, resp, err = th.SystemAdminClient.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, *maxAttempts, user.FailedAttempts)
|
|
})
|
|
|
|
t.Run("Reset password failed attempts when user has PermissionSysconsoleWriteUserManagementUsers", func(t *testing.T) {
|
|
th.AddPermissionToRole(t, model.PermissionSysconsoleWriteUserManagementUsers.Id, model.SystemUserRoleId)
|
|
defer th.RemovePermissionFromRole(t, model.PermissionSysconsoleWriteUserManagementUsers.Id, model.SystemUserRoleId)
|
|
|
|
client := th.CreateClient()
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.MaximumLoginAttempts = 10
|
|
})
|
|
maxAttempts := th.App.Config().ServiceSettings.MaximumLoginAttempts
|
|
|
|
user := th.CreateUser(t)
|
|
|
|
for i := 0; i < *maxAttempts; i++ {
|
|
_, _, err := client.Login(context.Background(), user.Email, "wrongpassword")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
fetchedUser, resp, err := th.SystemAdminClient.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, *maxAttempts, fetchedUser.FailedAttempts)
|
|
|
|
resp, err = th.Client.ResetFailedAttempts(context.Background(), user.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
fetchedUser, resp, err = th.SystemAdminClient.GetUser(context.Background(), user.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, int(0), fetchedUser.FailedAttempts)
|
|
})
|
|
|
|
t.Run("Unable to reset password failed attempts for sysadmin when user has PermissionSysconsoleWriteUserManagementUsers", func(t *testing.T) {
|
|
th.AddPermissionToRole(t, model.PermissionSysconsoleWriteUserManagementUsers.Id, model.SystemUserRoleId)
|
|
defer th.RemovePermissionFromRole(t, model.PermissionSysconsoleWriteUserManagementUsers.Id, model.SystemUserRoleId)
|
|
|
|
client := th.CreateClient()
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.MaximumLoginAttempts = 10
|
|
})
|
|
maxAttempts := th.App.Config().ServiceSettings.MaximumLoginAttempts
|
|
|
|
// create sysadmin user
|
|
sysadmin := th.CreateUser(t)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, sysadmin.Id, model.SystemUserRoleId+" "+model.SystemAdminRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
for i := 0; i < *maxAttempts; i++ {
|
|
_, _, err := client.Login(context.Background(), sysadmin.Email, "wrongpassword")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
sysadminUser, resp, err := th.SystemAdminClient.GetUser(context.Background(), sysadmin.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, *maxAttempts, sysadminUser.FailedAttempts)
|
|
|
|
resp, err = th.Client.ResetFailedAttempts(context.Background(), sysadminUser.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
|
|
sysadminUser, resp, err = th.SystemAdminClient.GetUser(context.Background(), sysadminUser.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, int(10), sysadminUser.FailedAttempts)
|
|
})
|
|
|
|
t.Run("Reset password failed attempts for sysadmin", func(t *testing.T) {
|
|
client := th.CreateClient()
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.MaximumLoginAttempts = 10
|
|
})
|
|
maxAttempts := th.App.Config().ServiceSettings.MaximumLoginAttempts
|
|
|
|
sysadmin := th.CreateUser(t)
|
|
_, appErr := th.App.UpdateUserRoles(th.Context, sysadmin.Id, model.SystemUserRoleId+" "+model.SystemAdminRoleId, false)
|
|
require.Nil(t, appErr)
|
|
|
|
for i := 0; i < *maxAttempts; i++ {
|
|
_, _, err := client.Login(context.Background(), sysadmin.Email, "wrongpassword")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
sysadminUser, resp, err := th.SystemAdminClient.GetUser(context.Background(), sysadmin.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, *maxAttempts, sysadminUser.FailedAttempts)
|
|
|
|
resp, err = th.SystemAdminClient.ResetFailedAttempts(context.Background(), sysadminUser.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
sysadminUser, resp, err = th.SystemAdminClient.GetUser(context.Background(), sysadminUser.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, int(0), sysadminUser.FailedAttempts)
|
|
})
|
|
}
|
|
|
|
func TestSearchUsersWithMfaEnforced(t *testing.T) {
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("mfa"))
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableMultifactorAuthentication = true
|
|
*cfg.ServiceSettings.EnforceMultifactorAuthentication = true
|
|
})
|
|
|
|
t.Run("user with MFA active can search users", func(t *testing.T) {
|
|
userWithMFAOK := th.BasicUser
|
|
secret, appErr := th.App.GenerateMfaSecret(userWithMFAOK.Id)
|
|
assert.Nil(t, appErr)
|
|
|
|
// Fake user has MFA enabled
|
|
err := th.Server.Store().User().UpdateMfaActive(userWithMFAOK.Id, true)
|
|
require.NoError(t, err)
|
|
|
|
err = th.Server.Store().User().UpdateMfaSecret(userWithMFAOK.Id, secret.Secret)
|
|
require.NoError(t, err)
|
|
|
|
code := dgoogauth.ComputeCode(secret.Secret, time.Now().UTC().Unix()/30)
|
|
|
|
client := th.CreateClient()
|
|
user, _, err := client.LoginWithMFA(context.Background(), th.BasicUser.Email, th.BasicUser.Password, fmt.Sprintf("%06d", code))
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, user)
|
|
|
|
_, _, err = client.SearchUsers(context.Background(), &model.UserSearch{
|
|
Term: "user",
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("user with MFA not active can't search users", func(t *testing.T) {
|
|
userWithMFANotOk := th.BasicUser2
|
|
err := th.Server.Store().User().UpdateMfaActive(userWithMFANotOk.Id, false)
|
|
require.NoError(t, err)
|
|
|
|
client := th.CreateClient()
|
|
_, _, err = client.Login(context.Background(), userWithMFANotOk.Email, userWithMFANotOk.Password)
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := client.SearchUsers(context.Background(), &model.UserSearch{
|
|
Term: "user",
|
|
})
|
|
CheckErrorID(t, err, "api.context.mfa_required.app_error")
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
}
|