/// <summary> /// Authenticates user's credentials. /// </summary> /// <param name="password">Password to be authenticated.</param> /// <returns>True if authentication was successful; otherwise False.</returns> public bool Authenticate(string password) { // We will not authenticate if user account doesn't exist or is locked. if (! m_isDefined || m_isLockedOut) { return false; } // Authenticate based on the specified authentication mode. switch (m_authenticationMode) { case AuthenticationMode.AD: if (m_isExternal) { // User is external according to the security database. if (! string.IsNullOrEmpty(password)) { // We'll validate the password against the security database. m_isAuthenticated = EncryptPassword(password) == m_password; } } else { // User is internal according to the security database. if (! string.IsNullOrEmpty(password)) { // We'll validate the password against the Active Directory. m_isAuthenticated = new UserInfo("TVA", m_username, true).Authenticate(password); } else { // The user to be authenticated is defined as an internal user in the security database, // but we don't have a password to authenticate against the Active Directory. ' In this // case the authentication requirement becomes that the user we're authenticating must // be user executing the request (i.e. accessing secure the app). string loginID = System.Threading.Thread.CurrentPrincipal.Identity.Name; if (! string.IsNullOrEmpty(loginID)) { m_isAuthenticated = string.Compare(m_username, loginID.Split('\\')[1], true) == 0; } } } break; case AuthenticationMode.RSA: TVA.Security.Radius.RadiusClient client = null; RadiusPacket response = null; try { // We first try to authenticate against the primary RSA server. client = new TVA.Security.Radius.RadiusClient(RsaServer1, TVA.Security.Cryptography.Common.Decrypt(RadiusSharedSecret)); response = client.Authenticate(m_username, password); if (response == null) { // We didn't get a response back from the primary RSA server. This is most likely // to happen when the primary server is unavailable, so we attempt to authenticate // against the backup RSA server. client.Dispose(); client = new TVA.Security.Radius.RadiusClient(RsaServer2, TVA.Security.Cryptography.Common.Decrypt(RadiusSharedSecret)); response = client.Authenticate(m_username, password); } if (response != null) { // We received a response back from the RSA server. switch (response.Type) { case PacketType.AccessAccept: // Credentials were accepted by the RSA server. m_isAuthenticated = true; break; case PacketType.AccessChallenge: // RSA server challenged our authentication request. if (client.IsUserInNewPinMode(response)) { // If the user's account is in the "new pin" mode, we treat it as if it's // time for the user to change the password so appropriate input form is // served to the user. m_passwordChangeDateTime = DateTime.Now; } else if (client.IsUserInNextTokenMode(response)) { // If the user's account is in the "next token" mode, we treat the account // as if it is disabled so the user must either email or call-in to get the // account enabled. m_isLockedOut = true; } break; } } } catch (Exception) { throw; } finally { if (client != null) { client.Dispose(); } } break; } // Log successful or unsuccessful authentication result to the security database so that a user account // gets locked-out automatically after a set number of unsuccessful login attempts. using (SqlConnection dbConnection = GetDatabaseConnection()) { TVA.Data.Common.ExecuteNonQuery("dbo.LogLogin", dbConnection, m_username, ! m_isAuthenticated); } return m_isAuthenticated; }
private void ClientHelper_AuthenticationFailure(object sender, CancelEventArgs e) { // Prompt for credentials. StringBuilder prompt = new StringBuilder(); UserInfo userInfo; string username; StringBuilder passwordBuilder = new StringBuilder(); prompt.AppendLine(); prompt.AppendLine(); prompt.Append("Connection to the service was rejected due to authentication failure. \r\n"); prompt.Append("Enter the credentials to be used for authentication with the service."); prompt.AppendLine(); prompt.AppendLine(); Console.Write(prompt.ToString()); // Tell outer connect loop to wait for authentication. m_authenticationWaitHandle.Reset(); // If the inner loop is active, post enter to the console // to escape the Console.ReadLine() in the inner loop. if (m_innerLoopActive) { m_remotingClient.Enabled = false; IntPtr hWnd = Process.GetCurrentProcess().MainWindowHandle; PostMessage(hWnd, WM_KEYDOWN, VK_RETURN, 0); Thread.Sleep(500); } // Capture the username. Console.Write("Enter username: "******"Enter password: "); while ((key = Console.ReadKey(true)).KeyChar != '\r') { passwordBuilder.Append(key.KeyChar); } // Set network credentials used when attempting AD authentication userInfo = new UserInfo(username); userInfo.Initialize(); m_remotingClient.NetworkCredential = new NetworkCredential(userInfo.LoginID, passwordBuilder.ToString()); // Set the username on the client helper. m_clientHelper.Username = username; m_clientHelper.Password = SecurityProviderUtility.EncryptPassword(passwordBuilder.ToString()); // Done with the console; signal reconnect. m_authenticationWaitHandle.Set(); // Re-attempt connection with new credentials. e.Cancel = true; Console.WriteLine(); Console.WriteLine(); }
/// <summary> /// Changes user password in the backend datastore. /// </summary> /// <param name="oldPassword">User's current password.</param> /// <param name="newPassword">User's new password.</param> /// <returns>true if the password is changed, otherwise false.</returns> /// <remarks> /// This method always returns <c>false</c> under Mono deployments. /// </remarks> public override bool ChangePassword(string oldPassword, string newPassword) { #if MONO return false; #else // Check prerequisites if (!UserData.IsDefined || UserData.IsDisabled || UserData.IsLockedOut) return false; UserInfo user = null; WindowsImpersonationContext context = null; try { string ldapPath = GetLdapPath(); // Create user info object using specified LDAP path if provided if (string.IsNullOrEmpty(ldapPath)) user = new UserInfo(UserData.Username); else user = new UserInfo(UserData.Username, ldapPath); // Initialize user entry user.PersistSettings = true; user.Initialize(); // Impersonate privileged user context = user.ImpersonatePrivilegedAccount(); // Change user password user.UserEntry.Invoke("ChangePassword", oldPassword, newPassword); // Commit changes (required for non-local accounts) if (!user.IsWinNTEntry) user.UserEntry.CommitChanges(); return true; } catch (TargetInvocationException ex) { // Propagate password change error if (ex.InnerException == null) throw new SecurityException(ex.Message, ex); else throw new SecurityException(ex.InnerException.Message, ex); } finally { if (user != null) user.Dispose(); if (context != null) UserInfo.EndImpersonation(context); RefreshData(); } #endif }
/// <summary> /// Gets information about the system where current application is executing. /// </summary> /// <returns>System information in text.</returns> public static string GetSystemInfo() { StringBuilder info = new StringBuilder(); info.AppendFormat("Date and Time: {0}", DateTime.Now); info.AppendLine(); switch (Common.GetApplicationType()) { case ApplicationType.WindowsCui: case ApplicationType.WindowsGui: UserInfo currentUserInfo = new UserInfo(Thread.CurrentPrincipal.Identity.Name); info.AppendFormat("Machine Name: {0}", Environment.MachineName); info.AppendLine(); info.AppendFormat("Machine IP: {0}", Dns.GetHostEntry(Environment.MachineName).AddressList[0].ToString()); info.AppendLine(); info.AppendFormat("Current User ID: {0}", currentUserInfo.LoginID); info.AppendLine(); info.AppendFormat("Current User Name: {0}", currentUserInfo.FullName); info.AppendLine(); info.AppendFormat("Current User Phone: {0}", currentUserInfo.Telephone); info.AppendLine(); info.AppendFormat("Current User Email: {0}", currentUserInfo.Email); info.AppendLine(); break; case ApplicationType.Web: UserInfo remoteUserInfo = new UserInfo(Thread.CurrentPrincipal.Identity.Name, true); info.AppendFormat("Server Name: {0}", Environment.MachineName); info.AppendLine(); info.AppendFormat("Server IP: {0}", Dns.GetHostEntry(Environment.MachineName).AddressList[0].ToString()); info.AppendLine(); info.AppendFormat("Process User: {0}", System.Security.Principal.WindowsIdentity.GetCurrent().Name); info.AppendLine(); info.AppendFormat("Remote User ID: {0}", remoteUserInfo.LoginID); info.AppendLine(); info.AppendFormat("Remote User Name: {0}", remoteUserInfo.FullName); info.AppendLine(); info.AppendFormat("Remote User Phone: {0}", remoteUserInfo.Telephone); info.AppendLine(); info.AppendFormat("Remote User Email: {0}", remoteUserInfo.Email); info.AppendLine(); info.AppendFormat("Remote Host: {0}", HttpContext.Current.Request.ServerVariables["REMOTE_HOST"]); info.AppendLine(); info.AppendFormat("Remote Address: {0}", HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]); info.AppendLine(); info.AppendFormat("HTTP Agent: {0}", HttpContext.Current.Request.ServerVariables["HTTP_USER_AGENT"]); info.AppendLine(); info.AppendFormat("HTTP Referer: {0}", HttpContext.Current.Request.ServerVariables["HTTP_REFERER"]); info.AppendLine(); info.AppendFormat("Web Page URL: {0}", HttpContext.Current.Request.Url.ToString()); info.AppendLine(); break; } return info.ToString(); }
/// <summary> /// Refreshes the <see cref="UserData"/> from the backend datastore loading user groups into desired collection. /// </summary> /// <param name="groupCollection">Target collection for user groups.</param> /// <param name="providerID">Unique provider ID used to distinguish cached user data that may be different based on provider.</param> /// <returns>true if <see cref="SecurityProviderBase.UserData"/> is refreshed, otherwise false.</returns> protected virtual bool RefreshData(List<string> groupCollection, int providerID) { if (groupCollection == null) throw new ArgumentNullException("groupCollection"); if (string.IsNullOrEmpty(UserData.Username)) return false; // Initialize user data UserData.Initialize(); // Populate user data UserInfo user = null; UserDataCache userDataCache = null; try { // Get current local user data cache if (m_enableOfflineCaching) { userDataCache = UserDataCache.GetCurrentCache(providerID); userDataCache.RetryDelayInterval = m_cacheRetryDelayInterval; userDataCache.MaximumRetryAttempts = m_cacheMaximumRetryAttempts; // TODO: Reload on change is disabled for now by default to eliminate GC handle leaks, if .NET fixes bug http://support.microsoft.com/kb/2628838 // then this can be safely reenabled. For now this will prevent automatic runtime reloading of user data cached by another application. userDataCache.ReloadOnChange = false; userDataCache.AutoSave = true; userDataCache.Load(); } // Create user info object using specified LDAP path if provided string ldapPath = GetLdapPath(); if (string.IsNullOrEmpty(ldapPath)) user = new UserInfo(UserData.Username); else user = new UserInfo(UserData.Username, ldapPath); // Make sure to load privileged user credentials from config file if present. user.PersistSettings = true; // Attempt to determine if user exists (this will initialize user object if not initialized already) UserData.IsDefined = user.Exists; UserData.LoginID = user.LoginID; if (UserData.IsDefined) { // Fill in user information from domain data if it is available if (user.DomainAvailable) { // Copy relevant user information UserData.FirstName = user.FirstName; UserData.LastName = user.LastName; UserData.CompanyName = user.Company; UserData.PhoneNumber = user.Telephone; UserData.EmailAddress = user.Email; UserData.IsLockedOut = user.AccountIsLockedOut; UserData.IsDisabled = user.AccountIsDisabled; UserData.PasswordChangeDateTime = user.NextPasswordChangeDate; UserData.AccountCreatedDateTime = user.AccountCreationDate; // Assign all groups the user is a member of foreach (string groupName in user.Groups) { if (!groupCollection.Contains(groupName, StringComparer.InvariantCultureIgnoreCase)) groupCollection.Add(groupName); } if (userDataCache != null) { // Cache user data so that information can be loaded later if domain is unavailable userDataCache[UserData.LoginID] = UserData; // Wait for pending serialization since cache is scoped locally to this method and will be disposed before exit userDataCache.WaitForSave(); } } else { // Attempt to load previously cached user information when domain is offline UserData cachedUserData = null; if (userDataCache != null && userDataCache.TryGetUserData(UserData.LoginID, out cachedUserData)) { // Copy relevant cached user information UserData.FirstName = cachedUserData.FirstName; UserData.LastName = cachedUserData.LastName; UserData.CompanyName = cachedUserData.CompanyName; UserData.PhoneNumber = cachedUserData.PhoneNumber; UserData.EmailAddress = cachedUserData.EmailAddress; UserData.IsLockedOut = cachedUserData.IsLockedOut; UserData.IsDisabled = cachedUserData.IsDisabled; UserData.Roles.AddRange(cachedUserData.Roles); UserData.Groups.AddRange(cachedUserData.Groups); // If domain is offline, a password change cannot be initiated UserData.PasswordChangeDateTime = DateTime.MaxValue; UserData.AccountCreatedDateTime = cachedUserData.AccountCreatedDateTime; } else { // No previous user data was cached but Windows allowed authentication, so all we know is that user exists UserData.IsLockedOut = false; UserData.IsDisabled = false; UserData.PasswordChangeDateTime = DateTime.MaxValue; UserData.AccountCreatedDateTime = DateTime.MinValue; } } } return UserData.IsDefined; } finally { if (user != null) { user.PersistSettings = false; user.Dispose(); } if (userDataCache != null) userDataCache.Dispose(); } }