Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,128 | Comments: 45,550

filter by tags archive

Are you an administrator?

time to read 4 min | 778 words

In RavenDB vNext, we tightened the security story a bit. Some operations that used to be possible for standard users are now administrator operations. For example, creating a new database require you to be admin.

Figuring out whatever you are admin is a bit tough, though. In particular, we use the following logic to determine that:

  • If you logged in using OAuth, the credentials will tell us whatever you are admin or not.
  • If you are logged in using Windows Auth, we make the following assumption:
    • If you are a Windows Admin, you are an administrator (ouch!).
    • If you are running on the same user as the one RavenDB is using, you are an administrator (debug / dev scenarios).
  • If you are running embedded, you are admin.

You might have noticed that there is an “ouch” on the Windows Admin line. The reason for that is that it is actually quite hard to figure that one out. RavenDB is running as a web server, and when we use Windows Auth, we get a WindowsIdentity that we can use. The problem is with UAC. When that is turned on, what we get is the non elevated user. But that user is not an Admin in the Windows sense of the word. We don’t actually care about that (it isn’t like we need to impersonate the user), we just use that as a “yes/no” for certain ops.

This is documented here: https://connect.microsoft.com/VisualStudio/feedback/details/679546/problem-with-windowsprincipal-isinrole-when-uac-is-enabled

The resolution is by design.

So… we need another way to check for this. Luckily, since we don’t need impersonation, we can just check Active Directory for that. Here is how we do so:

private static bool IsAdministratorNoCache(string username)
    PrincipalContext ctx;
            ctx = new PrincipalContext(ContextType.Domain);
        catch (PrincipalServerDownException)
            // can't access domain, check local machine instead 
            ctx = new PrincipalContext(ContextType.Machine);
    catch (ActiveDirectoryObjectNotFoundException)
        // not in a domain
        ctx = new PrincipalContext(ContextType.Machine);
    var up = UserPrincipal.FindByIdentity(ctx, username);
    if (up != null)
        PrincipalSearchResult<Principal> authGroups = up.GetAuthorizationGroups();
        return authGroups.Any(principal =>
                              principal.Sid.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid) ||
                              principal.Sid.IsWellKnown(WellKnownSidType.AccountDomainAdminsSid) ||
                              principal.Sid.IsWellKnown(WellKnownSidType.AccountAdministratorSid) ||
    return false;

Here we check whatever the user is directly or indirectly and admin. Note that we have to take care of cases in which we are running inside & outside a domain, as well as cases where the domain controller is down.

This works, but there is just one problem with that, it is sloooow. As in, multiple seconds slow. Even on the local machine without any domain involved.

I’ll discuss how we solved that on my next post.


Phil Bolduc

You could help the API by telling it you are providing a SamAccountName.

var up = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, username);

Not really sure the difference between GetAuthorizationGroups and GetGroups, but, you could just call

using (PrincipalSearchResult groups = up.GetGroups()) { return groups.Any(principal => principal.Sid.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid) || principal.Sid.IsWellKnown(WellKnownSidType.AccountDomainAdminsSid) || principal.Sid.IsWellKnown(WellKnownSidType.AccountAdministratorSid) || principal.Sid.IsWellKnown(WellKnownSidType.AccountEnterpriseAdminsSid)); }

Look forward to seeing your analysis of what took all the time,


i suppose your solution will have something to do with the current name of the method, "IsAdministratorNoCache" and in particular that "NO CACHE" part ;)


whatever whether

Just sayin' ...

Ayende Rahien

Phil, The SamAccountName isn't really helping perf in any material way. And the GetAuthorizationGroups() is used to get all groups in the hierarchy.

Comment preview

Comments have been closed on this topic.


  1. The worker pattern - 14 hours from now

There are posts all the way to May 30, 2016


  1. The design of RavenDB 4.0 (14):
    26 May 2016 - The client side
  2. RavenDB 3.5 whirl wind tour (14):
    25 May 2016 - Got anything to declare, ya smuggler?
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats