I was recently tasked with helping a customer configure their SharePoint 2013 farm to uses forms based authentication against a standard non-MS LDAP directory. This directory was configured to require an authenticated user to make the query. No anonymous queries allowed! The following article explains nicely how to configure the base scenario, where you don’t need to worry about passing user credentials.

http://technet.microsoft.com/en-us/library/ee806890(v=office.15).aspx

 

We spent entirely too much time working with the parameters to figure out how to pass log in information. After much research, and a look at the source code, I realized what’s needed. In the following web.config sample, you’ll see we’ve added 3 items that tell the provider to pass the connection info. The first two items are fairly self explanatory. You’ll need to provide a username and password. Make sure the username format matches what your LDAP is expecting. The important entry to make this all work is the 3rd highlighted item, useDNAttribute. This tells the provider to pass the web.config credentials to do the LDAP query. Make sure you add these entries for both your membership and role providers. (I have seen a lot of places list useUserDNAttribute in web.configs. As far as I can tell, it does nothing)

<add name="LdapMember" 
             type="Microsoft.Office.Server.Security.LdapMembershipProvider, Microsoft.Office.Server, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
             server="ldap.contoso.com" 
             port="389"
             useSSL="false"
             connectionUsername="uid=user1234,ou=people,ou=intranet,dc=contoso,dc=com" 
             connectionPassword=
pass@word111
             useDNAttribute="false" 
             DNAttribute="uid" 
             userNameAttribute="uid"
             userContainer="DC=contoso,DC=com" 
             userObjectClass="person" 
             userFilter="(&amp;(ObjectClass=person))"
             scope="Subtree" 
             otherRequiredUserAttributes="sn,givenname,cn" />

 

These were some of the entries we were seeing in the ULS logs. We could see that users weren’t getting authenticated, despite passing good username/password combinations. At times we saw success messages after this, but these lines told us they were false positives.

01/01/2014 09:18:00.57 w3wp.exe (0x2388) 0x1530 SharePoint Foundation Claims Authentication ad1qo Medium Token Handler: Claims Forms Sign-In: Membership Provider 'LdapMembership' username-password check for user 'someuser' failed. 756f7f9c-4791-a03e-e5ff-ea48482e0653

01/01/2014 09:18:32.61 w3wp.exe (0x287C)0x118C SharePoint Foundation Claims Authentication ad1qo Medium Token Handler: Claims Forms Sign-In: Membership Provider 'LdapMembership' username-password check for user 'someuser@contoso.com' failed. 7d6f7f9c-4765-a03e-f9e0-09ffd73f070d

 

If you need to do this configuration, I highly suggest you take a look at Kirk Evans PowerShell script linked below. It will write all of the necessary web.config entries. Don’t leave home without it!

http://blogs.msdn.com/b/kaevans/archive/2013/01/31/configuring-ldap-for-fba-in-sharepoint-2010-or-sharepoint-2013-with-powershell.aspx

 

The following is a PowerShell script you can leverage to test your configuration, without having to update web.configs 100 times. My colleague, Joe Rodgers, created it. I’ve attached a zipped copy to this post.

 $users = @("someuser1", "someuser2")
$roles = @("group1", "group2")

$nvc = New-Object System.Collections.Specialized.NameValueCollection
# Common Properties
$nvc.Add("connectionUsername", "contoso\localadmin") # leave empty to connect as logged on user
$nvc.Add("connectionPassword", 'pass@word111') # leave empty to connect as logged on user

$nvc.Add("server", "dc01.contoso.com")
$nvc.Add("port", 389)
$nvc.Add("useSSL", $false)
$nvc.Add("scope", "Subtree")

# Group Properties
$nvc.Add("groupContainer", "DC=contoso,DC=com")
$nvc.Add("groupNameAttribute", "cn")
$nvc.Add("groupMemberAttribute", "member")
$nvc.Add("groupFilter", "(ObjectClass=group)")
$nvc.Add("groupNameAlternateSearchAttribute", "samAccountName")
$nvc.Add("cacheDurationInMinutes", 0) # default is 30

# User Properties
$nvc.Add("useDNAttribute", $true)
$nvc.Add("userContainer", "DC=contoso,DC=com")
$nvc.Add("userFilter", "(ObjectClass=person)")
$nvc.Add("dnAttribute", "distinguishedName")
$nvc.Add("userNameAttribute", "sAMAccountName")
$nvc.Add("otherRequiredUserAttributes", "sn,givenname,cn")




### SHOULD NOT HAVE TO MODIFY ANYTHING BELOW THIS POINT ###
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server.UserProfiles")


$ldapProvider = New-Object Microsoft.Office.Server.Security.LdapRoleProvider
$ldapProvider.Initialize("PowerShell Test Application", $nvc)

Write-Host ""
$users | % {

$results = $ldapProvider.GetRolesForUser($_)

Write-Host "`nRoles for user: $($_)" -ForegroundColor Green
if($results)
{
foreach($role in $results)
{
Write-Host "`t - $role"
}
}
else
{
Write-Host "`t - None Found"
}
}

Write-Host ""
$roles | % {

$results = $ldapProvider.GetUsersInRole($_)

Write-Host "Users in role: $($_)" -ForegroundColor Green
if($results)
{
foreach($user in $results)
{
Write-Host "`t - $user"
}
}
else
{
Write-Host "`t - None Found"
}
}
Write-Host ""