xenadmin/XenAdmin/Dialogs/HealthCheck/HealthCheckSettingsDialog.cs
Gabor Apati-Nagy a1bb0846e8 CA-213281, CA-213278: OK fixed
Bugs fixed:
* OK button not re-enabling when switching back to using existing credentials in Health Check Enrollment dialog
* Using empty credentials to authenticate with Citrix Insight Services does not disable OK button in Health Check Enrollment dialog

Signed-off-by: Gabor Apati-Nagy <gabor.apati-nagy@citrix.com>
2016-07-25 13:54:47 +01:00

419 lines
18 KiB
C#

/* Copyright (c) Citrix Systems Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using XenAdmin.Actions;
using XenAdmin.Core;
using XenAdmin.Model;
using XenAdmin.Properties;
using XenAPI;
namespace XenAdmin.Dialogs.HealthCheck
{
public partial class HealthCheckSettingsDialog : XenDialogBase
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private readonly Pool pool;
private HealthCheckSettings healthCheckSettings;
private bool authenticationRequired;
private bool authenticated;
private string authenticationToken;
private string diagnosticToken;
private string xsUserName;
private string xsPassword;
internal override string HelpName { get { return "HealthCheckSettingsDialog"; } }
public HealthCheckSettingsDialog(Pool pool, bool enrollNow)
{
this.pool = pool;
this.connection = pool.Connection;
healthCheckSettings = pool.HealthCheckSettings;
if (enrollNow)
healthCheckSettings.Status = HealthCheckStatus.Enabled;
authenticated = healthCheckSettings.TryGetExistingTokens(pool.Connection, out authenticationToken, out diagnosticToken);
authenticationRequired = !authenticated;
xsUserName = healthCheckSettings.GetSecretyInfo(pool.Connection, HealthCheckSettings.UPLOAD_CREDENTIAL_USER_SECRET);
xsPassword = healthCheckSettings.GetSecretyInfo(pool.Connection, HealthCheckSettings.UPLOAD_CREDENTIAL_PASSWORD_SECRET);
InitializeComponent();
PopulateControls();
InitializeControls();
UpdateButtons();
}
private void PopulateControls()
{
var list = BuildDays();
var ds = new BindingSource(list, null);
dayOfWeekComboBox.DataSource = ds;
dayOfWeekComboBox.ValueMember = "key";
dayOfWeekComboBox.DisplayMember = "value";
var list1 = BuildHours();
var ds1 = new BindingSource(list1, null);
timeOfDayComboBox.DataSource = ds1;
timeOfDayComboBox.ValueMember = "key";
timeOfDayComboBox.DisplayMember = "value";
}
private Dictionary<int, string> BuildDays()
{
Dictionary<int, string> days = new Dictionary<int, string>();
foreach (var dayOfWeek in Enum.GetValues(typeof(DayOfWeek)))
{
days.Add((int)dayOfWeek, HelpersGUI.DayOfWeekToString((DayOfWeek)dayOfWeek, true));
}
return days;
}
private SortedDictionary<int, string> BuildHours()
{
SortedDictionary<int, string> hours = new SortedDictionary<int, string>();
for (int hour = 0; hour <= 23; hour++)
{
DateTime time = new DateTime(1900, 1, 1, hour, 0, 0);
hours.Add(hour, HelpersGUI.DateTimeToString(time, Messages.DATEFORMAT_HM, true));
}
return hours;
}
private void InitializeControls()
{
Text = String.Format(Messages.HEALTHCHECK_ENROLLMENT_TITLE, pool.Name);
authenticationRubricTextBox.Text = authenticationRequired
? Messages.HEALTHCHECK_AUTHENTICATION_RUBRIC_NO_TOKEN
: Messages.HEALTHCHECK_AUTHENTICATION_RUBRIC_EXISTING_TOKEN;
enrollmentCheckBox.Checked = healthCheckSettings.Status != HealthCheckStatus.Disabled;
frequencyNumericBox.Value = healthCheckSettings.IntervalInWeeks;
dayOfWeekComboBox.SelectedValue = (int)healthCheckSettings.DayOfWeek;
timeOfDayComboBox.SelectedValue = healthCheckSettings.TimeOfDay;
existingAuthenticationRadioButton.Enabled = existingAuthenticationRadioButton.Checked = !authenticationRequired;
newAuthenticationRadioButton.Checked = authenticationRequired;
SetMyCitrixCredentials(existingAuthenticationRadioButton.Checked);
bool useCurrentXsCredentials = string.IsNullOrEmpty(xsUserName) || xsUserName == pool.Connection.Username;
newXsCredentialsRadioButton.Checked = !useCurrentXsCredentials;
currentXsCredentialsRadioButton.Checked = useCurrentXsCredentials;
SetXSCredentials(currentXsCredentialsRadioButton.Checked);
}
private bool ChangesMade()
{
if (enrollmentCheckBox.Checked && healthCheckSettings.Status != HealthCheckStatus.Enabled)
return true;
if (!enrollmentCheckBox.Checked && healthCheckSettings.Status != HealthCheckStatus.Disabled)
return true;
if (frequencyNumericBox.Value != healthCheckSettings.IntervalInWeeks)
return true;
if (dayOfWeekComboBox.SelectedIndex != (int)healthCheckSettings.DayOfWeek)
return true;
if (timeOfDayComboBox.SelectedIndex != healthCheckSettings.TimeOfDay)
return true;
if (authenticationToken != healthCheckSettings.GetSecretyInfo(pool.Connection, HealthCheckSettings.UPLOAD_TOKEN_SECRET))
return true;
if (textboxXSUserName.Text != xsUserName)
return true;
if (textboxXSPassword.Text != xsPassword)
return true;
return false;
}
private void UpdateButtons()
{
okButton.Enabled = m_ctrlError.PerformCheck(CheckCredentialsEntered);
}
private void okButton_Click(object sender, EventArgs e)
{
okButton.Enabled = false;
if (enrollmentCheckBox.Checked && newAuthenticationRadioButton.Checked
&& !m_ctrlError.PerformCheck(CheckUploadAuthentication))
{
okButton.Enabled = true;
return;
}
if (ChangesMade())
{
var newHealthCheckSettings = new HealthCheckSettings(pool.health_check_config);
newHealthCheckSettings.Status = enrollmentCheckBox.Checked ? HealthCheckStatus.Enabled : HealthCheckStatus.Disabled;
newHealthCheckSettings.IntervalInDays = (int)(frequencyNumericBox.Value * 7);
newHealthCheckSettings.DayOfWeek = (DayOfWeek)dayOfWeekComboBox.SelectedValue;
newHealthCheckSettings.TimeOfDay = (int)timeOfDayComboBox.SelectedValue;
newHealthCheckSettings. RetryInterval = HealthCheckSettings.DEFAULT_RETRY_INTERVAL;
new SaveHealthCheckSettingsAction(pool, newHealthCheckSettings, authenticationToken, diagnosticToken, textboxXSUserName.Text.Trim(), textboxXSPassword.Text, false).RunAsync();
new TransferHealthCheckSettingsAction(pool, newHealthCheckSettings, textboxXSUserName.Text.Trim(), textboxXSPassword.Text, true).RunAsync();
}
okButton.Enabled = true;
DialogResult = DialogResult.OK;
Close();
}
private void cancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
private void enrollmentCheckBox_CheckedChanged(object sender, EventArgs e)
{
UpdateButtons();
}
private void newAuthenticationRadioButton_CheckedChanged(object sender, EventArgs e)
{
SetMyCitrixCredentials(existingAuthenticationRadioButton.Checked);
}
private void radioButton2_CheckedChanged(object sender, EventArgs e)
{
SetXSCredentials(currentXsCredentialsRadioButton.Checked);
testCredentialsButton.Enabled = newXsCredentialsRadioButton.Checked &&
!string.IsNullOrEmpty(textboxXSUserName.Text.Trim()) && !string.IsNullOrEmpty(textboxXSPassword.Text);
}
private void SetXSCredentials(bool useCurrent)
{
if (useCurrent)
{
textboxXSUserName.Text = pool.Connection.Username;
textboxXSPassword.Text = pool.Connection.Password;
textboxXSUserName.Enabled = false;
textboxXSPassword.Enabled = false;
}
else
{
textboxXSUserName.Text = xsUserName;
textboxXSPassword.Text = xsPassword;
textboxXSUserName.Enabled = true;
textboxXSPassword.Enabled = true;
}
}
private void SetMyCitrixCredentials(bool useExisting)
{
if (useExisting)
{
//textBoxMyCitrixUsername.Text = String.Empty;
//textBoxMyCitrixPassword.Text = String.Empty;
textBoxMyCitrixUsername.Enabled = false;
textBoxMyCitrixPassword.Enabled = false;
}
else
{
//textBoxMyCitrixUsername.Text = String.Empty;
//textBoxMyCitrixPassword.Text = String.Empty;
textBoxMyCitrixUsername.Enabled = true;
textBoxMyCitrixPassword.Enabled = true;
}
}
private bool CheckCredentialsEntered()
{
if (!enrollmentCheckBox.Checked || !newAuthenticationRadioButton.Checked)
return true;
if (newAuthenticationRadioButton.Checked &&
(string.IsNullOrEmpty(textBoxMyCitrixUsername.Text.Trim()) || string.IsNullOrEmpty(textBoxMyCitrixPassword.Text)))
return false;
if (newXsCredentialsRadioButton.Checked &&
(string.IsNullOrEmpty(textboxXSUserName.Text.Trim()) || string.IsNullOrEmpty(textboxXSPassword.Text)))
return false;
return true;
}
private bool CheckCredentialsEntered(out string error)
{
error = string.Empty;
return CheckCredentialsEntered();
}
private bool CheckUploadAuthentication(out string error)
{
error = string.Empty;
if (!CheckCredentialsEntered())
return false;
var action = new HealthCheckAuthenticationAction(textBoxMyCitrixUsername.Text.Trim(), textBoxMyCitrixPassword.Text.Trim(),
Registry.HealthCheckIdentityTokenDomainName, Registry.HealthCheckUploadGrantTokenDomainName, Registry.HealthCheckUploadTokenDomainName,
Registry.HealthCheckDiagnosticDomainName, Registry.HealthCheckProductKey, 0, false);
try
{
action.RunExternal(null);
}
catch
{
error = action.Exception != null ? action.Exception.Message : Messages.ERROR_UNKNOWN;
authenticationToken = null;
authenticated = false;
return authenticated;
}
authenticationToken = action.UploadToken; // curent upload token
diagnosticToken = action.DiagnosticToken; // curent diagnostic token
authenticated = !String.IsNullOrEmpty(authenticationToken) && !String.IsNullOrEmpty(diagnosticToken);
return authenticated;
}
private void credentials_TextChanged(object sender, EventArgs e)
{
UpdateButtons();
}
private void xsCredentials_TextChanged(object sender, EventArgs e)
{
UpdateButtons();
testCredentialsButton.Enabled = newXsCredentialsRadioButton.Checked &&
!string.IsNullOrEmpty(textboxXSUserName.Text.Trim()) && !string.IsNullOrEmpty(textboxXSPassword.Text);
HideTestCredentialsStatus();
}
private void PolicyStatementLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
new HealthCheckPolicyStatementDialog().ShowDialog(this);
}
private void testCredentialsButton_Click(object sender, EventArgs e)
{
CheckXenServerCredentials();
}
private void CheckXenServerCredentials()
{
if (string.IsNullOrEmpty(textboxXSUserName.Text.Trim()) || string.IsNullOrEmpty(textboxXSPassword.Text))
return;
bool passedRbacChecks = false;
DelegatedAsyncAction action = new DelegatedAsyncAction(connection,
Messages.CREDENTIALS_CHECKING, "", "",
delegate
{
Session elevatedSession = null;
try
{
elevatedSession = connection.ElevatedSession(textboxXSUserName.Text.Trim(), textboxXSPassword.Text);
if (elevatedSession != null && (elevatedSession.IsLocalSuperuser || SessionAuthorized(elevatedSession, Role.ValidRoleList("pool.set_health_check_config", connection))))
passedRbacChecks = true;
}
catch (Failure f)
{
if (f.ErrorDescription.Count > 0 && f.ErrorDescription[0] == Failure.RBAC_PERMISSION_DENIED)
{
// we use a different error message here from the standard one in friendly names
throw new Exception(Messages.HEALTH_CHECK_USER_HAS_NO_PERMISSION_TO_CONNECT);
}
throw;
}
finally
{
if (elevatedSession != null)
{
elevatedSession.Connection.Logout(elevatedSession);
elevatedSession = null;
}
}
},
true);
action.Completed += delegate
{
log.DebugFormat("Logging with the new credentials returned: {0} ", passedRbacChecks);
Program.Invoke(Program.MainWindow, () =>
{
if (passedRbacChecks)
ShowTestCredentialsStatus(Resources._000_Tick_h32bit_16, null);
else
ShowTestCredentialsStatus(Resources._000_error_h32bit_16, action.Exception != null ? action.Exception.Message : Messages.HEALTH_CHECK_USER_NOT_AUTHORIZED);
textboxXSUserName.Enabled = textboxXSPassword.Enabled = testCredentialsButton.Enabled = newXsCredentialsRadioButton.Checked;
});
};
log.Debug("Testing logging in with the new credentials");
ShowTestCredentialsStatus(Resources.ajax_loader, null);
textboxXSUserName.Enabled = textboxXSPassword.Enabled = testCredentialsButton.Enabled = false;
action.RunAsync();
}
private void ShowTestCredentialsStatus(Image image, string errorMessage)
{
testCredentialsStatusImage.Visible = true;
testCredentialsStatusImage.Image = image;
errorLabel.Text = errorMessage;
errorLabel.Visible = !string.IsNullOrEmpty(errorMessage);
}
private void HideTestCredentialsStatus()
{
testCredentialsStatusImage.Visible = false;
errorLabel.Visible = false;
}
private bool SessionAuthorized(Session s, List<Role> authorizedRoles)
{
UserDetails ud = s.CurrentUserDetails;
foreach (Role r in s.Roles)
{
if (authorizedRoles.Contains(r))
{
log.DebugFormat("Subject '{0}' is authorized to complete the action", ud.UserName ?? ud.UserSid);
return true;
}
}
log.DebugFormat("Subject '{0}' is not authorized to complete the action", ud.UserName ?? ud.UserSid);
return false;
}
private void authenticationRubricTextBox_LinkClicked(object sender, LinkClickedEventArgs e)
{
Program.OpenURL(e.LinkText);
}
private void existingAuthenticationRadioButton_CheckedChanged(object sender, EventArgs e)
{
UpdateButtons();
}
}
}