RoleList in the current PrincipalInfo behaving badly with AD membership/role provider

PLACE FOR BLOG

  • Home
  • /
  • Blogs
  • /
  • marija's blog
  • / RoleList in the current PrincipalInfo behaving badly with AD membership/role provider
RoleList in the current PrincipalInfo behaving badly with AD membership/role provider

RoleList in the current PrincipalInfo behaving badly with AD membership/role provider

marija

We have been using the standard search solution in an AD authentication based Intranet. It did work locally, I swear! But, for some of the test users, it just behaved unpredictably.

Intro

The search solution was more or less taken from the AlloyTech, at least majority of code that creates the Lucene query. After some time of debugging with different users, I got the correct results after skipping the execution of the code that adds AccessControlListQuery to the query expressions in the debugger.

Catching the issue

Then, the dotPeek came in handy again and I c/p-ed and called AccessControlListQueryExtensions from our code instead.

The troublesome value in public static void AddAclForUser(this AccessControlListQuery query, VirtualRoleRepository virtualRoleRepository, PrincipalInfo principal, object context) was principal.RoleList!

For some users, it was null, for others it gave only virtual roles and for some, it gave perfectly fine results. I didn't figure out why, since users with almost the same ActiveDirectory groups gave completely different results. But, I could easily change the extension method to fetch these roles instead of using principal.RoleList.

Solution

For the sake of clarity, I've named the extension method AddAclForUserFetchRoles. The only line that is different there is:

    var roleList = Roles.GetRolesForUser(principal.Name);

The whole class AccessControlListQueryExtensions can be found here:

using System.Web.Security;
using EPiServer.Framework;
using EPiServer.Search.Queries.Lucene;
using EPiServer.Security;

namespace PROJECT.Intranet.Service
{
    /// 
    /// This class is added as a workaround of the issue where some users had nothing in the principal.RoleList
    /// or only virtual roles
    /// Now, we fetch the roles by from the membership provider instead
    /// To view original code, disassemble AccessControlListQueryExtensions from EPiServer.Search.Queries.Lucene
    /// 
    public static class AccessControlListQueryExtensions
    {
        /// 
        /// Adds the roles and username of the provided user to the query.
        /// 
        /// 
        /// The query to extend.The principal.The context used for virtual roles to establish if the user is a part of a role.
        public static void AddAclForUserFetchRoles(this AccessControlListQuery query, PrincipalInfo principal, object context)
        {
            AddAclForUserFetchRoles(query, VirtualRoleRepository.GetDefault(), principal, context);
        }

        /// 
        /// Adds the roles and username of the provided user to the query.
        /// 
        /// 
        /// The query to extend.The virtual role repository used to retrieve virtual roles.The principal.The context used for virtual roles to establish if the user is a part of a role.
        public static void AddAclForUserFetchRoles(this AccessControlListQuery query, VirtualRoleRepository virtualRoleRepository, PrincipalInfo principal, object context)
        {
            if (principal == null) return;

            Validator.ThrowIfNull("virtualRoleRepository", virtualRoleRepository);
            if (!string.IsNullOrEmpty(principal.Name))
            {
                query.AddUser(principal.Name);
            }

            var roleList = Roles.GetRolesForUser(principal.Name);
            if (roleList != null)
            {
                foreach (var roleName in roleList)
                {
                    query.AddRole(roleName);
                }
            }

            foreach (var str in virtualRoleRepository.GetAllRoles())
            {
                VirtualRoleProviderBase virtualRoleProvider;
                if (virtualRoleRepository.TryGetRole(str, out virtualRoleProvider) && 
                    virtualRoleProvider.IsInVirtualRole(principal.Principal, context))
                {
                    query.AddRole(str);
                }
            }
        }
    }
}

With this, search worked for all users :)

LEAVE A COMMENT