Sitecore authenticate users against external membership database

Matthew Dresser picture Matthew Dresser · Aug 4, 2011 · Viewed 9.4k times · Source

I have a Sitecore site where I want to have website visitor accounts stored in an external asp.net membership database but keep Sitecore content editors/admins managed via the Sitecore interface (and hence stored in the 'Core' database).

I've read through the following forum post http://sdn.sitecore.net/SDN5/Forum/ShowPost.aspx?postid=35305

in which the following documents are mentioned http://sdn.sitecore.net/upload/sitecore6/62/membership_providers_sc62-a4.pdf http://sdn.sitecore.net/upload/sitecore6/62/security_api_cookbook_sc60-62-a4.pdf http://sdn.sitecore.net/upload/sdn5/modules/ad/low-level_sitecore_cms_security_and_custom_providers-a4.pdf

but none of these seem to provide a complete picture of what I need to do.

I've currently got the the <membership> section set up to use the 'switcher' provider (with a corresponding provider pointing to my membership DB) and the <roleManager> section also set up to use the switcher provider again with a corresponding provider pointing to said membership DB.

So far I have only succeeded in breaking the user manager in the Sitecore desktop (it throws either the exception Item has already been added. Key in dictionary: 'extranet\Anonymous' Key being added: 'extranet\Anonymous' if Sitecore has created the extranet\Anonymous account, or Object reference not set to an instance of an object. if I've deleted that user account.

As background information I'm using Sitecore 6.5 and the relevant section of my web config is as follows

<membership defaultProvider="switcher">
  <providers>
    <clear/>
    <add name="sitecore"
         type="Sitecore.Security.SitecoreMembershipProvider, Sitecore.Kernel"
         realProviderName="myProvider"
         providerWildcard="%"
         raiseEvents="true"/>
    <add name="sql"
         type="System.Web.Security.SqlMembershipProvider"
         connectionStringName="core"
         applicationName="sitecore"
         minRequiredPasswordLength="1"
         minRequiredNonalphanumericCharacters="0"
         requiresQuestionAndAnswer="false"
         requiresUniqueEmail="false"
         maxInvalidPasswordAttempts="256"/>
    <add name="switcher"
         type="Sitecore.Security.SwitchingMembershipProvider, Sitecore.Kernel"
         applicationName="sitecore"
         mappings="switchingProviders/membership"/>
    <add name="myProvider"
         type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
         applicationName="sitecore"
         connectionStringName="myDatabase"
         minRequiredPasswordLength="1"
         minRequiredNonalphanumericCharacters="0"
         requiresQuestionAndAnswer="false"
         requiresUniqueEmail="false"
         maxInvalidPasswordAttempts="10" />
  </providers>
</membership>
<roleManager defaultProvider="switcher" enabled="true">
  <providers>
    <clear/>
    <add name="sitecore" 
         type="Sitecore.Security.SitecoreRoleProvider, Sitecore.Kernel"
         realProviderName="myProvider"
         raiseEvents="true"/>
    <add name="sql"
         type="System.Web.Security.SqlRoleProvider"
         connectionStringName="core"
         applicationName="sitecore"/>
    <add name="switcher"
         type="Sitecore.Security.SwitchingRoleProvider, Sitecore.Kernel"
         applicationName="sitecore"
         mappings="switchingProviders/roleManager"/>
    <add name="myProvider"
         type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
         applicationName="sitecore"
         connectionStringName="myDatabase" />
  </providers>
</roleManager>

Answer

Yan Sklyarenko picture Yan Sklyarenko · Aug 5, 2011

The idea you should follow in the case of custom membership/role providers is similar to what AD module lists in its setup instructions. The entire process can be split into several steps:

  • Adding a connection string to connectionstrings.config
  • Adding membership/role provider definitions to the system.web section of web.config
  • Activating switchers
  • Creating a new domain for the users/roles from custom provider
  • Adding domain/provider mappings

Adding a connection string

This is pretty straightforward and it seems this is what you've done already. The point is to have a connection string to the database you can then reference from the custom providers.

Adding membership/role provider definitions

Another simple step - just add a membership provider definition (myProvider in your case) under system.web/membership/providers section in web.config, and add a role provider definition under system.web/roleManager/providers section. The order is not important. At this point, you do not modify any other provider definitions in the mentioned sections.

Activating switchers

This is where it becomes complicated. First off, DON'T CHANGE the @defaultProvider attribute value. It is 'sitecore' by default and it should stay as is. Instead, find the provider called "sitecore", and change its @realProviderName attribute value from 'sql' to 'switcher'.

The provider named "switcher" is responsible for all the magic behind switching the providers and combining the results of GetAll/Find methods.

Create a new domain

You should create a new domain for the users/role you'll take from your custom DB through your custom providers. Something like this:

   <domain name="myDomain" ensureAnonymousUser="false"/>

The @ensureAnonymousUser attribute being set to false means that Sitecore won't add an anonymous user to your domain, so there won't be myDomain\Anonymous. This is usually the desired behavior for the custom domains.

Adding domain/provider mappings

This is the last step to let Sitecore know which domain is served with each provider. One provider can handle multiple domains (default Sitecore SQL provider stores the users from 'sitecore' and 'extranet' domains), but not vice versa.

So, open the main web.config file and browse to the configuration/sitecore/switchingProviders section. Add something like this for memberhip subsection:

<provider providerName="myProvider" storeFullNames="false" wildcard="%" 
domains="myDomain" />

and the similar thing for roleManager subsection:

<provider providerName="myProvider" storeFullNames="false" wildcard="%" 
domains="myDomain" />

After this, the users from your DB will be visible as 'myDomain\user' in UserManager, the same is true for roles. The @storeFullNames='false' means that your DB stores the users/roles without domain prefixes, just the local names. Wildcard should be the default value in case your custom source is SQL (which obviously is).

That's it, and now it should work! :-) The details of the steps above are described in this article.