Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Danny 15 posts 136 karma points
    Oct 21, 2014 @ 22:15
    Danny
    0

    Using a custom MembershipProvider for the back office on a load balanced environment

    I have a custom MembershipProvider that communicates with an external authentication service to determine if the username and password provided for a user is valid. This works great on an environment with a single frontend.

    In our environment, the site files are stored on a network share, which is accessed by several frontend servers with a load balancer distributing the traffic (one of the frontend servers is the designated back office/admin server). Setup documentation. This works great using the UsersMembershipProvider that comes with Umbraco.

    When I try to use my custom MembershipProvider in the load balanced environment, publish no longer updates content on the non-admin frontend servers.

    I suspect the problem lies here

      <distributedCall enable="true">    
       <user>0</user><!-- <-- problem -->
        <servers>    
          <server forceProtocol="https" forcePortnumber="443" serverName="adminName">adminName</server>    
          <server forceProtocol="https" forcePortnumber="443" serverName="otherName">otherName</server>    
        </servers>    
      </distributedCall>
    

    refers to the admin account that I set up when I created the site, when it used the UsersMembershipProvider. My custom MembershipProvider doesn't store the user's password anywhere on our site, and it would violate policy to do so.

    Is there a way to have a publish user account without storing the password?

    I also considered calling the UsersMembershipProvider from within my custom MembershipProvider, so the publish user could be an Umbraco user account, but everyone else could authenticate using the external auth service. However, I haven't been able to get the UsersMembershipProvider working from within my MembershipProvider.

    public class MixedCustomProvider: MembershipProvider
    {
        private const String UmbracoProviderName = "UmbracoUsersMembershipProvider";
        private const String CustomProviderName = "CustomMembershipProvider";
    
        public MembershipProvider CustomProvider
        {
            get { return Membership.Providers[CustomProviderName]; }
        }
    
        public MembershipProvider UmbracoProvider
        {
            get { return Membership.Providers[UmbracoProviderName]; }
        }
    
        public override bool ValidateUser(string username, string password)
        {
            // this.UmbracoProvider.ValidateUser returns false when given valid credentials
            return this.UmbracoProvider.ValidateUser(username, password) ||
                this.CustomProvider.ValidateUser(username, password);
        }
    }
    
    <membership defaultProvider="MixedCustomMembershipProvider" userIsOnlineTimeWindow="5">
      <providers>
        <clear />
        <add name="MixedCustomMembershipProvider" type="NS.MembershipProviders.MixedCustomProvider" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="NetIDAlias" passwordFormat="Hashed" />
        <add name="CustomMembershipProvider" type="NS.MembershipProviders.CustomMembershipProvider" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="NetIDAlias" passwordFormat="Hashed" />
        <add name="UmbracoUsersMembershipProvider" type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" passwordFormat="Hashed" />
      </providers>
    </membership>
    
      <providers>
        <users>
         <DefaultBackofficeProvider>MixedCustomMembershipProvider</DefaultBackofficeProvider>
        </users>
      </providers>
    
  • Danny 15 posts 136 karma points
    Oct 27, 2014 @ 21:32
    Danny
    100

    I figured out the issue. Posting for anyone who runs into something similar.

    Issue 1 In the umbracoUser table, the admin account (userID = 0) had userNoConsole set to 1, which was causing the UmbracoMembershipProvider to fail to authenticate the admin account when I gave it valid credentials.

    Issue 2 I ran into This distributed call / shared configuration issue. I'm not sure why this bug didn't cause my initial publish attempts to fail, but when I replaced the umbraco.dll with the patched version publish began working once more.

    On the bright side, the code above works. I improved it by making the providers included in the MixedMembershipProvider configurable, and inheriting from MembershipProviderBase.

    private IEnumerable<String> providerNames;
    public IEnumerable<MembershipProvider> Providers
    {
        get { return this.providerNames.Select(x => Membership.Providers[x]); }
    }
    
    public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
    {
        base.Initialize(name, config);
        this.providerNames = config.GetValues("subProviders").First().Split(',').Select(x => x.Trim());
    }
    
    <add name="UmbracoMembershipProvider" type="N.S.MembershipProviders.MixedMembershipProvider" subProviders="UmbracoUsersMembershipProvider, CustomMembershipProvider" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="NetIDAlias" passwordFormat="Hashed" />
    
Please Sign in or register to post replies

Write your reply to:

Draft