github.com/gigforks/mattermost-server@v4.9.1-0.20180619094218-800d97fa55d0+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  type TokenLocation int
    15  
    16  const (
    17  	TokenLocationNotFound = iota
    18  	TokenLocationHeader
    19  	TokenLocationCookie
    20  	TokenLocationQueryString
    21  )
    22  
    23  func (tl TokenLocation) String() string {
    24  	switch tl {
    25  	case TokenLocationNotFound:
    26  		return "Not Found"
    27  	case TokenLocationHeader:
    28  		return "Header"
    29  	case TokenLocationCookie:
    30  		return "Cookie"
    31  	case TokenLocationQueryString:
    32  		return "QueryString"
    33  	default:
    34  		return "Unknown"
    35  	}
    36  }
    37  
    38  func (a *App) IsPasswordValid(password string) *model.AppError {
    39  	if license := a.License(); license != nil && *license.Features.PasswordRequirements {
    40  		return utils.IsPasswordValidWithSettings(password, &a.Config().PasswordSettings)
    41  	}
    42  	return utils.IsPasswordValid(password)
    43  }
    44  
    45  func (a *App) CheckPasswordAndAllCriteria(user *model.User, password string, mfaToken string) *model.AppError {
    46  	if err := a.CheckUserPreflightAuthenticationCriteria(user, mfaToken); err != nil {
    47  		return err
    48  	}
    49  
    50  	if err := a.checkUserPassword(user, password); err != nil {
    51  		return err
    52  	}
    53  
    54  	if err := a.CheckUserPostflightAuthenticationCriteria(user); err != nil {
    55  		return err
    56  	}
    57  
    58  	return nil
    59  }
    60  
    61  // This to be used for places we check the users password when they are already logged in
    62  func (a *App) doubleCheckPassword(user *model.User, password string) *model.AppError {
    63  	if err := checkUserLoginAttempts(user, *a.Config().ServiceSettings.MaximumLoginAttempts); err != nil {
    64  		return err
    65  	}
    66  
    67  	if err := a.checkUserPassword(user, password); err != nil {
    68  		return err
    69  	}
    70  
    71  	return nil
    72  }
    73  
    74  func (a *App) checkUserPassword(user *model.User, password string) *model.AppError {
    75  	if !model.ComparePassword(user.Password, password) {
    76  		if result := <-a.Srv.Store.User().UpdateFailedPasswordAttempts(user.Id, user.FailedAttempts+1); result.Err != nil {
    77  			return result.Err
    78  		}
    79  
    80  		return model.NewAppError("checkUserPassword", "api.user.check_user_password.invalid.app_error", nil, "user_id="+user.Id, http.StatusUnauthorized)
    81  	} else {
    82  		if result := <-a.Srv.Store.User().UpdateFailedPasswordAttempts(user.Id, 0); result.Err != nil {
    83  			return result.Err
    84  		}
    85  
    86  		return nil
    87  	}
    88  }
    89  
    90  func (a *App) checkLdapUserPasswordAndAllCriteria(ldapId *string, password string, mfaToken string) (*model.User, *model.AppError) {
    91  	if a.Ldap == nil || ldapId == nil {
    92  		err := model.NewAppError("doLdapAuthentication", "api.user.login_ldap.not_available.app_error", nil, "", http.StatusNotImplemented)
    93  		return nil, err
    94  	}
    95  
    96  	var user *model.User
    97  	if ldapUser, err := a.Ldap.DoLogin(*ldapId, password); err != nil {
    98  		err.StatusCode = http.StatusUnauthorized
    99  		return nil, err
   100  	} else {
   101  		user = ldapUser
   102  	}
   103  
   104  	if err := a.CheckUserMfa(user, mfaToken); err != nil {
   105  		return nil, err
   106  	}
   107  
   108  	if err := checkUserNotDisabled(user); err != nil {
   109  		return nil, err
   110  	}
   111  
   112  	// user successfully authenticated
   113  	return user, nil
   114  }
   115  
   116  func (a *App) CheckUserAllAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError {
   117  	if err := a.CheckUserPreflightAuthenticationCriteria(user, mfaToken); err != nil {
   118  		return err
   119  	}
   120  
   121  	if err := a.CheckUserPostflightAuthenticationCriteria(user); err != nil {
   122  		return err
   123  	}
   124  
   125  	return nil
   126  }
   127  
   128  func (a *App) CheckUserPreflightAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError {
   129  	if err := a.CheckUserMfa(user, mfaToken); err != nil {
   130  		return err
   131  	}
   132  
   133  	if err := checkUserNotDisabled(user); err != nil {
   134  		return err
   135  	}
   136  
   137  	if err := checkUserLoginAttempts(user, *a.Config().ServiceSettings.MaximumLoginAttempts); err != nil {
   138  		return err
   139  	}
   140  
   141  	return nil
   142  }
   143  
   144  func (a *App) CheckUserPostflightAuthenticationCriteria(user *model.User) *model.AppError {
   145  	if !user.EmailVerified && a.Config().EmailSettings.RequireEmailVerification {
   146  		return model.NewAppError("Login", "api.user.login.not_verified.app_error", nil, "user_id="+user.Id, http.StatusUnauthorized)
   147  	}
   148  
   149  	return nil
   150  }
   151  
   152  func (a *App) CheckUserMfa(user *model.User, token string) *model.AppError {
   153  	if license := a.License(); !user.MfaActive || license == nil || !*license.Features.MFA || !*a.Config().ServiceSettings.EnableMultifactorAuthentication {
   154  		return nil
   155  	}
   156  
   157  	if a.Mfa == nil {
   158  		return model.NewAppError("checkUserMfa", "api.user.check_user_mfa.not_available.app_error", nil, "", http.StatusNotImplemented)
   159  	}
   160  
   161  	if ok, err := a.Mfa.ValidateToken(user.MfaSecret, token); err != nil {
   162  		return err
   163  	} else if !ok {
   164  		return model.NewAppError("checkUserMfa", "api.user.check_user_mfa.bad_code.app_error", nil, "", http.StatusUnauthorized)
   165  	}
   166  
   167  	return nil
   168  }
   169  
   170  func checkUserLoginAttempts(user *model.User, max int) *model.AppError {
   171  	if user.FailedAttempts >= max {
   172  		return model.NewAppError("checkUserLoginAttempts", "api.user.check_user_login_attempts.too_many.app_error", nil, "user_id="+user.Id, http.StatusUnauthorized)
   173  	}
   174  
   175  	return nil
   176  }
   177  
   178  func checkUserNotDisabled(user *model.User) *model.AppError {
   179  	if user.DeleteAt > 0 {
   180  		return model.NewAppError("Login", "api.user.login.inactive.app_error", nil, "user_id="+user.Id, http.StatusUnauthorized)
   181  	}
   182  	return nil
   183  }
   184  
   185  func (a *App) authenticateUser(user *model.User, password, mfaToken string) (*model.User, *model.AppError) {
   186  	license := a.License()
   187  	ldapAvailable := *a.Config().LdapSettings.Enable && a.Ldap != nil && license != nil && *license.Features.LDAP
   188  
   189  	if user.AuthService == model.USER_AUTH_SERVICE_LDAP {
   190  		if !ldapAvailable {
   191  			err := model.NewAppError("login", "api.user.login_ldap.not_available.app_error", nil, "", http.StatusNotImplemented)
   192  			return user, err
   193  		} else if ldapUser, err := a.checkLdapUserPasswordAndAllCriteria(user.AuthData, password, mfaToken); err != nil {
   194  			err.StatusCode = http.StatusUnauthorized
   195  			return user, err
   196  		} else {
   197  			// slightly redundant to get the user again, but we need to get it from the LDAP server
   198  			return ldapUser, nil
   199  		}
   200  	} else if user.AuthService != "" {
   201  		authService := user.AuthService
   202  		if authService == model.USER_AUTH_SERVICE_SAML {
   203  			authService = strings.ToUpper(authService)
   204  		}
   205  		err := model.NewAppError("login", "api.user.login.use_auth_service.app_error", map[string]interface{}{"AuthService": authService}, "", http.StatusBadRequest)
   206  		return user, err
   207  	} else {
   208  		if err := a.CheckPasswordAndAllCriteria(user, password, mfaToken); err != nil {
   209  			err.StatusCode = http.StatusUnauthorized
   210  			return user, err
   211  		} else {
   212  			return user, nil
   213  		}
   214  	}
   215  }
   216  
   217  func ParseAuthTokenFromRequest(r *http.Request) (string, TokenLocation) {
   218  	authHeader := r.Header.Get(model.HEADER_AUTH)
   219  	if len(authHeader) > 6 && strings.ToUpper(authHeader[0:6]) == model.HEADER_BEARER {
   220  		// Default session token
   221  		return authHeader[7:], TokenLocationHeader
   222  	} else if len(authHeader) > 5 && strings.ToLower(authHeader[0:5]) == model.HEADER_TOKEN {
   223  		// OAuth token
   224  		return authHeader[6:], TokenLocationHeader
   225  	}
   226  
   227  	// Attempt to parse the token from the cookie
   228  	if cookie, err := r.Cookie(model.SESSION_COOKIE_TOKEN); err == nil {
   229  		return cookie.Value, TokenLocationCookie
   230  	}
   231  
   232  	// Attempt to parse token out of the query string
   233  	if token := r.URL.Query().Get("access_token"); token != "" {
   234  		return token, TokenLocationQueryString
   235  	}
   236  
   237  	return "", TokenLocationNotFound
   238  }