Tag Archives

One Article

Posted by .Ronald on

Add Azure Active Directory to an existing ASP.NET MVC web application

There are 2 options to add Azure Active Directory to your existing ASP.NET MVC application.

The easiest one is in Visual Studio. Right-click on your web project, and you are presented with the possibility to configure Azure AD Authentication. This starts a wizard which will do some checks and configures your application for you. Prerequisites are described on the Diagnosing errors with the Azure Active Directory Connection Wizard page.

The other, and slightly more difficult option, is to configure your application yourself. And that is what’s described below.

Prepare your application to use Azure Active Directory

  1. If your application doesn’t already use SSL, you need to enable it now. AAD without SSL, thus running over an unsecure connection is not advisable and a real hassle to setup.
    Note the SSL url, as you will need it later to register the application in AAD.

Remove existing authentication (if any)

  1. If you have configured your application in web.config to use any form of authentication, remove it
    <system.web>
      <authentication mode="None" />
    </system.web>
  2. If you have any settings in web.config regarding AAD authentication, remove them also
    <add key="ida:ClientId" value="[some GUID]" />
    <add key="ida:AADInstance" value="https://login.microsoftonline.com/" />
    <add key="ida:Domain" value="[your domain]" />
    <add key="ida:TenantId" value="[some guid]" />
    <add key="ida:PostLogoutRedirectUri" value="https://localhost:44364/" />
  3. It might also be interesting to check the .csproj file for any left-over authentication elements. Disable them and only enable anonymous authentication
    <PropertyGroup>
      <IISExpressAnonymousAuthentication>enabled</IISExpressAnonymousAuthentication>
      <IISExpressWindowsAuthentication>disabled</IISExpressWindowsAuthentication>
    </PropertyGroup>
  4. Remove authentication NuGet packages

Register your application in Azure Active Directory

  1. Sign in to the Azure portal
  2. Choose Azure Active Directory from your services (search using More Services if it isn’t shown yet)
  3. Choose App registrations and Add
  4. Enter a Name, choose Web app / API for Application Type and enter the URL of your web application under Sign-on URL (without the trailing slash)
    The URL is the SSL url we got earlier when we enable SSL for our web application
  5. Click Create
  6. Still in your application registrations, choose your application, choose All settings and Properties
  7. Copy the Application ID
  8. Enter the Logout URL as the Sign-on URL you entered earlier, followed by /Account/EndSession
    This will link to the single sign out URL of our application
  9. Also from the Settings menu, add a Key with a duration of 1 or 2 years
    Note down the key, as you will not be able to retrieve it afterwards.

Configure your application to use your Azure AD tenant

  1. Open web.config and add appSettings for:
    <appSettings>
      <add key="ida:ClientId" value="[some GUID]" />
      <add key="ida:AppKey" value="[The key we created earlier]" />
      <add key="ida:Tenant" value="[Tenant name]" />
      <add key="ida:AADInstance" value="https://login.microsoftonline.com/{0}" />
      <add key="ida:RedirectUri" value="[Url of the application]" />
    </appSettings>
    
  2. Replace the AccountController with this code:
    public class AccountController : Controller
    {
        public void SignIn()
        {
            // Send an OpenID Connect sign-in request.
            if (!Request.IsAuthenticated)
            {
                HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" }, OpenIdConnectAuthenticationDefaults.AuthenticationType);
            }
        }
        public void SignOut()
        {
            // Remove all cache entries for this user and send an OpenID Connect sign-out request.
            string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
            AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID));
            authContext.TokenCache.Clear();
    
            HttpContext.GetOwinContext().Authentication.SignOut(
                OpenIdConnectAuthenticationDefaults.AuthenticationType, CookieAuthenticationDefaults.AuthenticationType);
        }
    
        public void EndSession()
        {
            if (HttpContext.Request.IsAuthenticated)
            {
                // Remove all cache entries for this user and send an OpenID Connect sign-out request.
                string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
                AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID));
                authContext.TokenCache.Clear();
            }
    
            // If AAD sends a single sign-out message to the app, end the user's session, but don't redirect to AAD for sign out.
            HttpContext.GetOwinContext().Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
        }
    }

    (Credits for this code go to https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect/)

  3. Add a reference to Microsoft.AspNet.Identity, Microsoft.Owin.Security.OpenIdConnect, Microsoft.Owin.Security.Cookies, Microsoft.IdentityModel.Clients.ActiveDirectory
    PM> Install-Package Microsoft.AspNet.Identity.Owin
    PM> Install-Package Microsoft.Owin.Security.OpenIdConnect
    PM> Install-Package Microsoft.Owin.Security.Cookies
    PM> Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory
  4. Replace the Startup class in Startup.Auth.cs with this code:
    public partial class Startup
    {
        //
        // The Client ID is used by the application to uniquely identify itself to Azure AD.
        // The App Key is a credential used to authenticate the application to Azure AD.  Azure AD supports password and certificate credentials.
        // The Metadata Address is used by the application to retrieve the signing keys used by Azure AD.
        // The AAD Instance is the instance of Azure, for example public Azure or Azure China.
        // The Authority is the sign-in URL of the tenant.
        // The Post Logout Redirect Uri is the URL where the user will be redirected after they sign out.
        //
        private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
        private static string appKey = ConfigurationManager.AppSettings["ida:AppKey"];
        private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
        private static string tenant = ConfigurationManager.AppSettings["ida:Tenant"];
        private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
    
        public static readonly string Authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
    
        // This is the resource ID of the AAD Graph API.  We'll need this to request a token to call the Graph API.
        string graphResourceId = ConfigurationManager.AppSettings["ida:GraphResourceId"];
    
        public void ConfigureAuth(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
    
            app.UseCookieAuthentication(new CookieAuthenticationOptions());
    
            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    ClientId = clientId,
                    Authority = Authority,
                    PostLogoutRedirectUri = redirectUri,
                    RedirectUri = redirectUri,
    
                    Notifications = new OpenIdConnectAuthenticationNotifications()
                    {
                        //
                        // If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away.
                        //
                        AuthorizationCodeReceived = OnAuthorizationCodeReceived,
                        AuthenticationFailed = OnAuthenticationFailed
                    }
    
                });
        }
    
        private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
        {
            context.HandleResponse();
            context.Response.Redirect("/Home/Error?message=" + context.Exception.Message);
            return Task.FromResult(0);
        }
    
        private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification context)
        {
            var code = context.Code;
    
            ClientCredential credential = new ClientCredential(clientId, appKey);
            string userObjectID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
            AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectID));
    
            // If you create the redirectUri this way, it will contain a trailing slash.  
            // Make sure you've registered the same exact Uri in the Azure Portal (including the slash).
            Uri uri = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path));
    
            AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(code, uri, credential, graphResourceId);
        }
    

    (Credits for this code go to https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect/)

  5. Add the NaiveSessionCache utility class from https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect/blob/master/TodoListWebApp/Utils/NaiveSessionCache.cs to your web application
  6. Replace the content of _LoginPartial.cshtml with this code:
    @if (Request.IsAuthenticated)
    {
        <text>
            <ul class="nav navbar-nav navbar-right">
                <li class="navbar-text">
                    Hello, @User.Identity.Name!
                </li>
                <li>
                    @Html.ActionLink("Sign out", "SignOut", "Account")
                </li>
            </ul>
        </text>
    }
    else
    {
        <ul class="nav navbar-nav navbar-right">
            <li>@Html.ActionLink("Sign in", "SignIn", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
        </ul>
    }
  7. Decorate the controllers that require authorization with the [Authorize] attribute
    [Authorize]
    public class HomeController : Controller
    {
        public ActionResult Index()

Now run your application. It should require you to sign in to your Azure AD account and ask your permission to read your user profile, so the application knows who you are.

References