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