Recently I had a problem where I was writing a webpart to modify some user profile values of people other than the logged in user.
So I do what I usually do, I call:
SPSecurity.RunWithElevatedPrivileges
and found that even though I was impersonating, I would still get errors saying:
Property Not Editable. This property can only be modified by an administrator
or
You may only modify your own profile, unless you are an administrator
I then I also tried my other tactic of creating the SPSite using the System Token from:
SPContext.Current.Site.SystemAccount.UserToken
but again no joy.
I tried a bunch of different things until I stumbled across
this post, that suggested setting the HTTPContect to null just before updating the profile. I thought that could never work, but I tried it anyway. His post is unavailable and I only managed to get it through Google Cache! The sample code was:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPSite sc = new SPSite(SPContext.Current.Site.ID);
ServerContext context = ServerContext.GetContext(sc);
HttpContext currentContext = HttpContext.Current;
HttpContext.Current = null;
UserProfileManager profileManager = new UserProfileManager(context);
UserProfile user = profileManager.GetUserProfile("DOMAIN\\userName");
writer.Write(user.PersonalUrl);
HttpContext.Current = currentContext;
});
and to my amazement it works. It seems with no HTTPContext, SharePoint is unable to determine the current user and so uses the credentials of the actual impersonated user (as it should).
Disgusting - but it saved the day.
UPDATE: Kamilm posted in the comments below a new method for SharePoint 2010:
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);
I know the User Profile system is different in SPS2010 - so will have to give this a try. Thanks Kamlin
UPDATE 25-Feb-2011:
If you are interested in the cause of this problem see Yohan Belval's comment below - very enlightening.