C#笔记32:FRAMEWORK安全性之代码访问安全和角色安全
C#笔记32:FRAMEWORK安全性之代码访问安全和角色安全
本章概要:
1:FRAMEWORK安全性中的几个概念
1.1:安全权限
1.2:类型安全和安全性
1.3:安全策略
1.4:身份验证
2:代码访问安全之声明式安全性
3:代码访问安全之强制安全性
4:代码访问安全之请求权限
4.1:请求访问非托管代码的权限
4.2:通过使用 RequestMinimum 标志请求最小权限
4.3:通过使用 RequestOptional 标志请求可选权限
4.4:通过使用 RequestRefuse 标志拒绝授予权限
4.5:请求命名权限集的权限
5:基于角色的安全性
5.1:主体和标识对象
5.2:PrincipalPermission 对象
5.3基于角色的安全检查
5.3.1如何:执行命令性安全检查
5.3.2执行声明式安全检查
5.3.3直接访问主体对象
1:FRAMEWORK安全性中的几个概念
1.1:安全权限
指三类权限,如下:
-
代码访问权限,此权限表示对受保护资源的访问权或执行受保护操作的能力。
-
标识权限,此权限指示代码具有支持特定类型的标识的凭据。
例如,某个权限表示程序集必须具有的强名称,而另一权限表示代码必须源自的网站,诸如此类等等。由于标识权限具有一组与代码访问权限通用的功能,故它们与代码访问权限 CodeAccessPermission 从同一基类派生.
-
基于角色的安全性权限,此权限提供一种机制来确定用户(或代表用户的代理)是具有特定标识还是指定角色的成员。PrincipalPermission 是唯一的基于角色的安全性权限。
1.2:类型安全和安全性
当代码是类型安全时,运行库的安全性强制机制确保代码不会访问本机代码,除非它有访问本机代码的权限。所有非类型安全的代码必须通过传递的枚举成员 SkipVerification 授予 SecurityPermission 后才能运行。
1.3:安全策略
每当发生加载程序集的尝试时,运行库就使用安全策略确定授予程序集的权限。在检查了描述程序集标识的信息(称为证据)后,运行库使用安全策略决定代码的信任程度和由此授予程序集的权限。证据包括但不仅限于代码的出版商、它的站点以及它的区域。安全策略还确定授予应用程序域的权限。
1.4:身份验证
目前使用的身份验证机制种类繁多,其中许多都可以同 .NET Framework 基于角色的安全性一起使用。一些最常用的机制包括基本、简要、Passport、操作系统(如 NTLM 或 Kerberos)或应用程序定义的机制。
2:代码访问安全之声明式安全性
下面的代码段说明声明式语法,该语法用于请求代码的调用方拥有名为 MyPermission 的自定义权限。此权限是假设的自定义权限,在 .NET Framework 中并不存在。在此示例中,声明式调用直接放在类定义之前,指定将此权限应用到类级别。向该属性传递一个 SecurityAction.Demand 结构来指定调用方必须拥有此权限才能运行。
[MyPermission(SecurityAction.Demand, Unrestricted = true)] public class MyClass { public MyClass() { //The constructor is protected by the security call. } public void MyMethod() { //This method is protected by the security call. } public void YourMethod() { //This method is protected by the security call. } }
3:代码访问安全之强制安全性
下面的代码段说明请求代码的调用方拥有名为 MyPermission 的自定义权限时所用的强制性语法。此权限是假设的自定义权限,在 .NET Framework 中并不存在。在 MyMethod 中创建 MyPermision 的一个新实例,使用安全性调用仅保护此方法。
public class MyClass { public MyClass(){ } public void MyMethod() { //MyPermission is demanded using imperative syntax. MyPermission Perm = new MyPermission(); Perm.Demand(); //This method is protected by the security call. } public void YourMethod() { //This method is not protected by the security call. } }
4:代码访问安全之请求权限
请求权限会通知运行库应用程序正常运行需要哪些权限,或具体不需要哪些权限。例如,如果应用程序在不使用独立存储的情况下向本地硬盘进行写入,则应用程序必须拥有 FileIOPermission。如果代码不请求 FileIOPermission,而且本地安全设置不允许应用程序拥有此权限,则会在应用程序尝试向磁盘写入时引发安全性异常。即使应用程序能够处理此异常,也不会允许它向磁盘写入。如果您的应用程序是文本编辑程序,而用户已经使用了很长一段时间,则此行为会使用户很失望。另一方面,如果应用程序请求 FileIOPermission,而本地安全设置不允许您的应用程序拥有 FileIOPermission,则应用程序将在启动时生成异常,用户不会遇到丢失任何工作的问题。另外,如果您的应用程序请求 FileIOPermission 并且它是受信任的应用程序,则管理员可以调整安全策略来允许它从远程共享执行。
下表描述权限请求的类型。
最小权限 (RequestMinimum):您的代码要运行必须拥有的权限。
可选的权限 (RequestOptional):您的代码可以使用的权限,但在没有这些权限时代码仍可有效运行。此请求隐式拒绝未明确请求的所有其他权限。
拒绝的权限 (RequestRefuse):您要确保永远不授予您的代码的权限(即使安全策略允许将它们授予您的代码)。
对内置权限集执行上述任何请求(请求内置权限集):内置的权限集包括:Nothing、Execution、FullTrust、Internet、LocalIntranet 和 SkipVerification。
对 XML 编码的权限集执行上述任何请求(请求 XML 编码的权限):所需权限集的 XML 表示形式(或者是包含 XML 编码的权限集的字符串,或者是包含编码的权限集的 XML 文件的位置)。
4.1:请求访问非托管代码的权限
下面的示例说明如何请求权限来访问非托管代码。注意,它使用 SecurityPermissionAttribute 并指定两个值:指定所发出权限请求的类型的 SecurityAction 值(在此例中为 RequestMinimum)和指示所请求权限的标志。在此例中,SecurityPermissionFlag.UnmanagedCode 指定请求非托管代码权限。assembly: 语法通知编译器在程序集级别应用该属性。
//The request is placed at the assembly level. using System.Security.Permissions; [assembly:SecurityPermissionAttribute(SecurityAction.RequestMinimum, Flags = SecurityPermissionFlag.UnmanagedCode)] namespace MyNamespace { using System; using System.Runtime.InteropServices; public class MyClass { public MyClass() { } public void MyMethod() { //Perform interoperation with unmanaged code here. } } }
如果上面的代码未接收到具有 UnmanagedCode 标志的 SecurityPermission,则运行库将引发一个 PolicyException 并且不允许该代码执行。但是,如果代码一旦获得该权限,则允许该代码执行。
4.2:通过使用 RequestMinimum 标志请求最小权限
下面的示例使用 RequestMinimum 标志请求 FileIOPermission。如果尚未被授予请求的权限,此示例将不会执行。此示例假定在 LogNameSpace 中存在一个假设的类 Log。Log 类包含可在本地计算机上创建新的日志文件的 MakeLog 方法。此应用程序创建 Log 类的一个新实例,并在 try 块中执行 MakeLog 方法。使用 catch 关键字,它可以截获引发的任何 SecurityException 并显示消息。
//The request is placed at the assembly level. using System.Security.Permissions; [assembly:FileIOPermission(SecurityAction.RequestMinimum, Unrestricted = true)] namespace MyNamespace { using System; using System.Security; //The hypothetical class log is in this namespace. using LogNameSpace; public class MyClass { public MyClass() { } public static void Main(string[] args) { //Put any code that requires optional permissions in the try block. try { Log MyLog = new Log(); MyLog.MakeLog(); Console.WriteLine("The Log has been created."); } //Catch the security exception and inform the user that the //application was not granted FileIOPermission. catch(SecurityException) { Console.WriteLine("This application does not have permission to write to the disk."); } } } }
如果上面的代码有足够的权限,它会创建日志文件并将下面的消息显示到控制台上:
The Log has been created.
如果从共享位置运行该代码,并且本地安全设置不允许此类代码拥有 FileIOPermission,则不会授予该代码足够的权限,并显示下面的消息:
This application does not have permission to write to the disk.
4.3:通过使用 RequestOptional 标志请求可选权限
SecurityAction.RequestOptional 标志允许您请求一组权限,而拒绝所有其他权限(如果不拒绝,运行库将授予这些权限)。相反,RequestRefuse 标志允许您通过明确指定不应该向您的代码授予哪些权限来拒绝权限。
与使用 RequestMinimum 标志相比,如果应用程序没有接收到使用 RequestOptional 标志请求的所有权限,则您的应用程序将执行,当该应用程序试图访问受保护的资源时,将引发 SecurityException。如果您使用此类型的请求,必须使您的代码能够捕捉在未授予代码可选权限的情况下引发的任何异常。
下面的示例使用 SecurityAction.RequestOptional 标志请求 FileIOPermission,间接拒绝所有其他权限。此示例假定在 LogNameSpace 中存在一个假设的类 Log。Log 类包含可在本地计算机上创建新的日志文件的 MakeLog 方法。此应用程序创建 Log 类的一个新实例,并在 try 块中执行 MakeLog 方法。使用 catch 关键字,它可以截获引发的任何 SecurityException 并显示消息。
//The request is placed at the assembly level. using System.Security.Permissions; [assembly:FileIOPermission(SecurityAction.RequestOptional, Unrestricted = true)] namespace MyNamespace { using System; using System.Security; //The hypothetical class log is in this namespace. using LogNameSpace; public class MyClass { public MyClass() { } public static void Main(string[] args) { //Put any code that requires optional permissions in the try block. try { Log MyLog = new Log(); MyLog.MakeLog(); Console.WriteLine("The Log has been created."); } //Catch the security exception and inform the user that the //application was not granted FileIOPermission. catch(SecurityException) { Console.WriteLine("This application does not have permission to write to the disk."); } } } }
如果上面的代码有足够的权限,它会创建日志文件并将下面的消息显示到控制台上:
The Log has been created.
如果从共享位置运行该代码,并且本地安全设置不允许此类代码拥有 FileIOPermission,则不会授予该代码足够的权限,并显示下面的消息:
This application does not have permission to write to the disk.
4.4:通过使用 RequestRefuse 标志拒绝授予权限
如果担心您的代码会被恶意地用来访问系统资源,则可以请求永远不向它授予相应的权限。例如,浏览文件中的数据但从不修改数据的应用程序可能拒绝任何文件写入权限。在发生 bug 或恶意攻击时,此代码不会损坏它操作的数据。
RequestRefuse 允许将大量权限作为可选的权限来请求,同时确保某些特定的权限不在授予之列。
下面的示例使用 RequestRefuse 来拒绝来自公共语言运行库安全系统的 FileIOPermission:
//The request is placed at the assembly level. using System.Security.Permissions; [assembly:FileIOPermission(SecurityAction.RequestRefuse ,Unrestricted = true)] namespace MyNameSpace { using System; using System.Security; using System.Security.Permissions; using System.IO; public class MyClass { public MyClass() { } public static int Main(string[] args) { //Creation of the log is attempted in the try block. try { StreamWriter TextStream = new StreamWriter("Log.txt"); TextStream.WriteLine("This Log was created on {0}", DateTime.Now); TextStream.Close(); Console.WriteLine("The Log was created"); } //Catch the Security exception and inform the user that the //application was not granted FileIOPermission. catch(SecurityException) { Console.WriteLine("This application does not have permission to write to the disk."); } return 0; } } }
上面的示例没有被授予创建文件的权限,将生成安全性异常。捕捉语句截获异常,同时应用程序将下面的消息显示到控制台上:
This application does not have permission to write to the disk.
4.5:请求命名权限集的权限
您可以不请求单个权限(使用 RequestMinimum、RequestOptional 或 RequestRefuse),而请求下面的任何内置权限集:Nothing、Execution、FullTrust、Internet、LocalIntranet 和 SkipVerification。您不能请求自定义的命名权限集或 Everything 可修改的内置权限集,因为它们表示的权限可能会变化。下面的示例说明请求命名权限集的权限的语法。它将一个 PermissionSetAttribute 与表示所需权限集的名称的 Name 值连接起来。
//The attribute is placed at the assembly level. using System.Security.Permissions; [assembly:PermissionSetAttribute(SecurityAction.RequestMinimum, Name = "FullTrust")] namespace MyNamespace { using System; using System.Runtime.InteropServices; public class MyClass { public MyClass() { } public void MyMethod() { //Perform operations that require permissions here. } } }
5:基于角色的安全性
5.1:主体和标识对象
标识对象
标识对象封装有关正在验证的用户或实体的信息。在最基本的级别上,标识对象包含名称和身份验证类型。名称可以是用户名或 Windows 帐户名,而身份验证类型可以是所支持的登录协议(如 Kerberos V5)或自定义值。.NET Framework 定义了一个 GenericIdentity 对象和一个更专用的 WindowsIdentity 对象;前者可用于大多数自定义登录方案,而后者可用于在希望应用程序依赖于 Windows 身份验证的情况中。此外,您还可以定义自己的标识类来封装自定义用户信息。
IIdentity 接口定义用于访问名称和身份验证类型(如 Kerberos V5 或 NTLM)的属性。所有 Identity 类均实现 IIdentity 接口。Identity 对象同执行当前线程所用的 Windows NT 进程标记之间不需要有什么关系。但是,如果 Identity 对象是 WindowsIdentity 对象,则假定标识表示 Windows NT 安全标记。
主体对象
主体对象表示代码运行时所在的安全上下文。实现基于角色的安全性的应用程序将基于与主体对象关联的角色来授予权限。同标识对象类似,.NET Framework 提供 GenericPrincipal 对象和 WindowsPrincipal 对象。您还可以定义自己的自定义主体类。
5.2:PrincipalPermission 对象
基于角色的安全性模型支持与代码访问安全性模型中的权限对象类似的权限对象。此对象(即 PrincipalPermission)表示特定主体类在运行时必须具有的标识和角色。以命令方式和声明方式进行的安全检查均可使用 PrincipalPermission 类。
若要以命令方式实现 PrincipalPermission 类,请创建该类的一个新实例,并用希望用户在访问代码时具有的名称和角色来初始化该实例。例如,以下代码以“"Joan"”身份和“"Teller"”角色对此对象的一个新实例进行初始化。
String id = "Joan"; String role = "Teller"; PrincipalPermission principalPerm = new PrincipalPermission(id, role);
可使用 PrincipalPermissionAttribute 类,以声明方式创建一个类似的权限。以下代码以声明方式将身份初始化为“Joan”,并将角色初始化为“Teller”。
[PrincipalPermissionAttribute(SecurityAction.Demand, Name = "Joan", Role = "Teller")]
执行安全检查时,为成功完成检查,指定的身份和角色必须匹配。但是,创建 PrincipalPermission 对象时,可传递一个空的身份字符串以指示主体的身份可以是任意的。同样,传递一个空的角色字符串指示主体可以是任何角色的成员(或根本不属于任何角色)。对于声明的安全性,可通过省略两种属性之一来获得相同的效果。例如,下列代码使用 PrincipalPermissionAttribute 以声明方式指示主体可以具有任意名称,但必须具有出纳的角色。
[PrincipalPermissionAttribute(SecurityAction.Demand, Role = "Teller")]
5.3基于角色的安全检查
定义了标识和主体对象后,可采用下列方法之一对其进行安全检查:
-
使用命令式安全检查。
-
使用声明性安全检查。
-
直接访问 Principal 对象。
托管代码可使用命令式或声明式安全检查来确定以下内容:特定主体对象是否是已知角色的成员,是否具有已知的身份,或者是否表示一种角色中的一个已知身份。若要通过命令式或声明式安全性进行安全检查,必须对适当构造的 PrincipalPermission 对象生成一个安全请求。安全检查期间,公共语言运行库检查调用方的主体对象,确定其身份和角色是否与所请求的 PrincipalPermission 表示的身份和角色相匹配。如果主体对象不匹配,则引发 SecurityException。(只检查当前线程的主体对象;PrincipalPermission 类不会像代码访问权限那样导致产生堆栈遍历。)
此外,可以直接访问主体对象的值,并在不使用 PrincipalPermission 对象的情况下执行检查。在这种情况下,只需读取当前线程主体的值或使用 IsInRole 方法执行身份验证。
5.3.1如何:执行命令性安全检查
对于命令式请求,可以调用 PrincipalPermission 对象的 Demand 方法来确定当前主体对象是否表示指定的身份、角色或同时表示两者。假定有一个适当构造的 PrincipalPermission 对象(称为 MyPrincipalPermission),可使用以下代码调用命令式请求。
MyPrincipalPermission.Demand();
下面的代码示例使用命令式检查确保 GenericPrincipal 同 PrincipalPermission 对象匹配。当应用程序域中的许多方法或其他程序集必须做出基于角色的决定时,命令式检查是有用的。尽管此示例极其简单,但它阐明了与基于角色的请求相关的行为。
using System; using System.Security.Permissions; using System.Security.Principal; using System.Security; using System.Threading; using System.Security.Cryptography; public class MainClass { public static int Main(string[] args) { Console.WriteLine("Enter '1' to use the proper identity or " + "any other character to use the improper identity."); if(Console.ReadLine() == "1") { // Create a generic identity. GenericIdentity MyIdentity = new GenericIdentity("MyUser"); // Create a generic principal. String[] MyString = {"Administrator", "User"}; GenericPrincipal MyPrincipal = new GenericPrincipal(MyIdentity, MyString); Thread.CurrentPrincipal = MyPrincipal; } PrivateInfo(); return 0; } public static void PrivateInfo() { try { // Create a PrincipalPermission object. PrincipalPermission MyPermission = new PrincipalPermission("MyUser", "Administrator"); // Demand this permission. MyPermission.Demand(); // Print secret data. Console.WriteLine( "\n\nYou have access to the private data!"); } catch(SecurityException e) { Console.WriteLine(e.Message); } } }
如果用户键入 1,则将创建访问 PrivateInfo 方法所需的主体和标识对象。如果用户键入任何其他字符,则不会创建主体和标识对象,并且在调用 PrivateInfo 方法时,会引发一个安全异常。如果当前线程与一个名称为 MyUser、角色为 Administrator 的主体关联,则会出现下面的消息。
You have access to the private data!
5.3.2执行声明式安全检查
PrincipalPermission 的声明式请求的工作方式同代码访问权限的声明式请求相同。请求既可放在类级别上,也可放在个别方法、属性或事件上。如果声明式请求同时放在类级别和成员级别上,则成员上的声明式请求将覆盖(或取代)类级别上的请求。
下面的代码示例显示了前一节示例中的 PrivateInfo 方法经过修改后的版本。此版本使用声明式安全性。PrincipalPermissionAttribute 定义当前线程在调用方法时必须具有的主体。仅用所需的名称和角色传递 SecurityAction.Demand。
[PrincipalPermissionAttribute(SecurityAction.Demand, Name = "MyUser", Role = "User")] public static void PrivateInfo() { //Print secret data. Console.WriteLine("\n\nYou have access to the private data!"); }
如果当前线程不包含正确的主体,此方法将引发安全异常。如果用户输入 1,则将调用 PrivateInfo 方法,并将下面的消息显示到控制台。
You have access to the private data!
5.3.3直接访问主体对象
尽管使用命令式和声明式请求调用基于角色的安全检查是检查和强制身份与角色成员条件的主要机制,但在某些情况下,您可能希望直接访问 Principal 对象及其关联的 Identity 对象来完成身份验证任务,而不必创建权限对象。例如,如果不希望验证失败时的默认行为是引发异常,则可能不想使用声明式或命令式请求。这时,可以在 System.Threading.Thread 类上使用静态 CurrentPrincipal 属性来访问 Principal 对象并调用其方法。
获取主体对象后,可以使用条件语句根据主体名来控制对代码的访问,如下面的代码示例所示。
WindowsPrincipal MyPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal; if (MyPrincipal.Identity.Name == "fred") // Permit access to some code.
还可通过在当前 Principal 对象上调用 IsInRole 方法,以编程方式检查角色成员条件,如以下代码实例所示。
// Get the current identity. WindowsIdentity MyIdent = WindowsIdentity.GetCurrent(); // Create a principal. WindowsPrincipal MyPrincipal = new WindowsPrincipal(MyIdent); // Check the role using a string. if (MyPrincipal.IsInRole(@"BUILTIN\Administrators")) { Console.WriteLine("You are an administrator."); } else { Console.WriteLine("You are not an administrator."); } // Check the role using an enumeration. if (MyPrincipal.IsInRole(WindowsBuiltInRole.Administrator)) { Console.WriteLine("You are an administrator."); } else { Console.WriteLine("You are not an administrator."); }
当希望访问应用程序定义的 Principal 对象特定的行为时可以使用此方法。但是,在多数情况下,应使用 PrincipalPermission 类根据身份或角色成员条件来控制对代码的访问。
下面的代码示例将创建一个 WindowsPrincipal 对象和一个 WindowsIdentity 对象,将它们设置给当前用户,并根据 Principal 的值做出安全决策。此代码不以命令或声明的方式使用 PrincipalPermission 对象,而是根据主体对象的值做出访问决定。
using System; using System.Security.Permissions; using System.Security.Policy; using System.Security.Principal; using System.Threading; public class Class1 { public static int Main(string[] args) { // Set principal policy to get a WindowsPrincipal // as the current principal so you have permission to get // current user information. AppDomain.CurrentDomain.SetPrincipalPolicy( PrincipalPolicy.WindowsPrincipal); // Get the current principal and put it into a principal object. WindowsPrincipal myPrincipal = (Thread.CurrentPrincipal as WindowsPrincipal); // Check the name and see if the user is authenticated. if (myPrincipal.Identity.Name.Equals(@"MYDOMAIN\myuser") && myPrincipal.Identity.IsAuthenticated.Equals(true)) { Console.WriteLine("Hello {0}, you are authenticated!", myPrincipal.Identity.Name.ToString()); } else { Console.WriteLine("Go away! You are not authorized!"); } // Use IsInRole to determine the role of the current user. Array wbirFields = Enum.GetValues(typeof(WindowsBuiltInRole)); foreach (object roleName in wbirFields) { try { Console.WriteLine("{0}? {1}.", roleName, myPrincipal.IsInRole((WindowsBuiltInRole)roleName)); } catch (Exception) { Console.WriteLine("{0}: Could not obtain role for this RID.", roleName); } } return 0; } }
如果当前用户是 MYDOMAIN\myuser,此程序将向控制台显示以下消息。
Hello MYDOMAIN\myuser, you are authenticated!
但是,如果当前用户是任何其他用户,则程序将显示以下消息。
Go away! You are not authorized!
MyPrincipal.Identity.Name 中的值显示代表授权帐户的域和用户名。请注意,在 C# 中,字符串 "MYDOMAIN\myuser" 以 at 符号 (@) 为前缀,这样就不会将反斜杠解释为转义符。尽管前面的示例使用 WindowsIdentity 对象,但仍可使用一般对象轻松产生类似的代码。只需创建一般对象的实例,向其传递所需的值,然后就可以在该对象中检查那些值。
练习:
1.ou create a method that runs by using the credentials of the end user. You need to use Microsoft Windows
groups to authorize the user. You must add a code segment that identifies whether a user is in named Clerk. Which code segment should you use?
A. WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
foreach (IdentityReference grp in currentUser.Groups)
{NTAccount grpAccount = ((NTAccount)grp.Translate(typeof(NTAccount)));
isAuthorized = grpAccount.Value.Equals(Environment.MachineName + @"\Clerk");
if (isAuthorized) break;}
B. WindowsPrincipal currentUser = (WindowsPrincipal)Thread.CurrentPrincipal;
isAuthorized = currentUser.IsInRole("Clerk");
C. GenericPrincipal currentUser = (GenericPrincipal) Thread.CurrentPrincipal;
isAuthorized = currentUser.IsInRole("Clerk");
D. WindowsPrincipal currentUser = (WindowsPrincipal)Thread.CurrentPrincipal;
isAuthorized = currentUser.IsInRole(Environment.MachineName);
Answer: B
2.You are writing code for user authentication and authorization. The username, password, and roles are stored in
your application data store. You need to establish a user security context that will be used for authorization
checks such as IsInRole. You write the following code segment to authorize the user.
if (!TestPassword(userName, password))
throw new Exception("could not authenticate user");
string[] userRolsesArray = LookupUserRoles(userName);
You need to complete this code so that it establishes the user security context. Which code segment should you
use?
A. GenericIdentity ident = new GenericIdentity(userName);
GenericPrincipal currentUser = new GenericPrincipal(ident, userRolesArray);
Thread.CurrentPrincipal = currentUser;
B. WindowsIdentity ident = new WindowsIdentity(userName);
WindowsPrincipal currentUser = new WindowsPrincipal(ident);
Thread.CurrentPrincipal = currentUser;
C. NTAccount userNTName = new NTAccount(userName);
GenericIdentity ident = new GenericIdentity(userNTName.Value);
GenericPrincipal currentUser= new GenericPrincipal(ident, userRolesArray);
Thread.CurrentPrincipal = currentUser;
D. IntPtr token = IntPtr.Zero;token = LogonUserUsingInterop(userName, encryptedPassword);
WindowsImpersonationContext ctx = WindowsIdentity.Impersonate(token);
Answer: A
3.You are developing an application that will use custom authentication and role-based security. You need to
write a code segment to make the runtime assign an unauthenticated principal object to each running thread.
Which code segment should you use?
A. AppDomain domain = AppDomain.CurrentDomain;
domain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
B. AppDomain domain = AppDomain.CurrentDomain;
domain.SetThreadPrincipal(new WindowsPrincipal(null));
C. AppDomain domain = AppDomain.CurrentDomain;
domain.SetAppDomainPolicy(PolicyLevel.CreateAppDomainLevel());
D. AppDomain domain = AppDomain.CurrentDomain;
domain.SetPrincipalPolicy( PrincipalPolicy.UnauthenticatedPrincipal);
Answer: D
4.You are creating an assembly named Assembly1. Assembly1 contains a public method. The global cache
contains a second assembly named Assembly2.
You must ensure that the public method is only called from Assembly2 .
Which permission class should you use?
A. GacIdentityPermission
B. PublisherIdentityPermission
C. DataProtectionPermission
D. StrongNameIdentityPermission
Answer: D
5.You create a method that runs by using the credentials of the end user. You need to use Microsoft Windows
groups to authorize the user. You must add a code segment that identifies whether a user is in the local group
named Clerk. Which code segment should you use?
A. WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
For each (IdentityReference grp in currentUser.Groups)
{NTAccount grpAccount = ((NTAccount)grp.Translate(typeof(NTAccount)));
isAuthorized = grpAccount.Value.Equals(Environment.MachineName + @"\Clerk");
if (isAuthorized) break;}
B. WindowsPrincipal currentUser = (WindowsPrincipal)Thread.CurrentPrincipal;
isAuthorized = currentUser.IsInRole("Clerk");
C. GenericPrincipal currentUser = (GenericPrincipal) Thread.CurrentPrincipal;
isAuthorized = currentUser.IsInRole("Clerk");
D. WindowsPrincipal currentUser = (WindowsPrincipal)Thread.CurrentPrincipal;
isAuthorized = currentUser.IsInRole(Environment.MachineName);
Answer: B
6.You are developing a class library. Portions of your code need to access system environment variables. You
need to force a runtime SecurityException only when calle rs that are higher in the call stack do not have the
necessary permissions. Which call method should you use?
A. set.Demand();
B. set.Assert();
C. set.PermitOnly();
D. set.Deny();
Answer: A