CSOM give edit permissions to group on SharePoint list - sharepoint

I'm creating a new list in CSOM for SharePoint Online, but I'm very new to this so I'm stuck on changing the permissions.
There are 3 user groups, owners, visitors and members. I'd like to give the visitors editing rights on this list.
I've managed to break inheritance and get all the visitors with the following code, but I'm stuck on how to give them new permissions
newList.BreakRoleInheritance(false, true);
var visitors = ctx.Web.SiteGroups;
ctx.Load(visitors, groupitems => groupitems.Include(groupitem => groupitem.Title,
groupitem => groupitem.LoginName).Where(groupitem=> groupitem.Title == visitorsGroupName));

You can do something similar to this one:
foreach(var grpUser in grpUsers)
{
Principal user = ctx.Web.SiteUsers.GetByLoginName(grpUser);
RoleDefinition writeDefinition = ctx.Web.RoleDefinitions.GetByName("Edit");
RoleDefinitionBindingCollection roleDefCollection = new RoleDefinitionBindingCollection(ctx);
roleDefCollection.Add(writeDefinition);
RoleAssignment newRoleAssignment = ctx.Web.RoleAssignments.Add(grpUser, roleDefCollection);
}
ctx.ExecuteQuery();
This assumes that there is an "Edit" permission level which is available by default in SharePoint. Let me know if it works.

You could try this
var EditRole= new RoleDefinitionBindingCollection(ctx);
EditRole.Add(ctx.Web.RoleDefinitions.GetByType(RoleType.Editor));
Microsoft.SharePoint.Client.Group visitors= ctx.Web.SiteGroups.GetByName("visitors");
ctx.Load(visitors);
newList.RoleAssignments.Add(visitors, EditRole);
ctx.ExecuteQuery()

Related

Access denied office 365 / SharePoint online with Global Admin account

I am going crazy since two days solving an issue. The problem is;
I am making a console APP which is talking to SharePoint Online using global admin account (One which was specified as admin while making a new subscription). What I am trying to achieve is, I want to add a custom action using CSOM to each site collection and subsite of office 365. That code works fine except on the root site collection which is pre-created by office 365 while signing up (i.e. https://xyz.sharepoint.com)
For any tenant for root site collection, it gives me below error;
{
"SchemaVersion":"15.0.0.0","LibraryVersion":"16.0.3912.1201","ErrorInfo":{
"ErrorMessage":"Access denied. You do not have permission to perform
this action or access this
resource.","ErrorValue":null,"TraceCorrelationId":"2a47fd9c-c07b-1000-cfb7-cdffbe3ab83a","ErrorCode":-2147024891,"ErrorTypeName":"System.UnauthorizedAccessException"
},"TraceCorrelationId":"2a47fd9c-c07b-1000-cfb7-cdffbe3ab83a" }
Now the user is global admin. I also added again that user as site collection admin.
The same piece of code works fine on other site collections (search site collection, any newly made site collection...).
here is a code;
using (ClientContext spcollContext = new ClientContext(web.Url))
{
SecureString passWord = new SecureString();
foreach (char c in strAdminPassword.ToCharArray()) passWord.AppendChar(c);
SharePointOnlineCredentials creds = new SharePointOnlineCredentials(strAdminUser, passWord);
spcollContext.Credentials = creds;
Web currentweb = spcollContext.Web;
spcollContext.Load(currentweb);
spcollContext.ExecuteQuery();
// authCookie = creds.GetAuthenticationCookie(new Uri(web.Url));
var existingActions2 = currentweb.UserCustomActions;
spcollContext.Load(existingActions2);
spcollContext.ExecuteQuery();
var actions2 = existingActions2.ToArray();
foreach (var action in actions2)
{
if (action.Description == "CustomScriptCodeForEachsite" &&
action.Location == "ScriptLink")
{
action.DeleteObject();
spcollContext.ExecuteQuery();
}
}
var newAction2 = existingActions2.Add();
newAction2.Description = "CustomScriptCodeForEachsite";
newAction2.Location = "ScriptLink";
newAction2.ScriptBlock = scriptBlock;
newAction2.Update();
spcollContext.Load(currentweb, s => s.UserCustomActions);
spcollContext.ExecuteQuery(); // GETTING ERROR ON THIS LINE.
}
Note: Above error is Fiddler traces.
Most probably this behavior is caused by Custom Script feature, basically
the issue occurs when the Custom Script feature is turned off
How to verify?
You could verify the site permissions using the following console app:
using (var ctx = GetContext(webUri, userName, password))
{
var rootWeb = ctx.Site.RootWeb;
ctx.Load(rootWeb, w => w.EffectiveBasePermissions);
ctx.ExecuteQuery();
var permissions = rootWeb.EffectiveBasePermissions;
foreach (var permission in Enum.GetValues(typeof(PermissionKind)).Cast<PermissionKind>())
{
var permissionName = Enum.GetName(typeof(PermissionKind), permission);
var hasPermission = permissions.Has(permission);
Console.WriteLine("Permission: {0}, HasPermission: {1}", permissionName, hasPermission);
}
}
where
public static ClientContext GetContext(Uri webUri, string userName, string password)
{
var securePassword = new SecureString();
foreach (var ch in password) securePassword.AppendChar(ch);
return new ClientContext(webUri) {Credentials = new SharePointOnlineCredentials(userName, securePassword)};
}
When SP.PermissionKind.AddAndCustomizePages is set to False, the Access denied error occurs while adding user custom action.
Solution
According to Turn scripting capabilities on or off:
For self-service created sites, custom scripting is disabled by
default
Solution: enable Allow users to run custom scripts on self-service created sites
To enable or disable scripting from the SharePoint admin center
Sign in to Office 365 with your work or school account.
Go to the SharePoint admin center.
Select Settings.
Under Custom Script choose:
Prevent users from running custom script on personal sites or Allow
users to run custom script on personal sites.
Prevent users from running custom script on user created sites or
Allow users to run custom script on self-service created sites.
Select OK. It takes about 24 hours for the change to take
effect.
Since any change to the scripting setting made through the SharePoint Online admin center may take up to 24 hours to take effect, you could enable scripting on a particular site collection immediately via CSOM API (SharePoint Online Client Components SDK) as demonstrated below:
public static void DisableDenyAddAndCustomizePages(ClientContext ctx, string siteUrl)
{
var tenant = new Tenant(ctx);
var siteProperties = tenant.GetSitePropertiesByUrl(siteUrl, true);
ctx.Load(siteProperties);
ctx.ExecuteQuery();
siteProperties.DenyAddAndCustomizePages = DenyAddAndCustomizePagesStatus.Disabled;
var result = siteProperties.Update();
ctx.Load(result);
ctx.ExecuteQuery();
while (!result.IsComplete)
{
Thread.Sleep(result.PollingInterval);
ctx.Load(result);
ctx.ExecuteQuery();
}
}
Usage
using (var ctx = GetContext(webUri, userName, password))
{
using (var tenantAdminCtx = GetContext(tenantAdminUri, userName, password))
{
DisableDenyAddAndCustomizePages(tenantAdminCtx,webUri.ToString());
}
RegisterJQueryLibrary(ctx);
}
where
public static void RegisterJQueryLibrary(ClientContext context)
{
var actions = context.Site.UserCustomActions;
var action = actions.Add();
action.Location = "ScriptLink";
action.ScriptSrc = "~SiteCollection/Style Library/Scripts/jQuery/jquery.min.js";
action.Sequence = 1482;
action.Update();
context.ExecuteQuery();
}
If you don't have time for CSOM as described by Vadim, the page also links to a powershell script you can use:
Set-SPOsite <SiteURL> -DenyAddAndCustomizePages 0
But note that SiteUrl needs to be the admin url. If your tenant is https://mysite.sharepoint.com, the url you use is https://mysite-admin.sharepoint.com"
In our case, we were in the midst of a deployment when this hit and could not wait 24 hours (or even one hour!) to continue. Everything had been fine in our testing site collections, but when we deployed to the tenant root, we hit the error described above and this script fixed it. Apparently the feature is turned off by default on the tenant root.
Current site is not a tenant administration site
Turn scripting capabilities on or off
My first response would be that you shouldn't add a CustomAction on the fly through code. That said, I'm sure you have a good reason to need to do so.
Try to set the AllowUnsafeUpdates flag on SPWeb to true as soon as you reference currentWeb. Make sure to also set it back to false after you call the final ExecuteQuery()
By default, AllowUnsafeUpdates is false. It is used to block cross-site scripting attacks.
https://msdn.microsoft.com/en-us/library/Microsoft.SharePoint.SPWeb_properties.aspx

In SharePoint, is it possible to programmatically get the current list of users associated with the "nt authority/authenticated users" group?

In SharePoint, I'd like to find out all of the users who have been given access to a site.
If the user is directly granted permissions, granted permissions via a SharePoint group, or granted permissions via a domain group; then I'm able to get the necessary information.
However, if the user is granted permissions via the "authenticated users" group, I am not sure how to find the list of users associated with that group.
Is this possible?
This is more of a .Net question than a Sharepoint question. Yes, you can do this - use the AD APIs to query your domain controller for a list of all users. Here is some code to get you started on programmatic AD access:
http://www.codeproject.com/KB/system/everythingInAD.aspx
You could try to do a query for all objects in AD that are Users.
Please note that this will not list any users outside of AD that might have access to the Sharepoint content. Also, if you have multiple domains, be sure to query all of the AD domains that might have access to the Sharepoint server.
Kyle, thanks for the response.
Using that information, I came up with the following to get all of the users in all of the domains:
private List<Principal> GetAllAuthenticatedUsers()
{
List<Principal> users = new List<string>();
foreach (string domain in GetAllDomains())
{
try
{
PrincipalContext context = new PrincipalContext(ContextType.Domain, domain);
// Create search condition for all enabled users
PrincipalSearcher searcher = new PrincipalSearcher();
UserPrincipal user = new UserPrincipal(context);
user.Enabled = true;
user.Name = "*";
searcher.QueryFilter = user;
// Get the users
System.DirectoryServices.AccountManagement.PrincipalSearchResult<Principal> results = searcher.FindAll();
foreach (Principal principal in results)
{
users.Add(principal);
}
}
catch
{
}
}
return users;
}
private static List<string> GetAllDomains()
{
List<string> domains = new List<string>();
using (Forest forest = Forest.GetCurrentForest())
{
foreach (Domain domain in forest.Domains)
{
domains.Add(domain.Name);
}
}
return domains;
}

Set permission for user programmatically? (sharepoint)

I am using the following code to set permission for groups when I create a site:
// Assign Site Owner role to the selected users
string siteOwnerGroup = null;
string siteOwnerRole = null;
foreach (ListItem item in lbSiteOwner.Items)
{
siteOwnerGroup = item.Text.ToString();
siteOwnerRole = "Full Control";
SPRoleAssignment roleAssignment = new SPRoleAssignment(web.SiteGroups[siteOwnerGroup]);
SPRoleDefinitionBindingCollection roleDefinition = roleAssignment.RoleDefinitionBindings;
roleDefinition.Add(web.RoleDefinitions[siteOwnerRole]);
web.RoleAssignments.Add(roleAssignment);
web.Properties[siteOwnerGroup] = siteOwnerRole;
web.Properties.Update();
}
Shouldn't it be easy to change this to set permission for users in the lbSiteOwner listbox instead?
I tried
SPRoleAssignment roleAssignment = new SPRoleAssignment(web.SiteUsers[siteOwnerGroup]);
But it doesn't work, any ideas?
Thanks in advance.
following solution will hold true in your case as well in place of list use web
Programatically add user permission to a list in Sharepoint

SharePoint permissions for a specific group

I'm trying to establish whether a specific group has Read access to a particular site collection.
I have been trying for a day and a half but feel as if I have found three halves of different solutions!
The code fragments I have so far are:
using (SPSite site = new SPSite(this.GenerateAbsoluteUri(moduleCode, academicYear)))
{
using (SPWeb web = site.OpenWeb())
{
for (int i = web.SiteGroups.Count - 1; i >= 0; i--)
{
SPGroup group = web.SiteGroups[i];
if (Regex.IsMatch(group.Name, theGroupImLookingFor))
{
but then what?!
Most of my Google results tell me about roles but I don't know how to tie a role to a group.
Please help!
To assign permission to a user (account) or a SharePoint group there are some objects that we need to look at in a certain order. The first thing we need to do is get the the security principal that we want to assign the role to (SPUser or SPGroup). The next thing we need to do it get the actual permission (role) that we want to assign (ex: Read, Full Control etc…). Then we need to create a SPRoleAssignment object and on the constructor pass it in the SPUser or SPGroup (security principal) that we want to assign the permissions to. Now we need to add the role definition to the RoleDefinitionBindings collection of the role assignment object. Then we need to add the actual role assignment to the web (site) and update the web. Below is the full code lisitng.
// Create the site that contains our list
using(SPSite oSite = new SPSite("<<my site url>>"))
{
// Open the web object
using(SPWeb oWeb = oSite.OpenWeb())
{
// Get the group that we want to add the user to
SPGroup oGroup = oWeb.Groups["<<group name>>"];
// Get the role definition we want to assign ex: Full Control
SPRoleDefinition oRole = oWeb.RoleDefinitions["<< role name>>"];
// Create the role assignment object
SPRoleAssignment oRoleAssignment = new SPRoleAssignment(oGroup);
// Add the role definition to the role assignemnt.
// This will assign the specific permission to the security principal for this role assignemnt.
oRoleAssignment.RoleDefinitionBindings.Add(oRole);
// Now we need to add the role assignment to the web
oWeb.RoleAssignments.Add(oRoleAssignment);
// Now update the web
oWeb.Update();
}
}
Heres snippets from my own code (Sharepoint 2010).
Creating a role:
SPRoleDefinition network_role = new SPRoleDefinition();
network_role.BasePermissions = SPBasePermissions.AddListItems |
SPBasePermissions.BrowseDirectories |
SPBasePermissions.EditListItems |
SPBasePermissions.DeleteListItems;
network_role.Name = "Network - Project Member";
network_role.Description = "Provides permissions required for a member of a project.";
web.RoleDefinitions.Add(network_role);
Adding a role to a group:
var assign = new SPRoleAssignment(oweb.SiteGroups["Network Project - " + item.Code]);
assign.RoleDefinitionBindings.Add(network_role);

Creating a custom Document Library in SharePoint

I have a document library in my SharePoint page and there are 10 documents in it.
If User A is logged in I want him to only see 5 of those documents in that document library.
How can I create some custom document library for this to work?
I have MOSS installed.
Thanks in advance!
You could configure different permissions on each document in the document library. Just select the "Manage Permissions" option on each item and break the permission inheritance from the document library level. Just note that having too many documents with item level permissions can create a maintenance nightmare for you. Another option could be to create two document libraries with different permissions.
Write an ItemEventReceiver that breaks the permissions based on a field in the library, i.e. a column that holds the different roles .
We have done this by creating a list that holds all roles coupled to sharepoint groups.
i.e.
Administrator -> Owners of website (SPGroup), Company Administrators (SPGroup)
Managers -> Managers (SPGroup)
then in our content type we have a lookup column to this list.
Here's the code for the ItemEventReceiver:
public override void ItemUpdated(SPItemEventProperties properties)
{
lock (_lock)
{
try
{
using (SPSite site = new SPSite(properties.SiteId,
properties.ListItem.ParentList.ParentWeb.Site.SystemAccount.UserToken))
using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl))
{
web.AllowUnsafeUpdates = true;
var item = web.Lists[properties.ListId].GetItemById(properties.ListItemId);
var roles = item["Roles"] as SPFieldLookupValueCollection;
var rolesList = web.Site.RootWeb.Lists["Company Roles"];
var groupsToAdd = new List<SPFieldUserValue>();
if (item.HasUniqueRoleAssignments)
{
item.ResetRoleInheritance();
item = item.ParentList.GetItemById(item.ID);
}
if (roles != null && roles.Count > 0)
{
// Iterate over the roles and see if there is a group associated
foreach (var role in roles)
{
var roleItem = rolesList.GetItemById(rol.LookupId);
if (roleItem != null)
{
// This is the SPgroup field in the rolesList
var groups = roleItem["Groups"] as SPFieldUserValueCollection;
if (groups != null)
{
groupsToAdd.AddRange(from g in groups
where g.User == null
select g);
}
}
}
if (groupsToAdd.Count > 0)
{
item.BreakRoleInheritance(false);
foreach (var value in groupsToAdd)
{
var group = web.Groups[value.LookupValue];
var assignment = web.RoleAssignments.GetAssignmentByPrincipal(group);
item.RoleAssignments.Add(assignment);
}
}
}
DisableEventFiring();
item.SystemUpdate(false);
EnableEventFiring();
}
}
catch (Exception ex)
{
//LOG ERROR
}
}
}
If the coding doesn't work for you, and you'd rather not set permissions on each file, then there is a third option. We use folders with permissions set on them.
e.g.
Create a folder called "Managers", break permissions, and set rights to only the managers.
Create another folder called "Employee 1", break permissions, and set Contribute rights to the Employee and the Employe's manager.
Place the files in the appropriate folders and it will inherit rights from the folder.
This way, managers can see the manager files, and all files of their employees. Users can only see their own files.
Similar logic can be done for Headquarters, Region 1, Region 2, etc ... and creating different Groups for each region and then assigning the group to the folder's permissions.
Note, there's always concern in using this design on maintaining all the permissions and on performance, but we've been doing similar things for 750+ user populations and thousand of docs and it's been working fine for us so far.

Resources