/// <summary> /// Save a failed user login attempt. If the number of permitted failed logins in a row gets exceeded then the /// user account gets Locked, too! /// </summary> /// <param name="AUserID">User ID.</param> /// <param name="UserDR">s_user DataRow of the user.</param> /// <param name="AClientComputerName">Name of the Client Computer that the authentication request came from.</param> /// <param name="AClientIPAddress">IP Address of the Client Computer that the authentication request came from.</param> /// <param name="ATransaction">Instantiated DB Transaction.</param> private static void SaveFailedLogin(string AUserID, SUserRow UserDR, string AClientComputerName, string AClientIPAddress, TDBTransaction ATransaction) { int AProcessID; int FailedLoginsUntilAccountGetsLocked = TSystemDefaults.GetInt32Default(SharedConstants.SYSDEFAULT_FAILEDLOGINS_UNTIL_ACCOUNT_GETS_LOCKED, 10); bool AccountLockedAtThisAttempt = false; // Console.WriteLine('PetraPrincipal.PetraIdentity.FailedLogins: ' + PetraPrincipal.PetraIdentity.FailedLogins.ToString + // '; PetraPrincipal.PetraIdentity.AccountLocked: ' + PetraPrincipal.PetraIdentity.AccountLocked.ToString); UserDR.FailedLogins++; UserDR.FailedLoginDate = DateTime.Now; UserDR.FailedLoginTime = Conversions.DateTimeToInt32Time(UserDR.FailedLoginDate.Value); // Check if User Account should be Locked due to too many successive failed log-in attempts if ((UserDR.FailedLogins >= FailedLoginsUntilAccountGetsLocked) && ((!UserDR.AccountLocked))) { // Lock User Account (this user will no longer be able to log in until a Sysadmin resets this flag!) UserDR.AccountLocked = true; AccountLockedAtThisAttempt = true; TUserAccountActivityLog.AddUserAccountActivityLogEntry(UserDR.UserId, TUserAccountActivityLog.USER_ACTIVITY_PERMITTED_FAILED_LOGINS_EXCEEDED, String.Format(Catalog.GetString( "The permitted number of failed logins in a row got exceeded and the user account for the user {0} got locked! ") + String.Format(ResourceTexts.StrRequestCallerInfo, AClientComputerName, AClientIPAddress), UserDR.UserId), ATransaction); } // Logging TLoginLog.AddLoginLogEntry(AUserID, AccountLockedAtThisAttempt ? TLoginLog.LOGIN_STATUS_TYPE_LOGIN_ATTEMPT_PWD_WRONG_ACCOUNT_GOT_LOCKED : TLoginLog.LOGIN_STATUS_TYPE_LOGIN_ATTEMPT_PWD_WRONG, String.Format(Catalog.GetString("User supplied wrong password{0}! (Failed Logins: now {1}; " + "Account Locked: now {2}, User Retired: {3}) "), (AccountLockedAtThisAttempt ? Catalog.GetString("; because the permitted number of failed logins in a row got exceeded the user account " + "for the user got locked! ") : String.Empty), UserDR.FailedLogins, UserDR.AccountLocked, UserDR.Retired) + String.Format(ResourceTexts.StrRequestCallerInfo, AClientComputerName, AClientIPAddress), out AProcessID, ATransaction); SaveUser(AUserID, (SUserTable)UserDR.Table, ATransaction); }
public static TPetraPrincipal PerformUserAuthentication(String AUserID, String APassword, out Boolean ASystemEnabled) { DateTime LoginDateTime; TPetraPrincipal PetraPrincipal = null; Int32 AProcessID = -1; ASystemEnabled = true; string EmailAddress = AUserID; if (AUserID.Contains("@")) { AUserID = AUserID.Substring(0, AUserID.IndexOf("@")). Replace(".", string.Empty). Replace("_", string.Empty).ToUpper(); } try { SUserRow UserDR = LoadUser(AUserID, out PetraPrincipal); // Already assign the global variable here, because it is needed for SUserAccess.SubmitChanges later in this function UserInfo.GUserInfo = PetraPrincipal; // Check if user is retired if (PetraPrincipal.PetraIdentity.Retired) { throw new EUserRetiredException(StrInvalidUserIDPassword); } int FailedLoginsUntilRetire = TSystemDefaults.GetInt32Default(SharedConstants.SYSDEFAULT_FAILEDLOGINS_UNTIL_RETIRE, 10); // Console.WriteLine('PetraPrincipal.PetraIdentity.FailedLogins: ' + PetraPrincipal.PetraIdentity.FailedLogins.ToString + // '; PetraPrincipal.PetraIdentity.Retired: ' + PetraPrincipal.PetraIdentity.Retired.ToString); // Check if user should be autoretired if ((PetraPrincipal.PetraIdentity.FailedLogins >= FailedLoginsUntilRetire) && ((!PetraPrincipal.PetraIdentity.Retired))) { UserDR.Retired = true; UserDR.FailedLogins = 0; SaveUser(AUserID, (SUserTable)UserDR.Table); throw new EAccessDeniedException(StrInvalidUserIDPassword); } // Check SystemLoginStatus (Petra enabled/disabled) in the SystemStatus table (always holds only one record) Boolean NewTransaction = false; SSystemStatusTable SystemStatusDT; TDBTransaction ReadTransaction = DBAccess.GDBAccessObj.GetNewOrExistingTransaction(IsolationLevel.ReadCommitted, TEnforceIsolationLevel.eilMinimum, out NewTransaction); try { SystemStatusDT = SSystemStatusAccess.LoadAll(ReadTransaction); } finally { if (NewTransaction) { DBAccess.GDBAccessObj.CommitTransaction(); TLogging.LogAtLevel(7, "TUserManager.PerformUserAuthentication: committed own transaction."); } } if (SystemStatusDT[0].SystemLoginStatus) { ASystemEnabled = true; } else { ASystemEnabled = false; if (PetraPrincipal.IsInGroup("SYSADMIN")) { PetraPrincipal.LoginMessage = String.Format(StrSystemDisabled1, SystemStatusDT[0].SystemDisabledReason) + Environment.NewLine + Environment.NewLine + StrSystemDisabled2Admin; } else { TLoginLog.AddLoginLogEntry(AUserID, "System disabled", true, out AProcessID); throw new ESystemDisabledException(String.Format(StrSystemDisabled1, SystemStatusDT[0].SystemDisabledReason) + Environment.NewLine + Environment.NewLine + String.Format(StrSystemDisabled2, StringHelper.DateToLocalizedString(SystemStatusDT[0].SystemAvailableDate.Value), SystemStatusDT[0].SystemAvailableDate.Value.AddSeconds(SystemStatusDT[0].SystemAvailableTime).ToShortTimeString())); } } if ((AUserID == "SYSADMIN") && TSession.HasVariable("ServerAdminToken")) { // Login via server admin console authenticated by file token } else { string UserAuthenticationMethod = TAppSettingsManager.GetValue("UserAuthenticationMethod", "OpenPetraDBSUser", false); if (UserAuthenticationMethod == "OpenPetraDBSUser") { // TODO 1 oChristianK cSecurity : Perform user authentication by verifying password hash in the DB // see also ICTPetraWiki: Todo_Petra.NET#Implement_Security_.7B2.7D_.5BChristian.5D if (CreateHashOfPassword(String.Concat(APassword, UserDR.PasswordSalt)) != UserDR.PasswordHash) { // increase failed logins UserDR.FailedLogins++; LoginDateTime = DateTime.Now; UserDR.FailedLoginDate = LoginDateTime; UserDR.FailedLoginTime = Conversions.DateTimeToInt32Time(LoginDateTime); SaveUser(AUserID, (SUserTable)UserDR.Table); throw new EPasswordWrongException(StrInvalidUserIDPassword); } } else { IUserAuthentication auth = LoadAuthAssembly(UserAuthenticationMethod); string ErrorMessage; if (!auth.AuthenticateUser(EmailAddress, APassword, out ErrorMessage)) { UserDR.FailedLogins++; LoginDateTime = DateTime.Now; UserDR.FailedLoginDate = LoginDateTime; UserDR.FailedLoginTime = Conversions.DateTimeToInt32Time(LoginDateTime); SaveUser(AUserID, (SUserTable)UserDR.Table); throw new EPasswordWrongException(ErrorMessage); } } } // Save successful login LoginDateTime = DateTime.Now; UserDR.LastLoginDate = LoginDateTime; UserDR.LastLoginTime = Conversions.DateTimeToInt32Time(LoginDateTime); UserDR.FailedLogins = 0; SaveUser(AUserID, (SUserTable)UserDR.Table); PetraPrincipal.PetraIdentity.CurrentLogin = LoginDateTime; // PetraPrincipal.PetraIdentity.FailedLogins := 0; if (PetraPrincipal.IsInGroup("SYSADMIN")) { TLoginLog.AddLoginLogEntry(AUserID, "Successful SYSADMIN", out AProcessID); } else { TLoginLog.AddLoginLogEntry(AUserID, "Successful", out AProcessID); } PetraPrincipal.ProcessID = AProcessID; AProcessID = 0; if (UserDR.PasswordNeedsChange) { // The user needs to change their password before they can use OpenPetra PetraPrincipal.LoginMessage = SharedConstants.LOGINMUSTCHANGEPASSWORD; } } finally { DBAccess.GDBAccessObj.RollbackTransaction(); } return(PetraPrincipal); }