<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>The Cloud PFE</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/cloudpfe/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/cloudpfe/feed.xml</link>
    <description />
    <lastBuildDate>Tue, 02 Oct 2018 19:54:52 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Using Azure AD Device Code Flow with PowerShell</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudpfe/using-azure-ad-device-code-flow-with-powershell</link>
      <pubDate>Tue, 02 Oct 2018 17:50:11 GMT</pubDate>
      <dc:creator><![CDATA[Tino Donderwinkel]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudpfe/?p=795</guid>
      <description><![CDATA[Azure AD supports OAuth 2.0 Device Flow for Browserless and Input Constraint devices, as described...]]></description>
      <content:encoded><![CDATA[<p>Azure AD supports OAuth 2.0 Device Flow for Browserless and Input Constraint devices, as described here; <a title="https://tools.ietf.org/html/draft-ietf-oauth-device-flow-07" href="https://tools.ietf.org/html/draft-ietf-oauth-device-flow-07">https://tools.ietf.org/html/draft-ietf-oauth-device-flow-07</a></p><p>Assuming you do not want to, or cannot, use ADAL in PowerShell, you can script this flow entirely in native PowerShell.</p>
<!-- HTML generated using hilite.me --><div style="background: #f8f8f8;overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em"><pre style="margin: 0;line-height: 125%"><span style="color: #19177C">$clientId</span> = <span style="color: #BA2121">&quot;1950a258-227b-4e31-a9cf-717495945fc2&quot;</span>       <span style="color: #408080;font-style: italic"># This is the standard Client Identifier for Windows Azure PowerShell</span>
<span style="color: #19177C">$redirectUrl</span> = <span style="color: #880000">[System.Uri]</span><span style="color: #BA2121">&quot;urn:ietf:wg:oauth:2.0:oob&quot;</span>   <span style="color: #408080;font-style: italic"># This is the standard Redirect URI for Windows Azure PowerShell</span>
<span style="color: #19177C">$tenant</span> = <span style="color: #BA2121">&quot;YOURTENANTNAME.onmicrosoft.com&quot;</span>
<span style="color: #19177C">$resource</span> = <span style="color: #BA2121">&quot;https://graph.windows.net&quot;</span><span style="border: 1px solid #FF0000">;</span>
<span style="color: #19177C">$serviceRootURL</span> = <span style="color: #BA2121">&quot;https://graph.windows.net/$tenant&quot;</span>
<span style="color: #19177C">$authUrl</span> = <span style="color: #BA2121">&quot;https://login.microsoftonline.com/$tenant&quot;</span><span style="border: 1px solid #FF0000">;</span>

<span style="color: #19177C">$postParams</span> = <span style="border: 1px solid #FF0000">@</span>{resource=<span style="color: #BA2121">&quot;$resource&quot;</span><span style="border: 1px solid #FF0000">;</span>client_id=<span style="color: #BA2121">&quot;$clientId&quot;</span>}
<span style="color: #19177C">$response</span> = <span style="color: #008000">Invoke-RestMethod</span> -Method POST -Uri <span style="color: #BA2121">&quot;$authurl/oauth2/devicecode&quot;</span> -Body <span style="color: #19177C">$postParams</span>
<span style="color: #008000">Write-Host</span> <span style="color: #19177C">$response</span>.message

<span style="color: #19177C">$tokenParams</span> = <span style="border: 1px solid #FF0000">@</span>{grant_type=<span style="color: #BA2121">&quot;device_code&quot;</span><span style="border: 1px solid #FF0000">;</span> resource=<span style="color: #BA2121">&quot;$resource&quot;</span><span style="border: 1px solid #FF0000">;</span> client_id=<span style="color: #BA2121">&quot;$clientId&quot;</span><span style="border: 1px solid #FF0000">;</span> code=<span style="color: #BA2121">&quot;</span><span style="color: #BB6688;font-weight: bold">$(</span><span style="border: 1px solid #FF0000">$</span><span style="color: #BB6688;font-weight: bold">response.device_code)</span><span style="color: #BA2121">&quot;</span>}

<span style="color: #19177C">$tokenResponse</span> = <span style="color: #19177C">$null</span>
<span style="color: #19177C">$maxDate</span> = (<span style="color: #008000">Get-Date</span>).AddSeconds(<span style="color: #19177C">$response</span>.expires_in)

<span style="color: #008000;font-weight: bold">while</span> (!<span style="color: #19177C">$tokenResponse</span> <span style="color: #666666">-and</span> (<span style="color: #008000">Get-Date</span>) <span style="color: #666666">-lt</span> <span style="color: #19177C">$maxDate</span>)
{
    <span style="color: #008000;font-weight: bold">try</span>
    {
        <span style="color: #19177C">$tokenResponse</span> = <span style="color: #008000">Invoke-RestMethod</span> -Method POST -Uri <span style="color: #BA2121">&quot;$authurl/oauth2/token&quot;</span> -Body <span style="color: #19177C">$tokenParams</span>
    } 
    <span style="color: #008000;font-weight: bold">catch</span> <span style="color: #880000">[System.Net.WebException]</span> 
    {
        <span style="color: #008000;font-weight: bold">if</span> (<span style="color: #19177C">$_</span>.Exception.Response <span style="color: #666666">-eq</span> <span style="color: #19177C">$null</span>)
        {
            throw
        }

        <span style="color: #19177C">$result</span> = <span style="color: #19177C">$_</span>.Exception.Response.GetResponseStream()
        <span style="color: #19177C">$reader</span> = <span style="color: #008000">New-Object</span> System.IO.StreamReader(<span style="color: #19177C">$result</span>)
        <span style="color: #19177C">$reader</span>.BaseStream.<span style="color: #008000;font-weight: bold">Position</span> = 0
        <span style="color: #19177C">$errBody</span> = <span style="color: #008000">ConvertFrom-Json</span> <span style="color: #19177C">$reader</span>.ReadToEnd()<span style="border: 1px solid #FF0000">;</span>

        <span style="color: #008000;font-weight: bold">if</span>(<span style="color: #19177C">$errBody</span>.Error <span style="color: #666666">-ne</span> <span style="color: #BA2121">&quot;authorization_pending&quot;</span>)
        {
            throw
        }

        <span style="color: #008000">Start-Sleep</span>(<span style="color: #19177C">$response</span>.interval)<span style="border: 1px solid #FF0000">;</span>
        <span style="color: #008000">Write-Host</span> -NoNewline <span style="color: #BA2121">&quot;.&quot;</span><span style="border: 1px solid #FF0000">;</span>
    }
}
</pre></div>
<p>After executing this script, and after successfully authenticating against Azure AD, the variable $tokenResponse should contain your tokens as issued by Azure AD.</p>]]></content:encoded>
    </item>
    <item>
      <title>Managing Azure MFA Server with PowerShell</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudpfe/managing-azure-mfa-server-with-powershell</link>
      <pubDate>Thu, 26 Apr 2018 19:11:26 GMT</pubDate>
      <dc:creator><![CDATA[Tino Donderwinkel]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudpfe/?p=785</guid>
      <description><![CDATA[Do you have Azure MFA Server on-premises and want to manage it through PowerShell? Keep reading! If...]]></description>
      <content:encoded><![CDATA[Do you have Azure MFA Server on-premises and want to manage it through PowerShell? Keep reading! If you’re using Azure MFA (completely in the Cloud), this is not for you. Sorry.

<!--more-->

Many of our customers that have invested in our on-premises Azure MFA Server have complained about the lack of PowerShell support in the product. And I must agree; although our <em>2009 Common Engineering Criteria (CEC)</em> (which today are nowhere to be found) more or less stated that all Microsoft products should have PowerShell support, Azure MFA Server lacks this support. Furthermore, no investments are made to add PowerShell support to the product as far as I know.

But there are still two distinct ways to manage your Azure MFA Servers with PowerShell. In this article, I will discuss both.
<h3>Using the Azure MFA Server Web SDK</h3>
Azure MFA Server comes with a Web SDK that you can install on any Azure MFA Server in the environment. It exposes a SOAP interface to many features and functions of Azure MFA Server. It can also be used to integrate third party solutions to support MFA. Using PowerShell, you can easily access and use this SOAP interface. If you haven’t setup the Web SDK already, <a target="_blank" href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfaserver-deploy-mobileapp" rel="noopener">here’s a great article</a> on how to do it!

First, let’s declare where our SDK is installed, and provide a username and password. (The user needs to be in the PhoneFactor Admins group). You can also user certificate-based authentication for the user.
<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span> </span></span><span style="font-size: small"><span style="color: #ff4500">$MfaUrl</span> <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">'https://pfa.domain.com/MultiFactorAuthWebServiceSdk/'</span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$MfaUser</span> <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"domain\user"</span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$MfaPassword</span> <span style="color: #a9a9a9">=</span> </span><span style="color: #8b0000"><span><span style="font-size: small">"P@zzw0rd!"</span> </span></span></p>

</div>
Next thing we need to do, is convert our plain-text password to a Secure String and create a proxy to the SOAP interface. This proxy will allow us to execute all the methods available.
<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span> </span></span><span style="font-size: small"><span style="color: #ff4500">$MfaSecurePassword</span> <span style="color: #a9a9a9">=</span> <span style="color: #0000ff">ConvertTo-SecureString</span> <span style="color: #000080">-AsPlainText</span> <span style="color: #000080">-Force</span> <span style="color: #000080">-String</span> <span style="color: #ff4500">$MfaPassword</span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$Credentials</span> <span style="color: #a9a9a9">=</span> <span style="color: #0000ff">New-Object</span> <span style="color: #000080">-TypeName</span> <span style="color: #8a2be2">System.Management.Automation.PSCredential</span> <span style="color: #000080">-ArgumentList</span> <span style="color: #ff4500">$MfaUser</span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$MfaSecurePassword</span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$Proxy</span> <span style="color: #a9a9a9">=</span> <span style="color: #0000ff">New-WebServiceProxy</span> <span style="color: #000080">-Uri</span> <span style="color: #ff4500">$MfaUrl</span> <span style="color: #000080">-Credential</span>  <span style="color: #ff4500">$Credentials</span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$Namespace</span> <span style="color: #a9a9a9">=</span> <span style="color: #ff4500">$Proxy</span><span style="color: #a9a9a9">.</span>GetType()<span style="color: #a9a9a9">.</span>Namespace</span><span><span> </span></span><span></span></p>

</div>
The $Namespace variable is just a convenience, as we will see later.

After executing the code we have so far, let’s inspect the $Proxy variable. It’s the proxy to the SOAP interface, and all exposed methods are now available. You can check them out by piping the $Proxy to Get-Member:
<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span> </span></span><span style="font-size: small"><span style="color: #ff4500">$Proxy</span> <span style="color: #a9a9a9">|</span> </span><span style="color: #0000ff"><span><span style="font-size: small">Get-Member</span> </span></span></p>

</div>
You’ll see there’s a lot of stuff available. For this article, I am interested in adding a user in Azure MFA Server. So let’s dive in further to the Add User method;
<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span> </span></span><span style="font-size: small"><span style="color: #ff4500">$Proxy</span> <span style="color: #a9a9a9">|</span> <span style="color: #0000ff">Get-Member</span> </span><span style="color: #8a2be2"><span><span style="font-size: small">AddUser</span> </span></span></p>

</div>
In the output, we can see how we can call this method:
<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #012456"><span><span> </span></span><span style="color: #f5f5f5"><span style="font-size: small">PS C:\&gt; $Proxy | Get-Member AddUser</span></span></p>
<span style="font-size: small"></span>

<span style="font-size: small"></span>
<p style="margin: 0px;font-family: lucida console;background-color: #012456"><span style="color: #f5f5f5"><span style="font-size: small">   TypeName: Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1_MultiFactorAuthWebServiceSdk_.PfWsSdk</span></span></p>
<span style="font-size: small"></span>
<p style="margin: 0px;font-family: lucida console;background-color: #012456"><span style="color: #f5f5f5"><span style="font-size: small">Name    MemberType Definition                                                                                                                                                                                    </span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #012456"><span style="color: #f5f5f5"><span style="font-size: small">----    ---------- ----------                                                                                                                                                                                    </span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #012456"><span style="color: #f5f5f5"><span><span style="font-size: small">AddUser Method     bool AddUser(string username, Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1_MultiFactorAuthWebServiceSdk_.AddUserSettings addUserSettings, bool send...</span></span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #012456"><span style="color: #f5f5f5"><span> </span></span></p>

</div>
Apparently, the method expects a parameter of type <strong>Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1_MultiFactorAuthWebServiceSdk_.
AddUserSettings</strong>.

Let’s create an object of that type in PowerShell (here can see how the $Namespace variable saves us a ton of typing):
<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span> </span></span><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span> <span style="color: #a9a9a9">=</span> <span style="color: #0000ff">New-Object</span> (<span style="color: #ff4500">$Namespace</span> <span style="color: #a9a9a9">+</span> <span style="color: #8b0000">".AddUserSettings"</span>);</span><span><span> </span></span><span></span></p>

</div>
After creating the object, we can set the properties:
<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span> </span></span><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">.</span>CountryCode <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"31"</span>;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">.</span>EmailAddress <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"user@domain.com"</span>;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">.</span>Enabled <span style="color: #a9a9a9">=</span> <span style="color: #ff4500">$true</span>;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">.</span>FirstName <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"Firstname"</span>;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">.</span>LastName <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"Lastname"</span>;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">.</span>Phone <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"612345678"</span>;</span><span><span> </span></span><span></span></p>

</div>
When the object is completed, we need to create an object of type <strong>Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1_MultiFactorAuthWebServiceSdk_.Error</strong> (which is required in the method as a referenced parameter), and we can call the method:
<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span> </span></span><span style="font-size: small"><span style="color: #ff4500">$ErrorCode</span> <span style="color: #a9a9a9">=</span> <span style="color: #0000ff">New-Object</span> (<span style="color: #ff4500">$Namespace</span> <span style="color: #a9a9a9">+</span> <span style="color: #8b0000">".Error"</span>);</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$MfaResult</span> <span style="color: #a9a9a9">=</span> <span style="color: #ff4500">$Proxy</span><span style="color: #a9a9a9">.</span>AddUser(<span style="color: #8b0000">"user@domain.com"</span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$true</span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$null</span><span style="color: #a9a9a9">,</span> <span style="color: #a9a9a9">[</span><span style="color: #008080">ref</span><span style="color: #a9a9a9">]</span><span style="color: #ff4500">$ErrorCode</span>);</span><span><span> </span></span><span></span></p>

</div>
That’s it! Now just check $MfaResult to see if we’re all good.

Here is what we created:

<hr />

<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span> </span></span><span style="font-size: small"><span style="color: #ff4500">$MfaUrl</span> <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">'https://pfa.domain.com/MultiFactorAuthWebServiceSdk/'</span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$MfaUser</span> <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"domain\user"</span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$MfaPassword</span> <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"P@zzw0rd!"</span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$MfaSecurePassword</span> <span style="color: #a9a9a9">=</span> <span style="color: #0000ff">ConvertTo-SecureString</span> <span style="color: #000080">-AsPlainText</span> <span style="color: #000080">-Force</span> <span style="color: #000080">-String</span> <span style="color: #ff4500">$MfaPassword</span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$Credentials</span> <span style="color: #a9a9a9">=</span> <span style="color: #0000ff">New-Object</span> <span style="color: #000080">-TypeName</span> <span style="color: #8a2be2">System.Management.Automation.PSCredential</span> <span style="color: #000080">-ArgumentList</span> <span style="color: #ff4500">$MfaUser</span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$MfaSecurePassword</span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$Proxy</span> <span style="color: #a9a9a9">=</span> <span style="color: #0000ff">New-WebServiceProxy</span> <span style="color: #000080">-Uri</span> <span style="color: #ff4500">$MfaUrl</span> <span style="color: #000080">-Credential</span>  <span style="color: #ff4500">$Credentials</span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$Namespace</span> <span style="color: #a9a9a9">=</span> <span style="color: #ff4500">$Proxy</span><span style="color: #a9a9a9">.</span>GetType()<span style="color: #a9a9a9">.</span>Namespace</span></p>
<span style="font-size: small"></span>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span> <span style="color: #a9a9a9">=</span> <span style="color: #0000ff">New-Object</span> (<span style="color: #ff4500">$Namespace</span> <span style="color: #a9a9a9">+</span> <span style="color: #8b0000">".AddUserSettings"</span>);</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">.</span>CountryCode <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"31"</span>;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">.</span>EmailAddress <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"user@domain.com"</span>;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">.</span>Enabled <span style="color: #a9a9a9">=</span> <span style="color: #ff4500">$true</span>;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">.</span>FirstName <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"Firstname"</span>;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">.</span>LastName <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"Lastname"</span>;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">.</span>Phone <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"612345678"</span>; </span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$ErrorCode</span> <span style="color: #a9a9a9">=</span> <span style="color: #0000ff">New-Object</span> (<span style="color: #ff4500">$Namespace</span> <span style="color: #a9a9a9">+</span> <span style="color: #8b0000">".Error"</span>);</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$MfaResult</span> <span style="color: #a9a9a9">=</span> <span style="color: #ff4500">$Proxy</span><span style="color: #a9a9a9">.</span>AddUser(<span style="color: #ff4500">$User</span><span style="color: #a9a9a9">.</span>UserPrincipalName<span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$AddUserSettings</span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$true</span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$null</span><span style="color: #a9a9a9">,</span> <span style="color: #a9a9a9">[</span><span style="color: #008080">ref</span><span style="color: #a9a9a9">]</span><span style="color: #ff4500">$ErrorCode</span>);</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #00008b">if</span> (<span style="color: #ff4500">$MfaResult</span>)</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small">{</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small">    <span style="color: #0000ff">Write-Host</span> <span style="color: #8b0000">"User added."</span>;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small">}</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="color: #00008b"><span style="font-size: small">else</span></span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small">{</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small">    <span style="color: #0000ff">Write-Error</span> <span style="color: #8b0000">"Could not add user. Error Code: </span>$(<span style="color: #ff4500">$ErrorCode</span><span style="color: #a9a9a9">.</span>Code)<span style="color: #8b0000">, Error Description: </span>$(<span style="color: #ff4500">$ErrorCode</span><span style="color: #a9a9a9">.</span>Description)<span style="color: #8b0000">"</span>;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span><span style="font-size: small">}</span> </span></span></p>

</div>

<hr />

So what about the good and the bad of this solution?

+ Supported.
+ Runs remotely.
- Limited functionality available through the SOAP interface.
<h3>Using the Azure MFA Server Client Runtime DLL</h3>
Okay, this is not for the faint of heart. Using the provided scripts and DLL referenced in this part of the article might be unsupported and could potentially break your Azure MFA Server if used improprely.

Both the Multi-Factor Authentication Server UI (<strong>MultiFactorAuthUI.exe</strong>) and the Azure MFA Server Web SDK use the same DLL’s to ‘talk’ to the Azure MFA Server; one of which is <strong>pfsvcclientclr.DLL</strong>. And hey, whatever they can do, we can do from PowerShell! Drawback is that the communcations channel that this DLL uses requires the code to run on the MFA Server itself. (That’s also why the UI and the Web SDK only run on the Azure MFA Server actually.)

Side note; <em>If you want to use C# or something to manage your Azure MFA Server, you can reference this DLL as well. But there are additional DLL’s on the system that have nice wrappers around the hundreds of methods available through the pfsvcclientclr.dll. Perhaps sometimes I will write an article on that as well… (Do comment if you want me to.)</em>

So, let’s first reference the DLL in our script;
<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span> </span></span><span style="font-size: small"><span style="color: #0000ff">Add-Type</span> <span style="color: #000080">-Path</span> </span><span style="color: #8b0000"><span><span style="font-size: small">"C:\Program Files\Multi-Factor Authentication Server\pfsvcclientclr.DLL"</span> </span></span></p>

</div>
After referencing the DLL, we can access the methods and properties the DLL exposes. Unfortunately, it’s not too easy to find out what to do with this DLL. So I’ll give you the first steps to start using the magic of the DLL:
<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span> </span></span><span style="font-size: small"><span style="color: #ff4500">$problem</span> <span style="color: #a9a9a9">=</span> <span style="color: #a9a9a9">[</span><span style="color: #008080">PfSvcClientClr.ConstructResult</span><span style="color: #a9a9a9">]::</span>miscError;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$main</span> <span style="color: #a9a9a9">=</span> <span style="color: #a9a9a9">[</span><span style="color: #008080">PfSvcClientClr.PfSvcClient</span><span style="color: #a9a9a9">]::</span>construct(<span style="color: #a9a9a9">[</span><span style="color: #008080">PfSvcClientClr.ConstructTarget</span><span style="color: #a9a9a9">]::</span>local<span style="color: #a9a9a9">,</span> <span style="color: #a9a9a9">[</span><span style="color: #008080">ref</span><span style="color: #a9a9a9">]</span> <span style="color: #ff4500">$problem</span>);</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$master</span> <span style="color: #a9a9a9">=</span> <span style="color: #ff4500">$main</span><span style="color: #a9a9a9">.</span>GetType()<span style="color: #a9a9a9">.</span>GetMethod(<span style="color: #8b0000">"getInterface"</span>)<span style="color: #a9a9a9">.</span>MakeGenericMethod(<span style="color: #a9a9a9">[</span><span style="color: #008080">PfSvcClientClr.IPfMasterComposite</span><span style="color: #a9a9a9">]</span>)<span style="color: #a9a9a9">.</span>Invoke(<span style="color: #ff4500">$main</span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$null</span>);</span><span><span> </span></span><span></span></p>

</div>
Should there be any problems loading this stuff, the $problem variable should have some information what went wrong.

From this point on, we have a $master variable which serves as our proxy to the MFA Server. Using the Get-Member function, we can see which methods are now available to us:
<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span> </span></span><span style="font-size: small"><span style="color: #ff4500">$master</span> <span style="color: #a9a9a9">|</span> </span><span style="color: #0000ff"><span><span style="font-size: small">Get-Member</span> </span></span></p>

</div>
Wow. That’s a lot of stuff! 1.647 Methods! Actually, anything you can do through the MultiFactorAuthUI can be done through this DLL. Let’s try to do something that cannot be done through the SOAP interface; let’s make a user a User Portal Administrator, and allow him to <strong>Add Users</strong> and <strong>Block/Unblock Users</strong>:
<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span> </span></span><span style="font-size: small"><span style="color: #ff4500">$master</span><span style="color: #a9a9a9">.</span>set_user_isAdmin(<span style="color: #8b0000">"user@domain.com"</span><span style="color: #ff4500"></span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$true</span>);</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$master</span><span style="color: #a9a9a9">.</span>set_user_adminAddUser(<span style="color: #8b0000">"user@domain.com"</span><span style="color: #ff4500"></span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$true</span>);</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$master</span><span style="color: #a9a9a9">.</span>set_user_adminBlockUnblockUser(<span style="color: #8b0000">"user@domain.com"</span><span style="color: #ff4500"></span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$true</span>);</span><span><span> </span></span><span></span></p>

</div>
That’s not too hard! So let’s put the username in a variable and see what we got;

<hr />

<div style="text-align: left;color: #000000;font-family: segoe ui;font-style: normal;font-weight: normal">
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span><span> </span></span><span style="font-size: small"><span style="color: #0000ff">Add-Type</span> <span style="color: #000080">-Path</span> <span style="color: #8b0000">"C:\Program Files\Multi-Factor Authentication Server\pfsvcclientclr.DLL"</span></span></p>
<span style="font-size: small"></span>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$username</span> <span style="color: #a9a9a9">=</span> <span style="color: #8b0000">"user@domain.com"</span>;</span></p>
<span style="font-size: small"></span>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$problem</span> <span style="color: #a9a9a9">=</span> <span style="color: #a9a9a9">[</span><span style="color: #008080">PfSvcClientClr.ConstructResult</span><span style="color: #a9a9a9">]::</span>miscError;</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$main</span> <span style="color: #a9a9a9">=</span> <span style="color: #a9a9a9">[</span><span style="color: #008080">PfSvcClientClr.PfSvcClient</span><span style="color: #a9a9a9">]::</span>construct(<span style="color: #a9a9a9">[</span><span style="color: #008080">PfSvcClientClr.ConstructTarget</span><span style="color: #a9a9a9">]::</span>local<span style="color: #a9a9a9">,</span> <span style="color: #a9a9a9">[</span><span style="color: #008080">ref</span><span style="color: #a9a9a9">]</span> <span style="color: #ff4500">$problem</span>);</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$master</span> <span style="color: #a9a9a9">=</span> <span style="color: #ff4500">$main</span><span style="color: #a9a9a9">.</span>GetType()<span style="color: #a9a9a9">.</span>GetMethod(<span style="color: #8b0000">"getInterface"</span>)<span style="color: #a9a9a9">.</span>MakeGenericMethod(<span style="color: #a9a9a9">[</span><span style="color: #008080">PfSvcClientClr.IPfMasterComposite</span><span style="color: #a9a9a9">]</span>)<span style="color: #a9a9a9">.</span>Invoke(<span style="color: #ff4500">$main</span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$null</span>);</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$master</span><span style="color: #a9a9a9">.</span>set_user_isAdmin(<span style="color: #ff4500">$username</span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$true</span>);</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$master</span><span style="color: #a9a9a9">.</span>set_user_adminAddUser(<span style="color: #ff4500">$username</span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$true</span>);</span></p>
<p style="margin: 0px;font-family: lucida console;background-color: #ffffff"><span style="font-size: small"><span style="color: #ff4500">$master</span><span style="color: #a9a9a9">.</span>set_user_adminBlockUnblockUser(<span style="color: #ff4500">$username</span><span style="color: #a9a9a9">,</span> <span style="color: #ff4500">$true</span>);</span><span><span> </span></span><span></span></p>

</div>

<hr />

One of the drawbacks is that this solution only runs on MFA Servers. But using System Center Service Management Automation PowerShell Script Runbooks, this should not be a real problem.

So what about the good and the bad of this solution?

+ Unlimited functionality.
- Potentially Unsupported.
- Runs only locally on the MFA Server.
<h3>Conclusion</h3>
Using the two options provided, you should be able to <strong>do anything you want </strong>against your Azure MFA Servers <strong>using PowerShell</strong>. You decide what you want to use! There’s a lot of methods available to you, so spend some time figuring out what you can use. Keep in mind that the Web SDK is your best option to integrate solutions. For example if you want to use Username &amp; One-Time Password authentication in an application. The DLL mentioned in this article is primarily for managing the environment, not for integration.

Don’t call me if anything goes wrong… Some if the methods mentioned in this article might be unsupported… But hey; you <u>can</u> manage your Azure MFA Server with PowerShell!

&nbsp;

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>Base32 Encoding and Decoding in C#</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudpfe/base32-encoding-and-decoding-in-c</link>
      <pubDate>Wed, 18 Apr 2018 16:35:59 GMT</pubDate>
      <dc:creator><![CDATA[Tino Donderwinkel]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudpfe/?p=765</guid>
      <description><![CDATA[You might have to do some Base32 Encoding or Decoding in C# (or PowerShell). Here's a simple .NET...]]></description>
      <content:encoded><![CDATA[You might have to do some Base32 Encoding or Decoding in C# (or PowerShell). Here's a simple .NET implementation in C# you can use!

<code>
   using System;
    using System.Linq;
    using System.Text;
    public static class Base32
    {
        /// &lt;summary&gt;
        /// The different characters allowed in Base32 encoding.
        /// &lt;/summary&gt;
        /// &lt;remarks&gt;
        /// This is a 32-character subset of the twenty-six letters A–Z and six digits 2–7.
        /// &lt;see cref=&quot;https://en.wikipedia.org/wiki/Base32&quot; /&gt;
        /// &lt;/remarks&gt;
        private const string Base32AllowedCharacters = &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ234567&quot;;

        /// &lt;summary&gt;
        /// Converts a byte array into a Base32 string.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;input&quot;&gt;The string to convert to Base32.&lt;/param&gt;
        /// &lt;param name=&quot;addPadding&quot;&gt;Whether or not to add RFC3548 &#039;=&#039;-padding to the string.&lt;/param&gt;
        /// &lt;returns&gt;A Base32 string.&lt;/returns&gt;
        /// &lt;remarks&gt;
        /// https://tools.ietf.org/html/rfc3548#section-2.2 indicates padding MUST be added unless the reference to the RFC tells us otherswise.
        /// https://github.com/google/google-authenticator/wiki/Key-Uri-Format indicates that padding SHOULD be omitted.
        /// To meet both requirements, you can omit padding when required.
        /// &lt;/remarks&gt;
        public static string ToBase32String(this byte[] input, bool addPadding = true)
        {
            if (input == null || input.Length == 0)
            {
                return string.Empty;
            }

            var bits = input.Select(b =&gt; Convert.ToString(b, 2).PadLeft(8, &#039;0&#039;)).Aggregate((a, b) =&gt; a + b).PadRight((int)(Math.Ceiling((input.Length * 8) / 5d) * 5), &#039;0&#039;);
            var result = Enumerable.Range(0, bits.Length / 5).Select(i =&gt; Base32AllowedCharacters.Substring(Convert.ToInt32(bits.Substring(i * 5, 5), 2), 1)).Aggregate((a, b) =&gt; a + b);
            if (addPadding)
            {
                result = result.PadRight((int)(Math.Ceiling(result.Length / 8d) * 8), &#039;=&#039;);
            }
            return result;
        }

        public static string EncodeAsBase32String(this string input, bool addPadding = true)
        {
            if (string.IsNullOrEmpty(input))
            {
                return string.Empty;
            }

            var bytes = Encoding.UTF8.GetBytes(input);
            var result = bytes.ToBase32String(addPadding);
            return result;
        }

        public static string DecodeFromBase32String(this string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return string.Empty;
            }

            var bytes = input.ToByteArray();
            var result = Encoding.UTF8.GetString(bytes);
            return result;
        }

        /// &lt;summary&gt;
        /// Converts a Base32 string into the corresponding byte array, using 5 bits per character.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;input&quot;&gt;The Base32 String&lt;/param&gt;
        /// &lt;returns&gt;A byte array containing the properly encoded bytes.&lt;/returns&gt;
        public static byte[] ToByteArray(this string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return new byte[0];
            }

            var bits = input.TrimEnd(&#039;=&#039;).ToUpper().ToCharArray().Select(c =&gt; Convert.ToString(Base32AllowedCharacters.IndexOf(c), 2).PadLeft(5, &#039;0&#039;)).Aggregate((a, b) =&gt; a + b);
            var result = Enumerable.Range(0, bits.Length / 8).Select(i =&gt; Convert.ToByte(bits.Substring(i * 8, 8), 2)).ToArray();
            return result;
        }
    }

</code>

(Sorry about the formatting, but Visual Studio will sort it out for you!)]]></content:encoded>
    </item>
    <item>
      <title>OAuth 2.0 Confidential Clients and Active Directory Federation Services on Windows Server 2016</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudpfe/oauth-2-0-confidential-clients-and-active-directory-federation-services-on-windows-server-2016</link>
      <pubDate>Mon, 16 Oct 2017 10:55:11 GMT</pubDate>
      <dc:creator><![CDATA[Tino Donderwinkel]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudpfe/?p=745</guid>
      <description><![CDATA[In this blog post, I want to clarify just how you can make your OAuth 2.0 Confidential Client work...]]></description>
      <content:encoded><![CDATA[In this blog post, I want to clarify just how you can make your OAuth 2.0 Confidential Client work against Active Directory Federation Services on Windows Server 2016 (AD FS) using different forms of client authentication. Although there is a <a href="https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/development/enabling-oauth-confidential-clients-with-ad-fs">great article on the Microsoft web</a> on this topic, it doesn’t disclose how you can utilize either <strong>Certificate Based</strong>- or<strong> Windows Integrated Authentication-Based authentication</strong> for your confidential client.
<blockquote><strong>Important note</strong>: This article assumes you are using AD FS Farm Behavior Level 2 (AD_FS_BEHAVIOR_LEVEL_2) or higher.</blockquote>
<h1>Shared Secret</h1>
Whenever you code against Azure Active Directory (using version 1.0 or version 2.0 endpoints), you would use Client Credentials in the form of a <em>shared secret</em> to authenticate your client;

<a href="https://msdnshared.blob.core.windows.net/media/2017/10/aad-key2.png"><img width="832" height="235" title="aad-key2" alt="aad-key2" src="https://msdnshared.blob.core.windows.net/media/2017/10/aad-key2_thumb.png" border="0" /></a>

This also works against AD FS; You can create an Application Group and add a Confidential Client (called <em>Server application</em> in AD FS) to the Application Group. During the setup of the Server application, or by modifying its configuration, you can configure a shared secret by selecting “Generate a shared secret” from the Configure Application Credentials page:

<a href="https://msdnshared.blob.core.windows.net/media/2017/10/adfs-key1.png"><img width="527" height="429" title="adfs-key1" alt="adfs-key1" src="https://msdnshared.blob.core.windows.net/media/2017/10/adfs-key1_thumb.png" border="0" /></a>

Using this form of Client Authentication, you would POST your client identifier (as <em>client_id</em>) and your client secret (as <em>client_secret</em>) to the STS endpoint. Here is an example of such an HTTP POST (using Client Credentials Grant, added line breaks only for readability):

<span style="font-family: Consolas">resource=https%3a%2f%2fdemo.api.com
&amp;client_id=2954b462-a5de-5af6-83bc-497cc20bddde
&amp;client_secret=56V0RnQ1COwhf4YbN9VSkECTKW9sOHsgIuTl1FV9
&amp;grant_type=client_credentials</span>

Note that AD FS supports two other forms of authenticating the confidential client:
<ul>
 	<li><strong>Register a key used to sign JSON Web Tokens for authentication</strong>
This option is used to allow a confidential client to authenticate itself using a certificate.</li>
 	<li><strong>Windows Integrated Authentication</strong>
This option is used to allow a confidential client to authenticate itself using WIA; a Windows user context.</li>
</ul>
Let’s take a closer look at these two other options to authenticate a confidential client.
<h1>Signed JSON Web Tokens</h1>
When you don’t want to use a shared secret to authenticate your confidential client, nor does the client run on a Domain-Joined machine under an Active Directory User context, you can use Signed JSON Web Tokens to authenticate the client to AD FS. This option is typically chosen when you want the client to authenticate itself using Certificate Based-Authentication. Next to using Certificates, this option would also allow you to use JSON Web Key Sets (JWK Sets). In this article, I will focus on using Certificates.

Select “<em>Register a key used to sign JSON Web Tokens for authentication</em>” and click on <em>Configure…</em>

From there, click <em>Add…</em> to add the (public key) of the certificate(s) that you want to use with your client.

<a href="https://msdnshared.blob.core.windows.net/media/2017/10/adfs-cert.png"><img width="590" height="351" title="adfs-cert" alt="adfs-cert" src="https://msdnshared.blob.core.windows.net/media/2017/10/adfs-cert_thumb.png" border="0" /></a>

Under “JWT signing certificate revocation check”, select the CRL checking that you want. Remember that, for AD FS to do any CRL checking, AD FS would require Internet access (on port 80).

Now comes the hard part. Although the HTTP protocol defines certificate based authentication for clients, this is not actually what we will be using. Instead, we will use a JSON Web Token which is signed using the private key of the certificate you chose. This token is passed as the <em>client_assertion</em> in the request.

Hence, in our client we need to craft such a JWT and sign it accordingly. In this post, I will use <strong>RS256</strong> to sign the JWT. Signing a JWT is a straight-forward process: You Base64-Url-encode the header, you Base64-Url-Encode the content, you concatenate the two with a dot (‘.’), you create a <strong>SHA256</strong> hash on that string, and you sign it using your certificate.

The header should contain the algorithm (<em>alg</em>) used to create the signature (in our case; RS256). It should also contain the Certificate Hash in the <em>x5t</em> field. In “Pseudo-code”:

<span style="font-family: Consolas">{
“alg”: “RS256”,
“x5t”: Base64UrlEncode(certificate.GetCertHash()
}</span>

The token itself would need the intended audience (“<em>aud</em>”), which is the AD FS token endpoint, the Issuer (“<em>iss</em>”) which is the client identifier of our client, a Subject (“<em>sub</em>”) which in our case is also the client identifier, an issuance datetime (“<em>nbf</em>”) and expiry datetime (“<em>exp</em>”), both in Unix Epoch Time (e.g. seconds passed since 01-01-1970) and a unique identifier of the request (“<em>jti</em>”). In “Pseudo-code”:

<span style="font-family: Consolas">{
“aud”: “https://adfs.contoso.com/adfs/oauth2/token”,
“iss”: “2954b462-a5de-5af6-83bc-497cc20bddde”,
“sub”: “2954b462-a5de-5af6-83bc-497cc20bddde”,
“nbf”: (int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds,
“exp”: nbf + 60 * 10,
“jti”: Guid.NewGuid().ToString()
}</span>

We Base64-Url-Encode these two (which is the same as Base64 Encode but remove the trailing ‘=’ characters and replace ‘+’ by ‘-‘ and replace ‘/’ by ‘_’) and glue them together with a dot (‘.’).

Let’s get the SHA256 hash we need to sign:

<span style="font-family: Consolas">var bytesToSign = Encoding.UTF8.GetBytes($"{Base64UrlEncode(tokenHeader)}.{Base64UrlEncode(tokenContent)}");
var sha256 = SHA256.Create();
var hash = sha256.ComputeHash(bytesToSign);</span>

In this sample, <em>hash</em> contains the bytes to sign using SHA256.

The only thing left is to use the Private Key of our Certificate to sign the hash bytes using SHA256. This proves to be non-trivial. Typically, you’d use a <span style="font-family: Consolas">System.Security.Cryptography.RSACryptoServiceProvider</span> to handle this. Yet, SHA256 signing is not part of any of the default providers. Hence, we need to come up with our own. I took a look at the Active Directory Authentication Library (<a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.identitymodel.clients.activedirectory?view=azure-dotnet">ADAL</a>) to see how they handle this. It turns out, it’s in the <a href="https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/blob/dev/src/Microsoft.IdentityModel.Clients.ActiveDirectory/Platforms/net45/CryptographyHelper.cs">CryptographyHelper.cs</a> file. From that file, I derived a new <em>SignatureDescrption</em> class:

<span style="font-family: Consolas">using System;
using System.Security.Cryptography;</span>

public class ManagedSHA256SignatureDescription : SignatureDescription
{
public ManagedSHA256SignatureDescription()
{
KeyAlgorithm = typeof(RSACryptoServiceProvider).FullName;
DigestAlgorithm = typeof(SHA256Managed).FullName;
}

<span style="font-family: Consolas">
</span>

<span style="font-family: Consolas">    public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}</span>

<span style="font-family: Consolas">
</span>

<span style="font-family: Consolas">        var deformatter = new RSAPKCS1SignatureDeformatter(key);
deformatter.SetHashAlgorithm(typeof(SHA256Managed).FullName);
return deformatter;
}</span>

<span style="font-family: Consolas">
</span>

<span style="font-family: Consolas">    public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}</span>

<span style="font-family: Consolas">
</span>

<span style="font-family: Consolas">        var provider = (RSACryptoServiceProvider)key;
var cspParams = new CspParameters();
cspParams.ProviderType = 24;
cspParams.KeyContainerName = provider.CspKeyContainerInfo.KeyContainerName;
cspParams.KeyNumber = (int)provider.CspKeyContainerInfo.KeyNumber;
if (provider.CspKeyContainerInfo.MachineKeyStore)
{
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
}</span>

<span style="font-family: Consolas">
</span>

<span style="font-family: Consolas">        cspParams.Flags |= CspProviderFlags.UseExistingKey;
provider = new RSACryptoServiceProvider(cspParams);
var formatter = new RSAPKCS1SignatureFormatter(provider);
formatter.SetHashAlgorithm(typeof(SHA256Managed).FullName);
return formatter;
}
}</span>

This class can now be used to sign our hash. The resulting signature has to be Base64-Url-Encoded once more and added as the signature to the JWT token created earlier:

<span style="font-family: Consolas">var cryptoProvider = (RSACryptoServiceProvider)certificate.PrivateKey;
var cryptoDescription = new ManagedSHA256SignatureDescription();
var formatter = cryptoDescription.CreateFormatter(certificate.PrivateKey);
formatter.SetHashAlgorithm("SHA256");
var signature = formatter.CreateSignature(hash);
var tokenSignature = Base64UrlEncode(signature);
var clientCred = $"{tokenHeader}.{tokenContent}.{tokenSignature}";</span>

The resulting JWT is in the clientCred variable. This can now be passed to AD FS as the <em>client_assertion</em>. The type of assertion will also have to be passed. The type is <em>urn:ietf:params:oauth:client-assertion-type:jwt-bearer</em> and needs to be set as the <em>client_assertion_type</em> in the request.

The resulting HTTP POST to the AD FS Token Endpoint does now look like this (added line breaks only for readability):

<span style="font-family: Consolas">resource=https%3A%2F%2Fdemo.api.com
&amp;client_id=2954b462-a5de-5af6-83bc-497cc20bddde
&amp;client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&amp;client_assertion=eyJhbGciOiJSU9.eyJhdRmIn0.wq9E17Q
&amp;grant_type=client_credentials</span>

This is an HTTP POST using Client Credentials Grant, but of course you can use other grants or OAuth flows as well.
<h1>Windows Integrated Authentication</h1>
When your client runs on a domain-joined machine, you can use the “<em>Windows Integrated Authentication</em>” checkbox in the Configure Application Credentials dialog. You can either use the security context the client is running under, or you can pass other domain user credentials. Although the latter is possible, the feature is intended to be used against the currently user context. Should you use the current context, the client itself does not store these credential anywhere, which is obviously a security benefit.
This can be used with the security context of the IIS Application Pool (if it's a Web Application) or perhpaps the credentials used to schedule a task that runs the client. So it’s really great for scheduled tasks, daemons etc.!

When you select the “Windows Integrated Authentication” checkbox, you can select a user account in your Active Directory that the client needs to run under. (Although the dialog only allows you to select actual User objects, through PowerShell, you can also use (Group-) Managed Service Accounts using the <strong>Set-AdfsServerApplication</strong> command, in combination with the <strong>ADUserPrincipalName</strong> parameter.)

After selecting this form of authentication, your client needs to send the client identifier (as <em>client_id</em>) to AD FS, and it needs to ‘tell’ AD FS that the client is using Windows Integrated Authentication by adding this field and value to the request:

<strong>use_windows_client_authentication=true</strong>

Remember; you do not send a <em>client_secret</em> in the request.

Instead, you send your Windows Credentials whenever you POST the request to AD FS:

<span style="font-family: Consolas">var request = HttpWebRequest.CreateHttp(<em>endpoint</em>);
request.Headers.Add("client-request-id", Guid.NewGuid().ToString());
request.Accept = "application/json";
<strong>
request.UseDefaultCredentials = true;</strong>
var postBytes = Encoding.UTF8.GetBytes(<em>content</em>);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postBytes.Length;</span>

If you do not want to send your current context as the credential, simply replace the highlighted line with this one (where <strong>networkCredential</strong> is an instance of <strong>System.Security.NetworkCredential</strong>:

<strong>request.Credentials = networkCredential;</strong>

When the request is POSTed to the STS (typically the token-endpoint), no authorization header is sent, and AD FS replies with an <strong>HTTP 401 (Unauthorized)</strong>. AD FS adds two <strong>WWW-Authenticate</strong> headers in the 401 response; one for <strong>Negotiate</strong> and one for <strong>NTLM</strong>. The client then retries the HTTP POST, but now with the proper Authorization header in the request. If the credentials are valid, and the account is the one configured on AD FS, AD FS should reply properly. Here is an example of a successful request to AD FS (taken with <a href="https://www.telerik.com/fiddler">Fiddler</a>):

<a href="https://msdnshared.blob.core.windows.net/media/2017/10/adfs-wia2.png"><img width="416" height="550" title="adfs-wia2" alt="adfs-wia2" src="https://msdnshared.blob.core.windows.net/media/2017/10/adfs-wia2_thumb.png" border="0" /></a>
<h1>Conclusion</h1>
AD FS offers multiple ways of authenticating a client:
<ul>
 	<li>Shared Secret</li>
 	<li>Signed JWT’s</li>
 	<li>Windows Integrated Authentication</li>
</ul>
In this post, you have seen examples on all three of these authentication mechanisms in action without using any 3rd party library. Although we’ve been using Client Credentials Grant in our examples, you can use the same mechanism in your On Behalf Of or Resource Owner Password Credential Grant flows. (Code Flow and Implicit Flow would generally not require the use of Confidential Clients.)

Happy AuthZ!]]></content:encoded>
    </item>
    <item>
      <title>Multiple MFA Prompts connecting to Office 365?</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudpfe/multiple-mfa-prompts-connecting-to-office-365</link>
      <pubDate>Wed, 15 Mar 2017 20:01:02 GMT</pubDate>
      <dc:creator><![CDATA[Tino Donderwinkel]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudpfe/?p=655</guid>
      <description><![CDATA[Customers using Active Directory Federation Services (AD FS) to authenticate users accessing Office...]]></description>
      <content:encoded><![CDATA[<p>Customers using Active Directory Federation Services (AD FS) to authenticate users accessing Office 365, could be challenged by multiple prompts for Multi-Factor Authentication (MFA).</p> <p>Here is an example of a user trying to access the Office 365 Portal at <a href="https://portal.office.com">https://portal.office.com</a>. First, the user gets directed to the Security Token Service (STS) the organization has configured. (In this case, it’s AD FS running on Windows Server 2016.) After authenticating using a username and password (since the user is accessing Office 365 from the ‘extranet’) the users gets a prompt for MFA:</p> <p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/mfa-prompt-1.png"><img title="mfa-prompt-1" style="border-top: 0px;border-right: 0px;border-bottom: 0px;padding-top: 0px;padding-left: 0px;border-left: 0px;padding-right: 0px" border="0" alt="mfa-prompt-1" src="https://msdnshared.blob.core.windows.net/media/2017/03/mfa-prompt-1_thumb.png" width="244" height="190"></a></p> <p>After successfully verifying the request, the user is redirected back to <a href="https://login.microsoftonline.com">https://login.microsoftonline.com</a>, the STS for Office 365. For Office 365, the customer has configured MFA to be required, and the STS for Office 365 requests MFA once more;</p> <p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/mfa-prompt-2.png"><img title="mfa-prompt-2" style="border-top: 0px;border-right: 0px;border-bottom: 0px;padding-top: 0px;padding-left: 0px;border-left: 0px;padding-right: 0px" border="0" alt="mfa-prompt-2" src="https://msdnshared.blob.core.windows.net/media/2017/03/mfa-prompt-2_thumb.png" width="244" height="190"></a>&nbsp;</p> <p>This can happen when (any form of) MFA is required on the “Microsoft Office 365 Identity Platform” Relying Party in AD FS, and it’s also required to access Office 365 (using conditional access rules or simply because the user is enabled for Azure MFA).</p> <p>The cause of the double MFA prompt is that the AD FS farm, while issuing the token to the “Microsoft Office 365 Identity Platform”, did not ‘inform’ the recipient of the token about the fact that the user already did MFA. Part of the token that is sent from the AD FS farm to the “Microsoft Office 365 Identity Platform” is the way the user authenticated. It’s passed as a claim within the token. Whether the user did MFA or not, can be passed in another claim. This claim is not sent by default.</p> <p>We can easily change this behavior by modifying the Claim Issuance Policy for the “Microsoft Office 365 Identity Platform” Relying Parting in AD FS. </p> <p>In the AD FS Management Console, navigate to “<strong>Relying Party Trusts</strong>”, select the “<strong>Microsoft Office 365 Identity Platform</strong>” Relying Party Trust and click, on the right side, on “<strong>Edit Claim Issuance Policy…</strong>”.</p> <p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/original-rules.png"><img title="original-rules" style="border-top: 0px;border-right: 0px;border-bottom: 0px;padding-top: 0px;padding-left: 0px;border-left: 0px;padding-right: 0px" border="0" alt="original-rules" src="https://msdnshared.blob.core.windows.net/media/2017/03/original-rules_thumb.png" width="219" height="244"></a></p> <p>In the “<strong>Edit Claims Issuance Policy for Microsoft Office 365 Identity Platform</strong>” screen, click on the “<strong>Add Rule…</strong>” button.</p> <p>Under “<strong>Claim rule template:</strong>”, select “<strong>Pass Through or Filter and Incoming Claim</strong>”.</p> <p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/rulewiz-1.png"><img title="rulewiz-1" style="border-top: 0px;border-right: 0px;border-bottom: 0px;padding-top: 0px;padding-left: 0px;border-left: 0px;padding-right: 0px" border="0" alt="rulewiz-1" src="https://msdnshared.blob.core.windows.net/media/2017/03/rulewiz-1_thumb.png" width="244" height="199"></a></p> <p>Click “<strong>Next &gt;</strong>” to continue,</p> <p>In the next screen, give the rule a friendly name, for example “<strong>Pass Through MFA Claims</strong>”, and next to “<strong>Incoming claim type:</strong>” select “<strong>Authentication Methods References</strong>”.</p> <p><a href="https://msdnshared.blob.core.windows.net/media/2017/03/rulewiz-2.png"><img title="rulewiz-2" style="border-top: 0px;border-right: 0px;border-bottom: 0px;padding-top: 0px;padding-left: 0px;border-left: 0px;padding-right: 0px" border="0" alt="rulewiz-2" src="https://msdnshared.blob.core.windows.net/media/2017/03/rulewiz-2_thumb.png" width="244" height="199"></a></p>  <p>Click “<strong>Finish</strong>” to add the rule.</p> <p>After that, try it again!</p> <p>The only MFA prompt the user will get is from AD FS, and no longer from the Office 365 STS! Should a user in your tenant authenticate with a non-federated account, so an account which is not ‘served’ by AD FS, the user will be challenged for MFA by the Office 365 STS.</p> <p>(And this also works for any other applications that you have registered with your Azure Active Directory Tenant.)</p>]]></content:encoded>
    </item>
    <item>
      <title>Call Azure Resource Manager REST APIs from your .NET Application</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudpfe/call-azure-resource-manager-rest-apis-from-your-net-application</link>
      <pubDate>Wed, 14 Sep 2016 12:39:10 GMT</pubDate>
      <dc:creator><![CDATA[Tino Donderwinkel]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudpfe/?p=545</guid>
      <description><![CDATA[Every now and then, you might need to perform actions against the Azure Resource Manager REST APIs...]]></description>
      <content:encoded><![CDATA[Every now and then, you might need to perform actions against the <a target="_blank" href="https://msdn.microsoft.com/library/azure/dn790568.aspx">Azure Resource Manager REST APIs</a> from a .NET (deamon) application.

A good example could be a probe-like application that needs to change a route in an Azure route table, shutdown or start an Azure Virtual Machine or scale up or down instances. Anyway, you want to consume <a target="_blank" href="https://msdn.microsoft.com/library/azure/dn790568.aspx">Azure Resource Manager REST APIs</a> from your application without a browser-based sign-in process.

This blog post shows you one of the options you have to accomplish this. It consists of the following steps:
<ol>
 	<li>Create an application in Azure Active Directory.</li>
 	<li>Grant the application permissions to the resource(s) in Azure.</li>
 	<li>From your application, get an Access Token from Azure Active Directory.</li>
 	<li>Execute Azure Resource Manager REST API calls.</li>
 	<li>Try it!</li>
</ol>
<h2>Create an application Azure Active Directory.</h2>
Log on to the Classic Azure Portal at <a href="https://manage.windowsazure.com">https://manage.windowsazure.com</a> and locate the directory associated with the subscription where you want your application to touch resources. If you don’t know which subscription is linked to which directory, go to the Settings page of the Classic Azure Portal.

Open that directory, and navigate to the Applications tab. From there, click Add at the bottom of the page. Select <em>Add an application my organization is developing</em> and click next. Give the application a friendly name, and select <em>Web Application and/or Web API</em> (even though you might be creating an application that you might think is a native client application).

In the <em>sign-on url</em> and <em>app id uri</em> boxes, type anything valid. I suggest you use something like “https://myorganization.com/MyApp”. This URL does not have to exist nor will it be used. Click finish.

Once the application has been created, and you applications page opens up in the Classic Azure Portal, select the <em>Configure</em> tab.

Next to <em>User assignment required to access app</em>, select “Yes”, just to be sure.
Under <em>Keys</em>, expand the pull down menu and select your desired validity period for the applications key. After you save you changes the actual key will be shown in this area.
At the bottom of the page, under <em>Permissions to other applications</em>, click <em>Add application</em>. Select <em>Microsoft Apps</em> in the <em>Show</em> dialog box (which is the default), and click on <em>Windows Azure Service Management API</em>. Click the finish button.
On you applications configuration page, where you should be now, locate the added application <em>Windows Azure Service Management API</em> and click on <em>Delegated Permisssions: 0</em>. Click <em>Access Azure Service Management as organization users (preview)</em> to select it.

Click <em>save</em>, at the bottom of the screen, and locate the (newly generated) application <strong>key</strong> for the application (what's called the <strong>key</strong> here, is the <strong>clientSecret</strong> in code).

<a href="https://msdnshared.blob.core.windows.net/media/2016/09/Application-Key.png"><img width="699" height="184" title="Application Key" style="padding-top: 0px;padding-left: 0px;padding-right: 0px;border: 0px" alt="Application Key" src="https://msdnshared.blob.core.windows.net/media/2016/09/Application-Key_thumb.png" border="0" /></a>

Also note the <strong>Client Id</strong>, located a little above the key.
<h2>Grant the application permissions to the resource(s) in Azure.</h2>
Log on to the Azure Portal at <a href="https://portal.azure.com">https://portal.azure.com</a> and locate the resource that your application needs access to. From that resources page, click on <em>Access control (IAM)</em>.

Click on <em>add</em> and select the role you want your application to have. Next, type the name of your application (as you created it in the Azure Active Directory), and select it.

<a href="https://msdnshared.blob.core.windows.net/media/2016/09/Permissions-01.png"><img width="718" height="150" title="Permissions 01" style="padding-top: 0px;padding-left: 0px;padding-right: 0px;border: 0px" alt="Permissions 01" src="https://msdnshared.blob.core.windows.net/media/2016/09/Permissions-01_thumb.png" border="0" /></a>

Now click <em>Select</em> and <em>OK</em> to save the permissions.

<a href="https://msdnshared.blob.core.windows.net/media/2016/09/Permissions-02.png"><img width="420" height="155" title="Permissions 02" style="padding-top: 0px;padding-left: 0px;padding-right: 0px;border: 0px" alt="Permissions 02" src="https://msdnshared.blob.core.windows.net/media/2016/09/Permissions-02_thumb.png" border="0" /></a>
<h2>Get an Access Token from Azure Active Directory.</h2>
In order for your application to get an Access Token from Azure Active Directory, you need to have the following information:
<ul>
 	<li>The name (or identifier) of your Azure Active Directory instance.</li>
 	<li>The Client ID of the application in Azure Active Directory.</li>
 	<li>The Client Secret of the application in Azure Active Directory.</li>
</ul>
Once you have this information, it’s a very straight forward process to get an Access Token from Azure Active Directory.

First, install the NuGet package Active Directory Authentication Library (Microsoft.IdentityModel.Clients.ActiveDirectory).

Either use “Manage NuGet packages for solution…” from Visual Studio to search for this package:

<a href="https://msdnshared.blob.core.windows.net/media/2016/09/NuGet-Package-Manager-01.png"><img width="717" height="242" title="NuGet Package Manager 01" style="padding-top: 0px;padding-left: 0px;padding-right: 0px;border-width: 0px" alt="NuGet Package Manager 01" src="https://msdnshared.blob.core.windows.net/media/2016/09/NuGet-Package-Manager-01_thumb.png" border="0" /></a>

Or use the Package Manager Console to install it;

<span style="font-family: Consolas">Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory</span>

After the package is installed, add a reference to it in your code:
<pre class="csharpcode"><span class="kwrd">using</span> Microsoft.IdentityModel.Clients.ActiveDirectory;</pre>
Now, you can use the following method to get the Access Token from Azure Active Directory:

<!-- code formatted by https://manoli.net/csharpformat/ -->
<pre class="csharpcode"><span class="kwrd">private</span> async Task&lt;<span class="kwrd">string</span>&gt; GetAccessToken(<span class="kwrd">string</span> tenantName, <span class="kwrd">string</span> clientId, <span class="kwrd">string</span> clientSecret)
{
    <span class="kwrd">var</span> authString = <span class="str">"https://login.microsoftonline.com/"</span> + tenantName;
    <span class="kwrd">var</span> resourceUrl = <span class="str">"https://management.azure.com/"</span>;

    <span class="kwrd">var</span> authenticationContext = <span class="kwrd">new</span> AuthenticationContext(authString, <span class="kwrd">false</span>);
    <span class="kwrd">var</span> clientCred = <span class="kwrd">new</span> ClientCredential(clientId, clientSecret);
    <span class="kwrd">var</span> authenticationResult = await authenticationContext.AcquireTokenAsync(resourceUrl, clientCred);
    <span class="kwrd">var</span> token = authenticationResult.AccessToken;

    <span class="kwrd">return</span> token;
}</pre>
The Access Token returned from the method is a string that can be used to authenticate calls to the Azure Resource Manager REST APIs.
<h2>Execute Azure Resource Manager REST API calls.</h2>
In order for your application to issue calls to the Azure Resource Manager REST APIs, typically you need at least this information:
<ul>
 	<li>An Access Token.</li>
 	<li>Identifier of the Azure Subscription.</li>
 	<li>Resource Group Name.</li>
 	<li>Name or Identifier of the resource(s) you want to create, remove or modify.</li>
</ul>
We will use the example of updating a route in a route table with a new “<em>NextHopIpAddress</em>”, which would require;
<ul>
 	<li>Route Table Name</li>
 	<li>Route Name</li>
 	<li>The IP Address</li>
</ul>
With this information, it’s a very straight forward process to execute Azure Resource Manager REST API calls. (In this case; update a route.)

First, install the NuGet package(s) you need for your resource(s). All these packages start with “Microsoft.Azure.Management”. Since I want to update a route table in Azure, I need the “Microsoft.Azure.Management.Network” package. (I’m using the preview version.) Second, we need the package that provides us with a TokenCredential, but this package is installed as a dependency when installing the Microsoft.Azure.Management package(s).

Either use “Manage NuGet packages for solution…” from Visual Studio to search for these packages:

<a href="https://msdnshared.blob.core.windows.net/media/2016/09/NuGet-Package-Manager-02.png"><img width="719" height="266" title="NuGet Package Manager 02" style="padding-top: 0px;padding-left: 0px;padding-right: 0px;border-width: 0px" alt="NuGet Package Manager 02" src="https://msdnshared.blob.core.windows.net/media/2016/09/NuGet-Package-Manager-02_thumb.png" border="0" /></a>

Or use the Package Manager Console to install it;

<span style="font-family: Consolas">Install-Package Microsoft.Azure.Management.Network</span>

After the package is installed, add a reference to it in your code:
<pre class="csharpcode"><span class="kwrd">using</span> Microsoft.Azure.Management.Network
<span class="kwrd">using</span> Microsoft.Rest</pre>
Now, you can use the following method to, in my case, update a route in a route table:
<pre class="csharpcode"><span class="kwrd">private</span> async Task ChangeRouting(<span class="kwrd">string</span> token, <span class="kwrd">string</span> subscriptionId, <span class="kwrd">string</span> resourceGroup, <span class="kwrd">string</span> routeTableName, <span class="kwrd">string</span> routeName, <span class="kwrd">string</span> ipAddress)
{
    <span class="kwrd">var</span> credential = <span class="kwrd">new</span> TokenCredentials(token);
    <span class="kwrd">var</span> client = <span class="kwrd">new</span> NetworkManagementClient(credential);
    client.SubscriptionId = subscriptionId;

    <span class="kwrd">var</span> route = client.Routes.Get(resourceGroup, routeTableName, routeName);
    route.NextHopIpAddress = ipAddress;
    await client.Routes.CreateOrUpdateAsync(resourceGroup, routeTableName, routeName, route);
}</pre>
<h2>Try it!</h2>
To combine the two methods, and fill in the gaps, this is the code we could use to get the token and execute the call:
<pre class="csharpcode"><span class="kwrd">var</span> tenantName = <span class="str">"blogsample.onmicrosoft.com"</span>;
<span class="kwrd">var</span> clientId = <span class="str">"cae58962-1234-5678-abcd-84de99ecc675"</span>;
<span class="kwrd">var</span> clientSecret = <span class="str">"WxO+54VsAMNf2W3rbnBQZi15yTUiqpIexzBrNrNf+rQ="</span>;

<span class="kwrd">var</span> token = GetAccessToken(tenantName, clientId, clientSecret).Result;

<span class="kwrd">var</span> subscriptionId = <span class="str">"1a917324-4b19-4ab2-8c17-f25e89c58715"</span>;
<span class="kwrd">var</span> resourceGroup = <span class="str">"Default-Networking"</span>;
<span class="kwrd">var</span> routeTableName = <span class="str">"routetable1"</span>;
<span class="kwrd">var</span> ipAddress = <span class="str">"192.168.100.10"</span>;

ChangeRouting(token, subscriptionId, resourceGroup, routeTableName, routeTableName, ipAddress).Wait();</pre>
(Please note that I’m using .Result and .Wait() for my Async methods since this code ran in a console application. Typically, it is not recommended you use .Result or .Wait() Simply <em>await</em> the methods!)

Also, try to modify another resource in Azure, and see if your application has permissions to do so. In my example, let me try to get the details of a Virtual Network.

I’ve replaced this line:
<pre class="csharpcode">await client.Routes.CreateOrUpdateAsync(resourceGroup, routeTableName, routeName, route);</pre>
with this one:
<pre class="csharpcode">client.VirtualNetworks.Get(resourceGroup, "MyVirtualNetwork");</pre>
And here’s the exception I got;

<span style="font-family: Consolas">The client 'cae58962-1234-5678-abcd-84de99ecc675' with object id 'bd69d824-3c1e-4406-a1da-ea0fc085b0e7' does not have authorization to perform action 'Microsoft.Network/virtualNetworks/read' over scope '/subscriptions/1a917324-4b19-4ab2-8c17-f25e89c58715/resourceGroups/Default-Networking/providers/Microsoft.Network/virtualNetworks/MyVirtualNetwork'.</span>

Good! So the application does not have permissions to resources that it doesn’t require access to.]]></content:encoded>
    </item>
    <item>
      <title>Using Time-Based One-Time Passwords for Multi-Factor Authentication in AD FS 3.0</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudpfe/using-time-based-one-time-passwords-for-multi-factor-authentication-in-ad-fs-3-0</link>
      <pubDate>Sun, 26 Oct 2014 06:29:00 GMT</pubDate>
      <dc:creator><![CDATA[Tino Donderwinkel]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudpfe/2014/10/26/using-time-based-one-time-passwords-for-multi-factor-authentication-in-ad-fs-3-0/</guid>
      <description><![CDATA[I often get the question if it is possible in AD FS 3.0 to use the Google Authenticator as the...]]></description>
      <content:encoded><![CDATA[<p>I often get the question if it is possible in AD FS 3.0 to use the <a title="Google Authenticator" href="https://code.google.com/p/google-authenticator/" target="_blank">Google Authenticator</a> as the second factor for authentication. When we read the documentation for the Google Authenticator,&nbsp;we find that this product is actually based on two RFC&#39;s. One of these is <a title="RFC6238 " href="https://tools.ietf.org/html/rfc6238" target="_blank">RFC6238;</a> a Time-Based One-Time Password (TOTP) Algorithm. This algorithm is actually not only used in Google&#39;s Authenticator, but also in the Microsoft Verificator, and potentially in many other time-based authenticators. This means that if we were able to implement TOTP as a multi-factor authentication provider&nbsp;in AD FS, we could use any of the verificator apps out there, and we wouldn&#39;t have to create our own! RFC6238 references another RFC; <a title="RFC4226" href="https://tools.ietf.org/html/rfc4226" target="_blank">RFC4226</a>. Where RFC4226 describes the mechanism to create a code out of a secret key using some HMAC algorithm (&quot;<em>HOTP: An HMAC-Based One-Time Password Algorithm</em>&quot;), RFC6238 adds the time-based component to the code (&quot;<em>TOTP: Time-Based One-Time Password Algorithm</em>&quot;).</p>
<p>TOTP is based on a secret key, shared between the server and the client. Using this key, codes are generated. The generation of the TOTP codes also involves a time component; by doing this, the generated code is only valid for a limited amount of time. (According to RFC6238, by default, 30 seconds.) Next to that, there are some additional requirements, perhaps not imposed by the RFC&#39;s themselves, but maybe by Google&#39;s implementation or simple user friendliness.</p>
<h2>What we will create</h2>
<p>We will create a Multi-Factor Authentication Provider for AD FS 3.0 that adheres to these requirements;</p>
<p>- Implement a Time-Based One-Time Password for MFA in AD FS 3.0.<br />- The secret key is a 16-character key using [A-Z][2-7] (due to Base32 Encoding).<br />- Generated codes are 6 characters long and only contain numbers.<br />- Generated codes are valid for 30 seconds.<br />- Implement some time tolerance (client and server might not have the exact same time).<br />- Codes cannot be used more than once.<br />- Configure the Authenticator app using a QR Code.<br />- Adhere to the (encryption) protocols in the RFC6238 and, hence, RFC4226.</p>
<p>- Should work with the Google Authenticator App&nbsp;and the Microsoft Verificator App and potentially other apps that implement TOTP based on RFC6238.</p>
<h2>Creating Secret Keys, Intervals and Codes</h2>
<p>First, we need to be able to generate the 16-character secret key consisting of the characters that are allowed. The RFC dictates; <em>&quot;The keys SHOULD be randomly generated or derived using key derivation algorithms.&quot;</em> We will use the Random function in the .NET framework to accomplish this.</p>
<!-- code formatted by https://manoli.net/csharpformat/ -->
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">string</span> GenerateSecretKey()
{
      Random random = <span class="kwrd">new</span> Random((<span class="kwrd">int</span>)DateTime.Now.Ticks &amp; 0x0000FFFF);
      <span class="kwrd">return</span> <span class="kwrd">new</span> <span class="kwrd">string</span>((<span class="kwrd">new</span> <span class="kwrd">char</span>[secretKeyLength]).Select(c =&gt; c = allowedCharacters[random.Next(0, allowedCharacters.Length)]).ToArray());
}</pre>
<p>In this snippet, allowedCharacters is a string containing the characters that are allowed in the secret key, and it&#39;s defined elsewhere in the code.</p>
<p>To generate codes that are valid for X&nbsp;seconds, the RFC dictates that we should count the number of X second intervals from the Unix Epoch (1970-1-1):</p>
<p><em>&quot;X represents the time step in seconds (default value X = 30 seconds) and is a system parameter.&quot;</em><br /><em>&quot;T0 is the Unix time to start counting time steps (default value is 0, i.e., the Unix epoch) and is also a system parameter.&quot;</em></p>
<p>By default, we will use intervals of 30 seconds.</p>
<!-- code formatted by https://manoli.net/csharpformat/ -->
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">long</span> GetInterval(DateTime dateTime)
{
      TimeSpan elapsedTime = dateTime.ToUniversalTime() - unixEpoch;
      <span class="kwrd">return</span> (<span class="kwrd">long</span>)elapsedTime.TotalSeconds / validityPeriodSeconds;
}</pre>
<p>In this snippet, unixEpoch is defined elsewhere as DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).</p>
<p>Using the Secret Key and the Interval, we can generate the TOTP code. The code can&#39;t be longer than 6 numeric characters, we&#39;ll simply truncate it if it turns up longer. If it&#39;s shorter, we will prepend it with 0&#39;s. According to RFC4226 we have to use Base32 encoding, and we will use SHA1 for the HMAC key. (I won&#39;t bother you with the details, read the RFC if you&#39;re interested in this stuff. The RFC contains sample code in what I think is Java, but this my .NET translation of that code.)</p>
<!-- code formatted by https://manoli.net/csharpformat/ -->
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">string</span> GetCode(<span class="kwrd">string</span> secretKey, <span class="kwrd">long</span> timeIndex)
{
    <span class="kwrd">var</span> secretKeyBytes = Base32Encode(secretKey);
    HMACSHA1 hmac = <span class="kwrd">new</span> HMACSHA1(secretKeyBytes);
    <span class="kwrd">byte</span>[] challenge = BitConverter.GetBytes(timeIndex);
    <span class="kwrd">if</span> (BitConverter.IsLittleEndian) Array.Reverse(challenge);
    <span class="kwrd">byte</span>[] hash = hmac.ComputeHash(challenge);
    <span class="kwrd">int</span> offset = hash[19] &amp; 0xf;
    <span class="kwrd">int</span> truncatedHash = hash[offset] &amp; 0x7f;
    <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 1; i &lt; 4; i++)
    {
        truncatedHash &lt;&lt;= 8;
        truncatedHash |= hash[offset + i] &amp; 0xff;
    }
    truncatedHash %= 1000000;
    <span class="kwrd">return</span> truncatedHash.ToString(<span class="str">&quot;D6&quot;</span>);
}

<span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">byte</span>[] Base32Encode(<span class="kwrd">string</span> source)
{
    <span class="kwrd">var</span> bits = source.ToUpper().ToCharArray().Select(c =&gt;
        Convert.ToString(allowedCharacters.IndexOf(c), 2).PadLeft(5, <span class="str">&#39;0&#39;</span>)).Aggregate((a, b) =&gt; a + b);
    <span class="kwrd">return</span> Enumerable.Range(0, bits.Length / 8).Select(i =&gt; Convert.ToByte(bits.Substring(i * 8, 8), 2)).ToArray();
}</pre>
<p>We can now generate a secret key, calculate the proper interval starting 1970-1-1 and create a 6-character TOTP code.</p>
<h2>Validating Codes</h2>
<p>We now need to be able to validate code entered by a client. Since the client and the server might not have the exact same time, and transferring the code from the clients machine to the server might take &quot;some&quot; time, chances are that the client is presenting the server with &quot;the previous code&quot; or &quot;the next code&quot; (from the server&#39;s perspective). So when we validate the TOTP code provided by the client, we must also validate if the code presented&nbsp;perhaps is the previous or the next code. Therefore we will implement&nbsp;a configurable future- and past-tolerance. This tolerance is implement by means of past- and future intervals. Remember that 1 interval, by default, is 30 seconds. (From the RFC: &quot;<em>We RECOMMEND that at most one time step is allowed as the network delay.</em>&quot;)</p>
<p>Another thing we need to take into account when validating the codes, is that a&nbsp;code for a specific user&nbsp;can only be used once. Once a user has used the code has to successfully authenticate, the same code cannot be used again. The hard part, from an AD FS MFA perspective, is to check whether or not the code has been used previously.&nbsp;Since you might have multiple AD FS servers in a farm, and these servers do not share state, we cannot use in-memory lists or other objects&nbsp;to check if a code has been used previously. The easiest way to get this check accomplished is by using a database that all servers in the AD FS farm can access and use to store and check used keys. This is also the mechanism I chose to implement. Here is the SQL script for the database that I&#39;m using in my sample.</p>
<!-- code formatted by https://manoli.net/csharpformat/ -->
<pre class="csharpcode"><span class="kwrd">USE</span> [master]
<span class="kwrd">GO</span>

<span class="kwrd">CREATE</span> <span class="kwrd">DATABASE</span> [TOTPAuthentication]
 CONTAINMENT = <span class="kwrd">NONE</span>
 <span class="kwrd">ON</span>  <span class="kwrd">PRIMARY</span> 
( NAME = N<span class="str">&#39;TOTPAuthentication&#39;</span>, FILENAME = N<span class="str">&#39;https://storageaccount.blob.core.windows.net/container/TOTPAuthentication.mdf&#39;</span> , <span class="kwrd">SIZE</span> = 1048576KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
 LOG <span class="kwrd">ON</span> 
( NAME = N<span class="str">&#39;TOTPAuthentication_log&#39;</span>, FILENAME = N<span class="str">&#39;https://storageaccount.blob.core.windows.net/container/TOTPAuthentication_log.ldf&#39;</span> , <span class="kwrd">SIZE</span> = 1048576KB , MAXSIZE = 1073741824KB , FILEGROWTH = 10%)
<span class="kwrd">GO</span>

<span class="kwrd">USE</span> [TOTPAuthentication]
<span class="kwrd">GO</span>

<span class="kwrd">CREATE</span> <span class="kwrd">TABLE</span> [dbo].[Secrets](
    [upn] [<span class="kwrd">varchar</span>](255) <span class="kwrd">NOT</span> <span class="kwrd">NULL</span>,
    [secret] [<span class="kwrd">char</span>](16) <span class="kwrd">NOT</span> <span class="kwrd">NULL</span>,
 <span class="kwrd">CONSTRAINT</span> [PK_Secrets] <span class="kwrd">PRIMARY</span> <span class="kwrd">KEY</span> <span class="kwrd">CLUSTERED</span> 
(
    [upn] <span class="kwrd">ASC</span>
)<span class="kwrd">WITH</span> (PAD_INDEX = <span class="kwrd">OFF</span>, STATISTICS_NORECOMPUTE = <span class="kwrd">OFF</span>, IGNORE_DUP_KEY = <span class="kwrd">OFF</span>, ALLOW_ROW_LOCKS = <span class="kwrd">ON</span>, ALLOW_PAGE_LOCKS = <span class="kwrd">ON</span>) <span class="kwrd">ON</span> [<span class="kwrd">PRIMARY</span>]
) <span class="kwrd">ON</span> [<span class="kwrd">PRIMARY</span>]

<span class="kwrd">GO</span>

<span class="kwrd">CREATE</span> <span class="kwrd">TABLE</span> [dbo].[UsedCodes](
    [upn] [<span class="kwrd">varchar</span>](255) <span class="kwrd">NOT</span> <span class="kwrd">NULL</span>,
    [<span class="kwrd">interval</span>] [bigint] <span class="kwrd">NOT</span> <span class="kwrd">NULL</span>
) <span class="kwrd">ON</span> [<span class="kwrd">PRIMARY</span>]

GO</pre>
<p>The method to validate the codes could look something like this;</p>
<!-- code formatted by https://manoli.net/csharpformat/ -->
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">bool</span> CheckCode(<span class="kwrd">string</span> secretKey, <span class="kwrd">string</span> code, <span class="kwrd">string</span> upn, DateTime when)
{
    <span class="kwrd">long</span> currentInterval = GetInterval(when);
    <span class="kwrd">bool</span> success = <span class="kwrd">false</span>;
    <span class="kwrd">for</span> (<span class="kwrd">long</span> timeIndex = currentInterval - pastIntervals; timeIndex &lt;= currentInterval + futureIntervals; timeIndex++)
    {
        <span class="kwrd">string</span> intervalCode = GetCode(secretKey, timeIndex);
        <span class="kwrd">bool</span> intervalCodeHasBeenUsed = CodeIsUsed(upn, timeIndex);
        <span class="kwrd">if</span> (!intervalCodeHasBeenUsed &amp;&amp; ConstantTimeEquals(intervalCode, code))
        {
            success = <span class="kwrd">true</span>;
            SetUsedCode(upn, timeIndex);
            <span class="kwrd">break</span>;
        }
    }
    <span class="kwrd">return</span> success;
}</pre>
<p>In the snippet, you see that we use a configurable tolerance; pastIntervals and futureIntervals. We now need to implement the &quot;CodeIsUsed&quot; method to check whether the code has been previously used or not. Of course, after a successful authentication we would also have to indicate that the code has been used; SetUsedCode. Last, I want to point out to you the ConstantTimeEquals method. We could simple do &quot;a.Equals(b)&quot; or &quot;a == b&quot; or something like that, but apparently some hackers would then be able to find out where in the process the codes are different, to finally hack the code. (<a title="https://codahale.com/a-lesson-in-timing-attacks/" href="https://codahale.com/a-lesson-in-timing-attacks/">https://codahale.com/a-lesson-in-timing-attacks/</a>) You could just use &quot;a == b&quot;, but if you want to, here is the code for the Constant Time Equals operation;</p>
<!-- code formatted by https://manoli.net/csharpformat/ -->
<pre class="csharpcode"><span class="kwrd">protected</span> <span class="kwrd">static</span> <span class="kwrd">bool</span> ConstantTimeEquals(<span class="kwrd">string</span> a, <span class="kwrd">string</span> b)
{
    <span class="kwrd">uint</span> diff = (<span class="kwrd">uint</span>)a.Length ^ (<span class="kwrd">uint</span>)b.Length;
    <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; a.Length &amp;&amp; i &lt; b.Length; i++)
    {
        diff |= (<span class="kwrd">uint</span>)a[i] ^ (<span class="kwrd">uint</span>)b[i];
    }
    <span class="kwrd">return</span> diff == 0;
}</pre>
<p>We are pretty much done. We only now need to tie a secret key to a user. I have chosen to store the secret keys in a database. I could use Active Directory for that, but due to possible replication latency and permissions issues I have chose not to use that.</p>
<h2>Putting it all together</h2>
<p>Now that we have all to code to create a secret key, to create a time-based code and to validate it, it&#39;s time to combine all the components into the AD FS Multi-Factor Authentication provider. I have chosen to implement this MFA in the following manner;</p>
<p>The first time the user is required to use MFA, and uses the TOTP MFA Provider, a secret key is generated. Using the QR Code &quot;generator&quot; from Google, I will show the user the correct QR code. The user uses this QR code to configure the application. This is shown ONLY ONCE. The key is then stored in the database. If the user should lose the application, or phone, delete the key from the database and the next time the user logs on, he will get a new secret key and a new QR code. (For a taste of the QR code; <a title="Click Here" href="https://chart.googleapis.com/chart?chs=200x200&amp;chld=M%7C0&amp;cht=qr&amp;chl=otpauth%3A%2F%2Ftotp%2FORG%3Afoo@domain.com%3Fsecret%ABCDEFGHIJKLMNOP" target="_blank">click here</a>.)</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/TOTP-1.png" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/TOTP_2D00_1.png"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/TOTP-1.png" original-url="https://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/TOTP_2D00_1.png" border="0" /></a></p>
<p>After the initial setup, the secret key from the database will be used to validate the codes from the client.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/TOTP-2.png" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/TOTP_2D00_2.png"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/TOTP-2.png" original-url="https://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/TOTP_2D00_2.png" border="0" /></a></p>
<p>Now, using the same methodology I described earlier <a title="here" href="/b/cloudpfe/archive/2014/02/01/how-to-create-a-custom-authentication-provider-for-active-directory-federation-services-3-0-part-2.aspx" target="_blank">here</a>,&nbsp;or the methodology described on&nbsp;<a title="here" href="https://msdn.microsoft.com/en-us/library/dn783423.aspx" target="_blank">MSDN</a>, we can create our MFA Provider for AD FS 3.0. You can download the whole C# project <a title="here" href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/TOTPAuthenticationProvider%20-%20Blog.zip" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/TOTPAuthenticationProvider-_2D00_-Blog.zip">here</a>. You will have to create the proper reference to the AD FS DLL, create a database and configure the proper SQL Connection String. After compilation, copy it to the AD FS servers in the farm, add the DLL to the Global Assembly Cache and register the MFA provider. (Not sure how to do that? Check the references I pointed out to you!)</p>
<p>Good luck! I&#39;ve tested the solution with the Microsoft Verificator App, some &quot;random&quot; Google Authenticator Apps for Windows Phone and some for Windows. I don&#39;t own an iPhone, iPad or Android device. So if you have tried this solution with any of those devices and apps; please let me know how that worked!</p>
<p>Some key&nbsp;things to take into account before you start using this codebase for your own authentication provider:</p>
<h2>Safety</h2>
<p>This code has not been created with safety in mind. Think about encrypting the location where secret keys are stored.</p>
<h2>Stability</h2>
<p>No proper error handling has been implement. This could severely impact the working of the AD FS farm.</p>
<h2>Support</h2>
<p>This is only Proof-of-Concept code. This code is NOT SUPPORTED by me or Microsoft in any way, shape or form.</p>
<pre># THIS CODE AND ANY ASSOCIATED INFORMATION ARE PROVIDED &ldquo;AS IS&rdquo; WITHOUT
# WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
# LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS
# FOR A PARTICULAR PURPOSE. THE ENTIRE RISK OF USE, INABILITY TO USE, OR 
# RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.</pre>
<p></p>]]></content:encoded>
    </item>
    <item>
      <title>Microsoft Azure: Connecting multiple VNET's to a VNET.</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudpfe/microsoft-azure-connecting-multiple-vnets-to-a-vnet</link>
      <pubDate>Fri, 18 Jul 2014 13:47:41 GMT</pubDate>
      <dc:creator><![CDATA[Tino Donderwinkel]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudpfe/2014/07/18/microsoft-azure-connecting-multiple-vnets-to-a-vnet/</guid>
      <description><![CDATA[UPDATE: Microsoft has implemented VNET PEERING, which makes this article obsolete. For more...]]></description>
      <content:encoded><![CDATA[<strong>UPDATE: Microsoft has implemented VNET PEERING, which makes this article obsolete. For more information about Azure VNet Peering: <a href="https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-peering-overview">https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-peering-overview</a></strong>
<h1>Introduction</h1>
<p>Recently, Microsoft has introduced a new feature in Microsoft Azure to allow a direct VPN connection between multiple Virtual Networks (VNets). In this blog post I will explain how to connect multiple VNets to each other within Microsoft Azure.</p>
<p>A good starting point to read more on how to configure a connection between <span style="text-decoration:underline">two</span> VNets can be found here: <a title="Configure a VNet to VNet Connection" href="https://msdn.microsoft.com/en-us/library/azure/dn690122.aspx" target="_blank">Configure a VNet to VNet Connection</a> and <a title="Creating a Stretched Network on Microsoft Azure" href="https://blogs.msdn.com/b/niallsblog/archive/2014/05/22/creating-a-stretched-network-on-microsoft-azure.aspx" target="_blank">Creating a Stretched Network on Microsoft Azure</a>. The examples give you great guidance on how to configure VNet &lt;--&gt; VNet connectivity.</p>
<p>From the <a title="Virtual Network FAQ" href="https://msdn.microsoft.com/en-us/library/azure/dn133803.aspx" target="_parent">Virtual Network FAQ</a> we read that we connect multiple VNets to each other:</p>
<p><em>Q: How many on premises sites and virtual networks can one virtual network connect to?</em><br /><em>A: Max. 10 combined; e.g., one Azure virtual network and connect to 6 on premises sites and 4 virtual networks.</em></p>
<p>Yet, configuring a connection from one VNet to multiple other VNets is not as trivial as it perhaps should be. So what if you want to create some &quot;star&quot; topology? Or you need to connect two VNets to one other VNet? None of the articles mentioned before care to explain how something like that could be configured, but things functionality in Microsoft Azure will unleash new scenario&#039;s that previously where only possible using multiple VPN connections to on-premises locations. This is specifically try for people that want to deploy geo-redundant IaaS or PaaS solutions in Azure.</p>
<h1>Solution</h1>
<p>Let&#039;s assume you want to deploy&nbsp;two Cloud Services, in two different Microsoft Azure Datacenters. By using Microsoft Azure Traffic Manager, you can make sure that clients connect to that specific Cloud Service that performs best for their locations. (For any geographically dispersed, geo-redundant, solution, this should be something that you at least take a look at.)&nbsp;A Cloud Service would be deployed in a Virtual Network, and a Virtual Network is tied to Microsoft Azure Datacenter.&nbsp;Hence, both Cloud Services would be deployed in their own Virtual Network. Previously, if these Cloud Services would need to connect to a &quot;shared resource&quot;, like a Microsoft SQL Database, the only option would be to connect both Virtual Networks to an on-premises VPN endpoint (for example a Cisco- or Juniper device, or a Windows Server 2012 R2 Routing and Remote Access Server.) Then, the on-premises equipment could route traffic between the two VNets. All traffic between the two VNets would then be routed through the on-premises infrastructure.</p>
<p>So let&#039;s assume we have this sort of solution; deployed in two different Microsoft Azure Datacenters, and they both need to connect to a Microsoft SQL Database on the back-end. This Microsoft SQL Database is deployed on Microsoft Azure Infrastructure-as-a-Service, running in a third Microsoft Azure Datacenter, in it&#039;s own Cloud Service (Let&#039;s call it <em>CSDB</em>)&nbsp;and it&#039;s own Virtual Network (Let&#039;s call it <em>VNET3</em>). The front-ends are deployed in two Cloud Services (let assume the are named&nbsp;<em>CSINET1</em> and <em>CSINET2</em>) and their corresponding Virtual Networks (Let&#039;s call these <em>VNET1</em> and <em>VNET2</em>).</p>
<p>The goal here is to enable traffic to flow from VNET1 to VNET3 (and vice-versa) and from VNET2 to VNET3. Hence, we would need to connect VNET3 to two different Vnets; VNET1 as well as VNET2. Something like this: VNET1 &lt;--&gt; VNET3 &lt;--&gt; VNET2.</p>
<p>Here is the configuration of VNET1:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/VNET1-Config-01.PNG"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/VNET1-Config-01.PNG" border="0" /></a></p>
<p>You see that we use the address space 10.1.0.0/16 for this virtual network. The servers live in the Subnet-1 subnet; 10.1.0.0/19. We have created a Gateway Subnet called Gateway with IP network range 10.1.32.0/29.</p>
<p>The configuration for VNET2 is the same, except that we now use the 10.2.x.x address space:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/VNET2-Config-01.PNG"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/VNET2-Config-01.PNG" border="0" /></a></p>
<p>For our last network, VNET3, where the database &quot;lives&quot;, we use 10.3.x.x:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/VNET3-Config-01.PNG"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/VNET3-Config-01.PNG" border="0" /></a></p>
<p>Please do keep in mind that connection Azure Virtual Networks to other Azure Virtual Networks ONLY works when the gateway has been setup using Dynamic Routing.</p>
<p>If we want to connect a Virtual Network to another network (whether it be a Virtual Network or an on-premises network) we will have to define the network address range(s) for these networks in Microsoft Azure, under Local Networks. In our demonstration, we will create a Local Network for VNET1, VNET2 and VNET3, with their corresponding network ranges. (If you have not already created your Gateways in the Virtual Networks, simply put a bogus VPN Address in the dialog. We can change that later.)</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Local%20Nets.png"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Local%20Nets.png" border="0" /></a></p>
<p>Now, from the Microsoft Azure Management Portal, we can connect VNET1 to VNET3 and VNET2 to VNET3.</p>
<p>If you need any assistance completing the previous steps, please consult <a title="Configure a VNet to VNet Connection" href="https://msdn.microsoft.com/en-us/library/azure/dn690122.aspx" target="_blank">Configure a VNet to VNet Connection</a>. This will guide you through the process of creating the gateways, the local networks and connecting a Virtual Network to another Virtual Network.</p>
<p>Now, the real challenge starts when we want to configure VNET3 to connect to two other Vnets; VNET1 and VNET2. We cannot do this through the current Microsoft Azure Management Portal. Once we &quot;connect&quot; VNET3 to one of the other subnets, through the portal, we can no longer connect this VNet to another VNet. Apparently, what we want is not possible from the portal (currently).</p>
<p>To connect VNET3 to the remaining Vnet:</p>
<p>From the Microsoft Azure Management Portal, download the configuration for your Virtual Network:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Export.png"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Export.png" border="0" /></a></p>
<p>Let&#039;s assume you save this file as <em>vnet.xml</em> on your local machine.</p>
<p>Alternatively, you can use PowerShell to export the configuration by using this command:</p>
<p><span style="font-family:courier new,courier">Get-AzureVNetConfig -ExportToFile C:\Temp\VNET.xml</span></p>
<p>Open the <em>VNET.xml</em> file using notepad (or similar text editor) and locate the VNet configuration part for the VNet that you want to connect to multiple other VNet&#039;s. In our example, that is VNET3.</p>
<p>Locate this section:</p>
<p><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">VirtualNetworkSite</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"> </span></span></span><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small">name</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">=</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><em><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">VNET3</span></span></span></em><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"> </span></span></span><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small">Location</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">=</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><em><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">Azure Datacenter</span></span></span></em><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"></span></span></span></p>
<p>Under that section, there should be a Gateway section, that shows you the current gateway configuration. This is where need to make our changes.</p>
<p>Locate the Gateway section in the VirtualNetworkSite section:</p>
<p><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"> &lt;</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">Gateway</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">ConnectionsToLocalNetwork</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">LocalNetworkSiteRef</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"> </span></span></span><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small">name</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">=</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">VNET1</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">Connection</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"> </span></span></span><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small">type</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">=</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">IPsec</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"> /&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;/</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">LocalNetworkSiteRef</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;/</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">ConnectionsToLocalNetwork</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;/</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">Gateway</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;</span></span></span></p>
<p>In this case, our VNET3 already had a connection with VNET1, but we need to add a connection to VNET2. We add the appropriate section to this Gateway section. It should now look like this:</p>
<p><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;</span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">Gateway</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">ConnectionsToLocalNetwork</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">LocalNetworkSiteRef</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"> </span></span></span><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small">name</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">=</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">VNET1</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">Connection</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"> </span></span></span><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small">type</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">=</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">IPsec</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"> /&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;/</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">LocalNetworkSiteRef</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">LocalNetworkSiteRef</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"> </span></span></span><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small">name</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">=</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">VNET2</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">Connection</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"> </span></span></span><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small"><span style="color:#ff0000;font-family:Consolas;font-size:small">type</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">=</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">IPsec</span></span></span><span style="font-family:Consolas;font-size:small"><span style="font-family:Consolas;font-size:small">&quot;</span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"> /&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;/</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">LocalNetworkSiteRef</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"></span></span></span>&lt;/</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">ConnectionsToLocalNetwork</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;<br /></span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&lt;/</span></span></span><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small"><span style="color:#a31515;font-family:Consolas;font-size:small">Gateway</span></span></span><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small"><span style="color:#0000ff;font-family:Consolas;font-size:small">&gt;</span></span></span></p>
<p>Save this modified xml file, and import it into Azure;</p>
<p><span style="font-family:courier new,courier">Set-AzureVNetConfig -ConfigurationPath C:\Temp\VNET.xml</span></p>
<p>Make sure that your command completes successfully:</p>
<p><span style="font-family:courier new,courier">OperationDescription&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OperationId&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OperationStatus</span><br /><span style="font-family:courier new,courier">--------------------&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -----------&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ---------------</span><br /><span style="font-family:courier new,courier">Set-AzureVNetConfig&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 01fc891b-c4a5-ceb3-9a70... Succeeded</span></p>
<p>The new configuration should now be applied to Azure. When you open the Azure Management Portal and navigate to Virtual Networks, select the network you just modified, you will see that the GUI for the Dashboard has changed. You see that your virtual network is trying to connect to two other virtual networks. From the Azure Management Portal, you are no longer allowed to make any changes: (this screenshot is from a different setup, with different VNet names, but you&#039;ll get the idea...)</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Capture.PNG"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Capture.PNG" border="0" /></a></p>
<p>Although we see that there are now two virtual network connections, Azure is unable to connect the two virtual networks. This is because the shared keys for the gateways have not been (properly) set. We need to fix this. (And we cannot do this through the Azure Management Portal.) So we fix these keys through PowerShell:</p>
<p><span style="font-family:courier new,courier">Set-AzureVNetGatewayKey -VNetName VNET3 -LocalNetworkSiteName VNET1 -SharedKey SuperSecretKey</span><br /><span style="font-family:courier new,courier">Set-AzureVNetGatewayKey -VNetName VNET3 -LocalNetworkSiteName VNET2 -SharedKey SuperSecretKey</span><br /><span style="font-family:courier new,courier">Set-AzureVNetGatewayKey -VNetName VNET2 -LocalNetworkSiteName VNET3 -SharedKey SuperSecretKey</span><br /><span style="font-family:courier new,courier">Set-AzureVNetGatewayKey -VNetName VNET1 -LocalNetworkSiteName VNET3 -SharedKey SuperSecretKey</span></p>
<p>In this example, I set the keys for all Gateway connections but that is not required. You can use different keys for different networks and you don&#039;t have to change existing keys. Now give your gateways some time to bring up the connection, and check the Dashboard for the virtual networks to see if the connections work. You should see something resembling this:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Capture2.PNG"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Capture2.PNG" border="0" /></a></p>
<p>If you have Virtual Machines in for example VNET1, you can now connect to other Virtual Machines in VNET3. From machines in VNET2 you can connect to machines in VNET3. Please do keep in mind that using this simple sample configuration will not allow you to connect from machines in VNET1 to machines in VNET2, or vice versa, directly. If that&#039;s what you want, you can setup a new network connection following the same procedure.</p>
<p>That&#039;s it! You&#039;ve managed to connect multiple virtual networks to another virtual network in Microsoft Azure.</p>
<p></p>]]></content:encoded>
    </item>
    <item>
      <title>Pre-Provisioning Microsoft Azure Multi-Factor Authentication for Users</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudpfe/pre-provisioning-microsoft-azure-multi-factor-authentication-for-users</link>
      <pubDate>Wed, 09 Apr 2014 00:04:13 GMT</pubDate>
      <dc:creator><![CDATA[Tino Donderwinkel]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudpfe/2014/04/09/pre-provisioning-microsoft-azure-multi-factor-authentication-for-users/</guid>
      <description><![CDATA[If you enable or enforce Azure Multi-Factor Authentication for your users, you will most likely have...]]></description>
      <content:encoded><![CDATA[<p>If you <span style="text-decoration:underline;">enable</span> or <span style="text-decoration:underline;">enforce</span> Azure Multi-Factor Authentication for your users, you will most likely have seen the wizard that user goes through in order to properly provision Multi-Factor Authentication for their account.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/1.png" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/1.png"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/1.png" original-url="https://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/1.png" border="0" /></a></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/2.png" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/2.png"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/2.png" original-url="https://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/2.png" border="0" /></a></p>
<p>As an administrator, you might want to ease this process to the end-user and pre-provision Multi-Factor Authentication in Microsoft Azure Active Directory.</p>
<p>First, make sure that the users Mobile Phone Number is properly set in Microsoft Azure Active Directory. (If you are using the Directory Synchronization Tool (DirSync) or the Windows Azure Active Directory Connector for FIM 2010 R2, the user&#39;s mobile phone number will by synchronized from Active Directory automatically.)</p>
<p>If that&#39;s set, you can enable and configure Multi-Factor Authentication by using PowerShell:</p>
<!-- code formatted by https://manoli.net/csharpformat/ -->
<pre class="csharpcode">$upn = <span class="str">&quot;VOConner@contoso.com&quot;</span>


$st = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$st.RelyingParty = <span class="str">&quot;*&quot;</span>
$st.State = <span class="str">&quot;Enforced&quot;</span>

$sta = @($st)

$sm1 = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationMethod
$sm1.IsDefault = $true
$sm1.MethodType = <span class="str">&quot;OneWaySMS&quot;</span>

$sm2 = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationMethod
$sm2.IsDefault = $false
$sm2.MethodType = <span class="str">&quot;TwoWayVoiceMobile&quot;</span>

$sm = @($sm1, $sm2)

Set-MsolUser -UserPrincipalName $upn -StrongAuthenticationRequirements $sta -StrongAuthenticationMethods $sm</pre>
<p>By using this script, Multi-Factor Authentication for the user VOConner@contoso.com will be enabled for all applications in Azure Active Directory (this is the $st variable in the code). After we enable MFA, we need to provide Azure with the methods we want to use for MFA. In this case, we enable two methods; the PIN Text Message (OneWaySMS) and the voice call (TwoWayVoiceMobile). The default authentication method is OneWaySMS. These two methods are held in the $sm variable.</p>
<p>Last, we update the user using the Set-MsolUser command.</p>]]></content:encoded>
    </item>
    <item>
      <title>Using Windows Azure Active Directory as an Attribute Store in AD FS</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudpfe/using-windows-azure-active-directory-as-an-attribute-store-in-ad-fs</link>
      <pubDate>Tue, 25 Mar 2014 11:53:07 GMT</pubDate>
      <dc:creator><![CDATA[Tino Donderwinkel]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudpfe/2014/03/25/using-windows-azure-active-directory-as-an-attribute-store-in-ad-fs/</guid>
      <description><![CDATA[More and more of our customers are unleashing the power of Windows Azure Active Directory. This...]]></description>
      <content:encoded><![CDATA[<p>More and more of our customers are unleashing the power of <a title="Windows Azure Active Directory" href="https://www.windowsazure.com/en-us/services/active-directory/">Windows Azure Active Directory</a>. This Enterprise-level identity and access management for the cloud is so powerful that most like, I&#39;ll be creating more articles on this subject.</p>
<p>When you add Azure Active Directory as an Identity Provider, or Claims Provider, in Active Directory Federation Services, you get a defined set of claims from it. If you&#39;re not using the Premium version of Azure Active Directory, you won&#39;t for example get claims for group membership in Azure Active Directory. Other attributes that might be present in Azure Active Directory, like an alternate email address, are also not available as claims. There could be occasions where you need this information when a user authentications through an Azure Active Directory that you manage. (Now that is the keyword here; whatever we do in this article requires you to have proper permissions on the Azure Active Directory.)</p>
<p>In order to use attributes from Azure Active Directory users as claims in AD FS, we can create an Attribute Store that queries Azure Active Directory. This article explains just that. To get started, first create you Attribute Store as outlined on one of my earlier articles; <a title="How to create a Custom Attribute Store for Active Directory Federation Services 3.0" href="/b/cloudpfe/archive/2013/12/27/how-to-create-a-custom-attribute-store-for-active-directory-federation-services-3-0.aspx">How to create a Custom Attribute Store for Active Directory Federation Services 3.0</a>. We&#39;ll focus on the code that you need to write in the class that you create.</p>
<p>Prerequisites</p>
<ul>
<li>Check <a title="How to create a Custom Attribute Store for Active Directory Federation Services 3.0" href="/b/cloudpfe/archive/2013/12/27/how-to-create-a-custom-attribute-store-for-active-directory-federation-services-3-0.aspx">How to create a Custom Attribute Store for Active Directory Federation Services 3.0</a></li>
<li>Access to a Windows Azure Subscription with an Azure Active Directory provisioned. For a How To: <a href="https://msdn.microsoft.com/en-us/library/dn569294.aspx">https://msdn.microsoft.com/en-us/library/dn569294.aspx</a></li>
<li>A working federation trust relationship with Azure Active Directory and Active Directory Federation Services (where Azure Active Directory is setup as a Claims Provider in AD FS and AD FS is setup as an application in Azure Active Directory).</li>
</ul>
<h1>Active Directory Authentication Library</h1>
<p>First, we need to add the Active Directory Authentication Library. This is a NuGet package that can be installed by using the Package Manager Console (at the bottom of you Visual Studio screen) or through the Tools, Package Manager and then either Package Manager Console or Manage NuGet Packages for Solution...</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Package%20Manager%201.png" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/Package-Manager-1.png"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Package%20Manager%201.png" original-url="https://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/Package-Manager-1.png" border="0" /></a></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Package%20Manager%202.png" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/Package-Manager-2.png"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Package%20Manager%202.png" original-url="https://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/Package-Manager-2.png" border="0" /></a></p>
<p>If you&#39;re using the Package Manager Console type this command:</p>
<p><span style="font-family:courier new,courier;">Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory -Version 1.0.3</span></p>
<p>In this case, I&#39;m adding version 1.0.3, but newer versions might be available. Please check <a href="https://www.nuget.org/packages/Microsoft.IdentityModel.Clients.ActiveDirectory/">https://www.nuget.org/packages/Microsoft.IdentityModel.Clients.ActiveDirectory/</a> to see what the latest version is.</p>
<p>If you&#39;re using the Manage NuGet Packages option, search for &quot;Active Directory Authentication Library&quot; and select the version you want from there.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Package%20Manager%203.png" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/Package-Manager-3.png"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/Package%20Manager%203.png" original-url="https://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/Package-Manager-3.png" border="0" /></a></p>
<p>After adding that NuGet package, download the <a title="Windows Azure AD Graph API Helper Library" href="https://code.msdn.microsoft.com/windowsazure/Windows-Azure-AD-Graph-API-a8c72e18">Windows Azure AD Graph API Helper Library</a>. Unpack the zip file, open the Solution in Visual Studio and compile it. Next, add a reference to the resulting DLL from you Attribute Store project. Now, the references in you Attribute Store project should resemble this;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/References.PNG" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/References.PNG"><img alt=" " src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/01/41/References.PNG" original-url="https://blogs.technet.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-01-41/References.PNG" border="0" /></a></p>
<h1>Building the code</h1>
<p>Now switch to the class file where you will build the Attribute Store in. In the example I referenced earlier, it&#39;s called Class1.cs, but I will give it a more meaningful name, like WAADAttributeStore.cs</p>
<p>Inspect the using statements, at the beginning of the code, and add these lines:</p>
<!-- code formatted by https://manoli.net/csharpformat/ -->
<pre class="csharpcode"><span class="kwrd">using</span> Microsoft.IdentityServer.ClaimsPolicy.Engine.AttributeStore;
<span class="kwrd">using</span> Microsoft.WindowsAzure.ActiveDirectory;
<span class="kwrd">using</span> Microsoft.WindowsAzure.ActiveDirectory.GraphHelper;
<span class="kwrd">using</span> System.IdentityModel;</pre>
<p>Make sure you properly paste this code as the Initialize method in the class:</p>
<!-- code formatted by https://manoli.net/csharpformat/ -->
<pre class="csharpcode">        <span class="kwrd">public</span> <span class="kwrd">void</span> Initialize(Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; config)
        {
            <span class="kwrd">if</span> (<span class="kwrd">null</span> == config)
            {
                <span class="kwrd">throw</span> <span class="kwrd">new</span> AttributeStoreInvalidConfigurationException(<span class="str">&quot;No configuration parameters passed.&quot;</span>);
            }

            <span class="kwrd">string</span> tenantName;
            <span class="kwrd">string</span> clientId;
            <span class="kwrd">string</span> password;

            <span class="kwrd">if</span> (config.ContainsKey(<span class="str">&quot;TenantName&quot;</span>))
            {
                tenantName = config[<span class="str">&quot;TenantName&quot;</span>];
            }
            <span class="kwrd">else</span>
            {
                <span class="kwrd">throw</span> <span class="kwrd">new</span> AttributeStoreInvalidConfigurationException(<span class="str">&quot;TenantName configuration parameter not found.&quot;</span>);
            }
            <span class="kwrd">if</span> (config.ContainsKey(<span class="str">&quot;ClientId&quot;</span>))
            {
                clientId = config[<span class="str">&quot;ClientId&quot;</span>];
            }
            <span class="kwrd">else</span>
            {
                <span class="kwrd">throw</span> <span class="kwrd">new</span> AttributeStoreInvalidConfigurationException(<span class="str">&quot;ClientId configuration parameter not found.&quot;</span>);
            }
            <span class="kwrd">if</span> (config.ContainsKey(<span class="str">&quot;Password&quot;</span>))
            {
                password = config[<span class="str">&quot;Password&quot;</span>];
            }
            <span class="kwrd">else</span>
            {
                <span class="kwrd">throw</span> <span class="kwrd">new</span> AttributeStoreInvalidConfigurationException(<span class="str">&quot;Password configuration parameter not found.&quot;</span>);
            }

            AADJWTToken token = DirectoryDataServiceAuthorizationHelper.GetAuthorizationToken(tenantName, clientId, password);
            <span class="kwrd">this</span>.graphService = <span class="kwrd">new</span> DirectoryDataService(tenantName, token);
        }</pre>
<p>This Initialize method takes three parameters; TenantName, ClientId and Password. This information can be taken from the Azure management portal at <a href="https://manage.windowsazure.com">https://manage.windowsazure.com</a> after adding a custom application to your Azure Active Directory. (More information: <a href="https://msdn.microsoft.com/en-us/library/dn151791.aspx">https://msdn.microsoft.com/en-us/library/dn151791.aspx</a>) Now, let&#39;s just finish the coding part. In this example, we going to extract group membership information from Azure Active Directory (which is not required if you use Azure Active Directory Premium, because group membership is available as claims in there).</p>
<p>Replace the BeginExecuteQuery method with this code:</p>
<!-- code formatted by https://manoli.net/csharpformat/ -->
<pre class="csharpcode">        <span class="kwrd">public</span> IAsyncResult BeginExecuteQuery(<span class="kwrd">string</span> query, <span class="kwrd">string</span>[] parameters, AsyncCallback callback, <span class="kwrd">object</span> state)
        {
            <span class="kwrd">if</span> (String.IsNullOrEmpty(query))
            {
                <span class="kwrd">throw</span> <span class="kwrd">new</span> AttributeStoreQueryFormatException(<span class="str">&quot;No query string.&quot;</span>);
            }
            <span class="kwrd">if</span> (<span class="kwrd">null</span> == parameters)
            {
                <span class="kwrd">throw</span> <span class="kwrd">new</span> AttributeStoreQueryFormatException(<span class="str">&quot;No query parameter.&quot;</span>);
            }

            <span class="kwrd">if</span> (parameters.Length != 1)
            {
                <span class="kwrd">throw</span> <span class="kwrd">new</span> AttributeStoreQueryFormatException(<span class="str">&quot;More than one query parameter.&quot;</span>);
            }

            <span class="kwrd">string</span> inputString = parameters[0];

            <span class="kwrd">if</span> (inputString == <span class="kwrd">null</span>)
            {
                <span class="kwrd">throw</span> <span class="kwrd">new</span> AttributeStoreQueryFormatException(<span class="str">&quot;Query parameter cannot be null.&quot;</span>);
            }

            <span class="kwrd">string</span>[][] outputValues;

            <span class="kwrd">switch</span> (query)
            {
                <span class="kwrd">case</span> <span class="str">&quot;GetGroupNamesByUserName&quot;</span>:
                    {
                        <span class="kwrd">string</span> userPrincipalName = inputString;

                        User user = graphService.users
                            .Where(u =&gt; u.accountEnabled == <span class="kwrd">true</span> &amp;&amp; u.userPrincipalName == userPrincipalName)
                            .AsEnumerable()
                            .SingleOrDefault();

                        <span class="kwrd">var</span> groupReferences = graphService.LoadProperty(user, <span class="str">&quot;memberOf&quot;</span>)
                            .OfType&lt;Group&gt;()
                            .Select(g =&gt; g.displayName)
                            .ToArray();

                        outputValues = <span class="kwrd">new</span> <span class="kwrd">string</span>[groupReferences.Length][];

                        <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; groupReferences.Length; i++)
                        {
                            outputValues[i] = <span class="kwrd">new</span> <span class="kwrd">string</span>[1] { groupReferences[i] };
                        }
                        <span class="kwrd">break</span>;
                    }
                <span class="kwrd">default</span>:
                    {
                        <span class="kwrd">throw</span> <span class="kwrd">new</span> AttributeStoreQueryFormatException(<span class="str">&quot;The query string is not supported.&quot;</span>);
                    }
            }

            TypedAsyncResult&lt;<span class="kwrd">string</span>[][]&gt; asyncResult = <span class="kwrd">new</span> TypedAsyncResult&lt;<span class="kwrd">string</span>[][]&gt;(callback, state);
            asyncResult.Complete(outputValues, <span class="kwrd">true</span>);
            <span class="kwrd">return</span> asyncResult;
        }</pre>
<p>Our sample Attribute Store only supports one single query; GetGroupNamesByUserName. This method gets the users group membership, based on the username (where the username is a UPN). This UPN has to be provided by AD FS (and was originally provided by Azure Active Directory). We then take this UPN to lookup the user in Azure Active Directory, get the group membership and return these groups as claims. You can have AD FS decide what the exact claim type will be that AD FS will issue.</p>
<p>Last, check that the EndExecuteQuery method has the code we&#39;ve seen before:</p>
<!-- code formatted by https://manoli.net/csharpformat/ -->
<pre class="csharpcode">        <span class="kwrd">public</span> <span class="kwrd">string</span>[][] EndExecuteQuery(IAsyncResult result)
        {
            <span class="kwrd">return</span> TypedAsyncResult&lt;<span class="kwrd">string</span>[][]&gt;.End(result);
        }</pre>
<p>Okay, that&#39;s it! Compile it, ship the resulting DLL to the AD FS server, add the Attribute Store and use these initialization parameters:</p>
<ul>
<li>TenantName</li>
<li>ClientId</li>
<li>Password</li>
</ul>
<p>Then, configure a claim rule for a relying party to use the GetGroupNamesByUserName query for the attribute store, and pass a UPN as the parameter. Again, if you need more information on how to do this; consult my previous article; <a title="How to create a Custom Attribute Store for Active Directory Federation Services 3.0" href="/b/cloudpfe/archive/2013/12/27/how-to-create-a-custom-attribute-store-for-active-directory-federation-services-3-0.aspx">How to create a Custom Attribute Store for Active Directory Federation Services 3.0</a></p>
<p>Have fun!</p>
<p></p>]]></content:encoded>
    </item>
  </channel>
</rss>