I use FiddlerCore to capture HTTP traffic when performing web UI tests with Selenium (C#) ChromeDriver. I have finally managed to get it working by trial and error, but need a hint on why my solution works and the logical way (for me) doesn't.
I configure the fiddler proxy as:
CONFIG.IgnoreServerCertErrors = false;
FiddlerApplication.Prefs.SetBoolPref("fiddler.network.streaming.abortifclientaborts", true);
var startupSettings =
new FiddlerCoreStartupSettingsBuilder()
.ListenOnPort(0)
.DecryptSSL()
.OptimizeThreadPool()
.Build();
FiddlerApplication.Startup(startupSettings);
HttpPort = FiddlerApplication.oProxy.ListenPort;
FiddlerApplication.Log.LogFormat("Created HTTP endpoint listening on port {0}", HttpPort);
secureEndpoint = FiddlerApplication.CreateProxyEndpoint(HttpsPort, true, Host);
if (secureEndpoint != null)
{
HttpsPort = secureEndpoint.ListenPort;
FiddlerApplication.Log.LogFormat("Created secure endpoint listening on port {0}, using a HTTPS certificate for '{1}'",HttpsPort, Host);
}
CertMaker.trustRootCert();
This basically follows the demo project provided for FiddlerCore. Note, that the proxy is not registered as system proxy.
Then, ChromeDriver is configured as:
var chromeDriverService = ChromeDriverService.CreateDefaultService();
chromeDriverService.HideCommandPromptWindow = true;
var options = new ChromeOptions();
options.Proxy = new Proxy()
{
HttpProxy = $"{SkicoProxy.Host}:{SkicoProxy.HttpPort}",
SslProxy = $"{SkicoProxy.Host}:{SkicoProxy.HttpPort}"
};
_driver = new ChromeDriver(chromeDriverService, options);
What doesn't work, although I would expect it to is:
options.Proxy = new Proxy()
{
HttpProxy = $"{SkicoProxy.Host}:{SkicoProxy.HttpPort}",
SslProxy = $"{SkicoProxy.Host}:{SkicoProxy.HttpsPort}" // HTTPS PORT INSTEAD HTTP PORT
};
Still, if I do not configure the endpoint in Fiddler, SSL websites are shown as unsafe in Chrome.
Why doesn't SSL traffic needs to be routed through the according endpoint and why does it even work if it is not proxied through the secure endpoint?
Related
Trying to capture all traffic from browser using FiddlerCore using the .NetStandard libraries.
Below is what I have:
public class ProxyConfig
{
private const string SecureEndpointHostname = "localhost";
private readonly int _secureEndpointPort = 18888;
private static readonly ICollection<Session> AllSessions = new List<Session>();
private static Fiddler.Proxy _secureEndpoint;
private static readonly LoggerCnx Logger = new LoggerCnx();
public void SetupProxyListener()
{
// This is a workaround for known issue in .NET Core - https://github.com/dotnet/coreclr/issues/12668
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");
FiddlerApplication.BeforeRequest += session =>
{
// In order to enable response tampering, buffering mode MUST
// be enabled; this allows FiddlerCore to permit modification of
// the response in the BeforeResponse handler rather than streaming
// the response to the client as the response comes in.
session.bBufferResponse = false;
lock (AllSessions)
{
AllSessions.Add(session);
}
};
Logger.Info($"Starting {FiddlerApplication.GetVersionString()}...");
CONFIG.IgnoreServerCertErrors = true;
CONFIG.bCaptureCONNECT = true;
FiddlerApplication.Prefs.SetBoolPref("fiddler.network.streaming.abortifclientaborts", true);
FiddlerCoreStartupFlags startupFlags = FiddlerCoreStartupFlags.Default;
startupFlags = (startupFlags | FiddlerCoreStartupFlags.DecryptSSL);
FiddlerApplication.Startup(BaseConfiguration.ProxyPort, startupFlags);
Logger.Info("Created endpoint listening on port {0}", BaseConfiguration.ProxyPort);
Logger.Info("Starting with settings: [{0}]", startupFlags);
Logger.Info("Gateway: {0}", CONFIG.UpstreamGateway.ToString());
// Create a HTTPS listener, useful for when FiddlerCore is masquerading as a HTTPS server
// instead of acting as a normal CERN-style proxy server.
_secureEndpoint = FiddlerApplication.CreateProxyEndpoint(_secureEndpointPort, true, SecureEndpointHostname);
if (null != _secureEndpoint)
{
Logger.Info("Created secure endpoint listening on port {0}, using a HTTPS certificate for '{1}'", _secureEndpointPort, SecureEndpointHostname);
}
}
}
Everything seems to work fine on Windows, all traffic is captured, HTTP and HTTPS.
The problem arises when I'm trying to do the same when running the code on Linux (tried it on both VM and Linux conainer, Ubuntu 16.04). HTTP traffic is captured but HTTPS is not.
Any idea what I'm I'm missing?
I coded a WCF Service using HttpTransportBindingElement in conjunction with IIS on port 80.
The code works fine as long as no proxy is used. But if a customer has a http-proxy the communication between WCF-Client and Server does not work in this case by occuring following error:
'There was no endpoint listening at ... that could accept the message. This is often caused by an incorrect address or SOAP action.'
It is essential to use settings by code ONLY!
here is my code approach for that issue but i stuck on it:
bool SendClientRequest(Action<ICustomerService> channel)
{
string proxy ="my.proxy.domain:8080";
string user = "user1";
string password="secret";
// maybe i do not need this 3 lines!
WebProxy webproxy = new WebProxy(proxy, true);
webproxy.Credentials = new NetworkCredential(user, password);
WebRequest.DefaultWebProxy = webproxy;
CustomBinding customBinding = new CustomBinding();
customBinding.Elements.Add(new HttpTransportBindingElement()
{
AuthenticationSchemes.None : AuthenticationSchemes.Basic,
ProxyAddress = string.IsNullOrEmpty(proxy) ? null : new Uri(proxy),
UseDefaultWebProxy = false,
BypassProxyOnLocal = true,
TransferMode = TransferMode.Streamed,
MaxReceivedMessageSize = 84087406592,
MaxBufferPoolSize = 0x1000000,
MaxBufferSize = 0x1000000
});
using (ChannelFactory<ICustomerService> factory = new
ChannelFactory<ICustomerService>(customBinding ))
{
IClientChannel contextChannel = null;
string url = "http://my.domain.de/Distribution/eService.svc",
EndpointAddress ep = new EndpointAddress(url);
ICustomerService clientChannel = factory.CreateChannel(ep);
contextChannel = clientChannel as IClientChannel;
contextChannel.OperationTimeout = TimeSpan.FromMinutes(rcvTimeout );
channel(clientChannel); // <- here i get the exception!
return true;
}
}
I tried several solution approaches but nothing seems to be specific like mine.
I think you have a few options, some of which I'll detail below.
First you could set UseDefaultWebProxy to true. This would then mean that proxy information is retrieved automatically from system proxy settings, configurable in Internet Explorer (Internet Options > Connections > LAN settings > Proxy server). This may be appropriate if you don't need to specify credentials for proxy use.
Another approach that's worked for me is to use the ProxyAuthenticationScheme property within your HttpTransportBindingElement() object. This property is only available on the CustomBinding class and allows an authentication scheme to be specified that will be used to authenticate against a proxy. In conjunction with this, the proxy server must be set against property ProxyAddress. Last but not least, the credentials to use against the proxy should be set according to the authentication scheme used, so for example, using AuthenticationSchemes.Ntlm would mean setting the UserName and Password properties on ChannelFactory.ClientCredentials.Windows.ClientCredential or perhaps ChannelFactory.ClientCredentials.HttpDigest.ClientCredential
With the second approach, be sure to note the difference between holding credentials in the ChannelFactory for use with the remote service versus credentials used for the proxy server. I've highlighted these in the code example below for clarity:
// Example service call using a CustomBinding that is configured for client
// authentication based on a user name and password sent as part of the message.
var binding = new CustomBinding();
TransportSecurityBindingElement securityBindingElement = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
var secureTransport = new HttpsTransportBindingElement();
secureTransport.UseDefaultWebProxy = false;
secureTransport.ProxyAddress = new Uri("http://some-proxy");
secureTransport.ProxyAuthenticationScheme = AuthenticationSchemes.Ntlm;
binding.Elements.Add(securityBindingElement);
binding.Elements.Add(secureTransport);
var endpointAddress = new EndpointAddress("https://some-service");
var factory = new ChannelFactory<IService>(binding, endpointAddress);
// Credentials for authentication against the remote service
factory.Credentials.UserName.UserName = "serviceUser";
factory.Credentials.UserName.Password = "abc";
// Credentials for authentication against the proxy server
factory.Credentials.Windows.ClientCredential.UserName = "domain\user";
factory.Credentials.Windows.ClientCredential.Password = "xyz";
var client = factory.CreateChannel();
client.CallMethod();
I need to develop a WCF Hosted in a console app WebService.
I made it work using the Mutual Certificate (service and client) method using SecurityMode.Message.
But now i need to change the Security Mode to SecurityMode.Transport and use the wsHttpBinding with SSL. I made this code to host the service but i cannot get the wsdl with the browser, or execute some webmethod in the console app client.
static void Main()
{
var httpsUri = new Uri("https://localhost:8089/HelloServer");
var binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
var host = new ServiceHost(typeof(WcfFederationServer.HelloWorld), httpsUri);
host.AddServiceEndpoint(typeof(WcfFederationServer.IHelloWorld), binding, "", httpsUri);
var mex = new ServiceMetadataBehavior();
mex.HttpsGetEnabled = true;
host.Description.Behaviors.Add(mex);
// Open the service.
host.Open();
Console.WriteLine("Listening on {0}...", httpsUri);
Console.ReadLine();
// Close the service.
host.Close();
}
The service is up, but i cannot get nothing on the https://localhost:8089/HelloServer.
On fiddler the get request via browser shows me this message:
fiddler.network.https> HTTPS handshake to localhost failed. System.IO.IOException
What im missing here?
Thanks
EDIT:
The Console Application Client Code
static void Main()
{
try
{
var client = new HelloWorldHttps.HelloWorldClient();
client.ClientCredentials.ClientCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.TrustedPeople,
X509FindType.FindBySubjectName,
"www.client.com");
Console.WriteLine(client.GetData());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
}
Getting this error:
Could not establish trust relationship for the SSL/TLS secure channel
When it comes to the service, you need to map the certificate to the specific port as described here
http://msdn.microsoft.com/en-us/library/ms733791(v=vs.110).aspx
As for the client, you need to skip the verification of certificate properties like valid date, the domain by relaxing the certificate acceptance policy. An easiest way would be to accept any certiticate
ServicePointManager.ServerCertificateValidationCallback = (a,b,c,d) => true
You can finetune the acceptance callback according to the docs to best fit your needs.
Ok so I am hosting a WCF service within a console application.
all bindings are created programatically, so no config settings.
I have a working service as long as I use HttpTransportBindingElement however as soon as I use HttpsTransportBindingElement then nothing works, the service does not display within the browser and the client application returns a 405 (Method Not Allowed) CommunicationException
I have tried setting a SecurityBindingElement to my CustomBinding but I am not sure which option I should be using.
SecurityBindingElement.CreateCertificateOverTransportBindingElement()
SecurityBindingElement.CreateAnonymousForCertificateBindingElement()
etc.
The code for the creation of the host is below
baseAddress = new Uri(string.Format("{0}://{1}", strConnectionType, ConfigurationManager.AppSettings["baseAddress"]));
ServiceHost host = new ServiceHost(typeof(IMyService), baseAddress);
host.AddServiceEndpoint(typeof(MyService), binding, String.Empty);
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpsGetEnabled = certificate != null;
smb.HttpGetEnabled = certificate == null;
host.Description.Behaviors.Add(smb);
ServiceDebugBehavior sdb = host.Description.Behaviors.Find<ServiceDebugBehavior>();
if (sdb == null)
{
host.Description.Behaviors.Add(new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true });
}
else
{
if (!sdb.IncludeExceptionDetailInFaults)
{
sdb.IncludeExceptionDetailInFaults = true;
}
}
if (certificate != null)
{
host.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, certificate.Thumbprint);
}
I followed this blog http://blogs.msdn.com/b/james_osbornes_blog/archive/2010/12/10/selfhosting-a-wcf-service-over-https.aspx which highlighted that in order for HTTPS to work you need to bind the port to the certificate you are using.
Process bindPortToCertificate = new Process();
bindPortToCertificate.StartInfo.FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.SystemX86), "netsh.exe");
bindPortToCertificate.StartInfo.Arguments = string.Format("http add sslcert ipport=0.0.0.0:{0} certhash={1} appid={{{2}}}", port, certificate.Thumbprint, Guid.NewGuid());
bindPortToCertificate.Start();
bindPortToCertificate.WaitForExit();
once this was done it all worked.
contact me if any requires my example code of setting up and configuring a self-hosted WCF server with bindings programatically set. :)
I'm trying to build a C# SignalR app (console app on the server, winforms app on the client), and it works great (in Visual Studio) when both the client and server are on the same PC, but when I deploy the server and repoint the client to the server, I'm getting a "407 Proxy Authentication Required" exception when it tries to start.
This is my code...
var _connection = new HubConnection("http://www.redacted.com:8088/");
var _hub = _connection.CreateProxy("MyHub");
_connection.Start().ContinueWith(task =>
{
if (task.IsFaulted)
MessageBox.Show(string.Format("Could not connect - {0}", task.Exception.ToString()));
}).Wait();
I noticed that HubConnection has a Credentials property, and so I figured I'd try replacating some code I've used with WebServices when dealing with proxies (shown below, where I just make an HTTP request out and then pick up the proxy settings and credentials from that), but I get the same exception.
var _connection = new HubConnection("http://www.redacted.com:8088/");
var req = (HttpWebRequest)WebRequest.Create("http://www.google.com");
var proxy = new WebProxy(req.Proxy.GetProxy(req.RequestUri).AbsoluteUri) {UseDefaultCredentials = true};
_connection.Credentials = proxy.Credentials;
var _hub = _connection.CreateProxy("MyHub");
_connection.Start().ContinueWith(task =>
{
if (task.IsFaulted)
MessageBox.Show(string.Format("Could not connect - {0}", task.Exception.ToString()));
}).Wait();
This is required for some work I'm doing for a client where they want their local PCs to be able to receive messages from a remote system that's hosted outside the company.
Thanks!
Try to set the DefaultWebProxy:
WebProxy wproxy = new WebProxy("new proxy",true);
wproxy.Credentials = new NetworkCredential("user", "pass");
WebRequest.DefaultWebProxy = wproxy;