Tuesday, February 19, 2013

SharePoint 2010 - Edit SharePoint Group raise Access Denied Exception

If you experience "Access Denied" exception editing SharePoint Group Property, probably this article can give you some suggestion.

SharePoint page that give you ability to edit group properties in SharePoint 2010 runs with the permissions of the user who invokes it.
The operations that were successful were those related to the Update of the characteristics of the group, and immediately after it was returned "Access Denied".
By reverse eng the assembly from which SharePoint editgrp.aspx inherits (Microsoft.SharePoint.ApplicationPages.dll), what is clear is that, following the method "sPGroup.Update ();" there's a call to a base method called "UpdateAdditionalProperties".
This method essentially updates the description of the group on the hidden list "UserInfo" (properties siteUserInfoList of the Site Collection) that keeps track of all information related to Users and Groups.

This method returns an Access Denied exception (from tracelog: SPRequest Unknown error occurred. More information: 0x80070005).
User is also redirected to AccessDenied.aspx page.

This is the code from SharePoint dll.

// Microsoft.SharePoint.ApplicationPages.EditGroup
protected override int DoOperation()
{
 base.Trace.Write("Editing Group", "");
 if (this.RadAllowRequestToJoinLeaveYes.Checked && !this.RadAutoAcceptRequestYes.Checked && !SPUtility.IsEmailServerSet(base.Web))
 {
  throw new SPException(SPResource.GetString("RequestJoinLeaveGroupEmailServerSettingsInvalid", new object[0]));
 }
 SPGroup sPGroup = base.Web.SiteGroups[this.hdnGrpName.Value];
 if (sPGroup != null)
 {
  if (sPGroup.Name != this.m_strGrpName)
  {
   sPGroup.Name = this.m_strGrpName;
  }
  SPMember memberFromPeoplePicker = base.GetMemberFromPeoplePicker();
  sPGroup.Owner = memberFromPeoplePicker;
  sPGroup.AllowRequestToJoinLeave = this.RadAllowRequestToJoinLeaveYes.Checked;
  sPGroup.AutoAcceptRequestToJoinLeave = this.RadAutoAcceptRequestYes.Checked;
  sPGroup.OnlyAllowMembersViewMembership = this.RadViewMembershipGroupMembers.Checked;
  sPGroup.AllowMembersEditMembership = this.RadEditMembershipGroupMembers.Checked;
  if (this.RadAllowRequestToJoinLeaveYes.Checked && !this.RadAutoAcceptRequestYes.Checked)
  {
   sPGroup.RequestToJoinLeaveEmailSetting = this.TxtRequestEmail.Text.Trim();
  }
  sPGroup.ClearDistributionGroupErrorMessage();
  if (base.DistributionGroupsAvailable)
  {
   ErrorPage.SetupInfoForMessageContainingLink(this.Context, "GroupDistributionGroupErrorMessageContainingLink", "GroupSettingsPage", base.Web.GetServerRelativeUrlFromUrl("_layouts/editgrp.aspx?Group=" + SPHttpUtility.UrlKeyValueEncode(sPGroup.Name)));
   if (this.CreateDLTrue.Checked)
   {
    if (string.IsNullOrEmpty(sPGroup.DistributionGroupAlias))
    {
     sPGroup.CreateDistributionGroup(this.DLAlias.Text);
    }
    else
    {
     if (this.DLAlias.Text != sPGroup.DistributionGroupAlias)
     {
      sPGroup.RenameDistributionGroup(this.DLAlias.Text);
     }
    }
    if (this.ArchiveListExisting.Checked)
    {
     List<SPList> list = new List<SPList>();
     foreach (ListItem listItem in this.ArchiveListExistingLists.Items)
     {
      if (listItem.Selected)
      {
       list.Add(base.Web.Lists[new Guid(listItem.Value)]);
      }
     }
     sPGroup.SetDistributionGroupArchives(new ReadOnlyCollection<SPList>(list), base.Web);
    }
    else
    {
     if (this.ArchiveListNew.Checked)
     {
      base.CreateNewArchiveList(sPGroup, base.Web, this.ArchiveListNewName.Text);
     }
     else
     {
      sPGroup.SetDistributionGroupArchives(new ReadOnlyCollection<SPList>(new List<SPList>()), base.Web);
     }
    }
   }
   else
   {
    if (this.CreateDLFalse.Checked && !string.IsNullOrEmpty(sPGroup.DistributionGroupAlias))
    {
     sPGroup.DeleteDistributionGroup();
    }
   }
   ErrorPage.CleanupInfoForMessageContainingLink(this.Context);
  }
  sPGroup.Update();
 }
 base.UpdateAdditionalProperties(sPGroup.ID);
 return 0;
}


*** This one is the method that raise "Access Denied" exception and the consequent UI redirect to the Access Denied Exception. ***

// Microsoft.SharePoint.ApplicationPages.CBaseNewGroup
protected void UpdateAdditionalProperties(int groupId)
{
 SPList siteUserInfoList = base.Web.SiteUserInfoList;
 SPListItem itemById = siteUserInfoList.GetItemById(groupId);
 string text = this.txtGrpDescription.Text;
 itemById["Notes"] = text;
 int num = 1;
 while (true)
 {
  string text2 = base.Request.QueryString["FieldName" + num.ToString(CultureInfo.InvariantCulture)];
  if (string.IsNullOrEmpty(text2))
  {
   break;
  }
  string value = base.Request.QueryString["FieldValue" + num.ToString(CultureInfo.InvariantCulture)];
  itemById[text2] = value;
  num++;
 }
 itemById.Update();
}


At this point I've checked with powershell the property "EffectiveBasePermissions" over UserInfo list, comparing the result with another Test Farm (which is working fine).
On Test Farm this collection was valued at FullMask. On Production Farm this collection was listing a number of base permissions.

The missing permission is the one related to the Update User Information.
From central admin, at WebApplication level, invoking "User Permissions" dialog, what I've discovered is that there was no flag on the basic permission "Edit Personal User Information".
Settings this flag=true on the webapplication affected will result in no more "Access Denied" redirect .



This bug/behavior has been verified on SharePoint 2010 SP1 + October 2012 CU.

No comments: