<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Kirk Evans Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/kaevans/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/kaevans/feed.xml</link>
    <description>.NET From a Markup Perspective</description>
    <lastBuildDate>Tue, 13 Feb 2018 20:40:13 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Join a Virtual Machine to Existing Domain with Key Vault and ARM templates</title>
      <link>https://docs.microsoft.com/archive/blogs/kaevans/join-a-virtual-machine-to-existing-domain-with-key-vault-and-arm-templates</link>
      <pubDate>Sat, 15 Jul 2017 20:13:59 GMT</pubDate>
      <dc:creator><![CDATA[Kirk Evans[MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaevans/?p=14785</guid>
      <description><![CDATA[One of my customers is building a set of ARM templates for their internal users.  They wanted to...]]></description>
      <content:encoded><![CDATA[One of my customers is building a set of ARM templates for their internal users.  They wanted to remove the burden for users to specify the local administrator’s credentials, but wanted to store the credentials securely.

To skip the explanation and just go to the code, see <a href="https://github.com/kaevans/vm-domain-join-key-vault" title="https://github.com/kaevans/vm-domain-join-key-vault">https://github.com/kaevans/vm-domain-join-key-vault</a>.

The problem is that you cannot reference the Key Vault from within the template itself, its value has to be passed as a secure string.  The way around this is to create a nested deployment.  The first template will create the network interface, then call the second template, passing parameter values to it.  This is where we can leverage Key Vault such that the user can provision a VM that references Key Vault without ever knowing the Key Vault even exists or having access to the secrets it contains.

<a href="https://msdnshared.blob.core.windows.net/media/2017/07/image227.png"><img width="347" height="194" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/07/image_thumb190.png" border="0" /></a>

There are a few moving parts to make this work.  We need a domain controller with a properly-configured virtual network.
<h2>Create an Azure VM with a new Active Directory Forest</h2>
If you go to the <a href="https://azure.microsoft.com/en-us/resources/templates/">Azure Quickstart Templates page</a>, the first thing you will see is the list of most popular templates.  The second item is the template to <a href="https://azure.microsoft.com/en-us/resources/templates/active-directory-new-domain/">Create an Azure VM with a new AD Forest</a>.

<a href="https://msdnshared.blob.core.windows.net/media/2017/07/image228.png"><img width="244" height="162" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/07/image_thumb191.png" border="0" /></a>

Click that item, then click the big “Deploy to Azure” button.

<a href="https://msdnshared.blob.core.windows.net/media/2017/07/image229.png"><img width="244" height="59" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/07/image_thumb192.png" border="0" /></a>

You are taken to the Azure portal, where you need to fill in the parameters for the template.

<a href="https://msdnshared.blob.core.windows.net/media/2017/07/image230.png"><img width="244" height="224" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/07/image_thumb193.png" border="0" /></a>

Wait until it’s complete, and you will have a properly configured domain controller and Azure virtual network where the DNS settings have been updated to use the DNS from the domain controller.  Inspect the resulting resource group and see the virtual network is named “adVNET”.

<a href="https://msdnshared.blob.core.windows.net/media/2017/07/image231.png"><img width="244" height="142" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/07/image_thumb194.png" border="0" /></a>

We author our new template that it will place our new virtual machine into that existing virtual network.
<h2>Create the Key Vault</h2>
Now that we have the domain controller provisioned, we can create a Key Vault.  This vault doesn’t have to reside in the same resource group, but we do need to enable access to Azure Resource Manager for template deployment.  Do this by settings the advanced access policy.

<a href="https://msdnshared.blob.core.windows.net/media/2017/07/image232.png"><img width="244" height="199" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/07/image_thumb195.png" border="0" /></a>

Add the local machine administrator’s username:

<a href="https://msdnshared.blob.core.windows.net/media/2017/07/image233.png"><img width="244" height="169" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/07/image_thumb196.png" border="0" /></a>

Add the local machine administrator’s password:

<a href="https://msdnshared.blob.core.windows.net/media/2017/07/image234.png"><img width="244" height="168" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/07/image_thumb197.png" border="0" /></a>

Make note of the name of each of these secrets, we’ll use these later.
<h2>Create the Virtual Machine Template</h2>
The first template we create will have a whole bunch of parameters because it is designed to be reused in different contexts.  This template will create a VM using an existing network interface (implying the NIC has already been configured on a virtual network) and then join it to an existing domain.  This sample is very similar to the sample <a href="https://azure.microsoft.com/en-us/resources/templates/201-vm-domain-join/" title="https://azure.microsoft.com/en-us/resources/templates/201-vm-domain-join/">Join a VM to an existing domain</a>, with the notable change that the sample below uses managed disks, removing the need for storage accounts.
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:70e7e2f8-4842-4d44-9229-0bc8bc01a224" style="margin: 0px;padding: 0px;float: none">
<pre>[code language='javascript' ]
{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters":
  {
    "region":
    {
      "type": "string"
    },
    "vmName":
    {
      "type": "string"
    },
    "nicName":
    {
      "type": "string"
    },
    "vmSize":
    {
      "type": "string"
    },
    "vmAdminUsername":
    {
      "type": "string"
    },
    "vmAdminPassword":
    {
      "type": "securestring"
    },
    "domainToJoin":
    {
      "type": "string"
    },
    "domainUsername":
    {
      "type": "string"
    },
    "domainPassword":
    {
      "type": "securestring"
    },
    "ouPath":
    {
      "type": "string",
      "defaultValue": "",
      "metadata":
      {
        "description": "Specifies an organizational unit (OU) for the domain account. Enter the full distinguished name of the OU in quotation marks. Example: 'OU=testOU; DC=domain; DC=Domain; DC=com"
      }
    },
    "domainJoinOptions":
    {
      "type": "int",
      "defaultValue": 3,
      "metadata":
      {
        "description": "Set of bit flags that define the join options. Default value of 3 is a combination of NETSETUP_JOIN_DOMAIN (0x00000001) &amp; NETSETUP_ACCT_CREATE (0x00000002) i.e. will join the domain and create the account on the domain. For more information see https://msdn.microsoft.com/en-us/library/aa392154(v=vs.85).aspx"
      }
    },
    "windowsOSVersion":
    {
      "type": "string",
      "defaultValue": "2012-R2-Datacenter",
      "allowedValues":
      [
        "2008-R2-SP1",
        "2012-Datacenter",
        "2012-R2-Datacenter",
        "2016-Datacenter"
      ],
      "metadata":
      {
        "description": "The Windows version for the VM. This will pick a fully patched image of this given Windows version. Allowed values: 2008-R2-SP1, 2012-Datacenter, 2012-R2-Datacenter."
      }
    },
    "storageSku":
    {
      "type": "string",
      "allowedValues":
      [
        "Standard_LRS",
        "Premium_LRS"
      ]
    }
  },
  "variables":
  {
    "OSDiskName": "[concat(parameters('vmName'),'osdisk')]",
    "imagePublisher": "MicrosoftWindowsServer",
    "imageOffer": "WindowsServer"
  },
  "resources":
  [
    {
      "apiVersion": "2016-04-30-preview",
      "type": "Microsoft.Compute/virtualMachines",
      "name": "[parameters('vmName')]",
      "location": "[parameters('region')]",
      "tags":
      {
        "displayName": "VirtualMachine"
      },
      "properties":
      {
        "hardwareProfile":
        {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile":
        {
          "computerName": "[parameters('vmName')]",
          "adminUsername": "[parameters('vmAdminUsername')]",
          "adminPassword": "[parameters('vmAdminPassword')]",
          "windowsConfiguration":
          {
            "provisionVMAgent": true
          }
        },
        "storageProfile":
        {
          "imageReference":
          {
            "publisher": "[variables('imagePublisher')]",
            "offer": "[variables('imageOffer')]",
            "sku": "[parameters('windowsOSVersion')]",
            "version": "latest"
          },
          "osDisk":
          {
            "name": "[variables('OSDiskName')]",
            "managedDisk":
            {
              "storageAccountType": "[parameters('storageSku')]"
            },
            "caching": "ReadWrite",
            "createOption": "FromImage"
          }
        },
        "networkProfile":
        {
          "networkInterfaces":
          [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]"
            }
          ]
        }
      }
    },
    {
      "apiVersion": "2016-04-30-preview",
      "type": "Microsoft.Compute/virtualMachines/extensions",
      "name": "[concat(parameters('vmName'),'/joindomain')]",
      "location": "[parameters('region')]",
      "dependsOn":
      [
        "[concat('Microsoft.Compute/virtualMachines/', parameters('vmName'))]"
      ],
      "tags":
      {
        "displayName": "JsonADDomainExtension"
      },
      "properties":
      {
        "publisher": "Microsoft.Compute",
        "type": "JsonADDomainExtension",
        "typeHandlerVersion": "1.3",
        "autoUpgradeMinorVersion": true,
        "settings":
        {
          "Name": "[parameters('domainToJoin')]",
          "OUPath": "[parameters('ouPath')]",
          "User": "[concat(parameters('domainToJoin'), '\\', parameters('domainUsername'))]",
          "Restart": "true",
          "Options": "[parameters('domainJoinOptions')]"
        },
        "protectedSettings":
        {
          "Password": "[parameters('domainPassword')]"
        }
      }
    }

  ],
  "outputs": {
  }
}
[/code]
</pre>
</div>
There are no secrets or proprietary logic in this file, so we can upload it to a storage account or GitHub and make it publicly accessible.  I create a new container in a storage account, changing its access type to Blob.

<a href="https://msdnshared.blob.core.windows.net/media/2017/07/image235.png"><img width="244" height="139" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/07/image_thumb198.png" border="0" /></a>

I upload the file to blob storage and verify that I can download it publicly.  Note that we don’t have to use a public template, there are ways of uploading this to a private container with a SAS URL that grants temporary read access.  For our demo, a publicly accessible file is fine.

<a href="https://msdnshared.blob.core.windows.net/media/2017/07/image236.png"><img width="244" height="108" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/07/image_thumb199.png" border="0" /></a>
<h2>Create the Deployment Template</h2>
Typically, I expose many parameters to the user.  However, in this case, the customer explicitly did not want the person deploying this template to have to specify the local administrator credentials.  They also do not want the user who is deploying the template to have to know anything about Key Vault.  Instead of exposing this configuration as a parameter, we will embed the Key Vault reference as a variable.  This makes the template less portable, but still usable within this customer’s context.
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:43dbc3b7-7c87-4ceb-9ce3-49ed0ce1cc4c" style="margin: 0px;padding: 0px;float: none">
<pre>[code language='javascript'  highlight='62,63,64,115,145,153']
{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters":
  {
    "region":
    {
      "type": "string",
      "minLength": 1
    },
    "vmName":
    {
      "type": "string",
      "minLength": 1
    },
    "domainToJoin":
    {
      "type": "string",
      "minLength": 1,
      "defaultValue": "blueskyabove.local",
      "metadata":
      {
        "description": "The domain user alias to use when joining the machine to the specified domain"
      }
    },
    "domainUsername":
    {
      "type": "string",      
      "minLength": 1,
      "metadata":
      {
        "description": "The domain user alias to use when joining the machine to the specified domain"
      }
    },
    "domainPassword":
    {
      "type": "securestring",
      "minLength": 1,
      "metadata":
      {
        "description": "The password of the domain user to use when joining the machine to the specified domain"
      }
    }
  },
  "variables":
  {
    "existingVNETName": "adVNET",
    "existingVNETResourceGroupName": "ADDemo",
    "vnetRef": "[resourceId(subscription().subscriptionId, variables('existingVNETResourceGroupName'),'Microsoft.Network/virtualNetworks',variables('existingVNETName'))]",
    "subnetName": "adSubnet",
    "subnetRef": "[concat(variables('vnetRef'), '/subnets/', variables('subnetName'))]",
    "imagePublisher": "MicrosoftWindowsServer",
    "imageOffer": "WindowsServer",
    "imageSku": "2016-Datacenter",
    "OSDiskName": "vm1OSDisk",
    "storageSku": "Standard_LRS",
    "vmSize": "Standard_D2_v2",
    "nicName": "[concat(parameters('vmName'), 'NetworkInterface')]",
    "pipName": "[concat(parameters('vmName'), 'PublicIP')]",
    "domainJoinOptions": "3",
    "ouPath": "",    
    "keyVaultRef": "/subscriptions/678fbfe2-79a7-4689-839d-0a187e5b6b1a/resourceGroups/ADDemo/providers/Microsoft.KeyVault/vaults/ADDemoKeyVault",
    "usernameSecretName": "localAdminUsername",
    "passwordSecretName": "localAdminPassword"
  },
  "resources":
  [
    {
      "name": "[variables('nicName')]",
      "type": "Microsoft.Network/networkInterfaces",
      "location": "[parameters('region')]",
      "apiVersion": "2016-03-30",
      "dependsOn":
      [        
        "[resourceId('Microsoft.Network/publicIPAddresses', variables('pipName'))]"
      ],
      "tags":
      {
        "displayName": "vmNic"
      },
      "properties":
      {
        "ipConfigurations":
        [
          {
            "name": "ipconfig1",
            "properties":
            {
              "privateIPAllocationMethod": "Dynamic",
              "subnet":
              {
                "id": "[variables('subnetRef')]"
              },
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('pipName'))]"
              }
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2016-02-01",
      "name": "vmTemplate",
      "type": "Microsoft.Resources/deployments",
      "dependsOn":
      [
        "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
      ],
      "properties":
      {
        "mode": "Incremental",
        "templateLink":
        {
          "uri": "https://2lgwchcjfghlgadsa.blob.core.windows.net/arm/newVM.json",
          "contentVersion": "1.0.0.0"
        },
        "parameters":
        {
          "region":
          {
            "value": "[parameters('region')]"
          },
          "vmName":
          {
            "value": "[parameters('vmName')]"
          },
          "nicName":
          {
            "value": "[variables('nicName')]"
          },
          "vmSize":
          {
            "value": "[variables('vmSize')]"
          },
          "vmAdminUsername":
          {
            "reference":
            {
              "keyVault":
              {
                "id": "[variables('keyVaultRef')]"
              },
              "secretName": "[variables('usernameSecretName')]"
            }
          },
          "vmAdminPassword":
          {
            "reference":
            {
              "keyVault":
              {
                "id": "[variables('keyVaultRef')]"
              },
              "secretName": "[variables('passwordSecretName')]"
            }
          },
          "domainToJoin":
          {
            "value": "[parameters('domainToJoin')]"
          },
          "domainUsername":
          {
            "value": "[parameters('domainUsername')]"
          },
          "domainPassword":
          {
            "value": "[parameters('domainPassword')]"
          },
          "ouPath":
          {
            "value": "[variables('ouPath')]"
          },
          "windowsOSVersion":
          {
            "value": "[variables('imageSku')]"
          },
          "storageSku":
          {
            "value": "[variables('storageSku')]"
          }
        }
      }
    },
    {
      "name": "[variables('pipName')]",
      "type": "Microsoft.Network/publicIPAddresses",
      "location": "[parameters('region')]",
      "apiVersion": "2016-03-30",
      "dependsOn":
      [
      ],
      "tags":
      {
        "displayName": "vmPIP"
      },
      "properties":
      {
        "publicIPAllocationMethod": "Dynamic"
      }
    }
  ],
  "outputs":
  {

  }
}
[/code]
</pre>
</div>
Notice the hard-coded reference to the Key Vault resource ID in the variables section.  If this template is used in other contexts, the Key Vault resource ID would first need to be edited.  Also notice the URI in the templateLink property of the nested deployment. Again, there are other ways to manage this, but the customer wants a very specific scenario: upload from the Templates library in the portal.

To deploy the template, we will this template’s text to the Templates library in the Azure portal.

<a href="https://msdnshared.blob.core.windows.net/media/2017/07/image237.png"><img width="244" height="127" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/07/image_thumb200.png" border="0" /></a>

Once in the Templates library, a user can now easily deploy the template from the library, specifying a few parameters.  They do provide their domain credentials, but do not need to provide local administrator credentials as those are obtained from Key Vault.

<a href="https://msdnshared.blob.core.windows.net/media/2017/07/image238.png"><img width="244" height="203" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/07/image_thumb201.png" border="0" /></a>

Click Deploy, and in a few minutes you’ll have a virtual machine that is joined to the domain we previously created.  If you are getting impatient and want to see what is happening, click on the alerts button in the top right of the portal to view the deployment.  Once you see the deployment, click on the Events link to get a more detailed view of the deployment events.

<a href="https://msdnshared.blob.core.windows.net/media/2017/07/image239.png"><img width="244" height="188" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/07/image_thumb202.png" border="0" /></a>

Notice in the log that the VMADMINUSERNAME and VMADMINPASSWORD fields are blank, this is because these were secrets obtained from Key Vault and expressed as SecureString values.
<h2>Summary</h2>
The sample code is posted to GitHub - <a href="https://github.com/kaevans/vm-domain-join-key-vault" title="https://github.com/kaevans/vm-domain-join-key-vault">https://github.com/kaevans/vm-domain-join-key-vault</a>.

This post shows how you can use Key Vault to provide credentials from within a template without exposing them to the user who is deploying the template.  It’s worth noting that the user can edit the template, removing the Key Vault bindings in order to provide their own parameter values.  This is simply a convenience factor.

From a security standpoint, using the same local administrator credentials for all machines is an anti-pattern: Compromising one machine means you now have access to all machines.  This is how the SQL Slammer attack started, when the default SQL Server and Desktop Engine credentials were “sa” with a blank password. However, centrally managing these credentials through Key Vault helps prevent against users who provide weak or frequently re-used passwords, and the use of Key Vault enables frequent rolling of passwords used to create virtual machines. This particular customer’s environment is mitigated through group policy in Active Directory (the template joins the VM to the domain, and the GPO subsequently removes local administrator accounts).  Remember sound security practices when deploying virtual machines.
<h2>Resources</h2>
<a href="https://azure.microsoft.com/en-us/resources/templates/">Azure Quickstart Templates page</a>

<a href="https://azure.microsoft.com/en-us/resources/templates/active-directory-new-domain/">Create an Azure VM with a new AD Forest</a>

<a href="https://azure.microsoft.com/en-us/resources/templates/201-vm-domain-join/">Join a VM to an existing domain</a>

<a href="https://github.com/kaevans/vm-domain-join-key-vault">View this sample on GitHub</a>
]]></content:encoded>
    </item>
    <item>
      <title>Losing 100 Pounds in 5 Months</title>
      <link>https://docs.microsoft.com/archive/blogs/kaevans/losing-100-pounds-in-5-months</link>
      <pubDate>Sun, 25 Jun 2017 08:18:56 GMT</pubDate>
      <dc:creator><![CDATA[Kirk Evans[MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaevans/?p=14535</guid>
      <description><![CDATA[I have a lot of friends who have been asking me what the hell did I do to lose so much weight so...]]></description>
      <content:encoded><![CDATA[<p>I have a lot of friends who have been asking me what the hell did I do to lose so much weight so fast.&nbsp; This post is to try to capture everything.&nbsp; I didn’t do some fad diet, buy any pills, have any surgery, or spend any money except for my gym membership. I made the decision, stuck with a plan, and didn’t deviate: eat less, move more, drink more water.&nbsp; The first few parts of this post are a narrative about how I started. If you just want to see a sample routine, that’s at the end.</p><h2>Background</h2><p>On January 1st this year, I decided to change my life.&nbsp; I weighed 360 pounds, I was grossly out of shape, and I felt like time was running out.&nbsp; I’d felt like this for a long time, to the point of near depression, but rather than try to get healthy I continued to make bad health decisions and continued gaining weight.&nbsp; A few times I did try dieting, but I could never stick with anything long enough to see results.&nbsp; Clothes no longer fit, and buying new clothes at a “big and tall” shop (you rarely see tall people in these) was infuriating due to the huge sizes that I had to purchase.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/06/dinner-at-Zocados.jpg"><img width="244" height="139" title="dinner at Zocados" alt="dinner at Zocados" src="https://msdnshared.blob.core.windows.net/media/2017/06/dinner-at-Zocados_thumb.jpg" border="0"></a>&nbsp;</p>
<p>I love my wife, I love my kids, and I needed to be a better husband and father. My weight was in the way.</p>
<h2>Make The Decision</h2>
<p>I got the chance of a lifetime to go to Ireland for a business trip.&nbsp; While I was there, I went to see a dear friend, Derek Noonan.&nbsp; He took me out to see the sights, including a trip to the amazing Cliffs of Moher.&nbsp; It was stunning.&nbsp; <a href="https://msdnshared.blob.core.windows.net/media/2017/06/20161209_102140791_iOS.jpg"><img width="244" height="184" title="20161209_102140791_iOS" align="left" style="float: left" alt="20161209_102140791_iOS" src="https://msdnshared.blob.core.windows.net/media/2017/06/20161209_102140791_iOS_thumb.jpg" border="0"></a>We made the journey from Limerick to Burren in the morning.&nbsp; We arrived at the the visitor’s center, and it certainly was beautiful, but to get a really good look you needed to walk up a fairly long path of stairs. I was winded from the first few stairs, and by the time we reached the observation deck I was spent. </p>
<p>Derek took me to a few other places that day. We climbed the inside of Bunratty Castle, and I couldn’t imagine walking one more step. He wanted to take me to see King John’s Castle in Limerick, but I was exhausted and couldn’t do it. Here I was, my first time to Ireland (I’ve wanted to visit my entire life) and I was too exhausted to see anything.</p>
<p>We talked that night at dinner about my friend’s wife had started a diet called keto.&nbsp; I had seen Carl Franklin recently posting about a podcast he’d started (<a title="http://2ketodudes.com/" href="http://2ketodudes.com/">http://2ketodudes.com/</a>) and the results he’d seen. More excuses, I tried Atkins and I couldn’t last but a few days, no thanks. </p>
<p>I was really excited for the flight home, I was able to get an international business class seat.&nbsp; Traveling in style!&nbsp; I sat down and… I didn’t fit. I could get my butt and torso in, but my arms were resting uncomfortably and wedged against the seat divider. It was uncomfortable as hell. It was on that plane ride that I’d made up my mind to do something, but I didn’t act on it for a few weeks.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/2017/06/20161230_184209814_iOS.jpg"><img width="244" height="184" title="20161230_184209814_iOS" align="left" style="float: left" alt="20161230_184209814_iOS" src="https://msdnshared.blob.core.windows.net/media/2017/06/20161230_184209814_iOS_thumb.jpg" border="0"></a>My family purchased tickets to see my favorite football team, the Georgia Bulldogs, play in a bowl game.&nbsp; We drove from Dallas, Texas to Memphis, Tennessee.&nbsp; We rode in my wife’s car to get better gas mileage, and holy crap was it bad.&nbsp; I was too fat to fit comfortably, with nowhere to put my arms.&nbsp; We rented stadium seats, and they were worse than the bench seats because I was too fat to fit in them. I was too fat to sit with my family and had to sit one row in front of them to make sure my kids had enough room. If the plane flight home from Ireland was the decision point, this was the reinforcement.</p>
<p>I have a beautiful wife and two amazing kids, and I want to be here for a really, really long time.&nbsp; </p>
<p>The point of this introduction… you have to make the decision, you have to find your motivation to start. Do not go into this with the mindset of “dieting”, which carries a temporary connotation. Think of this as deciding to change your lifestyle, changing the behavior that caused you to gain weight.&nbsp; When you feel like giving up, you need to remember why you started, how you felt.</p>
<h2>The Start</h2>
<p>My employer (Microsoft) offers an employee benefit to stay healthy, providing $800 yearly to be used towards the purchase of exercise equipment or a gym membership.&nbsp; You should see the upstairs of my home, it’s littered with dusty exercise equipment I’ve accumulated over the years.&nbsp; I plunked the money down at a gym.&nbsp; I’d had gym memberships before, hired personal trainers before, and never seen results. I’d try it one more time.</p><p>While I was at the gym buying my membership, they told me that you could not exercise your way out of a bad diet, weight loss was 80% diet and just 20% exercise. I thought about Carl’s podcast and the results he had seen in a short timeframe… it was time. I’m done with feeling like this, I’m tired of feeling sick, I’m tired of my weight stopping me from enjoying life.&nbsp; I need to change the diet. I started researching keto more earnestly.</p><p>January 2nd, I woke and went to the gym. I scheduled a personal trainer session to force myself to actually go to the gym. It was embarrassing, to say the least. Simple exercises (step up, step down, 15 times) were nearly impossible. Planks? I could hardly hold myself up, and pushups were out of the question. I had to walk up a flight of stairs to go up to the cardio equipment, and I could barely make it up the stairs. I scheduled another personal trainer session, and he gave me homework. Total work out time was maybe 30 minutes, and I was exhausted.</p>
<p>I got home, slightly defeated, but determined. I started the keto diet by cooking eggs and bacon for breakfast, something I frequently ate, but this time no toast, no orange juice. Just black coffee. After breakfast, I started drinking water.&nbsp; I hadn’t drank water except to cure a hangover in a long time, opting for diet sodas or fruit juices. I was exhausted and took a long nap. I woke and, to my family’s shock, I had a salad for dinner: iceburg lettuce, a bit of shredded cheese, a boiled egg diced, and a grilled chicken breast, salt and pepper.</p>
<p>I did this for a week. Get up, go to the gym for an hour, get home and eat eggs and bacon, then sleep. Get up, eat a salad, then sleep. I was sleeping around 14 hours per day. I was a zombie when I was awake, I had zero energy and felt disgusting. At the end of the week, I weighed myself.&nbsp; Holy crap! I lost 10 pounds in ONE WEEK. It was water weight, I had read that others saw the same thing when they started keto, but wow. I can muscle through this and make it to week two. </p>
<p>I kept going to the gym, kept eating eggs and bacon in the morning with black coffee, chicken for dinner.&nbsp; Usually dinner was a salad, but sometimes I would just have grilled chicken breast with broccoli+butter or asparagus+olive oil. Occasionally, I’d have a steak, but it was mostly chicken.</p>
<h2>Progress</h2>
<p>At the end of month 1, I had lost 25 pounds. I was done with my personal trainer sessions, but still going to gym almost every day. Workouts had greatly improved. I could walk up the stairs without the railing and without being winded, and my workout routine increased to lift weights for 1 hour then cardio for 30 minutes. I was already noticing a few changes: cardio wasn’t nearly as hard as it was when I started, I was increasing the amount of weight that I was lifting. The coolest thing was when I made it up the flight of stairs and wasn’t even winded. I could keep doing this. I posted to Facebook, and received overwhelming encouragement from friends and family. It was so cool, people were telling me I was inspiring them. I kept checking into Facebook, telling everyone I was at the gym. Honestly, that was more for me than it was for them. It was accountability.</p>
<p>At the end of month 2, I was down 50 pounds. I was working out at the gym when I traveled, sticking to my diet, and was starting to visibly see changes. I had moved from being confined to just the elliptical machine or stationary bike at the gym, I could now using the rowing machine and the Stairmaster. Thinking back to where I was when I visited the Cliffs of Moher, being able to last for 30 minutes on the Stairmaster was huge for me. I was no longer feeling exhausted during the day and could now make it through the day without a nap (well, during the week, but weekends I sometimes indulge).</p>
<p>At the end of month 3, I took my son with me to the gym. He works out nearly every day at school and is in amazing shape, so I struggled to keep up with him. We went to do pushups, and I said “sorry, buddy, I can’t do pushups, my gut is too heavy.” He said to just try, and I did.. and I did 12 pushups. I had no idea I could do them, I was so proud of myself. A very cool thing happened: My son was proud of me, too. I was overwhelmed thinking, “my kids are seeing me work this hard.” </p>
<p><a href="https://msdnshared.blob.core.windows.net/media/2017/06/85-pounds.jpg"><img width="244" height="168" title="85 pounds" align="left" style="float: left" alt="85 pounds" src="https://msdnshared.blob.core.windows.net/media/2017/06/85-pounds_thumb.jpg" border="0"></a>End of month 4, I was down 85 pounds. I went from a size 5XL shirt down to a 2XL shirt, notched so many holes in my belt to tighten it that it wraps around to my back, even my shoes fit better.</p>
<p>Around this time, I hurt my arm at the gym (don’t overdo it, they say… well, pay attention, because it really effing hurts). I pulled or tore something in my forearm, now it hurts to lift a bottle of water, it hurts to push or pull anything, it hurts to walk and swing my arm. I stopped going to gym because it felt like I kept re-injuring it every time I went.&nbsp; I stuck with my diet, but weight loss came to a screeching halt for a few weeks. I was frustrated. I went to do the thing that got me into this mess in the first place: I went to grab a beer. Remember that you aren’t doing a short-term diet, you are changing the behaviors that caused the weight gain.</p>
<p>I didn’t drink it, instead I went running.&nbsp; RUNNING! Just a few months ago, I could barely get up a flight of stairs, and here I was running. I am still overweight, and I had to stop running to walk a few times. It took me about 20 minutes to run a mile.&nbsp; Still, I ran most of it, and it felt amazing. The next day, I had some pent-up energy and asked my son if he wanted to go our bicycles around the neighborhood. I was so heavy before that I didn’t fit on the bike, but now I did and I could keep up with my son while riding around the neighborhood.&nbsp; My daughter asked to ride bikes to the neighborhood pool, and we had a great time. Being lighter meant that I was enjoying more time with my kids.</p>
<p>Here we are, 5 1/2 months into this, and I am 100 pounds lighter. One hundred. When I started this, I couldn’t imagine losing 100 pounds, but then again, I couldn’t even imagine the first 10 pounds that I lost the first week. In the past, I’d always stopped a few weeks in when I didn’t see results. This time, I stuck with it. When I talk to people who want to lose weight, this is the part they are focused on: you lost so much weight! It didn’t happen overnight, it was a lot of trips to the gym, a lot of times eating a keto meal that I would much rather have had pizza and beer.</p>
<p>The point of this section is that it’s not just about losing weight, there are so many successes along the way to celebrate.</p><h2>The Rules</h2><p>The keys to losing weight are the same as they always have been: eat less, move more, drink more water.&nbsp; The problem with eating less is that it can be freaking impossible to get out of your own head.&nbsp; I use the keto diet and, admittedly, a lot of will power.&nbsp; The keto diet has you consume a very low amount of carbs and high fat, which makes you less hungry so you eat less. Fasting helps kick your metabolism back into gear, as does regular strenuous exercise. Drinking water not only helps you avoid being hungry but flushes everything from your body.</p><p>My rules are simple: </p><ul><li>Less than 20g total carbs per day. Usually closer to 10g.</li><li>Only eat when you are hungry.</li><li>Stop eating when you are no longer hungry.</li><li>Don’t eat after 7pm.</li><li>Drink water.</li></ul><p>To check carbs, I use an app called MyFitnessPal.com.&nbsp; For many foods, you can scan the barcode and it will display the carbs for you, or you can search. It can even check the menu of the restaurant that you are at. There is a paid version, but the free version works fine for me. This is great, especially when you are getting started, to log the food to make sure you are actually staying under 20g carbs.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/06/IMG_1719.png"><img width="139" height="244" title="IMG_1719" alt="IMG_1719" src="https://msdnshared.blob.core.windows.net/media/2017/06/IMG_1719_thumb.png" border="0"></a></p><p>There is a calculator online at <a href="http://keto-calculator.ankerl.com">http://keto-calculator.ankerl.com</a>.&nbsp; Enter in weight, height, sex, protein, and carbs, and it will tell you how much you should be consuming based on your body type.&nbsp; Here are my results:</p>
<table style="width: 200px"><tbody><tr><td>Daily calorie intake</td><td>1700</td></tr><tr><td>Carbs</td><td>15g</td></tr><tr><td>Protein</td><td>120g</td></tr><tr><td>Fat</td><td>129g</td></tr></tbody></table><p>The only one of these that I actually focus on is the carbs, but I do occasionally check protein, especially when weight loss stalls.&nbsp; I rarely ever hit 1700 calories, usually I am much lower than that.&nbsp; </p>
<h2>Schedule</h2>
<p>OK, the section some of you want to see since I get this one a lot… what the heck is your schedule?</p>
<table style="border: 1px solid black" border="1">
<tbody>
<tr><th style="width: 50px"><strong>Time</strong></th><th><strong><strong>Activity</strong></strong></th></tr><tr>
<td>5:00am</td>
<td>Wake. Drink black coffee, check calendar. Work – process email, finish deliverables that are due.</td>
</tr>
<tr>
<td>8:00am</td>
<td>Go to gym. 5 minute warmup, 5 minute stretch, 50 minutes heavy lifting followed by 30 minutes cardio.</td>
</tr>
<tr>
<td>9:45am</td>
<td>Cook breakfast. Two eggs cooked in 1 tbsp butter + 4 pieces bacon or sausage.</td>
</tr>
<tr><td>10:15am</td><td>Back to work. Phone calls, coding, writing. Keep drinking a LOT of water throughout the day.</td></tr><tr><td>2:00pm</td><td>Light snack: handful of salted almonds, 1-2 ounces cheddar cheese.&nbsp; </td></tr><tr><td>5:00pm</td><td>Dinner.</td></tr><tr><td>8:00pm</td><td>Bed.</td></tr></tbody>
</table><p>My rule is that I don’t eat past 7pm and I don’t eat breakfast before 10am, providing a 15 hour fast every day.&nbsp; Once every two weeks I do at least a 24-hour fast, occasionally I have done 48-hour fasts.&nbsp; I am a royal jerk when I fast for that long, and I don’t wake up thinking, “I’m going to start a fast today.”&nbsp; At breakfast, I ask myself if I am actually hungry, and if I’m not, I don’t eat then. At 2pm, I chug water to determine if I’m actually hungry or not. At dinner, I ask myself again if I am actually hungry. If I can make it through dinner and I am only a little hungry, I’ll push myself to wait until breakfast. </p><p>The first month or so, I frequently had to take a nap in the middle of the day. Part of that was because I was working out and my muscles were so sore that I didn’t sleep very well. Both of those passed, and I usually sleep 8-9 hours a night now, though I can still barely make it past 8pm. </p><h2>Sample Recipes</h2><p>Here is a sample of recipes that I usually eat.</p><p>Omelet and meat: 2 eggs and 2 tbsp whole milk, salt and pepper, scrambled, cooked in 1 tbsp butter.&nbsp; 4 strips of bacon (I don’t drain them, I keep them dripping with fat) or 4 sausage patties. Store the leftover meats for meals for the next 2 days.</p><p>1 8-ounce chicken breast, grilled. Cover in Frank’s RedHot sauce, top with shredded cheddar cheese.&nbsp; Side of broccoli (a whole bag), topped with butter and salt. </p><p>Pork rinds covered in shredded cheddar cheese, put in the oven for 5 minutes to melt the cheese.&nbsp; Add 1/4 to 1/2 cup taco meat (McCormick taco seasoning, no reason other than that’s the one I like). Add jalapenos and shredded iceburg lettuce. Add Frank’s RedHot sauce.</p><p>8oz steak. Side of asparagus cooked in olive oil and salt. </p><p>Large bowl of mixed greens salad. Add 6-8 ounces chicken, 1 hard-boiled egg, shredded cheddar cheese, bacon pieces, walnuts, salt and pepper.</p><p>Hamburger patties, usually 2 of them, with a very small amount of ketchup (remember that ketchup has carbs), topped with pickles and cheddar cheese. Wrap in iceburg lettuce instead of a bun.</p><p>8-10 oz grilled flank steak, cut into fajita strips, shredded cheddar, small amounts of picante (watch carbs!) wrapped in iceburg lettuce instead of tortillas.</p><h2>Workouts</h2><p>When I started working out, I hired a trainer for a few sessions just to get me started.&nbsp;&nbsp; I knew I wasn’t going to be able to afford to have a trainer for very long, so I focused on developing a plan.&nbsp; How many reps, how to stretch, how to increase over time.&nbsp; What web sites to visit.&nbsp; The trainer was helpful, but simply Googling with Bing for different workouts typically landed me at <a title="https://www.bodybuilding.com" href="https://www.bodybuilding.com">https://www.bodybuilding.com</a>.&nbsp; While I am no bodybuilder, it was helpful to get ideas for routines and even see videos of how to do the exercise correctly.</p><p>My workout routine is to do heavy lifting for about an hour, and cardio for 30 minutes. I don’t leave the gym until I’ve burned 1000 calories according to my Microsoft Band (or use a FitBit or Garmin or whatever works for you). The routine I've chosen is 6 days of strength training, alternating muscle isolation. Legs, lat/back, legs, triceps, legs, chest/biceps. 3 sets of 15 each exercise, 60-90 seconds between each set, with muscle failure on the 2nd and 3rd sets. I warmup, stretch, lift, do core exercises (planks, crunches, raises), then 30 minutes of cardio in the moderate range. The 7th day is a rest day. I had to build up to this routine, the first 2 weeks was primarily light weight with high repetitions to get my muscles used to moving. Stretching is key to avoid injury while improving flexibility.</p><table style="border: 1px solid black" border="1">
<tbody>
<tr><th style="width: 50px">Day</th><th>Routine</th><tr><td>Monday</td><td>Bicep/tricep – incline curls, pull-downs, tricep extensions, </td></tr><tr><td>Tuesday</td><td>Legs - extensions, curls, press, calf raise, calf extension, squat</td></tr><tr><td>Wednesday</td><td>Chest/lat</td></tr><tr><td>Thursday</td><td>Legs, planks</td></tr><tr><td>Friday</td><td>Shoulders/back</td></tr><tr><td>Saturday</td><td>Legs, planks</td></tr><tr><td></td><td></td></tr></tbody></table><p>In case you aren’t quite sure what to do, consider hiring a trainer for a few sessions. Another choice is to spend some time reading and watching videos. A fantastic place is <a title="https://www.bodybuilding.com/exercises/finder/lookup/filter/muscle/id/10/muscle" href="https://www.bodybuilding.com/exercises/finder/lookup/filter/muscle/id/10/muscle">https://www.bodybuilding.com/exercises/finder/lookup/filter/muscle/id/10/muscle</a>, you can filter by muscle group and then see different exercises and how to do them correctly. This site also has a ton of different articles that suggest workout routines, compares one approach to another, etc.&nbsp; </p><p>A variation for weightlifting that I sometimes do is called “10 to 1’s”.&nbsp; Lift weight and hold for 10 seconds, lift again and hold for 9 seconds, again and hold 8 seconds… all the way down to 1. If your muscles fail, wait for just 15 seconds and start where you left off.&nbsp; </p><p>Cardio is usually the elliptical machine or StairMaster. On the elliptical machine, I put it on level 13 and use the random program, and focus on keeping my heart rate in the 145-170 range.&nbsp; I sometimes have to focus to increase my pace to force my heart rate up.&nbsp; On StairMaster, I set it to level 3 to start for 1 minute, then up to level 7-9 for 2 minutes, back down to 3 for 1 minute, back up to level 7-9 for 2 minutes, etc. I usually don’t have to watch to keep heart rate up on StairMaster, it’s usually a matter of counting down seconds until I can rest on level 3 and catch my breath for a second. </p><p>The combination of heavy weight resistance training followed by cardio increases the fat burn.&nbsp; </p><p>As I am typing this, I am also gathering my phone, headphones, Microsoft Band, and keys to go to the gym. </p><h2>Summary</h2><p>It hasn’t been easy. Sitting at dinner eating leftover chicken while my family has pizza, I’m not gonna lie… that sucks. Eating leftover vegetables while watching them enjoy french fries can be incredibly tempting. Going out to dinner and picking apart your meal to avoid the carbs can get really frustrating. Watching others drink beer or enjoy a dessert can be discouraging. My wife tries to plan meals that accommodate everyone, but often it’s a pain the ass to accommodate me.&nbsp; I have to remind myself how awesome it feels to hit a milestone, to realize I can now do something I couldn’t before, to fit into something I haven’t for years, to feel better than I have in a very long time.&nbsp; </p><p>I get terrible breath due to the ketones my body is expelling. No amount of teeth brushing or mouthwash seems to make it go away for long. I have to go to the bathroom very frequently, often at inconvenient times, because I drink so much water. I do get sick of not eating carbs, and walking through a grocery store is almost physically painful as you are literally surrounded by things you cannot enjoy, delicious breads and baked goods whose smell permeates the air. I miss sweets, and I really miss beer. No matter the downsides, nothing matters to me but feeling better than I used to, improving myself. Nothing tastes as good as losing weight feels.</p><p>My clothes don’t fit. My pants are now huge on me, I have to cinch my belt really tight. I have a few old shirts that I can now start fitting into again, but the majority of my wardrobe is way too big and looks like I borrowed someone else’s clothes. My belts look ridiculous as they wrap 1.5 times around me, with handmade holes demonstrating progress. It doesn’t make any sense to buy clothes now, I’m just going to have to buy more again soon as I continue to drop, and I can’t wait to buy them off the rack, at the mall, and not in a specialty shop for fat people.</p><p>This post is just as much a reminder to me as it is information for you. I post progress to Facebook partially to hear all the encouragement from friends, but more for accountability. I hear from so many people that I have inspired them, and friends ask how they might do the same. Living as a positive example is something I strive for but don’t often feel I live up to. This is something I can feel good about, and definitely can show my kids that hard work is required for the things you want in life.</p><p>I am now 100 pounds lighter, and it took me 5 months and 10 days to accomplish. </p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/06/100lbs.jpg"><img width="169" height="244" title="100lbs" alt="100lbs" src="https://msdnshared.blob.core.windows.net/media/2017/06/100lbs_thumb.jpg" border="0"></a></p><p>Challenge: when are you going to make the decision to start?</p><h2>Resources</h2><p><a href="https://www.ketogenicforums.com">https://www.ketogenicforums.com</a> – Forums to ask questions, see what others are going through, get recipe ideas, or just simply vent.</p><p><a href="https://www.myfitnesspal.com">https://www.myfitnesspal.com</a> – App to count carbs. You have to track all the carbs in everything from vegetables and meats to drinks and condiments. </p><p><a href="https://keto-calculator.ankerl.com">https://keto-calculator.ankerl.com</a> – Keto calculator. If you aren’t seeing progress, go fill this out and compare with what you are doing.</p><p><a title="https://www.bodybuilding.com/exercises/finder/lookup/filter/muscle/id/10/muscle" href="https://www.bodybuilding.com/exercises/finder/lookup/filter/muscle/id/10/muscle">https://www.bodybuilding.com/exercises/finder/lookup/filter/muscle/id/10/muscle</a> – Discover workout routines without hiring a personal trainer.</p>]]></content:encoded>
    </item>
    <item>
      <title>Join a SUSE Linux Enterprise Server to an Azure AD Domain Services Managed Domain</title>
      <link>https://docs.microsoft.com/archive/blogs/kaevans/join-a-suse-linux-enterprise-server-to-an-azure-ad-domain-services-managed-domain</link>
      <pubDate>Fri, 12 May 2017 12:13:00 GMT</pubDate>
      <dc:creator><![CDATA[Kirk Evans[MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaevans/?p=14466</guid>
      <description><![CDATA[This post will show how to use Azure AD Domain Services (AAD-DS) with SUSE Linux Enterprise Server...]]></description>
      <content:encoded><![CDATA[<p>This post will show how to use Azure AD Domain Services (AAD-DS) with SUSE Linux Enterprise Server (SLES).</p><h2>Background</h2><p>A customer asked how they might use AAD-DS with SLES 11 SP4 to test their product.&nbsp; I am very familiar with Windows but still very much a Linux novice, and there seems to be no easy documentation that shows how to walk through this end to end.&nbsp; There are steps for Red Hat Enterprise Linux (<a title="https://docs.microsoft.com/en-us/azure/active-directory-domain-services/active-directory-ds-admin-guide-join-rhel-linux-vm" href="https://docs.microsoft.com/en-us/azure/active-directory-domain-services/active-directory-ds-admin-guide-join-rhel-linux-vm">https://docs.microsoft.com/en-us/azure/active-directory-domain-services/active-directory-ds-admin-guide-join-rhel-linux-vm</a>), but I couldn’t find steps to do this on other Linux distros. The package managers are different (SLES uses zypper, RHEL uses yum, Ubuntu uses apt-get), and the packages to use and instructions for configuring are cryptic and archaic.&nbsp; Turns out it’s really easy to domain join a machine using SLES.</p><h2>What is Azure Active Directory Domain Services</h2><p>The Azure Active Directory service does not directly provide NTLM, Kerberos, or LDAP, it provides WS-Trust, OpenID Connect, and OAuth capabilities.&nbsp; Applications hosted in Azure virtual machines may need these legacy authentication capabilities but can’t afford the latency of communicating back to on-premises infrastructure, requiring domain controllers to be hosted in the cloud.&nbsp; Many customers do not want to install their own domain controllers in cloud-hosted virtual machines, configure a VPN or ExpressRoute, and manage AD replication to on-premises domain controllers.&nbsp; This is exactly what Azure AD Domain Services (AAD-DS) provides: a managed domain controller with the same users and groups as your AAD directory.&nbsp; AAD-DS makes it easy to join a virtual machine to the managed domain so that your application can use NTLM, Kerberos, or LDAP with the same credentials that they use to log into Office 365 or Azure services. </p><p>Azure AD Domain Services will provision managed domain controllers into the Azure Virtual Network that you specify.&nbsp; In this image, the managed domain controller virtual machines are greyed out, indicating they are there but you can’t access them or do anything with the virtual machine directly, you simply use the familiar Windows Active Directory Domain Services (ADDS) as a service.&nbsp; </p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image235.png"><img width="604" height="609" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb217.png" border="0"></a></p><p>In this picture, AAD-DS is enabled for the directory, creating two virtual machines in the subnet of my choice.&nbsp; My application server can now communicate with those domain controllers to domain join the machine and enable authentication and authorization.&nbsp; Azure AD Domain Services works with either cloud-only or hybrid directories.&nbsp; If there is an existing ADDS infrastructure on-premises, you sync users to the AAD directory using HTTPS to enable single sign on to cloud resources such as O365.&nbsp; </p><h2>Getting Started</h2><p>The documentation to set up Azure AD Domain Services is pretty easy to follow, including screen shots.&nbsp; Nothing to install on your machine, nothing to configure locally, just go to the Azure portal and follow the directions:</p><p><a title="https://docs.microsoft.com/en-us/azure/active-directory-domain-services/active-directory-ds-getting-started" href="https://docs.microsoft.com/en-us/azure/active-directory-domain-services/active-directory-ds-getting-started">https://docs.microsoft.com/en-us/azure/active-directory-domain-services/active-directory-ds-getting-started</a>&nbsp;</p><p>The result is an Azure classic virtual network with the settings you chose. </p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image236.png"><img width="604" height="212" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb218.png" border="0"></a></p><p><em>Editor:&nbsp; At the time of this writing, AAD-DS only supports classic vnets.&nbsp; I don’t have insight to the product team’s plans if they are going to enable ARM-based VNets, but I sure hope so.</em></p><p>If I need to add users or groups, I do this using Azure AD.&nbsp; </p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image237.png"><img width="604" height="289" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb219.png" border="0"></a></p><p>I also have a group that contains the users who are administrators of the AAD-DS domain, enabling them to configure things like service principals and constrained delegation.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image238.png"><img width="604" height="242" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb220.png" border="0"></a></p><p>I can now add a Windows virtual machine to the same virtual network and join the machine to the domain blueskyabove.onmicrosoft.com.&nbsp; Note that I am using a cloud-only directory, there are no users sourced from on-premises, so when I am prompted by Windows for the credentials to join a machine to the domain, I use my cloud-only account <a href="mailto:kirkevans@blueskyabove.onmicrosoft.com">kirkevans@blueskyabove.onmicrosoft.com</a>, and when I RDP to my new WIndows VM I use the same credentials.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image239.png"><img width="244" height="193" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb221.png" border="0"></a></p><p>Once logged in, open PowerShell and run the command:</p><pre>Add-WindowsFeature -Name RSAT-ADDS-Tools</pre><p>This command will add the Active Directory tools such as Users and Computers.&nbsp; Now you can view the domain information from your new Windows virtual machine.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image240.png"><img width="604" height="354" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb222.png" border="0"></a></p><p>OK, enough Windows, let’s go look at the Linux stuff we promised in the beginning of the post!</p><h2>Create a SUSE Linux Enterprise Server Virtual Machine</h2><p>In the Azure portal, create a new SUSE Linux Enterprise Server virtual machine in the same VNet that you used previously.&nbsp; Filter for “SUSE” and choose your starting image.&nbsp; I chose SLES 11 SP4.&nbsp; </p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image241.png"><img width="604" height="472" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb223.png" border="0"></a></p><p><strong><strong><strong>IMPORTANT!!! </strong></strong></strong>Make sure to create a VM using the Classic deployment model so that it can be placed in the same VNet!</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image242.png"><img width="244" height="175" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb224.png" border="0"></a></p><p>The next step enables you to provide your SSH login information and SSH public key (for more information, see <a title="https://docs.microsoft.com/en-us/azure/virtual-machines/linux/mac-create-ssh-keys" href="https://docs.microsoft.com/en-us/azure/virtual-machines/linux/mac-create-ssh-keys">https://docs.microsoft.com/en-us/azure/virtual-machines/linux/mac-create-ssh-keys</a>).&nbsp; </p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image243.png"><img width="604" height="462" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb225.png" border="0"></a></p><p>Choose a size.&nbsp; A DS1_v2 machine is plenty for my quick demo.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image244.png"><img width="604" height="429" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb226.png" border="0"></a></p><p>Create or choose a storage account and cloud service (I used the same cloud service I used with my Windows VM above).&nbsp; The important point here is that you use the same virtual network that is configured for Azure AD Domain Services.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image245.png"><img width="604" height="1370" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb227.png" border="0"></a></p><p>After a few minutes, the VM is created and I can SSH into it.&nbsp; I am using the Windows Subsystem for Linux, just open a command prompt and type “bash” to open the bash shell, and then I can run my SSH commands.</p><p><em>Editor: I received a few weird errors while trying to provision the VM, mentioning something about a certificate thumbprint cannot be found.&nbsp; I kept trying and it finally worked.&nbsp; Sometimes I guess you have to click harder.</em></p><h2>SSH Using Your Certificate</h2><p>We haven’t yet joined the VM to the domain, so we will SSH using the details we provided when creating the Azure VM.&nbsp; Once the VM is created, open the VM to see its public IP address.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image246.png"><img width="604" height="226" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb228.png" border="0"></a></p><p>Note that the public IP can change if you restart the Azure virtual machine.&nbsp; Now, go to the Endpoints property of the VM to see which port to use for SSH.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image247.png"><img width="604" height="342" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb229.png" border="0"></a></p><p>Finally, SSH:&nbsp; ssh -i azure_ssh myadmin@52.173.77.97 -p 60252</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image248.png"><img width="604" height="329" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb230.png" border="0"></a></p><p>We’re in!</p><h2>Domain Join SLES Using YaST</h2><p>The last bit we need to do is to join to the domain controller that Azure AD Domain Services provides for us.&nbsp; Since the VM is in the same VNet and we have updated the DNS settings for the VNet, the new Linux machine can locate the domain controller by name without any further configuration with “sudo /sbin/yast”.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image249.png"><img width="604" height="39" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb231.png" border="0"></a></p><p>This opens up the YaST control center.&nbsp; Choose Network Services / Windows Domain Membership.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image250.png"><img width="604" height="329" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb232.png" border="0"></a></p><p>You are prompted to install the Samba client packages.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image251.png"><img width="604" height="329" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb233.png" border="0"></a></p><p>Next, provide your domain as all capital letters, and enable the settings in the top section to enable users to SSH to the machine using their credentials from Azure AD.&nbsp; Note that I am using a cloud-only directory without a custom domain.&nbsp; If you added and verified a custom domain, and have users from that custom domain in your AAD directory from a sync, then you should use your custom domain.&nbsp; </p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image252.png"><img width="604" height="329" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb234.png" border="0"></a></p><p><em>Editor: Backspace doesn’t work for me, I had to use CTRL+H to backspace.&nbsp; Dunno.</em></p><p>Once you are done, exit and reboot the VM.&nbsp; </p><p>You may be wondering what the YaST tool just did for us.&nbsp; For a comprehensive look at the files it edited and the values it used, see <a href="https://jreypo.wordpress.com/2012/02/01/how-to-integrate-suse-linux-enterprise-11-with-windows-active-directory/">https://jreypo.wordpress.com/2012/02/01/how-to-integrate-suse-linux-enterprise-11-with-windows-active-directory/</a>.&nbsp; </p><p>You can now log in using the same credentials that you use to log into Azure AD.</p><pre>ssh blueskyabove\\kirkevans@52.173.77.97 -p 62075</pre><p>You can now SSH using your credentials from Azure AD and the user has a home directory that was created.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/05/image253.png"><img width="604" height="329" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/05/image_thumb235.png" border="0"></a></p><p>The user is not in the sudoers group.&nbsp; It is possible to enable users from a particular Active Directory group to use sudo.</p><p><a href="https://derflounder.wordpress.com/2012/12/14/adding-ad-domain-groups-to-etcsudoers/">https://derflounder.wordpress.com/2012/12/14/adding-ad-domain-groups-to-etcsudoers/</a></p><h2>For More Information</h2><p><a title="https://docs.microsoft.com/en-us/azure/active-directory-domain-services/active-directory-ds-getting-started" href="https://docs.microsoft.com/en-us/azure/active-directory-domain-services/active-directory-ds-getting-started">https://docs.microsoft.com/en-us/azure/active-directory-domain-services/active-directory-ds-getting-started</a></p><p><a title="https://docs.microsoft.com/en-us/azure/virtual-machines/linux/mac-create-ssh-keys" href="https://docs.microsoft.com/en-us/azure/virtual-machines/linux/mac-create-ssh-keys">How to create and use an SSH public and private key pair for Linux VMs in Azure</a></p><p><a href="https://docs.microsoft.com/en-us/azure/active-directory-domain-services/active-directory-ds-admin-guide-join-rhel-linux-vm">Join a Red Hat Enterprise Linux 7 virtual machine to a managed domain</a></p><p><a href="https://jreypo.wordpress.com/2012/02/01/how-to-integrate-suse-linux-enterprise-11-with-windows-active-directory/">https://jreypo.wordpress.com/2012/02/01/how-to-integrate-suse-linux-enterprise-11-with-windows-active-directory/</a></p><p><a href="https://derflounder.wordpress.com/2012/12/14/adding-ad-domain-groups-to-etcsudoers/">https://derflounder.wordpress.com/2012/12/14/adding-ad-domain-groups-to-etcsudoers/</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Creating a Node.js Application Secured by Azure AD</title>
      <link>https://docs.microsoft.com/archive/blogs/kaevans/creating-a-node-js-application-secured-by-azure-ad</link>
      <pubDate>Fri, 10 Mar 2017 07:42:00 GMT</pubDate>
      <dc:creator><![CDATA[Kirk Evans[MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaevans/?p=14176</guid>
      <description><![CDATA[This post shows how to create a Node.js application using Node.js, Bash for Windows, Visual Studio...]]></description>
      <content:encoded><![CDATA[<p>This post shows how to create a Node.js application using Node.js, Bash for Windows, Visual Studio Code, and Azure Active Directory.&nbsp; The final solution is available at <a title="https://github.com/kaevans/node-aad" href="https://github.com/kaevans/node-aad">https://github.com/kaevans/node-aad</a>.&nbsp; </p><h2>Background</h2><p>I’ve been a C# .NET developer for the past 17 years&nbsp; Sure, I’ve coded with other languages (C++, Java, JavaScript, Pascal, F#, Visual Basic, Ruby), but given a deadline I would always use C# as that is what I am most productive in, and I am very comfortable with Visual Studio.&nbsp; I recently decided to leave my comfort zone of Windows, .NET, and SQL to venture into Linux and Node.js.&nbsp; I wanted to learn how to use various Azure services using Node.js, so the first that I picked was using Azure AD to secure a web application.&nbsp; </p><p>I went to an article, <a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-devquickstarts-openidconnect-nodejs">Node.js web app sign-in and sign-out with Azure AD</a>, followed the steps, and it didn’t work.&nbsp; I went to GitHub and cloned a repository, <a title="https://github.com/AzureAD/passport-azure-ad" href="https://github.com/AzureAD/passport-azure-ad">https://github.com/AzureAD/passport-azure-ad</a>, and it didn’t work.&nbsp; After wasting a really long time trying to figure it out, I discovered that those two resources (as of today’s date) use Node.js version 4.x, which is the current Long Term Support (LTS) version of Node.&nbsp; Following the instructions below, I ended up with Node version 7.4.0.&nbsp; The versions are not backwards-compatible between major releases, which explains why I couldn’t get things to work.</p><p><a href="https://github.com/nodejs/LTS#lts-schedule"><img width="551" height="285" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image211.png" border="0"></a></p><p>You could get things to work by using a Node version manager.&nbsp; A popular one is “<a href="https://www.npmjs.com/package/n">n</a>” which lets you interactively select which version of Node you are using.&nbsp; The rest of this post assumes Node version 7.4.0.</p><p>This post is going to look scary long.&nbsp; It’s actually not that bad, I am just verbose.&nbsp; The completed solution is available at <a title="https://github.com/kaevans/node-aad" href="https://github.com/kaevans/node-aad">https://github.com/kaevans/node-aad</a>.&nbsp; </p><h2>My Environment</h2><p>I am not using a Linux desktop, just using it as a server.&nbsp; I used vi in Linux enough to realize I prefer the productivity of menus and a mouse, so I have a Windows 10 desktop running Visual Studio Code.&nbsp; However, I fell in love with Bash, so I enabled the Bash for Windows feature.&nbsp; This lets me use the Bash shell for things like Node.js (including npm) and Express web server.&nbsp; Once I code and test locally, I deploy the code to a Linux VM running in Azure.&nbsp; If you are using a Mac, you can use the Bash shell natively and you can still install Visual Studio Code.&nbsp; </p><h2>Create an Azure AD Application</h2><p>Go to the Azure portal, under Azure Active Directory / App Registrations and add a new registration.&nbsp; Create it as a Web app / API with a sign-on URL of <a href="https://localhost">https://localhost</a>.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image212.png"><img width="244" height="197" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb203.png" border="0"></a></p><p>Once created, go to the properties of your new app registration.&nbsp; The App ID URI will have a GUID, you may wish to change that GUID to the name of your app (completely an optional step, but one that I prefer).</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image213.png"><img width="244" height="151" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb204.png" border="0"></a></p><p>In this screen shot, item #1 is the application ID, also known as the client ID.&nbsp; The App ID URI is also known as the Audience URI.&nbsp; We’ll use those values in our configuration at the end of the post.</p><p>If your application will access other APIs, you will need a key.&nbsp; To do that, go to the Keys setting of your app registration and add a new key. </p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image214.png"><img width="244" height="86" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb205.png" border="0"></a></p><p>Copy this value (you won’t be able to retrieve it later).&nbsp; This key is also known as the client secret.</p><h2>Install Node.js and Express Generator</h2><p>I am going to assume that you already have Bash on Windows enabled (more details <a href="https://msdn.microsoft.com/en-us/commandline/wsl/about">here</a>), and you have Visual Studio Code installed.&nbsp; Open a command line and just type “bash” to start the Bash shell.&nbsp; This enables you to <a href="https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions">install Node.js using a package manager in Bash</a>.&nbsp; Since Bash on Windows uses Ubuntu, you need to choose the Ubuntu directions for installing Node.js.&nbsp; <pre>curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo apt-get install -y build-essential</pre><p>Now that we have Node.js, we can use the Node Package Manager (NPM) to install dependencies similar to how we’ve used NuGet for packages in Visual Studio.&nbsp; Let’s install the Express Generator that lets us quickly scaffold Node.js applications that use Express.&nbsp; We use the “-g” switch to make this a global dependency.</p>
<pre>npm install express-generator -g</pre>
<p>So, where to keep our project?&nbsp; Bash for Windows creates a mounted file system to access your Windows files, so wherever we keep them in Windows is accessible via Bash as well.&nbsp; As an example, I created a directory “Source” under my user profile.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image215.png"><img width="244" height="134" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb206.png" border="0"></a></p><p>Just for completeness sake, I am showing the same directory using the old CMD shell in Windows to prove you can easily access those files in Windows.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image216.png"><img width="244" height="134" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb207.png" border="0"></a></p><p>Now close the CMD shell, we will only use the Bash shell during this post!</p><h2>Create the Application</h2><p>Now that we have a folder to keep our new application, we need to install some libraries.&nbsp; Change directory to the Source directory and then use the Express Generator to scaffold the application.&nbsp; In the Bash shell:</p><pre>express node-aad</pre><p>Open Visual Studio Code and then open the node-aad folder that was just created.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image217.png"><img width="244" height="159" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb208.png" border="0"></a></p><p>If you go to the debug menu in VS Code and hit Start, the application will fail with an error “Exception occured Error: Cannot find module 'express'”.&nbsp; Yes, “occurred” is misspelled, but the more important thing to note is that the packages.json file contains a list of dependencies that haven’t been downloaded yet, kind of like NuGet package refresh.&nbsp; This allows you to check your project into source control without all the dependency binaries.&nbsp; To download the binaries, we go back to the Bash shell and change directory to our project’s folder.</p><pre>npm install</pre><p>The output shows all the binaries that were downloaded.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image218.png"><img width="244" height="134" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb209.png" border="0"></a></p><p>To test the application, in the Bash shell try to following:</p><pre>npm start</pre><p>Now switch to a browser and go to <a href="http://localhost:3000">http://localhost:3000</a>.&nbsp; You will see your application.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image219.png"><img width="244" height="234" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb210.png" border="0"></a></p><p>Watch the Bash shell window to see the requests.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image220.png"><img width="381" height="119" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb211.png" border="0"></a></p><p>Hit Ctrl+C to stop the server.&nbsp; We now have a working Node.js web application.&nbsp; Let’s secure it with Azure AD.</p><h2>Update Your Application to Use Azure AD with Passport</h2><p>No, I don’t mean Passport as in the precursor to Microsoft Accounts (formerly Live accounts, formerly Hotmail accounts, formerly Passport accounts), I mean Passport the authentication middleware for Node.js.&nbsp; Passport makes it easy to use different strategies for authenticating to services such as Facebook, Twitter, and more.&nbsp; We will use the passport-azure-ad package that provides an OpenId Connect strategy for authenticating to Azure AD.&nbsp; Go to the Bash shell and run the following.&nbsp; This will install the packages method-override, express-session, passport, and passport-azure-ad, and the “—save” switch will update the package.js file to include the references.</p><pre>npm install --save method-override express-session passport passport-azure-ad</pre><p>Go check package.js and you will see that it has been updated.</p><h3>Enable HTTPS</h3><p>We are using OAuth, which means we are passing a bearer token in an HTTP header, which means using HTTPS is mandatory.&nbsp; In fact, this is one of the things that didn’t work when I tried the directions for Node.js 4.x using Node.js 7.4.0… the sample I linked to in the opening paragraph allowed you to use HTTP but that doesn’t work with Node 7.4.0.&nbsp; <a href="https://docs.nodejitsu.com/articles/HTTP/servers/how-to-create-a-HTTPS-server/">Creating an HTTPS server using Express</a> is really simple.&nbsp; Go to the Bash shell and create the signing key, certificate request, and certificate, then delete the request file.</p>
<pre>openssl genrsa -out key.pem
openssl req -new -key key.pem -out csr.pem
openssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pem
rm csr.pem</pre>
<p>Now update app.js.&nbsp; At the top of the file, add the require statements for https and fs.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:5adee775-979c-4f65-b9d8-841da4c45ea4" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">Requires</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2em;padding: 0 0 0 5px">
<li><span style="color:#569cd6">var</span><span style="color:#000000"> </span><span style="color:#dcdcdc">https</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#569cd6">require</span><span style="color:#dcdcdc">(</span><span style="color:#d69d85">&#039;https&#039;</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3"><span style="color:#569cd6">var</span><span style="color:#000000"> </span><span style="color:#dcdcdc">fs</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#569cd6">require</span><span style="color:#dcdcdc">(</span><span style="color:#d69d85">&#039;fs&#039;</span><span style="color:#dcdcdc">);</span></li>
</ol>
</div>
</div>
</div><p>At the bottom of the file, just before the last line of code, add the following:</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:d6211c3c-db97-4683-8d13-b68def560d5e" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">Create HTTPS Server</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2em;padding: 0 0 0 5px">
<li><span style="color:#569cd6">var</span><span style="color:#000000"> </span><span style="color:#dcdcdc">options</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">key:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">fs.readFileSync(</span><span style="color:#d69d85">&#039;./myappkey.pem&#039;</span><span style="color:#dcdcdc">)</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">cert:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">fs.readFileSync(</span><span style="color:#d69d85">&#039;./myappcert.pem&#039;</span><span style="color:#dcdcdc">)</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span><span style="color:#dcdcdc">;</span></li>
<li><span style="color:#57a64a">// Create an HTTPS service identical to the HTTP service.</span></li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">https.createServer(options</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">app).listen(</span><span style="color:#b5cea8">443</span><span style="color:#dcdcdc">);</span></li>
</ol>
</div>
</div>
</div><p> To test, go to the Bash shell and use “npm start” to start the application, then open a browser to “https://localhost” to see your application now listens to port 443 instead of 3000.&nbsp; You may get an unhandled error:</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image221.png"><img width="383" height="173" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb212.png" border="0"></a></p><p>If that is the case, then try running it using the sudo command:</p><pre>sudo npm start app.js</pre><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image222.png"><img width="244" height="191" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb213.png" border="0"></a></p><p><em>Note: this is using a self-signed certificate and is not secure for production use. </em></p><h3>Using Passport for Authentication</h3><p>In Visual Studio Code, add a new file called config.js.&nbsp; </p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:de11e0d2-4809-439e-8392-3e9b1528a5ec" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">config.js</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2.5em;padding: 0 0 0 5px">
<li><span style="color:#dcdcdc">exports.creds</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">returnURL:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">process.env.RETURN_URL</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">identityMetadata:</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;https://login.microsoftonline.com/common/.well-known/openid-configuration&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#57a64a">// For using Microsoft you should never need to change this.</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">clientID:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">process.env.CLIENT_ID</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">clientSecret:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">process.env.CLIENT_SECRET</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#57a64a">// if you are doing code or id_token code</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">skipUserProfile:</span><span style="color:#000000"> </span><span style="color:#569cd6">true</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#57a64a">// for AzureAD should be set to true.</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">responseType:</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;id_token code&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#57a64a">// for login only flows use id_token. For accessing resources use `id_token code`</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">responseMode:</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;query&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#57a64a">// For login only flows we should have token passed back to us in a POST</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">scope:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">[</span><span style="color:#d69d85">&#039;email&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;profile&#039;</span><span style="color:#dcdcdc">]</span><span style="color:#000000"> </span><span style="color:#57a64a">// additional scopes you may wish to pass</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span><span style="color:#dcdcdc">;</span></li>
</ol>
</div>
</div>
</div><p>Notice that we do not put hard-coded values for variable items in this file, and we certainly never ever never ever put secrets (like client ID and client secret) into code.&nbsp; </p><p>Add the following to the list of “require” statements in app.js.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:5a48aeac-c31f-47b2-be55-53bd7c7c9b38" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">Require config</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2em;padding: 0 0 0 5px">
<li><span style="color:#569cd6">var</span><span style="color:#000000"> </span><span style="color:#dcdcdc">config</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#569cd6">require</span><span style="color:#dcdcdc">(</span><span style="color:#d69d85">&#039;./config&#039;</span><span style="color:#dcdcdc">);</span></li>
</ol>
</div>
</div>
</div><p><br></p><p>Beneath the require statements, add the following:</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:33ab19ed-c9ed-45b4-a6b9-38ef5bbeb448" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">Configure Passport</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2.5em;padding: 0 0 0 5px">
<li><span style="color:#57a64a">// array to hold logged in users</span></li>
<li style="background: #f3f3f3"><span style="color:#569cd6">var</span><span style="color:#000000"> </span><span style="color:#dcdcdc">users</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#dcdcdc">[];</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//   To support persistent login sessions, Passport needs to be able to</span></li>
<li><span style="color:#57a64a">//   serialize users into and deserialize users out of the session.  Typically,</span></li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//   this will be as simple as storing the user ID when serializing, and finding</span></li>
<li><span style="color:#57a64a">//   the user by ID when deserializing.</span></li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">passport.serializeUser(</span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(user</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">done)</span><span style="color:#000000"> {</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">done(</span><span style="color:#569cd6">null</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">user.oid);</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">passport.deserializeUser(</span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(id</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">done)</span><span style="color:#000000"> {</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">findByOID(id</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(err</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">user)</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#dcdcdc">done(err</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">user);</span></li>
<li>    <span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3">&nbsp;</li>
<li><span style="color:#569cd6">var</span><span style="color:#000000"> </span><span style="color:#dcdcdc">findByOID</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(oid</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">fn)</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#569cd6">for</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(</span><span style="color:#569cd6">var</span><span style="color:#000000"> </span><span style="color:#dcdcdc">i</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#b5cea8">0</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">len</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#dcdcdc">users.length;</span><span style="color:#000000"> </span><span style="color:#dcdcdc">i</span><span style="color:#000000"> </span><span style="color:#b4b4b4">&lt;</span><span style="color:#000000"> </span><span style="color:#dcdcdc">len;</span><span style="color:#000000"> </span><span style="color:#dcdcdc">i</span><span style="color:#b4b4b4">++</span><span style="color:#dcdcdc">)</span><span style="color:#000000"> {</span></li>
<li>        <span style="color:#000000"></span><span style="color:#569cd6">var</span><span style="color:#000000"> </span><span style="color:#dcdcdc">user</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#dcdcdc">users[i];</span></li>
<li style="background: #f3f3f3">&nbsp;</li>
<li>        <span style="color:#000000"></span><span style="color:#569cd6">if</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(user.oid</span><span style="color:#000000"> </span><span style="color:#b4b4b4">===</span><span style="color:#000000"> </span><span style="color:#dcdcdc">oid)</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#569cd6">return</span><span style="color:#000000"> </span><span style="color:#dcdcdc">fn(</span><span style="color:#569cd6">null</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">user);</span></li>
<li>        <span style="color:#000000">}</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000">}</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">console.log(</span><span style="color:#d69d85">&quot;Did not find user by OID: &quot;</span><span style="color:#000000"> </span><span style="color:#b4b4b4">+</span><span style="color:#000000"> </span><span style="color:#dcdcdc">oid);</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#569cd6">return</span><span style="color:#000000"> </span><span style="color:#dcdcdc">fn(</span><span style="color:#569cd6">null</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#569cd6">null</span><span style="color:#dcdcdc">);</span></li>
<li><span style="color:#000000">}</span><span style="color:#dcdcdc">;</span></li>
<li style="background: #f3f3f3">&nbsp;</li>
<li><span style="color:#57a64a">// Use the OIDCStrategy within Passport. (Section 2) </span></li>
<li style="background: #f3f3f3"><span style="color:#57a64a">// </span></li>
<li><span style="color:#57a64a">//   Strategies in passport require a `validate` function, which accept</span></li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//   credentials (in this case, an OpenID identifier), and invoke a callback</span></li>
<li><span style="color:#57a64a">//   with a user object.</span></li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">passport.use(</span><span style="color:#569cd6">new</span><span style="color:#000000"> </span><span style="color:#dcdcdc">OIDCStrategy({</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">callbackURL:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">config.creds.returnURL</span><span style="color:#b4b4b4">,</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">redirectUrl:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">config.creds.redirectUrl</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">realm:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">config.creds.realm</span><span style="color:#b4b4b4">,</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">clientID:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">config.creds.clientID</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">clientSecret:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">config.creds.clientSecret</span><span style="color:#b4b4b4">,</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">oidcIssuer:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">config.creds.issuer</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">identityMetadata:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">config.creds.identityMetadata</span><span style="color:#b4b4b4">,</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">skipUserProfile:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">config.creds.skipUserProfile</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">responseType:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">config.creds.responseType</span><span style="color:#b4b4b4">,</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">responseMode:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">config.creds.responseMode</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">scope:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">config.creds.scope</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(iss</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">sub</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">profile</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">accessToken</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">refreshToken</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">done)</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#569cd6">if</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(</span><span style="color:#b4b4b4">!</span><span style="color:#dcdcdc">profile.oid)</span><span style="color:#000000"> {</span></li>
<li>            <span style="color:#000000"></span><span style="color:#dcdcdc">console.log(util.inspect(profile));</span></li>
<li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#569cd6">return</span><span style="color:#000000"> </span><span style="color:#dcdcdc">done(</span><span style="color:#569cd6">new</span><span style="color:#000000"> </span><span style="color:#dcdcdc">Error(</span><span style="color:#d69d85">&quot;No OID found&quot;</span><span style="color:#dcdcdc">)</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#569cd6">null</span><span style="color:#dcdcdc">);</span></li>
<li>        <span style="color:#000000">}</span></li>
<li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#57a64a">// asynchronous verification, for effect...</span></li>
<li>        <span style="color:#000000"></span><span style="color:#dcdcdc">process.nextTick(</span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">()</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#dcdcdc">findByOID(profile.oid</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(err</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">user)</span><span style="color:#000000"> {</span></li>
<li>                <span style="color:#000000"></span><span style="color:#569cd6">if</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(err)</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">                    <span style="color:#000000"></span><span style="color:#569cd6">return</span><span style="color:#000000"> </span><span style="color:#dcdcdc">done(err);</span></li>
<li>                <span style="color:#000000">}</span></li>
<li style="background: #f3f3f3">                <span style="color:#000000"></span><span style="color:#569cd6">if</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(</span><span style="color:#b4b4b4">!</span><span style="color:#dcdcdc">user)</span><span style="color:#000000"> {</span></li>
<li>                    <span style="color:#000000"></span><span style="color:#57a64a">// &quot;Auto-registration&quot;</span></li>
<li style="background: #f3f3f3">                    <span style="color:#000000"></span><span style="color:#dcdcdc">users.push(profile);</span></li>
<li>                    <span style="color:#000000"></span><span style="color:#569cd6">return</span><span style="color:#000000"> </span><span style="color:#dcdcdc">done(</span><span style="color:#569cd6">null</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">profile);</span></li>
<li style="background: #f3f3f3">                <span style="color:#000000">}</span></li>
<li>                <span style="color:#000000"></span><span style="color:#569cd6">return</span><span style="color:#000000"> </span><span style="color:#dcdcdc">done(</span><span style="color:#569cd6">null</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">user);</span></li>
<li style="background: #f3f3f3">            <span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li>        <span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000">}</span></li>
<li><span style="color:#dcdcdc">));</span></li>
</ol>
</div>
</div>
</div><p><br></p><p>Next, we create the app object and tell it what middleware to inject.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:ee1414b1-2312-4417-ba52-aee228133beb" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">App middleware</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2.5em;padding: 0 0 0 5px">
<li><span style="color:#569cd6">var</span><span style="color:#000000"> </span><span style="color:#dcdcdc">app</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#dcdcdc">express();</span></li>
<li style="background: #f3f3f3">&nbsp;</li>
<li><span style="color:#57a64a">// view engine setup</span></li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">app.set(</span><span style="color:#d69d85">&#039;views&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">path.join(__dirname</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;views&#039;</span><span style="color:#dcdcdc">));</span></li>
<li><span style="color:#dcdcdc">app.set(</span><span style="color:#d69d85">&#039;view engine&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;jade&#039;</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3">&nbsp;</li>
<li><span style="color:#57a64a">// uncomment after placing your favicon in /public</span></li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//app.use(favicon(path.join(__dirname, &#039;public&#039;, &#039;favicon.ico&#039;)));</span></li>
<li><span style="color:#dcdcdc">app.use(logger(</span><span style="color:#d69d85">&#039;dev&#039;</span><span style="color:#dcdcdc">));</span></li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">app.use(methodOverride());</span></li>
<li><span style="color:#dcdcdc">app.use(bodyParser.json());</span></li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">app.use(bodyParser.urlencoded({</span><span style="color:#000000"> </span><span style="color:#dcdcdc">extended:</span><span style="color:#000000"> </span><span style="color:#569cd6">true</span><span style="color:#000000"> }</span><span style="color:#dcdcdc">));</span></li>
<li><span style="color:#dcdcdc">app.use(cookieParser());</span></li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">app.use(session({</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">secret:</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;keyboard cat&#039;</span><span style="color:#b4b4b4">,</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">resave:</span><span style="color:#000000"> </span><span style="color:#569cd6">true</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">saveUninitialized:</span><span style="color:#000000"> </span><span style="color:#569cd6">false</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span><span style="color:#dcdcdc">));</span></li>
<li><span style="color:#57a64a">//Initialize Passport</span></li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">app.use(passport.initialize());</span></li>
<li><span style="color:#dcdcdc">app.use(passport.session());</span></li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">app.use(express.static(path.join(__dirname</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;public&#039;</span><span style="color:#dcdcdc">)));</span></li>
</ol>
</div>
</div>
</div><p><br></p><p>Finally we add our routes.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:dcc9282e-e081-4583-8cdf-cff60c43a3da" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">Routes</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2.5em;padding: 0 0 0 5px">
<li><span style="color:#57a64a">// GET /auth/openid</span></li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//   Use passport.authenticate() as route middleware to authenticate the</span></li>
<li><span style="color:#57a64a">//   request. The first step in OpenID authentication involves redirecting</span></li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//   the user to their OpenID provider. After authenticating, the OpenID</span></li>
<li><span style="color:#57a64a">//   provider redirects the user back to this application at</span></li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//   /auth/openid/return.</span></li>
<li><span style="color:#dcdcdc">app.get(</span><span style="color:#d69d85">&#039;/auth/openid&#039;</span><span style="color:#b4b4b4">,</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">passport.authenticate(</span><span style="color:#d69d85">&#039;azuread-openidconnect&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> {</span><span style="color:#000000"> </span><span style="color:#dcdcdc">failureRedirect:</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;/login&#039;</span><span style="color:#000000"> }</span><span style="color:#dcdcdc">)</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(req</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">res)</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#dcdcdc">console.log(</span><span style="color:#d69d85">&#039;Authentication was called in the Sample&#039;</span><span style="color:#dcdcdc">);</span></li>
<li>        <span style="color:#000000"></span><span style="color:#dcdcdc">res.redirect(</span><span style="color:#d69d85">&#039;/&#039;</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#57a64a">// GET /auth/openid/return</span></li>
<li><span style="color:#57a64a">//   Use passport.authenticate() as route middleware to authenticate the</span></li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//   request. If authentication fails, the user is redirected back to the</span></li>
<li><span style="color:#57a64a">//   sign-in page. Otherwise, the primary route function is called,</span></li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//   which, in this example, redirects the user to the home page.</span></li>
<li><span style="color:#dcdcdc">app.get(</span><span style="color:#d69d85">&#039;/auth/openid/return&#039;</span><span style="color:#b4b4b4">,</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">passport.authenticate(</span><span style="color:#d69d85">&#039;azuread-openidconnect&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> {</span><span style="color:#000000"> </span><span style="color:#dcdcdc">failureRedirect:</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;/login&#039;</span><span style="color:#000000"> }</span><span style="color:#dcdcdc">)</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(req</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">res)</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#dcdcdc">console.log(</span><span style="color:#d69d85">&#039;We received a return from AzureAD.&#039;</span><span style="color:#dcdcdc">);</span></li>
<li>        <span style="color:#000000"></span><span style="color:#dcdcdc">res.redirect(</span><span style="color:#d69d85">&#039;/&#039;</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#57a64a">// POST /auth/openid/return</span></li>
<li><span style="color:#57a64a">//   Use passport.authenticate() as route middleware to authenticate the</span></li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//   request. If authentication fails, the user is redirected back to the</span></li>
<li><span style="color:#57a64a">//   sign-in page. Otherwise, the primary route function is called,</span></li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//   which, in this example, redirects the user to the home page.</span></li>
<li><span style="color:#dcdcdc">app.post(</span><span style="color:#d69d85">&#039;/auth/openid/return&#039;</span><span style="color:#b4b4b4">,</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">passport.authenticate(</span><span style="color:#d69d85">&#039;azuread-openidconnect&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> {</span><span style="color:#000000"> </span><span style="color:#dcdcdc">failureRedirect:</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;/login&#039;</span><span style="color:#000000"> }</span><span style="color:#dcdcdc">)</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(req</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">res)</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#dcdcdc">console.log(</span><span style="color:#d69d85">&#039;We received a return from AzureAD.&#039;</span><span style="color:#dcdcdc">);</span></li>
<li>        <span style="color:#000000"></span><span style="color:#dcdcdc">res.redirect(</span><span style="color:#d69d85">&#039;/&#039;</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3">&nbsp;</li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//Routes (section 4)</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">app.get(</span><span style="color:#d69d85">&#039;/&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">index);</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">app.get(</span><span style="color:#d69d85">&#039;/account&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">ensureAuthenticated</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(req</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">res)</span><span style="color:#000000"> {</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">res.render(</span><span style="color:#d69d85">&#039;account&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> {</span><span style="color:#000000"> </span><span style="color:#dcdcdc">user:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">req.user</span><span style="color:#000000"> }</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">app.get(</span><span style="color:#d69d85">&#039;/login&#039;</span><span style="color:#b4b4b4">,</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">passport.authenticate(</span><span style="color:#d69d85">&#039;azuread-openidconnect&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> {</span><span style="color:#000000"> </span><span style="color:#dcdcdc">failureRedirect:</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;/login&#039;</span><span style="color:#000000"> }</span><span style="color:#dcdcdc">)</span><span style="color:#b4b4b4">,</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(req</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">res)</span><span style="color:#000000"> {</span></li>
<li>        <span style="color:#000000"></span><span style="color:#dcdcdc">console.log(</span><span style="color:#d69d85">&#039;Login was called in the Sample&#039;</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#dcdcdc">res.redirect(</span><span style="color:#d69d85">&#039;/&#039;</span><span style="color:#dcdcdc">);</span></li>
<li>    <span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3">&nbsp;</li>
<li><span style="color:#dcdcdc">app.get(</span><span style="color:#d69d85">&#039;/logout&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(req</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">res)</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">req.logout();</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">res.redirect(</span><span style="color:#d69d85">&#039;/&#039;</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3">&nbsp;</li>
<li><span style="color:#57a64a">// catch 404 and forward to error handler</span></li>
<li style="background: #f3f3f3"><span style="color:#dcdcdc">app.use(</span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(req</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">res</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">next)</span><span style="color:#000000"> {</span></li>
<li>    <span style="color:#000000"></span><span style="color:#569cd6">var</span><span style="color:#000000"> </span><span style="color:#dcdcdc">err</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#569cd6">new</span><span style="color:#000000"> </span><span style="color:#dcdcdc">Error(</span><span style="color:#d69d85">&#039;Not Found&#039;</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">err.status</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#b5cea8">404</span><span style="color:#dcdcdc">;</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">next(err);</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#57a64a">// error handler</span></li>
<li><span style="color:#dcdcdc">app.use(</span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(err</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">req</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">res</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">next)</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#57a64a">// set locals, only providing error in development</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">res.locals.message</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#dcdcdc">err.message;</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">res.locals.error</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#dcdcdc">req.app.get(</span><span style="color:#d69d85">&#039;env&#039;</span><span style="color:#dcdcdc">)</span><span style="color:#000000"> </span><span style="color:#b4b4b4">===</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;development&#039;</span><span style="color:#000000"> </span><span style="color:#dcdcdc">?</span><span style="color:#000000"> </span><span style="color:#dcdcdc">err</span><span style="color:#000000"> </span><span style="color:#dcdcdc">:</span><span style="color:#000000"> {}</span><span style="color:#dcdcdc">;</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#57a64a">// render the error page</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">res.status(err.status</span><span style="color:#000000"> </span><span style="color:#b4b4b4">||</span><span style="color:#000000"> </span><span style="color:#b5cea8">500</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">res.render(</span><span style="color:#d69d85">&#039;error&#039;</span><span style="color:#dcdcdc">);</span></li>
<li><span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3">&nbsp;</li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#57a64a">// Simple route middleware to ensure user is authenticated. (section 4)</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//   Use this route middleware on any resource that needs to be protected. If</span></li>
<li><span style="color:#57a64a">//   the request is authenticated (typically via a persistent sign-in session),</span></li>
<li style="background: #f3f3f3"><span style="color:#57a64a">//   the request proceeds. Otherwise, the user is redirected to the</span></li>
<li><span style="color:#57a64a">//   sign-in page.</span></li>
<li style="background: #f3f3f3"><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">ensureAuthenticated(req</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">res</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">next)</span><span style="color:#000000"> {</span></li>
<li>    <span style="color:#000000"></span><span style="color:#569cd6">if</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(req.isAuthenticated())</span><span style="color:#000000"> {</span><span style="color:#000000"> </span><span style="color:#569cd6">return</span><span style="color:#000000"> </span><span style="color:#dcdcdc">next();</span><span style="color:#000000"> }</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">res.redirect(</span><span style="color:#d69d85">&#039;/login&#039;</span><span style="color:#dcdcdc">)</span></li>
<li><span style="color:#000000">}</span></li>
</ol>
</div>
</div>
</div><p><br></p><h2>Making It Readable</h2><p>We now turn to making it readable so someone can actually use our application.&nbsp; Let’s update the controller for the Index view to pass both the user and the title to the view.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:22ee21d7-afe5-44ff-ae4e-06850894daa5" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">Index.js</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2.5em;padding: 0 0 0 5px">
<li><span style="color:#569cd6">var</span><span style="color:#000000"> </span><span style="color:#dcdcdc">express</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#569cd6">require</span><span style="color:#dcdcdc">(</span><span style="color:#d69d85">&#039;express&#039;</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3"><span style="color:#569cd6">var</span><span style="color:#000000"> </span><span style="color:#dcdcdc">router</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#dcdcdc">express.Router();</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#57a64a">/* GET home page. */</span></li>
<li><span style="color:#dcdcdc">router.get(</span><span style="color:#d69d85">&#039;/&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#569cd6">function</span><span style="color:#000000"> </span><span style="color:#dcdcdc">(req</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">res</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">next)</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#dcdcdc">console.log(</span><span style="color:#d69d85">&#039;index was called&#039;</span><span style="color:#dcdcdc">);</span></li>
<li>    <span style="color:#000000"></span><span style="color:#dcdcdc">res.render(</span><span style="color:#d69d85">&#039;index&#039;</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> {</span><span style="color:#000000"> </span><span style="color:#dcdcdc">user:</span><span style="color:#000000"> </span><span style="color:#dcdcdc">req.user</span><span style="color:#b4b4b4">,</span><span style="color:#000000"> </span><span style="color:#dcdcdc">title:</span><span style="color:#000000"> </span><span style="color:#d69d85">&#039;Express&#039;</span><span style="color:#000000"> }</span><span style="color:#dcdcdc">);</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span><span style="color:#dcdcdc">);</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#569cd6">module</span><span style="color:#dcdcdc">.exports</span><span style="color:#000000"> </span><span style="color:#b4b4b4">=</span><span style="color:#000000"> </span><span style="color:#dcdcdc">router;</span></li>
</ol>
</div>
</div>
</div><p><br></p><p>Now let’s update the view.&nbsp; </p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:2f4a4bab-b603-4f03-b08a-3163bc90c532" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">index.jade</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2em;padding: 0 0 0 5px">
<li><span style="color:#ff4500">extends</span><span style="color:#000000"> layout</span></li>
<li style="background: #f3f3f3">&nbsp;</li>
<li><span style="color:#ff4500">block</span><span style="color:#000000"> content</span></li>
<li style="background: #f3f3f3">  <span style="color:#000000"></span><span style="color:#800000">h1</span><span style="color:#0000ff">=</span><span style="color:#000000"> title</span></li>
<li>  <span style="color:#000000"></span><span style="color:#800000">p</span><span style="color:#000000"> Welcome to </span><span style="color:#0000ff">#{title}</span></li>
</ol>
</div>
</div>
</div><p><br></p><p>Notice the Jade file starts with “extends layout”.&nbsp; We can use this like a master page in ASP.NET (or a layout in ASP.NET MVC).&nbsp; Update the layout.jade file.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:849965ce-988a-4fe4-b48f-9c5ce70781f8" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">layout.jade</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2.5em;padding: 0 0 0 5px">
<li><span style="color:#800000">doctype</span><span style="color:#000000"> html</span></li>
<li style="background: #f3f3f3"><span style="color:#800000">html</span></li>
<li>  <span style="color:#000000"></span><span style="color:#800000">head</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#800000">title</span><span style="color:#0000ff">=</span><span style="color:#000000"> title</span></li>
<li>    <span style="color:#000000"></span><span style="color:#800000">link</span><span style="color:#000000">(</span><span style="color:#ff0000">rel</span><span style="color:#0000ff">=&#039;stylesheet&#039;</span><span style="color:#000000">, </span><span style="color:#ff0000">href</span><span style="color:#0000ff">=&#039;/stylesheets/style.css&#039;</span><span style="color:#000000">)</span></li>
<li style="background: #f3f3f3">  <span style="color:#000000"></span><span style="color:#800000">body</span></li>
<li>    <span style="color:#000000"></span><span style="color:#800000">div</span><span style="color:#000000">(</span><span style="color:#ff0000">id</span><span style="color:#0000ff">=&quot;navbar&quot;</span><span style="color:#000000">)</span></li>
<li style="background: #f3f3f3">      <span style="color:#000000"></span><span style="color:#0000ff">if</span><span style="color:#000000"> user      </span></li>
<li>        <span style="color:#000000"></span><span style="color:#800000">span</span></li>
<li style="background: #f3f3f3">          <span style="color:#000000"></span><span style="color:#800000">a</span><span style="color:#000000">(</span><span style="color:#ff0000">href</span><span style="color:#0000ff">=&quot;/&quot;</span><span style="color:#000000">) Home</span></li>
<li>        <span style="color:#000000"></span><span style="color:#800000">span</span></li>
<li style="background: #f3f3f3">          <span style="color:#000000"></span><span style="color:#800000">a</span><span style="color:#000000">(</span><span style="color:#ff0000">href</span><span style="color:#0000ff">=&quot;/account&quot;</span><span style="color:#000000">) Account</span></li>
<li>        <span style="color:#000000"></span><span style="color:#800000">span</span><span style="color:#000000"> </span></li>
<li style="background: #f3f3f3">          <span style="color:#000000"></span><span style="color:#800000">a</span><span style="color:#000000">(</span><span style="color:#ff0000">href</span><span style="color:#0000ff">=&quot;/logout&quot;</span><span style="color:#000000">) Log out</span></li>
<li>      <span style="color:#000000">      </span><span style="color:#0000ff">else</span><span style="color:#000000"></span></li>
<li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#800000">span</span></li>
<li>          <span style="color:#000000"></span><span style="color:#800000">a</span><span style="color:#000000">(</span><span style="color:#ff0000">href</span><span style="color:#0000ff">=&quot;/&quot;</span><span style="color:#000000">) Home</span></li>
<li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#800000">span</span></li>
<li>          <span style="color:#000000"></span><span style="color:#800000">a</span><span style="color:#000000">(</span><span style="color:#ff0000">href</span><span style="color:#0000ff">=&quot;/login&quot;</span><span style="color:#000000">) Log in</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#ff4500">block</span><span style="color:#000000"> content</span></li>
</ol>
</div>
</div>
</div><p><br></p><p>In our app.js file, there’s a route for /account.&nbsp; We need a view for that as well.&nbsp; Add a new “account.jade” file in the views folder.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:d5c518b7-d64b-476b-86ee-7e304cd330e7" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">account.jade</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2.5em;padding: 0 0 0 5px">
<li><span style="color:#ff4500">extends</span><span style="color:#000000"> layout</span></li>
<li style="background: #f3f3f3">&nbsp;</li>
<li><span style="color:#ff4500">block</span><span style="color:#000000"> content</span></li>
<li style="background: #f3f3f3">  <span style="color:#000000"></span><span style="color:#0000ff">if</span><span style="color:#000000"> user</span></li>
<li>    <span style="color:#000000"></span><span style="color:#800000">p</span><span style="color:#000000"> displayName: </span><span style="color:#0000ff">#{user.displayName}</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#800000">p</span><span style="color:#000000"> givenName: </span><span style="color:#0000ff">#{user.givenName}</span></li>
<li>    <span style="color:#000000"></span><span style="color:#800000">p</span><span style="color:#000000"> familyName: </span><span style="color:#0000ff">#{user.familyName}</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#800000">p</span><span style="color:#000000"> UPN: </span><span style="color:#0000ff">#{user._json.upn</span><span style="color:#000000"> }</span></li>
<li>  <span style="color:#000000">    </span><span style="color:#800000">p</span><span style="color:#000000"> Profile ID: </span><span style="color:#0000ff">#{user.id}</span><span style="color:#000000"></span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#800000">p</span><span style="color:#0000ff">=</span><span style="color:#000000">JSON.stringify(user)</span></li>
<li>    <span style="color:#000000"></span><span style="color:#800000">a</span><span style="color:#000000">(</span><span style="color:#ff0000">href</span><span style="color:#0000ff">=&quot;/logout&quot;</span><span style="color:#000000">) Log out</span></li>
<li style="background: #f3f3f3">  <span style="color:#000000"></span><span style="color:#0000ff">else</span></li>
<li>    <span style="color:#000000"></span><span style="color:#800000">h1</span><span style="color:#000000"> Please log in</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#800000">a</span><span style="color:#000000">(</span><span style="color:#ff0000">href</span><span style="color:#0000ff">=&quot;/login&quot;</span><span style="color:#000000">) Log in</span></li>
</ol>
</div>
</div>
</div><h2><br></h2><p>The last thing we need to do it to add a little styling so the navigation is easier to read.&nbsp; Update style.css in the public/stylesheets folder to include padding.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:4231aa53-eb02-4d2d-8dbb-6602d4b2105b" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">style.css</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2.5em;padding: 0 0 0 5px">
<li><span style="color:#800000">body</span><span style="color:#000000"> {</span></li>
<li style="background: #f3f3f3">  <span style="color:#000000"></span><span style="color:#ff0000">padding</span><span style="color:#000000">: </span><span style="color:#0000ff">50px</span><span style="color:#000000">;</span></li>
<li>  <span style="color:#000000"></span><span style="color:#ff0000">font</span><span style="color:#000000">: </span><span style="color:#0000ff">14px</span><span style="color:#000000"> </span><span style="color:#0000ff">&quot;Lucida Grande&quot;</span><span style="color:#000000">, </span><span style="color:#0000ff">Helvetica</span><span style="color:#000000">, </span><span style="color:#0000ff">Arial</span><span style="color:#000000">, </span><span style="color:#0000ff">sans-serif</span><span style="color:#000000">;</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#800000">a</span><span style="color:#000000"> {</span></li>
<li>  <span style="color:#000000"></span><span style="color:#ff0000">color</span><span style="color:#000000">: </span><span style="color:#0000ff">#00B7FF</span><span style="color:#000000">;</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span></li>
<li>&nbsp;</li>
<li style="background: #f3f3f3"><span style="color:#800000">#navbar</span><span style="color:#000000"> </span><span style="color:#800000">span{</span></li>
<li>  <span style="color:#000000"></span><span style="color:#ff0000">padding-right</span><span style="color:#000000">: </span><span style="color:#0000ff">20px</span><span style="color:#000000">;  </span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span></li>
</ol>
</div>
</div>
</div><p><br></p><h2>Check It In</h2><p>We want to commit the code to git, but we don’t need to commit all those dependencies.&nbsp; In the root of the project, create a file “.gitignore” and add the following:</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:47f3881e-a866-4193-a8ca-f65744872ac0" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">.gitignore</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2em;padding: 0 0 0 5px">
<li><span style="color:#000000"># .gitignore</span></li>
<li style="background: #f3f3f3"><span style="color:#000000"> </span></li>
<li><span style="color:#000000">node_modules</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">.vscode</span></li>
<li><span style="color:#000000">*.pem</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">*.log</span></li>
</ol>
</div>
</div>
</div><p>This will prevent checking in any files in the node_modules folder, the .vscode folder (will be created in the next step), the certificates for the HTTPS server, or any log files.</p><p>In VS Code, you can now go to the Git tool and initialize the repository and check your changes in.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image223.png"><img width="50" height="243" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb214.png" border="0"></a></p><h2>Test It Out</h2><p>Our config.js file uses a lot of environment variables.&nbsp; We need a way to pass those into our program when debugging locally.&nbsp; One way is to use the Bash command:</p><p><code>sudo CLIENT_ID=YOUR CLIENT_ID CLIENT_SECRET=YOUR_APP_SECRET_KEY REDIRECT_URL=https://localhost/auth/openid/return node app.js </code></p><p>Replace the placeholders for client ID and app secret with the values from your Azure AD app.&nbsp; </p><p>Another way to do this is to set the environment information within VS Code.&nbsp; Go to the debugging tab, then click Settings.&nbsp; </p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image224.png"><img width="244" height="173" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb215.png" border="0"></a></p><p>That will create a .vscode/launch.json file that makes it easy for you to configure the environment variables necessary for debugging your application without creating a script or actually setting those variables for your environment.&nbsp; Replace with the values for your Azure AD application.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:65875295-b23b-444e-8ff7-5296f036f3be" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">launch.json</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2.5em;padding: 0 0 0 5px">
<li>{</li>
<li style="background: #f3f3f3">  <span style="color:#000000"></span><span style="color:#008000">// Use IntelliSense to learn about possible Node.js debug attributes.</span></li>
<li>  <span style="color:#000000"></span><span style="color:#008000">// Hover to view descriptions of existing attributes.</span></li>
<li style="background: #f3f3f3">  <span style="color:#000000"></span><span style="color:#008000">// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387</span></li>
<li>  <span style="color:#000000"></span><span style="color:#2e75b6">&quot;version&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;0.2.0&quot;</span><span style="color:#000000">,</span></li>
<li style="background: #f3f3f3">  <span style="color:#000000"></span><span style="color:#2e75b6">&quot;configurations&quot;</span><span style="color:#000000">:</span></li>
<li>  <span style="color:#000000">[</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000">{</span></li>
<li>      <span style="color:#000000"></span><span style="color:#2e75b6">&quot;type&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;node&quot;</span><span style="color:#000000">,</span></li>
<li style="background: #f3f3f3">      <span style="color:#000000"></span><span style="color:#2e75b6">&quot;request&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;launch&quot;</span><span style="color:#000000">,</span></li>
<li>      <span style="color:#000000"></span><span style="color:#2e75b6">&quot;name&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;Launch Program&quot;</span><span style="color:#000000">,</span></li>
<li style="background: #f3f3f3">      <span style="color:#000000"></span><span style="color:#2e75b6">&quot;program&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;${workspaceRoot}/app.js&quot;</span><span style="color:#000000">,</span></li>
<li>      <span style="color:#000000"></span><span style="color:#2e75b6">&quot;env&quot;</span><span style="color:#000000">:</span></li>
<li style="background: #f3f3f3">      <span style="color:#000000">{</span></li>
<li>        <span style="color:#000000"></span><span style="color:#2e75b6">&quot;CLIENT_ID&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;2f992fd9-04dc-4809-931f-3b5eca6405f3&quot;</span><span style="color:#000000">,</span></li>
<li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#2e75b6">&quot;CLIENT_SECRET&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;6abc/rABCabcaaABCabcabcdefcjABsABCu1ABGabSg=&quot;</span><span style="color:#000000">,</span></li>
<li>        <span style="color:#000000"></span><span style="color:#2e75b6">&quot;REDIRECT_URL&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;https://localhost/auth/openid/return&quot;</span><span style="color:#000000">,</span></li>
<li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#2e75b6">&quot;AUDIENCE&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;https://BlueSkyAbove.onmicrosoft.com/node-aad&quot;</span><span style="color:#000000">,</span></li>
<li>        <span style="color:#000000"></span><span style="color:#2e75b6">&quot;IDENTITY_METADATA&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;https://login.microsoftonline.com/blueskyabove.onmicrosoft.com/.well-known/openid-configuration&quot;</span></li>
<li style="background: #f3f3f3">      <span style="color:#000000">}</span></li>
<li>    <span style="color:#000000">},</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000">{</span></li>
<li>      <span style="color:#000000"></span><span style="color:#2e75b6">&quot;type&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;node&quot;</span><span style="color:#000000">,</span></li>
<li style="background: #f3f3f3">      <span style="color:#000000"></span><span style="color:#2e75b6">&quot;request&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;attach&quot;</span><span style="color:#000000">,</span></li>
<li>      <span style="color:#000000"></span><span style="color:#2e75b6">&quot;name&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;Attach to Process&quot;</span><span style="color:#000000">,</span></li>
<li style="background: #f3f3f3">      <span style="color:#000000"></span><span style="color:#2e75b6">&quot;address&quot;</span><span style="color:#000000">: </span><span style="color:#a31515">&quot;localhost&quot;</span><span style="color:#000000">,</span></li>
<li>      <span style="color:#000000"></span><span style="color:#2e75b6">&quot;port&quot;</span><span style="color:#000000">: 5858</span></li>
<li style="background: #f3f3f3">    <span style="color:#000000">}</span></li>
<li>  <span style="color:#000000">]</span></li>
<li style="background: #f3f3f3"><span style="color:#000000">}</span></li>
</ol>
</div>
</div>
</div><h2><br></h2><p>In VS Code, you can now click the Debug button to start debugging, giving you access to breakpoints, step-through, watch locals, etc.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image225.png"><img width="244" height="172" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb216.png" border="0"></a></p><p>Now open a browser in InPrivate (Internet Explorer) or Incognito (Chrome) to ignore existing cookies.&nbsp; Navigate to <a href="https://localhost">https://localhost</a> and you will see your new application!</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image226.png"><img width="244" height="197" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb217.png" border="0"></a></p><p>Click Log In and see that you are prompted to log into Azure AD.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image227.png"><img width="244" height="153" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb218.png" border="0"></a></p><p>Once you log in, the UI changes to indicate you are logged in.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image228.png"><img width="244" height="228" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb219.png" border="0"></a></p><p>Click Account to see details about the claims in your token.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/image229.png"><img width="244" height="147" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/03/image_thumb220.png" border="0"></a></p><h2>Git the Source</h2><p>If you weren’t able to follow along or just want to download the source, the completed solution is available at <a title="https://github.com/kaevans/node-aad" href="https://github.com/kaevans/node-aad">https://github.com/kaevans/node-aad</a>.&nbsp; At a command line:</p><pre>git clone https://github.com/kaevans/node-aad.git</pre><p>To run the application, you will need to complete a few steps:</p><ol><li>The node modules are not checked into source, but are referenced in the package.json file.&nbsp; Just change directory to the project root and use the command “npm install” to download all of the dependencies so that you can debug locally.&nbsp; Checking these into source would bloat your repository needlessly.&nbsp; </li><li>The certificates are not checked into source (these are secrets).&nbsp; Follow the directions above for using openssl to generate the certificates.&nbsp; Do not check these into source!</li><li>The .vscode/launch.json is not checked into source (it has secrets in it).&nbsp; Follow the directions above for creating/modifying the .vscode/launch.json file.&nbsp; Do not check this into source!</li></ol><h2>For More Information</h2><p><a title="https://msdn.microsoft.com/en-us/commandline/wsl/about" href="https://msdn.microsoft.com/en-us/commandline/wsl/about">Bash on Windows</a></p><p><a href="https://docs.nodejitsu.com/articles/HTTP/servers/how-to-create-a-HTTPS-server/">Creating an HTTPS server using Express</a></p><p><a title="https://github.com/kaevans/node-aad" href="https://github.com/kaevans/node-aad">https://github.com/kaevans/node-aad</a> – Completed source code</p><p><a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-devquickstarts-openidconnect-nodejs">Node.js web app sign-in and sign-out with Azure AD</a> – instructions to build a Node.js 4.x application, some changes required for a 7.x application.</p><p><a title="https://github.com/AzureAD/passport-azure-ad" href="https://github.com/AzureAD/passport-azure-ad">https://github.com/AzureAD/passport-azure-ad</a> – Completed sample for a Node.js 4.x application, some changes required for a 7.x application.</p>]]></content:encoded>
    </item>
    <item>
      <title>Using Azure KeyVault to Store Secrets</title>
      <link>https://docs.microsoft.com/archive/blogs/kaevans/using-azure-keyvault-to-store-secrets</link>
      <pubDate>Mon, 31 Oct 2016 06:14:00 GMT</pubDate>
      <dc:creator><![CDATA[Kirk Evans[MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaevans/?p=13865</guid>
      <description><![CDATA[I have deleted the contents of this post as it demonstrated how to use clientID and clientSecret to...]]></description>
      <content:encoded><![CDATA[I have deleted the contents of this post as it demonstrated how to use clientID and clientSecret to obtain an AzureAD access token to Key Vault. This is not the correct guidance, your solution should leverage the Managed Service Identity feature of Azure AD or use certificates to authenticate to Azure AD in order to access Key Vault.

For more information:
https://azure.microsoft.com/en-us/resources/samples/app-service-msi-keyvault-dotnet/ 
https://docs.microsoft.com/en-us/azure/active-directory/msi-tutorial-windows-vm-access-nonaad ]]></content:encoded>
    </item>
    <item>
      <title>A Proud Day to be a Dad</title>
      <link>https://docs.microsoft.com/archive/blogs/kaevans/a-proud-day-to-be-a-dad</link>
      <pubDate>Wed, 24 Aug 2016 20:58:29 GMT</pubDate>
      <dc:creator><![CDATA[Kirk Evans[MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaevans/?p=13635</guid>
      <description><![CDATA[Thirteen years ago, I wrote about an amazing day that I had as a new father (A Great Day to be a...]]></description>
      <content:encoded><![CDATA[<p>Thirteen years ago, I wrote about an amazing day that I had as a new father (<a href="https://blogs.msdn.microsoft.com/kaevans/2003/04/09/a-great-day-to-be-a-dad/">A Great Day to be a Dad</a>).&nbsp; </p><p>Today, I had another one of those days.&nbsp; I don’t often share personal stuff via my blog, but this one is one to remember.&nbsp; </p><p>My son, Carson, picked up guitar this summer.&nbsp; I was standing in his room watching him play Guitar Hero, showing me he could get through the expert levels.&nbsp; While I have a lot of respect for <a href="http://www.fakeplasticrock.com/">fake plastic rock</a>, I couldn’t help but point out that if he could keep up with the game on expert level, he could read tab and learn to play a real guitar.&nbsp; An obsession was born, because I was right… he was playing songs that he knew within the first few days, and by end of summer he has surpassed any playing that I ever did.</p><p><a href="https://www.bing.com/images/search?q=allaso+ranch&amp;view=detailv2&amp;&amp;id=2996C54BA8F3287519CA9FD0E7C521C70A469181&amp;selectedIndex=8&amp;ccid=54tzlE0a&amp;simid=608009899553261941&amp;thid=OIP.Me78b73944d1a4c8cd0eeb1eabe879638o0"><img align="left" style="float: left" src="https://tse1.mm.bing.net/th?&amp;id=OIP.Me78b73944d1a4c8cd0eeb1eabe879638o0&amp;w=300&amp;h=124&amp;c=0&amp;pid=1.9&amp;rs=0&amp;p=0&amp;r=0"></a>This summer, my kids went to church camp at <a href="http://allasoranch.com/">Allaso Ranch</a> (just pointing out, my summer camp experience was never like this!), and was amazed by the teens playing in a praise band.&nbsp; He was really moved by the music that kids his age were playing!&nbsp; He really, really wanted to be part of the creative team at church.&nbsp; However, this is <a href="https://fellowshipchurch.com/">Fellowship Church</a>, a mega church in Texas.&nbsp; He decided he wanted to get serious about guitar and get good enough to join the creative team. </p><p>He got in.&nbsp; Tonight, he passed the tryout and is now a part of the creative team.&nbsp; I love that he set his sights on something, worked for it, and achieved it.&nbsp; He achieved one of his goals, and I am so proud!</p><p>It doesn’t end there.</p><p><a href="http://www.bing.com/images/search?q=hebron+hawks&amp;view=detailv2&amp;&amp;id=651CF63F3D9673D5B112DB6E2C3F46A08CE46392&amp;selectedIndex=0&amp;ccid=M5LV%2fncA&amp;simid=608000583787874658&amp;thid=OIP.M3392d5fe770019361762857a56792b41o0"><img width="114" height="114" align="left" style="float: left" src="http://tse1.mm.bing.net/th?&amp;id=OIP.M3392d5fe770019361762857a56792b41o0&amp;w=300&amp;h=300&amp;c=0&amp;pid=1.9&amp;rs=0&amp;p=0&amp;r=0"><br></a></p><p>My daughter, Avery, has been a competitive cheerleader since she was 5 (that’s 9 years).&nbsp; She is amazing.&nbsp; For those who aren’t familiar, there are really two sports in Texas:&nbsp; football and cheerleading.&nbsp; The football you probably know.&nbsp; The cheerleading is not pom poms or the silly dance you see the Cowboys cheerleaders do.&nbsp; Nope, this is gymnastics floor routines rivaling some of what you see in the Olympics coupled with team stunts that send my daughter 20 feet in the air as she performs full twists and flips.&nbsp; She’s worked so hard at this, cheering for <a href="http://spirit-of-texas.com/">Spirit of Texas</a> competitively and traveling all over the US competing (one of the top teams in the nation!)&nbsp; </p><p>She is a freshman at the local high school, and she joined the high school cheerleading squad.&nbsp; <a href="http://www.lisd.net/hhs">Hebron Hawks</a>!&nbsp; She has worked all summer on this as well, making sure she was ready for the squad.&nbsp; </p><p>Today, my daughter text me.&nbsp; </p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/08/file.jpg"><img width="254" height="448" title="file" alt="file" src="https://msdnshared.blob.core.windows.net/media/2016/08/file_thumb.jpg" border="0"></a></p><p>My daughter is captain of the cheerleading squad for 9th grade!&nbsp; She has worked so hard, and I am so completely proud to see her achieve her goals!</p><p>Today is a great day to be a Dad.</p>]]></content:encoded>
    </item>
    <item>
      <title>Using PowerShell With Certificates</title>
      <link>https://docs.microsoft.com/archive/blogs/kaevans/using-powershell-with-certificates</link>
      <pubDate>Fri, 12 Aug 2016 09:19:20 GMT</pubDate>
      <dc:creator><![CDATA[Kirk Evans[MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaevans/?p=13606</guid>
      <description><![CDATA[This post will demonstrate using PowerShell cmdlets to create, read, and delete certificates.&nbsp;...]]></description>
      <content:encoded><![CDATA[<p>This post will demonstrate using PowerShell cmdlets to create, read, and delete certificates.&nbsp; Spoiler alert: it’s dead simple.</p><h2>Background</h2><p>I was working through the example <a title="https://github.com/Azure-Samples/active-directory-dotnet-daemon-certificate-credential" href="https://github.com/Azure-Samples/active-directory-dotnet-daemon-certificate-credential">Authenticating to Azure AD in daemon apps with certificates</a> and I saw this:</p><pre><code>makecert -r -pe -n "CN=TodoListDaemonWithCert" -ss My -len 2048 TodoListDaemonWithCert.cer -sv TodoListDaemonPrivateKey.pvk
</code></pre><p>Easy to read, right?&nbsp; I mean, anyone can read that and understand it will create a self-signed certificate where the private key is exportable and store it in the current user’s personal certificate store, right?</p><p>Inevitably, when I tell someone to “just use a self-signed certificate”, I inevitably get a question asking something like “<a title="http://www.bing.com/search?q=where+do+i+get+makecert.exe" href="http://www.bing.com/search?q=where+do+i+get+makecert.exe">Makecert.exe is not on my computer, where do I get it from?</a>”&nbsp; You need to download the Windows SDK in order to obtain it, but that’s a pretty large tax for what seems like a simple function, creating a self-signed certificate.&nbsp; The sample then goes on with some more code to read a .CER file using PowerShell, using the .NET X509Certificate2 class:</p><pre><code>$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cer.Import("TodoListDaemonWithCert.cer")
$bin = $cer.GetRawCertData()
$base64Value = [System.Convert]::ToBase64String($bin)
$bin = $cer.GetCertHash()
$base64Thumbprint = [System.Convert]::ToBase64String($bin)
$keyid = [System.Guid]::NewGuid().ToString()
</code></pre><p>It struck me that this is fairly complicated for something that should have just been 1 line of code. <h2>Working With Certificates in PowerShell</h2><p>If you Google with Bing you’ll see a whole bunch of blog posts that show fairly long-winded examples of creating self-signed certificates using the .NET X509Certificate2 class.&nbsp; Turns out it’s so much simpler than that.&nbsp; The equivalent of the above command is:</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:0ceefeca-620a-4cb7-90e0-fadc901038a9" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">New-SelfSignedCertificate</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2em;padding: 0 0 0 5px">
<li> <span style="color:#ff4500">$cert</span> <span style="color:#a9a9a9">=</span> <span style="color:#0000ff">New-SelfSignedCertificate</span> <span style="color:#000080">-Subject</span> <span style="color:#8b0000">&quot;CN=TodoListDaemonWithCert&quot;</span> <span style="color:#000080">-CertStoreLocation</span> <span style="color:#8a2be2">cert:&#092;CurrentUser&#092;My</span> <span style="color:#000080">-Provider</span> <span style="color:#8b0000">&quot;Microsoft Strong Cryptographic Provider&quot; </span></li>
</ol>
</div>
</div>
</div><p><br></p><p>That’s it.&nbsp; No need to install the Windows SDK.&nbsp; </p><p>The cmdlet returns the certificate object (which is actually a System.Security.Cryptography.X509Certificates.X509Certificate2 .NET type).&nbsp; So you can just use a variable to store it:</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:d35357fb-a922-4bc6-b073-cb5cfd4ffc2b" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">New-SelfSignedCertificate</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2em;padding: 0 0 0 5px">
<li> <span style="color:#ff4500">$cert</span> <span style="color:#a9a9a9">=</span> <span style="color:#0000ff">New-SelfSignedCertificate</span> <span style="color:#000080">-Subject</span> <span style="color:#8b0000">&quot;CN=TodoListDaemonWithCert&quot;</span> <span style="color:#000080">-CertStoreLocation</span> <span style="color:#8a2be2">cert:&#092;CurrentUser&#092;My</span> <span style="color:#000080">-Provider</span> <span style="color:#8b0000">&quot;Microsoft Strong Cryptographic Provider&quot; </span></li>
</ol>
</div>
</div>
</div><p>Since you have an X509Certificate2 object, you can easily interrogate its properties:</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:a82e6e4b-a745-4d38-9d73-a3724226061b" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">Certificate Properties</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2em;padding: 0 0 0 5px">
<li> <span style="color:#0000ff">Write-Host</span> <span style="color:#8b0000">&quot;base64Cert: &quot;</span> (<span style="color:#a9a9a9">[</span><span style="color:#008080">System.Convert</span><span style="color:#a9a9a9">]::</span>ToBase64String(<span style="color:#ff4500">$cert</span><span style="color:#a9a9a9">.</span>GetRawCertData()))</li>
<li style="background: #f3f3f3"><span style="color:#0000ff">Write-Host</span> <span style="color:#8b0000">&quot;base64CertHash:&quot;</span> (<span style="color:#a9a9a9">[</span><span style="color:#008080">System.Convert</span><span style="color:#a9a9a9">]::</span>ToBase64String(<span style="color:#ff4500">$cert</span><span style="color:#a9a9a9">.</span>GetCertHash()))</li>
<li><span style="color:#0000ff">Write-Host</span> <span style="color:#8b0000">&quot;keyID:&quot;</span> (<span style="color:#a9a9a9">[</span><span style="color:#008080">System.Guid</span><span style="color:#a9a9a9">]::</span>NewGuid()<span style="color:#a9a9a9">.</span>ToString())</li>
</ol>
</div>
</div>
</div><p><br></p><p>Need to get an existing certificate by a property such as its Subject?&nbsp; You can use the Get-ChildItem cmdlet and specify the path to the certificate store.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:6bb83b11-dd19-4e7b-84ac-6ed8c82b2068" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">Get-ChildItem</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2em;padding: 0 0 0 5px">
<li> <span style="color:#ff4500">$cert</span> <span style="color:#a9a9a9">=</span> <span style="color:#0000ff">Get-ChildItem</span> <span style="color:#000080">-Path</span> <span style="color:#8a2be2">cert:&#092;CurrentUser&#092;My</span> <span style="color:#a9a9a9">|</span> <span style="color:#0000ff">?{</span><span style="color:#ff4500">$_</span><span style="color:#a9a9a9">.</span>Subject <span style="color:#a9a9a9">-eq</span> <span style="color:#8b0000">&quot;CN=TodoListDaemonWithCert&quot;}</span></li>
</ol>
</div>
</div>
</div><p><br></p><p>Need to exporting the public key?&nbsp; Straightforward.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:ca195eae-2090-4ee7-8cf6-22a06d96e996" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">Export Public Key</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2em;padding: 0 0 0 5px">
<li> <span style="color:#0000ff">Export-Certificate</span> <span style="color:#000080">-Type</span> <span style="color:#8a2be2">CERT</span> <span style="color:#000080">-Cert</span> <span style="color:#ff4500">$cert</span> <span style="color:#000080">-FilePath</span> <span style="color:#8b0000">&quot;c:&#092;temp&#092;sample.cer&quot; </span></li>
</ol>
</div>
</div>
</div><p><br></p><p>What about the private key?</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:8d25ae5e-de45-4922-9c95-dae6ef6e1f7b" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">Export Private Key</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2em;padding: 0 0 0 5px">
<li> <span style="color:#ff4500">$cred</span> <span style="color:#a9a9a9">=</span> <span style="color:#0000ff">Get-Credential</span></li>
<li style="background: #f3f3f3"><span style="color:#0000ff">Export-PfxCertificate</span> <span style="color:#000080">-Cert</span> <span style="color:#ff4500">$cert</span> <span style="color:#000080">-Password</span> <span style="color:#ff4500">$cred</span><span style="color:#a9a9a9">.</span>Password <span style="color:#000080">-FilePath</span> <span style="color:#8b0000">&quot;c:&#092;temp&#092;sample.pfx&quot; </span></li>
</ol>
</div>
</div>
</div><p>How about removing a certificate?&nbsp; Also very simple.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:729f67ab-ce09-467c-b05b-d3ce6eb55b66" style="margin: 0px;padding: 0px;float: none">
<div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt">
<div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">Removing Certificates</div>
<div style="background: #ddd;overflow: auto">
<ol start="1" style="background: #ffffff;margin: 0 0 0 2em;padding: 0 0 0 5px">
<li> <span style="color:#0000ff">Remove-Item</span> <span style="color:#000080">-Path</span> (<span style="color:#8b0000">&quot;cert:&#092;CurrentUser&#092;My&#092;&quot;</span> <span style="color:#a9a9a9">+</span> <span style="color:#ff4500">$cert</span><span style="color:#a9a9a9">.</span>Thumbprint)</li>
</ol>
</div>
</div>
</div><p><br></p><h2>Summary</h2><p>I’m guilty, I have been doing this a long time and stuck in my ways.&nbsp; I default to makecert.exe because that’s what I know, but it’s useful to have tools that are far easier to read and understand.&nbsp; </p>]]></content:encoded>
    </item>
    <item>
      <title>Blynclight for Developers–Daddy is Working Light</title>
      <link>https://docs.microsoft.com/archive/blogs/kaevans/blynclight-for-developers-daddy-is-working-light</link>
      <pubDate>Mon, 08 Aug 2016 21:06:18 GMT</pubDate>
      <dc:creator><![CDATA[Kirk Evans[MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaevans/?p=13605</guid>
      <description><![CDATA[This post will show you how to code a custom Visual Studio VSIX add-in that will control a USB...]]></description>
      <content:encoded><![CDATA[<p>This post will show you how to code a custom Visual Studio VSIX add-in that will control a USB light, turning the light the color of your choice when Visual Studio is in the foreground or actively debugging.&nbsp; </p><p>The code is available for download at <a href="https://github.com/kaevans/BlyncLightAddin">https://github.com/kaevans/BlyncLightAddin</a>.&nbsp; </p><h2>Background</h2><p>A few years ago, Andrew Connell and Scott Hanselman posted about getting a USB presence indicator for Lync (<a title="http://www.andrewconnell.com/blog/Lync-BusyLight-Great-Solution-for-the-Home-Office" href="http://www.andrewconnell.com/blog/Lync-BusyLight-Great-Solution-for-the-Home-Office">Lync + BusyLight = Great Solution for the Home Office</a>, <a title="http://www.hanselman.com/blog/IsDaddyOnACallABusyLightPresenceIndicatorForLyncForMyHomeOffice.aspx" href="http://www.hanselman.com/blog/IsDaddyOnACallABusyLightPresenceIndicatorForLyncForMyHomeOffice.aspx">Is Daddy on a call? A BusyLight Presence indicator for Lync for my Home Office</a>).&nbsp; I received a <a href="http://www.blynclight.com/">Blynclight</a> as a speaker gift for speaking at a conference a few years ago and it’s just sat on my desk, turning various colors as my Skype for Business presence changes.&nbsp; </p><p><img alt="Blynclight Standard" src="http://cdn.shopify.com/s/files/1/0244/8061/products/blynclight-busylight_1024x1024.jpg?v=1430400958"></p><p>I am on the phone in meetings, so this does come in handy.&nbsp; I started thinking that this could be really useful to tell someone I am currently coding and don’t wish to be disturbed as well.&nbsp; If I am debugging, do not disturb!&nbsp; Hence, the BlyncLightAddIn, where you can control what color should be shown on the Blynclight when Visual Studio starts and what color should be shown when debugging.&nbsp; </p><p>The code is available for download at <a href="https://github.com/kaevans/BlyncLightAddin">https://github.com/kaevans/BlyncLightAddin</a>.&nbsp; </p><h2>Download the SDK</h2><p>I downloaded the Blynclight SDK from the Blynclight Developer Forum (<a title="http://blynclight.proboards.com/thread/2/blync-sdk-create-own-applications" href="http://blynclight.proboards.com/thread/2/blync-sdk-create-own-applications">http://blynclight.proboards.com/thread/2/blync-sdk-create-own-applications</a>).&nbsp; It required registration in order to download the SDK, but once you download it you can see the binaries, a sample application, and a Word doc that contains information on the API.&nbsp; </p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/08/image308.png"><img width="244" height="95" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/08/image_thumb237.png" border="0"></a></p><p>Next, I created a Visual Studio 2015 Extensibility project.&nbsp; I didn’t have the extensibility tools installed, so I was prompted to install the Visual Studio SDK.&nbsp; Took awhile, but finally I had a few new project template options in Visual Studio.&nbsp; </p><h2>Create a Custom Tool Window</h2><p>Once you have the extensibility tools installed (Visual Studio prompts you to install these if you haven’t already), create a new VSIX project in Visual Studio.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/08/image309.png"><img width="244" height="139" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/08/image_thumb238.png" border="0"></a></p><p>Right-click the project and choose Add / New Item, then add a new Custom Tool Window.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/08/image311.png"><img width="244" height="139" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/08/image_thumb239.png" border="0"></a></p><p>Visual Studio generates a bunch of files, including a Command class that provides a menu command item to open the custom tool window and a WPF control to define your custom tool window.&nbsp; It also generates a file, *Package.cs, that loads all the stuff for your add-in.&nbsp; This is where you set the default window position for your custom tool window.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:98b20a18-7657-40d5-966e-9182d47900a9" style="margin: 0px;padding: 0px;float: none"> <div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt"> <div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">Set Default Window Pos</div> <div style="background: #ddd;overflow: auto"> <ol start="1" style="background: #ffffff;margin: 0 0 0 2em;padding: 0 0 0 5px"> <li><span style="color:#000000">[</span><span style="color:#2b91af">PackageRegistration</span><span style="color:#000000">(UseManagedResourcesOnly = </span><span style="color:#0000ff">true</span><span style="color:#000000">)]</span></li> <li style="background: #f3f3f3"><span style="color:#000000">[</span><span style="color:#2b91af">InstalledProductRegistration</span><span style="color:#000000">(</span><span style="color:#a31515">&quot;#110&quot;</span><span style="color:#000000">, </span><span style="color:#a31515">&quot;#112&quot;</span><span style="color:#000000">, </span><span style="color:#a31515">&quot;1.0&quot;</span><span style="color:#000000">, IconResourceID = 400)] </span><span style="color:#008000">// Info on this package for Help/About</span></li> <li><span style="color:#000000">[</span><span style="color:#2b91af">ProvideMenuResource</span><span style="color:#000000">(</span><span style="color:#a31515">&quot;Menus.ctmenu&quot;</span><span style="color:#000000">, 1)]</span></li> <li style="background: #f3f3f3"><span style="color:#000000">[</span><span style="color:#2b91af">ProvideToolWindow</span><span style="color:#000000">(</span><span style="color:#0000ff">typeof</span><span style="color:#000000">(</span><span style="color:#2b91af">BlyncLight</span><span style="color:#000000">), Style = Microsoft.VisualStudio.Shell.</span><span style="color:#2b91af">VsDockStyle</span><span style="color:#000000">.Tabbed, Window = </span><span style="color:#a31515">&quot;3ae79031-e1bc-11d0-8f78-00a0c9110057&quot;</span><span style="color:#000000">)]</span></li> <li><span style="color:#000000">[</span><span style="color:#2b91af">Guid</span><span style="color:#000000">(</span><span style="color:#2b91af">BlyncLightPackage</span><span style="color:#000000">.PackageGuidString)]</span></li> <li style="background: #f3f3f3"><span style="color:#000000">[</span><span style="color:#2b91af">SuppressMessage</span><span style="color:#000000">(</span><span style="color:#a31515">&quot;StyleCop.CSharp.DocumentationRules&quot;</span><span style="color:#000000">, </span><span style="color:#a31515">&quot;SA1650:ElementDocumentationMustBeSpelledCorrectly&quot;</span><span style="color:#000000">, Justification = </span><span style="color:#a31515">&quot;pkgdef, VS and vsixmanifest are valid VS terms&quot;</span><span style="color:#000000">)]</span></li> <li><span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">sealed</span><span style="color:#000000"> </span><span style="color:#0000ff">class</span><span style="color:#000000"> </span><span style="color:#2b91af">BlyncLightPackage</span><span style="color:#000000"> : </span><span style="color:#2b91af">Package</span></li> <li style="background: #f3f3f3"><span style="color:#000000">{</span></li> </ol> </div> </div> </div>
<p>Notice line 4 where the custom tool window is loaded, we provide the style as tabbed, meaning it will be a tab in an existing window, and the window is docked to the Solution Explorer window (the GUID value is the GUID of the Solution Explorer).&nbsp; To see where I stole this code from, see <a title="https://msdn.microsoft.com/en-us/library/cc138567.aspx" href="https://msdn.microsoft.com/en-us/library/cc138567.aspx">https://msdn.microsoft.com/en-us/library/cc138567.aspx</a>.&nbsp; </p><p>If you hit F5 right now, you have a functional yet boring addin.&nbsp; Go to the View / Other Windows menu item to load your custom tool window.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/08/image312.png"><img width="203" height="244" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/08/image_thumb240.png" border="0"></a></p><p>Your custom tool window is opened, docked to the Solution Explorer window.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/08/image313.png"><img width="244" height="221" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/08/image_thumb241.png" border="0"></a></p><h2>Add Blynclight Functionality</h2><p>Now that the shell of our add-in is working, we can create our custom tool window.&nbsp; You previously downloaded the SDK which includes Blynclight.dll.&nbsp; This file is not signed, so you won’t be able to load it.&nbsp; However, there is a workaround as shown in the post <a href="http://ryanfarley.com/blog/archive/2010/04/23/sign-a-.net-assembly-with-a-strong-name-without-recompiling.aspx">Sign a .NET Assembly with a Strong Name Without Recompiling</a>.&nbsp; You basically create a strong-named key using sn.exe, disassemble the DLL to intermediate language (IL) using ILDASM.exe, then assemble the IL into a DLL including your strong-named key using ILASM.exe.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/08/image314.png"><img width="558" height="286" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/08/image_thumb242.png" border="0"></a></p><p>Following these steps, I then add a reference in Visual Studio to the signed assembly.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/08/image315.png"><img width="244" height="84" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/08/image_thumb243.png" border="0"></a></p><p>We can now program against the Blynclight!</p><h2>Is Visual Studio the Active Window?</h2><p>If I have Visual Studio open, I usually don’t want to be disturbed.&nbsp; We can cheat this by registering for a callback any time the active window is changed.&nbsp; Once changed, we can look at the title of the window and decide if we want to change the light’s color or not. Registering the callback is very simple, especially when someone on Stack Overflow has done the hard lifting for us!&nbsp; See the post <a title="http://stackoverflow.com/questions/4372055/detect-active-window-changed-using-c-sharp-without-polling" href="http://stackoverflow.com/questions/4372055/detect-active-window-changed-using-c-sharp-without-polling">Detect active window changed using C# without polling</a>.&nbsp; I’ll be the first to admit, this is an amateurish approach to just look for a hard-coded string “Microsoft Visual Studio”… but that’s the beauty of open source, right?&nbsp; Just fork the repo and implement the rest that I was too lazy to finish.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:f5e34bc1-922b-4dc8-adee-e92034f0dc87" style="margin: 0px;padding: 0px;float: none"> <div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt"> <div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">ActiveWindowWatcher</div> <div style="background: #ddd;overflow: auto"> <ol start="1" style="background: #ffffff;margin: 0 0 0 2.5em;padding: 0 0 0 5px"> <li><span style="color:#0000ff">using</span><span style="color:#000000"> System;</span></li> <li style="background: #f3f3f3"><span style="color:#0000ff">using</span><span style="color:#000000"> System.Runtime.InteropServices;</span></li> <li><span style="color:#0000ff">using</span><span style="color:#000000"> System.Text;</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li><span style="color:#0000ff">namespace</span><span style="color:#000000"> BlyncLightAddin</span></li> <li style="background: #f3f3f3"><span style="color:#000000">{</span></li> <li>    <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">class</span><span style="color:#000000"> </span><span style="color:#2b91af">ActiveWindowWatcher</span><span style="color:#000000"> : </span><span style="color:#2b91af">IBlyncWatcher</span></li> <li style="background: #f3f3f3">    <span style="color:#000000">{        </span></li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">event</span><span style="color:#000000"> </span><span style="color:#2b91af">EventHandler</span><span style="color:#000000"> StatusChanged;</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">private</span><span style="color:#000000"> </span><span style="color:#0000ff">bool</span><span style="color:#000000"> isPaused;</span></li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">private</span><span style="color:#000000"> </span><span style="color:#0000ff">const</span><span style="color:#000000"> </span><span style="color:#0000ff">uint</span><span style="color:#000000"> WINEVENT_OUTOFCONTEXT = 0;</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">private</span><span style="color:#000000"> </span><span style="color:#0000ff">const</span><span style="color:#000000"> </span><span style="color:#0000ff">uint</span><span style="color:#000000"> EVENT_SYSTEM_FOREGROUND = 3;</span></li> <li>        <span style="color:#000000"></span><span style="color:#2b91af">IntPtr</span><span style="color:#000000"> m_hhook;</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#2b91af">WinEventDelegate</span><span style="color:#000000"> dele = </span><span style="color:#0000ff">null</span><span style="color:#000000">;</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">delegate</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> </span><span style="color:#2b91af">WinEventDelegate</span><span style="color:#000000">(</span><span style="color:#2b91af">IntPtr</span><span style="color:#000000"> hWinEventHook, </span><span style="color:#0000ff">uint</span><span style="color:#000000"> eventType, </span><span style="color:#2b91af">IntPtr</span><span style="color:#000000"> hwnd, </span><span style="color:#0000ff">int</span><span style="color:#000000"> idObject, </span><span style="color:#0000ff">int</span><span style="color:#000000"> idChild, </span><span style="color:#0000ff">uint</span><span style="color:#000000"> dwEventThread, </span><span style="color:#0000ff">uint</span><span style="color:#000000"> dwmsEventTime);</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">        <span style="color:#000000">[</span><span style="color:#2b91af">DllImport</span><span style="color:#000000">(</span><span style="color:#a31515">&quot;user32.dll&quot;</span><span style="color:#000000">)]</span></li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">static</span><span style="color:#000000"> </span><span style="color:#0000ff">extern</span><span style="color:#000000"> </span><span style="color:#2b91af">IntPtr</span><span style="color:#000000"> SetWinEventHook(</span><span style="color:#0000ff">uint</span><span style="color:#000000"> eventMin, </span><span style="color:#0000ff">uint</span><span style="color:#000000"> eventMax, </span><span style="color:#2b91af">IntPtr</span><span style="color:#000000"> hmodWinEventProc, </span><span style="color:#2b91af">WinEventDelegate</span><span style="color:#000000"> lpfnWinEventProc, </span><span style="color:#0000ff">uint</span><span style="color:#000000"> idProcess, </span><span style="color:#0000ff">uint</span><span style="color:#000000"> idThread, </span><span style="color:#0000ff">uint</span><span style="color:#000000"> dwFlags);</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000">[</span><span style="color:#2b91af">DllImport</span><span style="color:#000000">(</span><span style="color:#a31515">&quot;user32.dll&quot;</span><span style="color:#000000">)]</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">static</span><span style="color:#000000"> </span><span style="color:#0000ff">extern</span><span style="color:#000000"> </span><span style="color:#0000ff">bool</span><span style="color:#000000"> UnhookWinEvent(</span><span style="color:#2b91af">IntPtr</span><span style="color:#000000"> hWinEventHook);</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">        <span style="color:#000000">[</span><span style="color:#2b91af">DllImport</span><span style="color:#000000">(</span><span style="color:#a31515">&quot;user32.dll&quot;</span><span style="color:#000000">)]</span></li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">static</span><span style="color:#000000"> </span><span style="color:#0000ff">extern</span><span style="color:#000000"> </span><span style="color:#2b91af">IntPtr</span><span style="color:#000000"> GetForegroundWindow();</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000">[</span><span style="color:#2b91af">DllImport</span><span style="color:#000000">(</span><span style="color:#a31515">&quot;user32.dll&quot;</span><span style="color:#000000">)]</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">static</span><span style="color:#000000"> </span><span style="color:#0000ff">extern</span><span style="color:#000000"> </span><span style="color:#0000ff">int</span><span style="color:#000000"> GetWindowText(</span><span style="color:#2b91af">IntPtr</span><span style="color:#000000"> hWnd, </span><span style="color:#2b91af">StringBuilder</span><span style="color:#000000"> text, </span><span style="color:#0000ff">int</span><span style="color:#000000"> count);</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">private</span><span style="color:#000000"> </span><span style="color:#0000ff">string</span><span style="color:#000000"> GetActiveWindowTitle()</span></li> <li>        <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#0000ff">const</span><span style="color:#000000"> </span><span style="color:#0000ff">int</span><span style="color:#000000"> nChars = 256;</span></li> <li>            <span style="color:#000000"></span><span style="color:#2b91af">IntPtr</span><span style="color:#000000"> handle = </span><span style="color:#2b91af">IntPtr</span><span style="color:#000000">.Zero;</span></li> <li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#2b91af">StringBuilder</span><span style="color:#000000"> Buff = </span><span style="color:#0000ff">new</span><span style="color:#000000"> </span><span style="color:#2b91af">StringBuilder</span><span style="color:#000000">(nChars);</span></li> <li>            <span style="color:#000000">handle = GetForegroundWindow();</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>            <span style="color:#000000"></span><span style="color:#0000ff">if</span><span style="color:#000000"> (GetWindowText(handle, Buff, nChars) &gt; 0)</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">{</span></li> <li>                <span style="color:#000000"></span><span style="color:#0000ff">return</span><span style="color:#000000"> Buff.ToString();</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">}</span></li> <li>            <span style="color:#000000"></span><span style="color:#0000ff">return</span><span style="color:#000000"> </span><span style="color:#0000ff">null</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">}</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> WinEventProc(</span><span style="color:#2b91af">IntPtr</span><span style="color:#000000"> hWinEventHook, </span><span style="color:#0000ff">uint</span><span style="color:#000000"> eventType, </span><span style="color:#2b91af">IntPtr</span><span style="color:#000000"> hwnd, </span><span style="color:#0000ff">int</span><span style="color:#000000"> idObject, </span><span style="color:#0000ff">int</span><span style="color:#000000"> idChild, </span><span style="color:#0000ff">uint</span><span style="color:#000000"> dwEventThread, </span><span style="color:#0000ff">uint</span><span style="color:#000000"> dwmsEventTime)</span></li> <li>        <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#0000ff">var</span><span style="color:#000000"> text = GetActiveWindowTitle();</span></li> <li>            <span style="color:#000000"></span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#0000ff">string</span><span style="color:#000000">.IsNullOrEmpty(text))</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">{</span></li> <li>                <span style="color:#000000">OnStatusChanged(</span><span style="color:#0000ff">new</span><span style="color:#000000"> </span><span style="color:#2b91af">StatusChangedEventArgs</span><span style="color:#000000">(</span><span style="color:#2b91af">Status</span><span style="color:#000000">.Default));</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">}</span></li> <li>            <span style="color:#000000"></span><span style="color:#0000ff">else</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">{</span></li> <li>                <span style="color:#000000"></span><span style="color:#0000ff">if</span><span style="color:#000000"> (text.Contains(</span><span style="color:#a31515">&quot;Microsoft Visual Studio&quot;</span><span style="color:#000000">))</span></li> <li style="background: #f3f3f3">                <span style="color:#000000">{</span></li> <li>                    <span style="color:#000000"></span><span style="color:#008000">//Raise event</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000">OnStatusChanged(</span><span style="color:#0000ff">new</span><span style="color:#000000"> </span><span style="color:#2b91af">StatusChangedEventArgs</span><span style="color:#000000">(</span><span style="color:#2b91af">Status</span><span style="color:#000000">.Busy));</span></li> <li>                <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">                <span style="color:#000000"></span><span style="color:#0000ff">else</span></li> <li>                <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000">OnStatusChanged(</span><span style="color:#0000ff">new</span><span style="color:#000000"> </span><span style="color:#2b91af">StatusChangedEventArgs</span><span style="color:#000000">(</span><span style="color:#2b91af">Status</span><span style="color:#000000">.Available));</span></li> <li>                <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">}</span></li> <li>        <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> Initialize()</span></li> <li>        <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">dele = </span><span style="color:#0000ff">new</span><span style="color:#000000"> </span><span style="color:#2b91af">WinEventDelegate</span><span style="color:#000000">(WinEventProc);</span><span style="color:#008000">//&lt;-causing ERROR</span></li> <li>            <span style="color:#000000">m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, </span><span style="color:#2b91af">IntPtr</span><span style="color:#000000">.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">}</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> Close()</span></li> <li>        <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#0000ff">if</span><span style="color:#000000"> (m_hhook.ToInt32() != 0)</span></li> <li>            <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">                <span style="color:#000000">UnhookWinEvent(m_hhook);</span></li> <li>            <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">}</span></li> <li>        <span style="color:#000000"></span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">protected</span><span style="color:#000000"> </span><span style="color:#0000ff">virtual</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> OnStatusChanged(</span><span style="color:#2b91af">StatusChangedEventArgs</span><span style="color:#000000"> e)</span></li> <li>        <span style="color:#000000">{            </span></li> <li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#0000ff">if</span><span style="color:#000000"> (StatusChanged != </span><span style="color:#0000ff">null</span><span style="color:#000000"> &amp;&amp; isPaused == </span><span style="color:#0000ff">false</span><span style="color:#000000">)</span></li> <li>            <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">                <span style="color:#000000">StatusChanged(</span><span style="color:#0000ff">this</span><span style="color:#000000">, e);</span></li> <li>            <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">}</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> Pause()</span></li> <li>        <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">isPaused = </span><span style="color:#0000ff">true</span><span style="color:#000000">;</span></li> <li>        <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> Resume()</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">{</span></li> <li>            <span style="color:#000000">isPaused = </span><span style="color:#0000ff">false</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">}</span></li> <li>    <span style="color:#000000">}</span></li> <li style="background: #f3f3f3"><span style="color:#000000">}</span></li> </ol> </div> </div> </div><p><br></p><h2>Is Visual Studio Debugging?</h2><p>This one was a little harder to solve, but turned out so much easier to implement.&nbsp; I wanted to know if Visual Studio was actively debugging something.&nbsp; If it is, then changing windows doesn’t matter (debugging usually means that new windows are popping up all over the place), just show the status as busy.&nbsp; </p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:e815c5ba-389f-4483-bc59-15a9620b94fc" style="margin: 0px;padding: 0px;float: none"> <div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt"> <div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">DebuggerWatcher</div> <div style="background: #ddd;overflow: auto"> <ol start="1" style="background: #ffffff;margin: 0 0 0 2.5em;padding: 0 0 0 5px"> <li><span style="color:#0000ff">using</span><span style="color:#000000"> Microsoft.VisualStudio.Shell.Interop;</span></li> <li style="background: #f3f3f3"><span style="color:#0000ff">using</span><span style="color:#000000"> System;</span></li> <li><span style="color:#0000ff">using</span><span style="color:#000000"> System.Collections.Generic;</span></li> <li style="background: #f3f3f3"><span style="color:#0000ff">using</span><span style="color:#000000"> System.Linq;</span></li> <li><span style="color:#0000ff">using</span><span style="color:#000000"> System.Text;</span></li> <li style="background: #f3f3f3"><span style="color:#0000ff">using</span><span style="color:#000000"> System.Threading.Tasks;</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3"><span style="color:#0000ff">namespace</span><span style="color:#000000"> BlyncLightAddin</span></li> <li><span style="color:#000000">{</span></li> <li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">class</span><span style="color:#000000"> </span><span style="color:#2b91af">DebuggerWatcher</span><span style="color:#000000"> : </span><span style="color:#2b91af">IBlyncWatcher</span><span style="color:#000000">, </span><span style="color:#2b91af">IVsDebuggerEvents</span></li> <li>    <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">event</span><span style="color:#000000"> </span><span style="color:#2b91af">EventHandler</span><span style="color:#000000"> StatusChanged;</span></li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">private</span><span style="color:#000000"> </span><span style="color:#0000ff">uint</span><span style="color:#000000"> cookie = </span><span style="color:#0000ff">default</span><span style="color:#000000">(</span><span style="color:#0000ff">uint</span><span style="color:#000000">);</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">private</span><span style="color:#000000"> </span><span style="color:#0000ff">bool</span><span style="color:#000000"> isPaused;</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> Initialize()</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">{</span></li> <li>            <span style="color:#000000"></span><span style="color:#2b91af">IVsDebugger</span><span style="color:#000000"> debugService = Microsoft.VisualStudio.Shell.</span><span style="color:#2b91af">Package</span><span style="color:#000000">.GetGlobalService(</span><span style="color:#0000ff">typeof</span><span style="color:#000000">(</span><span style="color:#2b91af">SVsShellDebugger</span><span style="color:#000000">)) </span><span style="color:#0000ff">as</span><span style="color:#000000"> </span><span style="color:#2b91af">IVsDebugger</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#0000ff">if</span><span style="color:#000000"> (debugService != </span><span style="color:#0000ff">null</span><span style="color:#000000">)</span></li> <li>            <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">                <span style="color:#000000"></span><span style="color:#008000">// Register for debug events.</span></li> <li>                <span style="color:#000000"></span><span style="color:#008000">// Assumes the current class implements IDebugEventCallback2.</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>                <span style="color:#000000">debugService.AdviseDebuggerEvents(</span><span style="color:#0000ff">this</span><span style="color:#000000">, </span><span style="color:#0000ff">out</span><span style="color:#000000"> cookie);</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">}</span></li> <li>        <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">int</span><span style="color:#000000"> OnModeChange(</span><span style="color:#2b91af">DBGMODE</span><span style="color:#000000"> dbgmodeNew)</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">{</span></li> <li>            <span style="color:#000000"></span><span style="color:#0000ff">switch</span><span style="color:#000000"> (dbgmodeNew)</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">{</span></li> <li>                <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> </span><span style="color:#2b91af">DBGMODE</span><span style="color:#000000">.DBGMODE_Break:</span></li> <li style="background: #f3f3f3">                <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> </span><span style="color:#2b91af">DBGMODE</span><span style="color:#000000">.DBGMODE_Run:</span></li> <li>                <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> </span><span style="color:#2b91af">DBGMODE</span><span style="color:#000000">.DBGMODE_Enc:</span></li> <li style="background: #f3f3f3">                <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> </span><span style="color:#2b91af">DBGMODE</span><span style="color:#000000">.DBGMODE_EncMask: </span></li> <li>                    <span style="color:#000000"></span><span style="color:#008000">//Debugging                   </span></li> <li style="background: #f3f3f3">                    <span style="color:#000000">OnStatusChanged(</span><span style="color:#0000ff">new</span><span style="color:#000000"> </span><span style="color:#2b91af">StatusChangedEventArgs</span><span style="color:#000000">(</span><span style="color:#2b91af">Status</span><span style="color:#000000">.Busy));</span></li> <li>                    <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">                <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> </span><span style="color:#2b91af">DBGMODE</span><span style="color:#000000">.DBGMODE_Design:</span></li> <li>                    <span style="color:#000000"></span><span style="color:#008000">//Debugger detached</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000">OnStatusChanged(</span><span style="color:#0000ff">new</span><span style="color:#000000"> </span><span style="color:#2b91af">StatusChangedEventArgs</span><span style="color:#000000">(</span><span style="color:#2b91af">Status</span><span style="color:#000000">.Available));</span></li> <li>                    <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">                <span style="color:#000000"></span><span style="color:#0000ff">default</span><span style="color:#000000">:</span></li> <li>                    <span style="color:#000000">OnStatusChanged(</span><span style="color:#0000ff">new</span><span style="color:#000000"> </span><span style="color:#2b91af">StatusChangedEventArgs</span><span style="color:#000000">(</span><span style="color:#2b91af">Status</span><span style="color:#000000">.Default));</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li>            <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#0000ff">return</span><span style="color:#000000"> (</span><span style="color:#0000ff">int</span><span style="color:#000000">)dbgmodeNew;</span></li> <li>        <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">protected</span><span style="color:#000000"> </span><span style="color:#0000ff">virtual</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> OnStatusChanged(</span><span style="color:#2b91af">StatusChangedEventArgs</span><span style="color:#000000"> e)</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">{</span></li> <li>            <span style="color:#000000"></span><span style="color:#0000ff">if</span><span style="color:#000000"> (StatusChanged != </span><span style="color:#0000ff">null</span><span style="color:#000000"> &amp;&amp; isPaused == </span><span style="color:#0000ff">false</span><span style="color:#000000">)</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">{</span></li> <li>                <span style="color:#000000">StatusChanged(</span><span style="color:#0000ff">this</span><span style="color:#000000">, e);</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">}</span></li> <li>        <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> Close()</span></li> <li>        <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#2b91af">IVsDebugger</span><span style="color:#000000"> debugService = Microsoft.VisualStudio.Shell.</span><span style="color:#2b91af">Package</span><span style="color:#000000">.GetGlobalService(</span><span style="color:#0000ff">typeof</span><span style="color:#000000">(</span><span style="color:#2b91af">SVsShellDebugger</span><span style="color:#000000">)) </span><span style="color:#0000ff">as</span><span style="color:#000000"> </span><span style="color:#2b91af">IVsDebugger</span><span style="color:#000000">;</span></li> <li>            <span style="color:#000000"></span><span style="color:#0000ff">if</span><span style="color:#000000"> (debugService != </span><span style="color:#0000ff">null</span><span style="color:#000000">)</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">{</span></li> <li>                <span style="color:#000000"></span><span style="color:#008000">// Unegister for debug events.                </span></li> <li style="background: #f3f3f3">                <span style="color:#000000">debugService.UnadviseDebuggerEvents(cookie);</span></li> <li>            <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">}</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> Pause()</span></li> <li>        <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">isPaused = </span><span style="color:#0000ff">true</span><span style="color:#000000">;</span></li> <li>        <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> Resume()</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">{</span></li> <li>            <span style="color:#000000">isPaused = </span><span style="color:#0000ff">false</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">}</span></li> <li>    <span style="color:#000000">}</span></li> <li style="background: #f3f3f3"><span style="color:#000000">}</span></li> </ol> </div> </div> </div><h2><br></h2><h2>Using the IBlyncWatcher Interface</h2><p>Using our two implementations above is really simple.&nbsp; I defined the interface, IBlyncWatcher, that both implement.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:05cee92f-241c-424c-b9e3-2b6f279d4917" style="margin: 0px;padding: 0px;float: none"> <div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt"> <div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">IBlyncWatcher</div> <div style="background: #ddd;overflow: auto"> <ol start="1" style="background: #ffffff;margin: 0 0 0 2.5em;padding: 0 0 0 5px"> <li><span style="color:#0000ff">using</span><span style="color:#000000"> System;</span></li> <li style="background: #f3f3f3"><span style="color:#0000ff">using</span><span style="color:#000000"> System.Collections.Generic;</span></li> <li><span style="color:#0000ff">using</span><span style="color:#000000"> System.Linq;</span></li> <li style="background: #f3f3f3"><span style="color:#0000ff">using</span><span style="color:#000000"> System.Text;</span></li> <li><span style="color:#0000ff">using</span><span style="color:#000000"> System.Threading.Tasks;</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li><span style="color:#0000ff">namespace</span><span style="color:#000000"> BlyncLightAddin</span></li> <li style="background: #f3f3f3"><span style="color:#000000">{</span></li> <li>    <span style="color:#000000"></span><span style="color:#0000ff">interface</span><span style="color:#000000"> </span><span style="color:#2b91af">IBlyncWatcher</span></li> <li style="background: #f3f3f3">    <span style="color:#000000">{</span></li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">void</span><span style="color:#000000"> Initialize();</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">void</span><span style="color:#000000"> Pause();</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">void</span><span style="color:#000000"> Resume();</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">void</span><span style="color:#000000"> Close();</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">event</span><span style="color:#000000"> </span><span style="color:#2b91af">EventHandler</span><span style="color:#000000"> StatusChanged;</span></li> <li style="background: #f3f3f3">    <span style="color:#000000">}</span></li> <li><span style="color:#000000">}</span></li> </ol> </div> </div> </div><p>In the BlyncLightControl.xaml.cs file, you can see how easy it is to use the interface and the concrete classes.</p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:42a3c8cf-308a-42ae-92aa-c46aece33c3a" style="margin: 0px;padding: 0px;float: none"> <div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt"> <div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">BlyncLightControl</div> <div style="background: #ddd;overflow: auto"> <ol start="1" style="background: #ffffff;margin: 0 0 0 3em;padding: 0 0 0 5px"> <li><span style="color:#008000">//------------------------------------------------------------------------------</span></li> <li style="background: #f3f3f3"><span style="color:#008000">// &lt;copyright file=&quot;BlyncLightControl.xaml.cs&quot; company=&quot;Company&quot;&gt;</span></li> <li><span style="color:#008000">//     Copyright (c) Company.  All rights reserved.</span></li> <li style="background: #f3f3f3"><span style="color:#008000">// &lt;/copyright&gt;</span></li> <li><span style="color:#008000">//------------------------------------------------------------------------------</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li><span style="color:#0000ff">namespace</span><span style="color:#000000"> BlyncLightAddin</span></li> <li style="background: #f3f3f3"><span style="color:#000000">{</span></li> <li>    <span style="color:#000000"></span><span style="color:#0000ff">using</span><span style="color:#000000"> System;</span></li> <li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#0000ff">using</span><span style="color:#000000"> System.Diagnostics.CodeAnalysis;</span></li> <li>    <span style="color:#000000"></span><span style="color:#0000ff">using</span><span style="color:#000000"> System.Windows;</span></li> <li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#0000ff">using</span><span style="color:#000000"> System.Windows.Controls;</span></li> <li>    <span style="color:#000000"></span><span style="color:#0000ff">using</span><span style="color:#000000"> System.Runtime.InteropServices;</span></li> <li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#0000ff">using</span><span style="color:#000000"> System.Text;</span></li> <li>    <span style="color:#000000"></span><span style="color:#0000ff">using</span><span style="color:#000000"> Microsoft.VisualStudio.Shell.Interop;</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>    <span style="color:#000000"></span><span style="color:#808080">///</span><span style="color:#008000"> </span><span style="color:#808080">&lt;summary&gt;</span></li> <li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#808080">///</span><span style="color:#008000"> Interaction logic for BlyncLightControl.</span></li> <li>    <span style="color:#000000"></span><span style="color:#808080">///</span><span style="color:#008000"> </span><span style="color:#808080">&lt;/summary&gt;</span></li> <li style="background: #f3f3f3">    <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> </span><span style="color:#0000ff">partial</span><span style="color:#000000"> </span><span style="color:#0000ff">class</span><span style="color:#000000"> </span><span style="color:#2b91af">BlyncLightControl</span><span style="color:#000000"> : </span><span style="color:#2b91af">UserControl</span></li> <li>    <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#2b91af">IBlyncWatcher</span><span style="color:#000000"> debugWatcher;</span></li> <li>        <span style="color:#000000"></span><span style="color:#2b91af">IBlyncWatcher</span><span style="color:#000000"> activeWindowWatcher;</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000"></span><span style="color:#808080">///</span><span style="color:#008000"> </span><span style="color:#808080">&lt;summary&gt;</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#808080">///</span><span style="color:#008000"> Initializes a new instance of the </span><span style="color:#808080">&lt;see cref=&quot;</span><span style="color:#2b91af">BlyncLightControl</span><span style="color:#808080">&quot;/&gt;</span><span style="color:#008000"> class.</span></li> <li>        <span style="color:#000000"></span><span style="color:#808080">///</span><span style="color:#008000"> </span><span style="color:#808080">&lt;/summary&gt;</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">public</span><span style="color:#000000"> BlyncLightControl()</span></li> <li>        <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#0000ff">this</span><span style="color:#000000">.InitializeComponent();</span></li> <li>            <span style="color:#000000">debugWatcher = </span><span style="color:#0000ff">new</span><span style="color:#000000"> </span><span style="color:#2b91af">DebuggerWatcher</span><span style="color:#000000">();</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">debugWatcher.StatusChanged += DebugWatcher_StatusChanged;</span></li> <li>            <span style="color:#000000">debugWatcher.Initialize();</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>            <span style="color:#000000">activeWindowWatcher = </span><span style="color:#0000ff">new</span><span style="color:#000000"> </span><span style="color:#2b91af">ActiveWindowWatcher</span><span style="color:#000000">();</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">activeWindowWatcher.StatusChanged += ActiveWindowWatcher_StatusChanged;</span></li> <li>            <span style="color:#000000">activeWindowWatcher.Initialize();</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">}</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">private</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> ActiveWindowWatcher_StatusChanged(</span><span style="color:#0000ff">object</span><span style="color:#000000"> sender, </span><span style="color:#2b91af">EventArgs</span><span style="color:#000000"> e)</span></li> <li>        <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#0000ff">var</span><span style="color:#000000"> es = e </span><span style="color:#0000ff">as</span><span style="color:#000000"> </span><span style="color:#2b91af">StatusChangedEventArgs</span><span style="color:#000000">;</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#0000ff">switch</span><span style="color:#000000"> (es.Status)</span></li> <li>            <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">                <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> </span><span style="color:#2b91af">Status</span><span style="color:#000000">.Default:</span></li> <li>                    <span style="color:#000000">ChangeColor(Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Yellow);</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li>                    <span style="color:#000000"></span></li> <li style="background: #f3f3f3">                <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> </span><span style="color:#2b91af">Status</span><span style="color:#000000">.Busy:</span></li> <li>                    <span style="color:#000000">ChangeColor(Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Red);</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li>                <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> </span><span style="color:#2b91af">Status</span><span style="color:#000000">.Available:</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000">ChangeColor(Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Green);</span></li> <li>                    <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">                <span style="color:#000000"></span><span style="color:#0000ff">default</span><span style="color:#000000">:</span></li> <li>                    <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">}</span></li> <li>        <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">private</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> DebugWatcher_StatusChanged(</span><span style="color:#0000ff">object</span><span style="color:#000000"> sender, </span><span style="color:#2b91af">EventArgs</span><span style="color:#000000"> e)</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">{</span></li> <li>            <span style="color:#000000"></span><span style="color:#0000ff">var</span><span style="color:#000000"> es = e </span><span style="color:#0000ff">as</span><span style="color:#000000"> </span><span style="color:#2b91af">StatusChangedEventArgs</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>            <span style="color:#000000"></span><span style="color:#0000ff">switch</span><span style="color:#000000"> (es.Status)</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">{</span></li> <li>                <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> </span><span style="color:#2b91af">Status</span><span style="color:#000000">.Default:</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000">ChangeColor(Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Yellow);</span></li> <li>                    <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>                <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> </span><span style="color:#2b91af">Status</span><span style="color:#000000">.Busy:</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000">activeWindowWatcher.Pause();</span></li> <li>                    <span style="color:#000000">ChangeColor(Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Red);</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li>                <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> </span><span style="color:#2b91af">Status</span><span style="color:#000000">.Available:</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000">activeWindowWatcher.Resume();</span></li> <li>                    <span style="color:#000000">ChangeColor(Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Green);</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li>                <span style="color:#000000"></span><span style="color:#0000ff">default</span><span style="color:#000000">:</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li>            <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">}</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">        <span style="color:#000000">~BlyncLightControl()</span></li> <li>        <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">debugWatcher.Close();</span></li> <li>            <span style="color:#000000">debugWatcher.StatusChanged -= DebugWatcher_StatusChanged;</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">activeWindowWatcher.Close();</span></li> <li>            <span style="color:#000000">activeWindowWatcher.StatusChanged -= ActiveWindowWatcher_StatusChanged;</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">}</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000"></span><span style="color:#808080">///</span><span style="color:#008000"> </span><span style="color:#808080">&lt;summary&gt;</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#808080">///</span><span style="color:#008000"> Handles click on the button by displaying a message box.</span></li> <li>        <span style="color:#000000"></span><span style="color:#808080">///</span><span style="color:#008000"> </span><span style="color:#808080">&lt;/summary&gt;</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#808080">///</span><span style="color:#008000"> </span><span style="color:#808080">&lt;param name=&quot;</span><span style="color:#000000">sender</span><span style="color:#808080">&quot;&gt;</span><span style="color:#008000">The event sender.</span><span style="color:#808080">&lt;/param&gt;</span></li> <li>        <span style="color:#000000"></span><span style="color:#808080">///</span><span style="color:#008000"> </span><span style="color:#808080">&lt;param name=&quot;</span><span style="color:#000000">e</span><span style="color:#808080">&quot;&gt;</span><span style="color:#008000">The event args.</span><span style="color:#808080">&lt;/param&gt;</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">[</span><span style="color:#2b91af">SuppressMessage</span><span style="color:#000000">(</span><span style="color:#a31515">&quot;Microsoft.Globalization&quot;</span><span style="color:#000000">, </span><span style="color:#a31515">&quot;CA1300:SpecifyMessageBoxOptions&quot;</span><span style="color:#000000">, Justification = </span><span style="color:#a31515">&quot;Sample code&quot;</span><span style="color:#000000">)]</span></li> <li>        <span style="color:#000000">[</span><span style="color:#2b91af">SuppressMessage</span><span style="color:#000000">(</span><span style="color:#a31515">&quot;StyleCop.CSharp.NamingRules&quot;</span><span style="color:#000000">, </span><span style="color:#a31515">&quot;SA1300:ElementMustBeginWithUpperCaseLetter&quot;</span><span style="color:#000000">, Justification = </span><span style="color:#a31515">&quot;Default event handler naming pattern&quot;</span><span style="color:#000000">)]</span></li> <li style="background: #f3f3f3">        <span style="color:#000000"></span><span style="color:#0000ff">private</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> button1_Click(</span><span style="color:#0000ff">object</span><span style="color:#000000"> sender, </span><span style="color:#2b91af">RoutedEventArgs</span><span style="color:#000000"> e)</span></li> <li>        <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">ChangeColor(Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Blue);</span></li> <li>        <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>        <span style="color:#000000"></span><span style="color:#0000ff">private</span><span style="color:#000000"> </span><span style="color:#0000ff">void</span><span style="color:#000000"> ChangeColor(Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000"> color)</span></li> <li style="background: #f3f3f3">        <span style="color:#000000">{</span></li> <li>            <span style="color:#000000">Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000"> controller = </span><span style="color:#0000ff">new</span><span style="color:#000000"> Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">();</span></li> <li style="background: #f3f3f3">            <span style="color:#000000"></span><span style="color:#0000ff">int</span><span style="color:#000000"> numDevices = 0;</span></li> <li>            <span style="color:#000000"></span><span style="color:#0000ff">try</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">{</span></li> <li>                <span style="color:#000000">numDevices = controller.InitBlyncDevices();</span></li> <li style="background: #f3f3f3">                <span style="color:#000000"></span><span style="color:#0000ff">if</span><span style="color:#000000"> (numDevices &gt; 0)</span></li> <li>                <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000"></span><span style="color:#0000ff">switch</span><span style="color:#000000"> (color)</span></li> <li>                    <span style="color:#000000">{</span></li> <li style="background: #f3f3f3">                        <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Blue:</span></li> <li>                            <span style="color:#000000">controller.TurnOnBlueLight(0);</span></li> <li style="background: #f3f3f3">                            <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li>                        <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Cyan:</span></li> <li style="background: #f3f3f3">                            <span style="color:#000000">controller.TurnOnCyanLight(0);</span></li> <li>                            <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">                        <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Green:</span></li> <li>                            <span style="color:#000000">controller.TurnOnGreenLight(0);</span></li> <li style="background: #f3f3f3">                            <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li>                        <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Off:</span></li> <li style="background: #f3f3f3">                            <span style="color:#000000">controller.ResetLight(0);</span></li> <li>                            <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">                        <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Purple:</span></li> <li>                            <span style="color:#000000">controller.TurnOnMagentaLight(0);</span></li> <li style="background: #f3f3f3">                            <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li>                        <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Red:</span></li> <li style="background: #f3f3f3">                            <span style="color:#000000">controller.TurnOnRedLight(0);</span></li> <li>                            <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">                        <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.White:</span></li> <li>                            <span style="color:#000000">controller.TurnOnWhiteLight(0);</span></li> <li style="background: #f3f3f3">                            <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li>                        <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Yellow:</span></li> <li style="background: #f3f3f3">                            <span style="color:#000000">controller.TurnOnYellowLight(0);</span></li> <li>                            <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">                        <span style="color:#000000"></span><span style="color:#0000ff">case</span><span style="color:#000000"> Blynclight.</span><span style="color:#2b91af">BlynclightController</span><span style="color:#000000">.</span><span style="color:#2b91af">Color</span><span style="color:#000000">.Orange:</span></li> <li>                            <span style="color:#000000">controller.TurnOnOrangeLight(0);</span></li> <li style="background: #f3f3f3">                            <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li>                        <span style="color:#000000"></span><span style="color:#0000ff">default</span><span style="color:#000000">:</span></li> <li style="background: #f3f3f3">                            <span style="color:#000000">controller.ResetLight(0);</span></li> <li>                            <span style="color:#000000"></span><span style="color:#0000ff">break</span><span style="color:#000000">;</span></li> <li style="background: #f3f3f3">                    <span style="color:#000000">}</span></li> <li>                <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">}</span></li> <li>            <span style="color:#000000"></span><span style="color:#0000ff">catch</span><span style="color:#000000"> (</span><span style="color:#2b91af">Exception</span><span style="color:#000000"> oops)</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">{</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3">            <span style="color:#000000">}</span></li> <li>            <span style="color:#000000"></span><span style="color:#0000ff">finally</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">{</span></li> <li>                <span style="color:#000000">controller.CloseDevices(numDevices);</span></li> <li style="background: #f3f3f3">            <span style="color:#000000">}</span></li> <li>        <span style="color:#000000">}</span></li> <li style="background: #f3f3f3">    <span style="color:#000000">}</span></li> <li><span style="color:#000000">}</span></li> </ol> </div> </div> </div><p>Again, I could have made this more user-driven, even provided a UI for the developer to choose what color happens when, if the light blinks or not, and even support multiple devices.&nbsp; The Blynclight SDK comes with a sample called BlyncLightTest that is a Windows Forms solution that you can grab some inspiration from.&nbsp; </p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/08/image316.png"><img width="244" height="119" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/08/image_thumb244.png" border="0"></a></p><h2>Summary</h2><p>This was cathartic for me.&nbsp; I really just wanted to know how to code a VSIX extension and to spend some time in Visual Studio doing something other than Azure.&nbsp; I coded this in about a day (gotta love editor inheritance from Stack Overflow).&nbsp; </p><p>The code is available for download at <a href="https://github.com/kaevans/BlyncLightAddin">https://github.com/kaevans/BlyncLightAddin</a>.&nbsp; </p><h2>For More Information</h2><p><a title="https://msdn.microsoft.com/en-us/library/cc138567.aspx" href="https://msdn.microsoft.com/en-us/library/cc138567.aspx">Adding a Tool Window</a></p><p><a title="http://www.andrewconnell.com/blog/Lync-BusyLight-Great-Solution-for-the-Home-Office" href="http://www.andrewconnell.com/blog/Lync-BusyLight-Great-Solution-for-the-Home-Office">Lync + BusyLight = Great Solution for the Home Office</a></p><p><a title="http://www.hanselman.com/blog/IsDaddyOnACallABusyLightPresenceIndicatorForLyncForMyHomeOffice.aspx" href="http://www.hanselman.com/blog/IsDaddyOnACallABusyLightPresenceIndicatorForLyncForMyHomeOffice.aspx">Is Daddy on a call? A BusyLight Presence indicator for Lync for my Home Office</a></p><p><a href="http://blynclight.proboards.com/thread/2/blync-sdk-create-own-applications">Blync SDK – Create Your Own Blync Applications</a> (requires free registration)</p><p><a href="http://ryanfarley.com/blog/archive/2010/04/23/sign-a-.net-assembly-with-a-strong-name-without-recompiling.aspx">Sign a .NET Assembly with a Strong Name Without Recompiling</a></p><p><a title="http://stackoverflow.com/questions/4372055/detect-active-window-changed-using-c-sharp-without-polling" href="http://stackoverflow.com/questions/4372055/detect-active-window-changed-using-c-sharp-without-polling">Detect active window changed using C# without polling</a></p><p>The code is available for download at <a href="https://github.com/kaevans/BlyncLightAddin">https://github.com/kaevans/BlyncLightAddin</a>.&nbsp; </p>]]></content:encoded>
    </item>
    <item>
      <title>Connecting Virtual Networks in ARM Templates</title>
      <link>https://docs.microsoft.com/archive/blogs/kaevans/connecting-virtual-networks-in-arm-templates</link>
      <pubDate>Thu, 02 Jun 2016 14:58:38 GMT</pubDate>
      <dc:creator><![CDATA[Kirk Evans[MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaevans/?p=13415</guid>
      <description><![CDATA[This post will demonstrate creating two virtual networks, gateways for each, and connecting them...]]></description>
      <content:encoded><![CDATA[<p>This post will demonstrate creating two virtual networks, gateways for each, and connecting them together using an ARM template.</p><h2>Background</h2><p>I am working on a project that requires two Azure virtual networks to connect together.&nbsp; I have done this so many times, typically through CLI scripts or PowerShell, but didn’t find the time to create an ARM template to demonstrate how to do this until today.&nbsp; The result is very simple:</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/06/image85.png"><img width="675" height="275" title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/06/image_thumb76.png" border="0"></a></p><p>Note that I use this for quick and dirty deployments since everything is in a single resource group.&nbsp; For a production deployment, I would split each VNet into a separate resource group and I would apply network security group rules to each subnet to control the traffic allowed in or out.&nbsp; I’d <a href="https://azure.microsoft.com/en-us/documentation/articles/vpn-gateway-vnet-vnet-rm-ps/">script the connection between the VNets</a> rather than put it in an ARM template.&nbsp; In other words, this is not a complete and representative example of a production deployment.&nbsp; For the recommended “golden path” to follow for a production scenario, see the Patterns &amp; Practices guidance on <a href="https://azure.microsoft.com/en-us/documentation/articles/guidance-iaas-ra-secure-vnet-hybrid/">Implementing a secure hybrid network architecture in Azure</a>.&nbsp; </p><h2>Show Me the Code</h2><p>Again, this is a quick and dirty example, for a production scenario see <a href="https://azure.microsoft.com/en-us/documentation/articles/guidance-iaas-ra-secure-vnet-hybrid/">Implementing a secure hybrid network architecture in Azure</a>.&nbsp; </p><div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:bff9ee0d-bf80-46f2-80cb-1af451afd6fe" style="margin: 0px;padding: 0px;float: none"> <div style="border: #000080 1px solid;color: #000;font-family: 'Courier New', Courier, Monospace;font-size: 10pt"> <div style="background: #000080;color: #fff;font-family: Verdana, Tahoma, Arial, sans-serif;font-weight: bold;padding: 2px 5px">Connect Two VNets</div> <div style="background: #ddd;overflow: auto"> <ol start="1" style="background: #ffffff;margin: 0 0 0 3em;padding: 0 0 0 5px"> <li>{</li> <li style="background: #f3f3f3">  <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;$schema&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>  <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;contentVersion&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;1.0.0.0&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">  <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;parameters&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>  <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;VPNSharedKey&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>    <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;type&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;securestring&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;metadata&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;Description&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Shared key between VNets&quot;</span></li> <li>      <span style="background:#ffffff;color:#000000">}</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000">},</span></li> <li>    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;Location&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000">{</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;type&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;string&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;defaultValue&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;centralus&quot;</span></li> <li>    <span style="background:#ffffff;color:#000000">}</span></li> <li style="background: #f3f3f3">  <span style="background:#ffffff;color:#000000">},</span></li> <li>  <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;variables&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">  <span style="background:#ffffff;color:#000000">{</span></li> <li>    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;primaryvnetname&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;primaryvnet&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;primaryvnetPrefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;10.0.0.0/16&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;primaryvnetSubnet1Name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Subnet-1&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;primaryvnetSubnet1Prefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;10.0.0.0/24&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;primaryvnetSubnet2Name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Subnet-2&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;primaryvnetSubnet2Prefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;10.0.1.0/24&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;primaryvnetGatewaySubnetPrefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;10.0.255.224/27&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;secondaryvnetname&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;secondaryvnet&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;secondaryvnetPrefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;192.168.0.0/16&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;secondaryvnetSubnet1Name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Subnet-1&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;secondaryvnetSubnet1Prefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;192.168.0.0/24&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;secondaryvnetSubnet2Name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Subnet-2&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;secondaryvnetSubnet2Prefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;192.168.1.0/24&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;secondaryvnetGatewaySubnetPrefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;192.168.255.224/27&quot;</span></li> <li>  <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">  <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;resources&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>  <span style="background:#ffffff;color:#000000">[</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000">{</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;primaryvnetname&#039;)]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;type&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/virtualNetworks&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;location&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[resourceGroup().location]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;apiVersion&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;2015-06-15&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;dependsOn&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">[</span></li> <li>      <span style="background:#ffffff;color:#000000">],</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;tags&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;displayName&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;primaryvnet&quot;</span></li> <li>      <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;addressSpace&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>        <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">          <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;addressPrefixes&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>          <span style="background:#ffffff;color:#000000">[</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;primaryvnetPrefix&#039;)]&quot;</span></li> <li>          <span style="background:#ffffff;color:#000000">]</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000">},</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;subnets&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000">[</span></li> <li>          <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;primaryvnetSubnet1Name&#039;)]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000">{</span></li> <li>              <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;addressPrefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;primaryvnetSubnet1Prefix&#039;)]&quot;</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000">}</span></li> <li>          <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">          <span style="background:#ffffff;color:#000000">{</span></li> <li>            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;primaryvnetSubnet2Name&#039;)]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>            <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">              <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;addressPrefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;primaryvnetSubnet2Prefix&#039;)]&quot;</span></li> <li>            <span style="background:#ffffff;color:#000000">}</span></li> <li style="background: #f3f3f3">          <span style="background:#ffffff;color:#000000">},</span></li> <li>          <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;GatewaySubnet&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000">{</span></li> <li>              <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;addressPrefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;primaryvnetGatewaySubnetPrefix&#039;)]&quot;</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000">}</span></li> <li>          <span style="background:#ffffff;color:#000000">}</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000">]</span></li> <li>      <span style="background:#ffffff;color:#000000">}</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000">},</span></li> <li>    <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;apiVersion&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;2015-06-15&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;type&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/publicIPAddresses&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;primaryGatewayPIP&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;location&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[parameters(&#039;Location&#039;)]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;tags&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;displayName&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Primary Gateway PIP&quot;</span></li> <li>      <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;publicIPAllocationMethod&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Dynamic&quot;</span></li> <li>      <span style="background:#ffffff;color:#000000">}</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000">},</span></li> <li>    <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;apiVersion&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;2015-06-15&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;type&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/virtualNetworkGateways&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;primaryGateway&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;location&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[parameters(&#039;Location&#039;)]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;dependsOn&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">[</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/publicIPAddresses/primaryGatewayPIP&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;[concat(&#039;Microsoft.Network/virtualNetworks/&#039;, variables(&#039;primaryvnetname&#039;))]&quot;</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">],</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;tags&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">{</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;displayName&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;primaryGateway&quot;</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">},</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">{</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;ipConfigurations&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000">[</span></li> <li>          <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>            <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">              <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;privateIPAllocationMethod&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Dynamic&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>              <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;subnet&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">              <span style="background:#ffffff;color:#000000">{</span></li> <li>                <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;id&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[resourceId(&#039;Microsoft.Network/virtualNetworks/subnets&#039;,variables(&#039;primaryvnetname&#039;),&#039;GatewaySubnet&#039;)]&quot;</span></li> <li style="background: #f3f3f3">              <span style="background:#ffffff;color:#000000">},</span></li> <li>              <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;publicIPAddress&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">              <span style="background:#ffffff;color:#000000">{</span></li> <li>                <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;id&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[resourceId(&#039;Microsoft.Network/publicIPAddresses&#039;,&#039;primaryGatewayPIP&#039;)]&quot;</span></li> <li style="background: #f3f3f3">              <span style="background:#ffffff;color:#000000">}</span></li> <li>            <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;vnetGatewayConfig&quot;</span></li> <li>          <span style="background:#ffffff;color:#000000">}</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000">],</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;gatewayType&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Vpn&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;vpnType&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;RouteBased&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;enableBgp&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#0000ff">false</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">}</span></li> <li>    <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000">{</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;secondaryvnetname&#039;)]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;type&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/virtualNetworks&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;location&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[resourceGroup().location]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;apiVersion&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;2015-06-15&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;dependsOn&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">[</span></li> <li>      <span style="background:#ffffff;color:#000000">],</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;tags&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;displayName&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;secondaryvnet&quot;</span></li> <li>      <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;addressSpace&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>        <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">          <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;addressPrefixes&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>          <span style="background:#ffffff;color:#000000">[</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;secondaryvnetPrefix&#039;)]&quot;</span></li> <li>          <span style="background:#ffffff;color:#000000">]</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000">},</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;subnets&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000">[</span></li> <li>          <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;secondaryvnetSubnet1Name&#039;)]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000">{</span></li> <li>              <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;addressPrefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;secondaryvnetSubnet1Prefix&#039;)]&quot;</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000">}</span></li> <li>          <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">          <span style="background:#ffffff;color:#000000">{</span></li> <li>            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;secondaryvnetSubnet2Name&#039;)]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>            <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">              <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;addressPrefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;secondaryvnetSubnet2Prefix&#039;)]&quot;</span></li> <li>            <span style="background:#ffffff;color:#000000">}</span></li> <li style="background: #f3f3f3">          <span style="background:#ffffff;color:#000000">},</span></li> <li>          <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;GatewaySubnet&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000">{</span></li> <li>              <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;addressPrefix&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[variables(&#039;secondaryvnetGatewaySubnetPrefix&#039;)]&quot;</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000">}</span></li> <li>          <span style="background:#ffffff;color:#000000">}</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000">]</span></li> <li>      <span style="background:#ffffff;color:#000000">}</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000">},</span></li> <li>    <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;apiVersion&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;2015-06-15&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;type&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/publicIPAddresses&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;secondaryGatewayPIP&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;location&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[parameters(&#039;Location&#039;)]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;tags&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;displayName&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Secondary Gateway PIP&quot;</span></li> <li>      <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;publicIPAllocationMethod&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Dynamic&quot;</span></li> <li>      <span style="background:#ffffff;color:#000000">}</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000">},</span></li> <li>    <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;apiVersion&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;2015-06-15&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;type&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/virtualNetworkGateways&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;secondaryGateway&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;location&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[parameters(&#039;Location&#039;)]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;dependsOn&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">[</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/publicIPAddresses/secondaryGatewayPIP&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;[concat(&#039;Microsoft.Network/virtualNetworks/&#039;, variables(&#039;secondaryvnetname&#039;))]&quot;</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">],</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;tags&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">{</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;displayName&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;secondaryGateway&quot;</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">},</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">{</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;ipConfigurations&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000">[</span></li> <li>          <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>            <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">              <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;privateIPAllocationMethod&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Dynamic&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>              <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;subnet&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">              <span style="background:#ffffff;color:#000000">{</span></li> <li>                <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;id&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[resourceId(&#039;Microsoft.Network/virtualNetworks/subnets&#039;,variables(&#039;secondaryvnetname&#039;),&#039;GatewaySubnet&#039;)]&quot;</span></li> <li style="background: #f3f3f3">              <span style="background:#ffffff;color:#000000">},</span></li> <li>              <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;publicIPAddress&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li style="background: #f3f3f3">              <span style="background:#ffffff;color:#000000">{</span></li> <li>                <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;id&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[resourceId(&#039;Microsoft.Network/publicIPAddresses&#039;,&#039;secondaryGatewayPIP&#039;)]&quot;</span></li> <li style="background: #f3f3f3">              <span style="background:#ffffff;color:#000000">}</span></li> <li>            <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">            <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;vnetGatewayConfig&quot;</span></li> <li>          <span style="background:#ffffff;color:#000000">}</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000">],</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;gatewayType&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Vpn&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;vpnType&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;RouteBased&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;enableBgp&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#0000ff">false</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">}</span></li> <li>    <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000">{</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;primary2secondary&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;type&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/connections&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;apiVersion&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;2016-03-30&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;dependsOn&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">[</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;[concat(&#039;Microsoft.Network/virtualNetworks/&#039;, variables(&#039;primaryvnetname&#039;))]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;[concat(&#039;Microsoft.Network/virtualNetworks/&#039;, variables(&#039;secondaryvnetname&#039;))]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/virtualNetworkGateways/primaryGateway&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/virtualNetworkGateways/secondaryGateway&quot;</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">],</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;location&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[parameters(&#039;Location&#039;)]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;tags&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;displayName&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Primary to Secondary Connection&quot;</span></li> <li>      <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;virtualNetworkGateway1&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>        <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">          <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;id&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[resourceId(&#039;Microsoft.Network/virtualNetworkGateways&#039;, &#039;primaryGateway&#039;)]&quot;</span></li> <li>        <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;virtualNetworkGateway2&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>        <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">          <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;id&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[resourceId(&#039;Microsoft.Network/virtualNetworkGateways&#039;, &#039;secondaryGateway&#039;)]&quot;</span></li> <li>        <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;connectionType&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Vnet2Vnet&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;sharedKey&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[parameters(&#039;VPNSharedKey&#039;)]&quot;</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">}</span></li> <li>    <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">    <span style="background:#ffffff;color:#000000">{</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;name&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;secondary2primary&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;type&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/connections&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;apiVersion&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;2016-03-30&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;dependsOn&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">[</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;[concat(&#039;Microsoft.Network/virtualNetworks/&#039;, variables(&#039;primaryvnetname&#039;))]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;[concat(&#039;Microsoft.Network/virtualNetworks/&#039;, variables(&#039;secondaryvnetname&#039;))]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/virtualNetworkGateways/primaryGateway&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#a31515">&quot;Microsoft.Network/virtualNetworkGateways/secondaryGateway&quot;</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">],</span></li> <li>      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;location&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[parameters(&#039;Location&#039;)]&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;tags&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;displayName&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Secondary to Primary Connection&quot;</span></li> <li>      <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;properties&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>      <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;virtualNetworkGateway1&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>        <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">          <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;id&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[resourceId(&#039;Microsoft.Network/virtualNetworkGateways&#039;, &#039;secondaryGateway&#039;)]&quot;</span></li> <li>        <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;virtualNetworkGateway2&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>        <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">          <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;id&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[resourceId(&#039;Microsoft.Network/virtualNetworkGateways&#039;, &#039;primaryGateway&#039;)]&quot;</span></li> <li>        <span style="background:#ffffff;color:#000000">},</span></li> <li style="background: #f3f3f3">        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;connectionType&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;Vnet2Vnet&quot;</span><span style="background:#ffffff;color:#000000">,</span></li> <li>        <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;sharedKey&quot;</span><span style="background:#ffffff;color:#000000">: </span><span style="background:#ffffff;color:#a31515">&quot;[parameters(&#039;VPNSharedKey&#039;)]&quot;</span></li> <li style="background: #f3f3f3">      <span style="background:#ffffff;color:#000000">}</span></li> <li>    <span style="background:#ffffff;color:#000000">}</span></li> <li style="background: #f3f3f3">&nbsp;</li> <li>  <span style="background:#ffffff;color:#000000">],</span></li> <li style="background: #f3f3f3">  <span style="background:#ffffff;color:#000000"></span><span style="background:#ffffff;color:#2e75b6">&quot;outputs&quot;</span><span style="background:#ffffff;color:#000000">:</span></li> <li>  <span style="background:#ffffff;color:#000000">{</span></li> <li style="background: #f3f3f3">  <span style="background:#ffffff;color:#000000">}</span></li> <li><span style="background:#ffffff;color:#000000">}</span></li> </ol> </div> </div> </div><p><br></p><p>One of the things I like about this approach is how everything is parallelized.&nbsp; The VNets and Public IPs are created in parallel, then both gateways are created in parallel.&nbsp; This is a huge timesaver because each gateway creation takes around 30 minutes for each.. doing this in parallel reduces the time to just over 30 minutes total (my last deployment was just 33 minutes).&nbsp; </p><h2>Summary</h2><p>It’s a neat template and all, but not something that I would recommend for a production deployment.&nbsp; Instead, I would likely approach this with two different resource groups, and then use script (CLI or PowerShell) to connect the VNets together as shown in the article <a title="https://azure.microsoft.com/en-us/documentation/articles/vpn-gateway-vnet-vnet-rm-ps/" href="https://azure.microsoft.com/en-us/documentation/articles/vpn-gateway-vnet-vnet-rm-ps/">Configure a VNet-to-VNet connection by using Azure Resource Manager and PowerShell</a>.&nbsp; That said, I will probably use it often for quick and dirty tests across VNets since it’s easier to manage all the resources at once.</p><h2>Acknowledgement</h2><p>I have to thank <a href="https://www.linkedin.com/in/devin-lusby-536952b9">Devin Lusby from Avanade</a> who showed me how to create the Microsoft.Network/connections resource.&nbsp; </p><h2>For More Information</h2><p><a href="https://azure.microsoft.com/en-us/documentation/articles/guidance-iaas-ra-secure-vnet-hybrid/">Implementing a secure hybrid network architecture in Azure</a></p><p><a title="https://azure.microsoft.com/en-us/documentation/articles/vpn-gateway-vnet-vnet-rm-ps/" href="https://azure.microsoft.com/en-us/documentation/articles/vpn-gateway-vnet-vnet-rm-ps/">Configure a VNet-to-VNet connection by using Azure Resource Manager and PowerShell</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Azure Web App Client Certificate Authentication with ASP.NET Core</title>
      <link>https://docs.microsoft.com/archive/blogs/kaevans/azure-web-app-client-certificate-authentication-with-asp-net-core-2</link>
      <pubDate>Wed, 13 Apr 2016 06:40:58 GMT</pubDate>
      <dc:creator><![CDATA[Kirk Evans[MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/kaevans/?p=13391</guid>
      <description><![CDATA[This post will walk through securing an ASP.NET Core application deployed to an Azure Web App that...]]></description>
      <content:encoded><![CDATA[<p>This post will walk through securing an ASP.NET Core application deployed to an Azure Web App that is secured using client certificates.</p><p>The code is available for download at <a title="ClientCertDemo" href="https://github.com/kaevans/ClientCertDemo">ClientCertDemo</a>.&nbsp; </p><h2>Background</h2><p>Many customers have implemented client certificates for older web applications and are looking at Azure Web Apps to move their code.&nbsp; A common question is how to leverage client certificates in Azure Web Apps.&nbsp; This demo shows one possible solution to validating the certificate.</p><p>The client application will add the client certificate to the HTTP request.&nbsp; We will update the Azure Web App to enable client certificates, and the client certificate will be available using the X-ARR-ClientCert HTTP header.&nbsp; We can then parse this as an X509Certificate2 class to read the properties of the certificate and perform validation.&nbsp; Note that Azure Web Apps do not perform any validation on the certificate, this is up to the application to implement.&nbsp; That’s what this post shows.</p><p>The source code for the web application is available at <a title="https://github.com/kaevans/ClientCertDemo" href="https://github.com/kaevans/ClientCertDemo">https://github.com/kaevans/ClientCertDemo</a>.&nbsp; </p><h2>Create the Certificates</h2><p>There’s nothing special about the certificate used in this demo, we’ll use self-signed certificates.&nbsp; In fact, I am going to reuse the self-signed certificate that I used for creating a point-to-site VPN connection.&nbsp; I am using makecert.exe, which is easy to find if you have Visual Studio 2015 installed… just load the “VS2015 x64 x86 Cross Tools Command Prompt”.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image581.png"><img width="165" height="244" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb455.png" border="0"></a></p><p>First, generate the root cert.</p><div class="wlWriterSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:e1613338-faff-4408-bce0-a21cfc995aef" style="margin: 0px;padding: 0px;float: none"> <div> <div>Generate a Root Certificate</div> <div> <ol start="1"> <li><span>makecert -sky exchange -r -n "CN=NetworkingDemoRootCert2" -pe -a sha1 -len 2048 -ss My "NetworkingDemoRootCert2.cer"</span></li> </ol> </div> </div> </div><p>Next, generate a client certificate that references the root certificate.</p><div class="wlWriterSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:d658375a-5710-46f6-ba3c-a1b627b7a2c2" style="margin: 0px;padding: 0px;float: none"> <div> <div>Generate Client Certificate</div> <div> <ol start="1"> <li><span>makecert.exe -n "CN=NetworkingDemoClientCert2" -pe -sky exchange -m 96 -ss My -in "NetworkingDemoRootCert2" -is my -a sha1</span></li> </ol> </div> </div> </div>
<p>Now open certmgr.msc to verify the certificates are there.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image582.png"><img width="244" height="94" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb456.png" border="0"></a></p><p>Double-click on the client cert that you just created and see its properties, we’ll need these properties in a moment.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image583.png"><img width="193" height="244" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb457.png" border="0"></a></p><p>Now that we have the certs, create the project.</p><h2>Create the Web Application</h2><p>Create a new ASP.NET Web Application.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image584.png"><img width="244" height="139" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb458.png" border="0"></a></p><p>Use the ASP.NET 5 Web API template, and choose host in Azure Web App.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image585.png"><img width="244" height="191" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb459.png" border="0"></a></p><p>You are prompted to create the Azure Web App.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image586.png"><img width="244" height="184" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb460.png" border="0"></a></p><h2>Enable Configuration</h2><p>Update the dependencies in the project.json file to include Microsoft.Extensions.OptionModel.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image587.png"><img width="244" height="159" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb461.png" border="0"></a></p><p>Update appsettings.json with the values from your certificate, taking care to remove spaces from the values (I lost a bit of time troubleshooting that one!)</p><div class="wlWriterSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:866e6b5e-ee1f-4ad9-94d8-ccd216811f4b" style="margin: 0px;padding: 0px;float: none"> <div> <div>appsettings.json</div> <div> <ol start="1"> <li>{</li> <li>&nbsp; <span></span><span>"Logging"</span><span>:</span></li> <li>&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp; <span></span><span>"IncludeScopes"</span><span>: </span><span>false</span><span>,</span></li> <li>&nbsp;&nbsp;&nbsp; <span></span><span>"LogLevel"</span><span>:</span></li> <li>&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>"Default"</span><span>: </span><span>"Debug"</span><span>,</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>"System"</span><span>: </span><span>"Debug"</span><span>,</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>"Microsoft"</span><span>: </span><span>"Debug"</span></li> <li>&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp; <span>},</span></li> <li>&nbsp; <span></span><span>"CertificateValidation"</span><span>:</span></li> <li>&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp; <span></span><span>"Subject"</span><span>: </span><span>"CN=NetworkingDemoClientCert2a"</span><span>,</span></li> <li>&nbsp;&nbsp;&nbsp; <span></span><span>"IssuerCN"</span><span>: </span><span>"CN=NetworkingDemoRootCert2"</span><span>,</span></li> <li>&nbsp;&nbsp;&nbsp; <span></span><span>"Thumbprint"</span><span>: </span><span>"E8434AB532846AD2BDF20863A8789AF23E20ECBA"</span></li> <li>&nbsp; <span>}</span></li> <li><span>}</span></li> </ol> </div> </div> </div><p><br></p><p>Add a class to hold the configuration values.</p><div class="wlWriterSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:bfba2436-7bdc-4454-a4f2-d37e59f186c1" style="margin: 0px;padding: 0px;float: none"> <div> <div>CertificateValidationConfig</div> <div> <ol start="1"> <li><span>namespace</span><span> ClientCertWeb</span></li> <li><span>{</span></li> <li>&nbsp;&nbsp;&nbsp; <span></span><span>public</span><span> </span><span>class</span><span> </span><span>CertificateValidationConfig</span></li> <li>&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>public</span><span> </span><span>string</span><span> Subject { </span><span>get</span><span>; </span><span>set</span><span>; }</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>public</span><span> </span><span>string</span><span> IssuerCN { </span><span>get</span><span>; </span><span>set</span><span>; }</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>public</span><span> </span><span>string</span><span> Thumbprint { </span><span>get</span><span>; </span><span>set</span><span>; }</span></li> <li>&nbsp;&nbsp;&nbsp; <span>}</span></li> <li><span>}</span></li> </ol> </div> </div> </div><p>Now update the ConfigureServices method in Startup.cs to use services.AddOptions and register your custom class with the dependency injection system.</p><div class="wlWriterSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:00542a48-59f2-4ff6-9547-f2a21d88be0c" style="margin: 0px;padding: 0px;float: none"> <div> <div>ConfigureServices</div> <div> <ol start="1"> <li><span></span><span>public</span><span> </span><span>void</span><span> ConfigureServices(</span><span>IServiceCollection</span><span> services)</span></li> <li><span>{</span></li> <li>&nbsp;&nbsp;&nbsp; <span>services.AddOptions();</span></li> <li>&nbsp;&nbsp;&nbsp; <span>services.Configure&lt;</span><span>CertificateValidationConfig</span><span>&gt;(Configuration.GetSection(</span><span>"CertificateValidation"</span><span>));</span></li> <li>&nbsp;&nbsp;&nbsp; <span></span><span>// Add framework services.</span></li> <li>&nbsp;&nbsp;&nbsp; <span>services.AddMvc();</span></li> <li><span>}</span></li> </ol> </div> </div> </div><p><br></p><h2>Add Some Middleware</h2><p>Add a middleware class.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image588.png"><img width="244" height="139" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb462.png" border="0"></a></p><p>The middleware class will request the configuration class via the Options model, and will also request logging via dependency injection via its constructor.&nbsp; We add an overload to the extensions class to add the options model in the constructor.&nbsp; When the HTTP request is received, the Invoke method is run for every request, and the configuration and logging types are passed to our middleware.&nbsp; The Invoke method will validate the certificate that is passed.&nbsp; The validation code is borrowed from the article <a title="https://azure.microsoft.com/en-us/documentation/articles/app-service-web-configure-tls-mutual-auth/" href="https://azure.microsoft.com/en-us/documentation/articles/app-service-web-configure-tls-mutual-auth/">How To Configure TLS Mutual Authentication for Web App</a> with a few slight modifications to enable using the configuration system and adding logging.</p><div class="wlWriterSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:bc660a8f-7e43-47eb-8028-261697c116cb" style="margin: 0px;padding: 0px;float: none"> <div> <div>ClientCertMiddleware</div> <div> <ol start="1"> <li><span>using</span><span> Microsoft.AspNet.Builder;</span></li> <li><span>using</span><span> Microsoft.AspNet.Http;</span></li> <li><span>using</span><span> Microsoft.Extensions.Logging;</span></li> <li><span>using</span><span> Microsoft.Extensions.OptionsModel;</span></li> <li><span>using</span><span> System;</span></li> <li><span>using</span><span> System.Security.Cryptography.X509Certificates;</span></li> <li><span>using</span><span> System.Threading.Tasks;</span></li> <li>&nbsp;</li> <li><span>namespace</span><span> ClientCertWeb</span></li> <li><span>{</span></li> <li>&nbsp;&nbsp;&nbsp; <span></span><span>// You may need to install the Microsoft.AspNet.Http.Abstractions package into your project</span></li> <li>&nbsp;&nbsp;&nbsp; <span></span><span>public</span><span> </span><span>class</span><span> </span><span>ClientCertificateMiddleware</span></li> <li>&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>private</span><span> </span><span>readonly</span><span> </span><span>RequestDelegate</span><span> _next;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>private</span><span> </span><span>readonly</span><span> </span><span>CertificateValidationConfig</span><span> _config;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>private</span><span> </span><span>readonly</span><span> </span><span>ILogger</span><span> _logger;</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>public</span><span> ClientCertificateMiddleware(</span><span>RequestDelegate</span><span> next, </span><span>ILoggerFactory</span><span> loggerFactory, </span><span>IOptions</span><span>&lt;</span><span>CertificateValidationConfig</span><span>&gt; options)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>_next = next;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>_config = options.Value;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>_logger = loggerFactory.CreateLogger&lt;</span><span>ClientCertificateMiddleware</span><span>&gt;();</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>public</span><span> </span><span>async</span><span> </span><span>Task</span><span> Invoke(</span><span>HttpContext</span><span> context)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//Validate the cert here</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>bool</span><span> isValidCert = </span><span>false</span><span>;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>X509Certificate2</span><span> certificate = </span><span>null</span><span>;</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>string</span><span> certHeader = context.Request.Headers[</span><span>"X-ARR-ClientCert"</span><span>];</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>if</span><span> (!</span><span>String</span><span>.IsNullOrEmpty(certHeader))</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>try</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>byte</span><span>[] clientCertBytes = </span><span>Convert</span><span>.FromBase64String(certHeader);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>certificate = </span><span>new</span><span> </span><span>X509Certificate2</span><span>(clientCertBytes);</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>isValidCert = IsValidClientCertificate(certificate);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>if</span><span> (isValidCert)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//Invoke the next middleware in the pipeline</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>await</span><span> _next.Invoke(context);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>else</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//Stop the pipeline here.</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>_logger.LogError(</span><span>"Certificate is not valid"</span><span>);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>context.Response.StatusCode = 403;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>catch</span><span> (</span><span>Exception</span><span> ex)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//What to do with exceptions in middleware?</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>_logger.LogError(ex.Message, ex);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>await</span><span> context.Response.WriteAsync(ex.Message);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>context.Response.StatusCode = 403;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>else</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>_logger.LogError(</span><span>"X-ARR-ClientCert header is missing"</span><span>);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>context.Response.StatusCode = 403;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;</li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>private</span><span> </span><span>bool</span><span> IsValidClientCertificate(</span><span>X509Certificate2</span><span> certificate)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>// In this example we will only accept the certificate as a valid certificate if all the conditions below are met:</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>// 1. The certificate is not expired and is active for the current time on server.</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>// 2. The subject name of the certificate has the common name nildevecc</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>// 3. The issuer name of the certificate has the common name nildevecc and organization name Microsoft Corp</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>// 4. The thumbprint of the certificate is 30757A2E831977D8BD9C8496E4C99AB26CB9622B</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>// This example does NOT test that this certificate is chained to a Trusted Root Authority (or revoked) on the server </span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>// and it allows for self signed certificates</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>if</span><span> (</span><span>null</span><span> == certificate) </span><span>return</span><span> </span><span>false</span><span>;</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>// 1. Check time validity of certificate</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>if</span><span> (</span><span>DateTime</span><span>.Compare(</span><span>DateTime</span><span>.Now, certificate.NotBefore) &lt; 0 || </span><span>DateTime</span><span>.Compare(</span><span>DateTime</span><span>.Now, certificate.NotAfter) &gt; 0) </span><span>return</span><span> </span><span>false</span><span>;</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>// 2. Check subject name of certificate</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>bool</span><span> foundSubject = </span><span>false</span><span>;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>string</span><span>[] certSubjectData = certificate.Subject.Split(</span><span>new</span><span> </span><span>char</span><span>[] { </span><span>','</span><span> }, </span><span>StringSplitOptions</span><span>.RemoveEmptyEntries);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>foreach</span><span> (</span><span>string</span><span> s </span><span>in</span><span> certSubjectData)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>if</span><span> (</span><span>String</span><span>.Compare(s.Trim(), _config.Subject) == 0)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>foundSubject = </span><span>true</span><span>;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>break</span><span>;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>if</span><span> (!foundSubject) </span><span>return</span><span> </span><span>false</span><span>;</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>// 3. Check issuer name of certificate</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>bool</span><span> foundIssuerCN = </span><span>false</span><span>;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>string</span><span>[] certIssuerData = certificate.Issuer.Split(</span><span>new</span><span> </span><span>char</span><span>[] { </span><span>','</span><span> }, </span><span>StringSplitOptions</span><span>.RemoveEmptyEntries);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>foreach</span><span> (</span><span>string</span><span> s </span><span>in</span><span> certIssuerData)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>if</span><span> (</span><span>String</span><span>.Compare(s.Trim(), _config.IssuerCN) == 0)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>foundIssuerCN = </span><span>true</span><span>;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>break</span><span>;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>if</span><span> (!foundIssuerCN) </span><span>return</span><span> </span><span>false</span><span>;</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>// 4. Check thumprint of certificate</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>if</span><span> (</span><span>String</span><span>.Compare(certificate.Thumbprint.Trim().ToUpper(), _config.Thumbprint) != 0) </span><span>return</span><span> </span><span>false</span><span>;</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>// If you also want to test if the certificate chains to a Trusted Root Authority you can uncomment the code below</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//X509Chain certChain = new X509Chain();</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//certChain.Build(certificate);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//bool isValidCertChain = true;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//foreach (X509ChainElement chElement in certChain.ChainElements)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//&nbsp;&nbsp;&nbsp; if (!chElement.Certificate.Verify())</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//&nbsp;&nbsp;&nbsp; {</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; isValidCertChain = false;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//&nbsp;&nbsp;&nbsp; }</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//}</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//if (!isValidCertChain) return false;</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>return</span><span> </span><span>true</span><span>;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp; <span></span><span>// Extension method used to add the middleware to the HTTP request pipeline.</span></li> <li>&nbsp;&nbsp;&nbsp; <span></span><span>public</span><span> </span><span>static</span><span> </span><span>class</span><span> </span><span>ClientCertMiddlewareExtensions</span></li> <li>&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>public</span><span> </span><span>static</span><span> </span><span>IApplicationBuilder</span><span> UseClientCertMiddleware(</span><span>this</span><span> </span><span>IApplicationBuilder</span><span> builder)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>return</span><span> builder.UseMiddleware&lt;</span><span>ClientCertificateMiddleware</span><span>&gt;();</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>public</span><span> </span><span>static</span><span> </span><span>IApplicationBuilder</span><span> UseClientCertMiddleware(</span><span>this</span><span> </span><span>IApplicationBuilder</span><span> builder, </span><span>IOptions</span><span>&lt;</span><span>CertificateValidationConfig</span><span>&gt; options)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>return</span><span> builder.UseMiddleware&lt;</span><span>ClientCertificateMiddleware</span><span>&gt;(options);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;&nbsp;&nbsp; <span>}</span></li> <li><span>}</span></li> </ol> </div> </div> </div><p><br></p><p>To enable logging when deployed to Azure, modify the web.config file and change the stdoutLogEnabled value to true.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image589.png"><img width="244" height="57" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb463.png" border="0"></a></p><p>When deployed to Azure, this will write the log files so that you can troubleshoot when things aren’t working.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image590.png"><img width="244" height="243" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb464.png" border="0"></a></p><p>Finally, we need to register our middleware in the Configure method in Startup.cs.</p><div class="wlWriterSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:c44aea8d-b40a-4a4e-92dc-88fde05fcb16" style="margin: 0px;padding: 0px;float: none"> <div> <div>Configure</div> <div> <ol start="1"> <li><span></span><span>public</span><span> </span><span>void</span><span> Configure(</span><span>IApplicationBuilder</span><span> app, </span><span>IHostingEnvironment</span><span> env, </span><span>ILoggerFactory</span><span> loggerFactory)</span></li> <li><span>{</span></li> <li>&nbsp;&nbsp;&nbsp; <span>loggerFactory.AddConsole(Configuration.GetSection(</span><span>"Logging"</span><span>));</span></li> <li>&nbsp;&nbsp;&nbsp; <span>loggerFactory.AddDebug();</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp; <span>app.UseIISPlatformHandler();</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp; <span>app.UseStaticFiles();</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp; <span>app.UseClientCertMiddleware();</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp; <span>app.UseMvc();</span></li> <li><span>}</span></li> </ol> </div> </div> </div><p><br></p><p>That’s it!&nbsp; We have now created the middleware needed to validate the certificate.&nbsp; </p><h2>Update the Azure Web App</h2><p>The Azure Web App needs to be updated in order to allow client certificates.&nbsp; There are instructions at <a title="https://azure.microsoft.com/en-us/documentation/articles/app-service-web-configure-tls-mutual-auth/" href="https://azure.microsoft.com/en-us/documentation/articles/app-service-web-configure-tls-mutual-auth/">How To Configure TLS Mutual Authentication for Web App</a> that show how to use ARMClient to update the web app.&nbsp; Note that you could do this at deployment time if you were deploying using an ARM Template with web deploy.&nbsp; </p><p>The PUT request that you need looks like:</p><div class="wlWriterSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:818a8a15-d45d-44ce-b91d-e714373e7d3e" style="margin: 0px;padding: 0px;float: none"> <div> <div>ARMClient PUT</div> <div> <ol start="1"> <li><span>ARMClient PUT subscriptions/{Subscription Id}/resourcegroups/{Resource Group Name}/providers/Microsoft.Web/sites/{Website Name}?api-version=2015-04-01 @enableclientcert.json -verbose</span></li> </ol> </div> </div> </div><p><br></p><p>The ARMClient tool requires your subscription ID, resource group name, and web app name.&nbsp; An easy way to get this information is to go to the Azure portal and go to your web app’s properties, looking at the resource ID.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image591.png"><img width="244" height="209" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb465.png" border="0"></a></p><p>Create a local file, enableclientcert.json and use your web app’s location in the file.</p><div class="wlWriterSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:c6124763-d566-43a8-ae0b-254395cc32c5" style="margin: 0px;padding: 0px;float: none"> <div> <div>enableclientcert.json</div> <div> <ol start="1"> <li>{<span> </span><span>"location"</span><span>: </span><span>"South Central US"</span><span>,</span></li> <li><span> </span><span>"properties"</span><span>: {</span></li> <li><span> </span><span>"clientCertEnabled"</span><span>: </span><span>true</span><span> } }</span></li> </ol> </div> </div> </div><p><br></p><p>Run ARMClient.exe with the PUT URL and the output will look similar to the following.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image592.png"><img width="244" height="204" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb466.png" border="0"></a></p><h2>Publish the Web Application</h2><p>Right-click the project and choose Publish to publish the web application to Azure.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image593.png"><img width="244" height="194" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb467.png" border="0"></a></p><p>When the publish is complete, you’ll get an error page in the browser with a 403 error.&nbsp; </p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image594.png"><img width="244" height="57" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb468.png" border="0"></a></p><p>I opened an incognito window in Chrome and changed to the HTTPS URL for my Web API controller.&nbsp; I am prompted for a client certificate.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image595.png"><img width="244" height="84" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb469.png" border="0"></a></p><p>I provide it and now I can access the values.</p><p><a href="https://msdnshared.blob.core.windows.net/media/2016/04/image596.png"><img width="244" height="54" title="image" style="margin: 0px" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/04/image_thumb470.png" border="0"></a></p><h2>Create a Client Application</h2><p>For an extra bonus, I created a client application to test things out.&nbsp; It uses the HttpClient API to make a request to Azure.&nbsp; Make sure that you are using the SSL URL, else the certificate will not be sent.</p><div class="wlWriterSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:984c7dd5-7ced-40db-a60b-e3bf86f7b5cd" style="margin: 0px;padding: 0px;float: none"> <div> <div>Client</div> <div> <ol start="1"> <li><span>using</span><span> System;</span></li> <li><span>using</span><span> System.Collections.Generic;</span></li> <li><span>using</span><span> System.Linq;</span></li> <li><span>using</span><span> System.Net.Http;</span></li> <li><span>using</span><span> System.Net.Http.Headers;</span></li> <li><span>using</span><span> System.Net.Security;</span></li> <li><span>using</span><span> System.Security.Cryptography.X509Certificates;</span></li> <li><span>using</span><span> System.Text;</span></li> <li><span>using</span><span> System.Threading.Tasks;</span></li> <li>&nbsp;</li> <li><span>namespace</span><span> client</span></li> <li><span>{</span></li> <li>&nbsp;&nbsp;&nbsp; <span></span><span>class</span><span> </span><span>Program</span></li> <li>&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>static</span><span> </span><span>void</span><span> Main(</span><span>string</span><span>[] args)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>var</span><span> p = </span><span>new</span><span> </span><span>Program</span><span>();</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>p.RunAsync().Wait();</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>private</span><span> </span><span>async</span><span> </span><span>Task</span><span> RunAsync()</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>var</span><span> handler = </span><span>new</span><span> </span><span>WebRequestHandler</span><span>();</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>handler.ClientCertificateOptions = </span><span>ClientCertificateOption</span><span>.Manual;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>var</span><span> cert = GetClientCert();</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>handler.ClientCertificates.Add(cert);</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>handler.ServerCertificateValidationCallback = </span><span>delegate</span><span> (</span><span>object</span><span> sender, </span><span>X509Certificate</span><span> certificate, </span><span>X509Chain</span><span> chain, </span><span>SslPolicyErrors</span><span> error)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//Ignore errors</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>return</span><span> </span><span>true</span><span>;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>};</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>handler.UseProxy = </span><span>false</span><span>;</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>using</span><span> (</span><span>var</span><span> client = </span><span>new</span><span> </span><span>HttpClient</span><span>(handler))</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>client.BaseAddress = </span><span>new</span><span> </span><span>Uri</span><span>(</span><span>"https://certdemo.azurewebsites.net/"</span><span>);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>//client.BaseAddress = new Uri("https://localhost:44315/");</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>client.DefaultRequestHeaders.Accept.Clear();</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>client.DefaultRequestHeaders.Accept.Add(</span><span>new</span><span> </span><span>MediaTypeWithQualityHeaderValue</span><span>(</span><span>"application/json"</span><span>));</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>var</span><span> response = </span><span>await</span><span> client.GetAsync(</span><span>"api/values"</span><span>);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>if</span><span> (response.IsSuccessStatusCode)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>var</span><span> str = </span><span>await</span><span> response.Content.ReadAsStringAsync();</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>Console</span><span>.WriteLine(str);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>else</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>Console</span><span>.WriteLine(</span><span>"FAIL:"</span><span> + response.StatusCode);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>private</span><span> </span><span>static</span><span> </span><span>X509Certificate</span><span> GetClientCert()</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>X509Store</span><span> store = </span><span>null</span><span>;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>try</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>store = </span><span>new</span><span> </span><span>X509Store</span><span>(</span><span>StoreName</span><span>.My, </span><span>StoreLocation</span><span>.CurrentUser);</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>store.Open(</span><span>OpenFlags</span><span>.OpenExistingOnly | </span><span>OpenFlags</span><span>.ReadOnly);</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>var</span><span> certs = store.Certificates.Find(</span><span>X509FindType</span><span>.FindBySubjectName, </span><span>"NetworkingDemoClientCert2"</span><span>, </span><span>true</span><span>);</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>if</span><span> (certs.Count == 1)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>var</span><span> cert = certs[0];</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>return</span><span> cert;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>finally</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>{</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>if</span><span> (store != </span><span>null</span><span>)</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>store.Close();</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span></span><span>return</span><span> </span><span>null</span><span>;</span></li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>}</span></li> <li>&nbsp;&nbsp;&nbsp; <span>}</span></li> <li><span>}</span></li> </ol> </div> </div> </div><p><br></p><p>Just like in the web page, the client works, too.&nbsp; The source code for the web application is available at <a title="https://github.com/kaevans/ClientCertDemo" href="https://github.com/kaevans/ClientCertDemo">https://github.com/kaevans/ClientCertDemo</a>.&nbsp; </p><h2>For More Information</h2><p><a title="https://azure.microsoft.com/en-us/documentation/articles/app-service-web-configure-tls-mutual-auth/" href="https://azure.microsoft.com/en-us/documentation/articles/app-service-web-configure-tls-mutual-auth/">How To Configure TLS Mutual Authentication for Web App</a></p><p><a title="https://github.com/kaevans/ClientCertDemo" href="https://github.com/kaevans/ClientCertDemo">https://github.com/kaevans/ClientCertDemo</a></p>]]></content:encoded>
    </item>
  </channel>
</rss>