So, I had a pretty interesting support case the other day. Cx stated that people picker wasn’t returning any results for users in a trusted domain. I was thinking ok I mean how hard could this be……. well so, my brain hurts now . So hopefully this will save someone else a huge headache.
Ok so let me paint the scenario for you, but first what is the issue?
Problem:
When you perform a people picker search for a user account that resides in a trusted domain no results are returned and SharePoint reports “User SPPrincipalInfo doesn’t seem to have a user principal name value” for our user we queried for
Scenario:
-
We have two domains with a two-way external trust configured. So, everyone trusts everyone here it’s a happy family.
- SharePoint Servers, SharePoint Farm Service Accounts, and User accounts reside in the Contoso.com domain
- For purposes of this article only user accounts reside in the Fabrikam.com domain
-
We are using a SAML provider that is using an out of the box AD claim provider. This is created by SharePoint when we create our trusted identity token issuer using the “-UseDefaultConfiguration” parameter like so:
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(“C:\temp\ADFSSigningCert.cer”)
New-SPTrustedRootAuthority -Name “Token Signing Cert” -Certificate $cert
$ap = New-SPTrustedIdentityTokenIssuer -Name “ADFS SAML Provider” -Description “SAML Authentication for SharePoint” -realm “urn:sharepoint:www.contoso.com” -ImportTrustCertificate $cert -SignInUrl “https://adfs.Contoso.com/adfs/ls” -UseDefaultConfiguration -IdentifierClaimIs USER-PRINCIPAL-NAME;
$ap = Get-SPTrustedIdentityTokenIssuer -Identity “ADFS SAML Provider”;
$ap.ProviderRealms.Add(“https://www.contoso.com”, “urn:sharepoint:www.contoso.com”);
$ap.ProviderSignOutUri = “https://adfs.contoso.com/adfs/ls“;
$ap.ClaimProviderName = “ADFS SAML Provider”;
$ap.UseWReplyParameter = $true;
$ap.Update();
Note:
The -UseDefaultConfiguration parameter will create a claim provider for you. Since this is our code (Microsoft) we are able to sink our hooks into AD to perform the user lookup based on the information entered into the people picker. This allows us to return a friendly display name instead of the awful identifying claim, which is some cases could be an employee ID
Note:
Get the Short name for the domain
(net config workstation) -match ‘Workstation domain\s+\S+$’ -replace ‘.+?(\S+)$’,’$1′
-
The -UseDefaultConfiguration parameter will create a claim provider for you. Since this is our code we are able to sink our hooks into AD to perform the user lookup based on the information entered into the people picker. This allows us to return a friendly display name instead of the awful identifying claim, which is some cases could be an employee ID.
Search with people picker for the user account in the fabrikam.com domain
- Attempt to grant permissions to the user in the Fabrikam domain “PeoplePickerTest” using the people picker from here: https://www.contoso.com/_layouts/15/user.aspx
- Within People Picker search for “peoplepickertest”
-
Search result:
- No results found is the result
What You’ll see in the ULS logs and Network Monitor trace
Looking at netmon trace we see the first call
24167 12:47:08 PM 11/17/2016 13.6861171 w3wp.exe 10.19.141.20 RHWDC18.contoso.com LDAPSASLBuffer LDAPSASLBuffer:BufferLength: 667, AuthMechanism: GSS-SPNEGO {LDAP:686, TCP:682, IPv4:676}
Here is our query to the Contoso.com domain
Filter: (|(&(objectCategory=person)(|(anr=peoplepickertest*)(SamAccountName=peoplepickertest*)(userPrincipalName=peoplepickertest*)))(&(objectCategory=group)(BIT_AND: (groupType)&2147483648)(|(anr=peoplepickertest*)(SamAccountName=peoplepickertest*))))
Here are the attributes we are requesting
Attributes: ( objectSID )( mail )( mobile )( displayName )( title )( department )( proxyAddresses )( cn )( samAccountName )( groupType )( userAccountControl )( distinguishedName )( objectClass )( userPrincipalName )( msexchmasteraccountsid )
24168 12:47:08 PM 11/17/2016 13.6869698 w3wp.exe RHWDC18.contoso.com 10.19.141.20 LDAPSASLBuffer LDAPSASLBuffer:BufferLength: 1027, AuthMechanism: GSS-SPNEGO {LDAP:686, TCP:682, IPv4:676}
Here is our first search result
SearchResultEntry: CN=peoplepickertest@farbrikam.com,OU=Fabrikam,OU=Contacts from SimpleSync,OU=User,OU=Contoso,DC=contoso,DC=com
Here are the attributes returned
+ PartialAttribute: objectClass=( top )( person )( organizationalPerson )( contact )
+ PartialAttribute: cn=( peoplepickertest@Fabrikam.com )
+ PartialAttribute: title=( Business Application Consultant )
+ PartialAttribute: distinguishedName=( CN=peoplepickertest@Fabrikam.com,OU=Fabrikam,OU=Contacts from SimpleSync,OU=RHDC,OU=Contoso,DC=contoso,DC=com )
+ PartialAttribute: displayName=( Jones, Bob (Fabrikam) )
+ PartialAttribute: department=( AD_Medmanagement )
+ PartialAttribute: proxyAddresses=( x500:/o=Contoso.com/ou=First Administrative Group/cn=Recipients/cn=peoplepickertest.Farbrikam.com1 )( x500:/o=Contoso/ou=First Administrative Group/cn=Recipients/cn=peoplepickertest@Fabrikam.com1 )( X500:/o=Contoso/ou=First Administrative Group/cn=R
+ PartialAttribute: mail=( peoplepickertest@Farbrikam.com )
+ PartialAttribute: msExchMasterAccountSid=( )
In ULS we’ll see these entries for this search
SearchFromGC name = Contoso.com. start
GetAccountNameFromSid “0x0105000000000005150000007B005C46C7C60121369482B9798A0500” start
“0x0105000000000005150000007B005C46C7C60121369482B9798A0500” returned. returnValue=True
GetAccountNameFromSid “0x0105000000000005150000001741550EDE09584B0363450079C20000” start
GetAccountNameFromSid “0x0105000000000005150000001741550EDE09584B0363450079C20000” returned. returnValue=True
SearchFromGC name = Contoso.com. returned. Result count = 2
0x0105000000000005150000001741550EDE09584B0363450079C20000 = Userid:S-1-5-21-240468247-1264060894-4547331-49785
We have returned an entry with the SID S-1-5-21-240468247-1264060894-4547331-49785
This SID translates to fabrikam\peoplepickertest, but it was returned from the Contoso.com domain
We can see in the network monitor trace that this is returned as a contact with the attribute value msExchMasterAccountSid and no UPN
We then call out to the Fabrikam.com domain
39482 12:47:20 PM 11/17/2016 25.4775491 w3wp.exe 10.19.141.20 dc2vm.fabrikcam.com LDAPSASLBuffer LDAPSASLBuffer:BufferLength: 418, AuthMechanism: GSS-SPNEGO {LDAP:1013, TCP:1012, IPv4:1009}
Here we search fabrikcam.com
SearchRequest: BaseDN: DC=Fabrikam,DC=com, SearchScope: WholeSubtree, SearchAlias: neverDerefAliases
We filter on SID
Filter: (&(objectSID=))
And we request these attributes
Attributes: ( objectSID )( mail )( mobile )( displayName )( title )( department )( proxyAddresses )( cn )( samAccountName )( groupType )( userAccountControl )( distinguishedName )( objectClass )( userPrincipalName )( msexchmasteraccountsid )
Here is the search result
39519 12:47:20 PM 11/17/2016 25.4835293 w3wp.exe dc2vm.fabrikam.com 10.19.141.20 LDAPSASLBuffer LDAPSASLBuffer:BufferLength: 789, AuthMechanism: GSS-SPNEGO {LDAP:1013, TCP:1012, IPv4:1009}
SearchResultEntry: CN=PeoplePickerTest,OU=Contract,DC=Fabrikam,DC=Com
We return these attribute values
Frame: Number = 39519, Captured Frame Length = 847, MediaType = ETHERNET
– Attributes: 12 Partial Attributes
+ SequenceHeader:
+ PartialAttribute: objectClass=( top )( person )( organizationalPerson )( user )
+ PartialAttribute: cn=( PeoplePickerTest )
+ PartialAttribute: title=( Business Application Consultant )
+ PartialAttribute: distinguishedName=( CN=PeoplePickerTest,OU=Contract,DC=Fabrikam,DC=Com )
+ PartialAttribute: displayName=( PeoplePickerTest)
+ PartialAttribute: department=( AD_Medmanagement )
+ PartialAttribute: proxyAddresses=( smtp:PeoplePickerTest@fabrikam.com )( SMTP:PeoplePickerTest@fabrikam.com)
+ PartialAttribute: userAccountControl=( 512 )
+ PartialAttribute: objectSid=( )
+ PartialAttribute: sAMAccountName=( PeoplePickerTest )
+ PartialAttribute: userPrincipalName=( PeoplePickerTest@fabrikam.com )
+ PartialAttribute: mail=( PeoplePickerTest@fabrikam.com )
We then see these entries in the ULS for this search
SearchFromGC name = Fabrikam.com. start
GetAccountNameFromSid “0x0105000000000005150000001741550EDE09584B0363450079C20000” start
GetAccountNameFromSid “0x0105000000000005150000001741550EDE09584B0363450079C20000” returned. returnValue=True
SearchFromGC name = Fabrikam.com. returned. Result count = 1
We then see this error
User SPPrincipalInfo doesn’t seem to have a user principal name value. User: ‘fabrikam\PeoplePickerTest’, ID: ‘-1’
Conclusion:
- We bind to the first result received with the SID
- The attributes passed in the first search result was for a contact which does not have an object SID but does have a msEXCHMasterSID.
- This attribute is included in the first search results, so we bind to this master SID and translate to a user account, which is the account we are expecting.
- However, this search result does not contain a UserPrincipalName attribute, so we do not display the user.
Workarounds (in no particular order):
-
If you change the search order of the domains in the people picker searchadforests property to search the trusted domain Fabrikam.com first, then search Contoso.com. The people picker will bind to the first result it receives which will be the correct user object.
Origninal configuration
stsadm -o setproperty -url https://www.contoso.com -pn peoplepicker-searchadforests -pv “forest:contoso.com;forest:fabrikam.com”
Reversed search order
stsadm -o setproperty -url https://www.contoso.com -pn peoplepicker-searchadforests -pv “forest:fabrikam.com;forest:contoso.com“
-
If you search for the user using domain\username that will return the correct results regardless of the people picker search order
-
If you copy the account name and paste it into the people picker search this will also return the correct user
-
If you type in the users account name and then do a CTRL + K (check name function) this is the same as pasting in the users account name
- This also uses the check name function
More of a permanent solution:
Ultimately the issue is people picker is resolving contact objects. Since contacts can’t be used to log in with we can filter these out from the people picker results with a custom filter.
The filter is a LDAP search filter: (|(objectCategory=group)(&(objectCategory=person)(!objectClass=contact))).
We can test this filter using the custom search feature in Active Directory Users and Computers.



In SharePoint, we’ll fix this issue by using the below PowerShell:
==============================PowerShell Script==============================
Add-PSSnapin Microsoft.SharePoint.PowerShell -ea silentlycontinue
$wa = Get-SPWebApplication <Put Web App Here>
$wa.PeoplePickerSettings.SearchActiveDirectoryDomains | out-file c:\temp\pp_settings_before.txt
$wa.PeoplePickerSettings.SearchActiveDirectoryDomains.Clear()
$wa.update()
$wa.PeoplePickerSettings.SearchActiveDirectoryDomains
$wa = Get-SPWebApplication <Put Web App Here>
$adsearchobj1 = New-Object Microsoft.SharePoint.Administration.SPPeoplePickerSearchActiveDirectoryDomain
$adsearchobj1.DomainName = “Contoso.com”
$adsearchobj1.ShortDomainName = “Contoso”
$adsearchobj1.IsForest = $false
$newdomain.CustomFilter = “(|(objectCategory=group)(&(objectCategory=person)(!objectClass=contact)))”
$wa.PeoplePickerSettings.SearchActiveDirectoryDomains.Add($adsearchobj1)
$wa = Get-SPWebApplication <Put Web App Here>
$adsearchobj2 = New-Object Microsoft.SharePoint.Administration.SPPeoplePickerSearchActiveDirectoryDomain
$adsearchobj2.DomainName = “Fabrikam.com”
$adsearchobj2.ShortDomainName = “fabrikam”
$adsearchobj2.IsForest = $true
$newdomain2.CustomFilter = “(|(objectCategory=group)(&(objectCategory=person)(!objectClass=contact)))”
$wa.PeoplePickerSettings.SearchActiveDirectoryDomains.Add($adsearchobj2)
$wa.Update()
==============================PowerShell Script==============================
Additional information about People Picker and the MSExchMasterAccountSid property
https://blogs.iis.net/deanc/troubleshooting-people-picker-with-netmon
To see what is currently set in your environment use the following PowerShell
$webService = new-object Microsoft.SharePoint.Administration.SPWebService
$webService.PeoplePickerSearchReplicatedMasterSIDPropertyName
Now this is ignored if you copy paste in a value that exists in the local domain. This will return the local domains user object instead of the referenced object that is in the MSExchMasterAccountSid property