github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/app/authentication.go (about)

     1  // Copyright (c) 2015-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/v5/model"
    11  	"github.com/mattermost/mattermost-server/v5/services/mfa"
    12  	"github.com/mattermost/mattermost-server/v5/utils"
    13  )
    14  
    15  type TokenLocation int
    16  
    17  const (
    18  	TokenLocationNotFound TokenLocation = iota
    19  	TokenLocationHeader
    20  	TokenLocationCookie
    21  	TokenLocationQueryString
    22  	TokenLocationCloudHeader
    23  )
    24  
    25  func (tl TokenLocation) String() string {
    26  	switch tl {
    27  	case TokenLocationNotFound:
    28  		return "Not Found"
    29  	case TokenLocationHeader:
    30  		return "Header"
    31  	case TokenLocationCookie:
    32  		return "Cookie"
    33  	case TokenLocationQueryString:
    34  		return "QueryString"
    35  	case TokenLocationCloudHeader:
    36  		return "CloudHeader"
    37  	default:
    38  		return "Unknown"
    39  	}
    40  }
    41  
    42  func (a *App) IsPasswordValid(password string) *model.AppError {
    43  
    44  	if *a.Config().ServiceSettings.EnableDeveloper {
    45  		return nil
    46  	}
    47  
    48  	return utils.IsPasswordValidWithSettings(password, &a.Config().PasswordSettings)
    49  }
    50  
    51  func (a *App) CheckPasswordAndAllCriteria(user *model.User, password string, mfaToken string) *model.AppError {
    52  	if err := a.CheckUserPreflightAuthenticationCriteria(user, mfaToken); err != nil {
    53  		return err
    54  	}
    55  
    56  	if err := a.checkUserPassword(user, password); err != nil {
    57  		if passErr := a.Srv().Store.User().UpdateFailedPasswordAttempts(user.Id, user.FailedAttempts+1); passErr != nil {
    58  			return model.NewAppError("CheckPasswordAndAllCriteria", "app.user.update_failed_pwd_attempts.app_error", nil, passErr.Error(), http.StatusInternalServerError)
    59  		}
    60  
    61  		a.InvalidateCacheForUser(user.Id)
    62  
    63  		return err
    64  	}
    65  
    66  	if err := a.CheckUserMfa(user, mfaToken); err != nil {
    67  		// If the mfaToken is not set, we assume the client used this as a pre-flight request to query the server
    68  		// about the MFA state of the user in question
    69  		if mfaToken != "" {
    70  			if passErr := a.Srv().Store.User().UpdateFailedPasswordAttempts(user.Id, user.FailedAttempts+1); passErr != nil {
    71  				return model.NewAppError("CheckPasswordAndAllCriteria", "app.user.update_failed_pwd_attempts.app_error", nil, passErr.Error(), http.StatusInternalServerError)
    72  			}
    73  		}
    74  
    75  		a.InvalidateCacheForUser(user.Id)
    76  
    77  		return err
    78  	}
    79  
    80  	if passErr := a.Srv().Store.User().UpdateFailedPasswordAttempts(user.Id, 0); passErr != nil {
    81  		return model.NewAppError("CheckPasswordAndAllCriteria", "app.user.update_failed_pwd_attempts.app_error", nil, passErr.Error(), http.StatusInternalServerError)
    82  	}
    83  
    84  	a.InvalidateCacheForUser(user.Id)
    85  
    86  	if err := a.CheckUserPostflightAuthenticationCriteria(user); err != nil {
    87  		return err
    88  	}
    89  
    90  	return nil
    91  }
    92  
    93  // This to be used for places we check the users password when they are already logged in
    94  func (a *App) DoubleCheckPassword(user *model.User, password string) *model.AppError {
    95  	if err := checkUserLoginAttempts(user, *a.Config().ServiceSettings.MaximumLoginAttempts); err != nil {
    96  		return err
    97  	}
    98  
    99  	if err := a.checkUserPassword(user, password); err != nil {
   100  		if passErr := a.Srv().Store.User().UpdateFailedPasswordAttempts(user.Id, user.FailedAttempts+1); passErr != nil {
   101  			return model.NewAppError("DoubleCheckPassword", "app.user.update_failed_pwd_attempts.app_error", nil, passErr.Error(), http.StatusInternalServerError)
   102  		}
   103  
   104  		a.InvalidateCacheForUser(user.Id)
   105  
   106  		return err
   107  	}
   108  
   109  	if passErr := a.Srv().Store.User().UpdateFailedPasswordAttempts(user.Id, 0); passErr != nil {
   110  		return model.NewAppError("DoubleCheckPassword", "app.user.update_failed_pwd_attempts.app_error", nil, passErr.Error(), http.StatusInternalServerError)
   111  	}
   112  
   113  	a.InvalidateCacheForUser(user.Id)
   114  
   115  	return nil
   116  }
   117  
   118  func (a *App) checkUserPassword(user *model.User, password string) *model.AppError {
   119  	if !model.ComparePassword(user.Password, password) {
   120  		return model.NewAppError("checkUserPassword", "api.user.check_user_password.invalid.app_error", nil, "user_id="+user.Id, http.StatusUnauthorized)
   121  	}
   122  
   123  	return nil
   124  }
   125  
   126  func (a *App) checkLdapUserPasswordAndAllCriteria(ldapId *string, password string, mfaToken string) (*model.User, *model.AppError) {
   127  	if a.Ldap() == nil || ldapId == nil {
   128  		err := model.NewAppError("doLdapAuthentication", "api.user.login_ldap.not_available.app_error", nil, "", http.StatusNotImplemented)
   129  		return nil, err
   130  	}
   131  
   132  	ldapUser, err := a.Ldap().DoLogin(*ldapId, password)
   133  	if err != nil {
   134  		err.StatusCode = http.StatusUnauthorized
   135  		return nil, err
   136  	}
   137  
   138  	if err := a.CheckUserMfa(ldapUser, mfaToken); err != nil {
   139  		return nil, err
   140  	}
   141  
   142  	if err := checkUserNotDisabled(ldapUser); err != nil {
   143  		return nil, err
   144  	}
   145  
   146  	// user successfully authenticated
   147  	return ldapUser, nil
   148  }
   149  
   150  func (a *App) CheckUserAllAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError {
   151  	if err := a.CheckUserPreflightAuthenticationCriteria(user, mfaToken); err != nil {
   152  		return err
   153  	}
   154  
   155  	if err := a.CheckUserPostflightAuthenticationCriteria(user); err != nil {
   156  		return err
   157  	}
   158  
   159  	return nil
   160  }
   161  
   162  func (a *App) CheckUserPreflightAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError {
   163  	if err := checkUserNotDisabled(user); err != nil {
   164  		return err
   165  	}
   166  
   167  	if err := checkUserNotBot(user); err != nil {
   168  		return err
   169  	}
   170  
   171  	if err := checkUserLoginAttempts(user, *a.Config().ServiceSettings.MaximumLoginAttempts); err != nil {
   172  		return err
   173  	}
   174  
   175  	return nil
   176  }
   177  
   178  func (a *App) CheckUserPostflightAuthenticationCriteria(user *model.User) *model.AppError {
   179  	if !user.EmailVerified && *a.Config().EmailSettings.RequireEmailVerification {
   180  		return model.NewAppError("Login", "api.user.login.not_verified.app_error", nil, "user_id="+user.Id, http.StatusUnauthorized)
   181  	}
   182  
   183  	return nil
   184  }
   185  
   186  func (a *App) CheckUserMfa(user *model.User, token string) *model.AppError {
   187  	if !user.MfaActive || !*a.Config().ServiceSettings.EnableMultifactorAuthentication {
   188  		return nil
   189  	}
   190  
   191  	mfaService := mfa.New(a, a.Srv().Store)
   192  	ok, err := mfaService.ValidateToken(user.MfaSecret, token)
   193  	if err != nil {
   194  		return err
   195  	}
   196  
   197  	if !ok {
   198  		return model.NewAppError("checkUserMfa", "api.user.check_user_mfa.bad_code.app_error", nil, "", http.StatusUnauthorized)
   199  	}
   200  
   201  	return nil
   202  }
   203  
   204  func checkUserLoginAttempts(user *model.User, max int) *model.AppError {
   205  	if user.FailedAttempts >= max {
   206  		return model.NewAppError("checkUserLoginAttempts", "api.user.check_user_login_attempts.too_many.app_error", nil, "user_id="+user.Id, http.StatusUnauthorized)
   207  	}
   208  
   209  	return nil
   210  }
   211  
   212  func checkUserNotDisabled(user *model.User) *model.AppError {
   213  	if user.DeleteAt > 0 {
   214  		return model.NewAppError("Login", "api.user.login.inactive.app_error", nil, "user_id="+user.Id, http.StatusUnauthorized)
   215  	}
   216  	return nil
   217  }
   218  
   219  func checkUserNotBot(user *model.User) *model.AppError {
   220  	if user.IsBot {
   221  		return model.NewAppError("Login", "api.user.login.bot_login_forbidden.app_error", nil, "user_id="+user.Id, http.StatusUnauthorized)
   222  	}
   223  	return nil
   224  }
   225  
   226  func (a *App) authenticateUser(user *model.User, password, mfaToken string) (*model.User, *model.AppError) {
   227  	license := a.Srv().License()
   228  	ldapAvailable := *a.Config().LdapSettings.Enable && a.Ldap() != nil && license != nil && *license.Features.LDAP
   229  
   230  	if user.AuthService == model.USER_AUTH_SERVICE_LDAP {
   231  		if !ldapAvailable {
   232  			err := model.NewAppError("login", "api.user.login_ldap.not_available.app_error", nil, "", http.StatusNotImplemented)
   233  			return user, err
   234  		}
   235  
   236  		ldapUser, err := a.checkLdapUserPasswordAndAllCriteria(user.AuthData, password, mfaToken)
   237  		if err != nil {
   238  			err.StatusCode = http.StatusUnauthorized
   239  			return user, err
   240  		}
   241  
   242  		// slightly redundant to get the user again, but we need to get it from the LDAP server
   243  		return ldapUser, nil
   244  	}
   245  
   246  	if user.AuthService != "" {
   247  		authService := user.AuthService
   248  		if authService == model.USER_AUTH_SERVICE_SAML {
   249  			authService = strings.ToUpper(authService)
   250  		}
   251  		err := model.NewAppError("login", "api.user.login.use_auth_service.app_error", map[string]interface{}{"AuthService": authService}, "", http.StatusBadRequest)
   252  		return user, err
   253  	}
   254  
   255  	if err := a.CheckPasswordAndAllCriteria(user, password, mfaToken); err != nil {
   256  		err.StatusCode = http.StatusUnauthorized
   257  		return user, err
   258  	}
   259  
   260  	return user, nil
   261  }
   262  
   263  func ParseAuthTokenFromRequest(r *http.Request) (string, TokenLocation) {
   264  	authHeader := r.Header.Get(model.HEADER_AUTH)
   265  
   266  	// Attempt to parse the token from the cookie
   267  	if cookie, err := r.Cookie(model.SESSION_COOKIE_TOKEN); err == nil {
   268  		return cookie.Value, TokenLocationCookie
   269  	}
   270  
   271  	// Parse the token from the header
   272  	if len(authHeader) > 6 && strings.ToUpper(authHeader[0:6]) == model.HEADER_BEARER {
   273  		// Default session token
   274  		return authHeader[7:], TokenLocationHeader
   275  	}
   276  
   277  	if len(authHeader) > 5 && strings.ToLower(authHeader[0:5]) == model.HEADER_TOKEN {
   278  		// OAuth token
   279  		return authHeader[6:], TokenLocationHeader
   280  	}
   281  
   282  	// Attempt to parse token out of the query string
   283  	if token := r.URL.Query().Get("access_token"); token != "" {
   284  		return token, TokenLocationQueryString
   285  	}
   286  
   287  	if token := r.Header.Get(model.HEADER_CLOUD_TOKEN); token != "" {
   288  		return token, TokenLocationCloudHeader
   289  	}
   290  
   291  	return "", TokenLocationNotFound
   292  }