The Help Desk demo, Part 3–Authentication

Now that we have our application configured in Azure, we need to update the Startup.Auth.cs class (in the App_Start folder) so that the application can utilize Azure Active Directory authentication for the users.  The Startup.Auth.cs class looks like this.

using System;
using System.IdentityModel.Claims;
using System.Threading.Tasks;
using System.Web;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Owin;
using BusinessApps.HelpDesk.Models;
using BusinessApps.HelpDesk.Helpers;

namespace BusinessApps.HelpDesk
{
    public partial class Startup
    {
        public void ConfigureAuth(IAppBuilder app)
        {
            ApplicationDbContext db = new ApplicationDbContext();

            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            app.UseCookieAuthentication(new CookieAuthenticationOptions());

            OpenIdConnectAuthenticationOptions options = new OpenIdConnectAuthenticationOptions();
            options.ClientId = SettingsHelper.ClientId;
            options.Authority = SettingsHelper.AzureADAuthority;
            options.PostLogoutRedirectUri = SettingsHelper.LogoutAuthority;

            OpenIdConnectAuthenticationNotifications notifications = new OpenIdConnectAuthenticationNotifications();
            notifications.AuthorizationCodeReceived = (context) =>
            {
                string code = context.Code;

                AuthenticationHelper authHelper = new AuthenticationHelper();
               
                String signInUserId = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;

                AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.AzureADAuthAuthority);
                AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), authHelper.GetClientAssertionCertificate(), null);

                return Task.FromResult(0);
            };

            notifications.RedirectToIdentityProvider = (context) =>
            {
                string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
                context.ProtocolMessage.RedirectUri = appBaseUrl + "/";
                context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;

                return Task.FromResult(0);
            };

            notifications.AuthenticationFailed = (context) =>
            {
                context.HandleResponse();
                return Task.FromResult(0);
            };

            options.Notifications = notifications;

            app.UseOpenIdConnectAuthentication(options);
        }
    }
}

Next, we can add an AuthenticationHelper class to the Helpers folder.  This class will do the Azure authentication token management, and looks like this:

using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

namespace BusinessApps.HelpDesk.Helpers
{
    public class AuthenticationHelper
    {
        public ClientAssertionCertificate GetClientAssertionCertificate()
        {
            X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            certStore.Open(OpenFlags.ReadOnly);

            X509Certificate2 cert = certStore.Certificates.Find(X509FindType.FindByThumbprint, SettingsHelper.CertThumbprint, false)[0];

            ClientAssertionCertificate cac = new ClientAssertionCertificate(SettingsHelper.ClientId, cert);

            return cac;
        }

        public async Task<AuthenticationResult> GetToken(string resource)
        {
            ClientAssertionCertificate cac = GetClientAssertionCertificate();

            AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.AzureADAuthority);
            AuthenticationResult authResult = await authContext.AcquireTokenAsync(resource, cac);

            return authResult;
        }
    }
}

Next, we’ll tell the application to define unique users by name.  This can be accomplished by adding the following line of code to the Global.asax.cs file:

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;

The entire Global.asax.cs file now looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace BusinessApps.HelpDesk
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
        }
    }
}

With any luck, if we run the application at this point, it will launch successfully:

image

Clicking Log In in the top right corner will take us to the Log In screen.  Choose OpenIdConnect to login via Azure:

image

This takes us to the standard Azure login screen.  Choose/Enter the organizational account, enter a password, and click Sign In (note the name of the application listed at the top of the login screen):

image

If all goes well, the application now knows who we are!

image

Pretty painless, right?

The Help Desk Demo

The entire source code for the Help Desk demo can be found here https://github.com/OfficeDev/PnP/tree/dev/Solutions/BusinessApps.HelpDesk/, in the Office 365 Dev PnP GitHub repository.

Leave a Reply

Your email address will not be published. Required fields are marked *