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