mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-11-25 06:16:37 +01:00
CP-13077: Changes to the Health Check feature to work properly with RBAC
Changed all the health check actions to perform the necessary role checks - HealthCheckAuthenticationAction: changed so it does not save the tokens, so no role checks required in this action (all the checks are performed in SaveHealthCheckSettingsAction) - GetHealthCheckAnalysisActions: added role checks On the Health Check Overview dialog, a pool is displayed as read-only if connected as a user with roles that don't permit changing the health check settings: - the following actions are not available: enroll, edit settings, disable health check, request upload, get analysis result
This commit is contained in:
parent
f772763575
commit
53b01c425c
@ -44,21 +44,17 @@ namespace XenAdmin.Core
|
||||
public static event Action<bool> CheckForAnalysisResultsCompleted;
|
||||
|
||||
/// <summary>
|
||||
/// Checks the analysis results for all connections
|
||||
/// Checks the analysis results for all connections.
|
||||
/// Will only perform the check for the connection that have sufficient rights; will not show the action progress.
|
||||
/// </summary>
|
||||
public static void CheckForAnalysisResults()
|
||||
{
|
||||
List<AsyncAction> actions = new List<AsyncAction>();
|
||||
foreach (IXenConnection xenConnection in ConnectionsManager.XenConnectionsCopy)
|
||||
{
|
||||
Pool pool = Helpers.GetPoolOfOne(xenConnection);
|
||||
if (pool == null || Helpers.FeatureForbidden(xenConnection, Host.RestrictHealthCheck))
|
||||
continue;
|
||||
|
||||
var healthCheckSettings = pool.HealthCheckSettings;
|
||||
|
||||
if (healthCheckSettings.Status == HealthCheckStatus.Enabled && !healthCheckSettings.HasAnalysisResult)
|
||||
actions.Add(new GetHealthCheckAnalysisResultAction(pool, Registry.HealthCheckDiagnosticDomainName, true));
|
||||
var action = GetAction(xenConnection, true);
|
||||
if (action != null)
|
||||
actions.Add(action);
|
||||
}
|
||||
|
||||
if (actions.Count == 1)
|
||||
@ -75,22 +71,49 @@ namespace XenAdmin.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks the analysis results for the specified connections
|
||||
/// Checks the analysis results for the specified connections.
|
||||
/// Will only perform the check if the connection has sufficient rights; will not show the action progress.
|
||||
/// </summary>
|
||||
public static void CheckForAnalysisResults(object connection)
|
||||
{
|
||||
Pool pool = Helpers.GetPoolOfOne((IXenConnection)connection);
|
||||
if (pool == null || Helpers.FeatureForbidden((IXenConnection)connection, Host.RestrictHealthCheck))
|
||||
return;
|
||||
CheckForAnalysisResults(connection, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks the analysis results for the specified connections.
|
||||
/// Will only perform the check if the connection has sufficient rights; If suppressHistory is false, it will show the action progress.
|
||||
/// </summary>
|
||||
public static void CheckForAnalysisResults(object connection, bool suppressHistory)
|
||||
{
|
||||
var action = GetAction((IXenConnection)connection, suppressHistory);
|
||||
if (action != null)
|
||||
{
|
||||
action.Completed += actionCompleted;
|
||||
action.RunAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private static AsyncAction GetAction(IXenConnection connection, bool suppressHistory)
|
||||
{
|
||||
Pool pool = Helpers.GetPoolOfOne(connection);
|
||||
if (pool == null || Helpers.FeatureForbidden(connection, Host.RestrictHealthCheck))
|
||||
return null;
|
||||
|
||||
var healthCheckSettings = pool.HealthCheckSettings;
|
||||
|
||||
if (healthCheckSettings.Status == HealthCheckStatus.Enabled && !healthCheckSettings.HasAnalysisResult)
|
||||
{
|
||||
var action = new GetHealthCheckAnalysisResultAction(pool, Registry.HealthCheckDiagnosticDomainName, true);
|
||||
action.Completed += actionCompleted;
|
||||
action.RunAsync();
|
||||
var action = new GetHealthCheckAnalysisResultAction(pool, Registry.HealthCheckDiagnosticDomainName, suppressHistory);
|
||||
|
||||
if (PassedRbacChecks(pool.Connection))
|
||||
return action;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool PassedRbacChecks(IXenConnection connection)
|
||||
{
|
||||
return Role.CanPerform(new RbacMethodList("pool.set_health_check_config"), connection);
|
||||
}
|
||||
|
||||
private static void actionCompleted(ActionBase sender)
|
||||
|
@ -207,6 +207,8 @@ namespace XenAdmin.Dialogs.HealthCheck
|
||||
scheduleLabel.Text = GetScheduleDescription(poolRow.Pool.HealthCheckSettings);
|
||||
lastUploadLabel.Visible = lastUploadDateLabel.Visible = !string.IsNullOrEmpty(poolRow.Pool.HealthCheckSettings.LastSuccessfulUpload);
|
||||
lastUploadDateLabel.Text = GetLastUploadDescription(poolRow.Pool.HealthCheckSettings);
|
||||
|
||||
UpdateButtonsVisibility(poolRow.Pool);
|
||||
|
||||
healthCheckStatusPanel.Visible = poolRow.Pool.HealthCheckSettings.Status == HealthCheckStatus.Enabled;
|
||||
notEnrolledPanel.Visible = poolRow.Pool.HealthCheckSettings.Status != HealthCheckStatus.Enabled;
|
||||
@ -299,6 +301,16 @@ namespace XenAdmin.Dialogs.HealthCheck
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateButtonsVisibility(Pool pool)
|
||||
{
|
||||
refreshLinkLabel.Visible =
|
||||
editLinkLabel.Visible =
|
||||
disableLinkLabel.Visible =
|
||||
uploadRequestLinkLabel.Visible =
|
||||
enrollNowLinkLabel.Visible = Core.HealthCheck.PassedRbacChecks(pool.Connection);
|
||||
|
||||
}
|
||||
|
||||
private void HealthCheckOverviewDialog_Load(object sender, EventArgs e)
|
||||
{
|
||||
LoadPools();
|
||||
@ -450,7 +462,7 @@ namespace XenAdmin.Dialogs.HealthCheck
|
||||
if (poolRow.Pool == null)
|
||||
return;
|
||||
|
||||
Core.HealthCheck.CheckForAnalysisResults(poolRow.Pool.Connection);
|
||||
Core.HealthCheck.CheckForAnalysisResults(poolRow.Pool.Connection, false);
|
||||
}
|
||||
|
||||
private void HealthCheck_CheckForUpdatesCompleted(bool succeeded)
|
||||
|
@ -266,9 +266,9 @@ namespace XenAdmin.Dialogs.HealthCheck
|
||||
if (!CheckCredentialsEntered())
|
||||
return false;
|
||||
|
||||
var action = new HealthCheckAuthenticationAction(pool, textBoxMyCitrixUsername.Text.Trim(), textBoxMyCitrixPassword.Text.Trim(),
|
||||
var action = new HealthCheckAuthenticationAction(textBoxMyCitrixUsername.Text.Trim(), textBoxMyCitrixPassword.Text.Trim(),
|
||||
Registry.HealthCheckIdentityTokenDomainName, Registry.HealthCheckUploadGrantTokenDomainName, Registry.HealthCheckUploadTokenDomainName,
|
||||
Registry.HealthCheckDiagnosticDomainName, Registry.HealthCheckProductKey, true, 0, false);
|
||||
Registry.HealthCheckDiagnosticDomainName, Registry.HealthCheckProductKey, 0, false);
|
||||
|
||||
try
|
||||
{
|
||||
@ -283,7 +283,8 @@ namespace XenAdmin.Dialogs.HealthCheck
|
||||
}
|
||||
|
||||
authenticationToken = action.UploadToken; // curent upload token
|
||||
authenticated = pool.HealthCheckSettings.TryGetExistingTokens(pool.Connection, out authenticationToken, out diagnosticToken);
|
||||
diagnosticToken = action.DiagnosticToken; // curent diagnostic token
|
||||
authenticated = !String.IsNullOrEmpty(authenticationToken) && !String.IsNullOrEmpty(diagnosticToken);
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
|
@ -183,10 +183,10 @@ namespace XenAdmin.Wizards.BugToolWizardFiles
|
||||
if (string.IsNullOrEmpty(usernameTextBox.Text) || string.IsNullOrEmpty(passwordTextBox.Text))
|
||||
return false;
|
||||
|
||||
var action = new HealthCheckAuthenticationAction(null, usernameTextBox.Text.Trim(), passwordTextBox.Text.Trim(),
|
||||
var action = new HealthCheckAuthenticationAction(usernameTextBox.Text.Trim(), passwordTextBox.Text.Trim(),
|
||||
Registry.HealthCheckIdentityTokenDomainName, Registry.HealthCheckUploadGrantTokenDomainName,
|
||||
Registry.HealthCheckUploadTokenDomainName, Registry.HealthCheckDiagnosticDomainName, Registry.HealthCheckProductKey,
|
||||
false, TokenExpiration, false);
|
||||
TokenExpiration, false);
|
||||
|
||||
new ActionProgressDialog(action, ProgressBarStyle.Blocks).ShowDialog(Parent);
|
||||
|
||||
|
@ -49,7 +49,11 @@ namespace XenAdmin.Actions
|
||||
public GetHealthCheckAnalysisResultAction(Pool pool, bool suppressHistory)
|
||||
: base(pool.Connection, Messages.ACTION_GET_HEALTH_CHECK_RESULT, Messages.ACTION_GET_HEALTH_CHECK_RESULT_PROGRESS, suppressHistory)
|
||||
{
|
||||
|
||||
#region RBAC Dependencies
|
||||
ApiMethodsToRoleCheck.Add("secret.get_by_uuid");
|
||||
ApiMethodsToRoleCheck.Add("secret.get_value");
|
||||
ApiMethodsToRoleCheck.Add("pool.set_health_check_config");
|
||||
#endregion
|
||||
}
|
||||
|
||||
public GetHealthCheckAnalysisResultAction(Pool pool, string diagnosticDomainName, bool suppressHistory)
|
||||
@ -63,7 +67,7 @@ namespace XenAdmin.Actions
|
||||
{
|
||||
try
|
||||
{
|
||||
var diagnosticToken = Pool.HealthCheckSettings.GetSecretyInfo(Pool.Connection, HealthCheckSettings.DIAGNOSTIC_TOKEN_SECRET);
|
||||
var diagnosticToken = Pool.HealthCheckSettings.GetSecretyInfo(Session, HealthCheckSettings.DIAGNOSTIC_TOKEN_SECRET);
|
||||
if (string.IsNullOrEmpty(diagnosticToken))
|
||||
{
|
||||
log.InfoFormat("Cannot get the diagnostic result for {0}, because couldn't retrieve the diagnostic token", Pool.Name);
|
||||
|
@ -30,14 +30,11 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Runtime.Serialization;
|
||||
using XenAdmin.Network;
|
||||
using XenAPI;
|
||||
using System.Web.Script.Serialization;
|
||||
using XenAdmin.Model;
|
||||
|
||||
namespace XenAdmin.Actions
|
||||
{
|
||||
@ -45,14 +42,13 @@ namespace XenAdmin.Actions
|
||||
{
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private readonly Pool pool;
|
||||
private readonly string username;
|
||||
private readonly string password;
|
||||
|
||||
private readonly bool saveTokenAsSecret;
|
||||
private readonly long tokenExpiration;
|
||||
|
||||
private string uploadToken;
|
||||
private string diagnosticToken;
|
||||
|
||||
private const string identityTokenUrl = "/auth/api/create_identity/";
|
||||
private const string uploadGrantTokenUrl = "/feeds/api/create_grant/";
|
||||
@ -66,25 +62,19 @@ namespace XenAdmin.Actions
|
||||
|
||||
private readonly string productKey = "1a2d94a4263cd016dd7a7d510bde87f058a0b75d";
|
||||
|
||||
public HealthCheckAuthenticationAction(Pool pool, string username, string password, bool saveTokenAsSecret, long tokenExpiration, bool suppressHistory)
|
||||
: base(pool != null ? pool.Connection : null, Messages.ACTION_HEALTHCHECK_AUTHENTICATION, Messages.ACTION_HEALTHCHECK_AUTHENTICATION_PROGRESS, suppressHistory)
|
||||
public HealthCheckAuthenticationAction(string username, string password, long tokenExpiration, bool suppressHistory)
|
||||
: base(null, Messages.ACTION_HEALTHCHECK_AUTHENTICATION, Messages.ACTION_HEALTHCHECK_AUTHENTICATION_PROGRESS, suppressHistory)
|
||||
{
|
||||
this.pool = pool;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.saveTokenAsSecret = saveTokenAsSecret;
|
||||
this.tokenExpiration = tokenExpiration;
|
||||
#region RBAC Dependencies
|
||||
if (saveTokenAsSecret)
|
||||
ApiMethodsToRoleCheck.Add("pool.set_health_check_config");
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
public HealthCheckAuthenticationAction(Pool pool, string username, string password,
|
||||
public HealthCheckAuthenticationAction(string username, string password,
|
||||
string identityTokenDomainName, string uploadGrantTokenDomainName, string uploadTokenDomainName, string diagnosticTokenDomainName,
|
||||
string productKey, bool saveTokenAsSecret, long tokenExpiration, bool suppressHistory)
|
||||
: this(pool, username, password, saveTokenAsSecret, tokenExpiration, suppressHistory)
|
||||
string productKey, long tokenExpiration, bool suppressHistory)
|
||||
: this(username, password, tokenExpiration, suppressHistory)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(identityTokenDomainName))
|
||||
this.identityTokenDomainName = identityTokenDomainName;
|
||||
@ -100,22 +90,12 @@ namespace XenAdmin.Actions
|
||||
|
||||
protected override void Run()
|
||||
{
|
||||
System.Diagnostics.Trace.Assert(pool != null || !saveTokenAsSecret, "Pool is null! Cannot save token as secret");
|
||||
try
|
||||
{
|
||||
string identityToken = GetIdentityToken();
|
||||
string uploadGrantToken = GetUploadGrantToken(identityToken);
|
||||
uploadToken = GetUploadToken(uploadGrantToken);
|
||||
string diagnosticToken = GetDiagnosticToken(identityToken);
|
||||
|
||||
if (saveTokenAsSecret && pool != null)
|
||||
{
|
||||
log.Info("Saving upload token as xapi secret");
|
||||
Dictionary<string, string> newConfig = pool.health_check_config;
|
||||
SetSecretInfo(Connection, newConfig, HealthCheckSettings.UPLOAD_TOKEN_SECRET, uploadToken); log.Info("Saving upload token as xapi secret");
|
||||
SetSecretInfo(Connection, newConfig, HealthCheckSettings.DIAGNOSTIC_TOKEN_SECRET, diagnosticToken);
|
||||
Pool.set_health_check_config(Connection.Session, pool.opaque_ref, newConfig);
|
||||
}
|
||||
diagnosticToken = GetDiagnosticToken(identityToken);
|
||||
}
|
||||
catch (HealthCheckAuthenticationException)
|
||||
{
|
||||
@ -132,53 +112,9 @@ namespace XenAdmin.Actions
|
||||
get { return uploadToken; }
|
||||
}
|
||||
|
||||
public static void SetSecretInfo(IXenConnection connection, Dictionary<string, string> config, string infoKey, string infoValue)
|
||||
public string DiagnosticToken
|
||||
{
|
||||
if (string.IsNullOrEmpty(infoKey))
|
||||
return;
|
||||
|
||||
if (infoValue == null)
|
||||
{
|
||||
if (config.ContainsKey(infoKey))
|
||||
{
|
||||
TryToDestroySecret(connection, config[infoKey]);
|
||||
config.Remove(infoKey);
|
||||
}
|
||||
}
|
||||
else if (config.ContainsKey(infoKey))
|
||||
{
|
||||
try
|
||||
{
|
||||
string secretRef = Secret.get_by_uuid(connection.Session, config[infoKey]);
|
||||
Secret.set_value(connection.Session, secretRef, infoValue);
|
||||
}
|
||||
catch (Failure)
|
||||
{
|
||||
config[infoKey] = Secret.CreateSecret(connection.Session, infoValue);
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
config[infoKey] = Secret.CreateSecret(connection.Session, infoValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
config[infoKey] = Secret.CreateSecret(connection.Session, infoValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static void TryToDestroySecret(IXenConnection connection, string secret_uuid)
|
||||
{
|
||||
try
|
||||
{
|
||||
var secret = Secret.get_by_uuid(connection.Session, secret_uuid);
|
||||
Secret.destroy(connection.Session, secret.opaque_ref);
|
||||
log.DebugFormat("Successfully destroyed secret {0}", secret_uuid);
|
||||
}
|
||||
catch (Exception exn)
|
||||
{
|
||||
log.Error(string.Format("Failed to destroy secret {0}", secret_uuid), exn);
|
||||
}
|
||||
get { return diagnosticToken; }
|
||||
}
|
||||
|
||||
private string GetIdentityToken()
|
||||
|
@ -29,7 +29,9 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using XenAdmin.Model;
|
||||
using XenAPI;
|
||||
|
||||
@ -37,6 +39,8 @@ namespace XenAdmin.Actions
|
||||
{
|
||||
public class SaveHealthCheckSettingsAction : PureAsyncAction
|
||||
{
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private readonly Pool pool;
|
||||
HealthCheckSettings healthCheckSettings;
|
||||
private string authenticationToken;
|
||||
@ -59,12 +63,67 @@ namespace XenAdmin.Actions
|
||||
{
|
||||
Dictionary<string, string> newConfig = healthCheckSettings.ToDictionary(pool.health_check_config);
|
||||
if (!string.IsNullOrEmpty(authenticationToken))
|
||||
HealthCheckAuthenticationAction.SetSecretInfo(Connection, newConfig, HealthCheckSettings.UPLOAD_TOKEN_SECRET, authenticationToken);
|
||||
{
|
||||
log.Info("Saving upload token as xapi secret");
|
||||
SetSecretInfo(Session, newConfig, HealthCheckSettings.UPLOAD_TOKEN_SECRET, authenticationToken);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(diagnosticToken))
|
||||
HealthCheckAuthenticationAction.SetSecretInfo(Connection, newConfig, HealthCheckSettings.DIAGNOSTIC_TOKEN_SECRET, diagnosticToken);
|
||||
HealthCheckAuthenticationAction.SetSecretInfo(Connection, newConfig, HealthCheckSettings.UPLOAD_CREDENTIAL_USER_SECRET, username);
|
||||
HealthCheckAuthenticationAction.SetSecretInfo(Connection, newConfig, HealthCheckSettings.UPLOAD_CREDENTIAL_PASSWORD_SECRET, password);
|
||||
Pool.set_health_check_config(Connection.Session, pool.opaque_ref, newConfig);
|
||||
{
|
||||
log.Info("Saving diagnostic token as xapi secret");
|
||||
SetSecretInfo(Session, newConfig, HealthCheckSettings.DIAGNOSTIC_TOKEN_SECRET, diagnosticToken);
|
||||
}
|
||||
SetSecretInfo(Session, newConfig, HealthCheckSettings.UPLOAD_CREDENTIAL_USER_SECRET, username);
|
||||
SetSecretInfo(Session, newConfig, HealthCheckSettings.UPLOAD_CREDENTIAL_PASSWORD_SECRET, password);
|
||||
Pool.set_health_check_config(Session, pool.opaque_ref, newConfig);
|
||||
}
|
||||
|
||||
public static void SetSecretInfo(Session session, Dictionary<string, string> config, string infoKey, string infoValue)
|
||||
{
|
||||
if (string.IsNullOrEmpty(infoKey))
|
||||
return;
|
||||
|
||||
if (infoValue == null)
|
||||
{
|
||||
if (config.ContainsKey(infoKey))
|
||||
{
|
||||
TryToDestroySecret(session, config[infoKey]);
|
||||
config.Remove(infoKey);
|
||||
}
|
||||
}
|
||||
else if (config.ContainsKey(infoKey))
|
||||
{
|
||||
try
|
||||
{
|
||||
string secretRef = Secret.get_by_uuid(session, config[infoKey]);
|
||||
Secret.set_value(session, secretRef, infoValue);
|
||||
}
|
||||
catch (Failure)
|
||||
{
|
||||
config[infoKey] = Secret.CreateSecret(session, infoValue);
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
config[infoKey] = Secret.CreateSecret(session, infoValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
config[infoKey] = Secret.CreateSecret(session, infoValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static void TryToDestroySecret(Session session, string secret_uuid)
|
||||
{
|
||||
try
|
||||
{
|
||||
var secret = Secret.get_by_uuid(session, secret_uuid);
|
||||
Secret.destroy(session, secret.opaque_ref);
|
||||
log.DebugFormat("Successfully destroyed secret {0}", secret_uuid);
|
||||
}
|
||||
catch (Exception exn)
|
||||
{
|
||||
log.Error(string.Format("Failed to destroy secret {0}", secret_uuid), exn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ namespace XenAdmin.Model
|
||||
|
||||
#endregion
|
||||
|
||||
public string GetSecretyInfo(IXenConnection connection, string secretType)
|
||||
public string GetSecretyInfo(Session session, string secretType)
|
||||
{
|
||||
string UUID = string.Empty;
|
||||
switch (secretType)
|
||||
@ -294,12 +294,12 @@ namespace XenAdmin.Model
|
||||
break;
|
||||
}
|
||||
|
||||
if (connection == null || string.IsNullOrEmpty(UUID))
|
||||
if (session == null || string.IsNullOrEmpty(UUID))
|
||||
return null;
|
||||
try
|
||||
{
|
||||
string opaqueref = Secret.get_by_uuid(connection.Session, UUID);
|
||||
return Secret.get_value(connection.Session, opaqueref);
|
||||
string opaqueref = Secret.get_by_uuid(session, UUID);
|
||||
return Secret.get_value(session, opaqueref);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -308,6 +308,13 @@ namespace XenAdmin.Model
|
||||
}
|
||||
}
|
||||
|
||||
public string GetSecretyInfo(IXenConnection connection, string secretType)
|
||||
{
|
||||
if (connection == null)
|
||||
return null;
|
||||
return GetSecretyInfo(connection.Session, secretType);
|
||||
}
|
||||
|
||||
public bool TryGetExistingTokens(IXenConnection connection, out string uploadToken, out string diagnosticToken)
|
||||
{
|
||||
uploadToken = null;
|
||||
|
Loading…
Reference in New Issue
Block a user