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();
}
}
Related
I am attempting to secure a new .Net 4.5 WCF service using HTTPS / SSL, Basic client credentials and the WebHttpBinding. From reading up online I found a good series of Blog Posts from Allen Conway which I have used as a template.
WCF configuration
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webInteropSecureBinding" allowCookies="false" maxBufferPoolSize="2097152" maxBufferSize="2097152" maxReceivedMessageSize="2097152">
<security mode="Transport">
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="PsmDataProvider.PsmProvider" behaviorConfiguration="SecureRest">
<clear />
<endpoint address="" binding="webHttpBinding" bindingConfiguration="webInteropSecureBinding" name="PsmProvider" contract="PsmDataProvider.IPsmProvider" behaviorConfiguration="webHttpBehavior" />
<endpoint address="mex" binding="mexHttpsBinding" name="mex" contract="IMetadataExchange" listenUriMode="Explicit" />
<host>
<baseAddresses>
<add baseAddress="https://localhost:44300/PsmProvider/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="SecureRest">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="PsmDataProvider.Security.CustomerUserNamePasswordValidator, PsmDataProvider"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webHttpBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
CustomerUserNamePasswordValidator
I have stubbed out the CustomerUserNamePasswordValidator implementation and have confirmed that the constructor is called before the exception is raised.
using System;
using System.IdentityModel.Selectors;
namespace PsmDataProvider.Security
{
internal class CustomerUserNamePasswordValidator : UserNamePasswordValidator, ICustomerUserNamePasswordValidator
{
public CustomerUserNamePasswordValidator()
{
}
public override void Validate(string userName, string password)
{
if (userName == null) throw new ArgumentNullException("userName","The username must be provided in the request to access this service");
if (password == null) throw new ArgumentNullException("password", "The password must be provided in the request to access this service");
}
}
}
When I try to run the code in VS2012 through IIS Express the service fails to start with the below error.
If I remove the clientCredentialType from the configuration then it works but I require the additional security of using the username / password validation on the service and possibly at a method level in the future.
Is this something I have configured incorrectly in the WCF config or a problem with the configuration in IISExpress?
Please help...
The issue appears to be when using Basic Authentication when hosting the service in IIS as IIS wants to handle the authentication.
This is discussed in this MSDN blog post
In the version of WCF that shipped with .Net Framework 3.0 we didn't
support custom validators with transport level HTTP security. We
received much feedback from the community that this was a highly
desired feature, so I'm happy to say we added support for this
scenario in the 3.5 release of the .Net Framework. Note that this is
only supported under self hosted services.
There is a resolution as discussed in Allen Conway's Blog Post by implementing a custom authorisation manager derived from ServiceAuthorizationManager
CustomAuthorizationManager
public class CustomAuthorizationManager : ServiceAuthorizationManager
{
private const string UserName = "username";
private const string Password = "password";
protected override bool CheckAccessCore(OperationContext operationContext)
{
string authHeader = WebOperationContext.Current.IncomingRequest.Headers["Authorization"];
if ((authHeader != null) && (authHeader != string.Empty))
{
string[] svcCredentials = System.Text.ASCIIEncoding.ASCII
.GetString(Convert.FromBase64String(authHeader.Substring(6)))
.Split(':');
var user = new { Name = svcCredentials[0], Password = svcCredentials[1] };
if ((user.Name.Equals(UserName) && user.Password.Equals(Password)))
return true;
else
return false;
}
else
{
WebOperationContext.Current.OutgoingResponse.Headers.Add("WWW-Authenticate: Basic realm=\"PsmProvider\"");
throw new WebFaultException(HttpStatusCode.Unauthorized);
}
}
}
Config
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webInteropSecureBinding" allowCookies="false" maxBufferPoolSize="51200" maxBufferSize="51200" maxReceivedMessageSize="51200">
<security mode="Transport"/>
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="PsmDataProvider.PsmProvider" behaviorConfiguration="SecureRest">
<clear />
<endpoint binding="webHttpBinding" bindingConfiguration="webInteropSecureBinding"
name="PsmProvider" contract="PsmDataProvider.IPsmProvider" behaviorConfiguration="webHttpBehavior" />
<endpoint address="mex" binding="mexHttpsBinding" name="mex" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="https://localhost:44300/PsmProvider/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="SecureRest">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceAuthorization serviceAuthorizationManagerType="PsmDataProvider.Security.CustomAuthorizationManager, PsmDataProvider"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webHttpBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Note
Also note a comment from Travich regarding the IIS / IIS Express configuration
Travich said... One thing to help other users. It was briefly stated,
but something I overlooked... Turn off Basic Auth in IIS and remove
tag from your webHttpBinding!
Works for me.
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.
Hello and thank you for reading.
I'm trying to get a service hosted in IIS 7.5, that has multiple endpoints exposed.
I have a feeling the problem lies within my web.config, but I'll post my service code in here. There's no interface file, as I'm using the newer features of WCF 4, there's also no .svc file.
All the routing, from my understanding is handled in Global.asax.cs using the RouteTable feature.
Regardless, onto the code / config -
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
// NOTE: If the service is renamed, remember to update the global.asax.cs file
public class Service1
{
// TODO: Implement the collection resource that will contain the SampleItem instances
[WebGet(UriTemplate = "HelloWorld")]
public string HelloWorld()
{
// TODO: Replace the current implementation to return a collection of SampleItem instances
return "Hello World!";
}
}
And now, the config with the changes I thought would need to be made (I'm not sure if I needed to keep the standardEndpoints block, but with or without it I'm still getting error messages. -
<services>
<service name="AiSynthDocSvc.Service1" behaviorConfiguration="HttpGetMetadata">
<endpoint name="rest"
address=""
binding="webHttpBinding"
contract="AiSynthDocSvc.Service1"
behaviorConfiguration="REST" />
<endpoint name="soap"
address="soap"
binding="basicHttpBinding"
contract="AiSynthDocSvc.Service1" />
<endpoint name="mex"
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="REST">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="HttpGetMetadata">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<standardEndpoints>
<webHttpEndpoint>
<!--
Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
via the attributes on the <standardEndpoint> element below
-->
<standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
</webHttpEndpoint>
</standardEndpoints>
The Global.asax.cs file was left alone.
Again I'm pretty sure it has something to do with my config. The error I'm getting when I try to access any of the endpoints defined is -
The endpoint at '' does not have a Binding with the None MessageVersion. 'System.ServiceModel.Description.WebHttpBehavior' is only intended for use with WebHttpBinding or similar bindings.
Anyone have any ideas on this one?
Thanks,
Zachary Carter
OK, I tried to replicate your stuff - works like a charm for me :-)
I used your service class - no changes
I used your RegisterRoutes call in global.asax.cs
When I launch the web app from within Visual Studio, I get Cassini (the built-in web server) come up on http://localhost:3131/ - this might wary in your case.
Now, I can easily navigate there with a second browser window, and I do get a simple response on this URL:
http://localhost:3131/Service1/HelloWorld
+--------------------+
from Cassini
+--------+
name (first param) in ServiceRoute registration
+-----------+
from your URI template on the WebGet attribute
Does the same URL work for you??
Update: here's my config - I can connect to http://localhost:3131/Service1/HelloWorld in the browser using REST, and I can connect to http://localhost:3131/Service1/soap with the WCF Test Client to make a SOAP call (my Service1 lives in the RestWebApp namespace - thus my service and contract names are a tad different than yours - but other than that, I believe it's identical to your own config):
<system.serviceModel>
<serviceHostingEnvironment
aspNetCompatibilityEnabled="true" />
<services>
<service name="RestWebApp.Service1" behaviorConfiguration="Meta">
<endpoint name="rest"
address=""
binding="webHttpBinding"
contract="RestWebApp.Service1"
behaviorConfiguration="REST" />
<endpoint name="SOAP"
address="soap"
binding="basicHttpBinding"
contract="RestWebApp.Service1" />
<endpoint name="mex"
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="REST">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="Meta">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<standardEndpoints>
<webHttpEndpoint>
<!--
Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
via the attributes on the <standardEndpoint> element below
-->
<standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
Thanks for this it helped me a lot.
The issue in my case was that I had a default behaviour configured that contains webHttp. After giving it the name="REST" and setting my webHttpBinding endpoint behaviourConfiguration ="REST" I had no further errors.
<system.serviceModel>
<bindings>
<customBinding>
<binding name="CustomBinding_IMobileService">
<binaryMessageEncoding />
<httpTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://localhost:6862/silverlight/services/MobileService.svc"
binding="customBinding" bindingConfiguration="CustomBinding_IMobileService"
contract="AlchemyMobileService.IMobileService" name="CustomBinding_IMobileService" />
</client>
<services>
<service name="MobileService.Alchemy">
<endpoint address="http://localhost:8732/mobileservice" binding="webHttpBinding" contract="MobileService.IAlchemy" behaviorConfiguration="REST">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="REST">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
I am getting the following error when trying to use the WCF Test Client to hit my new web service. What is weird is every once in awhile it will execute once then start popping this error.
Failed to invoke the service. Possible causes: The service is offline or inaccessible; the client-side configuration does not match the proxy; the existing proxy is invalid. Refer to the stack trace for more detail. You can try to recover by starting a new proxy, restoring to default configuration, or refreshing the service.
My code (interface):
[ServiceContract(Namespace = "http://rivworks.com/Services/2010/04/19")]
public interface ISync
{
[OperationContract]
bool Execute(long ClientID);
}
My code (class):
public class Sync : ISync
{
#region ISync Members
bool ISync.Execute(long ClientID)
{
return model.Product(ClientID);
}
#endregion
}
My config (EDIT - posted entire serviceModel section):
<system.serviceModel>
<diagnostics performanceCounters="Default">
<messageLogging logMalformedMessages="true" logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true" />
</diagnostics>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" />
<behaviors>
<endpointBehaviors>
<behavior name="JsonpServiceBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="SimpleServiceBehavior">
<serviceMetadata httpGetEnabled="True" policyVersion="Policy15"/>
</behavior>
<behavior name="RivWorks.Web.Service.ServiceBehavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="RivWorks.Web.Service.NegotiateService" behaviorConfiguration="SimpleServiceBehavior">
<endpoint address=""
binding="customBinding"
bindingConfiguration="jsonpBinding"
behaviorConfiguration="JsonpServiceBehavior"
contract="RivWorks.Web.Service.NegotiateService" />
<!--<host>
<baseAddresses>
<add baseAddress="http://kab.rivworks.com/services"/>
</baseAddresses>
</host>
<endpoint address=""
binding="wsHttpBinding"
contract="RivWorks.Web.Service.NegotiateService" />-->
<endpoint address="mex"
binding="mexHttpBinding"
contract="RivWorks.Web.Service.NegotiateService" />
</service>
<service name="RivWorks.Web.Service.Sync" behaviorConfiguration="RivWorks.Web.Service.ServiceBehavior">
<endpoint address="" binding="wsHttpBinding" contract="RivWorks.Web.Service.ISync" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<extensions>
<bindingElementExtensions>
<add name="jsonpMessageEncoding" type="RivWorks.Web.Service.JSONPBindingExtension, RivWorks.Web.Service, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bindingElementExtensions>
</extensions>
<bindings>
<customBinding>
<binding name="jsonpBinding" >
<jsonpMessageEncoding />
<httpTransport manualAddressing="true"/>
</binding>
</customBinding>
</bindings>
</system.serviceModel>
2 questions:
What am I missing that causes this error?
How can I increase the time out for the service?
TIA!
Found the problem(s)...
Had an error inside the web service that was not handled.
The test app does not do an ABORT when it sees an error. Instead, it is left unhandled (and unreported) AND the channel is now locked because of the error.
Putting a try/catch around the inside method makes it so I can log the error and the test app does not lock up.
I have a RESTful Web Service hosted in IIS 6.0, I am able to Browse the Service in browser. When i am trying to access the same service via Client console App, it is giving me the following error:
"provided URI scheme'http' is invalid; expected 'https', Parameter name: Via"
My WebService web.config has this settings:
<system.serviceModel>
<services>
<service behaviorConfiguration="ServiceBehavior" name="TestAPI">
<endpoint address="" behaviorConfiguration="RESTFriendly" binding="webHttpBinding" contract="ITestAPI" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="RESTFriendly">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
My Client App has App.config from where i am getting the address :
<appSettings>
<add key="WEBSERVICE" value="URL"/>
in the Main method :
WebChannelFactory<ITestAPI> cf = new WebChannelFactory<IAPI>(baseAddress);
WebHttpBinding wb =cf.Endpoint.Binding as WebHttpBinding;
wb.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
wb.Security.Mode = WebHttpSecurityMode.Transport;
cf.Credentials.UserName.UserName = "usermane";
cf.Credentials.UserName.Password = "password";
ITestAPI channel = cf.CreateChannel();
string msg = channel.TestMethod();
When it tries to call TestMethod, it gives me this error.
You're setting the security to transport mode, which is HTTPS, with this line:
wb.Security.Mode = WebHttpSecurityMode.Transport;
Is the value of baseAddress an HTTP or HTTPS address?