Note that there are some explanatory texts on larger screens.

plurals
  1. POWCF message authentication with both username and certificate
    primarykey
    data
    text
    <p><strong>Long story short:</strong></p> <p>My WCF clients should be able to provide both username and certificate to a service hosted in IIS, where I should use that information to validate requests using a custom policies.</p> <p><strong>Complete story:</strong></p> <p>I have the need to authenticate some WCF clients to verify if they can execute operations.</p> <p>We have two kinds of clients: WPF applications and a web application. We would like to do the following:</p> <ul> <li>The web application uses a certificate trusted by the service so that it is recognized as a special user with all permissions (the web application already verifies permissions by itself and we wouldn't like to touch it by now)</li> <li>The WPF clients authenticate themselves with username/password provided by the user</li> </ul> <p>In the implementation of the operations, I would like to verify if the certificate was provided (then I recognize the "super user"), otherwise fallback to username/password authentication.</p> <p>Services are hosted in IIS 7 and we need to use NetTcpBinding. I was able to implement the username validation, but the problem is that the AuthorizationContext inspected by the service contains only identity information, and not the certificate. The following code is used on the client side to initialize the creation of channels (from a spike I'm using to test the solution):</p> <pre><code>var factory = new ChannelFactory&lt;T&gt;(this.Binding, address); var defaultCredentials = factory.Endpoint.Behaviors.Find&lt;ClientCredentials&gt;(); factory.Endpoint.Behaviors.Remove(defaultCredentials); var loginCredentials = new ClientCredentials(); loginCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None; loginCredentials.UserName.UserName = username; loginCredentials.UserName.Password = password; if (useCertificate) { loginCredentials.SetCertificate(); } factory.Endpoint.Behaviors.Add(loginCredentials); return factory.CreateChannel(); </code></pre> <p>With the SetCertificate extension being implemented like this:</p> <pre><code>public static void SetCertificate(this ClientCredentials loginCredentials) { loginCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "SecureWcfClient"); } </code></pre> <p>This is the configuration of the web application hosting the services:</p> <pre><code>&lt;system.serviceModel&gt; &lt;behaviors&gt; &lt;serviceBehaviors&gt; &lt;behavior name="SecureBehavior"&gt; &lt;serviceMetadata httpGetEnabled="true" /&gt; &lt;serviceDebug includeExceptionDetailInFaults="true" /&gt; &lt;serviceCredentials&gt; &lt;serviceCertificate findValue="Test" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" /&gt; &lt;clientCertificate&gt; &lt;authentication certificateValidationMode="Custom" customCertificateValidatorType="AuthenticationProtectedService.Security.CertificateValidator, AuthenticationProtectedService.Security"/&gt; &lt;/clientCertificate&gt; &lt;userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="AuthenticationProtectedService.Security.UserNamePassValidator, AuthenticationProtectedService.Security" /&gt; &lt;/serviceCredentials&gt; &lt;serviceAuthorization serviceAuthorizationManagerType="AuthenticationProtectedService.Security.CertificateAuthorizationManager, AuthenticationProtectedService.Security"/&gt; &lt;/behavior&gt; &lt;/serviceBehaviors&gt; &lt;/behaviors&gt; &lt;bindings&gt; &lt;netTcpBinding&gt; &lt;binding&gt; &lt;security mode="None"/&gt; &lt;/binding&gt; &lt;binding name="SecureNetTcp"&gt; &lt;security mode="Message"&gt; &lt;message clientCredentialType="UserName"/&gt; &lt;/security&gt; &lt;/binding&gt; &lt;/netTcpBinding&gt; &lt;/bindings&gt; &lt;service name="AuthenticationProtectedService.Services.OneWayServiceB" behaviorConfiguration="SecureBehavior"&gt; &lt;endpoint address="" binding="wsHttpBinding" contract="AuthenticationProtectedService.ServiceModel.IOneWayServiceB"&gt; &lt;/endpoint&gt; &lt;/service&gt; &lt;service name="AuthenticationProtectedService.Services.DuplexServiceB" behaviorConfiguration="SecureBehavior"&gt; &lt;endpoint address="" binding="netTcpBinding" bindingConfiguration="SecureNetTcp" contract="AuthenticationProtectedService.ServiceModel.IDuplexServiceB"&gt; &lt;/endpoint&gt; &lt;endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/&gt; &lt;/service&gt; &lt;/services&gt; &lt;serviceHostingEnvironment multipleSiteBindingsEnabled="true" /&gt; </code></pre> <p></p> <p>Finally, this is the implementation of the custom authorization manager (I also tried with a custom certificate validator but the function was never run)</p> <pre><code>public class CertificateAuthorizationManager : ServiceAuthorizationManager { protected override bool CheckAccessCore(OperationContext operationContext) { if (!base.CheckAccessCore(operationContext)) { return false; } string thumbprint = GetCertificateThumbprint(operationContext); // I'd need to verify the thumbprint, but it is always null return true; } private string GetCertificateThumbprint(OperationContext operationContext) { foreach (var claimSet in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets) { foreach (Claim claim in claimSet.FindClaims(ClaimTypes.Thumbprint, Rights.Identity)) { string tb = BitConverter.ToString((byte[])claim.Resource); tb = tb.Replace("-", ""); return tb; } } return null; } } </code></pre> <p>I think that the problem could be in the clientCredentialType property of the nettcpbinding.Security.Message node on the service configuration, but I don't see the option to use both Certificate and Username withing the Message security.</p> <p>Any help appreciated, thanks</p> <p>Remark: a specific goal of the project is to have very low level impact on server setup and in general in the system, so also SSL should be avoided if possible.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload