Question

* *Clarification. Application == Site Definition. Direct Database access is out the window ** I've created an application for SharePoint that utilizes some new approaches to coding List Access. I've structured things in a way that allows me to control data interaction in a precise manner.

For example, I have a class called Post, which has some typical metadata like Title, Summary, etc...

Inside Post is a static method called NewPost which returns a pre-formatted SPListItem for use in creating new posts.

public static SPListItem NewPost(string Title,string Summary)
{
   Posts = CoreLists.Posts();
   var item = Posts.AddItem();
   var item["Alias"] = SPContext.Current.Web.CurrentUser.LoginName;
   return item;
}

You'll notice I'm getting the SPList through a helper class called CoreLists

public static class CoreLists
{
   public static SPList Posts()
   {
      return SPContext.Current.Web.GetList(SPContext.Current.Web.ServerRelativeUrl + "/lists/Posts");
   }
}

This makes for some nice clean data methods. What I'm running in to, is that I cannot find a decent way to call these methods with SPSecurity.RunWithElevatedPrivileges

SPSecurity.RunWithElevatedPrivileges cannot function with a return block, so when I try to create a new list item, it fails every time.

I'm doing this because I'm making my lists hidden. I want people to only access them through the UI I'm creating. I want to further lock the system down from URL hacking by allowing only admins to create items, and use SecurityBits to lock down item editing only to the creators of list items.

Therefore, all List Items are created by System Account, and then they have a field called Alias which allows me to match the item to a user.

Do I need to rethink my entire Data Access Layer? Does the decision to restrict List Access conflict absolutely with the desire for a cleaner Data Access Layer?

Was it helpful?

Solution

You use SPContext.Current.Web inside the SPSecurity.RunWithElevatedPrivileges delegate?

That is not going to work. Getting stuff with SPContext gives you objects that has the context of the currently logged on user, not the elevated one. That means that if you create a new list entry using objects that comes from SPContext, they will be created in the security context of the user currently logged on, and not the elevated user you think is creating them.

If you want to create list entries using sharepoint\system, you need to open up new SPSite/SPWeb objects inside the SPSecurity.RunWithElevatedPrivileges delegate and work with those instead.

Try changing this:

   public static SPList Posts() 
   { 
      return SPContext.Current.Web.GetList(SPContext.Current.Web.ServerRelativeUrl + "/lists/Posts"); 
   } 

to this:

   public static SPList Posts() 
   { 
        using( var s = new SPSite(SPContext.Current.Site.ID)
        {
            using( var w = SPSite.OpenWeb(SPContext.Current.Web.ID)
            {
                 var postsList = w.Lists.TryGetList("Posts"); 
                 if( postsList != null )
                      return postsList;
                 else
                    /* do proper error handling */
            }
        }
    }

Now your posts.AddItem() should create list entries with the correctly elevated context.

Read more about privilege elevation on MSDN: http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spsecurity.runwithelevatedprivileges.aspx

OTHER TIPS

Do not use RWEP. You do not need it.

Hidden lists do not require special coding to access. If the current user has permissions to the list, then just access the hidden list as you would any other list.

If the current user does not have permissions to the list, and you wish to proxy the update via code, you should impersonate the System Account. Furthermore, you should not pass an object across security boundaries. I suggest creating data transfer object that you pass into your data layer.

Vedrans points re UI/Security are quite right - if you're rewriting the security system, you're working against the grain as it were. But you might still want to leverage the security (and other SharePoint benefits), so it's not completely mental to build an app on SharePoint.

For a more SharePoint based architecture - use a publishing site. This gives you:

  1. the standard sharepoint UI for lists etc. - this is the admin 'backstage' view.
  2. pages library with separate master page/UI - this is the 'application' interface.

Default (all authenticated users) get viewer access to the site. 'admin' users get contributer/explicit permissions to lists, whatever.

Punters can only access site data through custom web parts/code in the application interface.

Your whole concept is wrong.

If you are developing your own UI and security then why are you using SharePoint? Using SQL is much cleaner.

Every time you use SPSecurity.RunWithElevatedPrivileges in code Sharepoint security is compromised because you are allowing current user to act as SHAREPOINT\System and have access to everything.

Btw you can set 'creator' when running under SPSecurity.RunWithElevatedPrivileges

//First store current user
SPUser currentUser = SPContext.Current.Web.CurrentUser;

SPSecurity.RunWithElevatedPrivileges(delegate 
{
    using (SPSite elevatedSite = new SPSite(SPContext.Current.Site.Url))
    using (SPWeb targetWeb = elevatedSite.OpenWeb(webUrl))
    {
       //Code to get your item or to add a new one

       // Replace 'System Account' with current user
       item["Author"] = currentUser;
       item["Editor"] = currentUser;
       item.SystemUpdate();
    }
});

ADDITION:

To avoid any further misinterpretation: by using SQL I didn't meant SharePoint database but some other different SQL database. Why? Since you are using custom UI, custom security checks, your list are hidden (so users cannot use SP OOTB features like sorting, filtering etc.), search is also not an option -> I really don't see any advantage of using SharePoint as data storage.

Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top