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  }