Having started work at a company where my local box did not have me as a local admin , got me to thinking about admin rights. The following code displays the current user stats and attempts to access a protected method that only local admins should access. The code should discriminate against all those that don’t have local admin rights. Within the code I demonstrate declarative security (using the Attribute over the method) Imperative security calls to specific security methods within the code. First off one needs these usings:

using System.Security.Principal;
using System.Security.Permissions;

Here is the code,

   1: public static void GetRole()
   2: {
   3:     System.AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
   5:     WindowsIdentity curIdentity = WindowsIdentity.GetCurrent();
   6:     WindowsPrincipal myPrincipal = new WindowsPrincipal(curIdentity);
   8:     List<string> groups = new List<string>();
  10:     foreach (IdentityReference irc in curIdentity.Groups)
  11:     {
  12:         groups.Add(((NTAccount)irc.Translate(typeof(NTAccount))).Value);
  13:     }
  15:     Console.WriteLine(
  16: @"Name:           {0},
  17: System:
  18: Authenticated:  {2}
  19: BuiltinAdmin:   {3}
  20: Identity:       {4}
  21: Groups:         {5}"
  22:         curIdentity.Name,
  23:         curIdentity.IsSystem,
  24:         curIdentity.IsAuthenticated,
  25:         myPrincipal.IsInRole(  WindowsBuiltInRole.Administrator ) ? "True" : "False",
  26:         myPrincipal.Identity,
  27:         string.Join(string.Format(",{0}\t\t", Environment.NewLine), groups.ToArray()));
  30:     try
  31:     {
  32:         Console.WriteLine(Environment.NewLine);
  33:         ManagersOnly();
  34:     }
  35:     catch (System.Security.SecurityException scx)
  36:     {
  37:         Console.WriteLine(scx.Message + " " + scx.FirstPermissionThatFailed.ToString());
  38:     }
  39:     Console.WriteLine(Environment.NewLine);
  42: }
  45: [PrincipalPermissionAttribute(SecurityAction.Demand, Role = @"BUILTIN\Administrators")]
  46: private static void ManagersOnly()
  47: {
  48:     Console.WriteLine("Key to the Executive Wash Room");
  49: }

Here are some highlights

  • Line 3 is the killer. Without it we become rudderless when a check is made. (Causes an exception to be thrown even though we are in the admins group). This line is setting the processing up to work with the OS system token which will be geared toward the current user and windows security on the current thread. This doesn’t actually come into play until we call ManagersOnly method on line 33. Otherwise if this was commented out we would get an exception “Request for principal permission failed” would occur on line 33. (The rub is line 25 would actually work, so be careful when using declarative or imperative security, they can behave differently).
  • Line 5 of note the current identity will never have an actual user name (unless its the login name), password or other identifying aspects of the actual user.
  • Line 12 is where we convert the numeric ids to a relatable group names that we are all familiar with.
  • Line 15 informs us of what we are currently logged in as and will display different aspects of the account.
  • Line 25 is in a way using imperative security, where we could take that check and programmatically divine where to allow access. What is nice is that the call is type safe unlike on line 45 where we can make a spelling mistake and it all fails.
  • Line 33 calls the Declarative Security attributed method, any call to a role based security should be within a try catch block. Depending on where the code is, some problems exists as objects which are being disposed and the rights have changed on the GC thread which is trying to finalize objects.
  • Line 45 is the declarative security as done in the attribute above the method. We could actually drill down even more to specify an exact user name if we wanted. We will stick with groups (roles) and look for the local admin. Note spelling mistakes will cost you so BUILTIN\Administrator is not BUILTIN\Administrators.

The final output looks like this:

Name:          ORION\OmegaMan
System:        False
Authenticated: True
BuiltinAdmin:  True
Identity: System.Security.Principal.WindowsIdentity Groups: ORION\None,
NT AUTHORITY\Authenticated Users,

Key to the Executive Wash Room