on-prem = legacy

Headless Azure AD User Creation

If you’ve spent any time with the Azure Graph API, it’s pretty sweet. Federated identity for the masses, with almost zero drama. Up until now I was mostly doing logins, queries, etc. with Azure AD, but for my latest project, I need to create both new domains and new users in those domains. I haven’t tackled creating new domains yet, because that looks like it’s going to be a royal PITA (automating powershell? ick) – but I kicked down the user path today. Went pretty well, until I got stopped cold adding a user.

Here’s some code

Adding a user with ADALv2 + the Active Directory Graph Client is pretty easy. Both are NuGet packages and simplify the process considerably. You can also post the JSON yourself, which you can find here on MSDN.

But I’m using ADGC, so here’s a quick snip of the required fields you’ll need to get a user created:

var gc = new GraphConnection(accessToken); //get this below
var pp = new PasswordProfile() //required
  ForceChangePasswordNextLogin = true,
  Password = "Watermelon1!"
var u = new User
  DisplayName = displayName,
  UserPrincipalName = upn,
  PasswordProfile = pp,
  MailNickname = displayName.Replace(" ", string.Empty),
  UsageLocation = "US",
  AccountEnabled = true,
  ImmutableId = Guid.NewGuid().ToString()
  var p = gc.Add(u);
  Console.WriteLine("Created {0}, immutable ID: {1}", p.UserPrincipalName, p.ImmutableId);
catch (GraphException ex)
  Console.ForegroundColor = ConsoleColor.Red;
  Console.WriteLine("{0}: {1}", ex.ErrorMessage, ex.ErrorResponse.Error.Message);

Pretty straightforward…until you get to


chances are you’ll blow up with a 403 Forbidden. In fact, chances are high, like 100% this will happen (if it doesn’t let me know).

Graph Read/Write

For whatever reason, and I’m still trying to figure out exactly why, the ‘Read and write directory data’ permission doesn’t appear to allow adding users. I’m assuming this is because they want a user who’s in one of the principal management roles, like User Administrator (see this post for some info on that), as opposed to allowing app principals to do this. The long and short is that the Graph API wants you to go through an OAuth browser flow to delegate a token from a user with the appropriate permissions. If you’re using ADALv2, there’s no


overload that’ll do this. This is fine, unless you want to automate the creation of these users.

What are you to do?

Fortunately, we can use the OAuth password grant_type to request a token with only a user’s username & password.

AccessTokens & the Graph

You’ll need a few things to get setup. I’m not going to go into much detail here, because if you’re encountering this issue chances are you’re already well setup. We need to request a token from the AAD STS, including both the user’s username/password, as well as the client ID and secret of the app you’re developing. Here’s a sample:

var reqUri = " TENANT ID OR NAME/oauth2/token";
var postData = "resource=00000002-0000-0000-c000-000000000000&client_id={0}&grant_type=password&{1}";
var wc = new WebClient();
wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
var response = wc.UploadString(reqUri, "POST", string.Format(postData, AppId, EncodedKey));
var tokenData = JObject.Parse(response);
return tokenData["access_token"].Value();

Let’s deconstruct this request a bit, shall we? TENANT ID OR NAME/oauth2/token

This is where we’re posting our token request


The main chunk of our request.

resource The resource you’re trying to access. In this case, it’s the graph, which always has this ID: 00000002-0000-0000-c000-000000000000
client_id your app’s client ID
client_secret Important – make sure to URL encode your key before putting it here
grant_type password
username your UPN (e.g.,
password this should be obvious
scope Get data in the OpenID Connect format: openid

And make sure you URL encode the form/values before submitting, otherwise it’s 400s for you.

And that’s it

Provided you got a token back and didn’t have any problems with the request, you should be able to tack that access token into the header

Authorization: Bearer ...access token...

or you can stuff that into

new GraphConnection(accessToken)

if you’re using the Graph Client wrapper.

Create away! You’re off.


I’ll be at SharePoint Saturday, come out!

I’ll be speaking at SharePoint Saturday in Charlotte on September 20th. My session is on building a ‘shim’ for passive logon to Microsoft Online Services (Office 365, Azure, any federated apps) so you can do whatever kind of wild and crazy business logic you need to do. Should be fun!

Azure Admins vs. Azure AD Admins

This is a point that’s a bit ambiguous. I’m an Azure Service administrator, so I should be able to access the Azure AD associated with that tenant, right?

In a word, no.


If you need access to Azure Active Directory to add apps, users, etc – it’s pretty simple. It’s something we get a lot whenever one of our clients is using Azure, has granted us Azure service admin rights (E.g., Azure co-administrator), but we’re still asking for more access.

You can do this at the Azure portal ( or, for adding a new user in your org or setting permissions to existing people in your org, the Office 365 Admin Portal (

Your Azure AD administrator (if you’re the creator of the account, this should be you, otherwise it’s time to track down the admin) just needs to add you. You can add

  • A new account in your organization – this creates a brand new account in your Azure AD tenant. No different from creating a new cloud-based user for O365.
  • An existing Microsoft Account – for sharing with the plebs who don’t have an Office account
  • An existing organizational account in another directory - for sharing with other organizations that use Azure AD (e.g., or

Once the account is in Azure AD, you can set an access level. More info on access levels below.

Office Portal

Adding someone from the Office portal is easy. Open the portal as an admin, go to users and get crackin’ – but note, the Office portal only allows you to add users to your own organization. Could you imagine the chaos if you had options to add users from other orgs in here? LOL

office portal

But – you can add rights to an existing user from within the Office portal. Find the user in the list and you can set their access levels in there. Here’s my Live account, which was already added to my AD – I can set admin rights right from the portal.



Azure Portal

You can do everything from in here. Let’s dig in. Head into the Azure portal and find Active Directory in the left nav. If you don’t see your directory and you’re a member of multiple Azure subscriptions, click the Subscriptions filter to make sure you find the right one.

Once you’ve found your directory, click it and go to the Users header – here we’ll add a new user and grant them rights to AD. Alternatively, if you already see the account you want to grant access to, you can do that from in here as well.


Pick one of those three options (they’re outlined above) – if it’s not a valid account for the type you picked, when you try to go the next step, it’ll bomb out:



Otherwise, when you click next, you’ll be able to both set a name & display name for the new user (so that your Xbox name ‘N00b Slay3r 123′ doesn’t show up in your corporate apps) and grant an access level. Once you click the check, that new user is ready to go.


Role Play

Let’s talk about roles for a minute – you can find comparisons of each role here ( – I’m not going to repeat any of that.

Global administrators – if you’re using Azure for anything beyond test/dev, or if you’re using it with Office 365/Intune/CRM, you probably want as few global administrators as possible. The Global part of global administrator is just that – quite global.

So what’s an admin to do when he/she has devs clamoring to add apps? I can’t seem to find anything ‘official’ about what access levels have access to add applications to your Azure AD – but it appears that User administrators do have this right. It makes sense, since ‘user administration’ is really principal administration, and all of these apps are new principals.

If you only want to give your devs access to add new apps, User Administrator might be a good role for them.

DocuSign + SharePoint Online

Document signing + SharePoint Online with non-licensed users flew across my desk at WTFHQ today. Here’s the basic requirement:

Licensed users need to store PDFs in SharePoint while getting them digitally signed by non-licensed SharePoint users. Preferably without requiring creating External Users in SharePoint.

I’m happy to report this works quite easily with DocuSign + SharePoint Online. You’ll get SharePoint doc lib integration e.g., the context menu will offer you options on documents like ‘Sign with DocuSign’ and ‘Get Signatures with DocuSign.’

We’ll start with the main case – a licensed SharePoint user needs to get a document signed by a non-SharePoint user. It’s really easy.

It’s really pretty easy.

When you use the ‘Get Signatures with DocuSign’ option, you’re sent over to DocuSign, where you login (either with your Office 365 account or your DocuSign account), and it’s all vanilla from there – mark the required fields to collection from the target and drop their email addresses into the invitation field.



Document library integration

Invite non-licensed users to sign

Invite non-licensed users to sign

The target gets an email, inviting them to sign the document. When they click the link, they’ll go directly to DocuSign to sign the document, no SharePoint account required. They get an option to download the document, and the signed copy goes back into your document library. For our scenario, we’re finished.

Mail received by the target signer

Mail received by the target signer

Signed document automatically back in SharePoint library

Signed document automatically back in SharePoint library

Library Post

If you’re here wondering why the Library Post SharePoint app isn’t working, I’ve got some news for you. Unfortunately, it’s not good news, as I’m currently unable to access, manage or maintain the application. I built it at my former employer, who doesn’t have the resources to maintain it. I’m working on transferring control and republishing the app so that I can support it, but working out the details is taking some time.

The app’s Client ID has expired, so any calls it attempts to make into SharePoint will fail, which is why some of you are seeing infinite redirects.

I’m terribly sorry for the inconvenience.

As soon as I have more information to share, I will.

Azure Cloud Service Endpoint ACLs

Recently, Azure VMs got endpoint ACLs – this is a great addition and one of the biggest things I missed from AWS’ security groups. Using them on VMs is great and all, but what about cloud services? Since VMs are instances within a cloud service, it’s certainly possible, but how can we configure them as such? Fortunately it’s pretty easy.

No soup

First you’ll need to snag Azure SDK v2.3 and make sure your ServiceConfiguration.<env>.cscfg is at the latest schema (as of today, that’s 2014-01.2.3).

Head on in to ServiceConfiguration.Cloud.cscfg – these restrictions are obviously cloud-only – and add your chunk of config. Intellisense should pick this up and make it much simpler.

What’s nice is you can define your rules in total under AccessControls, then assign them as you need them to specific endpoints.

Here’s a sample allowing a few single IPs + a range and denying everyone else. These are executed in order, so be aware of the order tag.

<AccessControl name=”DenyAllExceptDevelopment”>
<Rule action=”permit” description=”stuff” order=”100″ remoteSubnet=”″ />
<Rule action=”permit” description=”thing” order=”101″ remoteSubnet=”″/>
<Rule action=”permit” description=”biz” order=”106″ remoteSubnet=”″/>
<Rule action=”deny” description=”theinternet” order=”200″ remoteSubnet=”″ />
<EndpointAcl role=”AzureService.Thing.Stuff” endPoint=”Endpoint1″ accessControl=”DenyAllExceptDevelopment” />

Denying Access through ADFS + Yammer

Start here if you haven’t already.

We’ll start with the last example – I’m piloting Yammer, I’ve got some users I want to grant access, but a whole lot more I want to deny. In the case of Yammer and likely some other RPs who don’t understand the Permit/Deny claim, you’ll have to manipulate something else to force the RP to boot you out. In Yammer’s case, they use the email address as the SAML_SUBJECT, which makes them pretty easy to poke.

Really, you should just update to ADFS 3.

But since that’s easier said than done, here’s how to make Yammer deny access to people using ADFS claims transformation rules.

Recursion? Did you mean recursion?

You’ll note from the previous post that we were denying users based on extensionAttribute1. This isn’t going to work any more, since Yammer doesn’t process the Deny claim, and punishes your insolence by stuffing you into an infinite redirect loop. The first thing you’ll want to do is remove any Issuance Authorization policies you have and put back ‘Allow all users.’

Next, we need to break users where extensionAttribute1 doesn’t equal false.

Persona Non Grata

In the case of Yammer, it’s easiest to just send in an invalid email address. Not invalid as in syntactically incorrect, but invalid for your organization.

That’ll give users a proper error message, informing them of their denial.

Two rules should do the trick (and you could probably get it down to a single composite rule) – one to transfer the email address to the SAML_SUBJECT and one to overwrite that claim if the user doesn’t have the requisite attributes.

To overwrite the claim (as opposed to adding a second value to the same claim), your issue statement should include the Issuer, OriginalIssuer and ValueType as the existing SAML_SUBJECT claim.

Something like this:

EXISTS(emailClaim:[Type == ""]) && NOT EXISTS(c:[Type == "", Value == "true"])
=> issue(Type = “SAML_SUBJECT”, Value = “”, ValueType = emailClaim.ValueType, Issuer = emailClaim.Issuer, OriginalIssuer = emailClaim.OriginalIssuer);

Denying Access to ADFS-secured Applications

I’m going to have to make this a two-parter, because some company *ahem* Yammer – doesn’t appear to handle the Deny ( claim very well. By very well, I mean at all.

Here’s the scenario – you’re piloting an application, likely a cloud-based or service-based application, and it’s using ADFS to authenticate (think Office 365, Yammer, Salesforce, etc). The key word here is pilot - you have some users you want to deny access.

But let’s back up a second – ADFS is, in my opinion, proper for authentication, but not authorization. ADFS is a means to validate your identity, but not a means to grant access to resources. That’s true in the purest of forms, but when an application doesn’t offer a valid way to deauthorize users, sometimes it’s easier to go to the source.

In the case of Yammer, restricting users is painfully bad – particularly for an enterprise app. Microsoft bought Yammer almost two years ago, so we should hope that things will get better.

Let’s talk claim rules.

Claim rules let you do all kinds of fun stuff – from manipulating claims before they’re sent to the relying parties to even determining if that user is authorized to access that relying party (by not sending any claims, which effectively denies them access).

Unfortunately, claim rules also use some regular expressions, which make my eyes bleed. But no matter, we must press on.

A simple example.

Let’s start simple. I want to toggle access to a specific ADFS application using a value from an AD attribute on a user. For this example, I’ll be denying myself access to the Microsoft Identity platform (Office 365, Azure, MPN, etc – what could go wrong, right?), based on a value in extensionAttribute1 in my AD profile. Of course, if you are a real pro and have extended your schema in AD, you can, of course, use your attribute.

Anyway, so I’ve got this going on:

  • Relying Party: Microsoft Office 365 Identity Platform (this is what you setup to federate with O365)
  • AD Attribute: extensionAttribute1, value ‘false’

Everything else is vanilla ADFS.

For this we’re only using Issuance Authorization policies, but this same claim rule syntax is valid for other rule types as well.

Let’s add a new claim.

First thing – let’s create a new claim that we can use to stuff our value in. This isn’t absolutely required, but makes it a lot easier – and hey, maybe you’ll even use that claim value in your relying parties one day!

Here’s mine.


To the relying party!

Now find your relying party. In my case, it’s Office 365. Let’s create some claim rules. Head over to your RP, right-click and edit your rules.

Here’s an important piece – claims are really only in scope within the tab they’re created on – for instance, if you’re in the Issuance Transform Rules tab, any custom rules you create (for instance, to assign an AD attribute’s value to a claim) are only valid within the scope of that tab. There may be some exceptions to that rule, but for the most part that’s how it’s compartmentalized. If you think about what you’re doing here, it makes sense – Issuance policies are different from transformation policies, etc – but I fell into this trap so hopefully you won’t have to.

In my example, I want to deny access based on a user account’s extensionAttribute1 being set to false.

First, we need to get a value into our fresh claim. You’ll need to do a custom rule, but it’s pretty simple:

c:[Type == "", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = (""), query = ";extensionAttribute1;{0}", param = c.Value);

Let’s dissect that a bit. No regular expressions! There’s a quick win.

We’re going to use AD to populate our new claim ( from our extensionAttribute1 AD property. Simple right?

Since rules are processed in order by the rules engine, this rule needs to come first. Now our subsequent rules can use the value of that claim (Authorized) to make decisions on token issuance.

Here’s my next rule:

c:[Type == "", Value =~ "^(?i)true$"]
=> issue(Type = "", Value = "PermitUsersWithClaim");

This one is so easy though that you can ‘cheat’ – just use the Permit or Deny based on Claim Value template – pick your claim (in my case, Authorized), set the value it should be equal to and you’re done.

In ADFS 3, you don’t even get sent to the relying party, you just get shut down at ADFS. I suspect this change is to support RPs that don’t know how to process the authorization claim.

Here’s my goofy ADFS login screen when my extensionAttribute1 is set to false:


You can, of course, get crazy with your rules, but remember, you’re going to AD for this – and these rules don’t appear to be terribly ‘optimized’ in the sense that AD queries aren’t batched or anything. If you’re a high-volume identity shop, make sure your farm is well equipped to handle the extra load you can possibly put on your infra with complex rules. Next up – dealing with RPs that don’t understand Deny.

Still think you can do it better?

My wife’s work laptop is a joke. Although she has no administrative rights, it recently got infected with one of those ransomware-type viruses. I tried to help her out – what I found was pretty awful.

She works for a bank. A bank. Where people keep money.

a) Antivirus? Bah. AVG Free. Pretty sure that’s a gross license violation, not to mention it’s just so incredibly bush league.

b) AVG’s ‘safe search’ set as the homepage and locked to prevent changes. Interestingly enough, these all have a specific client ID attached to the URL. I almost wonder if they are getting search kickbacks…

c) Windows Updates only through WSUS.

WSUS isn’t bad on its own, but when it’s only available on-prem (or through VPN), you leave disconnected workers (like her) out of the patching process. An arguably minor violation, just connect to VPN and away we go.

That is, of course, provided someone is managing your WSUS.

I took these screenshots, undoctored, last night, 6/4/14.

Most recent check: 1/12/14.

Last installed: 8/18/12.


But then it got really awful.

No updates available.


Let’s review – you can’t get updates from anyone except for your employer, but your employer obviously has people managing your systems who aren’t capable. It’s another reason that people, humans, end up getting in the way, be it hubris or ignorance. It’s dangerous, and in all honesty, Microsoft shouldn’t allow this to continue. There really should be some kind of dead man’s switch to allow people to get updates when a WSUS operator has effectively gone dead.

It’s really more of an indicator as to how bad things really are in the corporate landscape. Legions of people who mistakenly believe that the people they’ve hired to manage their infrastructure are somehow more capable than people who run massively scaled services for thousands (or millions) of customers daily. That’s not to say there aren’t bad eggs in the cloud space or diamonds on-prem, but those are exceptions to the rule. IT Managers and execs who see the cloud as a threat to their budget or headcount need to reevaluate – would you trust your personal information with these people? Would you trust your family’s livelihood with these people?

If the answer is no, it’s time to take a second look.

SharePoint Online + IRM + External Users

Since I can’t seem to find anything online regarding external users + IRM secured lists, I decided I should put it up here. In short,

External users using Microsoft Accounts can’t use IRM-secured documents that use an external client (e.g., Foxit).

There are some nuances, however. Some scenarios work, some don’t. I did all of this testing from a fresh, non-domain joined Windows 8.1.1 VM.

Scenario I: IRM Office docs + External Users

This appears to work. I shared an IRM lib with a Microsoft account and got to work. I could open and view the documents (Excel, Word & PowerPoint) in the Office Web Apps and the IRM restrictions persisted.

Scenario II: IRM PDF + External User + Foxit Reader

For managed PDFs, it’s not nearly as straightforward. Managed PDFs require one of two readers, Foxit or NitroPDF. I only tried Foxit, because Nitro wanted money. First, managed PDFs don’t open in the Word Web App (like they used to, hopefully that will come back one day), they require a client.

I tried to open the PDF from SharePoint, which prompted a download & open. Upon opening, Foxit told me I needed the AD RMS connector, which is a free download. Downloaded & installed that, tried again, then I needed the Microsoft Online Sign-In Assistant (MOSSIA) – another download/install. Did that.

The next time I opened Foxit, I was prompted by MOSSIA to sign in. Since the site was shared with my Microsoft account, I tried that. No dice – it just kept on kicking out my credentials. I tried app passwords, different Microsoft accounts, nothing.

I thought, perhaps it’s just broken, let me try the organizational account that belongs to the tenant which owns the SharePoint Online instance. This at least allowed me to login successfully, only to have Foxit kick me back out saying I didn’t have permission.

I killed Foxit and tried again – but now, my login information seemed to have persisted (granted, it’s what MOSSIA is supposed to do), so I was never prompted to login again. Fine, except that I couldn’t test any other accounts. Uninstalling MOSSIA didn’t help, so I’m guessing I need to whack some registry entries or some straggler files that are persisting my login information.

Scenario III/IV: IRM + External User (MSFT or Org) + Office 2013 client

I didn’t test this. It’s on my list, but I haven’t tried yet.

Scenario V: IRM PDF + External Organizational User + Foxit PDF

Also haven’t tried this yet. I’ll be really curious, but since the client I’m designing this for isn’t going to have external users with org accounts, it fell off the priority stack today.

A pseudo-solution

Since my specific parameters are IRM, PDF & External Microsoft account users, I’m left in a bind – there’s not a good story here. My parameters also are that the documents are read-only, so I found that if I convert the PDF to a Word doc and upload to the IRM-protected library, I can see it through the Word web app. That may not work for you, but it’s something to consider. It’s possible you could convert to some sort of an image as well, depending on your situation.


« Older posts

© 2014

Theme by Anders Noren, modified by jpd Up ↑