ADAL, Native Apps and the “Application Not Found in Directory” Error

It’s been a little while since I’ve written a Native Azure AD app, but as I was doing so today I got poked in the eye again.  I was logging in and using my app no problem with an account from the same tenant where the app was registered in Azure AD.  However when I tried logging in with a user from a different tenant, it failed with the error message “Application with identifier xxx was not found in the directory ‘foo.com'”.

I’ve seen that before but it’s been so long that I had to do some hunting around.  I temporarily was sent off course by a suggestion I found (that seemed strangely familiar) to set the oauth2AllowImplicitFlow property to true.  That turned out to not matter at all, but it did at least get me to take a look at the manifest, rather than at the application properties in the Azure portal.

Once in the manifest I found the property that needed to be updated:  availableToOtherTenants.  Set that to true, tried my app again, and my login with a user from a different tenant worked great.  Just thought I would add this to the blog in case you get stuck in the same spot.  These things always seem to take a bit of effort to figure out.

 

YARBACS or Yet Another RBAC Solution

RBAC is all the rage (as it should be) these days, but it’s not really new.  The concepts have been in use for many years, it’s just a case of bringing it into modern cloud-based scenarios.  Azure continues to invest in this concept so that we can increasingly lock down the control and use of various cloud-based services they offer.  There’s other “interesting” aspects to these scenarios though that can impact the availability and usefulness of it – things such as existing systems and identities, cross tenant applications, etc.

It’s these interesting aspects that bring me to this post today.  At Office365Mon we are ALL about integration with Azure Active Directory and all of the goodness it provides.  We also have had from day 1 the concept of allowing users from different tenants to be able to work on a set of resources using a common security model.  That really means that when you create Office365Mon subscriptions, you can assign subscription administrators to anyone with an Azure AD account.  It doesn’t require Azure B2C, or Azure B2B, or any kind of trust relationship between organizations.  It all “just works”, which is exactly what you want.  IMPORTANT DISCLAIMER:  the RBAC space frequently changes.  You should check in often to see what’s provided by the service and decide for yourself what works best for your scenario.

“Just works” in this case started out being really just a binary type operation – depending on who you are, you either had access or you didn’t.  There was no limited access based on one or more roles that you had.  As we got into more complex application scenarios it became increasingly important to develop some type of RBAC support capabilities, but there really wasn’t an out of the box solution for us.  That led us to develop this fairly simple framework of YARBACS as I call it, or “Yet Another RBAC Solution”.  It’s not a particularly complicated approach (I don’t think) so I thought I’d share the high level details here in case it may help those of you who are living with the same sort of constraints that we have.  We have a large existing user base, everyone is effectively a cloud user to us, we don’t have any type of trust relationship with other Azure AD tenants, but we need to be able to support a single resource (Office365Mon subscription) to be managed by users from any number of tenants and with varying sets of permissions.

With that in mind, these are the basic building blocks that we use for our YARBACS:

  1. Enable support for Roles in our Azure AD secured ASP.NET application
  2. Create application roles in our AD tenant that will be used for access control
  3. Store user and role relationships so that it can be used in our application
  4. Add role attributes to views, etc.
  5. Use a custom MVC FilterAction to properly populate users from different tenants with application roles from our Azure AD tenant

Let’s walk through each of these in a little more detail.

 

Enable Support for Roles

Enabling support for roles in your Azure AD secured application is something that has been explained very nicely by Dushyant Gill, who works as a PM on the Azure team.  You can find his blog explaining this process in more detail here:  http://www.dushyantgill.com/blog/2014/12/10/roles-based-access-control-in-cloud-applications-using-azure-ad/.   Rather than trying to plagiarize or restate his post here, just go read his.  J   The net effect is that you will end up with code in your Startup.Auth.cs class in your ASP.NET project that looks something like this:

app.UseOpenIdConnectAuthentication(

new OpenIdConnectAuthenticationOptions

{

ClientId = clientId,

Authority = Authority,

TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters

{

//for role support

RoleClaimType = “roles”

},

… //other unrelated stuff here

Okay, step 1 accomplished – your application supports the standard use of ASP.NET roles now – permission demands, IsInRole, etc.

 

Create Application Roles in Azure AD

This next step is also covered in Dushyant’s blog post mentioned above.  I’ll quickly recap here, but for complete steps and examples see Dushyant’s blog post.  Briefly, you’ll go to the application for which you want to use YARBACS and create applications roles.  Download the app manifest locally and add roles for the application – as many as you want.  Upload the manifest back to Azure AD, and now you’re ready to start using them.  For your internal users, you can navigate to the app in the Azure management portal and click on the Users tab.  You’ll see all of the users that have used your app there.  You can select whichever user(s) you want to assign to an app role and then click on the Assign button at the bottom.  The trick of course is now adding users to these groups (i.e. roles) when the user is not part of your Azure AD tenant.

 

Store User and Role Relationships for the Application

This is another step that requires no rocket science.  I’m not going to cover any implementation details here because it’s likely going to be different for every company in terms of how and what they implement it.  The goal here is simple though – you need something – like a SQL database – to store the user identifier and the role(s) that user is associated with.

In terms of identifying your user in code so you can look up what roles are associated with it, I use the UPN.  When you’ve authenticated to Azure AD you’ll find the UPN is in the ClaimsPrincipal.Current.Identity.Name property.  To be fair, it’s possible for a user’s UPN to change, so if you find that to be a scenario that concerns you then you should use something else.  As an alternative, I typically have code in my Startup.Auth.cs class that creates an AuthenticationResult as part of registering the application in the user’s Azure AD tenant after consent has been given.  You can always go back and look at doing something with the AuthenticationResult’s UserInfo.UniqueId property, which is basically just a GUID that identifies the user in Azure AD and never changes, even if the UPN does.

Now that you have the information stored, when we build our MVC ActionFilter we’ll pull this data out to plug into application roles.

 

Add Role Attributes to Views, Etc.

This is where the power of the ASP.NET permissions model and roles really comes into play.  In step 1 after you follow the steps in Dushyant’s blog, you are basically telling ASP.NET that anything in the claim type “roles” should be considered a role claim.  As such, you can start using it the way you would any other kind of ASP.NET role checking.  Here are a couple of examples:

  • As a PrincipalPermission demand – you can add a permission demand to a view in your controller (like an ActionResult) with a simple attribute, like this:  [PrincipalPermission(SecurityAction.Demand, Role = “MyAppAdmin”)].  So if someone tries to access a view and they have not been added to the MyAppAdmin role (i.e. if they don’t have a “roles” claim with that value), then they will get denied access to that view.
  • Using IsInRole – you can use the standard ASP.NET method to determine if a user is in a particular role and then based on that make options available, hide UI, redirect the user, etc. Here’s an example of that:  if (System.Security.Claims.ClaimsPrincipal.Current.IsInRole(“MyAppAdmin “))…  In this case if the user has the “roles” claim with a value of MyAppAdmin then I can do whatever – enabling a feature, etc.

Those are just a couple of simple and the most common examples, but as I said, anything you can do with ASP.NET roles, you can now do with this YARBACS.

 

Use a Custom FilterAction to Populate Roles for Users

This is really where the magic happens – we look at an individual and determine what roles we want to assign to it.   To start with, we create a new class and have it inherit from ActionFilterAttribute.  Then we override the OnActionExecuting event and plug in our code to look for the roles for the user and assign them.

Here’s what the skeleton of the class looks like:

public class Office365MonSecurity : ActionFilterAttribute

{

public override void OnActionExecuting(ActionExecutingContext filterContext)

{

//code here to assign roles

}

}

Within the override, we plug in our code.  To begin with, this code isn’t going to do any good unless the user is already authenticated.  If they haven’t then I have no way to identify them and look up the roles (short of something like a cookie, which would be a really bad approach for many reasons).  So first I check to make sure the request is authenticated:

if (filterContext.RequestContext.HttpContext.Request.IsAuthenticated)

{

//assign roles if user is authenticated

}

 

Inside this block then, I can do my look up and assign roles because I know the user has been authenticated and I can identify him.  So here’s a little pseudo code to demonstrate:

SqlHelper sql = new SqlHelper();

List<string> roles = sql.GetRoles(ClaimsPrincipal.Current.Identity.Name);

 

foreach(string role in roles)

{

Claim roleClaim = new Claim(“roles”, role);

ClaimsPrincipal.Current.Identities.First().AddClaim(roleClaim);

}

 

So that’s a pretty good and generic example of how you can implement it.  Also, unlike application roles that you define through the UI in the Azure management portal, you can assign multiple roles to a user this way.  It works because they just show up as role claims.  Here’s an example of some simple code to demonstrate:

 

//assign everyone to the app reader role

Claim readerClaim = new Claim(“roles”, “MyAppReader”);

ClaimsPrincipal.Current.Identities.First().AddClaim(readerClaim);

 

//add a role I just made up

Claim madeUpClaim = new Claim(“roles”, “BlazerFan”);

ClaimsPrincipal.Current.Identities.First().AddClaim(madeUpClaim);

This code actually demonstrates a couple of interesting things.  First, as I pointed out above, it adds multiple roles to the user.  Second, it demonstrates using a completely “made up” role.  What I mean by that is that the “BlazerFan” role does not exist in the list of application roles in Azure AD for my app.  Instead I just created it on the fly, but again it all works because it’s added as a standard Claim of type “roles”, which is what we’ve configured our application to use as a role claim.  Here’s a partial snippet of what my claims collection looks like after running through this demo code:

yarbacs

To actually use the FilterAction, I just need to add it as an attribute on the controller(s) where I’m going to use it.  Here’s an example – Office365MonSecurity is the class name of my FilterAction:

[Office365MonSecurity]

public class SignupController : RoutingControllerBase

There you have it.  All of the pieces to implement your own RBAC solution when the current service offering is not necessarily adequate for your scenario.  It’s pretty simple to implement and maintain, and should support a wide range of scenarios.

The New Azure Converged Auth Model and Office 365 APIs

Microsoft is currently working on a new authentication and authorization model that is simply referred to as “v2” in the docs that they have available right now (UPDATE:  they prefer the “v2 auth endpoint”). I decided to spend some time taking a look around this model and in the process have been writing up some tips and other useful information and code samples to help you out as you start making your way through it. Just like I did with other reviews of the new Azure B2B and B2C features, I’m not going to try and explain to you exactly what they are because Microsoft already has a team of humans doing that for you. Instead I’ll work on highlighting other things you might want to know when you actually go about implementing this.

One other point worth noting – this stuff is still pre-release and will change, so I’m going to “version” my blog post here and I will update as I can. Here we go.

Version History

1.0 – Feb. 3, 2016

What it Does and Doesn’t Do

One of the things you should know first and foremost before you jump in is exactly what it does today, and more importantly, what it does not. I’ll boil it down for you like this – it does basic Office 365: email, calendar and contacts. That’s pretty much it today; you can’t even query Azure AD as it stands today. So if you’re building an Office app, you’re good to go.

In addition to giving you access to these Microsoft services, you can secure your own site using this new model. One of the other terms you will see used to describe the model (besides “v2”) is the “converged model”. It’s called the converged model really for two reasons:

  • You no longer need to distinguish between “Work and School Accounts” (i.e. fred@contoso.com) and “Microsoft Accounts” (i.e. fred@hotmail.com). This is probably the biggest achievement in the new model. Either type of account can authenticate and access your applications.
  • You have a single URL starting point to use for accessing Microsoft cloud services like email, calendar and contacts. That’s nice, but not exactly enough to make you run out and change your code up.

Support for different account types may be enough to get you looking at this. You will find a great article on how to configure your web application using the new model here: https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-devquickstarts-dotnet-web/. There is a corresponding article on securing Web API here: https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-webapi-dotnet/.

Once you have that set up, you can see here what it looks like to have both types of accounts available for sign in:

v2App_ConvergedSignIn

The accounts with the faux blue badges are “Work or School Accounts” and the Microsoft logo account is the “Microsoft Account”. Equally interesting is the fact that you can remain signed in with multiple accounts at the same time. Yes! Bravo, Microsoft – well done.  🙂

Tips

Knowing now what it does and doesn’t do, it’s a good time to talk about some tips that will come in handy as you start building applications with it. A lot of what I have below is based on the fact that I found different sites and pages with different information as I was working through building my app. Some pages are in direct contradiction with each other, some are typos, and some are just already out of date. This is why I added the “version” info to my post, so you’ll have an idea about whether / when this post has been obsoleted.

 

Tip #1 – Use the Correct Permission Scope Prefix

You will see information about using permission scopes, which is something new to the v2 auth endpoint. In short, instead of defining the permissions your application requires in the application definition itself as you do with the current model, you tell Azure what permissions you require when you go through the process of acquiring an access token. A permission scope looks something like this: https://outlook.office.com/Mail.Read. This is the essence of the first tip – make sure you are using the correct prefix for your permission scope. In this case the permission prefix is “https://outlook.office.com/” and is used to connect to the Outlook API resource endpoint.  Alternatively your app can also call the Microsoft Graph endpoint under https://graph.microsoft.com, in which case you should use the prefix https://graph.microsoft.com/ for your permission scope.  The net of this tip is fairly simple – make sure you are using the same host name for your permission scopes as you do for your API endpoints.  So if you want to read email messages using the API endpoint of https://outlook.office.com/api/v2.0/me/messages, make sure you use a permission scope of https://outlook.office.com/Mail.Read.  If you mix and match – use a permission scope with a prefix of https://graph.microsoft.com but try to access an API at https://outlook.office.com&#8230; – you will get an access token; however when you try and use it you will get a 401 unauthorized response.

Also…I found in one or more places where it used a prefix of “http://outlook.office.com/”; note that it is missing the “s” after “http”. This is another example of a typo, so just double check if you are copying and pasting code from somewhere.

 

Tip #2 – Not All Permission Scopes Require a Prefix

After all the talk in the previous tip about scope prefixes, it’s important to note that not all permission scopes require a prefix. There are a handful that work today without a prefix: “openid”, “email”, “profile”, and “offline_access”. To learn what each of these permission scopes grants you can see this page: https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-compare/#scopes-not-resources.  One of the more annoying things in reviewing the documentation is that I didn’t see a simple example that demonstrated exactly what these scopes should look like. So…here’s an example of the scopes and how they’re used to request a code, which you can use to get an access token (and refresh token if you include the “offline_access” permission – see, I snuck that explanation in there). Note that they are “delimited” with a space between each one:

string mailScopePrefix = “https://outlook.office.com/&#8221;;

string scopes =
“openid email profile offline_access ” +
mailScopePrefix + “Mail.Read ” + mailScopePrefix + “Contacts.Read ” +
mailScopePrefix + “Calendars.Read “;

string authorizationRequest = String.Format(             “https://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=code+id_token&client_id={0}&scope={1}&redirect_uri={2}&state={3}&response_mode=form_post&nonce={4}”,
Uri.EscapeDataString(APP_CLIENT_ID),
Uri.EscapeDataString(scopes),
Uri.EscapeDataString(redirUri),
Uri.EscapeDataString(“Index;” + scopes + “;” + redirUri),
Uri.EscapeDataString(Guid.NewGuid().ToString()));

//return a redirect response
return new RedirectResult(authorizationRequest);

Also worth noting is that the response_type in the example above is “code+id_token”; if you don’t include the “openid” permission then Azure will return an error when it redirects back to your application after authentication.

When you log in you see the standard sort of Azure consent screen that models the permission scopes you asked for:

v2App_WorkAccountPermsConsent

Again, worth noting, the consent screen actually will look different based on what kind of account you’ve authenticated with. The image above is from a “Work or School Account”. Here’s what it looks like when you use a “Microsoft Account” (NOTE: it includes a few more permission scopes than the image above):

v2App_OutlookAccountPermsConsent

For completeness, since I’m sure most folks today use ADAL to get an access token from a code, here’s an example of how you can take the code that was returned and do a POST yourself to get back a JWT token that includes the access token:

public ActionResult ProcessCode(string code, string error, string error_description, string resource, string state)

{
string viewName = “Index”;

if (!string.IsNullOrEmpty(code))
{

string[] stateVals = state.Split(“;”.ToCharArray(),

StringSplitOptions.RemoveEmptyEntries);

viewName = stateVals[0];
string scopes = stateVals[1];
string redirUri = stateVals[2];

//create the collection of values to send to the POST
List<KeyValuePair<string, string>> vals =
new List<KeyValuePair<string, string>>();

vals.Add(new KeyValuePair<string, string>(“grant_type”, “authorization_code”));
vals.Add(new KeyValuePair<string, string>(“code”, code));
vals.Add(new KeyValuePair<string, string>(“client_id”, APP_CLIENT_ID));
vals.Add(new KeyValuePair<string, string>(“client_secret”, APP_CLIENT_SECRET));
vals.Add(new KeyValuePair<string, string>(“scope”, scopes));
vals.Add(new KeyValuePair<string, string>(“redirect_uri”, redirUri));

string loginUrl = “https://login.microsoftonline.com/common/oauth2/v2.0/token&#8221;;

//make the request
HttpClient hc = new HttpClient();

//form encode the data we’re going to POST
HttpContent content = new FormUrlEncodedContent(vals)

//plug in the post body
HttpResponseMessage hrm = hc.PostAsync(loginUrl, content).Result;

if (hrm.IsSuccessStatusCode)
{
//get the raw token
string rawToken = hrm.Content.ReadAsStringAsync().Result;

//deserialize it into this custom class I created
//for working with the token contents
AzureJsonToken ajt =
JsonConvert.DeserializeObject<AzureJsonToken>(rawToken);
}
else
{
//some error handling here
}
}
else
{
//some error handling here
}

return View(viewName);

}

One note – I’ll explain more about the custom AzureJsonToken class below.  To reiterate Tips #1 and 3, since my permission scope is based on the host name outlook.office.com, I can only use the access token from this code with the Outlook API endpoint, such as https://outlook.office.com/api/v1.0/me/messages or https://outlook.office.com/api/v2.0/me/messages.  Yes, that is not a typo, you should be able to use the access token against either version of the API.

 

Tip #3 – Use the Correct Service Endpoint

Similar to the first tip, I saw examples of articles that talked about using the v2 auth endpoint but used a Graph API permission scope with a Outlook API endpoint. So again, to be clear, make sure your host names are consistent between the permission scopes and API endpoints, as explained in Tip #1.

 

Tip #4 – Be Aware that Microsoft Has Pulled Out Basic User Info from Claims

One of the changes that Microsoft made in v2 of the auth endpoint is that they have arbitrarily decided to pull out most meaningful information about the user from the token that is returned to you. They describe this here – https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-compare/:

In the original Azure Active Directory service, the most basic OpenID Connect sign-in flow would provide a wealth of information about the user in the resulting id_token. The claims in an id_token can include the user’s name, preferred username, email address, object ID, and more.

We are now restricting the information that the openid scope affords your app access to. The openid scope will only allow your app to sign the user in, and receive an app-specific identifier for the user. If you want to obtain personally identifiable information (PII) about the user in your app, your app will need to request additional permissions from the user.

This is sadly classic Microsoft behavior – we know what’s good for you better then you know what’s good for you – and this horse has already left the barn; you can get this info today using the v1 auth endpoint. Never one to be deterred by logic however, they are pressing forward with this plan. That means more work on you, the developer. What you’ll want to do in order to get basic user info is a couple of things:

  1. Include the “email” and “profile” scopes when you are obtaining your code / token.
  2. Ask for both a code and id_token when you redirect to Azure asking for a code (as shown in the C# example above).
  3. Extract out the id_token results into a useable set of claims after you exchange your code for a token.

On the last point, the Microsoft documents say that they provide a library for doing this, but did not include any further detail about what it is or how you use it, so that was only marginally helpful. But hey, this is a tip, so here’s a little more. Here’s how you can extract out the contents of the id_token:

  1. Add the Security.IdentityModel.Tokens.Jwt NuGet package to your application.
  2. Create a new JwtSecurityToken instance from the id_token. Here’s a sample from my code:

JwtSecurityToken token = new JwtSecurityToken(ajt.IdToken);

  1. Use the Payload property of the token to find the individual user attributes that were included. Here’s a quick look at the most useful ones:

token.Payload[“name”] //display name
token.Payload[“oid”] //object ID
token.Payload[“preferred_username”] //upn usually
token.Payload[“tid”] //tenant ID

As noted above though in my description of the converged model, remember that not every account type will have every value. You need to account for circumstances when the Payload contents are different based on the type of account.

 

Tip #5 – Feel Free to Use the Classes I Created for Deserialization

I created some classes for deserializing the JSON returned from various service calls into objects that can be used for referring to things like the access token, refresh token, id_token, messages, events, contacts, etc. Feel free to take the examples attached to this posting and use them as needed.

Microsoft is updating its helper libraries to use Office 365 objects with v2 of the app model so you can use them as well; there is also a pre-release version of ADAL that you can use to work with access tokens, etc. For those of you rolling your own however (or who aren’t ready to fully jump onto the pre-release bandwagon) here are some code snippets from how I used them:

//to get the access token, refresh token, and id_token
AzureJsonToken ajt =
JsonConvert.DeserializeObject<AzureJsonToken>(rawToken);

This next set is from some REST endpoints I created to test everything out:

//to get emails
Emails theMail = JsonConvert.DeserializeObject<Emails>(data);

//to get events
Events theEvent = JsonConvert.DeserializeObject<Events>(data);

//to get contacts
Contacts theContact = JsonConvert.DeserializeObject<Contacts>(data);

You end up with a nice little dataset on the client this way. Here’s an example of the basic email details that comes down to my client side script:

v2App_MessageCollection

Finally, here’s it all pulled together, in a UI that only a Steve could love – using the v2 app model, some custom REST endpoints and a combination of jQuery and Angular to show the results (yes, I really did combine jQuery and Angular, which I know Angular people hate):

Emails

v2App_Emails

Events

v2App_Events

Contacts

v2App_Contacts

Summary

The new auth endpoint is out and available for testing now, but it’s not production ready. There’s actually a good amount of documentation out there – hats off to dstrockis at Microsoft, the writer who’s been pushing all the very good content out. There’s also a lot of mixed and conflicting documents though so try and follow some of the tips included here. The attachment to this posting includes sample classes and code so you can give it a spin yourself, but make sure you start out by at least reading about how to set up your new v2 applications here: https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-app-registration/. You can also see all the Getting Started tutorials here: https://azure.microsoft.com/en-us/documentation/articles/active-directory-appmodel-v2-overview/#getting-started. Finally, one last article that I recommend reading (short but useful): https://msdn.microsoft.com/en-us/office/office365/howto/authenticate-Office-365-APIs-using-v2.
You can download the attachment here:

Know When Your Azure Identity Won’t Work with Office 365 APIs

As those of you who are familiar with Office365Mon know, we heavily leverage the Office 365 APIs in our solution.  It’s been a key player in being able to issue now over 100 million health probes against Office 365.  I know and have talked to lots of you as well that are starting to build apps that leverage this same infrastructure for your own solutions.  As you develop these solutions based on the Office 365 APIs, it’s pretty important that you understand the scenarios where the Azure access token you get will and will not work to access Office 365 resources.

First, a couple of basics.  When you get an access token, for purposes of our conversation here today, the token represents your identity that is going to be used to access a resource in some way.  There are exceptions to this, i.e. app only tokens, but this post is about user identities and Office 365.  When you try and access a resource, you say here is my access token, I want do this with the content – for example, I am Steve, I want to read the email in my inbox.

The problem is this – what I just described is a common scenario, and it works well today with the Office 365 APIs.  But there are actually at least four scenarios, and you may be surprised to learn that the Office 365 APIs only work with one of them.  Part of the reason in writing this blog post is to make sure you all are aware of that, but also to hopefully drive a discussion with the folks that own the service so that they can give some consideration to expanding their support of these other scenarios in the future.  Here’s a quick run down on the scenarios that I’ve looked at so far; there may be others.

  1. I own or otherwise have direct rights to a resource – WORKS!  This is the first scenario I described above – for example, when I want to access the email in my inbox, or if I’m part of a SharePoint group in my Office 365 tenant and I want to access content in that site.
  2. I have been granted delegate rights to a mailbox – DOESN’T WORK!  In this scenario, I’ve been granted rights to another mailbox.  Now if open up Outlook for example I can read the mail in that mailbox no problem.  If I’m using the Exchange Web Services (EWS), I can access the mail in that mailbox.  But if I’m using the Office 365 APIs, it doesn’t work.
  3. I have been invited to a SharePoint Online site – DOESN’T WORK!  In this scenario I’ve been invited as an external user to a SharePoint Online site.  I use my Azure AD credentials to accept the invitation and I can connect to the site in the browser.  However if I try and use an Azure access token against that resource it fails with an access denied error.
  4. I have been added to an Azure tenant using the Azure B2B feature – DOESN’T WORK!  This is similar to #3 – after being added to the Azure tenant with the B2B feature I can be added to a SharePoint Online site and access it just fine in the browser.  However my Azure access token will only get me an access denied error if I try and use it on that site with the Office 365 APIs.

The key and common thread in all of these scenarios is that I am using my Azure AD identity.  It is a durable, immutable identity containing an immutable identifier known to Azure AD.  Even though I’m using that immutable identity, there is still a disconnect between it and all of the ways in which it has been granted access to resources in Office 365.  That is to say, there is a disconnect in the Office 365 APIs; in the browser applications they have this figured out.  Make sure you know these limitations, and let your favorite Microsoft human if you would like to these disconnects eliminated for a comprehensive and integrated identity and resource solution.

 

Invalid Client Secret when Publishing Azure AD Secured Apps

Back to my old nemesis…the long very long blog post title.  🙂   I ran across this problem myself recently, and had seen someone else experience but not had the time to dig into it.  In short the problem goes something like this – you create a new ASP.NET web application in Visual Studio 2015.  You configure it to be secured with Azure AD (i.e. Work and School accounts).  You do your thing, you build your web site, you test it locally, you can authenticate and everything works fine – great!

Now you want to deploy the app to your Azure web site.  You go through the publishing wizard, which pushes the content up to your web site.  It launches the browser for you to log in and check out your site but – boom – your app blows up.  After you authenticate it redirects you back to your site and you get the dreaded yellow page of death (i.e. an unhandled exception).  When you turn customErrors to Off in web.config you can see the error is “invalid client secret”.  You know it works fine when you run it on your local machine, so how can it be invalid?

This is the question that plagued me for a couple of days before I finally had the time to completely unwind it.  This post is partially “here’s how you fix it” and partially “this is why I think it happens”.  In the two cases where I’ve seen this happen so far, the project started out targeting .NET 4.52, then was subsequently changed to 4.61.  I noticed that the publishing wizard changes the UI slightly when you do that.

When targeting 4.52 the wizard includes a checkbox that says “Enable Organizational Accounts”.  The default behavior is to have that box checked.  I always uncheck it because my “organizational account” configuration is completed when I’m building and testing the application.  When targeting 4.61 I no longer see this option in the UI.

So here’s the fix and here’s the guess at what’s wrong.  If you look in the Properties folder in your project you will find one or more .pubxml files, which represent your publishing profiles.  In this case, the .pubxml file contained a completely different ClientId and ClientSecret value than my web.config did.  It was that client ID and secret that was getting pushed up to the Azure web site, and that’s why my application blew up once it was published to Azure.  To fix it, I just manually copied the ID and secret from my web.config into my .pubxml file.

Now…my guess as to why I think it happens (I deleted some stuff before I could actually verify this), I think when you have that box checked in the wizard when targeting 4.5.2, Visual Studio creates a new application definition in Azure AD, and then pulls in the client ID and secret from it into the publishing wizard.  That would explain how the wrong client ID and secret gets published and “stuff breaks”.

Anyways, if you run across this problem hopefully you’ll find this post.  Good luck!

Azure B2B First Look

This is a companion piece to the Azure B2C First Look I published last week. This post is some first thoughts around the new Azure B2B features that were recently announced. The goal of Azure B2B is to reduce the complexity and rigidity of managing business to business relationships and sharing data. The announcement around the B2B feature correctly characterizes this problem as typically being solved either by federating between two companies, or creating a directory (or OU or whatever) in your own internal directory for external users. Both solutions have pros and cons to them. The Azure B2B solution is what I would consider something of a hybrid approach between the two. External users continue to use their one and only external account for authentication so they don’t have to remember multiple account names and passwords. However, they also get added (maybe “linked” is a better way to describe it) within the Azure AD tenant into which they are “added” (a process I’ll explain below). Overall though, even in preview it’s a pretty painless and easy way to connect people up from different organizations.

As with the Azure B2C post, I’m not going to try and explain every bit of the feature and how to configure it – Microsoft has a team of writers tasked with just that. Instead I’ll give you a few links to get started and then share some real world experience now with how it looks and works. So…to get started I would recommend taking a look at this content:

 

Getting Started

The process for getting started is a little peculiar, but there is a certain logic to it. In short, when you want to allow users from other companies to access your resources, you have to create a CSV file with information about them and import that into Azure AD, which you can do via the portal. In fact PowerShell support for doing this is not there at this time, but I’ll be a little surprised if it doesn’t show up by RTM. This is where the second link above will be useful to you – it explains the format of the CSV file you need to create and provides an example of what it looks like.

In my case, for my first test I started with my SamlMan.Com tenant and built out a simple ASP.NET MVC application secured with Azure AD. I got that all working and then invited my Office365Mon.Com account. The CSV for it looked something like this:

Email,DisplayName,InviteAppID,InviteReplyUrl,InviteAppResources,InviteGroupResources,InviteContactUsUrl

speschka@office365mon.com,Office365Mon Steve,FFEAF5BD-528B-4B53-8324-E4A94C1F0F06,,65b11ba2-50f7-4ed2-876d-6a29515904b2,,http://azure.microsoft.com/services/active-directory/

The main things worth pointing out in this simple CSV is the display name I gave – Office365Mon Steve – because that’s how it’s going to show up in the SamlMan.Com AD tenant. Also the GUID that starts with 65b11… is the Client ID of my MVC application that I described above. Once you import the CSV file Azure sends an email to everyone in it, and then each person has to open the email, click a link and accept the invitation. You can see a report in Azure of the status of each person you invited.

Here’s what the report looks like:

When you get your invitation email it looks something like this (some additional customization options are available, but for testing I’m waaaaay to lazy to make it look pretty):

You’ll notice the email is addressed to the display name I put into the CSV file. I’ll show the invite pages in Azure a little later. Now, once that the person has accepted the invitation, as I noted above, they show up in the Azure AD tenant from which the invitation was sent. Here’s what my SamlMan.Com directory looks like after the invite was accepted:

Now with the invitation accepted I can log into the ASP.NET application as speschka@office365mon.com and it works just perfectly. Here’s yet another screenshot of my favorite home page, with all of the current user’s claims enumerated on the page:

You can see again that display name of “Office365Mon Steve” getting carried throughout, so make sure you use something that won’t require constant tinkering.

 

Using it with Other Cloud Applications

One of the things I thought was nice was the integration with other cloud applications. Obviously the images above illustrate integrating with my own custom apps, but what about the apps people frequently use in the cloud, like Office 365? Well, it works pretty slick for that as well. To work through this scenario I flipped things around and used my Office365Mon tenant and invited my account at SamlMan.Com. In the SharePoint spirit of things…I started out by creating a new group in my Azure AD tenant, like this:

Next I went to my SharePoint Online site and added this Azure AD group to the SharePoint Viewers group:

Next I got the object ID of the Azure AD group by running this bit of PoweShell: Get-MsolGroup | fl DisplayName, ObjectId. With that in hand, I created a new CSV file to invite my SamlMan.Com user. The CSV file looked like this:

Email,DisplayName,InviteAppID,InviteReplyUrl,InviteAppResources,InviteGroupResources,InviteContactUsUrl

steve@samlman.com,SamlMan Steve,6787E4D5-0159-4B74-B56D-AA7C36715C0E,,,95419596-ff8a-4db1-c406-ed4ad13fd272,https://www.office365mon.com

The most interesting part of this CSV is the GUID that starts with 95419… It’s the object ID of my SharePoint Readers group. Now when my invited user accepts his invitation he or she will get added to that group. I get the standard email invite that I showed above. When I click on the link to accept it, I am treated to a page in Azure that looks like this (you can also customize the appearance of this, which I chose not to do):

Now after I go through the process to accept the invitation, I went back to the Office365Mon SharePoint Online team site and was able to successfully authenticate and get in with Viewer rights:

Wrap Up

Overall everything with the B2B feature went incredibly smoothly with no hiccups or glitches of any kind; most of the Azure guys really seem to have their act together these days. J Honestly, it’s impressive and I know a lot of teams at Microsoft that could really take a lesson from how engaged the Azure team is with the community, taking feedback, and delivering great products. I think the biggest challenge I’m imagining after my first look is just the long-term user management; for example, when an invited user’s account is deleted from its home Azure AD tenant it would be nice to have it trigger deletes in all of the other AD tenants where it’s been invited. Stuff like that…but I think it will come in time. This is very good start however.

Getting an Azure Access Token for a Web Application Entirely in Code

UPDATE 1/13/2016:  The Azure and/or ADAL teams have made an unannounced change to purposely break this functionality.  This is clearly a problem for those providing and provisioning SaaS offerings in a variety of scenarios, but they have chosen to make this change without input.  If you would like to provide your feedback on this you can contact the responsible Program Manager directly at vbertocci@microsoft.com.

I generally find using Azure Active Directory for securing my resources to be a joyous thing, but the simplicity of use is pretty much vastly overstated by the marketing folks at Microsoft. I’ve used it quite a bit and yet still find myself simultaneously in seemingly uncharted and undocumented waters. As is unfortunately a little too common, I found myself in a spot where I really thought I was stuck the other day trying to get an access token for a specific user to a specific resource. I don’t think the scenario is really that uncommon so thought best to share.

The gist of this scenario is, I have an application defined in Azure Active Directory. It’s configured as a web application. That means that you *must* provide the application’s client secret when you request an access token to that application. The “standard” way to do this is to request an authorization code, and then you use the authorization code to get an access token. Okay, fundamentally I can do that and it won’t kill me.   The problem however is the really bad assumption, in my opinion, that you are going to have a human at the wheel, sitting at a browser and driving this thing around. That’s exactly how the process works in this case – users gets redirected to obtain the authorization code, they sign into Azure AD, they consent to whatever permissions the application is configured to use, and then the browser is redirected back again. You end up in some server side code plucking out authorization code from the query string and then using the Active Directory Authentication Library (ADAL) you call it’s AcquireTokenByAuthorizationCode to get your access token.

Okay that will work…as long as the human is sitting there driving. So what happens when the human is absent, and you want to get an access token for that person? Well, one of the ways you can get an access token from an application that is defined as a Native Application is to stick a username and password into a UserCredential and call the AcquireToken method in ADAL. Now I’m not suggesting that everyone should be storing usernames and passwords anywhere (and in fact in most cases I specifically go out of my way to avoid it). However there are certain cases, like where you are writing code that always runs as a service account, or you’re doing some scripting of new users and adding them to applications or application features, etc. Yeah, it’s a legit scenario (otherwise ADAL wouldn’t support this to begin with).

The problem is that while you can take that approach with a Native Application, it won’t work for a Web Application. A Web Application also requires the application’s client secret as explained above. Unfortunately there isn’t an overload in ADAL that supports both the UserCredential and client secret. I thought I was in a no win situation here when I came across this, but managed to work my way out of it so I thought I would share the approach I used. I do end up with an access token when I’m done, and I get it by providing a username, and a password, AND a client secret. I just don’t have to do the whole “drive this through a browser” thing to make it work.

The solution to this problem is that you’ll end up having to go outside of ADAL to get your access token. Instead you’ll need to make a post directly to the Graph API authorization endpoint to ask for your access token. When you do that, you can include whatever form values you want when you do your post. That ends up being the way to get your access token. Here’s a little code to illustrate, and then I’ll follow with some explanation.

//create the collection of values to send to the POST

List<KeyValuePair<string, string>> vals = new List<KeyValuePair<string, string>>();

vals.Add(new KeyValuePair<string, string>(“grant_type”, “password”));

vals.Add(new KeyValuePair<string, string>(“scope”, “openid”));

vals.Add(new KeyValuePair<string, string>(“resource”, ResourceUri));

vals.Add(new KeyValuePair<string, string>(“client_id”, ClientId));

vals.Add(new KeyValuePair<string, string>(“client_secret”, ClientSecret));

vals.Add(new KeyValuePair<string, string>(“username”, Username));

vals.Add(new KeyValuePair<string, string>(“password”, Password));

//create the post Url

//https://login.windows.net/8864cb2f-031a-5c22-fa2d-13d1cf4cb7dd/oauth2/token

string url = string.Format(“https://login.windows.net/{0}/oauth2/token “, TenantId);

//make the request

HttpClient hc = new HttpClient();

//form encode the data we’re going to POST

HttpContent content = new FormUrlEncodedContent(vals);

//plug in the post body

HttpResponseMessage hrm = hc.PostAsync(url, content).Result;

if (hrm.IsSuccessStatusCode)

{

//get the stream

Stream data = await hrm.Content.ReadAsStreamAsync();

}

So as you can see I’m creating a set of form values to send to the oauth endpoint, and I’m doing my post, and if it is successful, I’m reading the contents out into a stream in this case. The rest of the code that is less interesting is where I take that stream and serialize it into a class so I can easily refer to the access token, the refresh token, the expiration, etc. The key to making this work is to understand the various form key/value pairs. This is the “seemingly undocumented” piece I was describing above. You’ll find some documentation on MSDN about this at https://msdn.microsoft.com/en-us/library/azure/dn645542.aspx. Since they only want to focus on the authorization code flow there there, you won’t find a complete listing of all the possible form post keys and possible values of each. Booo!!! Since I don’t have that, I’ll just document for you from my working code above, what those form values represent:

Key Value
resource The resource you are trying to obtain an access token for. If you are trying to access another Azure AD application, then you would use the APP ID URI here. If you are accessing something like Exchange Online, you would use it’s resource URI (which is https://outlook.office365.com/ for those of you following at home).
client_id This is the Client ID of the Azure application you are getting the access token for.
client_secret This is the Client Secret of the Azure application you are getting the access token for.
username This is the name of the Azure AD user for whom you are getting the access token.
password This is the password for the Azure AD user for whom you are getting the access token.
TenantId This is the ID (i.e. GUID) of the Azure Active Directory instance in which the Azure AD user is located.

Calling directly to the token endpoint in the Graph API to obtain an access token is pretty powerful really. I really don’t like resorting to that and only have this time because ADAL just didn’t cover my use case. It would be, dare I say, “idyllic” if someone would actually document all of the values you can throw up there (and/or make it easy to find, because I could not do that despite the indexing power of Bing). Meanwhile, this ends up being a nice way to get the token when you find yourself in this scenario.