Tải bản đầy đủ - 0 (trang)
11-10. Determine If the Current User Is a Member of a Specific Windows Group

11-10. Determine If the Current User Is a Member of a Specific Windows Group

Tải bản đầy đủ - 0trang

CHAPTER 11 ■ SECURITY AND CRYPTOGRAPHY



the WindowsIdentity of the thread if it is not impersonating a user, and it returns the WindowsIdentity of

the process if the thread is currently impersonating a user.



■ Note The WindowsIdentity class provides overloaded constructors that, when running on Microsoft Windows

Server 2003 or later platforms, allow you to obtain a WindowsIdentity object representing a named user. You can

use this WindowsIdentity object and the process described in this recipe to determine whether that user is a

member of a specific Windows group. If you try to use one of these constructors when running on an earlier

version of Windows, the WindowsIdentity constructor will throw an exception. On Windows platforms preceding

Windows Server 2003, you must use native code to obtain a Windows access token representing the desired user.

You can then use this access token to instantiate a WindowsIdentity object. Recipe 11-12 explains how to obtain

Windows access tokens for specific users.



Once you have a WindowsIdentity, instantiate a new WindowsPrincipal object, passing the

WindowsIdentity object as an argument to the constructor. Finally, call the IsInRole method of the

WindowsPrincipal object to test if the user is in a specific group (role). IsInRole returns true if the user is

a member of the specified group; otherwise, it returns false. The IsInRole method provides four

overloads:





The first overload takes a string containing the name of the group for which you

want to test. The group name must be of the form [DomainName]\[GroupName] for

domain-based groups and [MachineName]\[GroupName] for locally defined groups.

If you want to test for membership of a standard Windows group, use the form

BUILTIN\[GroupName] or the other overload that takes a value from the

System.Security.Principal.WindowsBuiltInRole enumeration. IsInRole performs

a case-insensitive test for the specified group name.







The second IsInRole overload accepts an int, which specifies a Windows role

identifier (RID). RIDs provide a mechanism that is independent of language and

localization to identify groups.







The third IsInRole overload accepts a member of the

System.Security.Principal.WindowsBuiltInRole enumeration. The

WindowsBuiltInRole enumeration defines a set of members that represent each of

the built-in Windows groups.







The fourth IsInRole overload accepts a

System.Security.Principal.SecurityIdentifier object that represents the

security identifier (SID) of the group for which you want to test.



Table 11-2 lists the name, RID, and WindowsBuiltInRole value for each of the standard Windows

groups.



565



www.it-ebooks.info



CHAPTER 11 ■ SECURITY AND CRYPTOGRAPHY



Table 11-2. Windows Built-In Account Names and Identifiers



Account Name



RID (Hex)



WindowsBuiltInRole Value



BUILTIN\Account Operators



0x224



AccountOperator



BUILTIN\Administrators



0x220



Administrator



BUILTIN\Backup Operators



0x227



BackupOperator



BUILTIN\Guests



0x222



Guest



BUILTIN\Power Users



0x223



PowerUser



BUILTIN\Print Operators



0x226



PrintOperator



BUILTIN\Replicators



0x228



Replicator



BUILTIN\Server Operators



0x225



SystemOperator



BUILTIN\Users



0x221



User



■ Note Membership of the BUILTIN\Administrators group under Windows 7 will depend on the whether your

process is running with elevated privileges. If the current user is an administrator but your process is running

without elevated privileges, checking membership of BUILTIN\Administrators will return false. See Chapter 14

for recipes relating to elevated privileges.



The Code

The following example demonstrates how to test whether the current user is a member of a set of named

“Windows groups.” You specify the groups that you want to test for as command-line arguments.

Remember to prefix the group name with the machine or domain name, or BUILTIN for standard

Windows groups.

using System;

using System.Security.Principal;

namespace Apress.VisualCSharpRecipes.Chapter11

{

class Recipe11_10

{

public static void Main (string[] args)

{



566



www.it-ebooks.info



CHAPTER 11 ■ SECURITY AND CRYPTOGRAPHY



if (args.Length == 0)

{

Console.WriteLine(

"Please provide groups to check as command line arguments");

}

// Obtain a WindowsIdentity object representing the currently

// logged-on Windows user.

WindowsIdentity identity = WindowsIdentity.GetCurrent();

// Create a WindowsPrincipal object that represents the security

// capabilities of the specified WindowsIdentity; in this case,

// the Windows groups to which the current user belongs.

WindowsPrincipal principal = new WindowsPrincipal(identity);

// Iterate through the group names specified as command-line

// arguments and test to see if the current user is a member of

// each one.

foreach (string role in args)

{

Console.WriteLine("Is {0} a member of {1}? = {2}",

identity.Name, role, principal.IsInRole(role));

}

// Wait to continue.

Console.WriteLine("\nMain method complete. Press Enter.");

Console.ReadLine();

}

}

}



Usage

If you run this example as a user named Darryl on a computer named MACHINE using this command:

Recipe11-10 BUILTIN\Administrators BUILTIN\Users MACHINE\Accountants

you will see console output similar to the following:

Is MACHINE\Darryl a member of BUILTIN\Administrators? = False

Is MACHINE\Darryl a member of BUILTIN\Users? = True

Is MACHINE\Darryl a member of MACHINE\Accountants? = True



567



www.it-ebooks.info



CHAPTER 11 ■ SECURITY AND CRYPTOGRAPHY



11-11. Restrict Which Users Can Execute Your Code

Problem

You need to restrict which users can execute elements of your code based on the user’s name or the roles

of which the user is a member.



Solution

Use the permission class System.Security.Permissions.PrincipalPermission and its attribute

counterpart System.Security.Permissions.PrincipalPermissionAttribute to protect your program

elements with RBS demands.



How It Works

The .NET Framework supports both imperative and declarative RBS demands. The class

PrincipalPermission provides support for imperative security statements, and its attribute counterpart

PrincipalPermissionAttribute provides support for declarative security statements. RBS demands use

the same syntax as CAS demands, but RBS demands specify the name the current user must have, or

more commonly, the roles of which the user must be a member. An RBS demand instructs the runtime

to look at the name and roles of the current user, and if that user does not meet the requirements of the

demand, the runtime throws a System.Security.SecurityException exception.

To make an imperative security demand, you must first create a PrincipalPermission object

specifying the username and role name you want to demand, and then you must call its Demand method.

You can specify only a single username and role name per demand. If either the username or the role

name is null, any value will satisfy the demand. Unlike with code access permissions, an RBS demand

does not result in a stack walk; the runtime evaluates only the username and roles of the current user.

To make a declarative security demand, you must annotate the class or member you want to protect

with a correctly configured PrincipalPermissionAttribute attribute. Class-level demands apply to all

members of the class, unless a member-specific demand overrides the class demand.

Generally, you are free to choose whether to implement imperative or declarative demands.

However, imperative security demands allow you to integrate RBS demands with code logic to achieve

more sophisticated demand behavior. In addition, if you do not know the role or usernames to demand

at compile time, you must use imperative demands. Declarative demands have the advantage that they

are separate from code logic and easier to identify. In addition, you can view declarative demands using

the Permview.exe tool (discussed in recipe 11-6). Whether you implement imperative or declarative

demands, you must ensure that the runtime has access to the name and roles for the current user to

evaluate the demand correctly.

The System.Threading.Thread class represents an operating system thread running managed code.

The static property CurrentPrincipal of the Thread class contains an IPrincipal instance representing

the user on whose behalf the managed thread is running. At the operating system level, each thread also

has an associated Windows access token, which represents the Windows account on whose behalf the

thread is running. The IPrincipal instance and the Windows access token are two separate entities.

Windows uses its access token to enforce operating system security, whereas the .NET runtime uses its

IPrincipal instance to evaluate application-level RBS demands. Although they may, and often do,

represent the same user, this is by no means always the case.



568



www.it-ebooks.info



CHAPTER 11 ■ SECURITY AND CRYPTOGRAPHY



The benefit of this approach is that you can implement a user and an RBS model within your

application using a proprietary user accounts database, without the need for all users to have Windows

user accounts. This is a particularly useful approach in large-scale, publicly accessible Internet

applications.

By default, the Thread.CurrentPrincipal property is undefined. Because obtaining user-related

information can be time-consuming, and only a minority of applications use this information, the .NET

designers opted for lazy initialization of the CurrentPrincipal property. The first time code gets the

Thread.CurrentPrincipal property, the runtime assigns an IPrincipal instance to the property using the

following logic:





If the application domain in which the current thread is executing has a default

principal, the runtime assigns this principal to the Thread.CurrentPrincipal

property. By default, application domains do not have default principals.

You can set the default principal of an application domain by calling the

SetThreadPrincipal method on a System.AppDomain object that represents the

application domain you want to configure. Code must have the ControlPrincipal

element of SecurityPermission to call SetThreadPrincipal. You can set the default

principal only once for each application domain; a second call to

SetThreadPrincipal results in the exception System.Security.Policy.

PolicyException.







If the application domain does not have a default principal, the application

domain’s principal policy determines which IPrincipal implementation to create

and assign to Thread.CurrentPrincipal. To configure principal policy for an

application domain, obtain an AppDomain object that represents the application

domain and call the object’s SetPrincipalPolicy method. The

SetPrincipalPolicy method accepts a member of the enumeration

System.Security.Principal.PrincipalPolicy, which specifies the type of

IPrincipal object to assign to Thread.CurrentPrincipal. Code must have the

ControlPrincipal element of SecurityPermission to call SetPrincipalPolicy.

Table 11-3 lists the available PrincipalPolicy values; the default value is

UnauthenticatedPrincipal.







If your code has the ControlPrincipal element of SecurityPermission, you can

instantiate your own IPrincipal object and assign it to the Thread.

CurrentPrincipal property directly. This will prevent the runtime from assigning

default IPrincipal objects or creating new ones based on principal policy.



569



www.it-ebooks.info



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

11-10. Determine If the Current User Is a Member of a Specific Windows Group

Tải bản đầy đủ ngay(0 tr)

×