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.
Этот коммит содержится в:
коммит произвёл
Harrison Healey
родитель
19e69681d7
Коммит
347ee1d205
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())
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user