DotNetCurry Logo

Configure ASP.NET MVC to use Multiple ADFS using OWIN KATANA

Posted by: Kunal Chandratre , on 8/18/2015, in Category Microsoft Azure
Views: 29059
Abstract: Implement multiple ADFS integration in ASP.NET MVC using OWIN Katana

In Part 1 of this series Configure ADFS in Azure Virtual Machine for MVC authentication we saw how we could leverage Azure VM IaaS to configure ADFS. In part 2 of this series Using ADFS with Azure for Single Sign-On in ASP.NET MVC we saw integration of single ADFS into an ASP.Net MVC application using WIF.

In this article, we will go a step further and consume multiple ADFS in a single ASP.Net MVC application using Microsoft’s OWIN implementation known as KATANA. This way we will enable a single ASP.NET MVC application to integrate with multiple ADFS.

This involves the following steps –

- Configure one more ADFS in Azure VM by following the exact steps of Part1.

- Creating sample MVC application with individual authentication mechanism.

- Enable ASP.NET MVC application for OWIN KATANA

- Configure ADFS to send in important claims

- Receive the claims in ASP.NET MVC application and display them.

Important –

This article is also applicable if you are using on-premises ADFS instead of Azure VM based ADFS. The important aspect highlighted in this article is “how to integrate ASP.NET MVC application in multiple ADFS”.

If you are following the complete series, then this article is part of a series of articles that will highlight the following important scenarios –

1. Configure ADFS in Azure VM

2. Implementing ADFS (or WSFederation) based Single Sign-On authentication in MVC based ASP.NET application using Windows Identity Foundation (WIF or in Developer language – specifically using System.Identity.dll)

3. Implementing Multiple ADFS (or WSFederation) based authentication in MVC based ASP.NET application using Microsoft OWIN KATANA. (This is the article you are reading currently)

4. Hosting ASP.NET MVC application integrated with multiple wsfederation to Azure WebApps (formerly Azure websites) and Azure cloud Services (web role).

5. Making life simpler – use 3rd Party (Paid) Identity Server Provider Auth0 to achieve multiple WSFederation (or ADFS) authentication in ASP.NET MVC application.

Introduction

In this article I am going to use 2 ADFS (multi-wsfederation) configured in Azure VM for providing the implementation of Single Sign-on (SSO). Of course this is also applicable to ADFS which already exists on premises. I don’t have any ADFS on premises therefore I am going to use Azure VM to act as my domain controller and ADFS server.

Applicable Technology Stack

1. Windows Server 2012 R2 Data Center for ADFS

2. Azure VM based ADFS OR on premise ADFS

3. Self-Signed SSL Certificates

4. VS 2013

5. OWIN KATANA

Problem Statement

If you remember in Part 1 http://www.dotnetcurry.com/windows-azure/1145/active-directory-adfs-azure-virtual-machine-authentication-aspnet-mvc we had considered a space company called Antariksh that wanted to host ADFS in Azure VM. Let’s say another company named as IndiaUniverse working in Space has decided to work with Antariksh to share knowledge, findings of space and collaborate. Therefore they’ve  decided to launch an application for collaboration that will be hosted in Azure cloud platform and can be accessed by employees of both companies. They have decided to provide consistent login experience for their employees and therefore they want their employees to use existing AD credentials for accessing this new application.

In our context, this means we need an ASP.NET MVC application to be integrated with ADFS from Antariksh.com and IndiaUniverse.com; in short multiple ADFS integration in single ASP.NET MVC application.

ADFS Configuration for second ADFS

Ok, so first we need to have 2 ADFS in place so that we can integrate them in one ASP.NET MVC application. As depicted in Part 1 http://www.dotnetcurry.com/windows-azure/1145/active-directory-adfs-azure-virtual-machine-authentication-aspnet-mvc we will follow the same procedure to provision another ADFS in Azure VM. The only change we are making is about various values for domain name, vnet name, vm name and so on. I have used the following values by following all the steps of Part 1 to provision new ADFS for IndiaUniverse company. You can also follow the steps with these values or different values of your choice. Remember, if you are using on premises ADFS and if 2 ADFS are already in place, then you may skip this step.

· Cloud Service Name – indiauniverse

· Storage – indiauniverstorage

· Vnet – indiauniversevnet

· Subnet name and IP range, DNS IP - as per screenshot below –

provision-vnet1

· VM name – indiauniversedc

· VM admin – indiauniverseadmin

· VM admin password – As per your choice.

· Certificate name – indiauniverse.cloudapp.net

· Root domain name - universedomain.com

· DSRM password – of your choice.

· NETBIOS name – universedomain

At the end two VM’s in running state in Azure will be seen.

The values for personal information of India Universe admin in Active Directory are as follows –

universeadmin-data

Alright so here we have 2 ADFS with us hosted in Azure and their respective metadata url’s are as shown here –

· https://antariksh.cloudapp.net/FederationMetadata/2007-06/FederationMetadata.xml

· https://indiauniverse.cloudapp.net/FederationMetadata/2007-06/FederationMetadata.xml

In Part 2 http://www.dotnetcurry.com/windows-azure/1158/using-adfs-azure-single-signon-aspnet-mvc we saw integration of single ADFS in ASP.NET MVC application using WIF. When we created that ASP.NET MVC  application, we provided the information of metadata URL in the authentication wizard itself. Now if you see the wizard; we have the provision of only one metadata url configuration in WIF. So in the current problem, where we need integration with multiple ADFS, WIF can’t be used. This is where Microsoft OWIN implementation called Katana comes into picture.

But before that let’s understand about OWIN and KATANA at high level.

OWIN and KATANA

OWIN stands for Open Web Interface. OWIN defines a standard interface between .NET web servers and web applications. The goal of the OWIN interface is to decouple server and application, encourage the development of simple modules for .NET web development, and, by being an open standard, stimulate the open source ecosystem of .NET web development tools [courtesy - http://owin.org/ ]

There are 2 core components of OWIN specifications -

1. Environment Dictionary, is represented as IDictionary<string, object>. This data structure is responsible for storing all of the state necessary for processing an HTTP request and response and relevant server state information.

2. Application Delegate, is a function signature and it serves as a primary interface between all components in an OWIN application. The delegate is represented as -Func<IDictionary<string, object>, Task>;

OWIN is basically inspired from a Rack which is developed for Ruby community. Using OWIN specific implementation, you can create web application loosely coupled with hosting server technology. That means, you can create an application that can be hosted on any server technology without making any changes to your application. In short you decouple server and application using OWIN. The OWIN library is open source and consists of interfaces. So you can implement them the way you want. Many companies have implemented OWIN specifications and created their own custom frameworks. Similar to what I described in Part 1, WSFederation is the specification and ADFS is an implementation of this specification by Microsoft. Similarly OWIN is also a specification and KATANA is the implementation of it by Microsoft.

OWIN and KATANA is huge and explaining various aspects is out of scope of this article. For more read on OWIN KATANA refer to the link - https://katanaproject.codeplex.com/documentation

Our focus is going to be on using the OWIN KATANA in an ASP.NET MVC application to support multi ADFS integration. Let’s get started with actual implementation.

Create ASP.NET MVC application secured by First ADFS

I hope you have gone through the technology stack section above. First step would be to open Visual Studio 2013 in administrator mode and click on File -> New -> Project. A dialog box appears where in you can put the name of your project as MultipleADFSDemo and specify the appropriate location. When we click Ok, another pop up appears where we need to choose template of the project. Select MVC template. As soon as we select the MVC template, automatically in right hand panel, the authentication mode changes to “Individual User Account”!!

create-project1

This authentication mechanism equips application with all OWIN dependent assemblies. By default it is assumed that current ASP.NET MVC application will integrate with external identities such as Facebook, Microsoft Live Id, Google and so on. Click OK to continue with project creation. After project creation, open “solution explorer” and expand the folder “App_Start”. Then open a class file “Startup.Auth.cs”. In this class you will observe commented social identity providers integration code as shown below –

create-project2

In the current article, I am not demonstrating social login integration therefore I have removed the above highlighted commented code from Startup.Auth.cs.

Add OWIN WsFederation nuget

By default OWIN ADFS support libraries are not added in Individual Authentication mode based MVC project. Good that it is available as a Nuget package. So add the nuget package manually from “Library Package Manager”. From Visual Studio select Tools > Library Package Manager > Package Manager Console option. Open the nugget link for Owin wsfederation [https://www.nuget.org/packages/Microsoft.Owin.Security.WsFederation/ ] and copy the command. Paste this command in Package Manager Console and execute.

create-project3

Understanding Startup.Auth.cs class

Let’s understand the structure of Startup.Auth.cs class. To understand the contents of this class, let’s go a step backward and understand few OWIN and Katana basics. In OWIN KATANA, 4 components forms the architecture –

1. Host

2. Server

3. Middleware

4. Application

More details on this can be obtained from http://owin.org/html/owin.html#2-definitions. Let’s understand how these architecture components are represented in MultipleADFSDemo project. The section 4 [URL - http://owin.org/html/owin.html#4-application-startup ] of OWIN specification lists down the startup sequence. This startup sequence is specified in Startup.Auth.cs class. If you open this class, you will observe an interface named as IAppBuilder. This interface is responsible for laying down the startup sequence of Section 4 of OWIN specification. This startup sequence is also called as OWIN Pipeline and components of pipeline are also called as Middleware.

So in short we can say that the Startup class along with IAppBuilder interface is acting as a Host or Middleware or Startup sequence of OWIN specification in KATANA. In this class, we can register pipeline components with the help of USE method of IAppBuilder interface. As you can see below, IAppBuilder class has “Use” method for registering the middleware components in startup class. The middleware’s are executed in the same order in which they are added using “Use” method in IAppBuilder class.

create-project4

Remember IAppBuilder interface is not part of OWIN. When startup class in initialized and Configuration method is invoked, an instance of IAppBuilder is passed as an argument which then can be used for adding middleware’s with Use method.

Use method provides a way by which middleware can be added to pipeline. To simplify this process, usually extension methods are used to extend IAppBuilder functionality. Therefore as you can see in the startup class below, 2 extension methods are being used –

1. UseCookieAuthentication

2. UseExternalSignInCookie

create-project5

This way we have extension methods for adding pipeline of Twitter, Microsoft Live account, Facebook and Google authentication as shown in the figure below.

create-project2

Similarly we need extension method for ADFS integration as well and therefore we added the Nuget package of WSFederation as described above.

Configure ADFS Metadata URL’s in extension method in MVC application

WSFederation is an external identity provider here. So we need to change Cookie authentication options. Add the following lines of code in “ConfigureAuth” method of “Startup” class below existing code –

// these two lines of code are needed if you are using any of the external authentication middleware
app.Properties["Microsoft.Owin.Security.Constants.DefaultSignInAsAuthenticationType"] = "ExternalCookie";
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = "ExternalCookie",
    AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Passive
});

And remove the existing lines of code -

// Use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

We need to tell our application about ADFS using metadata URL. Also we need to specify the reply URL of the application to which ADFS will send claims. To configure this important information, we need to use WsFederationAuthenticationOptions class. Using this class we will configure startup class to ADFS middleware.

We know that application integrating with ADFS must be on HTTPS. Therefore I opened the properties of MultipleADFSDemo project and marked SSLEnabled as True.

create-project6

Also change the URL from properties of the project as shown below so as to browse the project in debug mode over https URL –

create-project7

In startup class, add following code to configure Antariksh ADFS.

//configure Antariksh ADFS middleware
var antarikshADFS = new WsFederationAuthenticationOptions
{
    MetadataAddress = "https://antariksh.cloudapp.net/FederationMetadata/2007-06/FederationMetadata.xml",
    AuthenticationType = "Antariksh ADFS",
    Caption = "Antariksh Domain",                
    //localhost
    Wreply = "https://localhost:44314/Account/LoginCallbackAntarikshAdfs",
    Wtrealm = "https://localhost:44314/Account/LoginCallbackAntarikshAdfs"
};
//add to pipeline
app.UseWsFederationAuthentication(antarikshADFS);

The metadata url is of antariksh adfs. The SSL URL present in project properties is https://localhost:44314/ forms part of Wreply and Wtrealm. The part after SSL URL is the Account controller and LoginCallbackAntarikshAdfs is the action within controller. UseWsFederationAuthentication method adds Antariksh ADFS option to pipeline.

Note - As of now we will configure only one ADFS with ASP.NET MVC application. After successful integration of single ADFS using OWIN Katana, we will add another ADFS.

Changes in Login views

Open Login.cshtml from Views > Account folder. You will find most of the code is unnecessary for our context. Therefore remove the entire code and paste the following:

@model MultipleADFSDemo.Models.LoginViewModel

@{
    ViewBag.Title = "Log in";
}

<h2>@ViewBag.Title.</h2>
<div class="row">
    <div class="col-md-8">
        <section id="socialLoginForm">
            @Html.Partial("_ExternalLoginsListPartial", new { Action = "ExternalLogin", ReturnUrl = ViewBag.ReturnUrl })
        </section>
    </div>
    <div class="col-md-4">

    </div>
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

In the above code, we are invoking external Partial login view in which we are invoking ExternalLogin action.

Delete existing code from _LoginPartial.html and add following lines of 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>
        <li>@Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>

    </ul>
}

In above code, instead of sign in action, I am specifying LogIn action and added SignOut action as well.

Modify Account Controller

The account controller is having many methods and actions. These actions of registering new user, forgot password and other related functionalities are irrelevant in ADFS scenario. Therefore remove code present inside the class and let’s replace with required code segments one by one.

First remove [Authorize] attribute from AccountController class and change the Login action to the following:

public ActionResult Login()
{
return View();
}

From the Login view, when user clicks on “Log In” action _ExternalLoginListPartial.cshtml view is displayed along with ADFS login options. The information about displaying Login options of ADFS will be picked from Startup class middleware configuration. As of now, the startup class has Antariksh ADFS configured. Let’s run the application to see if we get “Antariksh ADFS” option enabled on UI for login. So click on F5 and you will get a Certificate Error. Just click on Continue to websites… option. In the right hand side, we have “Login” button and voila!! You should see the option Antariksh ADFS available for login option as shown below –

modify-accountcontroller1

If you click on the button “Antariksh ADFS” an error is thrown as “the resource cannot be found”. The reason is quite obvious. We have not yet defined the ExternalLogin action in Account Controller yet. “ExternalLogin” action is actually getting invoked from _ExternalLoginsListPartial.cshtml. Let’s add “ExternalLogin” action in Account controller. If you observe the _ExternalLoginsListPartial.cshtml code, you will see that to ExternalLogin action we are sending “AuthenticationType” as provider name and return url as parameters. We have provided the “AuthenticationType” string value in Startup class in ADFS pipeline configuration. So provider name received will be Antariksh ADFS. Therefore we will compare if the provider parameter received in “ExternalLogin” action is Antariksh ADFS then challenge it. When my application wants to authenticate a user with an external provider like ADFS, we indicate this to the AuthenticationManager on the OwinContext. Our code calls Challenge() passing the name of the authentication middleware we want to invoke (here Antariksh ADFS). Also, the ADFS middleware won’t get invoked unless the current HTTP response is a 401 status code. When the ADFS middleware triggered sees the 401 response from our application, it initiates the protocol to the Antariksh ADFS provider. This usually involves various HTTP redirects to the ADFS so the user can login. Therefore we will add the following code in Account Controller and a class to Challenge the authentication.

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
    var ctx = Request.GetOwinContext();
    if (provider == "Antariksh ADFS")
    {
        ctx.Authentication.Challenge(
            new AuthenticationProperties
            {
                RedirectUri = Url.Action("LoginCallbackAntarikshAdfs", "Account", new { provider })
            },
            provider);
    }
    else if (provider == "Second ADFS. Yet to be added")
    {
        //do nothing as of now
    }
    return new HttpUnauthorizedResult();
}

public ActionResult LoginCallbackAntarikshAdfs(string provider)
{
    var ctx = Request.GetOwinContext();
    var result = ctx.Authentication.AuthenticateAsync("ExternalCookie").Result;
    ctx.Authentication.SignOut("ExternalCookie");
    
    if (result != null)
    {
        var claims = result.Identity.Claims.ToList();
        claims.Add(new Claim(ClaimTypes.AuthenticationMethod, provider));
    
    var ci = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
        ctx.Authentication.SignIn(ci);
    }
    return this.RedirectToAction("About", "Home");
}

The class to challenge authentication is added in AccountController.cs file as follows –

class ChallengeResult : HttpUnauthorizedResult
{
    private const string XsrfKey = "XsrfId";

    public ChallengeResult(string provider, string redirectUri)
        : this(provider, redirectUri, null)
    {
    }

    public ChallengeResult(string provider, string redirectUri, string userId)
    {
        LoginProvider = provider;
        RedirectUri = redirectUri;
        UserId = userId;
    }

    public string LoginProvider { get; set; }
    public string RedirectUri { get; set; }
    public string UserId { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {
        var properties = new AuthenticationProperties() { RedirectUri = RedirectUri };
        if (UserId != null)
        {
            properties.Dictionary[XsrfKey] = UserId;
        }
        context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
        }
}

The highlighted method LoginCallbackAntarikshAdfs is the callback method where we will retrieve and iterate through the claims received from Antariksh ADFS and it is also provided in WsFederationAuthenticationOptions in startup class as shown below -

Wreply = "https://localhost:44314/Account/LoginCallbackAntarikshAdfs",

Wtrealm = https://localhost:44314/Account/LoginCallbackAntarikshAdfs

Adding OWIN KATANA based MVC app as relying party trust in first ADFS

We have already seen Relying party trust process in Part 2 of the series http://www.dotnetcurry.com/windows-azure/1158/using-adfs-azure-single-signon-aspnet-mvc. The relying party trust we added in Part 2 was for WIF based ADFS integration. Adding relying party trust for OWIN KATANA based MVC application in ADFS needs few additional steps in it.

Add Trust relationship to ADFS

Now we are moving back to ADFS to do some configurations. In this step, we will essentially tell ADFS that our OWIN KATANA based MVC application with localhost url is trusted application and you can send the security tokens to it after successful authentication from a user. In technical terminology this is nothing but adding relying party trust in ADFS.

So login to ADFS Azure VM (in our case it is AntarikshDC azure VM). Open Server Manager > Tools > ADFS Management. Expand “Trust Relationships” from left hand panel and select “Relying Party trusts” option. You will see that Device Registration Service is already present as relying party, plus a relying party of WIF that we had added during Part 2 is also present; which may not be present in your case if you have directly started from this article and skipped part 2. Now click on option “Add Relying Party Trust” on the right hand panel.

add-trust1

Add relying party wizard will appear. Click on Start button to continue ahead. Select option “Enter data about relying party manually” and click on Next to continue. Now we are going to use the Wreply URL from startup class as relying party. Because ADFS will send the claims to callback URL, wherein received claims will be added to Identity Claims. We will be providing the name as OWIN KATANA Localhost.

add-trust2

Click Next to continue. In Choose Profile window select “ADFS Profile” option and click Next to continue. The ADFS configured on Windows Server 2012 is ADFS 3.0 therefore we are not selecting 1.0 and 1.1 profile option.

add-trust3

In the “Configure Certificate” option let’s not do anything. This window gives you an option to choose the certificate for encrypting tokens. As of now, we are not encrypting any of the tokens, therefore simply click on Next to continue further. In “Configure URL” window select the checkbox against the option “Enable support for the WS-Federation passive protocol”. A Textbox will get enabled and this is where we need to put our relying party URL or in simple words- our OWIN KATANA based MVC application URL and then click Next to continue.

add-trust4

On “Configure Identifiers”, we have the required relying party added therefore simply click Next to continue. Then select “I do not want to configure multi-factor authentication settings for this relying party trust at this time” and click Next to continue. Select “Permit all users to access this relying party” and click Next to continue.

add-trust5

In the “Ready to add trust” window click Next to continue. In the “Finish” window select the checkbox to open the claims rules and click on Close.

add-trust6

Edit claim rules popup opens.

Add Claim Rules

At this point, ADFS knows about our MVC application but there are a couple of additional things required. This is where we tell ADFS which claims need to be sent to relying party and what values will be present in those claims.

Click on “Add Rule” button.

add-claimrules1

Select template value as “Send LDAP attributes as claims”. Actually claims will be sent by Active Directory and since Active Directory is LDAP based store, therefore we are selecting this template. Now click Next to continue.

add-claimrules2

In configure Rule window provide the name for rule as Send AD Attributes. Select the attribute store as “Active Directory” and map attributes to values as shown below –

add-claimrules3

Add Claim Transformation Rules

For OWIN KATANA based application relying parties, we need to add rules for claim transformation also; unlike WIF based relying party where only claims rules were sufficient.

Click on “Add Rule” button again. Select the option as “Transform an incoming claim” and click Next to continue.

add-tranformrules1

Provide the name of the rule as Map Email to Name ID. Select Incoming claim type as E-Mail Address, Outgoing claim type as Name ID, Outgoing Name Id format as Email. Select the radio button option as “Pass through all claims values”. Then click on Finish and OK on add claim rules main window to finish the procedure of adding claim rules.

add-tranformrules2

Running the application with first ADFS

Alright now is the time to test everything we have done so far. Go back to Visual Studio and hit F5 to start the application in debug mode. Click continue on certificate errors. Then click on Login button and Antariksh ADFS caption button appears. So far so good! Let’s show some courage and click on Antariksh ADFS button and OOPS!! An error is shown as below –

“The remote certificate is invalid according to the validation procedure”.

This error is quite obvious as we are running everything on self-signed certificate created in Part 1 http://www.dotnetcurry.com/windows-azure/1145/active-directory-adfs-azure-virtual-machine-authentication-aspnet-mvc. Therefore we need to write code so that certificate validation procedure will be bypassed for this demo and localhost application. So set BackchannelCertificateValidator property to null in startup class under pipeline. So the code of ADFS middle ware in startup class changes as below – (highlighted below is the new addition to existing code) -

//configure Antariksh ADFS middleware
var antarikshADFS = new WsFederationAuthenticationOptions
{
    MetadataAddress = "https://antariksh.cloudapp.net/FederationMetadata/2007-06/FederationMetadata.xml",
    AuthenticationType = "Antariksh ADFS",
    Caption = "Antariksh Domain",
    BackchannelCertificateValidator = null,
    //localhost
    Wreply = "https://localhost:44314/Account/LoginCallbackAntarikshAdfs",
    Wtrealm = "https://localhost:44314/Account/LoginCallbackAntarikshAdfs"
};

Now we need to bypass the certificate validation procedure at application level as well. Therefore add following code in global.asax.cs –

ServicePointManager.ServerCertificateValidationCallback = delegate
{
    return true;
};

Alright run the application again and click on Antariksh ADFS caption button and Voila!! The login screen pop up of ADFS appears.

If you are  running your application in IE then you should see a credentials box from our Azure VM/ on premises ADFS as shown below –

run-app1

Enter the credentials of antarikshadmin or your ADFS admin and you will redirected to About page of MVC application with your admin flashing in right hand upper corner as shown –

run-app2

Let’s go further and analyze the claims we are receiving from ADFS.

Viewing the claims retrieved

Ok, now we must understand what all different claims our application is receiving. We are going to populate all the received claims in about action. Let’s first rename the about action to Showclaims from Layout.cshtml as highlighted below –

view-claims1

Modify the HomeController About action to ShowClaims and add code to return claims to views. You will need to mark System.Security.Claims reference at the top. Refer to following screenshot for details –

view-claims2

Add the code line in the view as shown here in About.cshtml –

view-claims3

Run the application, enter ADFS admin credentials. After successful login, click ShowClaims action at the top and all the claims will be displayed which are sent by ADFS.

view-claims4

The way we used admin user, other AD users can also be used in the same way.

Now you can use any of these claims like email in your application and can provide authorization to the user based on authorization roles and rules in your database. Till now we have achieved integration with Single ADFS using OWIN Katana. Let’s go ahead make changes to the application to integrate with second ADFS.

Secure OWIN KATANA based ASP.NET MVC application by Second ADFS

Our second ADFS India Universe is already in place. Steps will be very similar to what we have followed in Antariksh ADFS integration. Following section explains each steps in brief.

Configure second ADFS Metadata URL’s in extension method in MVC application

We need to tell the application about our second ADFS India Universe using metadata URL. We also need to specify the reply URL of the application to which ADFS will send claims back. To configure this important information, we need to use another WsFederationAuthenticationOptions class. Using this class we will configure startup class to ADFS middleware.

In the startup class, add the following code to configure IndiaUniverse ADFS.

//configure IndiaUniverse ADFS middleware
var indiaUniverseADFS = new WsFederationAuthenticationOptions
{
    MetadataAddress = "https://indiauniverse.cloudapp.net/FederationMetadata/2007-06/FederationMetadata.xml",
    AuthenticationType = "IndiaUniverse ADFS",
    Caption = "India Universe Domain",
    BackchannelCertificateValidator = null,
    //localhost
    Wreply = "https://localhost:44314/Account/LoginCallbackIndiaUniverseAdfs",
    Wtrealm = "https://localhost:44314/Account/LoginCallbackIndiaUniverseAdfs"
};

The metadata URL is of indiauniverse adfs. The SSL URL present in project properties is https://localhost:44314/ forms part of Wreply and Wtrealm. The part after SSL URL is the Account controller and LoginCallbackIndiaUniverseAdfs is the action within controller. UseWsFederationAuthentication method adds India Universe ADFS option to pipeline.

Important - Remove the below line from existing code of startup class –

//add to pipeline
app.UseWsFederationAuthentication(antarikshADFS);

This is because extension method of USE will perform chaining of middleware one by one and if we add second ADFS middleware, the request of second ADFS will also get served by first ADFS and it will result in error. Therefore instead of USE method we need Map method of IAppBuilder interface. Using Map method we can execute the middleware based on conditions, instead of executing one by one in sequence. Therefore add the following code in startup class –

app.Map("/Account", configuration =>
{
    configuration.UseWsFederationAuthentication(antarikshADFS);
    configuration.UseWsFederationAuthentication(indiaUniverseADFS);
});

Note - As this point, we have configured 2 ADFS with ASP.NET MVC application.

Modify Account Controller

The account controller is having all the code required for Antariksh ADFS, we just need to add the condition for India Universe ADFS in existing code. In the current code, we have an else if condition. Replace that with the following code –

else if (provider == "IndiaUniverse ADFS")
{
    ctx.Authentication.Challenge(new AuthenticationProperties
    {
    RedirectUri = Url.Action("LoginCallbackIndiaUniverseAdfs", "Account", new { provider })
    },
    provider);
}

The highlighted method LoginCallbackIndiaUniverseAdfs is the callback method where we will retrieve and iterate through the claims received from India Universe ADFS and it is also provided in WsFederationAuthenticationOptions in startup class as shown below -

Wreply = "https://localhost:44314/Account/LoginCallbackIndiaUniverseAdfs",

Wtrealm = "https://localhost:44314/Account/LoginCallbackIndiaUniverseAdfs"

Add the call back method of India Universe ADFS as shown here –

public ActionResult LoginCallbackIndiaUniverseAdfs(string provider)
{
    var ctx = Request.GetOwinContext();
    var result = ctx.Authentication.AuthenticateAsync("ExternalCookie").Result;
    ctx.Authentication.SignOut("ExternalCookie");
    
    if (result != null)
    {
        var claims = result.Identity.Claims.ToList();
        claims.Add(new Claim(ClaimTypes.AuthenticationMethod, provider));
        
        var ci = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
        ctx.Authentication.SignIn(ci);
    }
    return this.RedirectToAction("About", "Home");
}

Adding OWIN KATANA based MVC app as relying party trust in second ADFS

In this step, a trust relationship will be configured between MVC app and India Universe ADFS.

Add Trust relationship to ADFS - The steps involved are exactly similar to what we followed in Antariksh ADFS. The only change is in Wreply URL from startup class as relying party. For India Universe ADFS, the URL will be – https://localhost:44314/Account/LoginCallbackIndiaUniverseAdfs

Add Claim Rules - The steps involved are exactly similar to what we followed in Antariksh ADFS.

Add Claim Transformation Rules - The steps involved are exactly similar to what we followed in Antariksh ADFS.

Running the application with multiple ADFS

I salute you for sticking around this long!!!

It is time now to test all the hard work we have put in till now. Run the application from Visual Studio. Click on “Continue to websites” whenever certificate error appears in browser. Then click on Login button and you should see 2 ADFS caption button as shown below –

run-app3

Click on Login button and select India Universe ADFS then click on Show Claims to view the claims. Similarly close the browser and run application again to view the claims of Antariksh ADFS as shown below –

view-claims5

view-claims4

Conclusion

In this part of Identity and Azure series we saw how to implement multiple ADFS integration in ASP.Net MVC using OWIN Katana and how to retrieve claims, relying party, claims rules and many other aspects about a typical WSFederation implementation using OWIN Katana.

Source Code

Download the entire source code of this article (Github)

Alternate Download link (Technet)

Next Steps

In part 4 of this series, we will learn how to host an ASP.NET MVC application integrated with multiple ADFS authentication (either Azure VM configured or On premises) using OWIN Katana in Azure Cloud Service and Azure Websites. Stay tuned!

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on Google+
Further Reading - Articles You May Like!
Author
Kunal Chandratre is a Microsoft Azure MVP. He is working as Azure SME in leading software company in (Pune) India. He also works as a Freelancer with various organizations for Azure support and provides quick start trainings on Azure to corporates and individuals on weekends. He regularly blogs about his Azure experience and is a very active member in various Microsoft Communities and also participates as a ‘Speaker’ in many events. You can follow him on Twitter at: @kunalchandratre or subscribe to his blog


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!