{"id":36532,"date":"2019-05-10T08:55:24","date_gmt":"2019-05-10T15:55:24","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/premier-developer\/?p=36532"},"modified":"2019-05-06T12:29:47","modified_gmt":"2019-05-06T19:29:47","slug":"moving-legacy-asp-net-apps-with-windows-authentication-to-azure-app-service-part-1","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/moving-legacy-asp-net-apps-with-windows-authentication-to-azure-app-service-part-1\/","title":{"rendered":"Moving legacy ASP.NET apps with Windows authentication to Azure App Service (Part 1)"},"content":{"rendered":"<p>App Dev Manager\u00a0<a href=\"https:\/\/www.linkedin.com\/in\/mikelapierre\/\">Mike Lapierre<\/a> explores authentication options when moving legacy ASP.NET apps to Azure App Services.<\/p>\n<hr \/>\n<p>When attempting to move legacy ASP.NET apps to Azure App Service, you might encounter a few challenges which are documented <a href=\"https:\/\/appmigration.microsoft.com\/readinesschecks\">here<\/a>. I want to cover specially the use Windows authentication which is not supported in Azure App Service. Let\u2019s split this in two parts, first authentication and then authorization.<\/p>\n<h2>Authentication<\/h2>\n<p>The obvious solution is to use Azure AD which allows authentication on the Intranet without entering your password with technologies like Seamless SSO or ADFS. There are a few techniques that can be used to accomplish this. For instance, code can be modified to use Azure AD authentication as described by my colleague in <a href=\"https:\/\/devblogs.microsoft.com\/premier-developer\/convert-asp-net-webforms-with-windows-authentication-to-use-aad\/\">this article<\/a>. Another option, since the target environment is App Service, is to make use of <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/app-service\/overview-authentication-authorization\">App Service Authentication<\/a>. The nice thing about it is no change to the code is required, you just configure it and the identity will flow in automatically for ASP.NET 4.6+ applications. If you want authentication on the Intranet without any prompt, you\u2019ll also need to <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/app-service\/app-service-authentication-how-to#limit-the-domain-of-sign-in-accounts\">configure the domain hint<\/a>.<\/p>\n<h2>Authorization<\/h2>\n<p>Authorization is a broader topic since it depends on what technique you\u2019re using. With Azure AD, the use of roles scoped to the application is a popular choice. If backward compatibility is essential, it\u2019s also possible to use groups, but keep in mind they are not scoped to the application so they can get large and there\u2019s a 200 limit. If you wish to use application roles, follow <a href=\"https:\/\/blogs.msdn.microsoft.com\/waws\/2017\/03\/09\/azure-app-service-authentication-app-roles\/\">this procedure<\/a>. For groups, follow <a href=\"https:\/\/blogs.msdn.microsoft.com\/waws\/2017\/03\/13\/azure-app-service-authentication-aad-groups\/\">this one<\/a>.<\/p>\n<p>Now that the roles or groups claims are sent to the application, let\u2019s have a look on the application impacts. Since we\u2019re talking about legacy ASP.NET apps, let\u2019s start with Web Forms. The first Web Forms apps with Windows authentication usually relied on the two modules, the FileAuthorizationModule and\/or the UrlAuthorizationModule.<\/p>\n<h3>FileAuthorizationModule<\/h3>\n<p>The FileAuthorizationModule does authorization checks based on file permissions on the disk. Since you cannot authenticate with a Windows identity in App Service, you\u2019ll have to extract the ACL rules and move towards something else like the UrlAuhorizationModule I will cover next.<\/p>\n<h3>UrlAuthorizationModule<\/h3>\n<p>The UrlAuthorizationModule does authorization checks based on entries in the web.config. The module relies on the role claims, so it will continue to work as is. There\u2019s a small caveat though, you have to a little bit of claim transformation to make it work properly.<\/p>\n<p>If you choose to use roles, you\u2019ll need to convert the roles claims received from App Service to the proper claim type. Here\u2019s a small HttpModule that will do the trick:<\/p>\n<pre class=\"lang:default decode:true \">public class ClaimTransformationModule : IHttpModule\r\n{\r\n    public void Dispose() { }\r\n\r\n    public void Init(HttpApplication context)\r\n    {\r\n        context.PostAuthenticateRequest += new EventHandler(PostAuthenticateRequest);\r\n    }\r\n\r\n    private void PostAuthenticateRequest(Object source, EventArgs e)\r\n    {\r\n        if (!(HttpContext.Current.User?.Identity is ClaimsIdentity ci)) return;\r\n\r\n        foreach (var c in ci.Claims.Where(x =&gt; x.Type == \"roles\"))\r\n        {\r\n            ci.AddClaim(new Claim(ci.RoleClaimType, c.Value));\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>If you choose to use groups, you\u2019ll have to do something similar, but you\u2019ll receive the group object ids rather than the group names, so you\u2019ll have to convert them to the proper name before adding the claims, see <a href=\"https:\/\/blogs.msdn.microsoft.com\/waws\/2017\/03\/13\/azure-app-service-authentication-aad-groups\/\">this article<\/a> for more details. You could also choose to query the Microsoft Graph to resolve the group names.<\/p>\n<p>Now that we have injected the proper role claims, calls to IsInRole for imperative security checks will also work as is. That will cover most Web Form applications using Windows authentication. Let\u2019s now switch to MVC applications. With MVC, routes no longer map to physical files, so it doesn\u2019t make sense to use the FIleAuthorizationModule. The UrlAuthorizationModule can still be used, but the use of authorization filters like the Authorize attribute is more common. The Authorize attribute is based on the role claims, so it will also work just like the IsInRole calls. You could alternatively implement the same code as above using an OWIN Middleware instead of a HttpModule.<\/p>\n<p>The techniques covered in this article will work for most two-tier applications, but what about three-tier applications? In Part 2, I will cover moving web services using Windows authentication to Azure App Service.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>App Dev Manager\u00a0Mike Lapierre explores authentication options when moving legacy ASP.NET apps to Azure App Services. When attempting to move legacy ASP.NET apps to Azure App Service, you might encounter a few challenges which are documented here. I want to cover specially the use Windows authentication which is not supported in Azure App Service. Let\u2019s [&hellip;]<\/p>\n","protected":false},"author":582,"featured_media":36533,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[25,55],"tags":[53,67,149,3],"class_list":["post-36532","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","category-web","tag-app-services","tag-asp-net","tag-authentication","tag-team"],"acf":[],"blog_post_summary":"<p>App Dev Manager\u00a0Mike Lapierre explores authentication options when moving legacy ASP.NET apps to Azure App Services. When attempting to move legacy ASP.NET apps to Azure App Service, you might encounter a few challenges which are documented here. I want to cover specially the use Windows authentication which is not supported in Azure App Service. Let\u2019s [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/36532","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/582"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=36532"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/36532\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/36533"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=36532"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=36532"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=36532"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}