Programmatically updating locked down user profile attributes from a web part

Central Admin User Profile Service Profile PropertyIn our organization, we have a policy in place that only a peron’s organizational ID photo may be used in their SharePoint user profile.  We have it set to show by default.  However, we also allow them to “opt-out” of having it displayed.  We’ve created a simple web part that has two buttons to opt-in or opt-out of the photo being displayed in various systems in our organization.  To disable it in SharePoint and in Active Directory, we require that the “PictureUrl” user profile attribute be empty (not pointing to an image).  We have a reverse sync of that particular attribute back to Active Directory.  The Active Directory “thumbnailPhoto” is used in other various systems around the organization that integrate into Active Directory.  For the PictureUrl attribute, we have it set so that users cannot modify it.  Afterall, we don’t want them uploading in appropriate photos!

Central Admin User Profile Service PermissionsBut our opt-out web part needed to be able to modify that attribute.  Like most other web parts, it runs under the current user context.  Our non-admins do not have “Manage Profile” rights as that would be very dangerous since it would give a user access to other user’s profile data.  So the following code produced the error “Property Not Editable: This property can only be modified by an administrator”.

SPServiceContext serviceContext = SPServiceContext.GetContext(HttpContext.Current);
UserProfileManager upm = new UserProfileManager(serviceContext);
UserProfile up = upm.GetUserProfile(“DOMAIN\username”);
up["PictureURL"].Value = “http://www.someurl.com/image.jpg”;
up.Commit();

So the next logical step is to run the code using elevated privileges (RunWithElevatedPrivileges).

SPSecurity.RunWithElevatedPrivileges(delegate()
{
…code snippet from above…
});

But that still didn’t work, we continued to get the same error.

After some research, we found others who ran into the same problem and apparently user profile access has some problems using impersonation (as in it just doesn’t work!).  Somebody did find a workaround though, a hack of sorts, by removing the current context reference before calling the UPM.

SPSecurity.RunWithElevatedPrivileges(delegate()
{
HttpContext httpContext = HttpContext.Current;
SPServiceContext serviceContext = SPServiceContext.GetContext(httpContext);
HttpContext.Current = null; // Hack !!!
UserProfileManager upm = new UserProfileManager(serviceContext);
UserProfile up = upm.GetUserProfile(“DOMAIN\username”);
up["PictureURL"].Value = “http://www.someurl.com/image.jpg”;
up.Commit();
HttpContext.Current = httpContext; // Restore !!!
});

This technique has been working fine for me in SharePoint 2010.  However, I have seen some blog posts with the following technique which some say is more appropriate for SharePoint 2010 and doesn’t involve a hack.  I haven’t tried this method yet.

UserProfileConfigManager upcm = new UserProfileConfigManager(spServiceContext);
ProfilePropertyManager ppm = upcm.ProfilePropertyManager;
CorePropertyManager cpm = ppm.GetCoreProperties();
CoreProperty cp = cpm.Create(false);
ProfileTypePropertyManager ptpm = ppm.GetProfileTypeProperties(ProfileType.User);
ProfileTypeProperty ptp = ptpm.Create(cp);psp.IsUserEditable = true; // important in this case!
ProfileSubtypeManager psm = ProfileSubtypeManager.Get(spServerContext);
ProfileSubtype ps = psm.GetProfileSubtype(ProfileSubtypeManager.GetDefaultProfileName(ProfileType.User));
ProfileSubtypePropertyManager pspm = ps.Properties;
ProfileSubtypeProperty psp = pspm.Create(ptp);
Be Sociable, Share!

Leave a Reply

*