github.com/psyb0t/mattermost-server@v4.6.1-0.20180125161845-5503a1351abf+incompatible/app/authentication.go (about) 1 // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package app 5 6 import ( 7 "net/http" 8 "strings" 9 10 "github.com/mattermost/mattermost-server/model" 11 "github.com/mattermost/mattermost-server/utils" 12 ) 13 14 func (a *App) IsPasswordValid(password string) *model.AppError { 15 if utils.IsLicensed() && *utils.License().Features.PasswordRequirements { 16 return utils.IsPasswordValidWithSettings(password, &a.Config().PasswordSettings) 17 } 18 return utils.IsPasswordValid(password) 19 } 20 21 func (a *App) CheckPasswordAndAllCriteria(user *model.User, password string, mfaToken string) *model.AppError { 22 if err := a.CheckUserAdditionalAuthenticationCriteria(user, mfaToken); err != nil { 23 return err 24 } 25 26 if err := a.checkUserPassword(user, password); err != nil { 27 return err 28 } 29 30 return nil 31 } 32 33 // This to be used for places we check the users password when they are already logged in 34 func (a *App) doubleCheckPassword(user *model.User, password string) *model.AppError { 35 if err := checkUserLoginAttempts(user, *a.Config().ServiceSettings.MaximumLoginAttempts); err != nil { 36 return err 37 } 38 39 if err := a.checkUserPassword(user, password); err != nil { 40 return err 41 } 42 43 return nil 44 } 45 46 func (a *App) checkUserPassword(user *model.User, password string) *model.AppError { 47 if !model.ComparePassword(user.Password, password) { 48 if result := <-a.Srv.Store.User().UpdateFailedPasswordAttempts(user.Id, user.FailedAttempts+1); result.Err != nil { 49 return result.Err 50 } 51 52 return model.NewAppError("checkUserPassword", "api.user.check_user_password.invalid.app_error", nil, "user_id="+user.Id, http.StatusUnauthorized) 53 } else { 54 if result := <-a.Srv.Store.User().UpdateFailedPasswordAttempts(user.Id, 0); result.Err != nil { 55 return result.Err 56 } 57 58 return nil 59 } 60 } 61 62 func (a *App) checkLdapUserPasswordAndAllCriteria(ldapId *string, password string, mfaToken string) (*model.User, *model.AppError) { 63 if a.Ldap == nil || ldapId == nil { 64 err := model.NewAppError("doLdapAuthentication", "api.user.login_ldap.not_available.app_error", nil, "", http.StatusNotImplemented) 65 return nil, err 66 } 67 68 var user *model.User 69 if ldapUser, err := a.Ldap.DoLogin(*ldapId, password); err != nil { 70 err.StatusCode = http.StatusUnauthorized 71 return nil, err 72 } else { 73 user = ldapUser 74 } 75 76 if err := a.CheckUserMfa(user, mfaToken); err != nil { 77 return nil, err 78 } 79 80 if err := checkUserNotDisabled(user); err != nil { 81 return nil, err 82 } 83 84 // user successfully authenticated 85 return user, nil 86 } 87 88 func (a *App) CheckUserAdditionalAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError { 89 if err := a.CheckUserMfa(user, mfaToken); err != nil { 90 return err 91 } 92 93 if !user.EmailVerified && a.Config().EmailSettings.RequireEmailVerification { 94 return model.NewAppError("Login", "api.user.login.not_verified.app_error", nil, "user_id="+user.Id, http.StatusUnauthorized) 95 } 96 97 if err := checkUserNotDisabled(user); err != nil { 98 return err 99 } 100 101 if err := checkUserLoginAttempts(user, *a.Config().ServiceSettings.MaximumLoginAttempts); err != nil { 102 return err 103 } 104 105 return nil 106 } 107 108 func (a *App) CheckUserMfa(user *model.User, token string) *model.AppError { 109 if !user.MfaActive || !utils.IsLicensed() || !*utils.License().Features.MFA || !*a.Config().ServiceSettings.EnableMultifactorAuthentication { 110 return nil 111 } 112 113 if a.Mfa == nil { 114 return model.NewAppError("checkUserMfa", "api.user.check_user_mfa.not_available.app_error", nil, "", http.StatusNotImplemented) 115 } 116 117 if ok, err := a.Mfa.ValidateToken(user.MfaSecret, token); err != nil { 118 return err 119 } else if !ok { 120 return model.NewAppError("checkUserMfa", "api.user.check_user_mfa.bad_code.app_error", nil, "", http.StatusUnauthorized) 121 } 122 123 return nil 124 } 125 126 func checkUserLoginAttempts(user *model.User, max int) *model.AppError { 127 if user.FailedAttempts >= max { 128 return model.NewAppError("checkUserLoginAttempts", "api.user.check_user_login_attempts.too_many.app_error", nil, "user_id="+user.Id, http.StatusUnauthorized) 129 } 130 131 return nil 132 } 133 134 func checkUserNotDisabled(user *model.User) *model.AppError { 135 if user.DeleteAt > 0 { 136 return model.NewAppError("Login", "api.user.login.inactive.app_error", nil, "user_id="+user.Id, http.StatusUnauthorized) 137 } 138 return nil 139 } 140 141 func (a *App) authenticateUser(user *model.User, password, mfaToken string) (*model.User, *model.AppError) { 142 ldapAvailable := *a.Config().LdapSettings.Enable && a.Ldap != nil && utils.IsLicensed() && *utils.License().Features.LDAP 143 144 if user.AuthService == model.USER_AUTH_SERVICE_LDAP { 145 if !ldapAvailable { 146 err := model.NewAppError("login", "api.user.login_ldap.not_available.app_error", nil, "", http.StatusNotImplemented) 147 return user, err 148 } else if ldapUser, err := a.checkLdapUserPasswordAndAllCriteria(user.AuthData, password, mfaToken); err != nil { 149 err.StatusCode = http.StatusUnauthorized 150 return user, err 151 } else { 152 // slightly redundant to get the user again, but we need to get it from the LDAP server 153 return ldapUser, nil 154 } 155 } else if user.AuthService != "" { 156 authService := user.AuthService 157 if authService == model.USER_AUTH_SERVICE_SAML { 158 authService = strings.ToUpper(authService) 159 } 160 err := model.NewAppError("login", "api.user.login.use_auth_service.app_error", map[string]interface{}{"AuthService": authService}, "", http.StatusBadRequest) 161 return user, err 162 } else { 163 if err := a.CheckPasswordAndAllCriteria(user, password, mfaToken); err != nil { 164 err.StatusCode = http.StatusUnauthorized 165 return user, err 166 } else { 167 return user, nil 168 } 169 } 170 }