Cross Forest Exchange Impersonation - where the rubber meets the road
Published Apr 18 2008 04:48 PM 24.1K Views

Based on the feedback on my original post on Cross Forest Exchange Impersonation in Exchange 2007 Service Pack 1, I wanted to provide you with some "real life" examples to help you actually implement this. To dig into cross forest Exchange Impersonation a little more, we will use two approaches.  The first is the "easy" one, in which we create a linked mailbox in the Exchange forest to represent the Service Account.  The second is the "almost as easy, but not quite so" in which we manually create and link a cross forest contact in the Exchange forest to represent the Service Account. Linked Mailbox Given that our Exchange resource forest and our user forest have a trust relationship established, it seems reasonable that a request against and Exchange CAS box using a user account from the user forest will work.  However, as indicated in the previous blog post, EWS expects there to be some sort of AD object in the resource forest to represent the cross forest account, and unfortunately, a foreign security principal is not enough.  So, we will use the new-mailbox PowerShell Cmdlet to create a linked mailbox which will create a mailbox in the Exchange forest that is "linked" back to the Service Account in the user forest. First, we need to get the credentials of an account that has rights to read directory information from the user domain.  The LinkedCredential parameter of new-mailbox expects a PSCredential instance.  We can create these credentials as follows: $pass = read-host -AsSecureString $creds = new-object -typename System.Management.Automation.PSCredential -argumentlist "YourUserDomain\ServiceAccount",$pass The first line will allow you to type in a password in the shell which will be masked with password masking characters.  The resulting secure string will then be stored in $pass.  The next line creates an instance of the PSCredential class using the domain\username and the obtained password. With this information you can call new-mailbox as follows: new-mailbox -Name "ServiceAccount" -Database "Your Mailbox Database" -LinkedMasterAccount YourUserDomain\ServiceAccount -LinkedDomainController -LinkedCredential $creds -UserPrincipalName Name is just the name of the user account that will be created in the Exchange resource forest.  This does not have to be the same as the name of the account in the user forest. Database is the mailbox database that will hold the mailbox for ServiceAccount. LinkedMasterAccount is the domain\alias pair that represents the account in the user forest that you are creating a linked mailbox for.  You can also use other representations - check the docs for more detail. LinkedDomainController is the FQDN of a domain controller in the user forest that can be queried to get information about the user account LinkedCredential holds the credentials for an account in the user domain that has rights to query the LinkedDomainController. UserPrincipalName the UPN of the account. Once you do this, your linked mailbox account will be created.  If you are really adventurous, you can use a tool such as ADSIEdit to look at the new object.  Of interest, note that the objectSid attribute has a different value than the msExchMasterAccountSid attribute.  Why would that be?  Well, the objectSid is generated by the Exchange forest since it is authoritative for the mailbox account while the msExchMasterAccountSid contains the sid of the user in the user forest.  In fact, this msExchMasterAccountSid is precisely what EWS uses to resolve the incoming request from the account in the user forest into the object in the resource forest. Once we have this linked mailbox set up, we can configure our Exchange Impersonation rights. Add-AdPermission -Identity (Get-ExchangeServer -Identity "YourCASBox").Identity -User YourUserDomain\ServiceAccount -ExtendedRights ms-Exch-EPI-Impersonation Add-AdPermission -Identity ActAsAccount -User YourUserDomain\ServiceAccount -ExtendedRights ms-Exch-EPI-May-Impersonate Notice something interesting?  After creating the linked mailbox, we can really forget that it is there.  Notice that we are giving the Exchange Impersonation rights to the account in the USER forest, NOT the account in the Exchange forest. Once these rights are in place, you should be able to send in an Exchange Impersonation request to "YourCASBox" using "YourUserDomain\ServiceAccount" to authenticate the request in order to access "ActAsAccount's" mailbox. Cross Forest Contact Now that we have had loads of fun with linked mailboxes, why would we want something different?  Well, consider this - Does ServiceAccount *really* need a mailbox?  Let's see :)

1. In the user forest, we need to get the hex or decimal representation of ServiceAccount's objectSid in the user domain.  You can either use ADSIEdit in the user domain to look at the objectSid attribute, or you can do the following (from the Exchange forest since there is a trust):
$sid = new-object System.Security.Principal.NTAccount -argumentList "YourUserDomain\ServiceAccount"; $binarySid = $sid.Translate([System.Security.Principal.SecurityIdentifier]); $bytes = new-object System.Byte[] -argumentList $binarySid.BinaryLength; $binarySid.GetBinaryForm($bytes, 0); $sb = new-object System.Text.StringBuilder; foreach ($b in $bytes){ $sb.Append($b.ToString("000 ")); }; $sb.ToString();
2. Bring up our friend AD Users and Computers in the Exchange forest and create a new Contact in the users container.  Call the contact whatever you desire, but for our purposes, I will call it CFServiceAccount (CF == CrossForest).  Now, close out AD Users and Computers.
3. Next, bring up our friend ADSIEdit in the Exchange forest, connect to the default naming context and find the contact that was just created.
4. Right click on the contact and choose properties.
5. Go to the msExchMasterAcountSid attribute and click Edit to bring up the editor.
6. Copy the array values from step 1 into the editor.  Note that you will need to choose Decimal for the Value Format combo box since our byte array was provided in decimal format.  Also get rid of the trailing space that our PS script added.
7. Click OK , OK
So what did we just do?  We just created a contact object that Exchange is tied to the account in the user domain.  "But wait!?!" you say, "You can't add a contact to an ACL in the directory!"  Quite true.  However, if you recall from above, we DON'T use the linked mailbox when setting the exchange Impersonation rights - we use the account from the user domain.  In the same way, we DON'T use the cross forest contact when setting the Exchange Impersonation rights - we use the account from the user domain. The existence of this cross forest contact is simply a "wedge" to allow EWS to resolve to *something* in the exchange forest.  After this, we can call our Add-AdPermission calls in precisely the same form as we did with the linked mailbox. Why does EWS expect such an object to exist in the Exchange forest? As a matter of principle, EWS assumes that the caller is going to access their own mailbox unless explicitly told otherwise in the request. When a request comes in, EWS blindly configures itself so that it can access the resources of the caller, but in the case of a cross forest caller this action fails as we have seen. In practice, EWS should likely postpone such initialization until it is actually needed rather than doing it up front. In cross forest impersonation cases, the ServiceAccount caller will *never* be accessing their own resources and therefore such initialization is never used. Our wedge in this case simply allows EWS to perform its initialization steps so that we can complete the call. Conclusion So why would you choose a cross forest contact instead of a linked mailbox account?  Primarily for security reasons.  Linked mailboxes have mailboxes, passwords, rights in the exchange forest, etc...  Contact objects have nothing of the sort.  If the service account will only be used for making Exchange Impersonation calls in the Exchange forest, why give it rights and resources that it doesn't need? - David Sterling
Version history
Last update:
‎Jul 01 2019 03:36 PM
Updated by: