Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into MM-14727
Browse files Browse the repository at this point in the history
  • Loading branch information
Wipeout55 committed Jun 11, 2019
2 parents ee0e4af + c2d7fba commit cf34b5f
Show file tree
Hide file tree
Showing 40 changed files with 688 additions and 829 deletions.
10 changes: 5 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,14 @@ TESTFLAGSEE ?= -short
TE_PACKAGES=$(shell go list ./...|grep -v plugin_tests)

# Plugins Packages
PLUGIN_PACKAGES=mattermost-plugin-zoom-v1.0.6
PLUGIN_PACKAGES=mattermost-plugin-zoom-v1.0.7
PLUGIN_PACKAGES += mattermost-plugin-autolink-v1.0.0
PLUGIN_PACKAGES += mattermost-plugin-nps-v1.0.0-rc1
PLUGIN_PACKAGES += mattermost-plugin-nps-v1.0.0-rc2
PLUGIN_PACKAGES += mattermost-plugin-custom-attributes-v1.0.0
PLUGIN_PACKAGES += mattermost-plugin-github-v0.10.0
PLUGIN_PACKAGES += mattermost-plugin-github-v0.10.2
PLUGIN_PACKAGES += mattermost-plugin-welcomebot-v1.0.0
PLUGIN_PACKAGES += mattermost-plugin-aws-SNS-v1.0.0
PLUGIN_PACKAGES += mattermost-plugin-jira-v2.0.0
PLUGIN_PACKAGES += mattermost-plugin-jira-v2.0.1

# Prepares the enterprise build if exists. The IGNORE stuff is a hack to get the Makefile to execute the commands outside a target
ifeq ($(BUILD_ENTERPRISE_READY),true)
Expand Down Expand Up @@ -535,7 +535,7 @@ config-ldap: ## Configures LDAP.
config-reset: ## Resets the config/config.json file to the default.
@echo Resetting configuration to default
rm -f config/config.json
cp config/default.json config/config.json
OUTPUT_CONFIG=$(PWD)/config/config.json go generate ./config

clean: stop-docker ## Clean up everything except persistant server data.
@echo Cleaning
Expand Down
55 changes: 49 additions & 6 deletions api4/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -1242,13 +1242,56 @@ func sendPasswordReset(c *Context, w http.ResponseWriter, r *http.Request) {
func login(c *Context, w http.ResponseWriter, r *http.Request) {
// Translate all login errors to generic. MFA error being an exception, since it's required for the login flow itself
defer func() {
if c.Err != nil &&
c.Err.Id != "mfa.validate_token.authenticate.app_error" &&
c.Err.Id != "api.user.login.blank_pwd.app_error" &&
c.Err.Id != "api.user.login.bot_login_forbidden.app_error" &&
c.Err.Id != "api.user.login.client_side_cert.certificate.app_error" {
c.Err = model.NewAppError("login", "api.user.login.invalid_credentials", nil, "", http.StatusUnauthorized)
if c.Err == nil {
return
}

unmaskedErrors := []string{
"mfa.validate_token.authenticate.app_error",
"api.user.check_user_mfa.bad_code.app_error",
"api.user.login.blank_pwd.app_error",
"api.user.login.bot_login_forbidden.app_error",
"api.user.login.client_side_cert.certificate.app_error",
"api.user.login.inactive.app_error",
"api.user.login.not_verified.app_error",
}

maskError := true

for _, unmaskedError := range unmaskedErrors {
if c.Err.Id == unmaskedError {
maskError = false
}
}

if !maskError {
return
}

config := c.App.Config()
enableUsername := *config.EmailSettings.EnableSignInWithUsername
enableEmail := *config.EmailSettings.EnableSignInWithEmail
samlEnabled := *config.SamlSettings.Enable
gitlabEnabled := *config.GetSSOService("gitlab").Enable
googleEnabled := *config.GetSSOService("google").Enable
office365Enabled := *config.GetSSOService("office365").Enable

if samlEnabled || gitlabEnabled || googleEnabled || office365Enabled {
c.Err = model.NewAppError("login", "api.user.login.invalid_credentials_sso", nil, "", http.StatusUnauthorized)
return
}

if enableUsername && !enableEmail {
c.Err = model.NewAppError("login", "api.user.login.invalid_credentials_username", nil, "", http.StatusUnauthorized)
return
}

if !enableUsername && enableEmail {
c.Err = model.NewAppError("login", "api.user.login.invalid_credentials_email", nil, "", http.StatusUnauthorized)
return
}

c.Err = model.NewAppError("login", "api.user.login.invalid_credentials_email_username", nil, "", http.StatusUnauthorized)
}()

props := model.MapFromJson(r.Body)
Expand Down
81 changes: 68 additions & 13 deletions api4/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2673,7 +2673,7 @@ func TestLogin(t *testing.T) {

t.Run("unknown user", func(t *testing.T) {
_, resp := th.Client.Login("unknown", th.BasicUser.Password)
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials_email_username")
})

t.Run("valid login", func(t *testing.T) {
Expand Down Expand Up @@ -4121,6 +4121,61 @@ func TestGetUserTermsOfService(t *testing.T) {
assert.NotEmpty(t, userTermsOfService.CreateAt)
}

func TestLoginErrorMessage(t *testing.T) {
th := Setup().InitBasic()
defer th.TearDown()

_, resp := th.Client.Logout()
CheckNoError(t, resp)


// Email and Username enabled
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.EmailSettings.EnableSignInWithEmail = true
*cfg.EmailSettings.EnableSignInWithUsername = true
})
_, resp = th.Client.Login(th.BasicUser.Email, "wrong")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials_email_username")

// Email enabled
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.EmailSettings.EnableSignInWithEmail = true
*cfg.EmailSettings.EnableSignInWithUsername = false
})
_, resp = th.Client.Login(th.BasicUser.Email, "wrong")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials_email")

// Username enabled
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.EmailSettings.EnableSignInWithEmail = false
*cfg.EmailSettings.EnableSignInWithUsername = true
})
_, resp = th.Client.Login(th.BasicUser.Email, "wrong")
CheckErrorMessage(t, resp, "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.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 = ""
})
_, resp = th.Client.Login(th.BasicUser.Email, "wrong")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials_sso")
}

func TestLoginLockout(t *testing.T) {
th := Setup().InitBasic()
defer th.TearDown()
Expand All @@ -4132,34 +4187,34 @@ func TestLoginLockout(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })

_, resp = th.Client.Login(th.BasicUser.Email, "wrong")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials_email_username")
_, resp = th.Client.Login(th.BasicUser.Email, "wrong")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials_email_username")
_, resp = th.Client.Login(th.BasicUser.Email, "wrong")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials_email_username")
_, resp = th.Client.Login(th.BasicUser.Email, "wrong")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials_email_username")
_, resp = th.Client.Login(th.BasicUser.Email, "wrong")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials_email_username")

//Check if lock is active
_, resp = th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials_email_username")

// Fake user has MFA enabled
if result := <-th.Server.Store.User().UpdateMfaActive(th.BasicUser2.Id, true); result.Err != nil {
t.Fatal(result.Err)
}
_, resp = th.Client.LoginWithMFA(th.BasicUser2.Email, th.BasicUser2.Password, "000000")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials")
CheckErrorMessage(t, resp, "api.user.check_user_mfa.bad_code.app_error")
_, resp = th.Client.LoginWithMFA(th.BasicUser2.Email, th.BasicUser2.Password, "000000")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials")
CheckErrorMessage(t, resp, "api.user.check_user_mfa.bad_code.app_error")
_, resp = th.Client.LoginWithMFA(th.BasicUser2.Email, th.BasicUser2.Password, "000000")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials")
CheckErrorMessage(t, resp, "api.user.check_user_mfa.bad_code.app_error")
_, resp = th.Client.LoginWithMFA(th.BasicUser2.Email, th.BasicUser2.Password, "000000")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials_email_username")
_, resp = th.Client.LoginWithMFA(th.BasicUser2.Email, th.BasicUser2.Password, "000000")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials_email_username")

// Fake user has MFA disabled
if result := <-th.Server.Store.User().UpdateMfaActive(th.BasicUser2.Id, false); result.Err != nil {
Expand All @@ -4168,5 +4223,5 @@ func TestLoginLockout(t *testing.T) {

//Check if lock is active
_, resp = th.Client.Login(th.BasicUser2.Email, th.BasicUser2.Password)
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials")
CheckErrorMessage(t, resp, "api.user.login.invalid_credentials_email_username")
}
8 changes: 3 additions & 5 deletions app/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,14 +379,12 @@ func (a *App) ExportAllPosts(writer io.Writer) *model.AppError {
func (a *App) buildPostReplies(postId string) (*[]ReplyImportData, *model.AppError) {
var replies []ReplyImportData

result := <-a.Srv.Store.Post().GetRepliesForExport(postId)
replyPosts, err := a.Srv.Store.Post().GetRepliesForExport(postId)

if result.Err != nil {
return nil, result.Err
if err != nil {
return nil, err
}

replyPosts := result.Data.([]*model.ReplyForExport)

for _, reply := range replyPosts {
replyImportObject := ImportReplyFromPost(reply)
if reply.HasReactions == true {
Expand Down
31 changes: 10 additions & 21 deletions app/post.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,11 @@ func (a *App) CreatePost(post *model.Post, channel *model.Channel, triggerWebhoo
pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool {
replacementPost, rejectionReason := hooks.MessageWillBePosted(pluginContext, post)
if rejectionReason != "" {
rejectionError = model.NewAppError("createPost", "Post rejected by plugin. "+rejectionReason, nil, "", http.StatusBadRequest)
id := "Post rejected by plugin. " + rejectionReason
if rejectionReason == plugin.DismissPostError {
id = plugin.DismissPostError
}
rejectionError = model.NewAppError("createPost", id, nil, "", http.StatusBadRequest)
return false
}
if replacementPost != nil {
Expand All @@ -245,6 +249,7 @@ func (a *App) CreatePost(post *model.Post, channel *model.Channel, triggerWebhoo

return true
}, plugin.MessageWillBePostedId)

if rejectionError != nil {
return nil, rejectionError
}
Expand Down Expand Up @@ -662,34 +667,18 @@ func (a *App) GetPermalinkPost(postId string, userId string) (*model.PostList, *
}

func (a *App) GetPostsBeforePost(channelId, postId string, page, perPage int) (*model.PostList, *model.AppError) {
result := <-a.Srv.Store.Post().GetPostsBefore(channelId, postId, perPage, page*perPage)
if result.Err != nil {
return nil, result.Err
}
return result.Data.(*model.PostList), nil
return a.Srv.Store.Post().GetPostsBefore(channelId, postId, perPage, page*perPage)
}

func (a *App) GetPostsAfterPost(channelId, postId string, page, perPage int) (*model.PostList, *model.AppError) {
result := <-a.Srv.Store.Post().GetPostsAfter(channelId, postId, perPage, page*perPage)
if result.Err != nil {
return nil, result.Err
}
return result.Data.(*model.PostList), nil
return a.Srv.Store.Post().GetPostsAfter(channelId, postId, perPage, page*perPage)
}

func (a *App) GetPostsAroundPost(postId, channelId string, offset, limit int, before bool) (*model.PostList, *model.AppError) {
var pchan store.StoreChannel
if before {
pchan = a.Srv.Store.Post().GetPostsBefore(channelId, postId, limit, offset)
} else {
pchan = a.Srv.Store.Post().GetPostsAfter(channelId, postId, limit, offset)
}

result := <-pchan
if result.Err != nil {
return nil, result.Err
return a.Srv.Store.Post().GetPostsBefore(channelId, postId, limit, offset)
}
return result.Data.(*model.PostList), nil
return a.Srv.Store.Post().GetPostsAfter(channelId, postId, limit, offset)
}

func (a *App) DeletePost(postId, deleteByID string) (*model.Post, *model.AppError) {
Expand Down
7 changes: 6 additions & 1 deletion app/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -1711,7 +1711,7 @@ func (a *App) SearchUsersInTeam(teamId string, term string, options *model.UserS
if err != nil {
return nil, err
}
if len(listOfAllowedChannels) == 0 {
if listOfAllowedChannels != nil && len(listOfAllowedChannels) == 0 {
return []*model.User{}, nil
}

Expand Down Expand Up @@ -2102,6 +2102,11 @@ func (a *App) GetViewUsersRestrictions(userId string) (*model.ViewUsersRestricti
return &model.ViewUsersRestrictions{Teams: teamIdsWithPermission, Channels: channelIds}, nil
}

/**
* Returns a list with the channel ids that the user has permissions to view on a
* team. If the result is an empty list, the user can't view any channel; if it's
* nil, there are no restrictions for the user in the specified team.
*/
func (a *App) GetViewUsersRestrictionsForTeam(userId string, teamId string) ([]string, *model.AppError) {
if a.HasPermissionTo(userId, model.PERMISSION_VIEW_MEMBERS) {
return nil, nil
Expand Down
2 changes: 1 addition & 1 deletion build/Jenkinsfile.k8s
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ podTemplate(label: 'jenkins-slave',
sh 'apt-get update && apt-get install zip -y'

// Modify config to run on jenkins
sh 'mv /go/src/github.com/mattermost/mattermost-server/config/default.json /go/src/github.com/mattermost/mattermost-server/config/config.json'
sh 'cd /go/src/github.com/mattermost/mattermost-server && make config-reset'
sh 'cd /go/src/github.com/mattermost/mattermost-server && sed -i \'s/dockerhost/localhost/g\' config/config.json'
sh 'cd /go/src/github.com/mattermost/mattermost-server && sed -i \'s/2500/10025/g\' config/config.json'
}
Expand Down
2 changes: 1 addition & 1 deletion build/Jenkinsfile.pr
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pipeline {
ansiColor('xterm') {
sh """
cd /go/src/github.com/mattermost/mattermost-server
mv config/default.json config/config.json || echo ""
make config-reset
make check-style BUILD_NUMBER='${BRANCH_NAME}-${BUILD_NUMBER}'
make build BUILD_NUMBER='${BRANCH_NAME}-${BUILD_NUMBER}'
make package BUILD_NUMBER='${BRANCH_NAME}-${BUILD_NUMBER}'
Expand Down
2 changes: 1 addition & 1 deletion build/release.mk
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ package:
@# Resource directories
mkdir -p $(DIST_PATH)/config
cp -L config/README.md $(DIST_PATH)/config
cp -L config/config.json $(DIST_PATH)/config
OUTPUT_CONFIG=$(PWD)/$(DIST_PATH)/config/config.json go generate ./config
cp -RL fonts $(DIST_PATH)
cp -RL templates $(DIST_PATH)
cp -RL i18n $(DIST_PATH)
Expand Down
4 changes: 4 additions & 0 deletions config/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,14 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["LdapNicknameAttributeSet"] = "false"
props["LdapFirstNameAttributeSet"] = "false"
props["LdapLastNameAttributeSet"] = "false"
props["LdapPositionAttributeSet"] = "false"
props["EnableCompliance"] = "false"
props["EnableMobileFileDownload"] = "true"
props["EnableMobileFileUpload"] = "true"
props["SamlFirstNameAttributeSet"] = "false"
props["SamlLastNameAttributeSet"] = "false"
props["SamlNicknameAttributeSet"] = "false"
props["SamlPositionAttributeSet"] = "false"
props["EnableCluster"] = "false"
props["EnableMetrics"] = "false"
props["PasswordMinimumLength"] = "0"
Expand Down Expand Up @@ -136,6 +138,7 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["LdapNicknameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.NicknameAttribute != "")
props["LdapFirstNameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.FirstNameAttribute != "")
props["LdapLastNameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.LastNameAttribute != "")
props["LdapPositionAttributeSet"] = strconv.FormatBool(*c.LdapSettings.PositionAttribute != "")
}

if *license.Features.Compliance {
Expand All @@ -148,6 +151,7 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["SamlFirstNameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.FirstNameAttribute != "")
props["SamlLastNameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.LastNameAttribute != "")
props["SamlNicknameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.NicknameAttribute != "")
props["SamlPositionAttributeSet"] = strconv.FormatBool(*c.SamlSettings.PositionAttribute != "")

// do this under the correct licensed feature
props["ExperimentalClientSideCertEnable"] = strconv.FormatBool(*c.ExperimentalSettings.ClientSideCertEnable)
Expand Down
22 changes: 22 additions & 0 deletions config/config_generator/generator/generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package generator

import (
"encoding/json"
"os"

"github.com/mattermost/mattermost-server/model"
)

func GenerateDefaultConfig(outputFile *os.File) error {
defaultCfg := &model.Config{}
defaultCfg.SetDefaults()
if data, err := json.MarshalIndent(defaultCfg, "", " "); err != nil {
return err
} else if _, err := outputFile.Write(data); err != nil {
return err
}
return nil
}

0 comments on commit cf34b5f

Please sign in to comment.