System.Security.Principal in .NET

This article has been excerpted from book "The Complete Visual C# Programmer's Guide" from the Authors of C# Corner.

The System.Security.Principal namespace defines a principal object that represents the security context under which code is running. 

IIdentity Interface

  • AuthenticationType: this property returns a string that describes the type of authentication in place, such as basic authentication, NTLM, Kerberos, or Passport. The value for this property will be defined by each application.
  • IsAuthenticated: this property returns a value that indicates whether the current user has been authenticated.
  • Name: his property returns the user name of the user represented by this identity.

IPrincipal Interface

  • Identity: this property returns the identity object that is associated with this principal.
  • IsInRole: this method returns a value that indicates whether the user represented by this principal belongs to a specific role.

WindowsIdentity Class 

The WindowsIndentity class implements the IIdentity interface. It represents the identity of the user based on a method of authentication supported by the Windows operating system. A Windows identity provides the ability to impersonate another user so resources can be accessed on that user's behalf.

WindowsPrincipal Class 

The WindowsPrincipal class implements the IPrincipal interface. It represents Windows users and their roles, which are simply the Windows groups to which the users belong. 

GenericIdentity Class 

The GenericIdentity class implements the IIdentity interface. It represents the identity of the user based on a custom authentication method defined by the application. 

GenericPrincipal Class 

The GenericPrincipal class implements the IPrincipal interface. It represents users and roles that exist independent of Windows users and their roles. Essentially, the generic principal is a simple solution for application authentication and authorization. 

PrincipalPermission Class 

PrincipalPermission objects allow code to perform actions (Demand, Union, Intersect, etc.) against the current user identity in a manner consistent with the way those actions are performed for code access permissions and identity permissions. PrincipalPermission can be issued as an imperative demand, as shown at the top of Listing 22.27, or as a declarative demand, as the bottom of the listing shows. 

Listing 22.27: IsInRole Example 

PrincipalPermission p = new PrincipalPermission(null, "BUILTIN\Administrator");
p.Demand();

// or it can be issued as a declarative demand as shown in the line below
[PrincipalPermission(SecurityAction.Demand, Role=@"BUILTIN\Administrators")]

CurrentPrincipal Property 

The CurrentPrincipal property of the Thread class is a static proprety that allows you to get or set the current security context of the user. You can use the CurrentPrincipal property of the System.Threading.Thread class in order to get the current WindowsPrincipal object as in the line of code below: 

            WindowsPrincipal myWindowsPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal;

IsInRole Method 

You can check role membership by calling the IsInRole method on the principal object. You can use IsInRole with WindowsPrincipal and CurrentPrincipal. Listing 22.28 shows a simple use of the IsInRole method. 

Listing 22.28: IsInRole Example 

            // IsInRole
            WindowsPrincipal winpr = (WindowsPrincipal)Thread.CurrentPrincipal;

            // WindowsBuiltInRole is an enumeration!
            // Is winpr object in role of Administrator?
            winpr.IsInRole(WindowsBuiltInRole.Administrator);

            // Is the current thread principal in role of Administrator?
            System.Threading.Thread.CurrentPrincipal.IsInRole(@"BUILTIN\Administrator");

Impersonate and ImpersonateContext 

If your application must impersonate a Windows account that has not been attached to the current thread, you must retrieve that account's token and use it to activate the account:

  • Retrieve an account token for a particular user by making a call to the unmanaged LogonUser method, passing it the user name, password, and domain of the account you want. This method is not in the .NET Framework base class library but is located in the unmanaged advapi32.dll library. For the LogonUser call to work, a special privilege known as SE_TCB_NAME is needed. You can check this by selecting Control Panel?Administrative Tools?Local Security Policy Settings.
  • Create a new instance of the WindowsIdentity class, passing the account token retrieved in the preceding step.
  • Begin impersonation by creating a new instance of the WindowsImpersonationContext class and initializing it with the Impersonate method of the WindowsIdentity object created in the preceding step.
  • When you no longer need to impersonate the Windows user, call the WindowsImpersonationContext.Undo method to revert the impersonation with MyImpersonation.Undo();.

Listing 22.29 illustrates how you can accomplish impersonation. 

Listing 22.29: Impersonation Example 

// impersonation
public class ImpersonationExample
{
    [DllImport("ADVAPI32")]
    private unsafe static extern int LogonUser(
    String lpszUsername,
    String lpszDomain,
    String lpszPasswords,
    int dwLogonType,
    int dwLogonProvider,
    out InPtr phToken
    );

    public void anyfunction()
    {
        InPtr lToken;
        int lRetVal = 0;
        lRetval = LogonUser(strUserName, strDomain,
        strPassword, LOGON32_LOGON_NETWORK,
        LOGON32_PROVIDER_DEFAULT, out lToken);

        if (lRetval == 0)
        {
            Console.WriteLine("Login error occurred!");
            return;
        }

        WindowsIdentity ImpId = new WindowsIdentity(lToken);
        WindowsImpersonationContext ImpContext = ImpId.Impersonate();

        // you are impersonating another user now in this
        // thread!
        // execute some managed and unmanaged code now
        ImpContext.Undo();
    }
}

Listing 22.30 creates two PrincipalPermission objects representing two different users. The union demand succeeds only if user mcb is in the role of director or user mindcracker is in the role of officer. 

Listing 22.30: PrincipalPermission Union Example 

           // Union Demand
            String id1 = "mcb";
            String role1 = "Director";
            PrincipalPermission PrincipalPerm1 = new PrincipalPermission(id1, role1);
            String id2 = "mindcracker";
            String role2 = "Officer";
            PrincipalPermission PrincipalPerm2 = new PrincipalPermission(id2, role2);
            (PrincipalPerm1.Union(PrincipalPerm2)).Demand();

In Listing 22.31, the current WindowsIdentity class is transformed into a WindowsPrincipal class. Then all of the identity and principal properties are written to the system console. 

Listing 22.31: WindowsIdentity to WindowsPrincipal Example 

            // WindowsIdentity illustrated
            WindowsIdentity MyIdentity = WindowsIdentity.GetCurrent();
            WindowsPrincipal MyPrincipal = new WindowsPrincipal(MyIdentity);

            //Principal values.
            Console.WriteLine(MyPrincipal.Identity.Name);
            Console.WriteLine(MyPrincipal.Identity.AuthenticationType);
            Console.WriteLine(MyPrincipal.Identity.IsAuthenticated.ToString());

            //Identity values.
            Console.WriteLine(MyIdentity.Name);
            Console.WriteLine(MyIdentity.AuthenticationType);
            Console.WriteLine(MyIdentity.IsAuthenticated.ToString());
            Console.WriteLine(MyIdentity.IsAnonymous.ToString());
            Console.WriteLine(MyIdentity.IsGuest.ToString());
            Console.WriteLine(MyIdentity.IsSystem.ToString());
            Console.WriteLine(MyIdentity.Token.ToString());

Listing 22.32 illustrates GenericIdentity class usage. 

Listing 22.32: GenericIdentity Example 

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
WindowsPrincipal myUser = WindowsPrincipal)System.Threading.Thread.CurrentPrincipal;
GenericIdentity MyIdentity = new GenericIdentity(myUser.Identity.Name.ToString());

String[] MyStringArray = {"Role1", "Teller"};
GenericPrincipal MyPrincipal = new GenericPrincipal(MyIdentity, MyStringArray);
System.Threading.Thread.CurrentPrincipal = MyPrincipal;

//Return user values
String Name = MyPrincipal.Identity.Name;
bool Auth = MyPrincipal.Identity.IsAuthenticated;
bool IsInRole = MyPrincipal.IsInRole("Role2");

if(IsInRole)
{
           Console.WriteLine("The test was successful as a user in the user-defined role of Role1");
}
else
{
           Console.WriteLine("The test was not successful!");
}

In Listing 22.33, declarative demands for PrincipalPermission and PrincipalPermissionAttribute are illustrated. The attribute adjustment says that only a principal in the role of Role1 may execute these functions. 

Listing 22.33: Declarative Identity Example 

[PrincipalPermission(SecurityAction.Demand, Role=@"Role1")]

private string MyFunction()
{
           return "Declarative control for the role of Role1 is truly successfully. his function can be executed by you!";
}

[PrincipalPermissionAttribute(SecurityAction.Demand, Name = "MyUser", Role = "Role1")]

public static void PrivateInfo()
{
           //Output of private data
           Console.WriteLine("You have access to the private data!");
}

Conclusion

Hope this article would have helped you in understanding System.Security.Principal in .NET. See other articles on the website on .NET and C#.

visual C-sharp.jpg
The Complete Visual C# Programmer's Guide covers most of the major components that make up C# and the .net environment. The book is geared toward the intermediate programmer, but contains enough material to satisfy the advanced developer.


Similar Articles