/// <summary> /// Creates a new instance of an identity, but impersonated by the specified user. /// </summary> /// <param name="userID">The unique identity of the user to impersonate.</param> /// <param name="name">The name of the user to impersonate.</param> /// <param name="impersonator">The impersonator's authenticated identity.</param> public UserIdentity(Guid userID, string name, UserIdentity impersonator) { while (impersonator.ImpersonatorIdentity != null) // should be max 1 level deep impersonator = impersonator.ImpersonatorIdentity; //don't impersonate multiple levels deep. if (impersonator == null || !impersonator.IsAuthenticated || impersonator.Ticket == null || impersonator.Ticket.UserSession == null || impersonator.Ticket.UserSession.ExpirationDate < DateTime.UtcNow) throw new ApplicationException("You cannot impersonate at this time, because your session has ended."); Ticket = new AuthenticationHistory { CreatedDate = DateTime.Now, IPAddress = impersonator.Ticket.IPAddress, IsAuthenticated = impersonator.Ticket.IsAuthenticated, UserName = name, SessionID = impersonator.Ticket.SessionID, UserSession = new UserSession { CreatedDate = DateTime.Now, ExpirationDate = impersonator.Ticket.UserSession.ExpirationDate, RenewalToken = impersonator.Ticket.UserSession.RenewalToken, RenewedDate = impersonator.Ticket.UserSession.RenewedDate, SessionID = impersonator.Ticket.SessionID, UserID = userID } }; ImpersonatorIdentity = impersonator; }
/// <summary> /// Creates a new instance of an identity, but impersonated by the specified user. /// </summary> /// <param name="userID">The unique identity of the user to impersonate.</param> /// <param name="name">The name of the user to impersonate.</param> /// <param name="impersonator">The impersonator's authenticated identity.</param> public UserIdentity(Guid userID, string name, UserIdentity impersonator) { while (impersonator.ImpersonatorIdentity != null) // should be max 1 level deep { impersonator = impersonator.ImpersonatorIdentity; //don't impersonate multiple levels deep. } if (impersonator == null || !impersonator.IsAuthenticated || impersonator.Ticket == null || impersonator.Ticket.UserSession == null || impersonator.Ticket.UserSession.ExpirationDate < DateTime.UtcNow) { throw new ApplicationException("You cannot impersonate at this time, because your session has ended."); } Ticket = new AuthenticationHistory { CreatedDate = DateTime.Now, IPAddress = impersonator.Ticket.IPAddress, IsAuthenticated = impersonator.Ticket.IsAuthenticated, UserName = name, SessionID = impersonator.Ticket.SessionID, UserSession = new UserSession { CreatedDate = DateTime.Now, ExpirationDate = impersonator.Ticket.UserSession.ExpirationDate, RenewalToken = impersonator.Ticket.UserSession.RenewalToken, RenewedDate = impersonator.Ticket.UserSession.RenewedDate, SessionID = impersonator.Ticket.SessionID, UserID = userID } }; ImpersonatorIdentity = impersonator; }
/// <summary> /// Creates a user instance from an authentication attempt. /// </summary> /// <param name="ticket">The authentication results.</param> /// <param name="authType">The provider that authentication this identity.</param> public UserIdentity(AuthenticationHistory ticket, String authType) { if (ticket == null) { Ticket = new AuthenticationHistory { IsAuthenticated = false, UserName = string.Empty, CreatedDate = DateTime.Now, UserSession = new UserSession {ExpirationDate = DateTime.Now, UserID = Guid.Empty} }; _authenticationType = authType ?? "None"; } else { Ticket = ticket; _authenticationType = authType; } }
/// <summary> /// Creates a user instance from an authentication attempt. /// </summary> /// <param name="ticket">The authentication results.</param> /// <param name="authType">The provider that authentication this identity.</param> public UserIdentity(AuthenticationHistory ticket, String authType) { if (ticket == null) { Ticket = new AuthenticationHistory { IsAuthenticated = false, UserName = string.Empty, CreatedDate = DateTime.Now, UserSession = new UserSession { ExpirationDate = DateTime.Now, UserID = Guid.Empty } }; _authenticationType = authType ?? "None"; } else { Ticket = ticket; _authenticationType = authType; } }
protected override void InsertUserHistory(AuthenticationHistory history) { throw new NotImplementedException(); }
/// <summary> /// Inserts a new user authentication history. /// </summary> /// <param name="history"></param> protected abstract void InsertUserHistory(AuthenticationHistory history);
/// <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> /// Inserts a new user authentication history. /// </summary> /// <param name="history"></param> protected override void InsertUserHistory(AuthenticationHistory history) { using (var cn = new SqlConnection(ConnectionStringAudit)) { cn.Open(); using (var cmd = new SqlCommand()) { cmd.Connection = cn; cmd.CommandType = System.Data.CommandType.Text; cmd.CommandText = @"insert into Security.AuthenticationHistory (UserName, IpAddress, IsAuthenticated) Values (@UserName, @IpAddress, @IsAuthenticated)"; cmd.Parameters.AddWithValue("UserName", history.UserName); cmd.Parameters.AddWithValue("IpAddress", history.IPAddress); cmd.Parameters.AddWithValue("IsAuthenticated", history.IsAuthenticated); cmd.ExecuteNonQuery(); } } SaveUserSession(history.UserSession); }
/// <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)); }