/// <summary> /// Changes the user's current password under AD authentication mode if the user is external, or creates /// a new pin (if account is in "new pin" mode) under RSA authentication mode. /// </summary> /// <param name="oldPassword"> /// Current password under AD authentication. Current token under RSA authntication.</param> /// <param name="newPassword"> /// New password under AD authentication; new pin under RSA authentication. /// </param> /// <returns> /// True if password was changed successfully under AD authentication mode, or new pin was created /// successfully under RSA authentication mode; otherwise False. /// </returns> public bool ChangePassword(string oldPassword, string newPassword) { // Don't proceed to change password or create pin if user account is not defined or is locked. if (! m_isDefined || m_isLockedOut) { return false; } switch (m_authenticationMode) { case AuthenticationMode.AD: // Under AD authentication mode, we allow the password to be changed only if the user is // an external user and after the user's current password has been verified. if (m_isExternal && Authenticate(oldPassword)) { using (SqlConnection dbConnection = GetDatabaseConnection()) { TVA.Data.Common.ExecuteScalar("dbo.ChangePassword", dbConnection, m_username, m_password, EncryptPassword(newPassword)); } return true; } break; case AuthenticationMode.RSA: // Under RSA authentication mode, in order to create a pin, the account must actually be in // the "new pin" mode. If it is not, then repeated attempts to create a pin may result in the // account being placed in "next token" mode (i.e. equivalent to account being disabled). And // the problem is that we cannot verify if a account is actually in the "new pin" mode, because // a token can be used only once and no more than once. TVA.Security.Radius.RadiusClient client = null; try { // First, we try creating a pin against the primary RSA server. client = new TVA.Security.Radius.RadiusClient(RsaServer1, TVA.Security.Cryptography.Common.Decrypt(RadiusSharedSecret)); return client.CreateNewPin(m_username, oldPassword, newPassword); } catch (ArgumentNullException) { // When we encounter this exception, the primary RSA server didn't respond. try { // Next, we try creating a pin against the backup RSA server. client.Dispose(); client = new TVA.Security.Radius.RadiusClient(RsaServer2, TVA.Security.Cryptography.Common.Decrypt(RadiusSharedSecret)); return client.CreateNewPin(m_username, oldPassword, newPassword); } catch (Exception) { // Absorb any other exception. } } catch (Exception) { // Absorb any other exception. } finally { if (client != null) { client.Dispose(); } } break; } }
/// <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; }