protected override void SaveUserSession(UserSession session) { throw new NotImplementedException(); }
/// <summary> /// Saves a user session, insert or update. /// </summary> /// <param name="session"></param> protected abstract void SaveUserSession(UserSession session);
protected override AuthenticationHistory GetSessionAuthenticationHistory(UserSession session) { throw new NotImplementedException(); }
/// <summary> /// Authenticates a user with the requested rule options. This internal method is called /// by the other public versions of the method. Override in a derived class if you want /// to change the rule interpretations or add new rules. /// </summary> /// <param name="name"></param> /// <param name="password"></param> /// <param name="duration"></param> /// <param name="ipAddress"></param> /// <param name="checkHistory"></param> /// <param name="allowUpdateHash"></param> /// <param name="result"></param> /// <returns></returns> protected virtual UserIdentity AuthenticateUser(string name, string password, UserSessionDurationType duration, string ipAddress, bool checkHistory, bool allowUpdateHash, ExecutionResults result) { if (checkHistory) { var recentFailures = GetRecentFailedUserNameAuthenticationCount(name); if (recentFailures > AllowedFailuresPerPeriod) return FailAuthenticateUser(name, ipAddress, result); } var user = GetUserByName(name); if (user == null) return FailAuthenticateUser(name, ipAddress, result); var salt = GetUserSalt(user.UserID); if (salt == null) return FailAuthenticateUser(name, ipAddress, result); //this should get a named hashProvider used to originally hash the password... // fallback to 'default' provider in legacy case when we didn't store the name. var hasher = !string.IsNullOrEmpty(salt.HashName) ? HashManager.Providers[salt.HashName] : HashManager.DefaultProvider; var passwordHash = hasher.Hash(salt.PasswordSalt, password, salt.HashGroup + BaseHashIterations); if (user.PasswordHash != passwordHash) return FailAuthenticateUser(name, ipAddress, result); var session = new UserSession { CreatedDate = DateTime.UtcNow, ExpirationDate = DateTime.UtcNow.AddMinutes(duration == UserSessionDurationType.PublicComputer ? PublicSessionDuration : ExtendedSessionDuration), UserID = user.UserID, RenewalToken = Guid.NewGuid() }; var history = new AuthenticationHistory { CreatedDate = session.CreatedDate, IPAddress = ipAddress, IsAuthenticated = true, UserName = name, SessionID = session.SessionID, UserSession = session }; using (var scope = new System.Transactions.TransactionScope()) { if (allowUpdateHash && (hasher.IsObsolete || user.PasswordHashUpdatedDate < DateTime.UtcNow.AddMonths(-1))) { //update hashes on regular basis, keeps the iterations in latest range for current users, and with a 'current' hash provider. hasher = HashManager.SelectProvider(); salt.PasswordSalt = hasher.GetSalt(); salt.HashGroup = new Random(DateTime.Now.Second).Next(HashGroupMinimum, HashGroupMaximum); salt.HashName = hasher.Name; user.PasswordHash = hasher.Hash(salt.PasswordSalt, password, salt.HashGroup + BaseHashIterations); user.PasswordHashUpdatedDate = DateTime.UtcNow; //starts as a lightweight transaction SaveUser(user); //enlists in a full distributed transaction if users and salts have different connection strings SaveUserSalt(salt); } //either continues distributed transaction if applicable, // or creates a new lightweight transaction for these two commands SaveUserSession(session); InsertUserHistory(history); scope.Complete(); } return new UserIdentity(history, Name); }
/// <summary> /// Gets the authentication history for a specific session. /// </summary> /// <param name="session"></param> /// <returns></returns> protected abstract AuthenticationHistory GetSessionAuthenticationHistory(UserSession session);
/// <summary> /// Saves a user session, insert or update. /// </summary> /// <param name="session"></param> protected override void SaveUserSession(UserSession session) { using (var cn = new SqlConnection(ConnectionStringAudit)) { cn.Open(); using (var cmd = new SqlCommand()) { cmd.Connection = cn; cmd.CommandType = System.Data.CommandType.Text; if (session.SessionID == 0) { cmd.CommandText = @"insert into Security.UserSession (UserID, RenewalToken, ExpirationDate) Values (@UserID, @RenewalToken, @ExpirationDate)"; cmd.Parameters.AddWithValue("UserID", session.UserID); cmd.Parameters.AddWithValue("RenewalToken", session.RenewalToken); cmd.Parameters.AddWithValue("ExpirationDate", session.ExpirationDate); } else { cmd.CommandText = @"update Security.UserSession set ExpirationDate = @ExpirationDate, RenewedDate = @RenewedDate where SessionID = @SessionID"; cmd.Parameters.AddWithValue("ExpirationDate", session.ExpirationDate); cmd.Parameters.AddWithValue("RenewedDate", session.RenewedDate); cmd.Parameters.AddWithValue("SessionID", session.SessionID); } cmd.ExecuteNonQuery(); } } }
/// <summary> /// Gets the authentication history for a specific session. /// </summary> /// <param name="session"></param> /// <returns></returns> protected override AuthenticationHistory GetSessionAuthenticationHistory(UserSession session) { using (var cn = new SqlConnection(ConnectionStringAudit)) { cn.Open(); using (var cmd = new SqlCommand()) { cmd.Connection = cn; cmd.CommandType = System.Data.CommandType.Text; cmd.CommandText = @"Select top 1 RecordID, UserName, IPAddress, CreatedDate, IsAuthenticated, SessionID from Security.AuthenticationHistory where SessionID = @SessionID and IsAuthenticated == 1 order by CreatedDate desc"; cmd.Parameters.AddWithValue("SessionID", session.SessionID); using (var reader = cmd.ExecuteReader()) { if (reader.Read()) { return new AuthenticationHistory { RecordID = reader.GetInt32("RecordID", 0), UserName = reader.GetString("UserName", ""), IPAddress = reader.GetString("IPAddress", ""), CreatedDate = reader.GetUTCDateTime("CreatedDate", DateTime.MinValue), IsAuthenticated = reader.GetBoolean("IsAuthenticated", false), SessionID = session.SessionID, UserSession = session }; } } } } return null; }
/// <summary> /// Authenticates a user with the requested rule options. This internal method is called /// by the other public versions of the method. Override in a derived class if you want /// to change the rule interpretations or add new rules. /// </summary> /// <param name="name"></param> /// <param name="password"></param> /// <param name="duration"></param> /// <param name="ipAddress"></param> /// <param name="checkHistory"></param> /// <param name="allowUpdateHash"></param> /// <param name="result"></param> /// <returns></returns> protected virtual UserIdentity AuthenticateUser(string name, string password, UserSessionDurationType duration, string ipAddress, bool checkHistory, bool allowUpdateHash, ExecutionResults result) { if (checkHistory) { var recentFailures = GetRecentFailedUserNameAuthenticationCount(name); if (recentFailures > AllowedFailuresPerPeriod) { return(FailAuthenticateUser(name, ipAddress, result)); } } var user = GetUserByName(name); if (user == null) { return(FailAuthenticateUser(name, ipAddress, result)); } var salt = GetUserSalt(user.UserID); if (salt == null) { return(FailAuthenticateUser(name, ipAddress, result)); } //this should get a named hashProvider used to originally hash the password... // fallback to 'default' provider in legacy case when we didn't store the name. var hasher = !string.IsNullOrEmpty(salt.HashName) ? HashManager.Providers[salt.HashName] : HashManager.DefaultProvider; var passwordHash = hasher.Hash(salt.PasswordSalt, password, salt.HashGroup + BaseHashIterations); if (user.PasswordHash != passwordHash) { return(FailAuthenticateUser(name, ipAddress, result)); } var session = new UserSession { CreatedDate = DateTime.UtcNow, ExpirationDate = DateTime.UtcNow.AddMinutes(duration == UserSessionDurationType.PublicComputer ? PublicSessionDuration : ExtendedSessionDuration), UserID = user.UserID, RenewalToken = Guid.NewGuid() }; var history = new AuthenticationHistory { CreatedDate = session.CreatedDate, IPAddress = ipAddress, IsAuthenticated = true, UserName = name, SessionID = session.SessionID, UserSession = session }; using (var scope = new System.Transactions.TransactionScope()) { if (allowUpdateHash && (hasher.IsObsolete || user.PasswordHashUpdatedDate < DateTime.UtcNow.AddMonths(-1))) { //update hashes on regular basis, keeps the iterations in latest range for current users, and with a 'current' hash provider. hasher = HashManager.SelectProvider(); salt.PasswordSalt = hasher.GetSalt(); salt.HashGroup = new Random(DateTime.Now.Second).Next(HashGroupMinimum, HashGroupMaximum); salt.HashName = hasher.Name; user.PasswordHash = hasher.Hash(salt.PasswordSalt, password, salt.HashGroup + BaseHashIterations); user.PasswordHashUpdatedDate = DateTime.UtcNow; //starts as a lightweight transaction SaveUser(user); //enlists in a full distributed transaction if users and salts have different connection strings SaveUserSalt(salt); } //either continues distributed transaction if applicable, // or creates a new lightweight transaction for these two commands SaveUserSession(session); InsertUserHistory(history); scope.Complete(); } return(new UserIdentity(history, Name)); }