mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-11-25 14:27:26 +01:00
abec5c4aba
life browsers and allow the user to see the status even if other actions are taking place. Removed webClient use from the browser; instead try sequentially to navigate to all Uris until one succeeds; this avoids sending duplicate requests and allows the user to see all endpoints tried out. Reworked the WebBrowser event handlers to ensure the UI reflects correctly the browser state. Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
264 lines
9.7 KiB
C#
264 lines
9.7 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.Net;
|
|
using System.Net.Sockets;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security.Permissions;
|
|
using System.Windows.Forms;
|
|
using XenCenterLib;
|
|
|
|
namespace XenAdmin.Core
|
|
{
|
|
/// <summary>
|
|
/// This extension to System.Windows.Forms.WebBrowser adds two capabilities: an event fired whenever
|
|
/// browser navigation fails (NavigateError), and an event fired whenever the browser wants to
|
|
/// prompt for credentials (AuthenticationPrompt).
|
|
///
|
|
/// The event sink for NavigateError comes from
|
|
/// http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.createsink(VS.80).aspx.
|
|
/// The handling of authentication prompts comes partially from
|
|
/// http://izlooite.blogspot.com/2009/06/bypass-integrated-authentication-using.html.
|
|
/// The bit that he missed is that we can override CreateWebBrowserSiteBase to get ourselves
|
|
/// registered rather than having to override IOleClientSite as well. See
|
|
/// http://msdn2.microsoft.com/en-us/library/system.windows.forms.webbrowser.createwebbrowsersitebase.aspx.
|
|
///
|
|
/// (Final note: Contrary to the docs, you can't use the CreateWebBrowserSiteBase override to reimplement
|
|
/// IDocHostUIHandler. This is an acknowledged Microsoft bug
|
|
/// https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=115198.
|
|
/// Fortunately, we only need to implement IAuthenticate, not IDocHostUIHandler, so this isn't a problem
|
|
/// for us, but it was confusing for a couple of days.)
|
|
/// </summary>
|
|
public class WebBrowser2 : WebBrowser
|
|
{
|
|
private AxHost.ConnectionPointCookie cookie;
|
|
private WebBrowser2EventHelper helper;
|
|
|
|
public event Action<WebBrowser2, NavigateErrorEventArgs> NavigateError;
|
|
|
|
public event EventHandler WindowClosed;
|
|
|
|
public event Action<WebBrowser2, AuthenticationPromptEventArgs> AuthenticationPrompt;
|
|
|
|
private bool Authenticate(out string username, out string password)
|
|
{
|
|
if (AuthenticationPrompt == null)
|
|
{
|
|
username = "";
|
|
password = "";
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
var args = new AuthenticationPromptEventArgs();
|
|
AuthenticationPrompt(this, args);
|
|
username = args.Username;
|
|
password = args.Password;
|
|
return args.Success;
|
|
}
|
|
}
|
|
|
|
[PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
|
|
protected override void CreateSink()
|
|
{
|
|
base.CreateSink();
|
|
|
|
// Create an instance of the client that will handle the event
|
|
// and associate it with the underlying ActiveX control.
|
|
helper = new WebBrowser2EventHelper(this);
|
|
cookie = new AxHost.ConnectionPointCookie(ActiveXInstance, helper, typeof(DWebBrowserEvents2));
|
|
}
|
|
|
|
[PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
|
|
protected override void DetachSink()
|
|
{
|
|
// Disconnect the client that handles the event
|
|
// from the underlying ActiveX control.
|
|
if (cookie != null)
|
|
{
|
|
cookie.Disconnect();
|
|
cookie = null;
|
|
}
|
|
base.DetachSink();
|
|
}
|
|
|
|
protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
|
|
{
|
|
return new WebBrowserSite2(this);
|
|
}
|
|
|
|
protected virtual void OnNavigateError(NavigateErrorEventArgs e)
|
|
{
|
|
if (NavigateError != null)
|
|
NavigateError(this, e);
|
|
}
|
|
|
|
protected override void WndProc(ref Message m)
|
|
{
|
|
switch (m.Msg)
|
|
{
|
|
case Win32.WM_PARENTNOTIFY:
|
|
if (!DesignMode && (int)m.WParam == Win32.WM_DESTROY)
|
|
{
|
|
if (WindowClosed != null)
|
|
WindowClosed(this, EventArgs.Empty);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
base.WndProc(ref m);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#region Nested classes
|
|
|
|
private class WebBrowserSite2 : WebBrowserSite, Win32.IAuthenticate, Win32.IServiceProvider
|
|
{
|
|
private readonly WebBrowser2 Browser;
|
|
|
|
public WebBrowserSite2(WebBrowser2 browser)
|
|
: base(browser)
|
|
{
|
|
Browser = browser;
|
|
}
|
|
|
|
#region IAuthenticate Members
|
|
|
|
public int Authenticate(ref IntPtr phwnd, ref IntPtr pszUsername, ref IntPtr pszPassword)
|
|
{
|
|
string username, password;
|
|
if (Browser.Authenticate(out username, out password))
|
|
{
|
|
IntPtr sUser = Marshal.StringToCoTaskMemAuto(username);
|
|
IntPtr sPassword = Marshal.StringToCoTaskMemAuto(password);
|
|
|
|
pszUsername = sUser;
|
|
pszPassword = sPassword;
|
|
return Win32.S_OK;
|
|
}
|
|
else
|
|
{
|
|
return Win32.E_ACCESSDENIED;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IServiceProvider Members
|
|
|
|
public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
|
|
{
|
|
if (guidService.CompareTo(Win32.IID_IAuthenticate) == 0 && riid.CompareTo(Win32.IID_IAuthenticate) == 0)
|
|
{
|
|
ppvObject = Marshal.GetComInterfaceForObject(this, typeof(Win32.IAuthenticate));
|
|
return Win32.S_OK;
|
|
}
|
|
else
|
|
{
|
|
ppvObject = IntPtr.Zero;
|
|
return Win32.INET_E_DEFAULT_ACTION;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the NavigateError event from the underlying ActiveX
|
|
/// control by raising the NavigateError event defined in this class.
|
|
/// </summary>
|
|
private class WebBrowser2EventHelper : StandardOleMarshalObject, DWebBrowserEvents2
|
|
{
|
|
private WebBrowser2 parent;
|
|
|
|
public WebBrowser2EventHelper(WebBrowser2 parent)
|
|
{
|
|
this.parent = parent;
|
|
}
|
|
|
|
public void NavigateError(object pDisp, ref object url, ref object frame, ref object statusCode, ref bool cancel)
|
|
{
|
|
parent.OnNavigateError(new NavigateErrorEventArgs((string)url, (string)frame, (Int32)statusCode, cancel));
|
|
}
|
|
}
|
|
|
|
public class NavigateErrorEventArgs : EventArgs
|
|
{
|
|
public string Url;
|
|
public string Frame;
|
|
public Int32 StatusCode;
|
|
public bool Cancel;
|
|
|
|
public NavigateErrorEventArgs(string url, string frame, Int32 statusCode, bool cancel)
|
|
{
|
|
Url = url;
|
|
Frame = frame;
|
|
StatusCode = statusCode;
|
|
Cancel = cancel;
|
|
}
|
|
}
|
|
|
|
public class AuthenticationPromptEventArgs : EventArgs
|
|
{
|
|
/// <summary>
|
|
/// Set to true by the event handler if the user clicked OK on the authentication prompt.
|
|
/// </summary>
|
|
public bool Success;
|
|
|
|
/// <summary>
|
|
/// Set by the event handler, iff Success is true.
|
|
/// </summary>
|
|
public string Username;
|
|
|
|
/// <summary>
|
|
/// Set by the event handler, iff Success is true.
|
|
/// </summary>
|
|
public string Password;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
[ComImport, Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"),
|
|
InterfaceType(ComInterfaceType.InterfaceIsIDispatch),
|
|
TypeLibType(TypeLibTypeFlags.FHidden)]
|
|
public interface DWebBrowserEvents2
|
|
{
|
|
[DispId(271)]
|
|
void NavigateError([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp,
|
|
[In] ref object URL, [In] ref object frame,
|
|
[In] ref object statusCode, [In, Out] ref bool cancel);
|
|
}
|
|
}
|