{"id":3024,"date":"2014-10-09T00:01:04","date_gmt":"2014-10-09T07:01:04","guid":{"rendered":"http:\/\/www.cloudidentity.com\/blog\/?p=3024"},"modified":"2014-10-09T00:04:52","modified_gmt":"2014-10-09T07:04:52","slug":"the-use-of-azure-ad-behind-deploy-to-azure","status":"publish","type":"post","link":"https:\/\/www.cloudidentity.com\/blog\/2014\/10\/09\/the-use-of-azure-ad-behind-deploy-to-azure\/","title":{"rendered":"The use of Azure AD Behind &ldquo;Deploy to Azure&rdquo;"},"content":{"rendered":"<p>About one week ago I got a mail from my good friend Brady, who was looking for some clarifications about our <a href=\"https:\/\/github.com\/AzureADSamples\/WebApp-WebAPI-MultiTenant-OpenIdConnect-DotNet\">Azure AD multitenant web app sample<\/a>. That piqued my curiosity: Brady doesn\u2019t stay still for one sec and we chat about identity all the time, but multitenancy?<\/p>\n<p>As it turns out, he was cooking a really awesome project: a way of fast-tracking deployments of GitHub repos to new or existing Azure web sites. As of this morning, he release the project\u2019s bits and <a href=\"http:\/\/www.bradygaster.com\/post\/the-deploy-to-azure-button\">blogged about it<\/a>.<br \/>\nYou should really head to <a href=\"http:\/\/www.bradygaster.com\/post\/the-deploy-to-azure-button\">Brady\u2019s blog<\/a> and check out the details of the project. In this post I\u2019ll add some color to its identity backstory.<\/p>\n<h2>Deploy to Azure and Azure AD\u2019s Multitenancy Features<\/h2>\n<p>The idea behind Deploy to Azure is beautifully simple.<br \/>\nSay that you have the source of a great web app in a GitHub repo, and that you want to make extra easy for anybody to deploy your web app in their own Azure web site.<br \/>\nDeploy to Azure provides you with a simple button which will do just that, all you need to do is adding it to your repo. The button is in fact just an affordance for following a deep link, which points to a web application.<br \/>\nThe web app will start by asking you to authenticate with your Azure AD credentials \u2013 the ones corresponding to your Azure subscription (more about this later). If you happen to be already authenticated, you\u2019ll skip this step and find yourself single-signed-on in the app right away.<br \/>\nThe app will ask you some basic questions about your deployment, such as the name of the Azure web site you want to target. Done that, by clicking the \u201cDeploy\u201d button you\u2019ll trigger the web site creation (if necessary) and subsequent deployment. Straight from a public GitHub repository to an Azure web site of your choosing!<\/p>\n<p>Pretty neat, right? Once again, I encourage you to visit <a href=\"http:\/\/www.bradygaster.com\/post\/the-deploy-to-azure-button\">Brady\u2019s blog<\/a> to learn abut all the MAML (Microsoft Azure Management Libraries) magic that powers this sample.<\/p>\n<p>That said, let\u2019s see what makes Deploy to Azure tick from the identity perspective.<\/p>\n<h3>Signing In<\/h3>\n<p>The web app that makes all this possible is a fork of our <a href=\"https:\/\/github.com\/AzureADSamples\/WebApp-WebAPI-MultiTenant-OpenIdConnect-DotNet\">Azure AD multitenant web app sample<\/a>.<br \/>\nDeploy to Azure is significantly simpler than the original sample, given that it only manipulates 1st party resources &#8211; that is, Microsoft Azure management API. The original sample shows you how to protect your own resources, hence it contains code that is necessary for representing those resources and restricting access only to known users. In Deploy to Azure the authorization logic is applied automatically \u2013 Azure already knows what users can deploy to web sites, hence we dispensed of all the onboarding logic and associated custom validations.<\/p>\n<p>The sign in flow is enabled by the brand new ASP.NET OWIN OpenId Connect (OIDC) middleware. If you navigate to App_start\/startup.auth.cs, you\u2019ll locate right away the crucial bits carrying the sign on configuration:<\/p>\n<pre class=\"csharpcode\">app.UseOpenIdConnectAuthentication( \r\n  <span class=\"kwrd\">new<\/span> OpenIdConnectAuthenticationOptions \r\n  { \r\n    ClientId = clientId, \r\n    Authority = Authority, \r\n    TokenValidationParameters = <span class=\"kwrd\">new<\/span> System.IdentityModel.Tokens.TokenValidationParameters \r\n    { \r\n         <span class=\"rem\">\/\/ instead of using the default validation (validating against a single issuer value, as we do in line of business apps),  <\/span>\r\n         <span class=\"rem\">\/\/ we inject our own multitenant validation logic <\/span>\r\n         ValidateIssuer = <span class=\"kwrd\">false<\/span>, \r\n      }, \r\n<span class=\"rem\">\/\/ ...other stuff<\/span>\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Here there\u2019s the interesting bit about multitenancy.<br \/>\nIn the simplest case, apps configured to use Azure AD are set up to work with ONE specific directory tenant. That\u2019s the typical line of business app scenario: a contoso.com developer creates one app and wants to make it available to all his\/her contoso.com colleagues. In that case, the value of Authority would be \u201chttps:\/\/login.windows.net\/contoso.com\u201d and the OIDC middleware would make sure that only users presenting tokens issued by contoso.com\u2019s Azure AD tenant would be accepted.<\/p>\n<p>That would be too restrictive for Deploy to Azure: here we want to be able to accept anybody who has a valid Azure AD account, no matter from which directory he\/she comes from. We relax the default issuer validation policy via that <span style=\"font-family: Consolas;\">TokenValidationParameter<\/span> init you saw in the snippet above: not checking for any particular issuer means that we will be accepting tokens from any Azure AD tenant.<br \/>\nThat solves the validation part, but we still need to do something about the Authority.<br \/>\nAzure AD exposes a special endpoint, referred to as \u201ccommon\u201d, of the form \u201chttps:\/\/login.windows.net\/common\u201d. \u201cCommon\u201d makes it possible to gather user credentials without having to decide in advance from which Azure AD tenant he\/she comes from. All you need to do is using the common endpoint as Authority, and the app is configured to accept tokens from any Azure AD user without the need for you to understand anything of the following explanations. I am adding those in case you really want to understand what\u2019s going on in there.<\/p>\n<p>I described the common endpoint in details in <a href=\"https:\/\/www.cloudidentity.com\/blog\/2014\/08\/26\/the-common-endpoint-walks-like-a-tenant-talks-like-a-tenant-but-is-not-a-tenant\/\">this other post<\/a>. Here I\u2019ll offer a super quick explanation of how the mechanism works, in part because that\u2019s useful knowledge if you often write multitenant apps against AAD and in part because it will make it easier later in the post to explain why Deploy to Azure currently suffers from an important limitation.<\/p>\n<p>Here there\u2019s a rough diagram of how the common endpoint sign in works. I am assuming that the user is not already signed in \u2013 you can easily derive the behavior in that case by considering that steps 1 to 3 would take place automatically, without showing any UX to the user.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/10\/image1.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/10\/image_thumb1.png\" alt=\"image\" width=\"813\" height=\"548\" border=\"0\" \/><\/a><\/p>\n<p>1 \u2013 The user clicks on the Deploy to Azure button. That triggers a link that leads to a protected action on the Deploy to Azure web app, which in turns generate a web sign in request via the common endpoint.<\/p>\n<p>2 \u2013 Azure AD serves back a generic credential gathering experience.<\/p>\n<p>3 \u2013 As the user types the username, Azure AD <em>infers<\/em> the actual Azure AD tenant from which the user is from. Depending on the nature of the tenant, this might affect the experience: for example, if contoso is what we call a federated tenant (that is to say, its directory is a cloud projection of an on-premises one) then the auth flow would be directed to the local contoso ADFS instance.<\/p>\n<p>4 \u2013 With the tenant correctly identified, the user is authenticated and the requested token is issued by the target tenant. That token is what the OWIN middleware was waiting for to declare the caller signed in.<br \/>\nNote that, the first time this flow takes place, the user will be informed about what resources and permissions Deploy to Azure is requesting: actual issuance of the token wil depend on whether the user grants or deny consent. I didn\u2019t depict this part for simplicity.<\/p>\n<p>That\u2019s pretty neat! As mentioned earlier, if your app were to fa\u00e7ade your own resources you might want to add extra checks on from which tenant the user is coming from \u2013 see the <a href=\"https:\/\/github.com\/AzureADSamples\/WebApp-WebAPI-MultiTenant-OpenIdConnect-DotNet\">original sample<\/a> for that &#8211; but for Deploy to Azure that\u2019s all we need to do for web sign on.<\/p>\n<h3>Obtaining a Token for Accessing the Azure Management API<\/h3>\n<p>The web sign on is only the beginning. Deploy to Azure needs to be able to invoke the Azure management API. In order to do so, it needs to acquire an access token with the right permissions.<\/p>\n<p>OpenId Connect offers a great hybrid flow that non only signs the user in a web application, but at the same time it also obtains an authorization code that can be redeemed for access and refresh tokens for a resource of your choice.<\/p>\n<p>You can see the code redemption logic in action in the <span style=\"font-family: Consolas;\">AuthorizationCodeReceived<\/span> notification, once again in startup.auth.cs. ADAL makes it really easy, hiding all of the underlying protocol complexity and saving the tokens in a distributed cache that can later be accessed from anywhere in the web application. The initial access and refresh tokens obtained are for the Graph API, while Deploy to Azure needs tokens for the Azure management API: however, thanks to the fact that all refresh tokens issued by Azure AD today are <a href=\"https:\/\/www.cloudidentity.com\/blog\/2013\/10\/14\/adal-windows-azure-ad-and-multi-resource-refresh-tokens\/\">multi-resource refresh tokens<\/a>, having those initial tokens in the cache allows Deploy to Azure to silently (e.g. without user prompts) obtain all the other tokens it needs. You can observe that principle in action in the <span style=\"font-family: Consolas;\">DeployController<\/span>, where the <span style=\"font-family: Consolas;\">Index<\/span> action taps onto the common token cache to get the tokens it needs for performing its Azure management magic. For details about that, see <a href=\"http:\/\/www.bradygaster.com\/post\/the-deploy-to-azure-button\">Brady\u2019s post<\/a>.<\/p>\n<h2>Known Limitations &amp; Workarounds<\/h2>\n<p>Deploy to Azure is a super early preview, as Brady mentions. Here I\u2019d like to dig a bit in a shortcoming that you are pretty likely to notice: in its current form, Deploy to Azure will not work with a MSA (formerly known as LiveID) account, even if that MSA is a global administrator of your Azure AD and subscription.<\/p>\n<p>The root cause of this comes from the use of the common endpoint and the fact that today knowing the MSA of a user is not enough to infer which Azure AD tenant should issue the requested token. Below you can find a version of the earlier sign on diagram, modified to show what happens when you use an MSA.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/10\/image2.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/10\/image_thumb2.png\" alt=\"image\" width=\"792\" height=\"423\" border=\"0\" \/><\/a><\/p>\n<p>1 \u2013 The user clicks on the Deploy to Azure button. That triggers a link that leads to a protected action on the Deploy to Azure web app, which in turns generate a web sign in request via the common endpoint.<\/p>\n<p>2 \u2013 Azure AD serves back a generic credential gathering experience.<\/p>\n<p>3 \u2013 As the user types the username, Azure AD <em>infers<\/em> that the user comes from MSA and redirects accordingly. Here the suer successfully authenticates.<\/p>\n<p>4 \u2013 The flow goes back to AAD, carrying a token proving that the user successfully authenticated with MSA. However, that does not help Azure AD to decide which tenant should issue the token to Deploy to Azure! AN MSA user is not tied to any specific AAD tenant, and in fact can be a guest in many (as depicted). Currently Azure AD does not know how to eliminate the ambiguity, and fails to issue a token.<\/p>\n<p>The main workaround available today entails avoiding the use of common. That can be achieved in different ways:<\/p>\n<p>A \u2013 if you want to offer the feature to your own organization, or any known organization, you can fork the code and use the specific organization identifier in lieu of common. Once that happens, you can safely use guest MSAs as there is no doubt on which tenant should issue the token.<\/p>\n<p>B \u2013 this is a bit more elaborate. Instead of automatically triggering authentication upon accessing Deploy to Azure, you could offer one experience that asks the user for the tenant (in form of its domain) that they want to use. You could then inject that back in the Authority, basically getting back to A. You might even create a tracking cookie to pick up that choice automatically the next time around.<\/p>\n<p>I hope that the issue will be fixed, but hopefully those workarounds will get you going if you want to kick the tires with the app!<\/p>\n<h2>Next Steps<\/h2>\n<p>Working with Brady is always a lot of fun! I am excited to see Deploy to Azure making use of Azure AD and ADAL features to enable such compelling scenario, and I can\u2019t wait to see how the project will evolve with your contributions <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-smile\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/10\/wlEmoticon-smile1.png\" alt=\"Smile\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>About one week ago I got a mail from my good friend Brady, who was looking for some clarifications about our Azure AD multitenant web app sample. That piqued my curiosity: Brady doesn\u2019t stay still for one sec and we chat about identity all the time, but multitenancy? As it turns out, he&#8230;<\/p>\n","protected":false},"author":1,"featured_media":3020,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-3024","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/3024","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/comments?post=3024"}],"version-history":[{"count":2,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/3024\/revisions"}],"predecessor-version":[{"id":3026,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/3024\/revisions\/3026"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media\/3020"}],"wp:attachment":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media?parent=3024"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/categories?post=3024"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/tags?post=3024"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}