Thursday, April 20, 2017

Overview of item-level permissions in Sharepoint lists

In Sharepoint lists you may configure so called item-level permissions: List settings > Advanced settings > Item-level permissions:

In this article I will show how this setting affects behavior of the lists. In our examples I will use calendar list and 2 different users with Contribute permissions: user1 and user2. user1 created event “test from user1”, and user2 – “test from user2”.

So first of all we need to distinguish 2 concepts:

  1. Item-level security
  2. Item-level permissions

Item-level security means “physical” permissions which you may assign on particular list item (e.g. from context menu shown for this list item Shared With > Advanced) when list items don’t inherit permissions from parent list (and as you probably know list item is minimal securable object in Sharepoint: Site > Web > List > Folder > Item). E.g. you may grant particular permission level to user, AD or Sharepoint group on the list item and list item will become secured by standard Sharepoint security mechanism.

Item-level permissions shown in List settings > Advanced settings don’t use standard Sharepoint security mechanism. It is more like adding filters to the list views to shown only items created by current user ([Me]) and adding additional checks on Save button in Add and Edit list forms (see below).

So let’s start with configuration shown above:

  • Read all items
  • Create and edit all items

In this case both user1 and user2 will see the same list view:

I.e. all users see events created by all users. Also both users are able to modify all events regardless of who created this event.

Now let’s check the following configuration:

  • Read items that were created by the user
  • Create and edit all items

In this case user1 will see only own event:

the same as user2:

In this case even if user1 knows direct url of edit form for event created by user1 (EditForm.aspx?ID=…), it won’t be possible to edit it: Sharepoint will show error “Item not found”. I.e. “Read items that were created by the user” setting is has priority over “Create and edit all items” in this case.

Next combination is this one:

  • Read items that were created by the user
  • Create items and edit items that were created by the user

In this case it will work in the same way as previous combination, i.e. users may see and edit only own events.

Next combination:

  • Read all items
  • Create items and edit items that were created by the user

In this case both users again will see all events:

Also there still will be Edit button available in the ribbon so e.g. user1 may select “test from user2” and click Edit – edit form will be successfully shown. But when user1 will click Save on this form Sharepoint will show error “You do not have access to this page”.

And the last combination when user can’t create or edit items:

  • Read all items/Read items that were created by the user
  • None

In this case Sharepoint will show “You do not have access to this page” error when user will try to create new event or edit any event, including own (which was probably created before this setting was turned on). Although new and edit forms still will be opened, error will be shown on clicking Save button.

And last thing which I would like to mention is that under Item-level permissions section in advanced list setting there is the following note:

Users with the Cancel Checkout permission can read and edit all items.

If you will go to Site settings > Site permissions > Permissions levels and will try to edit existing permission level or create new one, you won’t find exactly “Cancel Checkout” permission there. Instead there will be “Override List Bahaviors”:

Discard or check in a document which is checked out to another user, and change or override settings which allow users to read/edit only their own items

And actually this permission is meant under Item-level permissions instead of “Cancel Checkout”. This is all what I wanted to share about this topic. Hope that this information will help someone.

Thursday, April 6, 2017

Problem with SPWeb.EnsureUser method and FBA users with claims based authentication in Sharepoint

If you need to perform some action on FBA user in your Sharepoint site where claims authentication is used from outside of Sharepoint context (e.g. from console application) you may face with the following issue: when you will call web.EnsureUser(userName) method it will throw exception:

Specified user ‘username’ not found

There are several things which have to be done in order to make it possible to work with FBA users without Sharepoint context with claims based authentication:

1. Fake HTTP context after you get instance of SPWeb:

   1: HttpRequest request = new HttpRequest("", web.Url, "");
   2: HttpContext.Current = new HttpContext(request,
   3:     new HttpResponse(new StringWriter()));
   4: HttpContext.Current.Items["HttpHandlerSPWeb"] = web;

2. Use user name in full claims format, i.e.:

   1: var user = web.EnsureUser("i:0#.f|mymembershipprovider|username");

where instead of mymembershipprovider and username you should use your own membership provider name and user name.

3. The most tricky thing: from web.config of your FBA site zone you need to copy the following sections to the app.config of your console application:

  • connectionStrings
  • system.web/membership
  • system.web/roleManager

e.g.:

   1: <connectionStrings>
   2:   <add name="MyConnStr" connectionString="..." />
   3: </connectionStrings>
   4: <system.web>
   5:   <membership defaultProvider="i">
   6:     <providers>
   7:       <add name="i" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthMembershipProvider,
   8: Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
   9:       <add connectionStringName="MyConnStr" name="MyMembershipProvider" ... />
  10:     </providers>
  11:   </membership>
  12:   <roleManager defaultProvider="c" enabled="true" cacheRolesInCookie="false">
  13:     <providers>
  14:       <add name="c" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthRoleProvider,
  15: Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
  16:       <add connectionStringName="MyConnStr" applicationName="/" name="MyRoleProvider" ... />
  17:     </providers>
  18:   </roleManager>
  19: </system.web>

Here is the full working C# code which allows to get FBA user from console application:

   1: using (var site = new SPSite("http://example.com"))
   2: {
   3:     using (var web = site.OpenWeb())
   4:     {
   5:         web.AllowUnsafeUpdates = true;
   6:         HttpRequest request = new HttpRequest("", web.Url, "");
   7:         HttpContext.Current = new HttpContext(request,
   8:             new HttpResponse(new StringWriter()));
   9:         HttpContext.Current.Items["HttpHandlerSPWeb"] = web;
  10:  
  11:         var user = web.EnsureUser("i:0#.f|mymembershipprovider|username");
  12:         ...
  13:     }
  14: }