WCF TCP Binding in a self hosted WinForms App - vb.net

I have decided to do net.tcp binding in my self hosted wcf app (with transport level encryption).
While I had quite an interesting time in getting info on the subject of making a self hosted wcf app work, my current working solution does not implicitly specify binding, so I guess it defaults to BasicHttp.
I am unsure of how to "add/change" the binding to net.tcp and transport level encryption ? I am also curious in "testing" my tcp secured connection. What would be used to run some test security scenarios?
Working Code: No implicit binding specified...
'create URI
Dim myServiceAddress As New Uri("http://" & LocalIpAddress & ":" & tcp_port & "/" & servicename)
Dim myservicehost As New ServiceHost(GetType(plutocomm), myServiceAddress)
' Enable metadata publishing.
Dim smb As New ServiceMetadataBehavior()
smb.HttpGetEnabled = True
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15
myservicehost.Description.Behaviors.Add(smb)
myservicehost.Open()
UPDATE
An Update on this... really starting to scratch my head here..
I have now:
Changed binding to tcp
Created, installed and referenced self signed certificate
trace shows no helpfull information...
Here's my new code:
Dim myServiceAddress As New Uri("net.tcp://" & localIpAddress & ":" & tcp_port & "/" & servicename)
Dim myservicehost As New ServiceHost(GetType(plutocomm))
'create binding
Dim myNetTcpBinding = New NetTcpBinding()
myNetTcpBinding.Security.Mode = SecurityMode.Transport
myNetTcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None
' Enable metadata publishing.
Dim smb As New ServiceMetadataBehavior()
smb.HttpGetEnabled = False
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15
myservicehost.Description.Behaviors.Add(smb)
myservicehost.AddServiceEndpoint(GetType(Iplutocomm), myNetTcpBinding, myServiceAddress)
myservicehost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "louisvantonder")
myservicehost.Open()
Heres my trace with a "warning" when trying to reference it, no real info on why...?
<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent"><System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system"><EventID>262171</EventID><Type>3</Type><SubType Name="Warning">0</SubType><Level>4</Level><TimeCreated SystemTime="2013-05-28T01:16:53.0868677Z" /><Source Name="System.ServiceModel" /><Correlation ActivityID="{a696dcda-b24a-4838-9f23-cd0d67690af7}" /><Execution ProcessName="pluto" ProcessID="8472" ThreadID="3" /><Channel /><Computer>LOUISVANTONDER</Computer></System><ApplicationData><TraceData><DataItem><TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Warning"><TraceIdentifier>http://msdn.microsoft.com/en-ZA/library/System.ServiceModel.Channels.SocketConnectionAbort.aspx</TraceIdentifier><Description>SocketConnection aborted</Description><AppDomain>pluto.exe</AppDomain><Source>System.ServiceModel.Channels.SocketConnection/37489757</Source></TraceRecord></DataItem></TraceData></ApplicationData></E2ETraceEvent>
I still cant get a workable solution... here is my current code

You didn't specify a binding in your original code and you specified a protocol of http (via your address), which is why you're getting BasicHttpBinding (which is the default for http).
The following code snippet should get you going in the right direction:
Dim myServiceAddress As New Uri("net.tcp://" & LocalIpAddress & ":" & tcp_port & "/" & servicename)
Dim myservicehost As New ServiceHost(GetType(plutocomm), myServiceAddress)
Note the net.tcp protocol in the address. In theory, that should be sufficient to get you the default NetTCPBinding. If you want to explicitly define it, here's one way:
Create a NetTCP endpoint and add it to your ServiceHost:
Dim myservicehost As New ServiceHost(GetType(plutocomm))
Note that you're not creating the endpoint yet. The following code will create the endpoint for your sevice:
Dim myNetTcpBinding = New NetTcpBinding()
myNetTcpBinding.Security.Mode = SecurityMode.Transport
myNetTcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate
myservicehost.AddServiceEndpoint(typeof(plutocomm), myNetTcpBinding, myServiceAddress)
Note that SecurityMode.Transport is the default for NetTcpBinding, so you don't need to explicitly set it. If you're using certificate you'll probably need to tell the binding where to find the certificate (take a look at the MSDN Example).
This is just one of several ways you can set up the binding (you can also do it in the config file, for example).
The key here is that WCF (with version 4 and later) has default settings that will come into play unless you explicitly specify something else.

Related

HTTPS webservice using WCF

I try to connect to https web service over proxy at my end.
below is code snippet
Dim strProxyURL As String = "http://myproxy.com"
Dim mypingRequest As New pingRequest()
Dim httpUri As New Uri("https://mysite.com")
Dim mybinding As New WSHttpBinding()
Dim remoteAddress As New EndpointAddress(httpUri)
mybinding.UseDefaultWebProxy = True
mybinding.BypassProxyOnLocal = True
mybinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.Windows
mybinding.MessageEncoding = WSMessageEncoding.Mtom
mybinding.TextEncoding = System.Text.Encoding.UTF8
mybinding.Security.Mode = SecurityMode.TransportWithMessageCredential 'TransportWithMessageCredential
mybinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows
Dim myMBClient As New v1_PortTypeClient(mybinding, remoteAddress)
myMBClient.ClientCredentials.Windows.ClientCredential.UserName = "username"
myMBClient.ClientCredentials.Windows.ClientCredential.Password = "pwd"
myMBClient.ping()
when I use proxy I error proxy authentication required error
if I remove proxy from desktop and use direct internet then I go to site web service but cannot login even thought the gave correct username and password
issue is resolved. WCF web services uses Custom binding hence error. also i have add webrequest.defaultwebproxy and credentials to access via web proxy at requesting client side WCF Custom Http Proxy Authentication

How to set VB Application Proxy Settings to Default System Proxy Settings

My application is supposed to work on a Company Network where proxy is enabled,
By default when logged in all applications like browser and all can access internet normally
But when i open my application "The remote server returned an error [407] Proxy Authentication Required" error is coming
In normal internet connected PC it works well
Is there any way to set manual proxy or more preferably set the system proxy as default to the application
I am too novice in the programming field
My code is
Dim PartURL As String = "http://www.google.com"
Dim request As System.Net.HttpWebRequest = System.Net.HttpWebRequest.Create(PartURL)
Dim response As System.Net.HttpWebResponse = request.GetResponse()
Dim sr As System.IO.StreamReader = New System.IO.StreamReader(response.GetResponseStream())
Dim sourcecode As String = sr.ReadToEnd()
SearchPageSource = sourcecode
Also my proxy settings is
Address: abcserver04
Port: 8080
Ipconfig output on cmd prompt is
Ethernet adapter local area connection
Connection Specific DNS Suffix : abc.defgroup.net
IP Address : 10.4.8.xx
Subnet Mask : 255.255.255.0
Default Gateway : 10.4.8.254
Try this...
request.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials
You can also use app.config.
From https://stackoverflow.com/a/8180854/239408
<system.net>
<defaultProxy useDefaultCredentials="true" />
</system.net>

IIS Application Initialization module sending request to localhost

I have a WCF Service using MSMQ, hosted in IIS. The service doesn't fire up and read messages from the queue until the URL to the service's SVC page has been hit in a browser, which is problem after deployment and the app pool recycling. To resolve this I installed the IIS Application Initialization module which will send a fake request to a page specified in the Web.config like this:
<system.webServer>
<applicationInitialization remapManagedRequestsTo="Startup.htm" skipManagedModules="true" >
<add initializationPage="/MyService.svc" />
</applicationInitialization>
</system.webServer>
The problem I'm having is that it's hitting localhost when my site is bound to another domain, so I'm seeing this error:
WebHost failed to process a request. Sender Information:
System.ServiceModel.Activation.HostedHttpRequestAsyncResult/42715336
Exception: System.ServiceModel.ServiceActivationException: No protocol
binding matches the given address 'http://localhost/MyService.svc'.
Protocol bindings are configured at the Site level in IIS or WAS
configuration. ---> System.InvalidOperationException: No protocol
binding matches the given address 'http://localhost/MyService.svc'.
Protocol bindings are configured at the Site level in IIS or WAS
configuration.
Any ideas how I can resolve this?
I've done this with an SVN Service Connecting to an EMS Server so it should work. If it doesn't create an ASPX page that does something like the followign that can even exercise your service.
<%# Page aspcompat=true Language="VBScript" %>
Dim objSvrHTTP
Dim PostData
Dim WebName
Dim SoapAction
SoapAction = "Your Soap Action"
WebName = Request.URL.Host & ":" & Request.URL.Port
objSvrHTTP = Server.CreateObject("Msxml2.ServerXMLHTTP")
PostData = "Soap Post XML (Recoreded probably)"
objSvrHTTP.open("POST", "http://" & WebName & "/path/SVCFile.svc", false)
objSvrHTTP.setRequestHeader("Content-Type", "text/xml" )
' set SOAPAction as appropriate for the operation '
objSvrHTTP.setRequestHeader("SOAPAction", SoapAction )
objSvrHTTP.Send(cstr(PostData))
dim serviceResponse
dim ExpectedResponse
ExpectedResponse = "asdf"
serviceResponse = objSvrHTTP.responseText
if (serviceResponse <> ExpectedResponse) then
Response.Write("The Service Didn't return false and should have. it returned: " )
Response.Write(serviceResponse)
else
Response.Write("OK")
end if

.net WCF - CXF/WSS4j interoperability

I would like to consume a CXF web-service from a .net c# client. We are currently working with java-to-java requests and we protect SOAP envelopes through ws-security (WSS4J library).
My question is: how can I implement a C# WS-client which produces the same SOAP requests as the following client-side java code?
//doc is the original SOAP envelope to process with WSS4J
WSSecHeader secHeader = new WSSecHeader();
secHeader.insertSecurityHeader(doc);
//add username token with password digest
WSSecUsernameToken usrNameTok = new WSSecUsernameToken();
usrNameTok.setPasswordType(WSConstants.PASSWORD_DIGEST);
usrNameTok.setUserInfo("guest",psw_guest);
usrNameTok.prepare(doc);
usrNameTok.appendToHeader(secHeader);
//sign the envelope body with client key
WSSecSignature sign = new WSSecSignature();
sign.setUserInfo("clientx509v1", psw_clientx509v1);
sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
Document signedDoc = null;
sign.prepare(doc, sigCrypto, secHeader);
signedDoc = sign.build(doc, sigCrypto, secHeader);
//encrypt envelope body with server public key
WSSecEncrypt encrypt = new WSSecEncrypt();
encrypt.setUserInfo("serverx509v1");
// build the encrypted SOAP part
String out = null;
Document encryptedDoc = encrypt.build(signedDoc, encCrypto, secHeader);
return encryptedDoc;
Does anybody know where I could find a microsoft how-to or a .net working example?
================================ EDIT ====================================
Thank you Ladislav! I applied your suggestions and I came up with something like:
X509Certificate2 client_pk, server_cert;
client_pk = new X509Certificate2(#"C:\x509\clientKey.pem", "blablabla");
server_cert = new X509Certificate2(#"C:\x509\server-cert.pfx", "blablabla");
// Create the binding.
System.ServiceModel.WSHttpBinding myBinding = new WSHttpBinding();
myBinding.TextEncoding = ASCIIEncoding.UTF8;
myBinding.MessageEncoding = WSMessageEncoding.Text;
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
myBinding.Security.Message.AlgorithmSuite =
System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128;
// Disable credential negotiation and the establishment of
// a security context.
myBinding.Security.Message.NegotiateServiceCredential = false;
myBinding.Security.Message.EstablishSecurityContext = false;
// Create the endpoint address.
EndpointAddress ea =
new EndpointAddress(new Uri("http://bla.bla.bla"),
EndpointIdentity.CreateDnsIdentity("issuer"));
// configure the username credentials on the channel factory
UsernameClientCredentials credentials = new UsernameClientCredentials(new
UsernameInfo("superadmin", "secret"));
// Create the client.
PersistenceClient client = new PersistenceClient(myBinding, ea);
client.Endpoint.Contract.ProtectionLevel =
System.Net.Security.ProtectionLevel.EncryptAndSign;
// replace ClientCredentials with UsernameClientCredentials
client.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
client.Endpoint.Behaviors.Add(credentials);
// Specify a certificate to use for authenticating the client.
client.ClientCredentials.ClientCertificate.Certificate = client_pk;
// Specify a default certificate for the service.
client.ClientCredentials.ServiceCertificate.DefaultCertificate = server_cert;
// Begin using the client.
client.Open();
clientProxyNetwork[] response = client.GetAllNetwork();
As a result I get (server-side) the following CXF exception:
java.security.SignatureException: Signature does not match.
at sun.security.x509.X509CertImpl.verify(X509CertImpl.java:421)
at sun.security.provider.certpath.BasicChecker.verifySignature(BasicChecker.java:133)
at sun.security.provider.certpath.BasicChecker.check(BasicChecker.java:112)
at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate (PKIXMasterCertPathValidator.java:117)
Therefore it seems a key jks->pem conversion problem... Or am I am missing something in the client-code above?
Well, in the end the solution is to encrypt and sign the whole username token. As for the interoperability, the ws addressing must be activated in cxf and a custom binding in c# is needed. The custom binding that did the trick is basically
AsymmetricSecurityBindingElement abe =
(AsymmetricSecurityBindingElement)SecurityBindingElement.
CreateMutualCertificateBindingElement(MessageSecurityVersion.
WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
           
Wcf signs each ws addressing element, therefore the same must be done server side.
This is usually pretty big problem because WCF does not support UserNameToken Profile with Digested password. I needed it few months ago and we had to implement our own custom binding but that code is not ready for publishing. Fortunatelly this blog article describes other implementation and contains sample code with new UserNameClientCredentials class supporting digested password.
Btw. same security configuration should be possible with older API called WSE 3.0. It was replaced by WCF but still some WS-* stack configuration are much simpler with that API and old ASMX services.

WCF, REST, SSL, Client, custom certificate validation

I have a specific problem that I can't solve. Let me explain in detail. I'm new to this technology so I might be using some wrong terms. Please correct and explain or ask for explanation if you don't understand.
I am creating a self hosted WCF REST server, hosted in WPF application. It uses https, SLL with WebHttpSecurityMode.Transport. I am using my own generated certificate.
I would like to create a WinForms client that would use this service. The format of the response form the server is JSON.
I would like to validate the certificate on the client with my custom validator inherited from X509CertificateValidator.
This is my server side code. I'm using a custom username validator that works fine. I have configured the certificate in the IIS Manager on my machine for the Default Website > Bindings, where I have generated the certificate (Windows 7).
WebServiceHost sh = new WebServiceHost(typeof(ReachService));
string uri = "https://localhost:9000/Service";
WebHttpBinding wb = new WebHttpBinding();
wb.Security.Mode = WebHttpSecurityMode.Transport;
wb.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
sh.AddServiceEndpoint(typeof(IReachService), wb, uri);
sh.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNameValidator();
sh.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
sh.Open();
and this is my client code
Uri uri = new Uri("https://localhost:9000/Service");
WebChannelFactory<ReachService> cf = new WebChannelFactory<IReachService>(uri);
WebHttpBinding wb = cf.Endpoint.Binding as WebHttpBinding;
wb.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
wb.Security.Mode = WebHttpSecurityMode.Transport;
cf.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
cf.Credentials.ServiceCertificate.Authentication.CustomCertificateValidator = new CustomCertificateValidator("PL2"); // this is the name that issued the certificate
cf.Credentials.UserName.UserName = "user1";
cf.Credentials.UserName.Password = "user1";
IReachService service = cf.CreateChannel();
try
{
CustomersList auth = service.GetCustomers();
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
on calling service.GetCustomers() I get:
Could not establish trust relationship for the SSL/TLS secure channel with authority
'localhost:9000'.
InnerException Message:
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
InnerException Message:
The remote certificate is invalid according to the validation procedure.
The server is working fine when I test in the browser.
But the client code is wrong cause it doesn't go to the custom cert validator class. And this class is the same as in the MSDN example on http://msdn.microsoft.com/en-us/library/system.identitymodel.selectors.x509certificatevalidator.aspx.
Can anyone please tell me where am I going wrong with this approach?
If you need more info please ask.
Thank you
It looks like the issue occurs because certificate was issued for some other hostname. You can check this (and customize if necessary) by providing custom ServicePointManager.ServerCertificateValidationCallback.
//don't use HttpWebRequest --you lose all of the strongly-typed method and data contracts!
//the code to create the channel and call a method:
SetCertPolicy();
var cf1 = new WebChannelFactory<TService>(new Uri(remoteServiceAddressSecure));
var service = cf1.CreateChannel();
sevice.DoMethod();
protected static void SetCertPolicy()
{
ServicePointManager.ServerCertificateValidationCallback += RemoteCertValidate;
}
private static bool RemoteCertValidate(object sender, X509Certificate cert, X509Chain chain,
SslPolicyErrors error)
{
// trust any cert!!!
return true;
}
If you want to use WCF on the client, then don't use WebHttpBinding, stick with the SOAP stuff it will work much better.
However, if you want to use a standard HTTP client like, WebClient or HttpWebRequest or HttpClient V.prototype or HttpClient V.Next then stick with the webHttpBinding.
Sorry for not addressing your direct question but you are likely to run into more problems because you are using a binding that was intended to make WCF services accessible to non-WCF platforms but then using WCF to try and access it.