Azure App Service and Client Certificate Authentication

Azure App Services can make use of Client Certificate Authentication. The options for this are not available in the portal and need to be configured manually.

Activating Client Certificate Authentication

In the below blog post on the Azure documentation site is explained how you can configure your Azure Web App for client certificate authentication:

The same way can also be used for for example an Azure API App. The below option is a option for setting the same property in a different way.

  • Open https://resources.azure.com/ and login with the same credentials as the Azure Portal.
  • Find your site. It will be under subscriptions – [your subscription] – resouceGroups – [your resource group] – providers – Microsoft.Web – sites –[your site]

image

 

 

 

 

 

 

 

 

  • Make sure the interface is set on “Read\Write” mode.

image

  • Click the “Edit” button on the op of the screen.

image

 

 

 

  • Find the property “clientCertEnabled” and set it to “true”.

image

 

 

  • Click the “PUT” button on top to save your changes.

image

 

 

 

 

With the Azure resource configured you need to make sure that your application is able to use Client Certificate Authentication.

Preparing your Application

Keep in mind that your Azure resource does not validate your Client Certificate! It only requires you to supply a certificate when opening the application. That requires you to write your own logic for validating the certificate. In the blog post mentioned above there is class for validating the certificate. Based on this example I have created a Certificate Authorization Attribute.

/// <summary>
/// Certificate Authorization Attribute
/// </summary>
/// <seealso cref="System.Web.Http.AuthorizeAttribute" />
[AttributeUsage(AttributeTargets.All)]
public class CertificateAuthorizationAttribute : AuthorizeAttribute {

    /// <summary>
    /// Indicates whether the specified control is authorized.
    /// </summary>
    /// <param name="actionContext">The context.</param>
    /// <returns>
    /// true if the control is authorized; otherwise, false.
    /// </returns>
    protected override bool IsAuthorized(HttpActionContext actionContext) {
        bool retVal = false;

        var cert = actionContext.RequestContext.ClientCertificate;

        if (cert != null) {
            try {
                retVal = IsValidClientCertificate(cert);
            } catch {
                //log exception
            }
        }
        return retVal;
    }

    /// <summary>
    /// Determines whether [is valid client certificate] [the specified certificate].
    /// </summary>
    /// <param name="certificate">The certificate.</param>
    /// <returns>boolean</returns>
    private bool IsValidClientCertificate(X509Certificate2 certificate) {
        //1. Check time validity of certificate
        if (DateTime.Compare(DateTime.Now, certificate.NotBefore) < 0 || DateTime.Compare(DateTime.Now, certificate.NotAfter) > 0) {
            return false;
        }

        //2. Check subject name of certificate
        bool foundSubject = false;
        string[] certSubjectData = certificate.Subject.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
        foreach (string s in certSubjectData) {
            if (String.Compare(s.Trim(), "[Subject Name]") == 0) {
                foundSubject = true;
                break;
            }
        }
        if (!foundSubject) return false;

        //3. Check issuer name of certificate
        bool foundIssuerCN = false;
        string[] certIssuerData = certificate.Issuer.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
        foreach (string s in certIssuerData) {
            if (String.Compare(s.Trim(), "[Issuer]") == 0) {
                foundIssuerCN = true;
                break;
            }
        }
        if (!foundIssuerCN) return false;

        // 4. Check thumbprint of certificate
        if (String.Compare(certificate.Thumbprint.Trim().ToUpper(), "[Thumbprint]") != 0) return false;

        return true;
    }
}

This attribute makes sure you call the application with a valid certificate. It checks the following properties of the certificate:

  1. The time validity
  2. The subject name
  3. The issuer name
  4. The thumbprint

With the attribute implemented it can be used on a Controller method for example.

[CertificateAuthorization]
[Route("spitems/{clientId}")]
public HttpResponseMessage Get(string clientId) {
}

Make sure you do not forget to add the following xml node to your web.config and call your application with https. If you do not do this your certificate will not be recognized in your request.

<configuration>
<!-- other settings -->
  <system.webServer>
    <security>
      <access sslFlags="SslNegotiateCert" />
    </security>
  </system.webServer>
<configuration>

Testing your application

Testing your application can be done by using the HttpClient to perform a request.

private async Task<string> RunAsync() {
    string retVal = string.Empty;
    var handler = new WebRequestHandler();
    handler.ClientCertificateOptions = ClientCertificateOption.Manual;
    var cert = GetClientCert();
    handler.ClientCertificates.Add(cert);

    handler.ServerCertificateValidationCallback = delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors error) {
        return true;
    };
    handler.UseProxy = false;

    using (var client = new HttpClient(handler)) {
        client.BaseAddress = new Uri("[Base Address]");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        var response = await client.GetAsync("[url part 2]");
        if (response.IsSuccessStatusCode) {
            retVal = await response.Content.ReadAsStringAsync();
        } 
    }

    return retVal;
}

Related Posts

Restricting access to your Azure Web Application As you may know almost everything that is deployed to Azure is publicly available. As with Azure SQL Database you do not have a firewall available for...
Configure access to a private network for a Azure App Services On-Premise connections for Azure App Services can be created by using Hybrid Connections. Hybrid connections do not need any development or re-configu...
Extensions and Tips for deploying with Azure Resource Templates Working with Azure Services in different subscriptions means that the Azure Services need to run in different subscriptions. This often occurs when we...
Part 3 – Console application to call a API with Azure Active Directory Aut... This post is the third and last in a series of three posts and will help you with the creation of identity pass-through authentication from a client a...
Part 2 – Azure API Application to query the Azure SQL Database This post is the second in a series of three posts and will help you with the creation of identity pass-through authentication from a client applicati...
Part 1 – Azure SQL Database with Azure Active Directory Authentication This post is the first post in a series of three posts and will help you with the creation of identity pass-through authentication from a client appli...

5 comments

  • Hi, we are getting “The page cannot be displayed because an internal server error has occurred.” when we add “” to the web.config. We have also updated the Any idea why or if there is anything else we need to modify?

    • Hi Allan,

      Did you turn off the custom errors, and did you make every configuration change? (Also on the Azure side). Keep in mind that when using Certificate Authentication you will need to open the site in the https form.

  • Ahhh thank you so much for this!

    I was stuck, but am no longer. Bookmarked 🙂

  • Hi, Is it possible to enable client certificate only to a specific path?

    For example adding the following element to web.config, Is there any way to set clientCertEnabled true only for the same path?

    • Hi CF,

      In the web.config you can’t enable client certificate for only a specific path. What you could test is not applying the attribute to specific controllers and test if it works when you do not apply a certificate to that specific controller.

Leave a Reply

Your email address will not be published. Required fields are marked *