If you’re setting up a certificate-based connection to Microsoft Graph Powershell (or whatever they’ve decided to name it at the point you’re reading this. You know what I’m talking about) and you’re getting an error when running:
The company I work for has our Exchange service hosted with Intermedia, which at the time of the transition from an on-premise solution seemed great. Why deal with the headache of an Exchange server when you can make someone else do it for you? Fast forward three years and Microsoft’s Exchange Online service has become both ubiquitous and quite stable, but for Reasons we aren’t in the market to move our e-mail servers again.
That being said, we’re happy to be leveraging Microsoft’s other Office 365 offerings (because we don’t have a choice in the matter. Thanks Microsoft). This has created a pretty interesting dilemma that should be applicable any time you have your Exchange service hosted outside Office 365, and are also looking to leverage Office 365. Intermedia provides Active Directory synchronization via their proprietary HostPilot software, and Microsoft provides Acive Directory synchronization via Azure AD Sync. Intermedia and Azure both look to our UPN for our e-mails (and more importantly, our usernames), which it turns out is a problem!
Local Computer Credential Persistence
For some reason, if the “username” e-mail address used for your Exchange mailbox is the same as your UPN, your computer will save the credentials for that account with “Local Computer” persistence. This means that the credentials will not persist through sessions. If you log out, then log back in, you will need to re-enter your password. You can check this in the Credential Manager. What you want is “Enterprise” persistence.
Okay, so what did we do? Well, we thought we were being pretty clever by changing our UPN to include a subdomain. Instead of [email protected], we changed everyone’s UPN to be [email protected]. We were then able to synchronize that UPN to Office 365, and ensure all of our users continued to be able to have their mailbox credential persist between sessions. The theory was that users would only need to use their @sub.domain.com account once, when activating Office licensing, and one of our technicians would be doing that anyways, so the impact would be minimal.
SAML Single Sign On
Fast forward another year, and we have a new dilemma. We have an on-prem application that previously did not have SSO enabled, but a security audit brought up doing so to ensure that user accounts are disabled in a timely fashion. Reasonable. When weighing our options, we considered setting up AD FS on-premise, but my boss brought up the idea of using Azure AD. We’re already synchronizing everything up to Azure, why not continue to leverage it.
Great idea, except we ran into the issue of minimal impact. We had assumed that we would only ever use the Azure AD accounts for Office activation, and users would never need to remember when to use sub.domain.com instead of domain.com. But here we are, hoisted upon our own pitard.
This got me thinking about how the Azure AD Synchronization works. The AD Sync Service Manager uses a bunch of rules to match the data in your local user object with the data in your cloud user object. For all intents and purposes, you have two identical Active Directory forests that are synchronized byt this service. That means that the service needs to know what attributes to synchronize with what attributes, and more importantly, the rules for how it does that is exposed to us. We can set each user’s extensionAttribute1 attribute to be their [email protected] e-mail address and retain [email protected] as their UPN, continuing to bypass the previous issue of credential persistence. There are a number of reasons I went with the extensionAttribute1 attribute and not, say, proxyAddresses and mail, but I’ll talk about that later.
Open the Synchronization Rules editor and find the two rules shown in the screenshot.
When editing the rules, you’re prompted to clone and disable the default rule. I highly recommend you do this, as this is a very simple failsafe. Make sure to rename the clone, and make sure to change the priority. Default rules all have priorities over 100, so choose something below 100.
Navigate to the “Transformations” tab on the left, and find the line for userPrincipalName. The userPrincipalName is, you guessed it, the attribute that is used as your as “username” for Azure AD, so we’ll need to change this expression. Do this for both rules above.
Here is what the default is, followed by what I changed it to be.
IIF(IsPresent([userPrincipalName]),[userPrincipalName], IIF(IsPresent([sAMAccountName]),([sAMAccountName]&"@"&%Domain.FQDN%),Error("AccountName is not present")))
IIF(IsPresent([extensionAttribute1]),[extensionAttribute1], IIF(IsPresent([userPrincipalName]),[userPrincipalName], IIF(IsPresent([sAMAccountName]),([sAMAccountName]&"@"&%Domain.FQDN%),Error("AccountName is not present"))))
If you take a minute to break it down, it makes a lot of sense. The default checks if there is a userPrincipalName for the object, and if it does it users that. Otherwise, it will check for a sAMAccountName and use that plus the domain from your FQDN, and finally error if none of those are around. What we want, though, is to add the extensionAttribute1 attribute as the first thing it checks, and have it use that. I liked keeping the UPN as a fallback so that worst comes to worst, I can direct a user to use that if I can’t immediately fix the problem.
However, that’s not the end. It turns out that when Azure AD Sync Service pulls the user object, it does not pull all attributes on the object, but rather a subset of them. You’ll need to find the pictured rule below and clone and edit that as well.
This is the rule that queries local AD and pulls what it needs. Go to the Join Rules tab on the left and add what’s highlighted in red. Now, it will pull in the extensionAttribute1 value and give the previous rules something to work with.
Once you’re done, open up Powershell and run the following to start a sync to match the value in your local user object’s extensionAttribute1 attribute with the UPN for your Azure AD user object.
Start-ADSyncSyncCycle –PolicyType Initial
I said earlier there were reasons we didn’t sync with certain attributes, so below are the attributes I thought about syncing with and why that didn’t work.
mail – Our mailboxes are set up funny-like with Intermedia, and so they all have to synchronize using another e-mail address, which turns out to be in the mail field. This is something I may try to untangle later, but it may also be that we had run into credential persistence issue during the migration.
proxyaddresses – Azure AD Sync really did not like using the proxyaddresses field. The UPN value accepts strings, and while the proxyaddresses field is stated to be a string, I’m not sure it’s string enough to be accepted. Also, our previous on-prem Exchange server meant that a lot of older user accounts still had a lot of X500 data in that attribute, so it was better to just avoid it.
otherMailbox – I had thought about using this earlier on, and probably could have, but in troubleshooting why the sync wasn’t working, I decided to use the extensionAttribute1 field instead. In hindsight, it probably didn’t work because of needing to add the join rule. If you’ve got a bee in your bonnet to use this attribute, it’s probably fine.
This was a real long post, and a culmination of about two months total of beating my head against a wall, mostly with regards to the credential persistence. That’s what I get for opening a support ticket with Microsoft. If this helped you, let me know. If there’s anything that isn’t technically correct or just straight up wrong, let me know as well. All in all, it was pretty cool bending Azure AD to my will.