Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

I have a requirement to create an Infopath form that saves the information to a list where no users should have read access. I have been thinking to accomplish this with impersonation where I want to impersonate an admin user when saving the form. Is this even possible?

Do you have any other idea of how I can save an Infopath form to a list without giving the user read permission to the list?

share|improve this question
add comment

5 Answers 5

Since RWEP is notoriously buggy and unforgiving to work with (lots of quirks with threading and security context that can hit you hard and leave you in an unsupported state), I usually dont use it. If you dont believe me, read Dan Larssons article on Best Practices for Elevated Privilege in SharePoint.

There is a more elegant way of elevating privileges using SPUserToken.

// this example will only work from inside SharePoint since it uses SPContext, but can easily be adapted to use url
using (SPSite hubSite = new SPSite(SPContext.Current.Site.ID, GetSystemToken(SPContext.Current.Site)))
{
    // code goes here
}

The user token is fetched using GetSystemToken helper method that, if and only if access is denied uses RWEP and only to get the SPUserToken for site collection administrator:

    internal SPUserToken GetSystemToken(SPSite site)
    {
         SPUserToken token = null;

         bool tempCADE = site.CatchAccessDeniedException;
         try
         {
            site.CatchAccessDeniedException = false;
            token = site.SystemAccount.UserToken;
         }
         catch (UnauthorizedAccessException)
         {
             SPSecurity.RunWithElevatedPrivileges(() =>
             {
                 using (SPSite elevSite = new SPSite(site.ID))
                     token = elevSite.SystemAccount.UserToken;
             });
         }
         finally
         {
             site.CatchAccessDeniedException = tempCADE;
         }
         return token;
     }

This pattern is adapted from Keith Dahlbys examples here.

share|improve this answer
1  
Under SharePoint 2010 you can get the SystemToken by calling SPUserToken.SystemAccount (msdn.microsoft.com/en-us/library/…). Opening the site would be more easier: SPSite hubSite = new SPSite(SPContext.Current.Site.ID, SPUserToken.SystemAccount) –  Matthias Oct 25 '11 at 14:14
    
Ahh i havent seen this new class (old one isnt obsolete yet, as i dont recall getting any warnings while compiling). Thanx! The reason it was necessary to wrap the token call in exception handling was that it would break for some permissions. Since i havent tried the new token class I dont know yet if it is safe to just call it or if it need to be wrapped as well! –  Anders Rask Oct 25 '11 at 18:05
    
I am using it quite some time and it seems to be safe without wrapping... –  Matthias Oct 26 '11 at 7:51
    
then why do you post the "old" way of doing RWEP? ;-) I think some cases could be anonymous users, but havent tested it -also i think "better safe than sorry", if you get an unmanaged exception you have no way to know if it failed other than dig in ULS logs on a prod. site –  Anders Rask Oct 26 '11 at 8:40
    
I think it is not wrong to use RWEP per se, you only have to use it in the correct way. And by the way, you are stating not to use the RWEP, but your suggested GetSystemToken method uses it as well... ;-) –  Matthias Oct 26 '11 at 9:06
show 1 more comment

Come to think of it, another solution exist: You could create a custom permission pattern that allowed users to only create content, not read it.

What you want to do is to copy a contributor permission level and call it something like Limited Contributor, and uncheck the contributors permissions to read, delete and other permissions you do not want to grant the users.

More on creating custom permissions here. Find a list of OOB permission levels here.

You also can set ReadSecurity and WriteSecurity on a list, so that users can only read/edit items they have created. You set this under List Settings for the list.

share|improve this answer
add comment

You can do it with SPSecurity.RunWithElevatedPrivileges. The important thing is, that you open the web inside of RunWithElevatedPrivileges.

SPSecurity.RunWithElevatedPrivileges(() =>
{
  using (SPSite s = new SPSite("http://weburl"))
  {
    using (SPWeb w = s.OpenWeb())
    {
      SPList list = w.Lists["ListName"];
      // do what ever with the list....
    }
  }

});
share|improve this answer
add comment

Another solution, would be to create another list on the site with high security. After the user submits the form, use a SharePoint Designer Workflow (on item create) to copy the submitted values into the secure list. A final step would be to delete the original submission.

Sharepoint Designer workflows run with elevated permissions.

share|improve this answer
add comment

To build on the answers given by Anders Rask, if you want to allow anonymous users to submit an InfoPath form (e.g., an InfoPath form on an Internet website), you will likely need to impersonate another account to perform the submission. However, if only authenticated users should be able to submit the form, a custom permission level is probably a better approach. In that case, I would suggest creating a SharePoint group for the InfoPath form(s), granting the custom permission level to the SharePoint group, and adding anyone that needs to submit the InfoPath form(s) to the SharePoint group.

From a performance standpoint, I believe it is best to cache SharePoint objects instead of calling the same SharePoint API multiple times, since there is often extensive logic associated with retrieving SharePoint objects. In addition, as indicated by the CA1822: Mark members as static code analysis warning, methods should be static unless they need access to instance data. Thus, the impersonation pattern becomes:

SPContext context = SPContext.Current;
SPSite contextSite = context.Site;
SPWeb contextWeb = context.Web;
using (SPSite site = new SPSite(contextSite.ID, GetSystemToken(contextSite))) {
    using (SPWeb web = site.OpenWeb(contextWeb.ID)) {
        // Do real work here
    }
}

static SPUserToken GetSystemToken(SPSite site) {
    bool cade = SPSecurity.CatchAccessDeniedException;
    SPSecurity.CatchAccessDeniedException = false;
    SPUserToken token = null;
    try {
        token = site.SystemAccount.UserToken;
    }
    catch (UnauthorizedAccessException) {
        SPSecurity.RunWithElevatedPrivileges(delegate() {
            using (SPSite elevatedSite = new SPSite(site.ID)) {
                token = elevatedSite.SystemAccount.UserToken;
            }
        });
    }
    finally {
        SPSecurity.CatchAccessDeniedException = cade;
    }
    return token;
}

Note: The code pattern above can be used to impersonate any account by replacing GetSystemToken(contextSite) with the appropriate SPUserToken.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.