8

Is there a way to detect if my code is running inside SPSecurity.RunWithElevatedPrivileges?

class Foo
{
  public static void Bar()
  {
     if (CODE_RUNS_ELEVATED)
     {
       Debug.WriteLine("You are elevated");
     }
     else
     {
       Debug.WriteLine("You are not elevated");
     }
  }
}

SPSecurity.RunWithElevatedPrivileges(() => Foo.Bar()); // Prints:  You are elevated
Foo.Bar(); // Prints: You are not elevated

My problem is how to resolve CODE_RUNS_ELEVATED.

UPDATE: Some observations I did so far:

  • Thread.CurrentPrincipal: logged on identity
  • WindowsIdentity: application pool identity
  • HttpContext.Current.User.Identity: logged on identity

So the only thing, which changes when doing the 'RWEP' is the WindowsIdentity.GetCurrent() from NT AUTHORITY\IUSR (with claims authentication) or from the logged on user (with windows integrated authentication) to the application pool identity.

2
  • Did you ever get an answer to this question ? I have the same requirement, but can't find a way to detect if the code is elevated or not.
    – Steve B
    Commented Jun 1, 2012 at 7:42
  • Please see my posted answer.
    – Matthias
    Commented Jun 1, 2012 at 8:52

5 Answers 5

3

I'm not entirely certain this will work, but you could try inspecting HttpContext.User.Identity within the RunWithElevatedPrivileges delegate, and see if it returns the application pool identity.

If so, you could provide some way of retrieving the application pool identity for a given SPWebApplication (possibly via SPWebApplication.ApplicationPool?), and compare the Identity name to that of what you get via HttpContext.User.Identity (if what we tried in the above paragraph works).

7
  • 1
    HttpContext.Current.User.Identity returns the current logged on identity. But WindowsIdentity.GetCurrent() returns the application pool identity.
    – Matthias
    Commented Feb 9, 2012 at 17:01
  • It does? Wicked. Use that and see if you can get a username or something to identify that identity. Then see if you can get the identity for the current SPWebApplication.ApplicationPool. Then you should be sorted.
    – James Love
    Commented Feb 9, 2012 at 17:06
  • RunWithElevated's basically does a thread impersonation to the application pool identity of the web app, executes the CodeToRunElevated delegate method and flips it back to the original user when the method returns.
    – James Love
    Commented Feb 9, 2012 at 17:07
  • Yes, up to now this is my only solution. But I did hope to find a more straight forward one...
    – Matthias
    Commented Feb 9, 2012 at 17:15
  • @Matthias just to be clear, you are saying that when with normal privs that the IDs are the same but when run with elevated privs they differ?
    – Dave Wise
    Commented Feb 9, 2012 at 17:34
2

The easy thing and which is working 100% is to get CurrentUser from a SPWeb object and compare it against 'SHAREPOINT/SYSTEM'.

100% agree there are cases when is needed to detect if code is already running under elevated privs. Cuz you might have classes calling other methods from other classes and so on and you can't elevate 2 or more times a context. Strange behavior results from that.

2
  • Yes you are right, but then you have to open a SPWeb specially for that, which is a perfomance killer...
    – Matthias
    Commented Feb 10, 2012 at 11:06
  • No, you don't have to open, you might have a SPList or a SPListItem object and navigate from property to the SPWeb. Like: SPList.ParentWeb or SPListItem.Web. Commented Feb 10, 2012 at 12:41
2

This is finally the solution I came to:

public static bool IsPrivilegedMode()
{
  using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
  {
    return identity != null && GetProcessIdentity().User == identity.User;
  }
}

private const uint processToken = 0x0008;
public static WindowsIdentity GetProcessIdentity()
{
  IntPtr handle = IntPtr.Zero;
  try
  {
    Process process = Process.GetCurrentProcess();              
    OpenProcessToken(process.Handle, processToken, out handle);
    return new WindowsIdentity(handle);
  }
  finally
  {
    if (handle != IntPtr.Zero)
    {
      CloseHandle(handle);
    }
  }
}

[DllImport("kernel32.dll")]
public static extern Boolean CloseHandle(IntPtr hObject);

[DllImport ("advapi32.dll", SetLastError = true)]
public static extern bool OpenProcessToken (IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

I recommend that you do some static caching of the process identity, in order to improve performance.

1
  • This seems to works only for web application. if I ran this code within a console application (or from unit tests in my case), the process identity is owned by the current user.
    – Steve B
    Commented Jun 1, 2012 at 9:09
1

The bigger question is why do you need to know?

If your code requires that it run with elevated privileges why not simply include that in the block? If that is not practical then let it throw an error if it attempts to do something without sufficient privilege. An error of that level would get certainly get caught and corrected in basic testing and the caller would be modified to increase privilege prior to the call.

If this is just a check to see if it is running with higher privs then you could simply wrap a call to some light duty higher-permission function (maybe something in Microsoft.SharePoint.Administration) in a try-catch block and return true/false based on that.

5
  • I need to know, since I want to do some custom permission handling independently of the SharePoint permissions. So your second suggestion could be a solution, but I guess that it is hard to find a function that will not have an impact on the performance.
    – Matthias
    Commented Feb 9, 2012 at 17:13
  • I would start with James' suggestion below and do a side-by-side comparison of both the SPContext and HttpContext objects as they appear normally and with elevated privileges. There has to be something there to indicate the difference. If there isn't or it invokes some high overhead method (like loading a Site) then try the above options
    – Dave Wise
    Commented Feb 9, 2012 at 17:16
  • If you do find a difference on the SPContext or HttpContext objects, please post it here as I am curious now as well
    – Dave Wise
    Commented Feb 9, 2012 at 17:18
  • Since SPContext doesn't inherit from HttpContext, and therefore run as completely separate entities with different roles, not sure if it is possible to compare them (internally there'll be some reference to HttpContext but that's surfaced nowhere in the API I don't think). EDIT: I just realised you want to see how they're both different when in different context modes, rather than a direct object to object comparison.
    – James Love
    Commented Feb 9, 2012 at 17:26
  • Correct. I have to think that there would be something different on one of those objects when run with elevated privs versus when run normally.
    – Dave Wise
    Commented Feb 9, 2012 at 17:31
1

I found this code is working (even in a unit test project) :

    private static readonly PropertyInfo g_OriginatingUserTokenProperty = typeof(SPSecurity).GetProperty(
                    "OriginatingUserToken",
                    System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic
                    );

    public static bool IsElevated
    {
        get
        {
            return g_OriginatingUserTokenProperty.GetValue(null, null) != null;
        }
    }

However, I'm not sure this will actually tells me if I'm elevated, or just impersonated with another user token.

1
  • After some test, this method is not reliable. This methds is telling if the context is impersonated. This can occur, for example, if we are in a event receiver.
    – Steve B
    Commented Jul 4, 2012 at 7:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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