M
Meghali
Guest
Recently I worked on a scenario where we had to set up client cert authentication for WCF service hosted as an App service in Azure: We followed the below steps to achieve the same and was able to parse the client certificate in service end using custom certificate validator:
Here I have highlighted in detail the steps of how to create and publish a WCF Service with Client Certificate enabled in Azure Web App.
Create an Azure Web App:
===========================
Deploying the WCF service to the Web App:
======================================
We will be able to publish the created WCF Service or any other type of application directly into the created Web APP.
IService1.cs:
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
Service1.cs:
public class Service1 : IService1
{
public static string str { get; set; }
public string GetData(int value)
{
return string.Format(str+ value);
} }
Note: I have defined the client certificate validator in the service end as a custom validator so that I can verify if the client certificate is fetched in service end and parse the client certificate details. You can ignore step 5 if you are not using custom validator.
using System;
using System.IdentityModel.Selectors;
using System.Security.Cryptography.X509Certificates;
namespace CertForAppServiceInAzure
{
public class MyX509CertificateValidator : X509CertificateValidator
{
public override void Validate(X509Certificate2 certificate)
{
// Check that there is a certificate.
if (certificate == null)
{
throw new ArgumentNullException("certificate");
}
Service1.str = certificate.Subject;
}
}
}
Enable Client certificate for the same App published in Azure:
=============================================
az webapp update --set clientCertEnabled=true --name WCFCLIENTCERTSAMPLE --resource-group MyResGroup
Note: Give your App service name and Resource Group name
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<security>
<access sslFlags="Ssl,SslRequireCert,SslNegotiateCert" />
</security>
<directoryBrowse enabled="true"/>
</system.webServer>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpsBinding_IService1">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://wcfclientcertsample.azurewebsites.net/Service1.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpsBinding_IService1" behaviorConfiguration="endpointCredentialBehavior"
contract="ServiceReference1.IService1" name="BasicHttpsBinding_IService1" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="endpointCredentialBehavior">
<clientCredentials>
<clientCertificate findValue="9c8a3857851e653ff22f0161914a1accf8ac5e76"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindByThumbprint" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
Continue reading...
Here I have highlighted in detail the steps of how to create and publish a WCF Service with Client Certificate enabled in Azure Web App.
Create an Azure Web App:
===========================
- Navigate to the Azure Portal and login with your Azure account and click on App services.
- Click on Add Web Apps and enter the details for Name, Subscription, Resource Group, OS and click Create.
- The Web App with name WCFCLIENTCERTSAMPLE is created at my end.
Deploying the WCF service to the Web App:
======================================
We will be able to publish the created WCF Service or any other type of application directly into the created Web APP.
- Open Visual studio and create a new project by selecting WCF service application as the project type and name it as CertForAppServiceInAzure.
- Let the Default generated code be in the operation contract and Service class for the sample. Modify it according to requirement. I modified it to print the certificate subject passed later:
IService1.cs:
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
Service1.cs:
public class Service1 : IService1
{
public static string str { get; set; }
public string GetData(int value)
{
return string.Format(str+ value);
} }
- We need to make the following changes in the Service’s web config inside system.servicemodel section to enable client cert authentication:
- In the binding at my end I have used basicHttpsBinding and enabled the security mode as Transport with clientCredentialType as Certificate.
<system.serviceModel>
<bindings>
<basicHttpsBinding>
<binding name="CertBind">
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</basicHttpsBinding>
</bindings>
<services>
<service name="CertForAppServiceInAzure.Service1">
<endpoint address="" binding="basicHttpsBinding" bindingConfiguration="CertBind" contract="CertForAppServiceInAzure.IService1"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="Custom" customCertificateValidatorType="CertForAppServiceInAzure.MyX509CertificateValidator, CertForAppServiceInAzure"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
Note: I have defined the client certificate validator in the service end as a custom validator so that I can verify if the client certificate is fetched in service end and parse the client certificate details. You can ignore step 5 if you are not using custom validator.
- To add the custom validator class, Create a Class file named MyX509CertificateValidator.cs in the service end with the below code to read the client certificate sent by the client and print the subject details (You can add your own condition check).
using System;
using System.IdentityModel.Selectors;
using System.Security.Cryptography.X509Certificates;
namespace CertForAppServiceInAzure
{
public class MyX509CertificateValidator : X509CertificateValidator
{
public override void Validate(X509Certificate2 certificate)
{
// Check that there is a certificate.
if (certificate == null)
{
throw new ArgumentNullException("certificate");
}
Service1.str = certificate.Subject;
}
}
}
- Right Click on your Project and select Publish, Select the Publish Location as Azure App Service.
- Select the Subscription, Resource Group and App service name from the dropdown which you have created on Azure and select Finish to publish the WCF service directly to the created Azure Web App.
- Browse the Service Over the Azure App service public URL https://wcfclientcertsample.azurewebsites.net/Service1.svc
- We get the below error:
Enable Client certificate for the same App published in Azure:
=============================================
- Run the below command to enable the Client certificate for the Azure Web App:
az webapp update --set clientCertEnabled=true --name WCFCLIENTCERTSAMPLE --resource-group MyResGroup
Note: Give your App service name and Resource Group name
- To fix the Server Error we add the below section in the Web.config system.WebServer Section and re-publish the same:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<security>
<access sslFlags="Ssl,SslRequireCert,SslNegotiateCert" />
</security>
<directoryBrowse enabled="true"/>
</system.webServer>
- Browse the application again over the same https://wcfclientcertsample.azurewebsites.net/Service1.svc we get the pop up to select the client certificate we select the client cert and we are able to access the service:
- Now Consume the same service in the client application by creating a test console application project and adding the service Reference by the url https://wcfclientcertsample.azurewebsites.net/Service1.svc
- Pass the client certificate details in the web.config and map it with the binding, In my scenario the client app is running on my Windows server. Make Sure the Client certificate is installed on the client machine and present in mmc under Current User.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpsBinding_IService1">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://wcfclientcertsample.azurewebsites.net/Service1.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpsBinding_IService1" behaviorConfiguration="endpointCredentialBehavior"
contract="ServiceReference1.IService1" name="BasicHttpsBinding_IService1" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="endpointCredentialBehavior">
<clientCredentials>
<clientCertificate findValue="9c8a3857851e653ff22f0161914a1accf8ac5e76"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindByThumbprint" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
- As in the Service end I have used a custom client certificate validator and for testing purpose I am printing the subject name of the client certificate passed via the custom validator in the service end. Now when we run the client we see the below Console Output.
Continue reading...