public static bool SetUserPassword(string AUsername, string ANewPassword, bool APasswordNeedsChanged, bool AUnretireIfRetired, string AClientComputerName, string AClientIPAddress, out TVerificationResultCollection AVerification) { TVerificationResult VerificationResult; SUserTable UserTable; SUserRow UserDR; string UserAuthenticationMethod = TAppSettingsManager.GetValue("UserAuthenticationMethod", "OpenPetraDBSUser", false); bool BogusPasswordChangeAttempt = false; AVerification = new TVerificationResultCollection(); // Password quality check if (!TSharedSysManValidation.CheckPasswordQuality(ANewPassword, out VerificationResult)) { AVerification.Add(VerificationResult); return(false); } if (UserAuthenticationMethod == "OpenPetraDBSUser") { TDBTransaction SubmitChangesTransaction = null; bool SubmissionResult = false; TPetraPrincipal tempPrincipal; DBAccess.GDBAccessObj.BeginAutoTransaction(IsolationLevel.Serializable, ref SubmitChangesTransaction, ref SubmissionResult, delegate { try { UserDR = TUserManagerWebConnector.LoadUser(AUsername.ToUpper(), out tempPrincipal, SubmitChangesTransaction); } catch (EUserNotExistantException) { // Because this cannot happen when a password change gets effected through normal OpenPetra // operation this is treated as a bogus operation that an attacker launches! BogusPasswordChangeAttempt = true; // Logging TUserAccountActivityLog.AddUserAccountActivityLogEntry(AUsername, TUserAccountActivityLog.USER_ACTIVITY_PWD_CHANGE_ATTEMPT_BY_SYSADMIN_FOR_NONEXISTING_USER, String.Format(Catalog.GetString( "A system administrator, {0}, made an attempt to change a User's password for UserID {1} " + "but that user doesn't exist! "), UserInfo.GUserInfo.UserID, AUsername) + String.Format(ResourceTexts.StrRequestCallerInfo, AClientComputerName, AClientIPAddress), SubmitChangesTransaction); SubmissionResult = true; // Need to set this so that the DB Transaction gets committed! // Simulate that time is spent on 'authenticating' a user (although the user doesn't exist)...! Reason for that: see Method // SimulatePasswordAuthenticationForNonExistingUser! TUserManagerWebConnector.SimulatePasswordAuthenticationForNonExistingUser(); return; } UserTable = (SUserTable)UserDR.Table; // Note: We are on purpose NOT checking here whether the new password is the same as the existing // password (which would be done by calling the IsNewPasswordSameAsExistingPassword Method) because // if we would do that then the SYSADMIN could try to find out what the password of a user is by // seeing if (s)he would get a message that the new password must be different from the old password...! SetNewPasswordHashAndSaltForUser(UserDR, ANewPassword, AClientComputerName, AClientIPAddress, SubmitChangesTransaction); UserDR.PasswordNeedsChange = APasswordNeedsChanged; // 'Unretire' the user if the user has been previously 'retired' and also 'unlock' the User Account if // it has previously been locked if (AUnretireIfRetired) { UserDR.Retired = false; UserDR.AccountLocked = false; } try { SUserAccess.SubmitChanges(UserTable, SubmitChangesTransaction); TUserAccountActivityLog.AddUserAccountActivityLogEntry(UserDR.UserId, TUserAccountActivityLog.USER_ACTIVITY_PWD_CHANGE_BY_SYSADMIN, String.Format(Catalog.GetString( "The password of user {0} got changed by user {1} (the latter user has got SYSADMIN " + "privileges). "), UserDR.UserId, UserInfo.GUserInfo.UserID) + String.Format(ResourceTexts.StrRequestCallerInfo, AClientComputerName, AClientIPAddress), SubmitChangesTransaction); } catch (Exception Exc) { TLogging.Log("An Exception occured during the saving of the new User Password by the SYSADMIN:" + Environment.NewLine + Exc.ToString()); throw; } SubmissionResult = true; }); return(!BogusPasswordChangeAttempt); } else { IUserAuthentication auth = TUserManagerWebConnector.LoadAuthAssembly(UserAuthenticationMethod); return(auth.SetPassword(AUsername, ANewPassword)); } }
/// <summary> /// Call this Method when a log-in is attempted for a non-existing user (!) so that the time that is spent on /// 'authenticating' them is as long as is spent on authenticating existing users. This is done so that an attacker /// that tries to perform user authentication with 'username guessing' cannot easily tell that the user doesn't exist by /// checking the time in which the server returns an error (this is an attack vector called 'timing attack')! /// </summary> public void SimulatePasswordAuthenticationForNonExistingUser() { TUserManagerWebConnector.SimulatePasswordAuthenticationForNonExistingUser(); }
public static bool SetUserPassword(string AUserID, string ANewPassword, string ACurrentPassword, bool APasswordNeedsChanged, string AClientComputerName, string AClientIPAddress, out TVerificationResultCollection AVerification) { string UserAuthenticationMethod = TAppSettingsManager.GetValue("UserAuthenticationMethod", "OpenPetraDBSUser", false); TVerificationResult VerificationResult; TVerificationResultCollection VerificationResultColl = null; SUserRow UserDR = null; SUserTable UserTable = null; bool BogusPasswordChangeAttempt = false; AVerification = new TVerificationResultCollection(); // Security check: Is the user that is performing the password change request the current user? if (AUserID != UserInfo.GUserInfo.UserID) { throw new EOPAppException( "The setting of a User's Password must only be done by the user itself, but this isn't the case here and therefore the request gets denied"); } // Password quality check if (!TSharedSysManValidation.CheckPasswordQuality(ANewPassword, out VerificationResult)) { AVerification.Add(VerificationResult); return(false); } if (UserAuthenticationMethod == "OpenPetraDBSUser") { TPetraPrincipal tempPrincipal; TDBTransaction SubmitChangesTransaction = null; bool SubmissionResult = false; DBAccess.GDBAccessObj.BeginAutoTransaction(IsolationLevel.Serializable, ref SubmitChangesTransaction, ref SubmissionResult, delegate { try { UserDR = TUserManagerWebConnector.LoadUser(AUserID.ToUpper(), out tempPrincipal, SubmitChangesTransaction); } catch (EUserNotExistantException) { // Because this cannot happen when a password change gets effected through normal OpenPetra // operation this is treated as a bogus operation that an attacker launches! BogusPasswordChangeAttempt = true; // Logging TUserAccountActivityLog.AddUserAccountActivityLogEntry(AUserID, TUserAccountActivityLog.USER_ACTIVITY_PWD_CHANGE_ATTEMPT_BY_USER_FOR_NONEXISTING_USER, String.Format(Catalog.GetString( "User {0} tried to make an attempt to change a User's password for UserID {1} " + "but that user doesn't exist! "), UserInfo.GUserInfo.UserID, AUserID) + String.Format(ResourceTexts.StrRequestCallerInfo, AClientComputerName, AClientIPAddress), SubmitChangesTransaction); SubmissionResult = true; // Need to set this so that the DB Transaction gets committed! // Simulate that time is spent on 'authenticating' a user (although the user doesn't exist)...! Reason for that: see Method // SimulatePasswordAuthenticationForNonExistingUser! TUserManagerWebConnector.SimulatePasswordAuthenticationForNonExistingUser(); return; } UserTable = (SUserTable)UserDR.Table; // Security check: Is the supplied current password correct? if (TUserManagerWebConnector.CreateHashOfPassword(ACurrentPassword, UserDR.PasswordSalt, UserDR.PwdSchemeVersion) != UserDR.PasswordHash) { VerificationResultColl = new TVerificationResultCollection(); VerificationResultColl.Add(new TVerificationResult("Password Verification", Catalog.GetString( "The current password was entered incorrectly! The password did not get changed."), TResultSeverity.Resv_Critical)); try { SUserAccess.SubmitChanges(UserTable, SubmitChangesTransaction); TUserAccountActivityLog.AddUserAccountActivityLogEntry(UserDR.UserId, TUserAccountActivityLog.USER_ACTIVITY_PWD_WRONG_WHILE_PWD_CHANGE, String.Format(Catalog.GetString( "User {0} supplied the wrong current password while attempting to change " + "his/her password! ") + String.Format(ResourceTexts.StrRequestCallerInfo, AClientComputerName, AClientIPAddress), UserInfo.GUserInfo.UserID), SubmitChangesTransaction); SubmissionResult = true; } catch (Exception Exc) { TLogging.Log(String.Format( "An Exception occured during the changing of the User Password by user '{0}' (Situation 1):", AUserID) + Environment.NewLine + Exc.ToString()); throw; } } }); if (BogusPasswordChangeAttempt) { // Note: VerificationResultColl will be null in this case because we don't want to disclose to an attackeer // why the password change attempt was denied!!! return(false); } if (VerificationResultColl != null) { AVerification = VerificationResultColl; return(false); } // Security check: Is the supplied new password the same than the current password? if (IsNewPasswordSameAsExistingPassword(ANewPassword, UserDR, out VerificationResult)) { AVerification.Add(VerificationResult); return(false); } // // All checks passed: We go aheand and change the user's password! // SetNewPasswordHashAndSaltForUser(UserDR, ANewPassword, AClientComputerName, AClientIPAddress, SubmitChangesTransaction); UserDR.PasswordNeedsChange = false; DBAccess.GDBAccessObj.BeginAutoTransaction(IsolationLevel.Serializable, ref SubmitChangesTransaction, ref SubmissionResult, delegate { try { SUserAccess.SubmitChanges(UserTable, SubmitChangesTransaction); TUserAccountActivityLog.AddUserAccountActivityLogEntry(UserDR.UserId, (APasswordNeedsChanged ? TUserAccountActivityLog.USER_ACTIVITY_PWD_CHANGE_BY_USER_ENFORCED : TUserAccountActivityLog.USER_ACTIVITY_PWD_CHANGE_BY_USER), String.Format(Catalog.GetString("User {0} changed his/her password{1}"), UserInfo.GUserInfo.UserID, (APasswordNeedsChanged ? Catalog.GetString(" (enforced password change.) ") : ". ")) + String.Format(ResourceTexts.StrRequestCallerInfo, AClientComputerName, AClientIPAddress), SubmitChangesTransaction); SubmissionResult = true; } catch (Exception Exc) { TLogging.Log(String.Format("An Exception occured during the changing of the User Password by user '{0}' (Situation 2):", AUserID) + Environment.NewLine + Exc.ToString()); throw; } }); return(true); } else { IUserAuthentication auth = TUserManagerWebConnector.LoadAuthAssembly(UserAuthenticationMethod); return(auth.SetPassword(AUserID, ANewPassword, ACurrentPassword)); } }