Authenticate an Azure AD user with SAML for ASP.NET Core

The other day I needed a test application to try something with SAML support in Azure Active Directory. I started looking how to configure an ASP.NET Core webapplication to support SAML. It’s very easy to set it up for OIDC authentication but I found out ASP.Net (core) doesn’t support SAML out of the box. Google to the rescue and ignoring the blogpost from my colleague Christos (he’s wrong, it’s WS-Fed not SAML he’s using in his blogpost) , I found a few 3rd parties who build support for ASP.NET (core) to add SAML.

I didn’t do any comparison, I just picked the first one I could find which supports ASP.NET Core middleware and went with that one. In this case I picked the library from Systainsys.

These are the steps I did to make my app work. I used a simple ASP.Net core website and added the Systainsys,SAML2.AspNetCore2 package to my project.

  1. Goto https://portal.azure.com and go to Azure Active Directory
  2. Click on Enterprise applications and click on +New Application
  3. Click on Non-gallery application
  4. Give your app a name (in my case SAMLBlogpost), click Add
  5. Click op 2. Set up single sign on

image

  1. Select SAML
  2. Enter en Identifier (Entity ID). This needs to be unique for your Azure AD tenant. I choose https://hoekstra.dev/SAMLBlogPost. It doesn’t need to be URI.
  3. Enter the reply URI (Assertion Consumer Service URL). In my case https://localhost:44300/Saml2/Acs this is the URI which will receive the response from AAD after a successful login. The result will look something like this:

image

  1. Copy the information from 3 (App Federation Metadata URL). Make sure you have the entire part. In my case it’s: https://login.microsoftonline.com/63eb1bcb-f74f-4703-8243-6f73d78ebf52/federationmetadata/2007-06/federationmetadata.xml?appid=21df91a5-a3b0-4c02-be57-8ce4b34b5da4

This URI contains important information like the public key used to sign the assertions. You can open it in a browser to see what it returns.

  1. Copy the Azure AD Identifier from section 4

Now you have all the information you need to setup your code. This is the code in my startup.cs in the ConfigureService method

services.AddAuthentication(sharedOptions =>
{
  sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
  sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
  sharedOptions.DefaultChallengeScheme = "Saml2";
})
.AddSaml2(options =>
{
  options.SPOptions.EntityId = new EntityId("https://localhost:44342/Saml2");
  options.IdentityProviders.Add(
    new IdentityProvider(
      new EntityId("https://sts.windows.net/63eb1bcb-f74f-4703-8243-6f73d78ebf52/"), options.SPOptions)
      {
        MetadataLocation = "https://login.microsoftonline.com/63eb1bcb-f74f-4703-8243-6f73d78ebf52/federationmetadata/2007-06/federationmetadata.xml?appid=9fd05134-d507-479b-a432-580541125356"
      });
  })
.AddCookie();

The SPOptions.EntityId is the first value you specified when creating the application. It’s similar to the appid or clientid you use with OIDC. The IdentityProvider you create uses the Azure AD Identifier value and the Metadatalocation is the App Federation Metadata Url.

One last step I always forget, if you test the application it will fail to log you in since you didn’t assign a user/group to the application yet. Do this first and test the sign-in if it works. Run the ASP.Net Core app and you should be good to go.

Next step, trying to get access tokens for MS Graph,