mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-11-25 14:27:26 +01:00
4b0b83245f
* CA-34231: Replace negative language with `block list` in code and references Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `stop` in code and references Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `freezing` in code Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `run/ran` in code comments Some paramater mentions have been renamed, as they will be renamed in future commits. Excluded mentions in XenAPI/Host.cs and XenAPI/VM.cs since code is autogenerated. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # CFUValidator/CommandLineOptions/CFUCommandLineOptionManager.cs # XenAdmin/Controls/Wlb/WlbOptModeScheduler.cs # XenAdmin/Dialogs/Wlb/WorkloadReports.cs * CA-34231: Replace negative language with `run` in Command.cs Run method Used Resharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/TabPages/GeneralTabPage.cs * CA-34231: Replace negative language with `run` in Command.cs CanRun method Used Resharper rename utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `run` in Command.cs CanRunCore method Used ReSharper rename utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Commands/DRConfigureCommand.cs # XenAdmin/Commands/DRDryrunCommand.cs # XenAdmin/Commands/DRFailbackCommand.cs # XenAdmin/Commands/DRFailoverCommand.cs # XenAdmin/Commands/DisasterRecoveryCommand.cs # XenAdmin/Commands/VMGroupCommand.cs * CA-34231: Replace negative language with `run` in Command.cs RunCore method Used ReSharper rename utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `run` in Command.cs GetCantExecuteReasonCore method Used ReSharper rename utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `run` in Command.cs GetCantRunReasons method Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace remaining negative language with `run` in Command.cs Also applied to related symbols. Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `run` in methods named CanRun Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `run` in methods in CrossPoolMigrateCommand.cs Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Commands/CrossPoolMigrateCommand.cs * CA-34231: Replace negative language with `run` in remaining Run methods Also updated negative language in `DeleteVMCommand` Also updated in comment in `CrossPoolMigrateCommand` Also renamed missed instances of `CanRun` Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `run` in `CanRunCore` and `RunCore` Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace remaining negative language with `run` in Commands folder Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace remaining negative language with `run` in XenAdmin/Controls folder Used ReSharper renaming utility. Had to rename `WlbReportView.xs:RunReport()` to `WlbReportView.xs:StartRunReport()` to resolve conflict with change from `WlbReportView:ExecuteReport()` to `WlbReportView:RunReport()` Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Controls/Wlb/WlbOptModeScheduler.cs # XenAdmin/Dialogs/Wlb/WorkloadReports.cs # XenAdminTests/UnitTests/WlbTests/WlbScheduledTaskTests.cs * CA-34231: Replace all remaining negative language with `run` in code Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Commands/Controls/WlbRecommendations.cs # XenAdminTests/UnitTests/WlbTests/WlbScheduledTaskTests.cs # XenModel/WLB/WlbScheduledTask.cs * CA-34231: Replace negative language with `supporter` or `bond member` in code strings Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `supporter` or `bond member` in Messages string Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/MainWindow.cs # XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.cs # XenModel/Messages.Designer.cs # XenModel/Messages.resx * CA-34231: Replace remaining negative language with `supporter` in .resx files Used ReSharper renaming utility. FriendlyErrorNames.resx has been excluded. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `supporter` or `bond member` in XenAdmin code Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Dialogs/NewPoolDialog.cs * CA-34231: Replace negative language with `supporter` or `bond member` in XenModel code Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `coordinator` in CFUValidator code Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # CFUValidator/CFUValidator.cs * CA-34231: Replace negative language with `coordinator` in solution's comments and hardcoded strings Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `coordinator` in `Helpers:GetCoordinator` method Used ReSharper renaming utility. also renamed similarly named method in `ObjectChange.cs` Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Alerts/Types/HotfixEligibilityAlert.cs # XenAdmin/Controls/CustomDataGraph/ArchiveMaintainer.cs * CA-34231: Replace negative language with `coordinator` in `EvacuateHostDialog.resx` Used ReSharper renaming utility. Excluded jp and zh resources Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Dialogs/EvacuateHostDialog.resx * CA-34231: Replace negative language with `coordinator` in `EvacuateHostDialog.resx` Used ReSharper renaming utility. Excluded jp and zh resource files. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Dialogs/NewPoolDialog.resx * CA-34231: Rename missing language references for change to `coordinator` Misc files were not saved before last commits. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `coordinator` in `Messages.resx`'s code Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Commands/HACommand.cs # XenAdmin/TabPages/AdPage.cs # XenModel/Actions/Network/CreateBondAction.cs # XenModel/Actions/Network/NetworkAction.cs # XenModel/Messages.Designer.cs # XenModel/Messages.resx * CA-34231: Replace negative language with `coordinator` in `ExternalPluginAction.cs` Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `coordinator` in `XenAdmin/Commands` Used ReSharper renaming utility. Also replace negative language in missed comment in `ExternalPluginAction.cs` Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Commands/AddHostToPoolCommand.cs # XenAdmin/Commands/HACommand.cs * CA-34231: Replace negative language with `coordinator` in `Helpers.cs` Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `coordinator` in `NetworkingHelper.cs` Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `coordinator` in `PoolJoinRules.cs` Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Dialogs/NewPoolDialog.cs * CA-34231: Replace negative language with `coordinator` in `XenAdmin/Commands`, `Controls`, and `Core` Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Commands/AddHostToPoolCommand.cs * CA-34231: Replace negative language with `coordinator` in `XenAdmin/Diagnostics` Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `coordinator` in `XenAdmin/Dialogs` Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Dialogs/NewPoolDialog.cs * CA-34231: Replace remaining negative language with `coordinator` in `XenAdmin` Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/MainWindow.cs # XenAdmin/TabPages/GeneralTabPage.cs # XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.cs # XenAdmin/Wizards/RollingUpgradeWizard/RollingUpgradeExtrasPage.cs # XenAdmin/Wizards/RollingUpgradeWizard/RollingUpgradeWizard.cs # XenAdmin/Wizards/RollingUpgradeWizard/RollingUpgradeWizardPrecheckPage.cs # XenAdmin/XenSearch/Columns.cs * CA-34231: Replace remaining negative language with `coordinator` in `XenModel\Actions` Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenModel/Actions/Network/CreateBondAction.cs * CA-34231: Replace remaining negative language with `coordinator` in `XenModel` Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace remaining negative strings with `main` in `Messages.resx` Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenModel/Messages.Designer.cs # XenModel/Messages.resx * CA-34231: Replace remaining negative string names with `main` in `Messages.resx` Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Dialogs/OptionsPages/SaveAndRestoreOptionsPage.cs # XenModel/Messages.resx * CA-34231: Rename dialogs to replace negative connotations with `main` Used ReSharper renaming utility Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `main` in `SaveAndResoreOptionsPage.cs` Also updated its resx file. Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> # Conflicts: # XenAdmin/Dialogs/OptionsPages/SaveAndRestoreOptionsPage.cs * CA-34231: Fix invalid reference in `SaveAndRestoreOptionsPage.Designer.cs` after renaming Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `main` in `EnterMainPasswordDialog.cs` Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `main` in `ChangeMainPasswordDialog.cs` Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Fix invalid reference not changed after renaming `EnterMainPasswordDialog.cs` Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace remaining negative language with `main` in `XenAdmin/Dialogs` Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Update class names in HelpManager.resx Following renaming of main password dialog. Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace negative language with `main` in `Metadata.cs` Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Remove remaning negative language with `coordinator` from `Messages.resx` Used ReSharper renaming Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Remove remaning negative language with `other pool member` from `Messages.resx` Used ReSharper Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CA-34231: Replace remaining negative language in solution Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Remove commented out code in VNCGraphicsClient.cs Code has only been improved partially as it's not strictly relevant to the PR Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Amend negative word replacement in XSVNCScreen.cs Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Simplify debug call formatting in NewPoolDialog.cs Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Add code mistakenly removed in MainWindow.cs Removed as part of `f155f9c8` Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Revert renaming of constant related to Windows' API Considered external to CH Center Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Amend hotkey for Coordinator field in `NewPoolDialog` Previous ALT+<key> hotkey was conflicting with CreatePool Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Remove unecessary whitespace in EvacuateHostDialog.cs Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Update if block to exclude unecessary else in DRFailoverWizard.cs Not relevant to the PR, but the change is small enought to no need extra testing Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Amend typo in PoolJoinRules.cs supporer -> supporter Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Replace missing negative language with `coordinator` in `XenAPI-Extensions/Pool.cs` Variables and methods XenAPI-Extensions were mistakenly skipped Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Replace negative language in `XenApi-Extensions` with `coordinator/interface` Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Replace negative language in `XenApi-Extensions` with `supporter/member` Used ReSharper renaming utility. Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Replace remaining negative language in `XenServerHealthCheckBugTool.cs` This is only used to format the string Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Change line-endings to CRLF in `Page_CloudConfigParamters.cs` Done in order to fix merge conflict into master Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com> * CP-34231: Amend misc negative language renaming typos `XenServerHealthCheckBugTool` and `XenServerHealthCheckService` Signed-off-by: Danilo Del Busso <Danilo.Del.Busso@citrix.com>
1157 lines
47 KiB
C#
1157 lines
47 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.ComponentModel;
|
|
using System.Linq;
|
|
using System.Windows.Forms;
|
|
using XenAPI;
|
|
using XenAdmin.Dialogs;
|
|
using System.Threading;
|
|
using XenAdmin.Controls.DataGridViewEx;
|
|
using XenAdmin.Core;
|
|
using XenAdmin.Actions;
|
|
using XenAdmin.Commands;
|
|
using XenAdmin.Network;
|
|
using XenCenterLib;
|
|
|
|
namespace XenAdmin.TabPages
|
|
{
|
|
public partial class AdPage : BaseTabPage
|
|
{
|
|
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
|
|
|
/// <summary>
|
|
/// The pool this settings page refers to (can be a poolOfOne). Only set on the GUI thread, and we also assert that it is only
|
|
/// ever set once.
|
|
/// </summary>
|
|
private Pool pool;
|
|
private Host coordinator;
|
|
private IXenConnection _connection;
|
|
|
|
private Thread _loggedInStatusUpdater;
|
|
private bool _updateInProgress;
|
|
|
|
private string _storedDomain;
|
|
private string _storedUsername;
|
|
|
|
private readonly CollectionChangeEventHandler Pool_CollectionChangedWithInvoke;
|
|
public IXenObject XenObject
|
|
{
|
|
set
|
|
{
|
|
Program.AssertOnEventThread();
|
|
|
|
ClearHandles();
|
|
|
|
_connection = value == null ? null : value.Connection;
|
|
if (_connection == null)
|
|
return;
|
|
|
|
pool = Helpers.GetPoolOfOne(_connection);
|
|
if (pool == null) // Cache not populated
|
|
_connection.Cache.RegisterCollectionChanged<Pool>(Pool_CollectionChangedWithInvoke);
|
|
else
|
|
pool.PropertyChanged += pool_PropertyChanged;
|
|
|
|
if (_connection.Session != null)
|
|
_connection.Session.PropertyChanged += Session_PropertyChanged;
|
|
checkAdType();
|
|
|
|
if (_loggedInStatusUpdater == null)
|
|
{
|
|
// Fire off the the thread that will update the logged in status
|
|
_loggedInStatusUpdater = new Thread(updateLoggedInStatus);
|
|
_loggedInStatusUpdater.IsBackground = true;
|
|
_loggedInStatusUpdater.Start();
|
|
}
|
|
}
|
|
}
|
|
|
|
public AdPage()
|
|
{
|
|
InitializeComponent();
|
|
Pool_CollectionChangedWithInvoke = Program.ProgramInvokeHandler(Pool_CollectionChanged);
|
|
ColumnSubject.CellTemplate = new KeyValuePairCell();
|
|
tTipLogoutButton.SetToolTip(Messages.AD_CANNOT_MODIFY_ROOT);
|
|
tTipRemoveButton.SetToolTip(Messages.AD_CANNOT_MODIFY_ROOT);
|
|
ConnectionsManager.History.CollectionChanged += History_CollectionChanged;
|
|
Text = Messages.ACTIVE_DIRECTORY_TAB_TITLE;
|
|
}
|
|
|
|
public override string HelpID => "TabPageAD";
|
|
|
|
/// <summary>
|
|
/// This method is used when the cache was not populated by the time we set the XenObject. It sets the appropriate event handlers,
|
|
/// references to the coordinator and the pool, and populates the tab with the correct configuration. It de-registers
|
|
/// itself when successful.
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
void Pool_CollectionChanged(object sender, CollectionChangeEventArgs e)
|
|
{
|
|
pool = Helpers.GetPoolOfOne(_connection);
|
|
if (pool == null) // Cache not populated
|
|
return;
|
|
|
|
_connection.Cache.DeregisterCollectionChanged<Pool>(Pool_CollectionChangedWithInvoke);
|
|
pool.PropertyChanged += pool_PropertyChanged;
|
|
|
|
Program.Invoke(this, checkAdType);
|
|
}
|
|
|
|
private void RefreshCoordinator()
|
|
{
|
|
if (coordinator != null)
|
|
coordinator.PropertyChanged -= coordinator_PropertyChanged;
|
|
|
|
coordinator = Helpers.GetCoordinator(_connection);
|
|
if (coordinator != null)
|
|
coordinator.PropertyChanged += coordinator_PropertyChanged;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears all event handles that could be set in this control.
|
|
/// </summary>
|
|
private void ClearHandles()
|
|
{
|
|
if (pool != null)
|
|
pool.PropertyChanged -= pool_PropertyChanged;
|
|
|
|
if (coordinator != null)
|
|
coordinator.PropertyChanged -= coordinator_PropertyChanged;
|
|
|
|
if (_connection != null)
|
|
{
|
|
_connection.Cache.DeregisterBatchCollectionChanged<Subject>(SubjectCollectionChanged);
|
|
if (_connection.Session != null)
|
|
_connection.Session.PropertyChanged -= Session_PropertyChanged;
|
|
}
|
|
}
|
|
|
|
public override void PageHidden()
|
|
{
|
|
ClearHandles();
|
|
}
|
|
|
|
/// <summary>
|
|
/// We keep track of the actions currently running so we can disable the tab if we are in the middle of configuring AD.
|
|
/// </summary>
|
|
void History_CollectionChanged(object sender, CollectionChangeEventArgs e)
|
|
{
|
|
if (e.Action == CollectionChangeAction.Add &&
|
|
(e.Element is EnableAdAction || e.Element is DisableAdAction))
|
|
{
|
|
AsyncAction action = (AsyncAction)e.Element;
|
|
action.Completed += action_Completed;
|
|
|
|
if (_connection != null && _connection == action.Connection)
|
|
Program.Invoke(this, checkAdType);
|
|
}
|
|
}
|
|
|
|
void action_Completed(ActionBase sender)
|
|
{
|
|
AsyncAction action = (AsyncAction)sender;
|
|
action.Completed -= action_Completed;
|
|
|
|
if (_connection != null && _connection == action.Connection)
|
|
Program.Invoke(this, checkAdType);
|
|
}
|
|
|
|
void Session_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
{
|
|
Program.BeginInvoke(this, RepopulateListBox);
|
|
}
|
|
|
|
/// <summary>
|
|
/// We need to update the configuration if the authentication method changes, and also various labels display the name of the
|
|
/// coordinator and should also be updated if that changes.
|
|
/// </summary>
|
|
/// <param name="sender1"></param>
|
|
/// <param name="e"></param>
|
|
void coordinator_PropertyChanged(object sender1, PropertyChangedEventArgs e)
|
|
{
|
|
if (e.PropertyName == "external_auth_type" || e.PropertyName == "name_label")
|
|
Program.Invoke(this, checkAdType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Various labels display the name of the pool and should also be updated if that changes.
|
|
/// Additionally if the pool coordinator changes we need to update our event handles.
|
|
/// There is a sanity check in the checkAdType() method in case this event is stuck in a queue.
|
|
/// </summary>
|
|
void pool_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
{
|
|
if (e.PropertyName == "name_label" || e.PropertyName == "master")
|
|
Program.Invoke(this, checkAdType);
|
|
}
|
|
|
|
private void SetSubjectListEnable(bool enable)
|
|
{
|
|
Program.AssertOnEventThread();
|
|
GridViewSubjectList.Enabled = enable;
|
|
if (GridViewSubjectList.Enabled)
|
|
{
|
|
LabelGridViewDisabled.Visible = false;
|
|
RepopulateListBox();
|
|
|
|
foreach (AdSubjectRow r in GridViewSubjectList.Rows)
|
|
{
|
|
if (r.IsLocalRootRow)
|
|
{
|
|
r.ToggleExpandedState();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (AdSubjectRow row in GridViewSubjectList.Rows)
|
|
{
|
|
if (row.IsLocalRootRow)
|
|
continue;
|
|
row.subject.PropertyChanged -= subject_PropertyChanged;
|
|
}
|
|
GridViewSubjectList.Rows.Clear();
|
|
LabelGridViewDisabled.Visible = true;
|
|
}
|
|
}
|
|
|
|
private void checkAdType()
|
|
{
|
|
Program.AssertOnEventThread();
|
|
//refresh the coordinator in case the cache is slow
|
|
RefreshCoordinator();
|
|
|
|
if (coordinator == null)
|
|
{
|
|
log.WarnFormat("Could not resolve pool coordinator for connection '{0}'; disabling.", Helpers.GetName(_connection));
|
|
OnCoordinatorUnavailable();
|
|
return;
|
|
}
|
|
|
|
var action = (from ActionBase act in ConnectionsManager.History
|
|
let async = act as AsyncAction
|
|
where async != null && !async.IsCompleted && !async.Cancelled && async.Connection == _connection
|
|
&& (async is EnableAdAction || async is DisableAdAction)
|
|
select async).FirstOrDefault();
|
|
|
|
if (action != null)
|
|
{
|
|
OnAdConfiguring();
|
|
}
|
|
else if (coordinator.external_auth_type == Auth.AUTH_TYPE_NONE) // AD is not yet configured
|
|
{
|
|
OnAdDisabled();
|
|
}
|
|
else // AD is already configured
|
|
{
|
|
if (coordinator.external_auth_type != Auth.AUTH_TYPE_AD)
|
|
{
|
|
log.WarnFormat("Unrecognised value '{0}' for external_auth_type on pool coordinator '{1}' for pool '{2}'; assuming AD enabled on pool.",
|
|
coordinator.external_auth_type, Helpers.GetName(coordinator), Helpers.GetName(_connection));
|
|
}
|
|
|
|
OnAdEnabled();
|
|
}
|
|
}
|
|
|
|
private void SubjectCollectionChanged(object sender, EventArgs e)
|
|
{
|
|
Program.BeginInvoke(this, RepopulateListBox);
|
|
}
|
|
|
|
private string Domain
|
|
{
|
|
get
|
|
{
|
|
Program.AssertOnEventThread();
|
|
|
|
Host coordinator = Helpers.GetCoordinator(_connection);
|
|
if (coordinator == null)
|
|
{
|
|
log.WarnFormat("Could not resolve pool coordinator for connection '{0}'; disabling.", Helpers.GetName(_connection));
|
|
return Messages.UNKNOWN;
|
|
}
|
|
|
|
return coordinator.external_auth_service_name;
|
|
}
|
|
}
|
|
|
|
private void OnAdEnabled()
|
|
{
|
|
Program.AssertOnEventThread();
|
|
|
|
flowLayoutPanel1.Enabled = true;
|
|
SetSubjectListEnable(true);
|
|
buttonJoinLeave.Text = Messages.AD_LEAVE_DOMAIN;
|
|
buttonJoinLeave.Enabled = true;
|
|
labelBlurb.Text = string.Format(Helpers.GetPool(_connection) != null ? Messages.AD_CONFIGURED_BLURB : Messages.AD_CONFIGURED_BLURB_HOST, Helpers.GetName(_connection).Ellipsise(70), Domain.Ellipsise(30));
|
|
_connection.Cache.RegisterBatchCollectionChanged<Subject>(SubjectCollectionChanged);
|
|
}
|
|
|
|
private void OnAdDisabled()
|
|
{
|
|
Program.AssertOnEventThread();
|
|
|
|
flowLayoutPanel1.Enabled = false;
|
|
SetSubjectListEnable(false);
|
|
buttonJoinLeave.Text = Messages.AD_JOIN_DOMAIN;
|
|
buttonJoinLeave.Enabled = true;
|
|
labelBlurb.Text = string.Format(Helpers.GetPool(_connection) != null ? Messages.AD_NOT_CONFIGURED_BLURB : Messages.AD_NOT_CONFIGURED_BLURB_HOST,
|
|
Helpers.GetName(_connection).Ellipsise(70));
|
|
_connection.Cache.DeregisterBatchCollectionChanged<Subject>(SubjectCollectionChanged);
|
|
}
|
|
|
|
private void OnAdConfiguring()
|
|
{
|
|
Program.AssertOnEventThread();
|
|
|
|
flowLayoutPanel1.Enabled = false;
|
|
SetSubjectListEnable(false);
|
|
buttonJoinLeave.Enabled = false;
|
|
labelBlurb.Text = string.Format(Helpers.GetPool(_connection) != null ? Messages.AD_CONFIGURING_BLURB : Messages.AD_CONFIGURING_BLURB_HOST,
|
|
Helpers.GetName(_connection).Ellipsise(70));
|
|
}
|
|
|
|
private void OnCoordinatorUnavailable()
|
|
{
|
|
Program.AssertOnEventThread();
|
|
|
|
flowLayoutPanel1.Enabled = false;
|
|
SetSubjectListEnable(false);
|
|
buttonJoinLeave.Enabled = false;
|
|
labelBlurb.Text = Messages.AD_COORDINATOR_UNAVAILABLE_BLURB;
|
|
}
|
|
|
|
private void RepopulateListBox()
|
|
{
|
|
Program.AssertOnEventThread();
|
|
|
|
if (!GridViewSubjectList.Enabled)
|
|
return;
|
|
|
|
Dictionary<string, bool> selectedSubjectUuids = new Dictionary<string, bool>();
|
|
Dictionary<string, bool> expandedSubjectUuids = new Dictionary<string, bool>();
|
|
bool rootExpanded = false;
|
|
string topSubject = "";
|
|
if (GridViewSubjectList.FirstDisplayedScrollingRowIndex > 0)
|
|
{
|
|
AdSubjectRow topRow = GridViewSubjectList.Rows[GridViewSubjectList.FirstDisplayedScrollingRowIndex] as AdSubjectRow;
|
|
if (topRow != null && topRow.subject != null)
|
|
topSubject = topRow.subject.uuid;
|
|
}
|
|
|
|
if (GridViewSubjectList.SelectedRows.Count > 0)
|
|
{
|
|
foreach (AdSubjectRow r in GridViewSubjectList.SelectedRows)
|
|
{
|
|
if (r.subject != null)
|
|
selectedSubjectUuids.Add(r.subject.uuid, true);
|
|
}
|
|
}
|
|
foreach (AdSubjectRow row in GridViewSubjectList.Rows)
|
|
{
|
|
if (row.Expanded)
|
|
if (row.subject == null)
|
|
rootExpanded = true;
|
|
else
|
|
expandedSubjectUuids.Add(row.subject.uuid, true);
|
|
}
|
|
|
|
try
|
|
{
|
|
_updateInProgress = true;
|
|
GridViewSubjectList.SuspendLayout();
|
|
|
|
foreach (AdSubjectRow row in GridViewSubjectList.Rows)
|
|
{
|
|
if (row.IsLocalRootRow)
|
|
continue;
|
|
row.subject.PropertyChanged -= subject_PropertyChanged;
|
|
}
|
|
|
|
GridViewSubjectList.Rows.Clear();
|
|
|
|
var rows = new List<DataGridViewRow> {new AdSubjectRow(null)}; //local root account
|
|
|
|
foreach (Subject subject in _connection.Cache.Subjects) //all other subjects in the pool
|
|
{
|
|
subject.PropertyChanged += subject_PropertyChanged;
|
|
rows.Add(new AdSubjectRow(subject));
|
|
}
|
|
GridViewSubjectList.Rows.AddRange(rows.ToArray());
|
|
|
|
GridViewSubjectList.Sort(GridViewSubjectList.SortedColumn ?? ColumnSubject,
|
|
GridViewSubjectList.SortOrder == SortOrder.Ascending ? ListSortDirection.Ascending : ListSortDirection.Descending);
|
|
|
|
// restore old selection, old expansion state and top row
|
|
foreach (AdSubjectRow r in GridViewSubjectList.Rows)
|
|
{
|
|
r.Selected = !r.IsLocalRootRow && selectedSubjectUuids.ContainsKey(r.subject.uuid);
|
|
r.Expanded = r.IsLocalRootRow ? rootExpanded : expandedSubjectUuids.ContainsKey(r.subject.uuid);
|
|
|
|
if (!r.IsLocalRootRow && topSubject == r.subject.uuid)
|
|
GridViewSubjectList.FirstDisplayedScrollingRowIndex = r.Index;
|
|
}
|
|
if (GridViewSubjectList.SelectedRows.Count == 0)
|
|
GridViewSubjectList.Rows[0].Selected = true;
|
|
|
|
HelpersGUI.ResizeGridViewColumnToAllCells(ColumnSubject);
|
|
HelpersGUI.ResizeGridViewColumnToAllCells(ColumnRoles);
|
|
HelpersGUI.ResizeGridViewColumnToAllCells(ColumnStatus);
|
|
}
|
|
finally
|
|
{
|
|
GridViewSubjectList.ResumeLayout();
|
|
_updateInProgress = false;
|
|
EnableButtons();
|
|
}
|
|
}
|
|
|
|
private void subject_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
{
|
|
if (e.PropertyName != "roles" && e.PropertyName != "other_config")
|
|
return;
|
|
|
|
var subject = sender as Subject;
|
|
if (subject == null)
|
|
return;
|
|
|
|
Program.Invoke(this, () =>
|
|
{
|
|
if (!GridViewSubjectList.Enabled)
|
|
return;
|
|
|
|
var found = (from DataGridViewRow row in GridViewSubjectList.Rows
|
|
let adRow = row as AdSubjectRow
|
|
where adRow != null && adRow.subject != null && adRow.subject.opaque_ref == subject.opaque_ref
|
|
select adRow).FirstOrDefault();
|
|
|
|
try
|
|
{
|
|
GridViewSubjectList.SuspendLayout();
|
|
|
|
if (found == null)
|
|
GridViewSubjectList.Rows.Add(new AdSubjectRow(subject));
|
|
else
|
|
found.RefreshCellContent(subject);
|
|
}
|
|
finally
|
|
{
|
|
GridViewSubjectList.ResumeLayout();
|
|
EnableButtons();
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
private object statusUpdaterLock = new object();
|
|
/// <summary>
|
|
/// Background thread called periodically to update subjects logged in status.
|
|
/// </summary>
|
|
private void updateLoggedInStatus()
|
|
{
|
|
// This could get a bit spammy with a repeated exception, consider a back off or summary approach if it becomes an issue
|
|
Program.AssertOffEventThread();
|
|
|
|
while (!Disposing && !IsDisposed)
|
|
{
|
|
try
|
|
{
|
|
|
|
bool showing = false;
|
|
Program.Invoke(this, delegate
|
|
{
|
|
showing = Program.MainWindow.TheTabControl.SelectedTab == Program.MainWindow.TabPageAD;
|
|
|
|
});
|
|
if (showing)
|
|
{
|
|
String[] loggedInSids = _connection.Session.get_all_subject_identifiers();
|
|
// Want fast access time for when we take the lock and switch off the background thread
|
|
Dictionary<string, bool> loggedSids = new Dictionary<string, bool>();
|
|
foreach (string s in loggedInSids)
|
|
loggedSids.Add(s, true);
|
|
Program.Invoke(this, delegate
|
|
{
|
|
foreach (AdSubjectRow r in GridViewSubjectList.Rows)
|
|
{
|
|
// local root row
|
|
if (r.IsLocalRootRow)
|
|
continue;
|
|
|
|
r.LoggedIn = loggedSids.ContainsKey(r.subject.subject_identifier);
|
|
}
|
|
EnableButtons();
|
|
});
|
|
}
|
|
lock (statusUpdaterLock)
|
|
{
|
|
Monitor.Wait(statusUpdaterLock, 5000);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
showLoggedInStatusError();
|
|
log.Error(e);
|
|
Thread.Sleep(5000);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void showLoggedInStatusError()
|
|
{
|
|
Program.Invoke(this, delegate
|
|
{
|
|
foreach (AdSubjectRow r in GridViewSubjectList.Rows)
|
|
{
|
|
if (r.IsLocalRootRow)
|
|
continue;
|
|
|
|
r.SetStatusLost();
|
|
}
|
|
});
|
|
}
|
|
|
|
#region Custom AD Row Class
|
|
|
|
/// <summary>
|
|
/// Used in the DataGridView on the ConfigureAdDialog. Stores information about the subject and the different text to show if the
|
|
/// row is expanded or not.
|
|
/// </summary>
|
|
private class AdSubjectRow : DataGridViewRow
|
|
{
|
|
private readonly DataGridViewImageCell _cellExpander = new DataGridViewImageCell();
|
|
private readonly DataGridViewImageCell _cellGroupOrUser = new DataGridViewImageCell();
|
|
private readonly KeyValuePairCell _cellSubjectInfo = new KeyValuePairCell();
|
|
private readonly DataGridViewTextBoxCell _cellRoles = new DataGridViewTextBoxCell();
|
|
private readonly DataGridViewTextBoxCell _cellLoggedIn = new DataGridViewTextBoxCell();
|
|
|
|
internal Subject subject { get; private set; }
|
|
private bool expanded;
|
|
private bool loggedIn;
|
|
/// <summary>
|
|
/// The row is created with unknown status until it's updated from outside the class
|
|
/// </summary>
|
|
private bool statusLost = true;
|
|
|
|
public bool LoggedIn
|
|
{
|
|
get
|
|
{
|
|
return loggedIn;
|
|
}
|
|
set
|
|
{
|
|
loggedIn = value;
|
|
statusLost = false;
|
|
RefreshCellContent();
|
|
}
|
|
}
|
|
|
|
internal bool IsLocalRootRow
|
|
{
|
|
get { return subject == null; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The full list of the subject's roles
|
|
/// </summary>
|
|
private readonly string expandedRoles = string.Empty;
|
|
/// <summary>
|
|
/// Topmost of the subject's roles
|
|
/// </summary>
|
|
private readonly string contractedRoles = string.Empty;
|
|
/// <summary>
|
|
/// The detailed info from the subject's other_config along with their display name
|
|
/// </summary>
|
|
private readonly List<KeyValuePair<string, string>> expandedSubjectInfo = new List<KeyValuePair<String, String>>();
|
|
/// <summary>
|
|
/// The subject's display name
|
|
/// </summary>
|
|
private readonly List<KeyValuePair<string, string>> contractedSubjectInfo = new List<KeyValuePair<String, String>>();
|
|
|
|
/// <summary>
|
|
/// A DataGridViewRow that corresponds to a subject and shows their
|
|
/// information in expanded and collapsed states
|
|
/// </summary>
|
|
/// <param name="subject">If null, if it is a root account (no subject)</param>
|
|
internal AdSubjectRow(Subject subject)
|
|
{
|
|
if (subject == null) //root account
|
|
{
|
|
expandedSubjectInfo.Add(new KeyValuePair<string, string>(Messages.AD_LOCAL_ROOT_ACCOUNT, ""));
|
|
expandedSubjectInfo.Add(new KeyValuePair<string, string>("", ""));
|
|
expandedSubjectInfo.Add(new KeyValuePair<string, string>(Messages.AD_ALWAYS_GRANTED_ACCESS, ""));
|
|
contractedSubjectInfo.Add(new KeyValuePair<string, string>(Messages.AD_LOCAL_ROOT_ACCOUNT, ""));
|
|
}
|
|
else
|
|
{
|
|
this.subject = subject;
|
|
var roles = subject.Connection.ResolveAll(subject.roles);
|
|
roles.Sort();
|
|
roles.Reverse();
|
|
if (roles.Count > 0)
|
|
expandedRoles = roles.Select(r => r.FriendlyName()).Aggregate((acc, s) => acc + "\n" + s);
|
|
|
|
contractedRoles = roles.Count > 0
|
|
? roles.Count > 1 ? roles[0].FriendlyName().AddEllipsis() : roles[0].FriendlyName()
|
|
: "";
|
|
|
|
contractedSubjectInfo.Add(new KeyValuePair<string, string>(subject.DisplayName ?? subject.SubjectName ?? "", ""));
|
|
expandedSubjectInfo = Subject.ExtractKvpInfo(subject);
|
|
}
|
|
|
|
Cells.AddRange(_cellExpander, _cellGroupOrUser, _cellSubjectInfo, _cellRoles, _cellLoggedIn);
|
|
RefreshCellContent();
|
|
}
|
|
|
|
public void RefreshCellContent(Subject subj = null)
|
|
{
|
|
if (subj != null)
|
|
subject = subj;
|
|
|
|
_cellExpander.Value = expanded ? Images.StaticImages.expanded_triangle : Images.StaticImages.contracted_triangle;
|
|
_cellGroupOrUser.Value = IsLocalRootRow || !subject.IsGroup ? Images.StaticImages._000_User_h32bit_16 : Images.StaticImages._000_UserAndGroup_h32bit_16;
|
|
_cellSubjectInfo.Value = expanded ? expandedSubjectInfo : contractedSubjectInfo;
|
|
_cellRoles.Value = expanded ? expandedRoles : contractedRoles;
|
|
_cellLoggedIn.Value = IsLocalRootRow || subject.IsGroup || statusLost
|
|
? "-"
|
|
: loggedIn ? Messages.YES : Messages.NO;
|
|
}
|
|
|
|
public void ToggleExpandedState()
|
|
{
|
|
expanded = !expanded;
|
|
RefreshCellContent();
|
|
}
|
|
|
|
public bool Expanded
|
|
{
|
|
get
|
|
{
|
|
return expanded;
|
|
}
|
|
set
|
|
{
|
|
if (expanded != value)
|
|
{
|
|
expanded = value;
|
|
RefreshCellContent();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetStatusLost()
|
|
{
|
|
if (statusLost)
|
|
return;
|
|
|
|
statusLost = true;
|
|
RefreshCellContent();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
private void buttonJoinLeave_Click(object sender, EventArgs e)
|
|
{
|
|
Program.AssertOnEventThread();
|
|
if (buttonJoinLeave.Text == Messages.AD_JOIN_DOMAIN)
|
|
{
|
|
// We're enabling AD
|
|
// Obtain domain, username and password; store the domain and username
|
|
// so the user won't have to retype it for future join attempts
|
|
|
|
using (var joinPrompt = new AdPasswordPrompt(true)
|
|
{Domain = _storedDomain, Username = _storedUsername})
|
|
{
|
|
var result = joinPrompt.ShowDialog(this);
|
|
_storedDomain = joinPrompt.Domain;
|
|
_storedUsername = joinPrompt.Username;
|
|
|
|
if (result == DialogResult.Cancel)
|
|
return;
|
|
|
|
new EnableAdAction(_connection, joinPrompt.Domain, joinPrompt.Username, joinPrompt.Password).RunAsync();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We're disabling AD
|
|
|
|
// Warn if the user will boot himself out by disabling AD
|
|
Session session = _connection.Session;
|
|
if (session == null)
|
|
return;
|
|
|
|
if (session.IsLocalSuperuser)
|
|
{
|
|
// User is authenticated using local root account. Confirm anyway.
|
|
string msg = string.Format(Messages.AD_LEAVE_CONFIRM,
|
|
Helpers.GetName(_connection).Ellipsise(50).EscapeAmpersands(), Domain.Ellipsise(30));
|
|
|
|
DialogResult r;
|
|
using (var dlg = new NoIconDialog(msg,
|
|
ThreeButtonDialog.ButtonYes,
|
|
new ThreeButtonDialog.TBDButton(Messages.NO_BUTTON_CAPTION, DialogResult.No, selected: true))
|
|
{WindowTitle = Messages.AD_FEATURE_NAME})
|
|
{
|
|
r = dlg.ShowDialog(this);
|
|
}
|
|
|
|
//CA-64818: DialogResult can be No if the No button has been hit
|
|
//or Cancel if the dialog has been closed from the control box
|
|
if (r != DialogResult.Yes)
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// Warn user will be booted out.
|
|
string msg = string.Format(Helpers.GetPool(_connection) != null ? Messages.AD_LEAVE_WARNING : Messages.AD_LEAVE_WARNING_HOST,
|
|
Helpers.GetName(_connection).Ellipsise(50), Domain.Ellipsise(30));
|
|
|
|
DialogResult r;
|
|
using (var dlg = new WarningDialog(msg,
|
|
ThreeButtonDialog.ButtonYes,
|
|
new ThreeButtonDialog.TBDButton(Messages.NO_BUTTON_CAPTION, DialogResult.No, selected: true))
|
|
{WindowTitle = Messages.ACTIVE_DIRECTORY_TAB_TITLE})
|
|
{
|
|
r = dlg.ShowDialog(this);
|
|
}
|
|
|
|
//CA-64818: DialogResult can be No if the No button has been hit
|
|
//or Cancel if the dialog has been closed from the control box
|
|
if (r != DialogResult.Yes)
|
|
return;
|
|
}
|
|
|
|
Host coordinator = Helpers.GetCoordinator(_connection);
|
|
if (coordinator == null)
|
|
{
|
|
// Really shouldn't happen unless we have been very slow with the cache
|
|
log.Error("Could not retrieve coordinator when trying to look up domain..");
|
|
throw new Exception(Messages.CONNECTION_IO_EXCEPTION);
|
|
}
|
|
|
|
using (var passPrompt = new AdPasswordPrompt(false, coordinator.external_auth_service_name))
|
|
{
|
|
var result = passPrompt.ShowDialog(this);
|
|
if (result == DialogResult.Cancel)
|
|
return;
|
|
|
|
var creds = new Dictionary<string, string>();
|
|
if (result != DialogResult.Ignore)
|
|
{
|
|
creds.Add(DisableAdAction.KEY_USER, passPrompt.Username);
|
|
creds.Add(DisableAdAction.KEY_PASSWORD, passPrompt.Password);
|
|
}
|
|
|
|
new DisableAdAction(_connection, creds).RunAsync();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void buttonAdd_Click(object sender, EventArgs e)
|
|
{
|
|
Program.AssertOnEventThread();
|
|
if (!buttonAdd.Enabled)
|
|
return;
|
|
|
|
using (var dlog = new ResolvingSubjectsDialog(_connection))
|
|
dlog.ShowDialog(this);
|
|
}
|
|
|
|
private void ButtonRemove_Click(object sender, EventArgs e)
|
|
{
|
|
Program.AssertOnEventThread();
|
|
|
|
// Double check, this method is called from a context menu as well and the state could have changed under it
|
|
if (!ButtonRemove.Enabled)
|
|
return;
|
|
|
|
var subjectsToRemove = GridViewSubjectList.SelectedRows.Cast<AdSubjectRow>().Select(r => r.subject).ToList();
|
|
if (subjectsToRemove.Count < 1)
|
|
return;
|
|
|
|
var removeMessage = subjectsToRemove.Count == 1
|
|
? string.Format(Messages.QUESTION_REMOVE_AD_USER_ONE, subjectsToRemove[0].DisplayName ?? subjectsToRemove[0].SubjectName)
|
|
: string.Format(Messages.QUESTION_REMOVE_AD_USER_MANY, subjectsToRemove.Count);
|
|
|
|
string adminMessage = null;
|
|
var conn = subjectsToRemove.FirstOrDefault(s => s.Connection != null)?.Connection;
|
|
|
|
if (conn != null && Helpers.StockholmOrGreater(conn) && !conn.Cache.Hosts.Any(Host.RestrictPoolSecretRotation))
|
|
{
|
|
var poolAdminsToRemove = (from Subject s in subjectsToRemove
|
|
let roles = s.Connection.ResolveAll(s.roles)
|
|
where roles.Any(r => r.name_label == Role.MR_ROLE_POOL_ADMIN)
|
|
select s).ToList();
|
|
|
|
if (subjectsToRemove.Count == poolAdminsToRemove.Count)
|
|
adminMessage = poolAdminsToRemove.Count == 1
|
|
? Messages.QUESTION_ADMIN_EXIT_PROCEDURE_ONE
|
|
: Messages.QUESTION_ADMIN_EXIT_PROCEDURE_MANY;
|
|
else if (poolAdminsToRemove.Count > 0)
|
|
adminMessage = poolAdminsToRemove.Count == 1
|
|
? Messages.QUESTION_ADMIN_EXIT_PROCEDURE_ONE_OF_MANY
|
|
: string.Format(Messages.QUESTION_ADMIN_EXIT_PROCEDURE_SOME_OF_MANY, poolAdminsToRemove.Count);
|
|
|
|
if (!string.IsNullOrEmpty(adminMessage))
|
|
removeMessage = string.Format("{0}\n\n{1} {2}", removeMessage, adminMessage, Messages.QUESTION_ADMIN_EXIT_PROCEDURE_ADVISORY);
|
|
}
|
|
|
|
using (var dlg = new WarningDialog(removeMessage,
|
|
ThreeButtonDialog.ButtonYes,
|
|
new ThreeButtonDialog.TBDButton(Messages.NO_BUTTON_CAPTION, DialogResult.No, selected: true))
|
|
{WindowTitle = Messages.AD_FEATURE_NAME})
|
|
{
|
|
//CA-64818: DialogResult can be No if the No button has been hit
|
|
//or Cancel if the dialog has been closed from the control box
|
|
|
|
if (dlg.ShowDialog(this) != DialogResult.Yes)
|
|
return;
|
|
}
|
|
|
|
// Warn if user is revoking his currently-in-use credentials
|
|
Session session = _connection.Session;
|
|
if (session != null && session.SessionSubject != null)
|
|
{
|
|
foreach (Subject entry in subjectsToRemove)
|
|
{
|
|
if (entry.opaque_ref == session.SessionSubject)
|
|
{
|
|
string subjectName = entry.DisplayName ?? entry.SubjectName;
|
|
if (subjectName == null)
|
|
{
|
|
subjectName = entry.subject_identifier;
|
|
}
|
|
else
|
|
{
|
|
subjectName = subjectName.Ellipsise(256);
|
|
}
|
|
string msg = string.Format(entry.IsGroup ? Messages.AD_CONFIRM_SUICIDE_GROUP : Messages.AD_CONFIRM_SUICIDE,
|
|
subjectName, Helpers.GetName(_connection).Ellipsise(50));
|
|
|
|
DialogResult r;
|
|
using (var dlg = new WarningDialog(msg,
|
|
ThreeButtonDialog.ButtonYes,
|
|
new ThreeButtonDialog.TBDButton(Messages.NO_BUTTON_CAPTION, DialogResult.No, selected: true))
|
|
{WindowTitle = Messages.AD_FEATURE_NAME})
|
|
{
|
|
r = dlg.ShowDialog(this);
|
|
}
|
|
|
|
//CA-64818: DialogResult can be No if the No button has been hit
|
|
//or Cancel if the dialog has been closed from the control box
|
|
if (r != DialogResult.Yes)
|
|
return;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
var action = new AddRemoveSubjectsAction(_connection, new List<string>(), subjectsToRemove);
|
|
using (var dlog = new ActionProgressDialog(action, ProgressBarStyle.Continuous))
|
|
dlog.ShowDialog(this);
|
|
}
|
|
|
|
private void GridViewSubjectList_SelectionChanged(object sender, EventArgs e)
|
|
{
|
|
if (!_updateInProgress)
|
|
EnableButtons();
|
|
}
|
|
|
|
private void EnableButtons()
|
|
{
|
|
Program.AssertOnEventThread();
|
|
if (GridViewSubjectList.SelectedRows.Count < 1)
|
|
return;
|
|
|
|
bool adminSelected = false;
|
|
bool allSelectedLoggedIn = true;
|
|
|
|
foreach (AdSubjectRow r in GridViewSubjectList.SelectedRows)
|
|
{
|
|
if (r.IsLocalRootRow)
|
|
adminSelected = true;
|
|
|
|
if (!r.LoggedIn)
|
|
allSelectedLoggedIn = false;
|
|
}
|
|
|
|
tTipChangeRole.SuppressTooltip = ButtonChangeRoles.Enabled = !adminSelected;
|
|
tTipChangeRole.SetToolTip(Messages.AD_CANNOT_MODIFY_ROOT);
|
|
|
|
tTipLogoutButton.SuppressTooltip = !adminSelected;
|
|
ButtonLogout.Enabled = !adminSelected && allSelectedLoggedIn;
|
|
|
|
tTipRemoveButton.SuppressTooltip = ButtonRemove.Enabled = !adminSelected;
|
|
|
|
toolStripMenuItemChangeRoles.Enabled = ButtonChangeRoles.Enabled;
|
|
toolStripMenuItemLogout.Enabled = ButtonLogout.Enabled;
|
|
toolStripMenuItemRemove.Enabled = ButtonRemove.Enabled;
|
|
}
|
|
|
|
private void GridViewSubjectList_CellClick(object sender, DataGridViewCellEventArgs e)
|
|
{
|
|
if (e.ColumnIndex < 0 || e.RowIndex < 0 || e.ColumnIndex != ColumnExpand.Index)
|
|
return;
|
|
|
|
var row = GridViewSubjectList.Rows[e.RowIndex] as AdSubjectRow;
|
|
if (row != null)
|
|
row.ToggleExpandedState();
|
|
}
|
|
|
|
private void GridViewSubjectList_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
|
|
{
|
|
if (e.ColumnIndex < 0 || e.RowIndex < 0)
|
|
return;
|
|
|
|
var row = GridViewSubjectList.Rows[e.RowIndex] as AdSubjectRow;
|
|
if (row != null)
|
|
row.ToggleExpandedState();
|
|
}
|
|
|
|
private void GridViewSubjectList_SortCompare(object sender, DataGridViewSortCompareEventArgs e)
|
|
{
|
|
// First of all, the admin row is always displayed at the top.
|
|
AdSubjectRow row1 = (AdSubjectRow)GridViewSubjectList.Rows[e.RowIndex1];
|
|
AdSubjectRow row2 = (AdSubjectRow)GridViewSubjectList.Rows[e.RowIndex2];
|
|
if (row1.IsLocalRootRow)
|
|
{
|
|
e.SortResult = GridViewSubjectList.SortOrder == SortOrder.Ascending ? -1 : 1;
|
|
}
|
|
else if (row2.IsLocalRootRow)
|
|
{
|
|
e.SortResult = GridViewSubjectList.SortOrder == SortOrder.Ascending ? 1 : -1;
|
|
}
|
|
else
|
|
{
|
|
// Next we look to see which column we are sorting on
|
|
switch (GridViewSubjectList.SortedColumn.Index)
|
|
{
|
|
case 0: // shouldn't happen (expander column)
|
|
case 1: // Group/individual picture column
|
|
e.SortResult = GroupCompare(row1.subject, row2.subject);
|
|
break;
|
|
case 2: // Name and detail column
|
|
e.SortResult = NameCompare(row1.subject, row2.subject);
|
|
break;
|
|
case 3: // Role Column
|
|
e.SortResult = RoleCompare(row1.subject, row2.subject);
|
|
break;
|
|
case 4: // Logged in column
|
|
e.SortResult = LoggedInCompare(row1, row2);
|
|
break;
|
|
}
|
|
}
|
|
e.Handled = true;
|
|
}
|
|
|
|
private int RoleCompare(Subject s1, Subject s2)
|
|
{
|
|
List<Role> s1Roles = _connection.ResolveAll(s1.roles);
|
|
List<Role> s2Roles = _connection.ResolveAll(s2.roles);
|
|
s1Roles.Sort();
|
|
s2Roles.Sort();
|
|
// If one subject doesn't have any roles, but it below the one with roles
|
|
if (s1Roles.Count < 1)
|
|
{
|
|
if (s2Roles.Count < 1)
|
|
{
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
if (s2Roles.Count < 1)
|
|
return 1;
|
|
|
|
return s1Roles[0].CompareTo(s2Roles[0]);
|
|
}
|
|
|
|
private int NameCompare(Subject s1, Subject s2)
|
|
{
|
|
return StringUtility.NaturalCompare(s1.SubjectName, s2.SubjectName) * -1;
|
|
}
|
|
|
|
private int LoggedInCompare(AdSubjectRow s1, AdSubjectRow s2)
|
|
{
|
|
if (s1.LoggedIn)
|
|
{
|
|
if (s2.LoggedIn)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if (s2.LoggedIn)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private int GroupCompare(Subject s1, Subject s2)
|
|
{
|
|
if (s1.IsGroup)
|
|
{
|
|
if (s2.IsGroup)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if (s2.IsGroup)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private void ButtonChangeRoles_Click(object sender, EventArgs e)
|
|
{
|
|
Program.AssertOnEventThread();
|
|
if (Helpers.FeatureForbidden(_connection, Host.RestrictRBAC))
|
|
{
|
|
UpsellDialog.ShowUpsellDialog(string.Format(Messages.UPSELL_BLURB_RBAC, BrandManager.ProductBrand), this);
|
|
return;
|
|
}
|
|
|
|
// Double check, this method is called from a context menu as well and the state could have changed under it
|
|
if (!ButtonChangeRoles.Enabled)
|
|
return;
|
|
|
|
var selectedSubjects = GridViewSubjectList.SelectedRows.Cast<AdSubjectRow>().Where(r => !r.IsLocalRootRow).Select(r => r.subject).ToList();
|
|
|
|
using (var dialog = new RoleSelectionDialog(_connection, selectedSubjects))
|
|
if (dialog.ShowDialog(this) == DialogResult.OK)
|
|
{
|
|
foreach (Subject s in selectedSubjects)
|
|
new AddRemoveRolesAction(_connection, s, dialog.SelectedRoles).RunAsync();
|
|
}
|
|
}
|
|
|
|
private void ButtonLogout_Click(object sender, EventArgs e)
|
|
{
|
|
Program.AssertOnEventThread();
|
|
// Double check, this method is called from a context menu as well and the state could have changed under it
|
|
if (!ButtonLogout.Enabled)
|
|
return;
|
|
|
|
Session session = _connection.Session;
|
|
if (session == null)
|
|
return;
|
|
|
|
var subjectsToLogout = new List<Subject>();
|
|
bool logSelfOut = false;
|
|
|
|
foreach (AdSubjectRow r in GridViewSubjectList.SelectedRows)
|
|
{
|
|
if (r.IsLocalRootRow || !r.LoggedIn)
|
|
continue;
|
|
|
|
subjectsToLogout.Add(r.subject);
|
|
|
|
if (session.SessionSubject != null && r.subject.opaque_ref == session.SessionSubject)
|
|
logSelfOut = true;
|
|
}
|
|
|
|
bool suicide = false;
|
|
if (logSelfOut)
|
|
{
|
|
var warnMsg = string.Format(subjectsToLogout.Count > 1 ? Messages.AD_LOGOUT_SUICIDE_MANY : Messages.AD_LOGOUT_SUICIDE_ONE,
|
|
Helpers.GetName(_connection).Ellipsise(50));
|
|
|
|
using (var dlg = new WarningDialog(warnMsg,
|
|
ThreeButtonDialog.ButtonYes,
|
|
new ThreeButtonDialog.TBDButton(Messages.NO_BUTTON_CAPTION, DialogResult.No, selected: true))
|
|
{WindowTitle = Messages.AD_FEATURE_NAME})
|
|
{
|
|
//CA-64818: DialogResult can be No if the No button has been hit
|
|
//or Cancel if the dialog has been closed from the control box
|
|
if (dlg.ShowDialog(this) != DialogResult.Yes)
|
|
return;
|
|
|
|
suicide = true;
|
|
}
|
|
}
|
|
|
|
var logoutMessage = subjectsToLogout.Count == 1
|
|
? string.Format(Messages.QUESTION_LOGOUT_AD_USER_ONE, subjectsToLogout[0].DisplayName ?? subjectsToLogout[0].SubjectName)
|
|
: string.Format(Messages.QUESTION_LOGOUT_AD_USER_MANY, subjectsToLogout.Count);
|
|
|
|
if (!suicide)//CA-68645
|
|
{
|
|
using (var dlg = new WarningDialog(logoutMessage,
|
|
ThreeButtonDialog.ButtonYes,
|
|
new ThreeButtonDialog.TBDButton(Messages.NO_BUTTON_CAPTION, DialogResult.No, selected: true))
|
|
{WindowTitle = Messages.AD_FEATURE_NAME})
|
|
{
|
|
//CA-64818: DialogResult can be No if the No button has been hit
|
|
//or Cancel if the dialog has been closed from the control box
|
|
if (dlg.ShowDialog(this) != DialogResult.Yes)
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Then we go through the list and disconnect each user session, doing our own last if necessary
|
|
foreach (AdSubjectRow r in GridViewSubjectList.SelectedRows)
|
|
{
|
|
if (r.IsLocalRootRow || !r.LoggedIn)
|
|
continue;
|
|
|
|
if (session.UserSid == r.subject.subject_identifier)
|
|
continue;
|
|
|
|
new DelegatedAsyncAction(_connection,
|
|
string.Format(Messages.TERMINATING_USER_SESSION, r.subject.DisplayName ?? r.subject.SubjectName),
|
|
Messages.IN_PROGRESS, Messages.COMPLETED,
|
|
s => Session.logout_subject_identifier(s, r.subject.subject_identifier),
|
|
"session.logout_subject_identifier").RunAsync();
|
|
}
|
|
|
|
if (suicide)
|
|
{
|
|
new DisconnectCommand(Program.MainWindow, _connection, true).Run();
|
|
}
|
|
else
|
|
{
|
|
// signal the background thread to update the logged in status
|
|
lock (statusUpdaterLock)
|
|
Monitor.Pulse(statusUpdaterLock);
|
|
}
|
|
}
|
|
}
|
|
}
|