I trying to do WCF using self-signed certificate. I found some solutions,but they need client to know clinet certificate before connection.
I would like make client works as browser(When browser use web server certificate).
I mean browser don't know webserver's certificate before connection, it can obtain it from web server.
My server's web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" />
<services>
<service behaviorConfiguration="security" name="WebApplicationExchange.UKService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="security" contract="WebApplicationExchange.IUKService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="https://localhost/UKService/UKService.svc" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="security">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="ServiceAuthorization.PasswordValidator,ServiceAuthorization" />
<windowsAuthentication allowAnonymousLogons="false" />
</serviceCredentials>
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="ServiceAuthorization.AuthorizationPolicy,ServiceAuthorization" />
</authorizationPolicies>
</serviceAuthorization>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="security">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Basic" />
</security>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
It works fine with web browsers.
But client show error:
Could not establish trust connection for secure channel SSL / TLS with authority "localhost: 56389".
Client code:
System.ServiceModel.EndpointAddress eaSecurity = new System.ServiceModel.EndpointAddress("https://localhost:56389/UKService.svc");
var binding = new System.ServiceModel.BasicHttpBinding();
binding.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.TransportWithMessageCredential;
binding.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType = System.ServiceModel.BasicHttpMessageCredentialType.UserName;
var securityFactory = new System.ServiceModel.ChannelFactory<ServiceReference1.IUKService>(binding, eaSecurity);
securityFactory.Credentials.UserName.UserName = "test";
securityFactory.Credentials.UserName.Password = "test";
myService = securityFactory.CreateChannel();
Any ideas how to solve this?
UPDATE:
I look deeper in error stack and find following:
System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the results of authentication.
I tryed this code:
ClientCredentials cc = securityFactory.Endpoint.Behaviors.Find<ClientCredentials>();
cc.UserName.UserName = "test";
cc.UserName.Password = "test";
cc.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
But it doesn't help.
I solve it this way:
System.Net.ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(RemoteCertValidateCallback);
public static bool RemoteCertValidateCallback(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)
{
return true;
}
The problem is that your certificate is not trusted by the client. This has nothing to do with client certificates or downloading the certificate from the browser.
In order for the server certificate to be accepted by te client, you need to either:
Buy a certificate from a trusted certificate authority
Add the certificate (or its root) to the client machine's certificate store or
Disable certificate validation.
Related
After I moved WCF service and ASP.NET Core website to server I get following error:
The HTTP request is unauthorized with client authentication scheme 'Ntlm'. The authentication header received from the server was 'Negotiate, NTLM'.
I have enabled only Windows Authentication on WCF service with following web.config:
<system.serviceModel>
<client />
<behaviors>
<serviceBehaviors>
<behavior name="authBehavior">
<serviceAuthorization principalPermissionMode="UseWindowsGroups">
<authorizationPolicies>
<add policyType="WCF.AuthorizationPolicy, WCF" />
</authorizationPolicies>
</serviceAuthorization>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WCF.IdentityValidator, WCF" />
<serviceCertificate findValue="16E86CCAFFE6211DAE6E841B984F71FB7609D349" storeLocation="LocalMachine" x509FindType="FindBySerialNumber" storeName="My" />
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpsBinding>
<binding name="basicHttpsEndpointBinding" maxReceivedMessageSize="1073741824" maxBufferSize="1073741824" maxBufferPoolSize="1073741824">
<readerQuotas maxDepth="32" maxArrayLength="1073741824" maxStringContentLength="1073741824" />
<security mode="Transport">
<transport clientCredentialType="Ntlm" />
</security>
</binding>
</basicHttpsBinding>
</bindings>
<services>
<service name="WCF.MyService" behaviorConfiguration="authBehavior">
<endpoint address="" binding="basicHttpsBinding" bindingConfiguration="basicHttpsEndpointBinding" contract="WCF.IMyService">
<identity>
<dns value="example.com" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
ASP.NET Core client:
BasicHttpsBinding binding = new BasicHttpsBinding
{
MaxBufferPoolSize = 1073741824,
MaxBufferSize = 1073741824,
MaxReceivedMessageSize = 1073741824
};
binding.ReaderQuotas.MaxDepth = 32;
binding.ReaderQuotas.MaxArrayLength = 1073741824;
binding.ReaderQuotas.MaxStringContentLength = 1073741824;
binding.Security.Mode = BasicHttpsSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
MyServiceClient client = new MyServiceClient(binding, new EndpointAddress(new Uri("https://example.com/MyService.svc"), new DnsEndpointIdentity("mydomain.com")));
client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
client.ClientCredentials.Windows.ClientCredential.Domain = Configuration.GetSection("WCF")["MyServiceDomain"];
client.ClientCredentials.Windows.ClientCredential.UserName = Configuration.GetSection("WCF")["MyServiceUserName"];
client.ClientCredentials.Windows.ClientCredential.Password = Configuration.GetSection("WCF")["MyServicePassword"];
// client call
I run out of ideas what could be wrong. If I change Ntlm to Windows in config/code then I get error with client authentication scheme 'Negotiate'. Can I somehow use both or I have to remove somehow Negotiate/Ntlm from IIS?
Thanks for any idea!
SOLUTION!
Method 1 from article https://blogs.msdn.microsoft.com/distributedservices/2009/11/10/wcf-calling-wcf-service-hosted-in-iis-on-the-same-machine-as-client-throws-authentication-error/
Requires server reboot!
I found this article which offers solution for my issue
Article: https://blogs.msdn.microsoft.com/distributedservices/2009/11/10/wcf-calling-wcf-service-hosted-in-iis-on-the-same-machine-as-client-throws-authentication-error/
Use method 1. Requires server reboot!
In registry I used CNAME like
mySubdomain
mySubdomain.myDomain.com
localhost
192.168.0.xxx
192.168.0.1 (default gateway)
xx.xx.xx.xx (my ip address)
Server's App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true"/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="NewBehaviour">
<serviceMetadata httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="Binding">
<security mode="Transport">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="Server.InternalClass" behaviorConfiguration="NewBehaviour">
<endpoint address="IInternal" binding="wsHttpBinding" bindingConfiguration="Binding" contract="Common.IInternal">
<identity>
<dns value="MyMachine"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="https://MyMachine:8733/"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
Client
static ChannelFactory<IInternal> factory = new ChannelFactory<IInternal>(new WSHttpBinding(), new EndpointAddress("https://MyMachine:8733/IInternal"));
When i call the method factory.CreateChannel(), i get error
I configure certificate
You have to tell the client to use a secure transport channel so that it uses https instead of http. This is true because the binding settings at the client must match the ones at the service side.
You can do this via configuration in the app.config file of the client, or you can do it via code like this:
var ws_http_binding = new WSHttpBinding();
ws_http_binding.Security.Mode = SecurityMode.Transport;
ChannelFactory<IInternal> factory =
new ChannelFactory<IInternal>(
ws_http_binding,
new EndpointAddress("https://MyMachine:8733/IInternal"));
var channel = factory.CreateChannel();
Is it possible to call a WCF service from a universal application?
I added a service reference and the proxy was generated just fine.
But when creating a NetTcpBinding programmatically and passing that to the proxy's constructor the service model throws the exception PlatformNotSupported.
Both running the app in the simulator and on the local machine generates the same exception.
An exception of type 'System.PlatformNotSupportedException' occurred
in System.Private.ServiceModel.dll but was not handled in user code
"this operation is not supported"
EndpointAddress address = new EndpointAddress("net.tcp://test:9000/ServicesHost/PublishService");
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.None;
PublishingService.PublishClient proxy = new PublishingService.PublishClient(binding, address);
Does anybody have an example of a working WCF client in a UAP?
EDIT
It has something to do with the service being a duplex service!
The original contract:
[ServiceContract(CallbackContract = typeof(IPublishCallback))]
public interface IPublish { }
After removing the CallbackContract attribute the UAP client can create a connection, so basic WCF works.
So I guess it's better to rephrase the question.
Is it possible to create a duplex WCF client in a universal application?
edit servicemodel for the host
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="netTcpPublishService" openTimeout="00:00:10" receiveTimeout="infinite">
<reliableSession inactivityTimeout="24.20:31:23.6470000" enabled="true" />
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehaviour">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="serviceBehaviour" name="PublishService.Publish">
<endpoint binding="mexHttpBinding" name="mexPublishService"
contract="IMetadataExchange" />
<endpoint address="PublishService" binding="netTcpBinding" bindingConfiguration="netTcpPublishService"
name="netTcpPublishService" contract="PublishService.IPublish" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8004/ServicesHost/PublishService" />
<add baseAddress="net.tcp://localhost:9004/ServicesHost/PublishService" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
Yes, it is possible. This is how i connect in a sample app i did a while ago:
using Tradeng.Srvc.Client.WinAppSimple.SrvcRefTradeng;
private InstanceContext instanceContext;
private TradengSrvcClientBase serviceProxy;
instanceContext = new InstanceContext(this);
serviceProxy = new TradengSrvcClientBase(instanceContext);
bool result = await serviceProxy.ConnectAsync();
if (result)
{
// connected...
}
I used the binding from the config file that is generated when you add a reference to your service.
This is what the app looks like. Cutting edge stuff.... :O)
https://www.youtube.com/watch?v=YSg6hZn1DpE
The service itself is running as a WebRole on Azure, by the way.
I create a certificate with Pluralsight Selfcert. when I use it in wcf service it takes an SecurityNegotiation Exception. I search it and found a solution. I put certificateValidationMode="None" in clientCertificate of Web.config but problem not solved. but if I put this command on client app.config problem solve. but I I don't want to change my client configs. why this command doesn't work in server side? is there any other way?
The X.509 certificate CN=QtasCert chain building failed. The
certificate that was used has a trust chain that cannot be verified.
Replace the certificate or change the certificateValidationMode. A
certificate chain processed, but terminated in a root certificate
which is not trusted by the trust provider.
<services>
<service name="ArchiveBoundedContext.WcfService.WcfServices.ArchiveWcfService">
<endpoint address="" binding="netTcpBinding" bindingConfiguration="QTasBinding" name="QTasEndpoint" contract="ArchiveBoundedContext.WcfService.WcfServices.IArchiveWcfService" />
<endpoint address="mex" binding="mexTcpBinding" name="QTasMex" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:808/WcfServices/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceSecurityAudit auditLogLocation="Application" serviceAuthorizationAuditLevel="SuccessOrFailure" messageAuthenticationAuditLevel="SuccessOrFailure" suppressAuditFailure="true" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="ArchiveBoundedContext.WcfService.ServiceAuthenticator, ArchiveBoundedContext.WcfService" />
<serviceCertificate findValue="QtasCert" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
<clientCertificate>
<authentication certificateValidationMode="None" revocationMode="NoCheck" />
</clientCertificate>
</serviceCredentials>
<serviceAuthorization principalPermissionMode="UseAspNetRoles" />
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
I install certificate in client and the problem solved.
class Program
{
static void Main(string[] args)
{
Console.WriteLine(#"Certificate Installer v1.0");
var certificate = new X509Certificate2(Certificates.QTasCert, "*****");
var rootStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
rootStore.Open(OpenFlags.ReadWrite);
rootStore.Add(certificate);
rootStore.Close();
var myStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
myStore.Open(OpenFlags.ReadWrite);
myStore.Add(certificate);
myStore.Close();
Console.WriteLine(#"Certificate Installed Successfuly");
Console.ReadKey();
}
}
I have a Wcf Service project. system.serviceModel tag in my web.config is :
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="RCISPNetTcpBinding" openTimeout="00:10:00" sendTimeout="00:10:00">
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign">
</transport>
<message clientCredentialType="Windows"/>
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service behaviorConfiguration="RCISP.WcfServiceBehaviour" name="RCISP.WcfService.PersonWcfService">
<endpoint address="PersonServices" binding="netTcpBinding" bindingConfiguration="RCISPNetTcpBinding"
contract="RCISP.Common.ServiceContract.IPersonService" >
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:40003/"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="RCISP.WcfServiceBehaviour">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceAuthorization principalPermissionMode="UseWindowsGroups" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
I have a runtime error when I want create self-hosting for service.
public class ServiceFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
if (!IsInitialised) InitialiseService();
return base.CreateServiceHost(serviceType, baseAddresses);
}
}
Message of Exception is :
Could not find a base address that matches scheme net.tcp for the endpoint with binding NetTcpBinding. Registered base address schemes are [http].
Why?
You said you were self hosting the service (within your own process) but based on the code above I think you're trying to host it inside of a web application. If so Visual Studio's web server can not host a net.tcp end point. You'll need to set the project up to run under IIS. Please follow the instructions here .
If you are truly self hosting than you can leave the configuration exactly how you have it and spin up the service using the following code:
var host = new ServiceHost(typeof(Service1));
host.Open();
You need to add a protocol mapping to your configuration file to tell it what the "net.tcp" protocol is. Right after your <bindings> section add this:
<protocolMapping>
<add scheme="net.tcp" binding="netTcpbinding"/>
</protocolMapping>