xenadmin/XenAdmin/Dialogs/RoleElevationDialog.cs

231 lines
9.2 KiB
C#
Raw Normal View History

/* 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 XenAPI;
using XenAdmin.Actions;
using XenAdmin.Network;
using XenAdmin.Core;
namespace XenAdmin.Dialogs
{
public partial class RoleElevationDialog : XenDialogBase
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public Session elevatedSession = null;
public string elevatedPassword;
public string elevatedUsername;
public string originalUsername;
public string originalPassword;
private List<Role> authorizedRoles;
/// <summary>
/// Displays a dialog informing the user they need a different role to complete the task, and offers the chance to switch user. Optionally logs
/// out the elevated session. If successful exposes the elevated session, password and username as fields.
/// </summary>
/// <param name="connection">The current server connection with the role information</param>
/// <param name="session">The session on which we have been denied access</param>
/// <param name="authorizedRoles">A list of roles that are able to complete the task</param>
/// <param name="actionTitle">A description of the current action, if null or empty will not be displayed</param>
public RoleElevationDialog(IXenConnection connection, Session session, List<Role> authorizedRoles, string actionTitle)
{
InitializeComponent();
Image icon = SystemIcons.Exclamation.ToBitmap();
pictureBox1.Image = icon;
pictureBox1.Width = icon.Width;
pictureBox1.Height = icon.Height;
this.connection = connection;
UserDetails ud = session.CurrentUserDetails;
labelCurrentUserValue.Text = ud.UserDisplayName ?? ud.UserName ?? Messages.UNKNOWN_AD_USER;
labelCurrentRoleValue.Text = Role.FriendlyCSVRoleList(session.Roles);
authorizedRoles.Sort((r1, r2) => r2.CompareTo(r1));
labelRequiredRoleValue.Text = Role.FriendlyCSVRoleList(authorizedRoles);
labelServerValue.Text = Helpers.GetName(connection);
labelServer.Text = Helpers.IsPool(connection) ? Messages.POOL_COLON : Messages.SERVER_COLON;
originalUsername = session.Connection.Username;
originalPassword = session.Connection.Password;
if (string.IsNullOrEmpty(actionTitle))
{
labelCurrentAction.Visible = false;
labelCurrentActionValue.Visible = false;
}
else
{
labelCurrentActionValue.Text = actionTitle;
}
this.authorizedRoles = authorizedRoles;
}
private void buttonAuthorize_Click(object sender, EventArgs e)
{
try
{
Exception delegateException = null;
log.Debug("Testing logging in with the new credentials");
DelegatedAsyncAction loginAction = new DelegatedAsyncAction(connection,
Messages.AUTHORIZING_USER,
Messages.CREDENTIALS_CHECKING,
Messages.CREDENTIALS_CHECK_COMPLETE,
delegate
{
try
{
elevatedSession = connection.ElevatedSession(TextBoxUsername.Text.Trim(), TextBoxPassword.Text);
}
catch (Exception ex)
{
delegateException = ex;
}
});
using (var dlg = new ActionProgressDialog(loginAction, ProgressBarStyle.Marquee, false))
dlg.ShowDialog(this);
// The exception would have been handled by the action progress dialog, just return the user to the sudo dialog
if (loginAction.Exception != null)
return;
if(HandledAnyDelegateException(delegateException))
return;
if (elevatedSession.IsLocalSuperuser || SessionAuthorized(elevatedSession))
{
elevatedUsername = TextBoxUsername.Text.Trim();
elevatedPassword = TextBoxPassword.Text;
DialogResult = DialogResult.OK;
Close();
return;
}
ShowNotAuthorisedDialog();
return;
}
catch (Exception ex)
{
log.DebugFormat("Exception when attempting to sudo action: {0} ", ex);
using (var dlg = new ThreeButtonDialog(
new ThreeButtonDialog.Details(
SystemIcons.Error,
String.Format(Messages.USER_AUTHORIZATION_FAILED, TextBoxUsername.Text),
Messages.XENCENTER)))
{
dlg.ShowDialog(Parent);
}
}
finally
{
// Check whether we have a successful elevated session and whether we have been asked to log it out
// If non successful (most likely the new subject is not authorized) then log it out anyway.
if (elevatedSession != null && DialogResult != DialogResult.OK)
{
elevatedSession.Connection.Logout(elevatedSession);
elevatedSession = null;
}
}
}
private bool HandledAnyDelegateException(Exception delegateException)
{
if (delegateException != null)
{
Failure f = delegateException as Failure;
if (f != null && f.ErrorDescription[0] == Failure.RBAC_PERMISSION_DENIED)
{
ShowNotAuthorisedDialog();
return true;
}
throw delegateException;
}
return false;
}
private void ShowNotAuthorisedDialog()
{
using (var dlg = new ThreeButtonDialog(
new ThreeButtonDialog.Details(
SystemIcons.Error,
Messages.USER_NOT_AUTHORIZED,
Messages.PERMISSION_DENIED)))
{
dlg.ShowDialog(this);
}
}
private bool SessionAuthorized(Session s)
{
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.UserDisplayName ?? ud.UserName ?? ud.UserSid);
return true;
}
}
log.DebugFormat("Subject '{0}' is not authorized to complete the action", ud.UserDisplayName ?? ud.UserName ?? ud.UserSid);
return false;
}
private void buttonCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
private void UpdateButtons()
{
buttonAuthorize.Enabled = TextBoxUsername.Text.Trim() != "" && TextBoxPassword.Text != "";
}
private void TextBoxUsername_TextChanged(object sender, EventArgs e)
{
UpdateButtons();
}
private void TextBoxPassword_TextChanged(object sender, EventArgs e)
{
UpdateButtons();
}
}
}