/// <summary> /// Attempts to log in a user. /// </summary> /// <param name="name">Username. Cannot be null.</param> /// <param name="pass">Password. Cannot be null.</param> /// <param name="hostname">Host name where the user is logging in from. Cannot be null.</param> /// <param name="delayFailedLogin">Whether failed login should cause artificial delay.</param> /// <returns>Login attempt result. Cannot be null.</returns> public LoginResult CheckAuthentication(string name, string pass, string hostname, bool delayFailedLogin) { if (string.IsNullOrWhiteSpace(name) || string.IsNullOrEmpty(pass)) { return(LoginResult.CreateError(LoginError.InvalidPassword)); } var lc = name.ToLowerInvariant(); return(repository.HandleTransaction(ctx => { if (IsPoisoned(ctx, lc)) { ctx.AuditLogger.SysLog(string.Format("failed login from {0} - account is poisoned.", MakeGeoIpToolLink(hostname)), name); return LoginResult.CreateError(LoginError.AccountPoisoned); } // Attempt to find user by either lowercase username. var user = ctx.Query().FirstOrDefault(u => u.Active && (u.NameLC == lc || (u.Options.EmailVerified && u.Email == name))); if (user == null) { ctx.AuditLogger.AuditLog(string.Format("failed login from {0} - no user.", MakeGeoIpToolLink(hostname)), name); if (delayFailedLogin) { Thread.Sleep(2000); } return LoginResult.CreateError(LoginError.NotFound); } // Attempt to verify password. var hashed = LoginManager.GetHashedPass(user.NameLC, pass, user.Salt); if (user.Password != hashed) { ctx.AuditLogger.AuditLog(string.Format("failed login from {0} - wrong password.", MakeGeoIpToolLink(hostname)), name); if (delayFailedLogin) { Thread.Sleep(2000); } return LoginResult.CreateError(LoginError.InvalidPassword); } // Login attempt successful. ctx.AuditLogger.AuditLog(string.Format("logged in from {0} with '{1}'.", MakeGeoIpToolLink(hostname), name), user); user.UpdateLastLogin(hostname); ctx.Update(user); return LoginResult.CreateSuccess(new UserContract(user)); })); }