Monday, May 18, 2015

Creating an Intranet MVC 5 application using Windows Authentication that connects to a separate Intranet Web API 2 application also using Windows Authentication

Recently I wanted to create an Intranet MVC application using Windows Authentication that connects to a separate, pre-existing Intranet Web API 2 web service that also uses Windows Authentication. In order to get the Windows Authentication of the MVC application propagated to authenticate with the Web API 2 web service, I had to do the following:

1) Place the following in both applications' <system.web> sections in their respective configuration files.

        <authentication mode="Windows" />
        <authorization>
            <deny users="?" />
        </authorization>
2) Update the .NET aspnet.config file located at "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Aspnet.config" to change the following settings to the following values:

        <legacyImpersonationPolicy enabled="false"/>
        <alwaysFlowImpersonationPolicy enabled="true"/>
 3) In the code for the MVC app that wants to call the Web API 2 app, do the following:

            WindowsIdentity identity = (WindowsIdentity) this.HttpContext.User.Identity;

            using (identity.Impersonate())
            {
                searchModel.SearchResults = this.webApiService.FindWebApiItems(searchModel.SearchCriteria);
            }

This last bit is necessary to ensure that the currently authenticated user in the MVC app gets correctly propagated to the Web API 2 app. In the service that's mentioned in the code above, you'll also need to do the following for interacting with Web API 2:

4) Use the following to connect to Web API 2:

            HttpClientHandler handler = new HttpClientHandler
            {
                PreAuthenticate = true, 
                UseDefaultCredentials = true, 
                Credentials = CredentialCache.DefaultNetworkCredentials
            };

            using (HttpClient client = new HttpClient(handler))
            {
                string result = client.GetStringAsync(uriBuilder.Uri).GetAwaiter().GetResult();

                IList<MyWebApiModel> webApiModels = JsonConvert.DeserializeObject<MyWebApiModel[]>(result);

                return webApiModels;
            }
You should now have working code to propagate Windows Authentication via services.

As a side note, apparently there's also a way to change the settings so that you don't have to modify the global aspnet.config file, you can do it on a per-AppPool basis. The technique is described here, though I've never tried it myself.

No comments: