<?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>Jen's blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/jenfieldmsft/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/jenfieldmsft/feed.xml</link>
    <description />
    <lastBuildDate>Wed, 17 Apr 2019 04:08:18 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Debugging and Troubleshooting your MFA adapter</title>
      <link>https://docs.microsoft.com/archive/blogs/jenfieldmsft/debugging-and-troubleshooting-your-mfa-adapter</link>
      <pubDate>Mon, 24 Mar 2014 18:00:00 GMT</pubDate>
      <dc:creator><![CDATA[JenField_MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jenfieldmsft/2014/03/24/debugging-and-troubleshooting-your-mfa-adapter/</guid>
      <description><![CDATA[Debugging your adapter
If you hit a problem with either the sample or your own adapter,...]]></description>
      <content:encoded><![CDATA[<h1><span style="font-size: small;">Debugging your adapter</span></h1>
<p>If you hit a problem with either the sample or your own adapter, you&rsquo;ll probably wish to debug to see what&rsquo;s going on.&nbsp; You&rsquo;ll need to attach your debugger to the AD FS process <strong>Microsoft.IdentityServer.ServiceHost.exe</strong>. &nbsp;</p>
<p>If you are using Visual Studio 2012 you can do this locally or remotely.</p>
<p>Tips for remote debugging in Visual Studio 2012</p>
<ul>
<li>Install the <a href="https://www.microsoft.com/en-us/download/details.aspx?id=38184">VS 2012 remote debugging components</a> on the AD FS test machine</li>
<li>After installation, the first time you run &ldquo;Remote Debugger&rdquo; it will configure the remote debugging components on the test STS (including the correct firewall settings)</li>
<li>On the dev box:</li>
<ul>
<li>Ensure the configured list of symbols file locations (<strong>Debug</strong>-&gt;<strong>Options</strong> and <strong>Settings</strong>-&gt;<strong>Debugging</strong>-&gt;<strong>Symbols</strong>) contains an entry that points to the location of your pdb file</li>
<li>Ensure the version of the dll and pdb match and match the source</li>
<li>Ensure you are running VS 2012 as elevated (run as administrator from Start page)</li>
<li>Start remote debugging by choosing menu option <strong>Debug</strong>...<strong>Attach to process</strong>... and select the AD FS service as shown below</li>
<li>Specify the remote machine and port in the <strong>Qualifier</strong> (you can get the port from the UI of the Remote Debugger itself)</li>
<li>Ensure <strong>Attach to</strong>: is set to <strong>Managed (v4.5, v4.0) code</strong> (this will require elevation)</li>
<li>Once attached, find your dll in the <strong>Modules</strong> window and ensure the symbols are loaded</li>
</ul>
</ul>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/0310.debug1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/0310.debug1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/0310.debug1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/0310.debug1.png" alt="" border="0" /></a></p>
<p>Finally, initiate a login (for example, by opening the IDP initiated signon html page) and sign in as a valid Active Directory user.</p>
<p>&nbsp;</p>
<h1><span style="font-size: small;">Additional / Troubleshooting Information</span></h1>
<h1><span style="font-size: small;">Get PublicKeyToken value for sn signed assembly (cmd line)</span></h1>
<p><span style="font-family: 'courier new', courier;">C:\&gt; sn.exe &ndash;T MFAAdapter.dll</span></p>
<h1><span style="font-size: small;">Add assembly to GAC on AD FS server (cmd line)</span></h1>
<p><span style="font-family: 'courier new', courier;">C:\&gt;.\gacutil.exe /if .\MFAAdapter.dll</span></p>
<h1><span style="font-size: small;">View assembly in the GAC (cmd line)</span></h1>
<p><span style="font-family: 'courier new', courier;">C:\&gt; .\gacutil.exe /l mfaadapter</span></p>
<h1><span style="font-size: small;">Remove assembly from GAC (cmd line)</span></h1>
<p>If you need to remove and replace the assembly with an updated version, use &lsquo;gacutil /u &hellip;&rsquo; to remove assemblies from the GAC, and&rsquo; gacutil /if &hellip;&rsquo; to add the new one. &nbsp;(You may need to increment the version (in Visual Studio prior to build) in order for the dll to be truly replaced)</p>
<p>First, use the following command to find the fully qualified strong name of the entry:</p>
<p><span style="font-family: 'courier new', courier;">C:\&gt;.\gacutil.exe /l mfaadapter</span></p>
<p>Then, use the following command to remove it from the GAC:</p>
<p>gacutil /u &ldquo;&lt;output from the above command&gt;&rdquo;</p>
<p>Example:</p>
<p><span style="font-family: 'courier new', courier;">C:\&gt;.\gacutil /u &ldquo;mfaadapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2ed0b0f386e8e3a4&rdquo;</span></p>
<h1><span style="font-size: small;">Unregister provider (PowerShell)</span></h1>
<p><span style="font-family: 'courier new', courier;">PS C:\&gt; Unregister-AdfsAuthenticationProvider &ndash;Name &ldquo;MyMFAAdapter&rdquo;</span></p>
<ul>
<li>Note that the value you pass for &ldquo;Name&rdquo; is the same value as &ldquo;Name&rdquo; you provided to the Register-AdfsAuthenticationProvider cmdlet.&nbsp; It is also the &ldquo;Name&rdquo; property that is output from Get-AdfsAuthenticationProvider.</li>
<li>Note that before unregistering a provider, must remove the provider from the AdfsGlobalAuthenticationPolicy (either by clearing the checkboxes you checked in AD FS admin MMC snapin or by using PSH)</li>
<li>Note that the AD FS service must be restarted after this operation</li>
</ul>
<h1><span style="font-size: small;">Re-register provider with config data (PowerShell)</span></h1>
<p><span style="font-family: 'courier new', courier;">PS:\&gt; Register-AdfsAuthenticationProvider &ndash;TypeName YourTypeName &ndash;Name &ldquo;MyMFAAdapter2&rdquo; &ndash;ConfigurationFilePath &ldquo;C:\sources\configData.txt&rdquo;</span></p>
<ul>
<li>Note that the AD FS service must be restarted after this operation</li>
</ul>
<div>&nbsp;</div>]]></content:encoded>
    </item>
    <item>
      <title>Build your own external authentication provider for AD FS in Windows Server 2012 R2: Walk-through Part 2</title>
      <link>https://docs.microsoft.com/archive/blogs/jenfieldmsft/build-your-own-external-authentication-provider-for-ad-fs-in-windows-server-2012-r2-walk-through-part-2</link>
      <pubDate>Mon, 24 Mar 2014 17:33:00 GMT</pubDate>
      <dc:creator><![CDATA[JenField_MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jenfieldmsft/2014/03/24/build-your-own-external-authentication-provider-for-ad-fs-in-windows-server-2012-r2-walk-through-part-2/</guid>
      <description><![CDATA[Update the adapter for successful authentication
In Part 1, we created a basic adapter...]]></description>
      <content:encoded><![CDATA[<h1><span style="font-size: small;">Update the adapter for successful authentication</span></h1>
<p>In <a href="https://blogs.msdn.com/b/jenfieldmsft/archive/2014/03/24/build-your-own-mfa-adapter-walk-through-for-ad-fs-in-windows-server-2012-r2.aspx">Part 1</a>, we created a basic adapter implementation and added it to an AD FS server. &nbsp;We can get the MFA forms page, but we cannot yet authenticated because we have not yet put the correct logic in our TryEndAuthentication implementation.&nbsp; So let&rsquo;s add that.&nbsp; Back to our code...</p>
<p>Recall our TryEndAuthentication implementation:</p>
<pre class="scroll"><code class="csharp"><span style="font-size: x-small;"><span style="color: #0000ff;">public</span> <span style="color: #008080;">IAdapterPresentation</span> TryEndAuthentication(<span style="color: #008080;">IAuthenticationContext</span> authContext, <span style="color: #008080;">IProofData</span> proofData, <span style="color: #008080;">HttpListenerRequest</span> request, <span style="color: #0000ff;">out</span> <span style="color: #008080;">Claim</span>[] outgoingClaims)</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small; color: #008000;"> //return new instance of IAdapterPresentationForm derived class</span><br /><span style="font-size: x-small;"> outgoingClaims = <span style="color: #0000ff;">new</span> <span style="color: #008080;">Claim</span>[0];</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> return new</span> <span style="color: #008080;">MyPresentationForm</span>();</span><br /> <br /><span style="font-size: x-small;"> }</span></code></pre>
<p>Let&rsquo;s update it so it doesn&rsquo;t always return MyPresentationForm().&nbsp; For this we&rsquo;ll create one simple utility method within our class:</p>
<pre class="scroll"><code class="csharp"><span style="font-size: x-small;"><span style="color: #0000ff;">static bool</span> ValidateProofData(<span style="color: #008080;">IProofData</span> proofData, <span style="color: #008080;">IAuthenticationContext</span> authContext)</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> if</span> (proofData == <span style="color: #0000ff;">null</span> || proofData.Properties == <span style="color: #0000ff;">null</span> || !proofData.Properties.ContainsKey("ChallengeQuestionAnswer"))</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> throw new</span> <span style="color: #008080;">ExternalAuthenticationException</span>("Error - no answer found", authContext);</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="font-size: x-small;"><span style="color: #0000ff;"> if</span> ((<span style="color: #0000ff;">string</span>)proofData.Properties["ChallengeQuestionAnswer"] == "adfabric")</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> return true</span>;</span><br /><span style="font-size: x-small;"> }</span><br /><span style="font-size: x-small; color: #0000ff;"> else</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> return false</span>;</span><br /><span style="font-size: x-small;"> }</span><br /><span style="font-size: x-small;"> }</span><br /></code></pre>
<p>Then, update TryEndAuthentication as below:</p>
<pre class="scroll"><code class="csharp"><span style="font-size: x-small;"><span style="color: #0000ff;">public</span> <span style="color: #008080;">IAdapterPresentation</span> TryEndAuthentication(<span style="color: #008080;">IAuthenticationContext</span> authContext, <span style="color: #008080;">IProofData</span> proofData, <span style="color: #008080;">HttpListenerRequest</span> request, <span style="color: #0000ff;">out</span> <span style="color: #008080;">Claim</span>[] outgoingClaims)</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> outgoingClaims = <span style="color: #0000ff;">new</span> <span style="color: #008080;">Claim</span>[0];</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> if</span> (ValidateProofData(proofData, authContext))</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small; color: #008000;"> //authn complete - return authn method</span><br /><span style="font-size: x-small;"> outgoingClaims = <span style="color: #0000ff;">new</span>[] </span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small; color: #008000;"> // Return the required authentication method claim, indicating the particulare authentication method used.</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> new</span> <span style="color: #008080;">Claim</span>( "https://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", </span><br /><span style="font-size: x-small;"> "https://example.com/myauthenticationmethod1" )</span><br /><span style="font-size: x-small;"> };</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> return null</span>;</span><br /><span style="font-size: x-small;"> }</span><br /><span style="font-size: x-small; color: #0000ff;"> else</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small; color: #008000;"> //authn not complete - return new instance of IAdapterPresentationForm derived class</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> return new</span> <span style="color: #008080;">MyPresentationForm</span>();</span><br /><span style="font-size: x-small;"> }</span><br /><span style="font-size: x-small;"> }</span><br /></code></pre>
<p>Now you will have to update the adapter on the test box.&nbsp; It is a little painful (i apologize for that) because you have to undo the AD FS policy, then un-register from AD FS and restart AD FS, then remove the dll from the GAC, then add the new dll to the GAC, then register it in AD FS, restart AD FS, and re-configure AD FS policy. &nbsp;I will walk you through it...</p>
<h1><span style="font-size: small;">Deploy and configure the updated adapter on your test AD FS machine</span></h1>
<h1><span style="font-size: small;">Clear AD FS Policy</span></h1>
<p>Clear all MFA related checkboxes in the MFA UI, shown below, then click OK.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/0523.mfa0.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/0523.mfa0.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/0523.mfa0.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/0523.mfa0.png" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<h1><span style="font-size: small;">Unregister provider (PowerShell)</span></h1>
<p>PS C:\&gt; Unregister-AdfsAuthenticationProvider &ndash;Name &ldquo;<em>YourAuthProviderName</em>&rdquo;</p>
<p>Example:</p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">PS C:\&gt; Unregister-AdfsAuthenticationProvider &ndash;Name &ldquo;MyMFAAdapter&rdquo;</span></p>
<ul>
<li>Note that the value you pass for &ldquo;Name&rdquo; is the same value as &ldquo;Name&rdquo; you provided to the Register-AdfsAuthenticationProvider cmdlet.&nbsp; It is also the &ldquo;Name&rdquo; property that is output from Get-AdfsAuthenticationProvider.</li>
<li>Note that before unregistering a provider, must remove the provider from the AdfsGlobalAuthenticationPolicy (either by clearing the checkboxes you checked in AD FS admin MMC snapin or by using PSH)</li>
<li>Note that the <strong>AD FS service must be restarted</strong> after this operation</li>
</ul>
<h1><span style="font-size: small;">Remove assembly from GAC (cmd line)</span></h1>
<p>To remove assembly from GAC</p>
<p>First, use the following command to find the fully qualified strong name of the entry:</p>
<p><span style="font-family: 'courier new', courier;">C:\&gt;.\gacutil.exe /l &lt;yourAdapterAssemblyName&gt;</span></p>
<p>Example:</p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">C:\&gt;.\gacutil.exe /l mfaadapter</span></p>
<p>Then, use the following command to remove it from the GAC:</p>
<p><span style="font-family: 'courier new', courier;">.\gacutil /u &ldquo;&lt;output from the above command&gt;&rdquo;</span></p>
<p>Example:</p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">C:\&gt;.\gacutil /u &ldquo;mfaadapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e675eb33c62805a0, processorArchitecture=MSIL&rdquo;</span></p>
<h1><span style="font-size: small;">Add the updated assembly to GAC (cmd line)</span></h1>
<p>Make sure you paste the updated dll locally first :)</p>
<p><span style="font-family: 'courier new', courier;">C:\&gt;.\gacutil.exe /if .\MFAAdapter.dll</span></p>
<h1><span style="font-size: small;">View assembly in the GAC (cmd line)</span></h1>
<p><span style="font-family: 'courier new', courier;">C:\&gt; .\gacutil.exe /l mfaadapter</span></p>
<p>&nbsp;</p>
<h1><span style="font-size: small;">Register your provider in AD FS</span></h1>
<p><span style="font-family: 'courier new', courier;">PS C:\&gt;$typeName = "MFAadapter.MyAdapter, MFAadapter, Version=1.0.0.1, Culture=neutral, PublicKeyToken=e675eb33c62805a0, processorArchitecture=MSIL&rdquo;</span></p>
<p><span style="font-family: 'courier new', courier;">PS C:\&gt;Register-AdfsAuthenticationProvider -TypeName $typeName -Name &ldquo;MyMFAAdapter1&rdquo;</span></p>
<p>Restart the AD FS service</p>
<h1><span style="font-size: small;">Create policy using the AD FS Management snapin</span></h1>
<p>1)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Open the AD FS Management Snapin (from Server Manager Tools menu)</p>
<p>2)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Click <strong>Authentication Policies</strong> at left</p>
<p>3)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; In the center pane, under <strong>Multi-Factor Authentication</strong>, click the blue <strong>Edit</strong> link to the right of <strong>Global Settings</strong>.</p>
<p>4)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Under <strong>Select additional authentication methods</strong> at the bottom of the page, check the box for your provider&rsquo;s AdminName. Click <strong>Apply</strong>.</p>
<p>5)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; To provide a &ldquo;trigger&rdquo; to invoke MFA using your adapter, under <strong>Locations</strong> check both &ldquo;<strong>Extranet</strong>&rdquo; and &ldquo;<strong>Intranet</strong>&rdquo;, for example. Click <strong>OK</strong>.</p>
<p>&nbsp;</p>
<h1><span style="font-size: small;">Authenticate with MFA using your adapter</span></h1>
<p>Finally, perform the steps below to test your adapter:</p>
<ul>
<li>Ensure the &nbsp;AD FS global Primary authentication type is configured as Forms Authentication for both Extranet and Intranet (this makes your demo easier to authenticate as a specific user)
<ul>
<li>In the AD FS snapin, under <strong>Authentication Policies</strong>, in the <strong>Primary Authentication</strong> area, click <strong>Edit</strong> next to <strong>Global Settings</strong>
<ul>
<li>Or just click the <strong>Primary</strong> tab from the <strong>Multi-factor policy</strong> UI</li>
</ul>
</li>
</ul>
</li>
<li>Ensure <strong>Forms Authentication</strong> is the only option checked for both the <strong>Extranet</strong> and the <strong>Intranet</strong> authentication method.&nbsp; Click <strong>OK</strong>.</li>
<li>Open the IDP initiated signon html page (https://&lt;fsname&gt;/adfs/ls/idpinitiatedsignon.htm) and sign in as a valid AD user in your test environment</li>
<li>Enter credentials for primary authentication</li>
<li>You should see the MFA forms page with example challenge text appear.&nbsp;
<ul>
<li>if you have more than one adapter configured, you will see the MFA choice page with your friendly name</li>
</ul>
</li>
</ul>
<p>You should see a successful signin when entering &ldquo;adfabric&rdquo; at the MFA authentication page.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/3583.signinMFA3.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/3583.signinMFA3.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/3583.signinMFA3.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/3583.signinMFA3.png" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/3438.signinMFA4.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/3438.signinMFA4.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/3438.signinMFA4.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/3438.signinMFA4.png" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<p>Also check out <a href="https://blogs.technet.com/b/cloudpfe/archive/2014/02/01/how-to-create-a-custom-authentication-provider-for-active-directory-federation-services-3-0-part-1.aspx">these excellent blogs</a> from my colleague at Microsoft.</p>]]></content:encoded>
    </item>
    <item>
      <title>Build your own external authentication provider for AD FS in Windows Server 2012 R2: Walk-through Part 1</title>
      <link>https://docs.microsoft.com/archive/blogs/jenfieldmsft/build-your-own-external-authentication-provider-for-ad-fs-in-windows-server-2012-r2-walk-through-part-1</link>
      <pubDate>Mon, 24 Mar 2014 15:35:00 GMT</pubDate>
      <dc:creator><![CDATA[JenField_MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jenfieldmsft/2014/03/24/build-your-own-external-authentication-provider-for-ad-fs-in-windows-server-2012-r2-walk-through-part-1/</guid>
      <description><![CDATA[Introduction
Welcome to the Build your own external authentication provider&nbsp;walk-through for...]]></description>
      <content:encoded><![CDATA[<h1><span style="font-size: small;">Introduction</span></h1>
<p>Welcome to the <em>Build your own external authentication provider</em>&nbsp;walk-through for AD FS in Windows Server 2012 R2!</p>
<p>This article provides a step by step walk through to get you started building your provider.&nbsp; The example we will build is&nbsp;<strong>for educational purposes only</strong>. &nbsp;It's the most minimal, bare bones implementation possible to expose the required elements of the model.&nbsp; There is no actual authentication back end, error processing, or configuration data. &nbsp;But it is enough to get you started, so let's begin!</p>
<h1><span style="font-size: small;">Setting up the development box</span></h1>
<p>This walk-through uses Visual Studio 2012. &nbsp;The project can be built using any development environment that can create a .NET class for Windows.</p>
<p>The project must target .NET 4.5 because the BeginAuthentication and TryEndAuthentication methods use the type System.Security.Claims.Claim, part of .NET Framework version 4.5.</p>
<p>There is one reference required for the project:</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="212">
<p>Reference dll</p>
</td>
<td valign="top" width="187">
<p>Where to find it</p>
</td>
<td valign="top" width="224">
<p>Required for</p>
</td>
</tr>
<tr>
<td valign="top" width="212">
<p>Microsoft.IdentityServer.Web.dll</p>
</td>
<td valign="top" width="187">
<p>The dll is located in %windir%\ADFS on a Windows Server 2012 R2 machine on which AD FS has been installed.</p>
<p>&nbsp;</p>
<p>This dll must be copied to the development machine and an explicit reference created in the project</p>
</td>
<td valign="top" width="224">
<p>Interface types including IAuthenticationContext, IProofData</p>
</td>
</tr>
</tbody>
</table>
<h1><span style="font-size: small;">Create the provider</span></h1>
<p>In Visual Studio 2012: Choose&nbsp;<strong>File</strong>-&gt;<strong>New</strong>-&gt;<strong>Project</strong>...</p>
<p>Select <strong>Class Library</strong> and be sure you are targeting <strong>.NET 4.5:</strong></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/0020.class1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/0020.class1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/0020.class1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/0020.class1.png" alt="" border="0" /></a></p>
<p>Make a copy <strong>Microsoft.IdentityServer.Web.dll</strong> from <strong>%windir%\ADFS</strong> on a Windows Server 2012 R2 machine on which AD FS has been installed and paste it in your Project folder on your development machine.</p>
<p>In <strong>Solution Explorer</strong>, right click <strong>References</strong> and <strong>Add Reference</strong>...</p>
<p>Browse to your local copy of <strong>Microsoft.IdentityServer.Web.dll</strong> and <strong>Add</strong>...</p>
<p>Click <strong>OK</strong> to confirm the new reference:</p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/0714.reference1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/0714.reference1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/0714.reference1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/0714.reference1.png" alt="" border="0" /></a></p>
<p>You should now be setup to resolve all of the types required for the provider.&nbsp;</p>
<p>Add a new class to your project (Right click your project, <strong>Add</strong>...<strong>Class</strong>...) and give it a name like <em>MyAdapter</em>, shown below:</p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/8255.addclass1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/8255.addclass1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/8255.addclass1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/8255.addclass1.png" alt="" border="0" /></a></p>
<p>In the new file MyAdapter.cs, replace the existing code with the following:</p>
<pre class="scroll"><code class="csharp"><span style="font-size: x-small;"><span style="color: #0000ff;"> using</span> System;</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">using</span> System.Collections.Generic;</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">using</span> System.Linq;</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">using</span> System.Text;</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">using</span> System.Threading.Tasks;</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">using</span> System.Globalization;</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">using</span> System.IO;</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">using</span> System.Net;</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">using</span> System.Xml.Serialization;</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">using</span> Microsoft.IdentityServer.Web.Authentication.External;</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">using</span> <span style="color: #008080;">Claim</span> = System.Security.Claims.<span style="color: #008080;">Claim</span>;</span><br /> <br /><span style="font-size: x-small;"> <span style="color: #0000ff;">namespace</span> MFAadapter</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">class</span> <span style="color: #008080;">MyAdapter</span> : <span style="color: #008080;">IAuthenticationAdapter</span></span><br /><span style="font-size: x-small;"> {</span><br /> <br /><span style="font-size: x-small;"> }</span><br /><span style="font-size: x-small;"> }</span><br /></code></pre>
<p>Now you should be able to F12 (right click &ndash; Go To Definition) on IAuthenticationAdapter to see the set of required interface members.&nbsp; Now we will do a simple implementation of these.</p>
<p>Replace the entire contents of your class with the below.</p>
<pre class="scroll"><span style="font-size: x-small;"><code class="cplusplus"><span style="color: #0000ff;">namespace</span> MFAadapter<br /> {<br /> <span style="color: #0000ff;">class</span> <span style="color: #008080;">MyAdapter</span> : <span style="color: #008080;">IAuthenticationAdapter</span><br /> {<br /> <span style="color: #0000ff;">public</span> <span style="color: #008080;">IAuthenticationAdapterMetadata</span> Metadata<br /> {<br /> <span style="color: #008000;">//get { return new &lt;instance of IAuthenticationAdapterMetadata derived class&gt;; }</span><br /> }<br /> <br /> <span style="color: #0000ff;">public</span> <span style="color: #008080;">IAdapterPresentation</span> BeginAuthentication(<span style="color: #008080;">Claim</span> identityClaim, <span style="color: #008080;">HttpListenerRequest</span> request, <span style="color: #008080;">IAuthenticationContext</span> authContext)<br /> {<br /> <span style="color: #008000;">//return new instance of IAdapterPresentationForm derived class</span><br /> <br /> }<br /> <br /> <span style="color: #0000ff;">public bool</span> IsAvailableForUser(<span style="color: #008080;">Claim</span> identityClaim, <span style="color: #008080;">IAuthenticationContext</span> authContext)<br /> {<br /> <span style="color: #0000ff;">return true</span>; <span style="color: #008000;">//its all available for now</span><br /> <br /> }<br /> <br /> <span style="color: #0000ff;">public void</span> OnAuthenticationPipelineLoad(<span style="color: #008080;">IAuthenticationMethodConfigData</span> configData)<br /> {<br /> <span style="color: #008000;">//this is where AD FS passes us the config data, if such data was supplied at registration of the adapter</span><br /> <br /> }<br /> <br /> <span style="color: #0000ff;">public void</span> OnAuthenticationPipelineUnload()<br /> {<br /> <br /> }<br /> <br /> <span style="color: #0000ff;">public</span> <span style="color: #008080;">IAdapterPresentation</span> OnError(<span style="color: #008080;">HttpListenerRequest</span> request, <span style="color: #008080;">ExternalAuthenticationException</span> ex)<br /> {<br /><span style="color: #008000;"> //return new instance of IAdapterPresentationForm derived class</span><br /> <br /> }<br /> <br /> <span style="color: #0000ff;">public</span> <span style="color: #008080;">IAdapterPresentation</span> TryEndAuthentication(<span style="color: #008080;">IAuthenticationContext</span> authContext, <span style="color: #008080;">IProofData</span> proofData, <span style="color: #008080;">HttpListenerRequest</span> request, <span style="color: #0000ff;">out</span> <span style="color: #008080;">Claim</span>[] outgoingClaims)<br /> {<br /> <span style="color: #008000;">//return new instance of IAdapterPresentationForm derived class</span><br /> <br /> }<br /> <br /> }<br /> }</code></span></pre>
<pre class="scroll">&nbsp;</pre>
<p>We&rsquo;re not ready to build yet...just two more interfaces to go :)<br /> Add two more classes to your project: one will be for the metadata, and the other for the presentation form.&nbsp; You can add these within the same file as the class above.</p>
<pre class="scroll"><code class="csharp"><span style="font-size: x-small;"><span style="color: #0000ff;"> class</span> <span style="color: #008080;">MyMetadata</span> : <span style="color: #008080;">IAuthenticationAdapterMetadata</span></span><br /><span style="font-size: x-small;"> {</span><br /> <br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="font-size: x-small;"> <span style="color: #0000ff;">class</span> <span style="color: #008080;">MyPresentationForm</span> : <span style="color: #008080;">IAdapterPresentationForm</span></span><br /><span style="font-size: x-small;"> {</span><br /> <br /><span style="font-size: x-small;"> }</span><br /> </code></pre>
<p>Now we will add the required members for each.</p>
<p>First, the metadata (with some hopefully helpful inline comments)</p>
<pre class="scroll"><code class="csharp"><span style="font-size: x-small;"><span style="color: #0000ff;">class</span> <span style="color: #008080;">MyMetadata</span> : <span style="color: #008080;">IAuthenticationAdapterMetadata</span></span><br /><span style="font-size: x-small;"> {</span><br /><span style="color: #008000; font-size: x-small;"> //Returns the name of the provider that will be shown in the AD FS management UI (not visible to end users)</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">public string</span> AdminName</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">get</span> { <span style="color: #0000ff;">return</span> "My Example MFA Adapter"; }</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="color: #008000; font-size: x-small;"> //Returns an array of strings containing URIs indicating the set of authentication methods implemented by the adapter </span><br /><span style="color: #008000; font-size: x-small;"> /// AD FS requires that, if authentication is successful, the method actually employed will be returned by the</span><br /><span style="color: #008000; font-size: x-small;"> /// final call to TryEndAuthentication(). If no authentication method is returnd, or the method returned is not</span><br /><span style="color: #008000; font-size: x-small;"> /// one of the methods listed in this property, the authentication attempt will fail.</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">public virtual string</span>[] AuthenticationMethods </span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">get</span> { <span style="color: #0000ff;">return new</span>[] { "https://example.com/myauthenticationmethod1", "https://example.com/myauthenticationmethod2" }; }</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="color: #008000; font-size: x-small;"> /// Returns an array indicating which languages are supported by the provider. AD FS uses this information</span><br /><span style="color: #008000; font-size: x-small;"> /// to determine the best language\locale to display to the user.</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">public int</span>[] AvailableLcids</span><br /><span style="font-size: x-small;"> {</span><br /><span style="color: #0000ff; font-size: x-small;"> get</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">return new</span>[] { <span style="color: #0000ff;">new</span> <span style="color: #008080;">CultureInfo</span>("en-us").LCID, <span style="color: #0000ff;">new</span> <span style="color: #008080;">CultureInfo</span>("fr").LCID};</span><br /><span style="font-size: x-small;"> }</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="color: #008000; font-size: x-small;"> /// Returns a Dictionary containg the set of localized friendy names of the provider, indexed by lcid. </span><br /><span style="color: #008000; font-size: x-small;"> /// These Friendly Names are displayed in the "choice page" offered to the user when there is more than </span><br /><span style="color: #008000; font-size: x-small;"> /// one secondary authentication provider available.</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">public</span> <span style="color: #008080;">Dictionary</span>&lt;<span style="color: #0000ff;">int</span>, <span style="color: #0000ff;">string</span>&gt; FriendlyNames</span><br /><span style="font-size: x-small;"> {</span><br /><span style="color: #0000ff; font-size: x-small;"> get</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> <span style="color: #008080;">Dictionary</span>&lt;<span style="color: #0000ff;">int</span>, <span style="color: #0000ff;">string</span>&gt; _friendlyNames = <span style="color: #0000ff;">new</span> <span style="color: #008080;">Dictionary</span>&lt;<span style="color: #0000ff;">int</span>, <span style="color: #0000ff;">string</span>&gt;();</span><br /><span style="font-size: x-small;"> _friendlyNames.Add(<span style="color: #0000ff;">new</span> <span style="color: #008080;">CultureInfo</span>("en-us").LCID, "Friendly name of My Example MFA Adapter for end users (en)");</span><br /><span style="font-size: x-small;"> _friendlyNames.Add(<span style="color: #0000ff;">new</span> <span style="color: #008080;">CultureInfo</span>("fr").LCID, "Friendly name translated to fr locale");</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">return</span> _friendlyNames;</span><br /><span style="font-size: x-small;"> }</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="color: #008000; font-size: x-small;"> /// Returns a Dictionary containing the set of localized descriptions (hover over help) of the provider, indexed by lcid. </span><br /><span style="color: #008000; font-size: x-small;"> /// These descriptions are displayed in the "choice page" offered to the user when there is more than one </span><br /><span style="color: #008000; font-size: x-small;"> /// secondary authentication provider available.</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">public</span> <span style="color: #008080;">Dictionary</span>&lt;<span style="color: #0000ff;">int</span>, <span style="color: #0000ff;">string</span>&gt; Descriptions</span><br /><span style="font-size: x-small;"> {</span><br /><span style="color: #0000ff; font-size: x-small;"> get </span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> <span style="color: #008080;">Dictionary</span>&lt;<span style="color: #0000ff;">int</span>, <span style="color: #0000ff;">string</span>&gt; _descriptions = <span style="color: #0000ff;">new</span> <span style="color: #008080;">Dictionary</span>&lt;<span style="color: #0000ff;">int</span>, <span style="color: #0000ff;">string</span>&gt;();</span><br /><span style="font-size: x-small;"> _descriptions.Add(<span style="color: #0000ff;">new</span> <span style="color: #008080;">CultureInfo</span>("en-us").LCID, "Description of My Example MFA Adapter for end users (en)");</span><br /><span style="font-size: x-small;"> _descriptions.Add(<span style="color: #0000ff;">new</span> <span style="color: #008080;">CultureInfo</span>("fr").LCID, "Description translated to fr locale");</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">return</span> _descriptions; </span><br /><span style="font-size: x-small;"> }</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="color: #008000; font-size: x-small;"> /// Returns an array indicating the type of claim that that the adapter uses to identify the user being authenticated.</span><br /><span style="color: #008000; font-size: x-small;"> /// Note that although the property is an array, only the first element is currently used.</span><br /><span style="color: #008000; font-size: x-small;"> /// MUST BE ONE OF THE FOLLOWING</span><br /><span style="color: #008000; font-size: x-small;"> /// "https://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"</span><br /><span style="color: #008000; font-size: x-small;"> /// "https://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"</span><br /><span style="color: #008000; font-size: x-small;"> /// "https://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"</span><br /><span style="color: #008000; font-size: x-small;"> /// "https://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid"</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">public string</span>[] IdentityClaims</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">get</span> { <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">new</span>[] { "https://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" }; }</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="color: #008000; font-size: x-small;"> //All external providers must return a value of "true" for this property.</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">public bool</span> RequiresIdentity</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">get</span> { <span style="color: #0000ff;">return true</span>; }</span><br /><span style="font-size: x-small;"> }</span><br /><span style="font-size: x-small;">}</span><br /><br /></code></pre>
<p>Next, the presentation form:</p>
<pre class="scroll"><code class="csharp"><span style="font-size: x-small;"><span style="color: #0000ff;"> class</span> <span style="color: #008080;">MyPresentationForm</span> : <span style="color: #008080;">IAdapterPresentationForm</span></span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small; color: #008000;"> /// Returns the HTML Form fragment that contains the adapter user interface. This data will be included in the web page that is presented</span><br /><span style="font-size: x-small; color: #008000;"> /// to the cient.</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> public</span> <span style="color: #0000ff;">string</span> GetFormHtml(<span style="color: #0000ff;">int</span> lcid)</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> string</span> htmlTemplate = Resources.FormPageHtml; <span style="color: #008000;">//todo we will implement this</span></span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> return</span> htmlTemplate;</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="font-size: x-small; color: #008000;"> /// Return any external resources, ie references to libraries etc., that should be included in </span><br /><span style="font-size: x-small; color: #008000;"> /// the HEAD section of the presentation form html. </span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> public string</span> GetFormPreRenderHtml(<span style="color: #0000ff;">int</span> lcid)</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> return null</span>;</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="font-size: x-small; color: #008000;"> //returns the title string for the web page which presents the HTML form content to the end user</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> public string</span> GetPageTitle(<span style="color: #0000ff;">int</span> lcid)</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"><span style="color: #0000ff;"> return</span> "MFA Adapter";</span><br /><span style="font-size: x-small;"> }</span><br /> <br /> <br /><span style="font-size: x-small;"> }</span><br /> </code></pre>
<p>Note the &lsquo;todo&rsquo; for the Resources.FormPageHtml element above.&nbsp; We will get to that, but first let's add the final required return statements, based on our newly implemented types, to our initial MyAdapter class.&nbsp; To do this, add the <span style="background-color: #ffff00;">yellow</span> highlighted items below to your existing IAuthenticationAdapter implementation:</p>
<pre class="scroll"><code class="csharp"><span style="font-size: x-small;">class MyAdapter : IAuthenticationAdapter</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> public IAuthenticationAdapterMetadata Metadata</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> //get { return new &lt;instance of IAuthenticationAdapterMetadata derived class&gt;; }</span><br /><span style="font-size: x-small; background-color: #ffff00;"><span style="color: #0000ff;"> get</span> { <span style="color: #0000ff;">return new</span> <span style="color: #008080;">MyMetadata</span>(); }</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="font-size: x-small;"> public IAdapterPresentation BeginAuthentication(Claim identityClaim, HttpListenerRequest request, IAuthenticationContext authContext)</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> //return new instance of IAdapterPresentationForm derived class</span><br /><span style="font-size: x-small; background-color: #ffff00;"><span style="color: #0000ff;"> return new</span> <span style="color: #008080;">MyPresentationForm</span>();</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="font-size: x-small;"> public bool IsAvailableForUser(Claim identityClaim, IAuthenticationContext authContext)</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> return true; //its all available for now</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="font-size: x-small;"> public void OnAuthenticationPipelineLoad(IAuthenticationMethodConfigData configData)</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> //this is where AD FS passes us the config data, if such data was supplied at registration of the adapter</span><br /> <br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="font-size: x-small;"> public void OnAuthenticationPipelineUnload()</span><br /><span style="font-size: x-small;"> {</span><br /> <br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="font-size: x-small;"> public IAdapterPresentation OnError(HttpListenerRequest request, ExternalAuthenticationException ex)</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> //return new instance of IAdapterPresentationForm derived class</span><br /><span style="font-size: x-small; background-color: #ffff00;"><span style="color: #0000ff;"> return new</span> <span style="color: #008080;">MyPresentationForm</span>();</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="font-size: x-small;"> public IAdapterPresentation TryEndAuthentication(IAuthenticationContext authContext, IProofData proofData, HttpListenerRequest request, out Claim[] outgoingClaims)</span><br /><span style="font-size: x-small;"> {</span><br /><span style="font-size: x-small;"> //return new instance of IAdapterPresentationForm derived class</span><br /><span style="font-size: x-small; background-color: #ffff00;"> outgoingClaims = <span style="color: #0000ff;">new</span> <span style="color: #008080;">Claim</span>[0];</span><br /><span style="font-size: x-small; background-color: #ffff00;"><span style="color: #0000ff;"> return new</span> <span style="color: #008080;">MyPresentationForm</span>();</span><br /><span style="font-size: x-small;"> }</span><br /> <br /><span style="font-size: x-small;"> }</span><br /><br /></code></pre>
<p>Now for the resource file containing the html fragment.&nbsp;</p>
<p>Create a new text file in your project folder with the following contents:</p>
<pre class="scroll"><code class="html">&lt;div id="loginArea"&gt;<br /> &lt;form method="post" id="loginForm" &gt;<br /> &lt;!-- These inputs are required by the presentation framework. Do not modify or remove --&gt;<br /> &lt;input id="authMethod" type="hidden" name="AuthMethod" value="%AuthMethod%"/&gt;<br /> &lt;input id="context" type="hidden" name="Context" value="%Context%"/&gt;<br /> &lt;!-- End inputs are required by the presentation framework. --&gt;<br /> &lt;p id="pageIntroductionText"&gt;This content is provided by the MFA sample adapter. Challenge inputs should be presented below.&lt;/p&gt;<br /> &lt;label for="challengeQuestionInput" class="block"&gt;Question text&lt;/label&gt;<br /> &lt;input id="challengeQuestionInput" name="ChallengeQuestionAnswer" type="text" value="" class="text" placeholder="Answer placeholder" /&gt;<br /> &lt;div id="submissionArea" class="submitMargin"&gt;<br /> &lt;input id="submitButton" type="submit" name="Submit" value="Submit" onclick="return AuthPage.submitAnswer()"/&gt;<br /> &lt;/div&gt;<br /> &lt;/form&gt;<br /> &lt;div id="intro" class="groupMargin"&gt;<br /> &lt;p id="supportEmail"&gt;Support information&lt;/p&gt;<br /> &lt;/div&gt;<br /> &lt;script type="text/javascript" language="JavaScript"&gt;<br /> //&lt;![CDATA[<br /> function AuthPage() { }<br /> AuthPage.submitAnswer = function () { return true; };<br /> //]]&gt;<br /> &lt;/script&gt;&lt;/div&gt;</code></pre>
<p>Then, select <strong>Project</strong>-&gt;<strong>Add Component</strong>... <strong>Resources file</strong> and name the file <strong>Resources </strong>and click <strong>Add</strong>:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/2047.resource1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/2047.resource1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/2047.resource1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/2047.resource1.png" alt="" border="0" /></a></p>
<p>Then, within the <strong>Resources.resx</strong> file, choose <strong>Add Resource</strong>...<strong>Add existing file</strong>.&nbsp; Navigate to the text file (containing the html fragment) that you saved above.&nbsp;&nbsp;&nbsp;</p>
<p>&nbsp;</p>
<p>Ensure your GetFormHtml code resolves the name of the new resource correctly by the resources file (.resx file) name prefix followed by the name of the resource itself:</p>
<pre class="scroll"><code class="csharp"><span style="font-size: x-small;"><span style="color: #0000ff;">public string</span> GetFormHtml(<span style="color: #0000ff;">int</span> lcid)</span><br /><span style="font-size: x-small;">{</span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">string</span> htmlTemplate = <span style="color: #008080;">Resources</span>.MfaFormHtml; <span style="color: #008000;">//Resxfilename.resourcename</span></span><br /><span style="font-size: x-small;"> <span style="color: #0000ff;">return</span> htmlTemplate;</span><br /><span style="font-size: x-small;">}</span><br /> </code></pre>
<p>You should now be able to build.&nbsp;</p>
<h1><span style="font-size: small;">Build the adapter</span></h1>
<p>The adapter should be built into a strongly named .NET assembly that can be installed into the GAC in Windows.&nbsp; To achieve this in a Visual Studio project:</p>
<ol>
<li>Right click your project name in Solution Explorer and click <strong>Properties</strong></li>
<li>On the <strong>Signing</strong> tab, check <strong>Sign the assembly</strong> and choose <strong>&lt;New...&gt;</strong> under <strong>Choose a strong name key file:</strong>&nbsp; Enter a key file name and password and click <strong>OK</strong>.&nbsp; Then ensure <strong>Sign the assembly</strong> is checked and <strong>Delay sign only</strong> is unchecked.&nbsp; The properties <strong>Signing</strong> page should look like the below:</li>
</ol>
<pre class="scroll"><code class="html"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/7801.sign1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/7801.sign1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/7801.sign1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/7801.sign1.png" alt="" border="0" /></a><br /></code></pre>
<p>Then build the solution.</p>
<h1><span style="font-size: small;">Deploy the adapter to your AD FS test machine</span></h1>
<p>Before an external provider will be invoked by AD FS, it must be registered in the system.&nbsp; Adapter providers MUST provide an installer which performs the necessary installation actions including installation in the GAC, and the installer SHOULD support registration in AD FS.&nbsp; If that is not done, the administrator will need to execute the PowerShell steps below.&nbsp; These steps can be used in the lab to enable testing and debugging.</p>
<h1><span style="font-size: small;">Prepare the test AD FS machine</span></h1>
<p>You&rsquo;ll need to perform the following steps to get your test box ready</p>
<h1><span style="font-size: small;">Copy files and add to GAC</span></h1>
<p>1)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ensure you have a Windows Server 2012 R2 machine or virtual machine</p>
<p>2)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Install the AD FS role service and configure a farm with at least one node.</p>
<p style="padding-left: 30px;">For detailed steps to setup a federation server in a lab environment, see the guidance on <a href="https://technet.microsoft.com/en-us/library/dn486820.aspx">Technet</a>.</p>
<p>3)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Copy the Gacutil.exe tools to the server</p>
<p style="padding-left: 30px;">Gacutil.exe can be found in <strong>%homedrive%\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools</strong>\ on a Windows 8 machine.&nbsp; You will need the <strong>gacutil.exe</strong> file itself as well as the <strong>1033</strong> and <strong>en-US</strong> other localized resource folder below the NETFX 4.0 Tools location</p>
<p>4)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Copy your provider file(s) (one or more strong name signed dll files) to the same folder location as gacutil (the location is just for convenience)</p>
<p>5)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Add your dll file(s) to the GAC on each AD FS federation server in the farm:</p>
<p style="padding-left: 30px;">Example: using command line tool GACutil.exe to add a dll to the GAC:&nbsp;</p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">C:\&gt;.\gacutil.exe /if .\&lt;yourdllname&gt;.dll</span></p>
<p style="padding-left: 30px;">To view the resulting entry in the GAC:</p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">C:\&gt;.\gacutil.exe /l &lt;yourassemblyname&gt;</span></p>
<h1><span style="font-size: small;">Register your provider in AD FS</span></h1>
<p>Once the above pre-requisites are met, open a PowerShell command window on your federation server and enter the following commands (note that if you are using federation server farm that uses Windows Internal Database, you must execute these commands on the primary federation server of the farm):</p>
<p>1) &nbsp; &nbsp; &nbsp;Register-AdfsAuthenticationProvider &ndash;TypeName <em>YourTypeName</em> &ndash;Name &ldquo;<em>AnyNameYouWish&rdquo;</em> [&ndash;ConfigurationFilePath (optional)]</p>
<p style="padding-left: 30px;">Where&nbsp;<em>YourTypeName</em> is your .NET strong type name: "YourDefaultNamespace.YourIAuthenticationAdapterImplementationClassName, YourAssemblyName, Version=YourAssemblyVersion, Culture=neutral, PublicKeyToken=YourPublicKeyTokenValue, processorArchitecture=MSIL"</p>
<p style="padding-left: 30px;">This will register your external provider in AD FS, with the Name you provided as <em>AnyNameYouWish</em> above</p>
<p>2)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Restart the AD FS service (using the Windows Services snapin for example)</p>
<p>3)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Get-AdfsAuthenticationProvider</p>
<p style="padding-left: 30px;">This shows your provider as one of the providers in the system</p>
<p>Example powershell command line:</p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">PS C:\&gt;$typeName = "MFAadapter.MyAdapter, MFAadapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e675eb33c62805a0, processorArchitecture=MSIL&rdquo;</span></p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">PS C:\&gt;Register-AdfsAuthenticationProvider -TypeName $typeName -Name &ldquo;MyMFAAdapter&rdquo;</span></p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">PS C:\&gt;net stop adfssrv</span></p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">PS C:\&gt;net start adfssrv</span></p>
<p style="padding-left: 30px;">If you have the device registration service enabled in your AD FS environment, also execute the following:&nbsp;</p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">PS C:\&gt;net start drs</span></p>
<p>To verify the registered provider, use the command below:</p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">PS C:\&gt;Get-AdfsAuthenticationProvider</span></p>
<p>This shows your provider as one of the providers in the system</p>
<h1><span style="font-size: small;">Create AD FS policy that invokes your adapter</span></h1>
<p><strong>Create policy using the AD FS Management snapin</strong></p>
<p>1)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Open the AD FS Management Snapin (from Server Manager Tools menu)</p>
<p>2)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Click <strong>Authentication Policies</strong> at left</p>
<p>3)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; In the center pane, under <strong>Multi-Factor Authentication</strong>, click the blue <strong>Edit</strong> link to the right of <strong>Global Settings</strong>.</p>
<p>4)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Under <strong>Select additional authentication methods</strong> at the bottom of the page, check the box for your provider&rsquo;s AdminName. Click <strong>Apply</strong>.</p>
<p>5)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; To provide a &ldquo;trigger&rdquo; to invoke MFA using your adapter, under <strong>Locations</strong> check both &ldquo;<strong>Extranet</strong>&rdquo; and &ldquo;<strong>Intranet</strong>&rdquo;, for example. Click <strong>OK</strong>. (To configure triggers per relying party, see Create policy using PowerShell below.)</p>
<p>6)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Check the results using PSH</p>
<p style="padding-left: 30px;">First use Get-AdfsGlobalAuthenticationPolicy. You should see your provider <strong>Name</strong> as one of the <strong>AdditionalAuthenticationProvider</strong> values</p>
<p style="padding-left: 30px;">Then use Get-AdfsAdditionalAuthenticationRule. You should see the rules for Extranet and Intranet configured as a result of your policy selection in the admin UI</p>
<p><strong>Create policy using PowerShell</strong></p>
<p>To configure MFA policy using PowerShell, use the following steps:</p>
<p>First, enable the provider in global policy:</p>
<p style="padding-left: 30px;">PS C:\&gt;Set-AdfsGlobalAuthenticationPolicy -AdditionalAuthenticationProvider &ldquo;<em>YourAuthProviderName&rdquo;</em></p>
<p style="padding-left: 30px;">Note that the value provided for the AdditionalAuthenticationProvider parameter corresponds to the value you provided for the &ldquo;Name&rdquo; parameter in the Register-AdfsAuthenticationProvider cmdlet above and to the &ldquo;Name&rdquo; property from Get-AdfsAuthenticationProvider cmdlet output.&nbsp;</p>
<p>Example powershell command to enable provider:</p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">PS C:\&gt;Set-AdfsGlobalAuthenticationPolicy &ndash;AdditionalAuthenticationProvider &ldquo;MyMFAAdapter&rdquo;</span></p>
<p>&nbsp;</p>
<p>Next, configure global or relying party specific rules to trigger MFA:</p>
<p style="padding-left: 30px;">Example 1: Powershell command to create global rule to require MFA for External requests:</p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">PS C:\&gt;Set-AdfsAdditionalAuthenticationRule &ndash;AdditionalAuthenticationRules 'c:[type == "https://schemas.microsoft.com/ws/2012/01/insidecorporatenetwork", value == "false"] =&gt; issue(type = "https://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", value = "https://schemas.microsoft.com/claims/multipleauthn" );'</span></p>
<p style="padding-left: 30px;">Example 2: Powershell command to create MFA rules to require MFA for external requests to a specific relying party.&nbsp; (Note that individual providers cannot be connected to individual relying parties in AD FS in Windows Server 2012 R2).</p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">PS C:\&gt;$rp = Get-AdfsRelyingPartyTrust &ndash;Name &lt;Relying Party Name&gt;</span></p>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">PS C:\&gt;Set-AdfsRelyingPartyTrust &ndash;TargetRelyingParty $rp &ndash;AdditionalAuthenticationRules 'c:[type == "https://schemas.microsoft.com/ws/2012/01/insidecorporatenetwork", value == "false"] =&gt; issue(type = "https://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", value = "https://schemas.microsoft.com/claims/multipleauthn" );'</span></p>
<p style="padding-left: 30px;">&nbsp;</p>
<h1><span style="font-size: small;">Authenticate with MFA using your adapter</span></h1>
<p>Finally, perform the steps below to test your adapter:</p>
<ul>
<li>Ensure the &nbsp;AD FS global Primary authentication type is configured as Forms Authentication for both Extranet and Intranet (this makes your demo easier to authenticate as a specific user)
<ul>
<li>In the AD FS snapin, under <strong>Authentication Policies</strong>, in the <strong>Primary Authentication</strong> area, click <strong>Edit</strong> next to <strong>Global Settings</strong>
<ul>
<li>Or just click the <strong>Primary</strong> tab from the <strong>Multi-factor policy</strong> UI</li>
</ul>
</li>
</ul>
</li>
<li>Ensure <strong>Forms Authentication</strong> is the only option checked for both the <strong>Extranet</strong> and the <strong>Intranet</strong> authentication method.&nbsp; Click <strong>OK</strong>.</li>
<li>Open the IDP initiated signon html page (https://&lt;fsname&gt;/adfs/ls/idpinitiatedsignon.htm) and sign in as a valid AD user in your test environment</li>
<li>Enter credentials for primary authentication</li>
<li>You should see the MFA forms page with example challenge questions appear.&nbsp;
<ul>
<li>if you have more than one adapter configured, you will see the MFA choice page with your friendly name from above</li>
</ul>
</li>
</ul>
<p><span style="font-family: 'courier new', courier;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/2350.signinMFA1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/2350.signinMFA1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/2350.signinMFA1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/2350.signinMFA1.png" alt="" border="0" /></a></span></p>
<p>&nbsp;</p>
<p><span style="font-family: 'courier new', courier;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/1643.signinMFA2.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/1643.signinMFA2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/1643.signinMFA2.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/1643.signinMFA2.png" alt="" border="0" /></a></span></p>
<p>&nbsp;</p>
<p>You now have a working implementation of the interface (though granted it does not do much yet!), but you can at least see how the model works. For example, try setting break points in the BeginAuthentication as well as the TryEndAuthentication.&nbsp; Notice how BeginAuthentication is executed when the user first enters the MFA form, whereas TryEndAuthentication is triggered at each Submit of the form.</p>
<p>But wait &ndash; our example adapter will never successfully authenticate!&nbsp; This is because nothing in our code returns null for TryEndAuthentication.&nbsp; <a href="https://blogs.msdn.com/b/jenfieldmsft/archive/2014/03/24/build-your-own-mfa-adapter-for-ad-fs-in-windows-server-2012-r2-walk-through-part-2.aspx">So let&rsquo;s add that in part 2...</a></p>]]></content:encoded>
    </item>
    <item>
      <title>External authentication providers in AD FS in Windows Server 2012 R2: Overview</title>
      <link>https://docs.microsoft.com/archive/blogs/jenfieldmsft/external-authentication-providers-in-ad-fs-in-windows-server-2012-r2-overview</link>
      <pubDate>Mon, 24 Mar 2014 15:19:00 GMT</pubDate>
      <dc:creator><![CDATA[JenField_MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jenfieldmsft/2014/03/24/external-authentication-providers-in-ad-fs-in-windows-server-2012-r2-overview/</guid>
      <description><![CDATA[Introduction
Welcome to the external authentication providers overview&nbsp;for AD FS in Windows...]]></description>
      <content:encoded><![CDATA[<h1><span style="font-size: small;">Introduction</span></h1>
<p>Welcome to the external authentication providers overview&nbsp;for AD FS in Windows Server 2012 R2.</p>
<p>This article provides you with the high level information, adapter requirements, and interface and method specs to help you understand the model and get you started toward building an adapter. &nbsp;</p>
<p><strong>For those of you interested in getting directly to the walk-through, go directly <a href="https://blogs.msdn.com/b/jenfieldmsft/archive/2014/03/24/build-your-own-mfa-adapter-walk-through-for-ad-fs-in-windows-server-2012-r2.aspx">here</a></strong><strong>. &nbsp;</strong>For more conceptual information, read on.</p>
<h1><span style="font-size: small;">Multi Factor Authentication as part of Conditional Access policies</span></h1>
<p>Multi factor authentication is one of the key elements of conditional access policies in AD FS in Windows Server 2012 R2.&nbsp; Multi factor authentication has traditionally meant using a Smart Card or other second factor with AD based authentication such as Windows Integrated Authentication.&nbsp; This type of MFA can impose client side requirements such as smart card drivers, USB ports or other client hardware or software that cannot always be expected with BYOD client devices.&nbsp; Because of this, AD FS in Windows Server 2012 R2 introduced a new<em> pluggable authentication provider</em> concept focused on flexibility, integration with AD FS policy, and consistent user experience.</p>
<h1><span style="font-size: small;">Primary and Secondary Authentication</span></h1>
<p>Previous versions of AD FS have supported authenticating users against Active Directory using any of the following methods:</p>
<ul>
<li>Windows integrated authentication</li>
<li>Username and password</li>
<li>Client certificate (client TLS, including Smart Card authentication)</li>
</ul>
<p>The above methods are still supported in Windows Server 2012 R2, but are now called &ldquo;primary authentication&rdquo; because we have introduced a new feature called secondary or &ldquo;additional&rdquo; authentication.&nbsp; This is where &nbsp;external authentication providers can plug in.</p>
<p>Secondary authentication occurs immediately after primary authentication and authenticates the same AD user.&nbsp; Once primary authentication is complete and successful, AD FS invokes the external authentication handler.&nbsp; This handler invokes additional authentication providers, either the in-box AD FS provider for certificate authentication or external MFA providers configured on the system, based on protocol inputs and policy.&nbsp; AD FS passes the primary authenticated user&rsquo;s identity to the additional authentication provider, which performs the authentication and hands the result back.&nbsp; At this point, AD FS continues executing the authentication/authorization policy and issues the token accordingly.</p>
<p>Secondary authentication is performed by two key methods of the adapter: BeginAuthentication and TryEndAuthentication.&nbsp; AD FS calls these methods as part of the authentication process, as shown in the diagrams below (click the individual images for higher resolution).</p>
<p>1) Primary authentication works as it always has:</p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/5657.authnflow1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/5657.authnflow1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/5657.authnflow1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/5657.authnflow1.png" alt="" border="0" /></a></p>
<p>2) Secondary authentication is triggered and BeginAuthentication provides initial form to user:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/3515.authnflow2.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/3515.authnflow2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/3515.authnflow2.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/3515.authnflow2.png" alt="" border="0" /></a></p>
<p>3) Form post back from client initiates TryEndAuthentication flow</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/1321.authnflow3.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/1321.authnflow3.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/1321.authnflow3.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/1321.authnflow3.png" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<h1><span style="font-size: small;">Requirements for External Adapters</span></h1>
<p>This section describes some of the key aspects of the implementation that are important for the adapter developer to understand.</p>
<h1><span style="font-size: small;">Adapter Requirements</span></h1>
<p>The adapter must implement the interfaces listed below (which you can see in more detail in the <a href="https://blogs.msdn.com/b/jenfieldmsft/archive/2014/03/24/build-your-own-mfa-adapter-walk-through-for-ad-fs-in-windows-server-2012-r2.aspx">walk-through</a>).&nbsp;</p>
<p>&nbsp;</p>
<ul>
<li><strong>IAuthenticationAdapter</strong>: top level adapter that contains the key authentication methods</li>
<li><strong>IAuthenticationAdapterMetadata</strong>: defines adapter metadata including its name and the type(s) of authentication it supports</li>
<li><strong>IAdapterPresentationForm&nbsp;</strong>(derived from <strong>IAdapterPresentation</strong>): creates the form html for the web interface</li>
</ul>
<p>&nbsp;</p>
<p>Implementation of the above interfaces will in turn require that you reference and use the following interface types.</p>
<ul>
<li><strong>IProofData</strong>: carries the user-provided proof data, such as answers to challenge questions, one time password, or PIN from MFA provider.</li>
<li><strong>IAuthenticationContext</strong>: carries authentication context data across multiple round-trips to the user</li>
</ul>
<p>In addition to the above, you must construct, at minimum, an html fragment for the web user interface that includes the required hidden elements documented in the&nbsp;<a href="https://blogs.msdn.com/b/jenfieldmsft/archive/2014/03/24/build-your-own-mfa-adapter-walk-through-for-ad-fs-in-windows-server-2012-r2.aspx">walk-through</a>.</p>
<p>&nbsp;</p>
<h1><span style="font-size: small;">Adapter Metadata</span></h1>
<p>Metadata is the means by which an external authentication provider tells AD FS of its capabilities.&nbsp; Metadata is read by AD FS at the time the adapter is registered.</p>
<p>Adapter metadata contains several elements which developers must be sure to select carefully:</p>
<p><strong><span style="font-size: small;">AuthenticationMethods[]</span></strong></p>
<p>This metadata member is an array of URI strings that indicates the authentication types offered by the external provider.&nbsp; Multiple types can be defined, and at least one type from this list must be returned by the adapter to AD FS upon successful authentication.</p>
<p><strong><span style="font-size: small;">AdminName</span></strong></p>
<p>This single string is the name of the authentication provider, used by AD FS in the administrative UI shown below.&nbsp; This name is not customizable by the administrator. &nbsp;Note that this string describes the provider itself, not an individual authentication method as the provider can support multiple specific authentication methods.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/5811.mfa2.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/5811.mfa2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/5811.mfa2.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/5811.mfa2.png" alt="" border="0" /></a></p>
<p><strong><span style="font-size: small;">FriendlyNames</span></strong></p>
<p>A dictionary, indexed by LCID, of friendly names of the authentication provider, for use in the "method choice&rdquo; page, shown below.&nbsp; This text must be specified by the adapter to refer to their provider in a friendly way that is consumable by the end user.&nbsp; The adapter should provide a description for each locale supported (specified in the <strong>AvailableLcids</strong>&nbsp;metadata member).&nbsp; The AD FS framework will decide on the correct LCID, based on the locale of the client.</p>
<h3><a style="font-size: 12px;" href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/3426.friendlynames1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/3426.friendlynames1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/25/3426.friendlynames1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-25/3426.friendlynames1.png" alt="" border="0" /></a></h3>
<p><strong><span style="font-size: small;">Descriptions</span></strong></p>
<p>A list of localized descriptions of the authentication method, indexed by LCID.&nbsp; These strings are not currently used in the AD FS UI, but they are visible to the administrator via PowerShell.&nbsp; The adapter should provide a description for each lcid specified in the&nbsp;<strong>AvailableLcids</strong>&nbsp;metadata member.</p>
<h1><span style="font-size: small;">Authentication itself</span></h1>
<p>The adapter performs authentication by implementing two key methods: <strong>BeginAuthentication</strong> and <strong>TryEndAuthentication</strong>.&nbsp; AD FS calls these methods as part of the authentication process, as shown in the diagrams&nbsp;above.</p>
<p>Upon successful authentication via <strong>TryEndAuthentication</strong>, the provider must return one claim with claim type <strong>https://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod</strong> that contains as its value the type of authentication performed.&nbsp; This method must be one of the AuthenticationMethods[] declared via <strong>IAuthenticationAdapterMetadata</strong>.</p>
<p><strong><span style="font-size: small;">Web user interface</span></strong></p>
<p>The adapter provides html presentation information to AD FS via the IAdapterPresentationForm interface. This contains as one of its members a string of html that AD FS will include in the user-facing authentication pages.</p>
<p><strong><span style="font-size: small;">Required form elements</span></strong></p>
<p>There are two hidden form elements AD FS requires external providers to include within the required html string.&nbsp; These are shown below:</p>
<p><span style="font-family: 'courier new', courier;">&lt;input id="authMethod" type="hidden" name="AuthMethod" value="%AuthMethod%"/&gt;</span></p>
<p><span style="font-family: 'courier new', courier;">&lt;input id="context" type="hidden" name="Context" value="%Context%"/&gt;</span></p>
<h1><span style="font-size: small;">Invoking additional authentication</span></h1>
<p>There are two ways to configure AD FS in Windows Server 2012 R2 to invoke multi factor authentication: policy configuration or via the protocol token request.</p>
<p><strong>Via policy</strong></p>
<p>AD FS in Windows Server 2012 R2 introduces a new rule set called &ldquo;additional authentication rules&rdquo; that are used for triggering additional (including external) authentication providers. As with many other settings in AD FS, you can set these rules at a global level or at the relying party trust level.</p>
<p>As part of the new rule set, AD FS introduces a new claim type and value to refer to "multi factor" (primary plus additional) authentication.&nbsp; When this claim type and value is generated via an additional authentication rule, AD FS will invoke the external authentication handler, and hence the provider(s) configured on the system. If more than one provider is enabled in AD FS, the user will see a method choice page that presents the friendly name of each provider and allows the user to select one by clicking on it.</p>
<h1><span style="font-size: small;">Via protocol</span></h1>
<p>Relying parties can cause AD FS to invoke additional authentication by sending the special &ldquo;MFA claim&rdquo; value via protocol parameters within the WS-Federation or SAML protocols.</p>
<p><strong>WS Federation request parameter</strong></p>
<p>Use the following request protocol parameter and value for WS-Federation requests:</p>
<p>wauth=https://schemas.microsoft.com/claims/multipleauthn</p>
<p><strong>SAML Protocol request parameter</strong></p>
<p>Use the following request protocol element for SAML 2.0 requests:</p>
<p>samlp:AuthnContextClassRef with value https://schemas.microsoft.com/claims/multipleauthn</p>
<p><strong>Claims issued by AD FS</strong></p>
<p>In either of the above cases, AD FS issues the a special "MFA claim" to assert that MFA was done:</p>
<p>Claim type: https://schemas.microsoft.com/claims/authnmethodsreferences</p>
<p>Value: https://schemas.microsoft.com/claims/multipleauthn</p>
<p>Note: AD FS issues an additional claim of type https://schemas.microsoft.com/claims/authnmethodsreferences for each individual authentication type performed, both primary and additional.</p>
<h1><span style="font-size: small;">Next steps</span></h1>
<p>Now that you know some of the mechanics, you can get started building your provider using my step-by-step walk through <a href="https://blogs.msdn.com/b/jenfieldmsft/archive/2014/03/24/build-your-own-mfa-adapter-walk-through-for-ad-fs-in-windows-server-2012-r2.aspx">here</a>.</p>
<p>Also visit my colleague Ramiro's <a href="https://blogs.msdn.com/b/ramical/archive/2014/01/30/under-the-hood-tour-on-multi-factor-authentication-in-ad-fs-part-1-policy.aspx">blog</a>&nbsp;for a deep dive on AD FS multi-factor authentication policy.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>Welcome</title>
      <link>https://docs.microsoft.com/archive/blogs/jenfieldmsft/welcome</link>
      <pubDate>Mon, 24 Mar 2014 14:07:00 GMT</pubDate>
      <dc:creator><![CDATA[JenField_MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jenfieldmsft/2014/03/24/welcome/</guid>
      <description><![CDATA[Welcome to my MSDN blog!]]></description>
      <content:encoded><![CDATA[<p>Welcome to my MSDN blog!</p>]]></content:encoded>
    </item>
  </channel>
</rss>