12

I am using Sitecore version 8.1.160302

I am attempting to implement some logic when users are added to or removed from Administrator roles. The basic idea is that if a user is being added to a role that is structured as {domain}\Administrator, then some logic will fire to grab a number of domains to add to the user's list of managed domains. If the role is structured as {domain}\User Administrator then just that domain should be added. If the user is removed from a role then their managed domains should be recalculated (there is some redundancy in roles managing domains due to the logic).

I have hooked into the roles:usersAdded and roles:usersRemoved events, and can see in the debugger that my code is executing, but for some reason my changes are not being saved. The code reports no errors, but viewing the user's managed domains shows that the changes weren't saved.

public void OnRolesModified(object sender, EventArgs args)
    {
        //Each user in users is being removed from each role in roles
        //If any roles are Admin roles, this affects Managed Domains
        //Otherwise do nothing

        string[] users = Sitecore.Events.Event.ExtractParameter<string[]>(args, 0);
        string[] roles = Sitecore.Events.Event.ExtractParameter<string[]>(args, 1);

        //If any roles are Admin roles, this affects Managed Domains. Otherwise do nothing.
        if (roles.Any(p => p.Contains("Administrator")))
        {
            //I would expect this to always be one user, but iterate through the list in case there are more
            foreach (string userName in users)
            {
                Sitecore.Security.Accounts.User user = Sitecore.Security.Accounts.User.FromName(userName, true);
                string managedDomains = string.Empty;
                foreach (Sitecore.Security.Accounts.Role role in user.Roles.Where(p => p.Name.Contains("Administrator")))
                {
                    //roles are Domain\Role, so grab domain
                    string domain = role.Domain.Name;

                    if (role.Name.Contains("\\Administrator"))
                    {
                        //If the role has a backslash before the word Administrator, it's a root site
                        //Add all the subdomains to managed domains.
                        Sitecore.Data.Items.Item item = Sitecore.Data.Database.GetDatabase("master").SelectSingleItem(string.Format("fast:/sitecore/content/{0}", domain));
                        if (item != null)
                        {
                            IEnumerable<Sitecore.Security.Accounts.Account> acctList = item.Security.GetAccessRules().Helper.GetAccounts();
                            foreach (Sitecore.Security.Accounts.Account acct in acctList)
                            {
                                managedDomains = AddDomain(managedDomains, acct.Domain.Name);
                            }
                        }
                    }
                    else
                    {
                        //If the role doesn't have a backslash before the word Administrator, it's not a root site
                        //Add just the specific domain to managed domains.
                        managedDomains = AddDomain(managedDomains, domain);
                    }
                }
                //Set the managed domains for the user
                SaveDomains(user,managedDomains);
            }
        }
    }

    private void SaveDomains(Sitecore.Security.Accounts.User user, string managedDomains)
    {
        using (new Sitecore.SecurityModel.SecurityDisabler())
        {
            Sitecore.Security.UserProfile profile = user.Profile;
            profile.ManagedDomainNames = managedDomains;
            profile.Save();
        }
    }

    private string AddDomain(string managedDoms, string domain)
    {
        if (managedDoms == "")
        {
            managedDoms = domain;
        }
        else if (!managedDoms.Split('|').Any(p => p == domain))
        {
            managedDoms = string.Format("{0}|{1}", managedDoms, domain);
        }

        return managedDoms;
    }

The only thing I've been able to find that seems suspicious is the value IsSynchronized of the UserProfile is false, but I don't actually know if that matters.

2
  • 1
    Done a quick Google and noticed on this blog post: blog.nikkipunjabi.com/2015/08/… they're calling Profile.Reload() after the Save() - could you try this and see if the tried profile contains the saved data? Commented Oct 14, 2017 at 7:44
  • 1
    After calling .Reload() the debugger shows the profile to still contain the updated value, but resuming execution and double-checking in Sitecore shows the value is still unchanged. Might be worth noting that the blog post is for an earlier version of Sitecore than what I am using - I've updated the question to include version. Commented Oct 16, 2017 at 14:07

1 Answer 1

0

Heard back from Sitecore support, the solution that was decided on was to add a delay to the code to prevent it from firing until a second had passed. The issue is that this code fires before the dialogue window closes, and when the window closes it fires another save that was overwriting what I had just set. So the solution is to wait until that is done to fire the save.

I'm not a huge fan of throwing in delays as a solution - it always feels more likely to cause inconsistencies and issues down the line. The solution we went with was to move the code to the login pipeline, so that a user's managed domains are recalculated every time they login. This has its own disadvantaged - namely, we can't give special one-off privileges that fall outside our rules, as they will be lost as soon as the user logs in - but it's the best solution we've found.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.