mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
MM-11327: Restrict Teams by Email (#9142)
* Check a team's AllowedDomains setting before adding users to the team. * Updated AddUser tests to validate AllowedDomains restriction. * Updated variable name to match convention. * Removed AllowedDomains from team sanitization. * Update AppError's Where to match the calling function. * Added tests for user matching allowedDomains, and multi domain values of allowedDomains. * Added test to make sure we block users who have a subdomain of a whitelisted domain. * Revert "Removed AllowedDomains from team sanitization." This reverts commit 17c2afea584da40c7d769787ae86408e9700510c. * Update sanitization tests to include dockerhost, now that we enforce AllowedDomains. * Added tests to verify the interplay between the global and per team domain restrictions. * Validate AllowedDomains property against RestrictCreationToDomains before updating a team. * Remove team.AllowedDomains from sanitization. * Add i18n string for the team allowed domains restriction app error.
This commit is contained in:
committed by
Harrison Healey
parent
19e69681d7
commit
347ee1d205
@@ -96,15 +96,13 @@ func TestCreateTeamSanitization(t *testing.T) {
|
||||
Name: GenerateTestTeamName(),
|
||||
Email: th.GenerateTestEmail(),
|
||||
Type: model.TEAM_OPEN,
|
||||
AllowedDomains: "simulator.amazonses.com",
|
||||
AllowedDomains: "simulator.amazonses.com,dockerhost",
|
||||
}
|
||||
|
||||
rteam, resp := th.Client.CreateTeam(team)
|
||||
CheckNoError(t, resp)
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -114,15 +112,13 @@ func TestCreateTeamSanitization(t *testing.T) {
|
||||
Name: GenerateTestTeamName(),
|
||||
Email: th.GenerateTestEmail(),
|
||||
Type: model.TEAM_OPEN,
|
||||
AllowedDomains: "simulator.amazonses.com",
|
||||
AllowedDomains: "simulator.amazonses.com,dockerhost",
|
||||
}
|
||||
|
||||
rteam, resp := th.SystemAdminClient.CreateTeam(team)
|
||||
CheckNoError(t, resp)
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -183,7 +179,7 @@ func TestGetTeamSanitization(t *testing.T) {
|
||||
Name: GenerateTestTeamName(),
|
||||
Email: th.GenerateTestEmail(),
|
||||
Type: model.TEAM_OPEN,
|
||||
AllowedDomains: "simulator.amazonses.com",
|
||||
AllowedDomains: "simulator.amazonses.com,dockerhost",
|
||||
})
|
||||
CheckNoError(t, resp)
|
||||
|
||||
@@ -197,8 +193,6 @@ func TestGetTeamSanitization(t *testing.T) {
|
||||
CheckNoError(t, resp)
|
||||
if rteam.Email != "" {
|
||||
t.Fatal("should've sanitized email")
|
||||
} else if rteam.AllowedDomains != "" {
|
||||
t.Fatal("should've sanitized allowed domains")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -207,8 +201,6 @@ func TestGetTeamSanitization(t *testing.T) {
|
||||
CheckNoError(t, resp)
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -217,8 +209,6 @@ func TestGetTeamSanitization(t *testing.T) {
|
||||
CheckNoError(t, resp)
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -364,7 +354,7 @@ func TestUpdateTeamSanitization(t *testing.T) {
|
||||
Name: GenerateTestTeamName(),
|
||||
Email: th.GenerateTestEmail(),
|
||||
Type: model.TEAM_OPEN,
|
||||
AllowedDomains: "simulator.amazonses.com",
|
||||
AllowedDomains: "simulator.amazonses.com,dockerhost",
|
||||
})
|
||||
CheckNoError(t, resp)
|
||||
|
||||
@@ -375,8 +365,6 @@ func TestUpdateTeamSanitization(t *testing.T) {
|
||||
CheckNoError(t, resp)
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email for admin")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -385,8 +373,6 @@ func TestUpdateTeamSanitization(t *testing.T) {
|
||||
CheckNoError(t, resp)
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email for admin")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -463,7 +449,7 @@ func TestPatchTeamSanitization(t *testing.T) {
|
||||
Name: GenerateTestTeamName(),
|
||||
Email: th.GenerateTestEmail(),
|
||||
Type: model.TEAM_OPEN,
|
||||
AllowedDomains: "simulator.amazonses.com",
|
||||
AllowedDomains: "simulator.amazonses.com,dockerhost",
|
||||
})
|
||||
CheckNoError(t, resp)
|
||||
|
||||
@@ -474,8 +460,6 @@ func TestPatchTeamSanitization(t *testing.T) {
|
||||
CheckNoError(t, resp)
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email for admin")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -484,8 +468,6 @@ func TestPatchTeamSanitization(t *testing.T) {
|
||||
CheckNoError(t, resp)
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email for admin")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -655,7 +637,7 @@ func TestGetAllTeamsSanitization(t *testing.T) {
|
||||
Name: GenerateTestTeamName(),
|
||||
Email: th.GenerateTestEmail(),
|
||||
Type: model.TEAM_OPEN,
|
||||
AllowedDomains: "simulator.amazonses.com",
|
||||
AllowedDomains: "simulator.amazonses.com,dockerhost",
|
||||
AllowOpenInvite: true,
|
||||
})
|
||||
CheckNoError(t, resp)
|
||||
@@ -664,7 +646,7 @@ func TestGetAllTeamsSanitization(t *testing.T) {
|
||||
Name: GenerateTestTeamName(),
|
||||
Email: th.GenerateTestEmail(),
|
||||
Type: model.TEAM_OPEN,
|
||||
AllowedDomains: "simulator.amazonses.com",
|
||||
AllowedDomains: "simulator.amazonses.com,dockerhost",
|
||||
AllowOpenInvite: true,
|
||||
})
|
||||
CheckNoError(t, resp)
|
||||
@@ -682,15 +664,11 @@ func TestGetAllTeamsSanitization(t *testing.T) {
|
||||
teamFound = true
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email for team admin")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains for team admin")
|
||||
}
|
||||
} else if rteam.Id == team2.Id {
|
||||
team2Found = true
|
||||
if rteam.Email != "" {
|
||||
t.Fatal("should've sanitized email for non-admin")
|
||||
} else if rteam.AllowedDomains != "" {
|
||||
t.Fatal("should've sanitized allowed domains for non-admin")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -710,8 +688,6 @@ func TestGetAllTeamsSanitization(t *testing.T) {
|
||||
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -773,7 +749,7 @@ func TestGetTeamByNameSanitization(t *testing.T) {
|
||||
Name: GenerateTestTeamName(),
|
||||
Email: th.GenerateTestEmail(),
|
||||
Type: model.TEAM_OPEN,
|
||||
AllowedDomains: "simulator.amazonses.com",
|
||||
AllowedDomains: "simulator.amazonses.com,dockerhost",
|
||||
})
|
||||
CheckNoError(t, resp)
|
||||
|
||||
@@ -787,8 +763,6 @@ func TestGetTeamByNameSanitization(t *testing.T) {
|
||||
CheckNoError(t, resp)
|
||||
if rteam.Email != "" {
|
||||
t.Fatal("should've sanitized email")
|
||||
} else if rteam.AllowedDomains != "" {
|
||||
t.Fatal("should've sanitized allowed domains")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -797,8 +771,6 @@ func TestGetTeamByNameSanitization(t *testing.T) {
|
||||
CheckNoError(t, resp)
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -807,8 +779,6 @@ func TestGetTeamByNameSanitization(t *testing.T) {
|
||||
CheckNoError(t, resp)
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -904,7 +874,7 @@ func TestSearchAllTeamsSanitization(t *testing.T) {
|
||||
Name: GenerateTestTeamName(),
|
||||
Email: th.GenerateTestEmail(),
|
||||
Type: model.TEAM_OPEN,
|
||||
AllowedDomains: "simulator.amazonses.com",
|
||||
AllowedDomains: "simulator.amazonses.com,dockerhost",
|
||||
})
|
||||
CheckNoError(t, resp)
|
||||
team2, resp := th.Client.CreateTeam(&model.Team{
|
||||
@@ -912,7 +882,7 @@ func TestSearchAllTeamsSanitization(t *testing.T) {
|
||||
Name: GenerateTestTeamName(),
|
||||
Email: th.GenerateTestEmail(),
|
||||
Type: model.TEAM_OPEN,
|
||||
AllowedDomains: "simulator.amazonses.com",
|
||||
AllowedDomains: "simulator.amazonses.com,dockerhost",
|
||||
})
|
||||
CheckNoError(t, resp)
|
||||
|
||||
@@ -955,8 +925,6 @@ func TestSearchAllTeamsSanitization(t *testing.T) {
|
||||
if rteam.Id == team.Id || rteam.Id == team2.Id || rteam.Id == th.BasicTeam.Id {
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -968,8 +936,6 @@ func TestSearchAllTeamsSanitization(t *testing.T) {
|
||||
for _, rteam := range rteams {
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1026,7 +992,7 @@ func TestGetTeamsForUserSanitization(t *testing.T) {
|
||||
Name: GenerateTestTeamName(),
|
||||
Email: th.GenerateTestEmail(),
|
||||
Type: model.TEAM_OPEN,
|
||||
AllowedDomains: "simulator.amazonses.com",
|
||||
AllowedDomains: "simulator.amazonses.com,dockerhost",
|
||||
})
|
||||
CheckNoError(t, resp)
|
||||
team2, resp := th.Client.CreateTeam(&model.Team{
|
||||
@@ -1034,7 +1000,7 @@ func TestGetTeamsForUserSanitization(t *testing.T) {
|
||||
Name: GenerateTestTeamName(),
|
||||
Email: th.GenerateTestEmail(),
|
||||
Type: model.TEAM_OPEN,
|
||||
AllowedDomains: "simulator.amazonses.com",
|
||||
AllowedDomains: "simulator.amazonses.com,dockerhost",
|
||||
})
|
||||
CheckNoError(t, resp)
|
||||
|
||||
@@ -1054,8 +1020,6 @@ func TestGetTeamsForUserSanitization(t *testing.T) {
|
||||
|
||||
if rteam.Email != "" {
|
||||
t.Fatal("should've sanitized email")
|
||||
} else if rteam.AllowedDomains != "" {
|
||||
t.Fatal("should've sanitized allowed domains")
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1070,8 +1034,6 @@ func TestGetTeamsForUserSanitization(t *testing.T) {
|
||||
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1086,8 +1048,6 @@ func TestGetTeamsForUserSanitization(t *testing.T) {
|
||||
|
||||
if rteam.Email == "" {
|
||||
t.Fatal("should not have sanitized email")
|
||||
} else if rteam.AllowedDomains == "" {
|
||||
t.Fatal("should not have sanitized allowed domains")
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1993,17 +1953,48 @@ func TestInviteUsersToTeam(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.RestrictCreationToDomains = "@example.com" })
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.RestrictCreationToDomains = "@global.com,@common.com" })
|
||||
|
||||
err := th.App.InviteNewUsersToTeam(emailList, th.BasicTeam.Id, th.BasicUser.Id)
|
||||
t.Run("restricted domains", func(t *testing.T) {
|
||||
err := th.App.InviteNewUsersToTeam(emailList, th.BasicTeam.Id, th.BasicUser.Id)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("Adding users with non-restricted domains was allowed")
|
||||
}
|
||||
if err.Where != "InviteNewUsersToTeam" || err.Id != "api.team.invite_members.invalid_email.app_error" {
|
||||
t.Log(err)
|
||||
t.Fatal("Got wrong error message!")
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("Adding users with non-restricted domains was allowed")
|
||||
}
|
||||
if err.Where != "InviteNewUsersToTeam" || err.Id != "api.team.invite_members.invalid_email.app_error" {
|
||||
t.Log(err)
|
||||
t.Fatal("Got wrong error message!")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("override restricted domains", func(t *testing.T) {
|
||||
th.BasicTeam.AllowedDomains = "invalid.com,common.com"
|
||||
if _, err := th.App.UpdateTeam(th.BasicTeam); err == nil {
|
||||
t.Fatal("Should not update the team")
|
||||
}
|
||||
|
||||
th.BasicTeam.AllowedDomains = "common.com"
|
||||
if _, err := th.App.UpdateTeam(th.BasicTeam); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should update the team")
|
||||
}
|
||||
|
||||
if err := th.App.InviteNewUsersToTeam([]string{"test@global.com"}, th.BasicTeam.Id, th.BasicUser.Id); err == nil || err.Where != "InviteNewUsersToTeam" {
|
||||
t.Log(err)
|
||||
t.Fatal("Per team restriction should take precedence over the global restriction")
|
||||
}
|
||||
|
||||
if err := th.App.InviteNewUsersToTeam([]string{"test@common.com"}, th.BasicTeam.Id, th.BasicUser.Id); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Failed to invite user which was common between team and global domain restriction")
|
||||
}
|
||||
|
||||
if err := th.App.InviteNewUsersToTeam([]string{"test@invalid.com"}, th.BasicTeam.Id, th.BasicUser.Id); err == nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should not invite user")
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetTeamInviteInfo(t *testing.T) {
|
||||
|
||||
86
app/team.go
86
app/team.go
@@ -44,7 +44,7 @@ func (a *App) CreateTeamWithUser(team *model.Team, userId string) (*model.Team,
|
||||
team.Email = user.Email
|
||||
}
|
||||
|
||||
if !a.isTeamEmailAllowed(user) {
|
||||
if !a.isTeamEmailAllowed(user, team) {
|
||||
return nil, model.NewAppError("isTeamEmailAllowed", "api.team.is_team_creation_allowed.domain.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
@@ -60,35 +60,43 @@ func (a *App) CreateTeamWithUser(team *model.Team, userId string) (*model.Team,
|
||||
return rteam, nil
|
||||
}
|
||||
|
||||
func (a *App) isTeamEmailAddressAllowed(email string) bool {
|
||||
email = strings.ToLower(email)
|
||||
func (a *App) normalizeDomains(domains string) []string {
|
||||
// commas and @ signs are optional
|
||||
// can be in the form of "@corp.mattermost.com, mattermost.com mattermost.org" -> corp.mattermost.com mattermost.com mattermost.org
|
||||
domains := strings.Fields(strings.TrimSpace(strings.ToLower(strings.Replace(strings.Replace(a.Config().TeamSettings.RestrictCreationToDomains, "@", " ", -1), ",", " ", -1))))
|
||||
return strings.Fields(strings.TrimSpace(strings.ToLower(strings.Replace(strings.Replace(domains, "@", " ", -1), ",", " ", -1))))
|
||||
}
|
||||
|
||||
matched := false
|
||||
for _, d := range domains {
|
||||
if strings.HasSuffix(email, "@"+d) {
|
||||
matched = true
|
||||
break
|
||||
func (a *App) isTeamEmailAddressAllowed(email string, allowedDomains string) bool {
|
||||
email = strings.ToLower(email)
|
||||
// First check per team allowedDomains, then app wide restrictions
|
||||
for _, restriction := range []string{allowedDomains, a.Config().TeamSettings.RestrictCreationToDomains} {
|
||||
domains := a.normalizeDomains(restriction)
|
||||
if len(domains) <= 0 {
|
||||
continue
|
||||
}
|
||||
matched := false
|
||||
for _, d := range domains {
|
||||
if strings.HasSuffix(email, "@"+d) {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if len(a.Config().TeamSettings.RestrictCreationToDomains) > 0 && !matched {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *App) isTeamEmailAllowed(user *model.User) bool {
|
||||
func (a *App) isTeamEmailAllowed(user *model.User, team *model.Team) bool {
|
||||
email := strings.ToLower(user.Email)
|
||||
|
||||
if len(user.AuthService) > 0 && len(*user.AuthData) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return a.isTeamEmailAddressAllowed(email)
|
||||
return a.isTeamEmailAddressAllowed(email, team.AllowedDomains)
|
||||
}
|
||||
|
||||
func (a *App) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) {
|
||||
@@ -98,6 +106,23 @@ func (a *App) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
validDomains := a.normalizeDomains(a.Config().TeamSettings.RestrictCreationToDomains)
|
||||
if len(validDomains) > 0 {
|
||||
for _, domain := range a.normalizeDomains(team.AllowedDomains) {
|
||||
matched := false
|
||||
for _, d := range validDomains {
|
||||
if domain == d {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
err := model.NewAppError("UpdateTeam", "api.team.update_restricted_domains.mismatch.app_error", map[string]interface{}{"Domain": domain}, "", http.StatusBadRequest)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
oldTeam.DisplayName = team.DisplayName
|
||||
oldTeam.Description = team.Description
|
||||
oldTeam.InviteId = team.InviteId
|
||||
@@ -430,6 +455,9 @@ func (a *App) joinUserToTeam(team *model.Team, user *model.User) (*model.TeamMem
|
||||
}
|
||||
|
||||
func (a *App) JoinUserToTeam(team *model.Team, user *model.User, userRequestorId string) *model.AppError {
|
||||
if !a.isTeamEmailAllowed(user, team) {
|
||||
return model.NewAppError("JoinUserToTeam", "api.team.join_user_to_team.allowed_domains.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
tm, alreadyAdded, err := a.joinUserToTeam(team, user)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -843,20 +871,6 @@ func (a *App) InviteNewUsersToTeam(emailList []string, teamId, senderId string)
|
||||
return err
|
||||
}
|
||||
|
||||
var invalidEmailList []string
|
||||
|
||||
for _, email := range emailList {
|
||||
if !a.isTeamEmailAddressAllowed(email) {
|
||||
invalidEmailList = append(invalidEmailList, email)
|
||||
}
|
||||
}
|
||||
|
||||
if len(invalidEmailList) > 0 {
|
||||
s := strings.Join(invalidEmailList, ", ")
|
||||
err := model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.invalid_email.app_error", map[string]interface{}{"Addresses": s}, "", http.StatusBadRequest)
|
||||
return err
|
||||
}
|
||||
|
||||
tchan := a.Srv.Store.Team().Get(teamId)
|
||||
uchan := a.Srv.Store.User().Get(senderId)
|
||||
|
||||
@@ -874,6 +888,20 @@ func (a *App) InviteNewUsersToTeam(emailList []string, teamId, senderId string)
|
||||
user = result.Data.(*model.User)
|
||||
}
|
||||
|
||||
var invalidEmailList []string
|
||||
|
||||
for _, email := range emailList {
|
||||
if !a.isTeamEmailAddressAllowed(email, team.AllowedDomains) {
|
||||
invalidEmailList = append(invalidEmailList, email)
|
||||
}
|
||||
}
|
||||
|
||||
if len(invalidEmailList) > 0 {
|
||||
s := strings.Join(invalidEmailList, ", ")
|
||||
err := model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.invalid_email.app_error", map[string]interface{}{"Addresses": s}, "", http.StatusBadRequest)
|
||||
return err
|
||||
}
|
||||
|
||||
nameFormat := *a.Config().TeamSettings.TeammateNameDisplay
|
||||
a.SendInviteEmails(team, user.GetDisplayName(nameFormat), user.Id, emailList, a.GetSiteURL())
|
||||
|
||||
|
||||
173
app/team_test.go
173
app/team_test.go
@@ -73,13 +73,99 @@ func TestAddUserToTeam(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
|
||||
ruser, _ := th.App.CreateUser(&user)
|
||||
t.Run("add user", func(t *testing.T) {
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
|
||||
ruser, _ := th.App.CreateUser(&user)
|
||||
defer th.App.PermanentDeleteUser(&user)
|
||||
|
||||
if _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, ""); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should add user to the team")
|
||||
}
|
||||
if _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, ""); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should add user to the team")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("allow user by domain", func(t *testing.T) {
|
||||
th.BasicTeam.AllowedDomains = "example.com"
|
||||
if _, err := th.App.UpdateTeam(th.BasicTeam); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should update the team")
|
||||
}
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
|
||||
ruser, _ := th.App.CreateUser(&user)
|
||||
defer th.App.PermanentDeleteUser(&user)
|
||||
|
||||
if _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, ""); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should have allowed whitelisted user")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("block user by domain", func(t *testing.T) {
|
||||
th.BasicTeam.AllowedDomains = "example.com"
|
||||
if _, err := th.App.UpdateTeam(th.BasicTeam); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should update the team")
|
||||
}
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "test@invalid.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
|
||||
ruser, _ := th.App.CreateUser(&user)
|
||||
defer th.App.PermanentDeleteUser(&user)
|
||||
|
||||
if _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, ""); err == nil || err.Where != "JoinUserToTeam" {
|
||||
t.Log(err)
|
||||
t.Fatal("Should not add restricted user")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("block user with subdomain", func(t *testing.T) {
|
||||
th.BasicTeam.AllowedDomains = "example.com"
|
||||
if _, err := th.App.UpdateTeam(th.BasicTeam); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should update the team")
|
||||
}
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "test@invalid.example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
|
||||
ruser, _ := th.App.CreateUser(&user)
|
||||
defer th.App.PermanentDeleteUser(&user)
|
||||
|
||||
if _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, ""); err == nil || err.Where != "JoinUserToTeam" {
|
||||
t.Log(err)
|
||||
t.Fatal("Should not add restricted user")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("allow users by multiple domains", func(t *testing.T) {
|
||||
th.BasicTeam.AllowedDomains = "foo.com, bar.com"
|
||||
if _, err := th.App.UpdateTeam(th.BasicTeam); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should update the team")
|
||||
}
|
||||
|
||||
user1 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@foo.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
|
||||
ruser1, _ := th.App.CreateUser(&user1)
|
||||
user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@bar.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
|
||||
ruser2, _ := th.App.CreateUser(&user2)
|
||||
user3 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@invalid.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
|
||||
ruser3, _ := th.App.CreateUser(&user3)
|
||||
defer th.App.PermanentDeleteUser(&user1)
|
||||
defer th.App.PermanentDeleteUser(&user2)
|
||||
defer th.App.PermanentDeleteUser(&user3)
|
||||
|
||||
if _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser1.Id, ""); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should have allowed whitelisted user1")
|
||||
}
|
||||
if _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser2.Id, ""); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should have allowed whitelisted user2")
|
||||
}
|
||||
if _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser3.Id, ""); err == nil || err.Where != "JoinUserToTeam" {
|
||||
t.Log(err)
|
||||
t.Fatal("Should not have allowed restricted user3")
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestAddUserToTeamByToken(t *testing.T) {
|
||||
@@ -158,19 +244,62 @@ func TestAddUserToTeamByToken(t *testing.T) {
|
||||
t.Fatal("The token must be deleted after be used")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("block user", func(t *testing.T) {
|
||||
th.BasicTeam.AllowedDomains = "example.com"
|
||||
if _, err := th.App.UpdateTeam(th.BasicTeam); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should update the team")
|
||||
}
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "test@invalid.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
|
||||
ruser, _ := th.App.CreateUser(&user)
|
||||
defer th.App.PermanentDeleteUser(&user)
|
||||
|
||||
token := model.NewToken(
|
||||
TOKEN_TYPE_TEAM_INVITATION,
|
||||
model.MapToJson(map[string]string{"teamId": th.BasicTeam.Id}),
|
||||
)
|
||||
<-th.App.Srv.Store.Token().Save(token)
|
||||
|
||||
if _, err := th.App.AddUserToTeamByToken(ruser.Id, token.Token); err == nil || err.Where != "JoinUserToTeam" {
|
||||
t.Log(err)
|
||||
t.Fatal("Should not add restricted user")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestAddUserToTeamByTeamId(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
|
||||
ruser, _ := th.App.CreateUser(&user)
|
||||
t.Run("add user", func(t *testing.T) {
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
|
||||
ruser, _ := th.App.CreateUser(&user)
|
||||
|
||||
if err := th.App.AddUserToTeamByTeamId(th.BasicTeam.Id, ruser); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should add user to the team")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("block user", func(t *testing.T) {
|
||||
th.BasicTeam.AllowedDomains = "example.com"
|
||||
if _, err := th.App.UpdateTeam(th.BasicTeam); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should update the team")
|
||||
}
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "test@invalid.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
|
||||
ruser, _ := th.App.CreateUser(&user)
|
||||
defer th.App.PermanentDeleteUser(&user)
|
||||
|
||||
if err := th.App.AddUserToTeamByTeamId(th.BasicTeam.Id, ruser); err == nil || err.Where != "JoinUserToTeam" {
|
||||
t.Log(err)
|
||||
t.Fatal("Should not add restricted user")
|
||||
}
|
||||
})
|
||||
|
||||
if err := th.App.AddUserToTeamByTeamId(th.BasicTeam.Id, ruser); err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal("Should add user to the team")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermanentDeleteTeam(t *testing.T) {
|
||||
@@ -264,7 +393,7 @@ func TestSanitizeTeam(t *testing.T) {
|
||||
}
|
||||
|
||||
sanitized := th.App.SanitizeTeam(session, copyTeam())
|
||||
if sanitized.Email != "" && sanitized.AllowedDomains != "" {
|
||||
if sanitized.Email != "" {
|
||||
t.Fatal("should've sanitized team")
|
||||
}
|
||||
})
|
||||
@@ -283,7 +412,7 @@ func TestSanitizeTeam(t *testing.T) {
|
||||
}
|
||||
|
||||
sanitized := th.App.SanitizeTeam(session, copyTeam())
|
||||
if sanitized.Email != "" && sanitized.AllowedDomains != "" {
|
||||
if sanitized.Email != "" {
|
||||
t.Fatal("should've sanitized team")
|
||||
}
|
||||
})
|
||||
@@ -302,7 +431,7 @@ func TestSanitizeTeam(t *testing.T) {
|
||||
}
|
||||
|
||||
sanitized := th.App.SanitizeTeam(session, copyTeam())
|
||||
if sanitized.Email == "" && sanitized.AllowedDomains == "" {
|
||||
if sanitized.Email == "" {
|
||||
t.Fatal("shouldn't have sanitized team")
|
||||
}
|
||||
})
|
||||
@@ -321,7 +450,7 @@ func TestSanitizeTeam(t *testing.T) {
|
||||
}
|
||||
|
||||
sanitized := th.App.SanitizeTeam(session, copyTeam())
|
||||
if sanitized.Email != "" && sanitized.AllowedDomains != "" {
|
||||
if sanitized.Email != "" {
|
||||
t.Fatal("should've sanitized team")
|
||||
}
|
||||
})
|
||||
@@ -340,7 +469,7 @@ func TestSanitizeTeam(t *testing.T) {
|
||||
}
|
||||
|
||||
sanitized := th.App.SanitizeTeam(session, copyTeam())
|
||||
if sanitized.Email == "" && sanitized.AllowedDomains == "" {
|
||||
if sanitized.Email == "" {
|
||||
t.Fatal("shouldn't have sanitized team")
|
||||
}
|
||||
})
|
||||
@@ -359,7 +488,7 @@ func TestSanitizeTeam(t *testing.T) {
|
||||
}
|
||||
|
||||
sanitized := th.App.SanitizeTeam(session, copyTeam())
|
||||
if sanitized.Email == "" && sanitized.AllowedDomains == "" {
|
||||
if sanitized.Email == "" {
|
||||
t.Fatal("shouldn't have sanitized team")
|
||||
}
|
||||
})
|
||||
@@ -402,11 +531,11 @@ func TestSanitizeTeams(t *testing.T) {
|
||||
|
||||
sanitized := th.App.SanitizeTeams(session, teams)
|
||||
|
||||
if sanitized[0].Email != "" && sanitized[0].AllowedDomains != "" {
|
||||
if sanitized[0].Email != "" {
|
||||
t.Fatal("should've sanitized first team")
|
||||
}
|
||||
|
||||
if sanitized[1].Email == "" && sanitized[1].AllowedDomains == "" {
|
||||
if sanitized[1].Email == "" {
|
||||
t.Fatal("shouldn't have sanitized second team")
|
||||
}
|
||||
})
|
||||
@@ -439,11 +568,11 @@ func TestSanitizeTeams(t *testing.T) {
|
||||
|
||||
sanitized := th.App.SanitizeTeams(session, teams)
|
||||
|
||||
if sanitized[0].Email == "" && sanitized[0].AllowedDomains == "" {
|
||||
if sanitized[0].Email == "" {
|
||||
t.Fatal("shouldn't have sanitized first team")
|
||||
}
|
||||
|
||||
if sanitized[1].Email == "" && sanitized[1].AllowedDomains == "" {
|
||||
if sanitized[1].Email == "" {
|
||||
t.Fatal("shouldn't have sanitized second team")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1654,6 +1654,10 @@
|
||||
"id": "api.team.join_team.post_and_forget",
|
||||
"translation": "%v joined the team."
|
||||
},
|
||||
{
|
||||
"id": "api.team.join_user_to_team.allowed_domains.app_error",
|
||||
"translation": "Email must be from a specific domain (e.g. @example.com). Please ask your team or system administrator for details."
|
||||
},
|
||||
{
|
||||
"id": "api.team.leave.left",
|
||||
"translation": "%v left the team."
|
||||
@@ -1730,6 +1734,10 @@
|
||||
"id": "api.team.update_member_roles.not_a_member",
|
||||
"translation": "Specified user is not a member of specified team."
|
||||
},
|
||||
{
|
||||
"id": "api.team.update_restricted_domains.mismatch.app_error",
|
||||
"translation": "Restricting team to {{ .Domain }} is not allowed by the system config. Please contact your system administrator."
|
||||
},
|
||||
{
|
||||
"id": "api.team.update_team_scheme.license.error",
|
||||
"translation": "Your license does not support updating a team's scheme"
|
||||
|
||||
@@ -47,6 +47,7 @@ type TeamPatch struct {
|
||||
DisplayName *string `json:"display_name"`
|
||||
Description *string `json:"description"`
|
||||
CompanyName *string `json:"company_name"`
|
||||
AllowedDomains *string `json:"allowed_domains"`
|
||||
InviteId *string `json:"invite_id"`
|
||||
AllowOpenInvite *bool `json:"allow_open_invite"`
|
||||
}
|
||||
@@ -241,7 +242,6 @@ func CleanTeamName(s string) string {
|
||||
|
||||
func (o *Team) Sanitize() {
|
||||
o.Email = ""
|
||||
o.AllowedDomains = ""
|
||||
}
|
||||
|
||||
func (t *Team) Patch(patch *TeamPatch) {
|
||||
@@ -257,6 +257,10 @@ func (t *Team) Patch(patch *TeamPatch) {
|
||||
t.CompanyName = *patch.CompanyName
|
||||
}
|
||||
|
||||
if patch.AllowedDomains != nil {
|
||||
t.AllowedDomains = *patch.AllowedDomains
|
||||
}
|
||||
|
||||
if patch.InviteId != nil {
|
||||
t.InviteId = *patch.InviteId
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user