Authenticating an ASP.NET Core web app using Azure AD - Part 1

Overview

I am in the midst of designing security of a web application hosted on Microsoft Azure. I have been exploring modern authentication and understanding OAuth, OpenID Connect, JWT etc. for sometime and thought doing some hands on demo with authenticating various application types with Azure AD. The first scenario I am describing is a web browser connecting to a ASP.NET Core MVC web application secured by Azure AD.

I am updating this post on 17/04/2017 with Visual Studio 2017 and new Azure portal

The steps are

  • Create a ASP.NET Core MVC web app
  • Configure for securing using Azure AD
  • Register the app with Azure AD
  • Open the app in browser and analyse traffic using Fiddler

There is a prerequisite that you have an Azure subscription in which you have created a directory and a test user account. In my case I am using my MSDN Azure subscription in which I have created a directory named ADSample101 and in which I have added an user named testuser@ADSample101.onmicrosoft.com.

Creating the web app

Start Visual Studio 2017.

Start with creating a new ASP.NET Core web application as shown below.

Create a new ASP.NET Core web application

In the next Step make sure that Authentication is set to 'No Authentication'. This is because instead of using the tooling I want to add authentication in code from scratch. Also untick the 'Host in Cloud' option.

Web app settings

At this point I remove all references and use of AppInisghts as it pollutes the traffic with telemetry collection. I also disabled browser link for same reason as it opens a web socket.
Disable BrowserLink

Open NuGet Package Manager and add the following two packages in dependencies

Microsoft.AspNetCore.Authentication.Cookies  
Microsoft.AspNetCore.Authentication.OpenIdConnect  

NuGet Packages

These are the two ASP.NET Core middleware we will need. The first enables cookie based authentication and the second OpenID Connect authentication workflow.

Set the 'Launch URL' in the debug setting to be the same as the 'App URL'. One thing in a real app please don't use http and check the 'Enable SSL' box. Transport Layer Security is critical as modern authentication depends on it to encrypt the channel.

Debug settings

At this point we can F5 and run the application to test. The web application names "BrowserToWebApp" should launch. I have used Chrome browser for testing.

Configuring the authentication middleware

Lets add some setting keys and values to appsettings.json. The application will need these later.

"AAD": {
    "ClientID": "",
    "AADInstance": "http://login.microsoftonline.com/{0}",
    "Tenant": "ADSample101.onmicrosoft.com",
    "PostLogoutRedirectUri": "http://localhost:37873/"
  }

The ClientID value will come from Azure AD once the app is registered. The AADInstance is a well known URL for Azure. The Tenant is your tenancy name. Finally PostLogoutRedirectUri is the URL of this web app.

In the Startup.cs file add the code in ConfigureServices method.

public void ConfigureServices(IServiceCollection services)  
{
    // Add framework services.
    services.AddMvc();
    // Add authentication services.
    services.AddAuthentication(
        sharedAuthenticationOptions =>
                sharedAuthenticationOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme);
}

We are setting up cookie authentication as the user's identity needs to be persisted in a cookie after successful authentication.

In Configure method add the following code to add cookie authentication middleware and OpenID Connect middleware to the ASP.Net pipeline. Add this right after the loggerFactory.AddDebug(); line

// Read the config values.
string clientId = Configuration["AAD:ClientID"];  
string aadInstance = Configuration["AAD:AADInstance"];  
string tenant = Configuration["AAD:Tenant"];  
string postLogoutRedirectUri = Configuration["AAD:PostLogoutRedirectUri"];

// Configure the pipeline to add OpenID Connect authentication middleware.
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions  
{
    ClientId = clientId,
    Authority = string.Format(aadInstance, tenant),
    PostLogoutRedirectUri = postLogoutRedirectUri,
    RequireHttpsMetadata = false,
    Events = new OpenIdConnectEvents
    {
        OnAuthenticationFailed = context =>
        {
            context.HandleResponse();
            context.Response.Redirect("/Error/message" + context.Exception.Message);
            return Task.CompletedTask;
        }
    }
});

Adding the SignIn and SignOut functionality

Add a shared view named _LoginPartial.cshtml to show the login and logout links

@if (User.Identity.IsAuthenticated)
{
    <ul class="nav navbar-nav navbar-right">
        <li style="color: yellow">Hello, @User.Identity.Name</li>
        <li>@Html.ActionLink("Sign Out", "SignOut", "Account")</li>
    </ul>
}
else  
{
    <ul class="nav navbar-nav navbar-right">
        <li>@Html.ActionLink("Sign In", "SignIn", "Account", null, new { id = "loginLink" })</li>
    </ul>
}

So if the user is authenticated display the Name on the navigation bar in yellow.

Then inject this view to _Layout.cshtml file

<div class="navbar-collapse collapse">  
    <ul class="nav navbar-nav">
        <li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
        <li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
        <li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
    </ul>
    @Html.Partial("_LoginPartial")
</div>  

Add a bit of razor to show all the claims on the About.cshtml page.

<ul>  
    @foreach(var claim in User.Claims)
    { <li>@claim.Type : @claim.Value</li>}
</ul>  

Create a new controller named AccountController with two action methods SignIn and SignOut. Fill with code as shown below.

public class AccountController : Controller  
{
    [HttpGet]
    public async Task SignIn()
    {
        if (!User?.Identity.IsAuthenticated ?? false)
        {
            await HttpContext.Authentication.ChallengeAsync(
                OpenIdConnectDefaults.AuthenticationScheme, 
                new AuthenticationProperties
                {
                    RedirectUri = "/"
                });
        }
    }

    [HttpGet]
    public async Task SignOut()
    {
        await HttpContext.Authentication.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
        await HttpContext.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    }
}

In the SignIn method if the user is not authenticated then we want to use OpenId Connect authentication type passing it some properties, in this case the RedirectUri to the home page. The OpenId Connect middleware as configured before will take care of redirecting the user to Azure AD at this point.

The SignOut method is easier, just sign out from the two authentication types.

Registering the app in Azure AD

Now all that is left is to register our app in Azure AD. The steps are as below

Browse to new Azure management portal and go to the Azure Active Directory resource ADSample101. At the time of this post AAD is in PREVIEW in the new Portal.

Click 'App registrations' from the MANAGE menu and then click on the '+ New application registration' menu on the top. This will open the create pane as shown below.
Provide a name to the application in the screen.
Populate the sign on URL which is the URL of our web app.
Azure app create

Click 'Create' to finish. The app will be registered now as below.
Azure app registration

Click on the app and it opens the settings pane where you can look at the values of various properties. Important to note the 'Application ID' property. This is a unique Id for our web app. Copy the value of this property and paste it in the appsettings.json file ClientID property.

App properties

Run the app

Now that all code and configuration is done lets F5 and run the app from Visual Studio. The browser windows should come up. Click on the 'Sign In' link on top right corner. This will redirect to the Azure AD Sign In page. Sign using the 'Test User' account login/password. If all goes well we are redirected back to our app and the user's name is displayed on the top.

App signin page

Click on the 'About' link and this should take use to the About page and all claims for the user should be displayed as shown below.

App about page

Summary

That's it. This finishes my first part. We have successfully authenticated an ASP.NET Core MVC web application with Azure AD via OpenID Connect protocol. In the next part I will trace the browser traffic using Fiddler and explain what is happening under the cover.

Pratik Khasnabis

Solution architect, Azure expert, API designer, C# programmer, Data Science learner, IT geek and Star Wars fan. MCSD Azure Solution Architect, MCSD Web Applications and TOGAF certified.

Melbourne