Monday, November 22, 2010

Managing Memberships, Colleagues and Links for Other SharePoint User Profiles

Programming the SharePoint 2010 UserProfileManager, ColleagueManager, QuickLinkManager and MembershipManager seems simple enough, until you try to manage these profile aspects for other users. There are several quirks that when forgotten throws an UnauthorizedAccessException with the message "This operation requires you to be managing your own data or have administrator privileges".

Note that using the well known RunWithElevatedPrivileges is not sufficient to read the profile data of other users. To be able to do that, your UserProfileManager code must either run as a user profile manager, or be configured to respect the built-in privacy control using the IgnoreUserPrivacy parameter. Note how the SDK is very vague on using true or ...hmm... true?
When this parameter is true, administrators can load and access complete user records for any user profile objects. When this parameter is true, administrators work as regular users and can load only trimmed profile information based on the user profile’s privacy setting.
As it turns out, you must use false to get the expected behavior to avoid getting the access denied exception as a normal user. Only accounts that are registered as User Profile service application (UPA) managers will have access to ignore user privacy. If your code use IgnoreUserPrivacy = true and runs as an account that is not an UPA administrator, you will get this error:
You must have manage user profiles administrator rights to use administrator mode.

Set IgnoreUserPrivacy to false when creating the UserProfileManager object, as shown here:

//profile and membership internally use ValidateIsSelfOrAdmin, must use IgnoreUserPrivacy = false
string siteUrl = SPContext.Current.Site.Url;
using (SPSite mySite = new SPSite(siteUrl))
{
SPServiceContext context = SPServiceContext.GetContext(mySite);
UserProfileManager profileManager = new UserProfileManager(context, false);

MySiteUtilities profileSiteInfo = new MySiteUtilities(Page);
UserProfile userProfile = profileManager.GetUserProfile(profileSiteInfo.CurrentProfileSiteAccountName);

MembershipManager memberManager = userProfile.Memberships;
Membership[] membershipList = memberManager.GetItems(MembershipSortType.Alphabetical);

. . .
//membership management code here
. . .

}

If you need to ignore the user privacy to filter memberships or access private profile properties, or manage user profiles in general, then you must be an UPA administrator or the code must implement Windows impersonation as the user profile manager ignores RunWithElevatedPrivileges.

Note that SharePoint site memberships are periodically processed by the "User Profile Service Application Proxy - User Profile to SharePoint Full/Quick Synchronization" timer jobs, and that only direct account membership in a site's member SharePoint group will be registered in the user profile membership list. Having access to a site through an AD security group will not do, as SharePoint don't resolve AD group memberships.