Forms Based Authentication in MOSS

There have been a lot of great posts in the blogosphere on how to setup forms based authentication. Some of them:
SharePoint Product Group Blog by Steve Peschka
Nick Swan [non-MS]

What I want to put forth in this post, is a reference on the web.config changes that are required for various types of providers plus some tips on how to troubleshoot failures.

ASPNET SQL PROVIDER

- Connection String for local SQL
<membership defaultProvider="AspNetSqlMembershipProvider" />
<connectionStrings>
<remove name="LocalSqlServer" />
<add name="LocalSqlServer" connectionString="data source=127.0.0.1;Integrated Security=SSPI;Initial Catalog=aspnetdb" />
</connectionStrings>

- Connection String for Remote SQL
<connectionStrings>
<add name="SqlProviderConnection" connectionString="server=SQLSERVERMACHINE;database=aspnetdb;Trusted_Connection=True" />
</connectionStrings>

- Role Provider XML
<roleManager enabled="true" defaultProvider="AspNetSqlRoleProvider">
<providers>
<remove name="AspNetSqlRoleProvider" />
<add connectionStringName="LocalSqlServer" applicationName="/"
description="Stores and retrieves roles data from the local Microsoft SQL Server database" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</roleManager>

- Membership Provider XML
<membership defaultProvider="AspNetSqlMembershipProvider">
<providers>
<remove name="AspNetSqlMembershipProvider" />
<add connectionStringName="SqlProviderConnection" passwordAttemptWindow="10" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed" description="Stores and retrieves membership data from the Microsoft SQL Server database" name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</membership>

Office Server LDAP

Membershipprovider XML

<membership defaultProvider="PeopleDCLDAPMembership">
<providers>
<add name="PeopleDCLDAPMembership" type="Microsoft.Office.Server.Security.LDAPMembershipProvider, Microsoft.Office.Server.LDAPProvider, Version=12.0.0.0, Culture=neutral, PublicKeyToken=94de0004b6e3fcc5" server= [server name as string] port="389" useSSL="false" userDNAttribute="distinguishedName" userNameAttribute="sAMAccountName" userContainer="OU=UserAccounts,DC= [fqdnstringpart] ,DC= [fqdnstringpart] ,DC= [fqdnstringpart] ,DC=com" userObjectClass="person" userFilter="(&amp;(ObjectClass=person))" scope="Subtree" otherRequiredUserAttributes="sn,givenname,cn" />
</providers>
</membership>

Roleprovider XML

<roleManager defaultProvider="PeopleDCLDAPRole" enabled="true" cacheRolesInCookie="true" cookieName=".PeopleDCRole">
<providers>
<add name="PeopleDCLDAPRole" type="Microsoft.SharePoint.Security.LDAPRoleProvider, Microsoft.SharePoint.LDAPProvider, Version=12.0.0.0, Culture=neutral, PublicKeyToken=94de0004b6e3fcc5" server= [server name as string] port="389" useSSL="false" groupContainer="OU=UserAccounts, DC= [fqdnstringpart] ,DC= [fqdnstringpart] ,DC= [fqdnstringpart] ,DC=com" groupNameAttribute="sAMAccountName" groupMemberAttribute="uniquemember" userNameAttribute="sAMAccountName" dnAttribute="CN" groupFilter="(&amp;(ObjectClass=group))" scope="Subtree" />
</providers>
</roleManager>

WebSSO (ADFS)- Modification to the Web Application Web.config

<sectionGroup name="system.web">
<section name="websso" type="System.Web.Security.SingleSignOn.WebSsoConfigurationHandler, System.Web.Security.SingleSignOn, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, Custom=null" />
</sectionGroup>

<add key="SingleSignOnMembershipProvider" value="" />

<add name="Identity Federation Services Application Authentication Module" type="System.Web.Security.SingleSignOn.WebSsoAuthenticationModule, System.Web.Security.SingleSignOn, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, Custom=null" />

<trust level="Full" originUrl="" />

Membership provider

<membership defaultProvider="SingleSignOnMembershipProvider">
<providers>
<add name="SingleSignOnMembershipProvider" type="System.Web.Security.SingleSignOn.SingleSignOnMembershipProvider, System.Web.Security.SingleSignOn, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" fs="https://fs-server/adfs/fs/federationserverservice.asmx" />
</providers>
</membership>

Role provider

<roleManager enabled="true" defaultProvider="SingleSignOnRoleProvider">
<providers>
<add name="SingleSignOnRoleProvider" type="System.Web.Security.SingleSignOn.SingleSignOnRoleProvider, System.Web.Security.SingleSignOn, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" fs="https://fs-server/adfs/fs/federationserverservice.asmx" />
</providers>
</roleManager>

<websso>
<authenticationrequired />
<auditlevel>55</auditlevel>
<urls>
<returnurl>https://servername</returnurl>
</urls>

<cookies Persistent="True">
<path>/</path>
</cookies>

<fs>https://fs-server/adfs/fs/federationserverservice.asmx</fs>
<!-- usettp / -->
<isSharePoint />
</websso>

- Modification to the Central Administration web application web.config

Membership Provider
<membership>
<providers>
<add name="SingleSignOnMembershipProvider" type="System.Web.Security.SingleSignOn.SingleSignOnMembershipProvider, System.Web.Security.SingleSignOn, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" fs="https://fs-server/adfs/fs/federationserverservice.asmx" />
</providers>
</membership>

Role Provider
<roleManager enabled="true" defaultProvider="AspNetWindowsTokenRoleProvider" >
<providers>
<remove name="AspNetSqlRoleProvider"/>
<add name="SingleSignOnRoleProvider" type="System.Web.Security.SingleSignOn.SingleSignOnRoleProvider, System.Web.Security.SingleSignOn, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" fs="https://fs-server/adfs/fs/federationserverservice.asmx" />
</providers>
</roleManager>

ASPNET Active Directory Provider

Connection string
<connectionStrings>
<add name="ADConnectionString" connectionString="LDAP:// [domainname] /OU=UserAccounts, DC= [fqdnstringpart] ,DC= [fqdnstringpart] ,DC=com" />
</connectionStrings>

Membership Provider
<membership defaultProvider="AspNetActiveDirectoryMembershipProvider">
<providers>
<add name="AspNetActiveDirectoryMembershipProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="ADConnectionString" enableSearchMethods="true" attributeMapUsername="sAMAccountName" />
</providers>
</membership>

Thanks to DW for compiling this list

OVERVIEW AND TROUBLESHOOTING

A lot of us who have played with Forms based Authentication with Microsoft Office SharePoint Server 2007 would know, that the steps for setting it up are fairly simple, however, if and when something does go wrong, finding it out is really a mess. Here's something that can help do so some basic troubleshooting:
A thumb rule to look for is, when you browse to the Login page, and the page loads without the CSS, then definitely something has gone amiss. That's the first clue. After this, it is many a times a mind game. The question that comes up is why is it so difficult to figure it out? A lot of people have asked me as to why there wasn't any logging or error handling implemented from within SharePoint to make it easier to troubleshoot Forms Based Authentication? The answer lies in understanding how SharePoint implements FBA.

As you can see from the flow diagram above, the bulk of the action happens within .NET Framework. From a SharePoint perspective the request to login (when you click the Login button) just sends the user credentials entered in the Login web control (yeah, we use that on the default login page!) to the Provider. Obviously, prior to this, the framework has already swung into action and prepped the environment by loading the Provider assembly based on the entries made in the web.config file. There are a whole bunch of problems that you can run into at this level. Let's take them one by one:

1. The assembly does not get loaded. The page displays File Not Found.
This is a classic in itself. There are multiple reasons for this to occur. The manifestation of this problem is a simple "File Not Found" string displayed in the browser window. By itself this does not tell much. If you do venture out and enable call stacks and turn on the debug flags in the web.config (refer the debugging explanation @ http://msdn2.microsoft.com/en-us/library/ms916837.aspx ), then you will see the error being generally thrown from a System.Reflection call on the provider assembly.
One solution that works is to check the name of the provider that is registered in the web.config. If you are using OOB providers, then obviously this does not apply. This solution works for custom providers. Why this causes a problem, is the reflection makes a call to the provider for loading. There is a overridden property within the provider called Name. If this has not been implemented properly to get/set the value specified in the web.config, then the framework keeps looking for the provider with a different name than the one that is actually returned from within the assembly.
Another solution that works, is running the Fusion Log Viewer, to make a note of the location the framework is looking for the provider assembly.
http://msdn2.microsoft.com/en-us/library/e74a18c4(VS.80).aspx
Closely looking at the log, generally reveals the location of the ASP.NET cache. Clearing this cache, will most likely solve the problem.

2. The browser displays the message "Default membership provider could not be found"
To solve this, check the web.config, for the value of the defaultProvider there. Then browse to the IIS manager, and open the property sheet for the web site corresponding to the web application throwing the error. Crack open the ASP.NET configuration settings. Under Authentication, take a look at the default provider. Due to some weird framework calls, the default provider gets reset to AspNetSqlMembershipProvider. Change it back to the correct one.

If you have seen these errors and have a solution that you vouch by, then I would like to hear about it. More interestingly, if you have seen errors other than these, I would like to hear about those too.
For others, if these don't solve the problem, contact your friendly neighborhood MS support guy.

~harsh