public static bool PerformReset(string mailAddress, string ticket, string newPassword) { People people = People.FromMail(mailAddress.Trim()); if (people.Count != 1) { return(false); } Person resetPerson = people[0]; string[] resetData = resetPerson.ResetPasswordTicket.Split(','); if (resetData.Length != 2) { return(false); // invalid data or no ticket } // This may throw on invalid data, which will give a slightly different error but that's fine too for now. DateTime ticketExpiresUtc = DateTime.Parse(resetData[0]); if (DateTime.UtcNow > ticketExpiresUtc) { // Ticket expired. return(false); } if (ticket != resetData[1]) { // Bad ticket. return(false); } // When we get here, all checks to reset the password have completed. Change the password, log the change, // notify the user that the password was changed, set a new authentication cookie, and have the web page // redirect to Dashboard (by returning true). // Clear password reset ticket resetPerson.ResetPasswordTicket = string.Empty; // Create lockdown code, notify string lockdownTicket = SupportFunctions.GenerateSecureRandomKey(16); OutboundComm.CreateSecurityNotification(resetPerson, null, null, lockdownTicket, NotificationResource.Password_Changed); resetPerson.AccountLockdownTicket = DateTime.UtcNow.AddDays(1).ToString(CultureInfo.InvariantCulture) + "," + lockdownTicket; // Set new password resetPerson.SetPassword(newPassword); // Log the password reset SwarmopsLog.CreateEntry(resetPerson, new PasswordResetLogEntry(resetPerson, SupportFunctions.GetRemoteIPAddressChain())); // Set authentication cookies int lastOrgId = resetPerson.LastLogonOrganizationId; if (lastOrgId == 0) { lastOrgId = Organization.SandboxIdentity; } if (!resetPerson.ParticipatesInOrganizationOrParent(lastOrgId)) { // If the person doesn't have access to the last organization (anymore), log on to Sandbox lastOrgId = 1; } // Set cookies FormsAuthentication.SetAuthCookie(Authority.FromLogin(resetPerson).ToEncryptedXml(), true); DashboardMessage.Set(Resources.Pages.Security.ResetPassword_Success); return(true); // temp // do NOT NOT NOT trim password - this is deliberate. Passwords starting/ending in whitespace must be possible }
public static bool RequestTicket(string mailAddress) { mailAddress = mailAddress.Trim(); if (string.IsNullOrEmpty(mailAddress)) { return(false); // this is the only case when we return false: a _syntactically_invalid_ address } People concernedPeople = People.FromMail(mailAddress); // Should result in exactly 1 if (concernedPeople.Count != 1) { return(true); // TODO: Prevent registration with duplicate mail addy, or this will cause problems down the road } Person concernedPerson = concernedPeople[0]; if (!string.IsNullOrEmpty(concernedPerson.BitIdAddress)) { // Cannot reset password - two factor auth is enabled. Manual intervention required. OutboundComm.CreateSecurityNotification(concernedPerson, null, null, string.Empty, NotificationResource.Password_CannotReset2FA); return(true); // still returning true - the fail info is in mail only } string resetTicket = SupportFunctions.GenerateSecureRandomKey(16); resetTicket = resetTicket.Substring(0, 21); // We're using a 21-character (84-bit) key mostly for UI consistency with the ticket sent in mail, and it's secure enough concernedPerson.ResetPasswordTicket = DateTime.UtcNow.AddHours(1).ToString(CultureInfo.InvariantCulture) + "," + resetTicket; // Adds expiry - one hour OutboundComm.CreateSecurityNotification(concernedPerson, null, null, resetTicket, NotificationResource.Password_ResetOnRequest); SwarmopsLog.CreateEntry(null, new PasswordResetRequestLogEntry(concernedPerson, SupportFunctions.GetRemoteIPAddressChain())); return(true); }