none
How to use a public certificate in Azure for WCF Message level security

    Question

  • We are migrating our WCF web services to Azure. Our services relies on Message level security, custom UserNamePasswordValidationMode and a public certificate as serviceCertificate.
    In order to enable this in Azure I understand full trust is mandatory, therefore I enabled native code executing in the .csdef file.

    <WebRole name="WebServiceRole" enableNativeCodeExecution="true">

     

     

    Now the tricky part: How can I place the public certificate in my Azure project so WCF can use it?

    I thought of taking advantage of the SSL properties in the cloud project in VS as a way to carry the certificate, even if I am not interested in exposing HTTPS endpoints.
    So I set the public "ws.xyz.com" as the Publishing certificate of choice and publishing completed successfully, I suppose because I have the private key set as exportable on my development environment.

    I deployed the package on Azure but my service fails as WCF is unable to find the "ws.xyz.com" X.509 certificate in the StoreName 'My' and StoreLocation 'CurrentUser', the same happens with StoreLocation 'LocalMachine'. So where is the certificate located once in Azure?
    If I attempt to access the Default.aspx page I left in this test project with SSL, I get a warning as the Azure site address doesn't match with "ws.xyz.com" but I have the proof the certificate has been deployed to the Azure machine.

    Is this the right way to approach this problem? Are there other ways to support this scenario?

    Thanks in advance,
    Davide
    BEDIN Shop Systems


    Davide Bedin
    • Moved by DanielOdievich Tuesday, September 28, 2010 9:26 PM forum migration (From:Windows Azure)
    Monday, September 14, 2009 4:16 PM

Answers

  • Hello, WCF message security does not rely on the https endpoint in your web role (only transport security rellies on the https endpoint). Actually the normal solution for WCF message security (set the serviceCertificate property in web.config) should also work in Windows Azure. Unfortunately, currently you have no access to the certificate store on the cloud machine. So you have to embed the encoded value of the certificate in web.config.

    You can find a step by step guide about how to work with certificates in the cloud at http://code.msdn.microsoft.com/wifwazpassive. Anyway, looks like a lot of customers are interested in this scenario. So I'll give a quick summary below.

    First you must download the project from the above link. After unpackage it, under the assets folder, you will find a Microsoft.IdentityModelPlus.dll. This assembly has done all the dirty work for you to load a certificate from the encoded value. So please reference it in your web role.

    Then export the certificate from your local certificate MMC. Make sure to export the private key as well. As you already know, when exporting a certificate with the private key, you're required to specify a password. Remember it.

    Now open a command prompt, and run the Encoder.exe found under assets\utils folder. Pass the path of your certificate as the command line parameter. For example:

    Encoder.exe "C:\MyCertificate.pfx"

    You will not see any information in the console, however, the output of this tool can be found under the same assets\utils folder. It is named encoder.out. You can open it in NotePad. Ignore the password (it is a fake password), but pay attention to the encodedValue. You'll need it in your web.config.

    Now open web.config, and add a configuration section in configSections. Make sure not to put it under any sectionGroups. Put it directly under the configSections node. This is just the normal way to add a configuration section in ASP.NET.

                <section name="microsoft.identityModelPlus"

    type="Microsoft.IdentityModelPlus.Configuration.MicrosoftIdentityModelPlusSection, Microsoft.IdentityModelPlus"

                requirePermission="false" />

    In the bottom of web.config, add the microsoft.identityModelPlus section:

          <microsoft.identityModelPlus>

                <serviceCertificate>

                      <certificate name="YourCertificateName" password="YourPassword" encodedType="pfx" encodedValue="TheEncodedValueFoundEarlier"/>

                </serviceCertificate>

          </microsoft.identityModelPlus>

    As for the configuration of the serviceCredentials section in the serviceBehavior, now you need to remove the serviceCertificate. In the following sample, since I'm using a self-signed certificate, I'm specifying certificateValidationMode as None. In real world application, please use a real certificate.

                                  <serviceCredentials>

                                        <!--Remove the serviceCertificate section.

    <serviceCertificate findValue="" storeName="My" x509FindType="FindByThumbprint" storeLocation="LocalMachine"/>-->

                                        <clientCertificate>

                                              <authentication certificateValidationMode="None"/>

                                        </clientCertificate>

                                  </serviceCredentials>

    The remaining configuration is the same as a normal message security WCF service.

                <bindings>

                      <wsHttpBinding>

                            <binding name="wsBinding">

                                  <security mode="Message">

                                        <message clientCredentialType="Certificate"/>

                                  </security>

                            </binding>

                      </wsHttpBinding>

                </bindings>

    So far, you've configured the certificate, and you know Microsoft.MicrosoftIdentityModelPlusSection is able to create a X509Certificate2 object from the configuration. But how do you specify this certificate to be used in your service? The answer is to create a custom ServiceHost and a custom ServiceHostFactory. You probably already know how to do that, so I'll omit the majority code here. Below is the ApplyConfiguration method. In this method, you use MicrosoftIdentityModelPlusSection to create the certificate, and set the ServiceCertificate.Certificate property to this certificate.

                protected override void ApplyConfiguration()

                {

                      base.ApplyConfiguration();

                      MicrosoftIdentityModelPlusSection plusConfiguration = MicrosoftIdentityModelPlusSection.Current;

                      if (plusConfiguration != null && plusConfiguration.ServiceCertificate.ElementInformation.IsPresent)

                      {

                            X509Certificate2 serviceCertificate = plusConfiguration.ServiceCertificate.GetCertificate();

                            ServiceCredentials serviceCredentials = (ServiceCredentials)this.Description.Behaviors[typeof(ServiceCredentials)];

                            serviceCredentials.ServiceCertificate.Certificate = serviceCertificate;

                      }

                }


    Lante, shanaolanxing This posting is provided "AS IS" with no warranties, and confers no rights.
    • Marked as answer by DavideB Thursday, September 17, 2009 12:46 PM
    Tuesday, September 15, 2009 6:51 AM

All replies

  • Hello, WCF message security does not rely on the https endpoint in your web role (only transport security rellies on the https endpoint). Actually the normal solution for WCF message security (set the serviceCertificate property in web.config) should also work in Windows Azure. Unfortunately, currently you have no access to the certificate store on the cloud machine. So you have to embed the encoded value of the certificate in web.config.

    You can find a step by step guide about how to work with certificates in the cloud at http://code.msdn.microsoft.com/wifwazpassive. Anyway, looks like a lot of customers are interested in this scenario. So I'll give a quick summary below.

    First you must download the project from the above link. After unpackage it, under the assets folder, you will find a Microsoft.IdentityModelPlus.dll. This assembly has done all the dirty work for you to load a certificate from the encoded value. So please reference it in your web role.

    Then export the certificate from your local certificate MMC. Make sure to export the private key as well. As you already know, when exporting a certificate with the private key, you're required to specify a password. Remember it.

    Now open a command prompt, and run the Encoder.exe found under assets\utils folder. Pass the path of your certificate as the command line parameter. For example:

    Encoder.exe "C:\MyCertificate.pfx"

    You will not see any information in the console, however, the output of this tool can be found under the same assets\utils folder. It is named encoder.out. You can open it in NotePad. Ignore the password (it is a fake password), but pay attention to the encodedValue. You'll need it in your web.config.

    Now open web.config, and add a configuration section in configSections. Make sure not to put it under any sectionGroups. Put it directly under the configSections node. This is just the normal way to add a configuration section in ASP.NET.

                <section name="microsoft.identityModelPlus"

    type="Microsoft.IdentityModelPlus.Configuration.MicrosoftIdentityModelPlusSection, Microsoft.IdentityModelPlus"

                requirePermission="false" />

    In the bottom of web.config, add the microsoft.identityModelPlus section:

          <microsoft.identityModelPlus>

                <serviceCertificate>

                      <certificate name="YourCertificateName" password="YourPassword" encodedType="pfx" encodedValue="TheEncodedValueFoundEarlier"/>

                </serviceCertificate>

          </microsoft.identityModelPlus>

    As for the configuration of the serviceCredentials section in the serviceBehavior, now you need to remove the serviceCertificate. In the following sample, since I'm using a self-signed certificate, I'm specifying certificateValidationMode as None. In real world application, please use a real certificate.

                                  <serviceCredentials>

                                        <!--Remove the serviceCertificate section.

    <serviceCertificate findValue="" storeName="My" x509FindType="FindByThumbprint" storeLocation="LocalMachine"/>-->

                                        <clientCertificate>

                                              <authentication certificateValidationMode="None"/>

                                        </clientCertificate>

                                  </serviceCredentials>

    The remaining configuration is the same as a normal message security WCF service.

                <bindings>

                      <wsHttpBinding>

                            <binding name="wsBinding">

                                  <security mode="Message">

                                        <message clientCredentialType="Certificate"/>

                                  </security>

                            </binding>

                      </wsHttpBinding>

                </bindings>

    So far, you've configured the certificate, and you know Microsoft.MicrosoftIdentityModelPlusSection is able to create a X509Certificate2 object from the configuration. But how do you specify this certificate to be used in your service? The answer is to create a custom ServiceHost and a custom ServiceHostFactory. You probably already know how to do that, so I'll omit the majority code here. Below is the ApplyConfiguration method. In this method, you use MicrosoftIdentityModelPlusSection to create the certificate, and set the ServiceCertificate.Certificate property to this certificate.

                protected override void ApplyConfiguration()

                {

                      base.ApplyConfiguration();

                      MicrosoftIdentityModelPlusSection plusConfiguration = MicrosoftIdentityModelPlusSection.Current;

                      if (plusConfiguration != null && plusConfiguration.ServiceCertificate.ElementInformation.IsPresent)

                      {

                            X509Certificate2 serviceCertificate = plusConfiguration.ServiceCertificate.GetCertificate();

                            ServiceCredentials serviceCredentials = (ServiceCredentials)this.Description.Behaviors[typeof(ServiceCredentials)];

                            serviceCredentials.ServiceCertificate.Certificate = serviceCertificate;

                      }

                }


    Lante, shanaolanxing This posting is provided "AS IS" with no warranties, and confers no rights.
    • Marked as answer by DavideB Thursday, September 17, 2009 12:46 PM
    Tuesday, September 15, 2009 6:51 AM
  • Thank for your detailed response.

    In the meanwhile we solved putting the certificate in the resources, configuring  the <service>.svc WCF service to use a custom service host factory we created. This custom servicehost factory retrieve the X509Certificate2 from the Resources and do pretty the same as you described.

    Do you think this is an inherently less secure solution than placing the encoded certificate in the .config file?

    Thanks again,
    Davide Bedin
    BEDIN Shop Systems
    Davide Bedin
    Thursday, September 17, 2009 1:16 PM
  • Hi

    Is this still the accepted way of retrieving service certificates in the cloud?

    Graeme
    Friday, February 12, 2010 2:52 PM