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