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 }