Allowing UserProfileManager Permissions in SharePoint 2010 - sharepoint

I am trying to display a list of users in a custom webpart using the UserProfileManager. For some reason, I can view the webpart and all profiles are output to the screen (maybe because I am an administrator). But when a standard user logs in, they encounter a 403 page.
I have done some reading up on this and I know its something to do with permissions. This is what I have in my code:
private DataTable GetProfiles()
{
DataTable dtUserProfile = new DataTable();
//...DataTable Columns
SPSecurity.RunWithElevatedPrivileges(delegate()
{
Guid guid = SPContext.Current.Site.ID;
using (SPSite intranet = new SPSite(guid))
{
SPUserToken userToken = intranet.Owner.UserToken;
//Get current intranet context.
SPServiceContext sContext = SPServiceContext.GetContext(intranet);
UserProfileManager profileManager = new UserProfileManager(sContext);
int totalUsers = int.Parse(profileManager.Count.ToString());
Random random = new Random();
for (int i = 0; i < NumberOfUsersToRetrieve(NoOfProfiles, totalUsers); i++)
{
int randNumber = random.Next(1, totalUsers);
DataRow drUserProfile;
UserProfile up = profileManager.GetUserProfile(randNumber);
drUserProfile = dtUserProfile.NewRow();
drUserProfile["DisplayName"] = up.DisplayName;
drUserProfile["FirstName"] = up["FirstName"].Value;
drUserProfile["LastName"] = up["LastName"].Value;
drUserProfile["Department"] = up["Department"].Value;
drUserProfile["ContactNumber"] = up["Office"].Value;
drUserProfile["MySiteUrl"] = up.PublicUrl;
dtUserProfile.Rows.Add(drUserProfile);
}
}
});
return dtUserProfile;
}
My code basically gets a random collection of users depending on the number of users I want to return.
Is it possible to create a SPUserToken for a user that all permissions needed to retrieve the user profiles?
Thanks!

I appreciate this question is old, but I had the exact same problem. To help the original poster and other users, I have altered the code from the original post to the following:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPSite sc = new SPSite(SPContext.Current.Site.ID);
SPServiceContext context = SPServiceContext.GetContext(sc);
HttpContext currentContext = HttpContext.Current;
HttpContext.Current = null;
UserProfileManager profileManager = new UserProfileManager(context);
IEnumerator profileEnum = profileManager.GetEnumerator();
while (profileEnum.MoveNext())
{
UserProfile up = (UserProfile)profileEnum.Current;
if ((up["FirstName"] != null && up["FirstName"].Value != null && !String.IsNullOrEmpty(up["FirstName"].Value.ToString()))
&& (up.PublicUrl != null && !String.IsNullOrEmpty(up.PublicUrl.ToString())))
{
DataRow drUserProfile;
drUserProfile = dtUserProfile.NewRow();
drUserProfile["DisplayName"] = up.DisplayName;
drUserProfile["FirstName"] = up["FirstName"].Value;
drUserProfile["LastName"] = up["LastName"].Value;
drUserProfile["Department"] = up["Department"].Value;
drUserProfile["Location"] = up["SPS-Location"].Value;
drUserProfile["MySiteUrl"] = up.PublicUrl.ToString().Replace(#"\", #"\");
dtUserProfile.Rows.Add(drUserProfile);
}
}
}
HttpContext.Current = currentContext;
Hopefully this code should resolve the error.

Instead of getting the UserToken of SPSite.Owner, have you tried SPSite.SystemAccount.UserToken, or SPWeb.AllUsers["user"].UserToken;
I'd do the latter if possible, rule of least privileges etc.

Related

How can I create new site (not subsite ) in sharepoint online using CSOM

I want to create new site at root level (not subsite in existing site). I am using CSOM for creating site. In current scenario I need to provide the Site URL to client context for authentication and perform operations. Here is a pseudo code.
string url = "https://mysharepoint.com/sites/testsite";
SecureString f_SecurePass = new SecureString();
foreach (char ch in pass)
f_SecurePass.AppendChar(ch);
clientcontext = new ClientContext(url);
var credentials = new SharePointOnlineCredentials(userid, f_SecurePass);
clientcontext.Credentials = credentials;
Web web = clientcontext.Web;
clientcontext.Load(web, website => website.Lists);
clientcontext.ExecuteQuery();
WebCreationInformation wci = new WebCreationInformation();
wci.Url = "/TestAPISite2";
wci.Title = "TestAPISite2";
wci.Language = 1033;
var newsite = clientcontext.Site.RootWeb.Webs.Add(wci);
clientcontext.ExecuteQuery();
Please suggest the solution.
Regarding the requirement:
I want to create new site at root level (not subsite in existing
site).
in SharePoint terminology it is called a site collection:
site collection / top level site / parent site - a site collection
is a web site that can contain sub-sites (aka webs)
In SharePoint CSOM API Tenant class is intended for that purpose, in particular Tenant.CreateSite method.
Here is an example:
const string username = "username#contoso.onmicrosoft.com";
const string password = "password";
const string tenantAdminUrl = "https://contoso-admin.sharepoint.com/";
using (var ctx = GetContext(tenantAdminUrl,userName,password))
{
CreateSite(ctx, "https://contoso.sharepoint.com/sites/marketing","Marketing");
}
where
internal static void CreateSite(ClientContext context, String url, String owner, String title =null, String template = null, uint? localeId = null, int? compatibilityLevel = null, long? storageQuota = null, double? resourceQuota = null, int? timeZoneId = null)
{
var tenant = new Tenant(context);
if (url == null)
throw new ArgumentException("Site Url must be specified");
if (string.IsNullOrEmpty(owner))
throw new ArgumentException("Site Owner must be specified");
var siteCreationProperties = new SiteCreationProperties {Url = url, Owner = owner};
if (!string.IsNullOrEmpty(template))
siteCreationProperties.Template = template;
if (!string.IsNullOrEmpty(title))
siteCreationProperties.Title = title;
if (localeId.HasValue)
siteCreationProperties.Lcid = localeId.Value;
if (compatibilityLevel.HasValue)
siteCreationProperties.CompatibilityLevel = compatibilityLevel.Value;
if (storageQuota.HasValue)
siteCreationProperties.StorageMaximumLevel = storageQuota.Value;
if (resourceQuota.HasValue)
siteCreationProperties.UserCodeMaximumLevel = resourceQuota.Value;
if (timeZoneId.HasValue)
siteCreationProperties.TimeZoneId = timeZoneId.Value;
var siteOp = tenant.CreateSite(siteCreationProperties);
context.Load(siteOp);
context.ExecuteQuery();
}
and
public static ClientContext GetContext(string url, string userName, string password)
{
var securePassword = new SecureString();
foreach (var ch in password) securePassword.AppendChar(ch);
return new ClientContext(url) {Credentials = new SharePointOnlineCredentials(userName, securePassword)};
}

Need help in converting DirectoryServices code to PrincipalContext

DirectorySearcher deSearch;SearchResultCollection result;
deSearch.SearchRoot = baseResult.GetDirectoryEntry();// I know this one can be done like - PrincipalContext pContext = new PrincipalContext(ContextType.Domain, deSearch.SearchRoot.Path);
deSearch.Filter = "(&(&(objectClass=user)(objectCategory=person))(name=" + name + "))"; //???? **Not sure how to apply the filter in Principal Context**
results = deSearch.FindAll();
Please help me in applying filter in principlecontext
You can use PrincipalSearcher to search for a particular user.
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
UserPrincipal searchUser = new UserPrincipal(ctx);
searchUser.GivenName = "Name";
PrincipalSearcher srch = new PrincipalSearcher(searchUser);
foreach(var found in srch.FindAll())
{
//found will contain the info
}
}
You can also use UserPrincipal.
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.DistinguishedName, "DN"))
if (user != null)
{
//user contains info
}
}
You can define different IdentityType if you want to search by samAccountName or etc.

Programmatically checkout webpage sharepoint

Im trying to remove all content in page. but i get an exception when i trying to do this, it says that the file is not checked out and i have to do this. And when i use file.CheckOut() I see that the file is checked out to the systemAccount and i get exception:
The file is CheckedOut to another user
How to do that i can ignore the CheckOut to the current/specific user
this is what i have tried
SPSecurity.RunWithElevatedPrivileges(delegate()
{
var webMngr = web.GetLimitedWebPartManager("Sidor/default.aspx", PersonalizationScope.Shared);
List<System.Web.UI.WebControls.WebParts.WebPart> webPartList = (from System.Web.UI.WebControls.WebParts.WebPart webPart in webMngr.WebParts select webPart).ToList();
SPFile file = web.GetFile(web.Url+"Sidor/default.aspx");
web.AllowUnsafeUpdates = true;
if (file.CheckOutType == SPFile.SPCheckOutType.Online)
{
file.CheckIn("Comment");
}
file.CheckOut();
object _lock = new object();
lock (_lock)
{
for (int i = 0; i < webMngr.WebParts.Count; i++)
{
webMngr.DeleteWebPart(webPartList[i]);
}
}
web.AllowUnsafeUpdates = false;
});
file.forceCheckOut = false
here the msdn function
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splist.forcecheckout(v=office.15).aspx

Error when I run the SPDisposeChecker tool

I am getting the error "Disposable type not disposed Microsoft.SharePoint.SPWeb ***This may be a false positive depending on how the type was created or if it is disposed outside the current scope".
Below is my code :
public static int AddtoList( string title)
{
int returnValue = int.MinValue;
SPUser sysAcount = SPContext.Current.Web.AllUsers[#"SHAREPOINT\SYSTEM"];
SPUserToken sysAcountToken = sysAcount.UserToken;
using (SPSite siteCollection = new SPSite(SPContext.Current.Site.Url, sysAcountToken))
{
SPWeb currentWeb = siteCollection.RootWeb;
SPList list = currentWeb.Lists[MyList];
SPListItem newItem = errorList.Items.Add();
newItem[TitleColumnName] = title;
currentWeb.AllowUnsafeUpdates = true;
newItem.SystemUpdate(false);
currentWeb.AllowUnsafeUpdates = false;
returnValue = newItem.ID;
}
return returnValue;
}
I understood that when we use RootWeb we do not have dispose the object. Please let me know what does this error message mean and how do I correct it . I have several blogs bug failed to understand the error. Please help me.
Do you have the most up to date version of SPDisposeCheck?
An older version (Dec 2010?) incorrectly flagged .RootWeb
http://blogs.technet.com/b/stefan_gossner/archive/2010/12/15/first-issue-with-spdisposecheck-has-been-identified-by-the-community.aspx
Please try below code sample for SPDisposeChecker error resolve.
public static int AddtoList( string title)
{
int returnValue = int.MinValue;
SPUser sysAcount = SPContext.Current.Web.AllUsers[#"SHAREPOINT\SYSTEM"];
SPUserToken sysAcountToken = sysAcount.UserToken;
using (SPSite siteCollection = new SPSite(SPContext.Current.Site.Url, sysAcountToken))
{
//Add below code for dispose currentWeb object end of the functionality
using(SPWeb currentWeb = siteCollection.RootWeb)
{
SPList list = currentWeb.Lists[MyList];
SPListItem newItem = errorList.Items.Add();
newItem[TitleColumnName] = title;
currentWeb.AllowUnsafeUpdates = true;
newItem.SystemUpdate(false);
currentWeb.AllowUnsafeUpdates = false;
returnValue = newItem.ID;
}
}
return returnValue;
}
Happy SharePointing !!!
Thanks,

How to add a term to TermCollection (taxonomy field)

In sharePoint 2010, I want to set taxonomy values of a document field. The field can take multiple taxonomy terms.
I am doing it the wrong way because the cast of taxoTerms.Concat(terms) in TermCollection class fails :
TaxonomyField taxoField = file.Item.Fields.GetFieldByInternalName(entry.Key)
as TaxonomyField;
TaxonomySession taxoSession = new TaxonomySession(web.Site);
TermStore store = taxoSession.TermStores[taxoField.SspId];
TermSet termSet = store.GetTermSet(taxoField.TermSetId);
if (taxoField.AllowMultipleValues)
{
string[] taxoValues = entry.Value.Split(';');
TermCollection taxoTerms = termSet.GetTerms(taxoValues[0], true);
for (int j = 1; j < taxoValues.Length; j++)
{
TermCollection terms = termSet.GetTerms(taxoValues[j], true);
if (terms.Count > 0)
{
taxoTerms = (TermCollection)taxoTerms.Concat(terms);
}
}
taxoField.SetFieldValue(file.Item, taxoTerms);
}
Do you know how can I add terms to my TermCollection object so I can save the term values in the field ?
I found my solution. Here it is :
TaxonomyField taxoField =
file.Item.Fields.GetFieldByInternalName(entry.Key) as TaxonomyField;
TaxonomySession taxoSession = new TaxonomySession(web.Site);
TermStore store = taxoSession.TermStores[taxoField.SspId];
TermSet termSet = store.GetTermSet(taxoField.TermSetId);
if (taxoField.AllowMultipleValues)
{
string[] taxoValues = entry.Value.Split(';');
TermCollection terms = termSet.GetAllTerms();
List<string> taxonomyValueList = taxoValues.ToList<string>();
TaxonomyFieldValueCollection fieldValues = new TaxonomyFieldValueCollection(taxoField);
foreach (Term term in terms)
{
if (taxonomyValueList.Contains(term.Name))
{
TaxonomyFieldValue fieldValue = new TaxonomyFieldValue(taxoField);
fieldValue.TermGuid = term.Id.ToString();
fieldValue.Label = term.Name;
fieldValues.Add(fieldValue);
}
}
taxoField.SetFieldValue(file.Item, fieldValues);
}
Hope it helps others.
Here is a sample that could work:
var item = file.Item;
var taxonomyField = item.Fields.GetFieldByInternalName(entry.Key);
var values = new TaxonomyFieldValueCollection(taxonomyField);
values.PopulateFromLabelGuidPairs(entry.Value);
item[entry.Key] = values;
item.Update();
I did not test it on a life system so there can be some additional work, but I hope you get the general idea. The values in the entry.Value string have to contain the | and ; separated list of tags. If the tag does not exist you have to create it and get its id before you save it to the item.
HTH
Vojta

Resources