Cefsharp IgnoreCertificateErrors after Cef is initialized - wpf

I'm using Cefsharp.WPF in a plugin that runs inside a program which is already using Cefsharp 57.0.0 internally. The recommendation from the main developer is to use this exact version to avoid conflicts. As the main program already has initialised Cef, there's no need to call Cef.Initialize() in the plugin and Cef.IsInitialized returns true too. This means calling Cef.Initialize() throws an exception as expected. The other thing to note is that when shipping the plugin files, I don't need to include Cefsharp dlls and files. I can just create a new ChromiumWebBrowser in my plugin and everything has been working fine until recently.
My plugin has been loading Google maps in a ChromiumWebBrowser. But from about a week ago this request returns ERR_Aborted. Upon investigating I found that setting IgnoreCertificateErrors to true fixes this issue.
I can set my own settings in a test standalone WPF app with Cef 57.0.0 as I initialise Cef myself. So this code loads Google maps fine in my standalone test WPF app:
ChromiumWebBrowser t;
public MainWindow()
{
InitializeComponent();
var settings = new CefSettings();
settings.IgnoreCertificateErrors = true;
//settings.CefCommandLineArgs.Add("ignore-certificate-errors", string.Empty);
Cef.Initialize(settings);
t = new ChromiumWebBrowser();
t.IsBrowserInitializedChanged += ChromiumWebBrowser_IsBrowserInitializedChanged;
g.Children.Add(t);
}
private void ChromiumWebBrowser_IsBrowserInitializedChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (t.IsBrowserInitialized)
{
t.Load("https://www.google.com.au/maps/");
}
}
But in my plugin, I can only set the RequestHandler of the browser instance with a custom implementation of IRequestHandler and implement OnCertificateError. Doing this, I encounter a weird behaviour where Google maps loads but there are some resources broken (not loaded) and seems like some Javascript codes are not running properly also.
Here's the full implementation of IRequestHandler:
public class ChromiumRequestHandler : IRequestHandler
{
public bool GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)
{
return false;
}
public IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
{
return null;
}
public bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect)
{
return false;
}
public CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback)
{
callback.Continue(true);
return CefReturnValue.Continue;
}
public bool OnCertificateError(IWebBrowser browserControl, IBrowser browser, CefErrorCode errorCode, string requestUrl, ISslInfo sslInfo, IRequestCallback callback)
{
if (!callback.IsDisposed)
{
using (callback)
{
callback.Continue(true);
return true;
}
}
return false;
}
public bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
{
return false;
}
public void OnPluginCrashed(IWebBrowser browserControl, IBrowser browser, string pluginPath)
{
}
public bool OnProtocolExecution(IWebBrowser browserControl, IBrowser browser, string url)
{
return false;
}
public bool OnQuotaRequest(IWebBrowser browserControl, IBrowser browser, string originUrl, long newSize, IRequestCallback callback)
{
return false;
}
public void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status)
{
}
public void OnRenderViewReady(IWebBrowser browserControl, IBrowser browser)
{
}
public void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength)
{
}
public void OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, ref string newUrl)
{
}
public bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
{
return false;
}
public bool OnSelectClientCertificate(IWebBrowser browserControl, IBrowser browser, bool isProxy, string host, int port, X509Certificate2Collection certificates, ISelectClientCertificateCallback callback)
{
return false;
}
}
I know using a more up-to-date version of Cefsharp will fix the issue but I MUST use this specific version (57.0.0). My question is how can I implement the IRequestHandler to exactly work as if I have set CefSettings.IgnoreCertificateErrors to true?
When I step through the code, the following methods in my custom implementation get called:
OnRenderViewReady
OnBeforeBrowse
OnBeforeResourceLoad
OnCertificateError
GetResourceResponseFilter
OnResourceResponse
OnResourceLoadComplete

Related

ASP.NET Core with Winforms - Saving the username once

I have a standard Hoemcontroller in ASP.NET Core MVC:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index(string user)
{
if(user != null)
{
TempData["UserName"] = user;
return View("Index", user);
}
return View("Index");
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
In the Index Action there will be a parameter sent from a winforms application. The string will contain the username of the client connecting to the website. This is the code for winforms:
public partial class Form1 : Form
{
public ChromiumWebBrowser chromeBrowser;
public Form1()
{
InitializeComponent();
InitializeChromium();
this.WindowState = FormWindowState.Maximized;
}
public void InitializeChromium()
{
CefSettings settings = new CefSettings();
Cef.Initialize(settings);
Cef.EnableHighDPISupport();
chromeBrowser = new ChromiumWebBrowser("https://localhost:5001/Home/Index/" + Environment.UserName);
this.Controls.Add(chromeBrowser);
//chromeBrowser.Dock = DockStyle.Fill;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Cef.Shutdown();
}
}
Now I am unsure on how to handle this on the webserver. I get the username inside the HomeController but in the same time when a user goes to the other pages with their controllers then the user should see only his content. Is that even possible?
It is not good practice to do authorization through a parameter in URI. For that, you should use Authentication (when the user passes his login and password) and receive a token with permissions. After that, you pass the token to the server and check permission there(using Authorize attribute for example). Example
If you are making a test project, and you don't need authentication at all, then you can pass a username everywhere you need and write some code to handle the content of every user (using headers, URI parameters, etc.)

CefSharp new version IContextMenuHandler

How do I hide the CefSharp.WinForms.ChromiumWebBrowser right click context menu?
public class CustomMenuHandler : CefSharp.IContextMenuHandler
{
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model)
{
model.Clear();
}
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags)
{
return false;
}
public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame)
{
}
public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback)
{
return false;
}
}
previously I used the code from the above post to disable the context menu in CefSharp.
with the newest update, CefSharp.IContextMenuHandler no longer exists
how can i restore this functionality?

can't open pdf with wpf webbrowser

I'm trying to create an app to open a local PDF file using web browser in WPF. However the file doesn't open properly, instead displays a grey blank screen. The code works perfectly fine when used to open a HTML file. Please help!
Code: webBrowser1.Navigate(#"file:///C:/Working/sample.pdf");
Note: I have adobe reader installed in my PC, if that is necessary. Is it?
WPF by default uses IE-based WebBrowser. In order to be able to view PDF-files, you must have a plugin installed into IE which can display PDF-files.
In addition to grey background, this is what can happen with a PC where IE doesn't have a PDF-plugin (Acrobat Reader etc) installed:
If you don't want to install plugins, one option to get around this issue is to use Windows 10 APIs to draw the PDF.
Other option is a 3rd party library, like CefSharp. Here's steps for using CefSharp:
First install Nuget CefSharp.WPF
Second, change XAML from the default WebBrowser to:
<wpf:ChromiumWebBrowser Loaded="ChromiumWebBrowser_Loaded" x:Name="Browser"></wpf:ChromiumWebBrowser>
Then create custom resolvers for CefSharp:
public class CustomProtocolSchemeHandler : ResourceHandler
{
public CustomProtocolSchemeHandler()
{
}
public override bool ProcessRequestAsync(IRequest request, ICallback callback)
{
return true;
}
}
public class CustomProtocolSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "customFileProtocol";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
return new CustomProtocolSchemeHandler();
}
}
Almost lastly, register the resolvers in App.xaml.cs:
public partial class App : Application
{
protected override void OnLoadCompleted(NavigationEventArgs e)
{
var settings = new CefSettings();
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = CustomProtocolSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new CustomProtocolSchemeHandlerFactory(),
IsCSPBypassing = true
});
settings.LogSeverity = LogSeverity.Error;
Cef.Initialize(settings);
}
}
Now everything should work:
More information about using CefSharp: https://www.codeproject.com/Articles/881315/Display-HTML-in-WPF-and-CefSharp-Tutorial-Part
I'll probably add a few changes to #Mikael's code (In case something didn't work out for you)
public class CustomProtocolSchemeHandler : ResourceHandler
{
public CustomProtocolSchemeHandler()
{
}
public override CefSharp.CefReturnValue ProcessRequestAsync(IRequest request, ICallback callback)
{
return CefSharp.CefReturnValue.Continue;
}
}
public class CustomProtocolSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "customFileProtocol";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
return new CustomProtocolSchemeHandler();
}
}

IdentityServer4 and OidcClient on IOS prompt

I have IDS4 and a Xamarin.Forms app all working fine except one little issue. Every single time the iOS app accesses the IDP server it first gives me this prompt:
"AppName" Wants to Use "" to Sign In
This allows the app and website to share information about you
What is causing this?
I have this error using IdentityModel.OidcClient2. Please see this link for the cause. This is the gist of it:
Cause
This is a system dialog that was added in iOS 11 to SFAuthenticationSession. It is triggered by this code in AppAuth:
SFAuthenticationSession* authenticationVC =
[[SFAuthenticationSession alloc] initWithURL:requestURL
callbackURLScheme:redirectScheme
completionHandler:^(NSURL * _Nullable callbackURL,
NSError * _Nullable error) {
There isn't a way to get rid of the dialog, except to not use SFAuthenticationSession which means you lose Single SignOn, which is worse.
I ended up using SFSafariViewController instead of SFAuthenticationSession by using the method mentioned by MLeech HERE
Solution
Which basically meant add these lines to your AppDelegate.cs
public override UIWindow Window
{
get;
set;
}
public static Action<string> CallbackHandler { get; set; }
public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
{
CallbackHandler(url.AbsoluteString);
CallbackHandler = null;
return true;
}
Then use this code for your SFAuthenticationSessionBrowser.cs
public class SFAuthenticationSessionBrowser : IBrowser
{
public Task<BrowserResult> InvokeAsync(BrowserOptions options)
{
var task = new TaskCompletionSource<BrowserResult>();
var safari = new SFSafariViewController(new NSUrl(options.StartUrl));
AppDelegate.CallbackHandler = async url =>
{
await safari.DismissViewControllerAsync(true);
task.SetResult(new BrowserResult()
{
Response = url
});
};
// https://forums.xamarin.com/discussion/24689/how-to-acces-the-current-view-uiviewcontroller-from-an-external-service
var window = UIApplication.SharedApplication.KeyWindow;
var vc = window.RootViewController;
while (vc.PresentedViewController != null)
{
vc = vc.PresentedViewController;
}
vc.PresentViewController(safari, true, null);
return task.Task;
}
}

Close the already opened Custom menu handler when click on Cefsharp webbrowser container

I am developing WPF application using cefsharp chromium web browser as a browser control. In my App, when right click on the Cefsharp browser I would like to show some controls and I am able to show the controls. When I right click, open the custom menu and click on container then I am not able to close the custom menu.
My Code is
_cefchrbrowser.Address = _address;
_cefchrbrowser.MenuHandler = new CustomMenuHandler();
My Class is
public class CustomMenuHandler : IContextMenuHandler
{
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model)
{
model.Remove(CefMenuCommand.ViewSource);
model.Remove(CefMenuCommand.Print);
model.Remove(CefMenuCommand.Undo);
model.Remove(CefMenuCommand.Redo);
}
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags)
{
return false;
}
public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame)
{
}
public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback)
{
return false;
}
}
Without selecting any custom menu item when I click on browser, I am not able to close the menu.

Resources