How to: Request Optional Permissions by Using the RequestOptional Flag

The RequestOptional flag enables you to request a set of permissions and implicitly refuse all other permissions that the runtime otherwise might be willing to give. By contrast, the RequestRefuse flag enables you to refuse permissions by explicitly specifying which ones your code should not be granted.

You must use the RequestMinimum flag to identify permissions that you must have in addition to the optional permissions you identify with the RequestOptional flag. Your code loads and runs even if it does not have the permissions identified with the RequestOptional flag. A SecurityException is thrown when your application tries to use a resource that it does not have permission to access. If you use RequestOptional permissions, you must enable your code to catch any exceptions that will be thrown if your code is not granted the optional permission.

The Test example in the following procedure requests UIPermission by using the RequestMinimum flag, and requests FileIOPermission by using the RequestOptional flag. Therefore, it indirectly refuses all other permissions. The code in the try block in the Main method tries to create a new file. If the attempt fails, the catch block intercepts the SecurityException that is thrown and displays a message.

To run an application in a sandbox that demonstrates RequestOptional

  1. In Visual Studio, create a console application project.

  2. Copy the code from the Example section into the application file. The code creates a sandbox that runs with the LocalIntranet permission set. The LocalIntranet permission set does not include FileIOPermission.

  3. On the Project menu, click Properties, click the Signing tab, and sign the project with a strong name key.

  4. Add a new console application project named Test to the solution.

  5. Copy the following code into the application file for Test. The code requests FileIOPermission as an optional requirement. The application can be started even if it does not have FileIOPermission.

    Imports System
    Imports System.Security
    Imports System.Security.Permissions
    Imports System.IO
    
    <Assembly: FileIOPermission(SecurityAction.RequestOptional, Unrestricted:=True)> _
    <Assembly: UIPermission(SecurityAction.RequestMinimum, Unrestricted:=True)> 
    
    Public Class [MyClass]
    
        Public Sub New()
    
        End Sub 'New 
    
    
        Public Shared Sub Main(ByVal args() As String)
            'Put any code that requires optional permissions in the try block.  
            Try
                File.Create("test.txt")
                Console.WriteLine("The file has been created.")
                'Catch the security exception and inform the user that the  
                'application was not granted FileIOPermission. 
            Catch exception As SecurityException
                Console.WriteLine("This application does not have permission to write to the disk.")
            End Try 
    
        End Sub 'Main
    End Class '[MyClass]
    
    using System;
    using System.Security;
    using System.Security.Permissions;
    using System.IO;
    
    [assembly:FileIOPermission(SecurityAction.RequestOptional, Unrestricted = true)]
    [assembly: UIPermission(SecurityAction.RequestMinimum, Unrestricted = true)]
    
    public class MyClass
    {
        public MyClass()
        {
        }
    
        public static void Main(string[] args)
        {
            //Put any code that requires optional permissions in the try block.  
            try
            {
                File.Create("test.txt");
                Console.WriteLine("The file 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.");
            }
        }
    }
    
  6. Run the sandbox application. It will load and run the test application. When the application is run, an exception is thrown with the following message:

    This application does not have permission to write to the disk. 
    

For more information about how to run applications in a sandbox, see How to: Run Partially Trusted Code in a Sandbox.

Example

The following example creates a sandbox that runs with LocalIntranet permissions.

Imports System
Imports System.Collections
Imports System.Diagnostics
Imports System.Security
Imports System.Security.Permissions
Imports System.Security.Policy
Imports System.Reflection
Imports System.IO

Namespace SimpleSandbox

    Class Program

        Shared Sub Main(ByVal args() As String)
            ' Create the permission set to grant to other assemblies. 
            ' In this case we are granting the permissions found in the LocalIntranet zone. 
            Dim pset As PermissionSet = GetNamedPermissionSet("LocalIntranet")
            If pset Is Nothing Then 
                Return 
            End If 
            Dim ads As New AppDomainSetup()
            ' Identify the folder to use for the sandbox.
            Directory.CreateDirectory("C:\Sandbox")
            ads.ApplicationBase = "C:\Sandbox" 
            ' Copy the application to be executed to the sandbox.
            File.Copy("..\..\..\Test\Bin\Debug\Test.exe", "C:\sandbox\Test.exe", True)
            File.Copy("..\..\..\Test\Bin\Debug\Test.pdb", "C:\sandbox\Test.pdb", True)

            Dim hostEvidence As New Evidence()

            ' Create the sandboxed domain. 
            Dim sandbox As AppDomain = AppDomain.CreateDomain("Sandboxed Domain", hostEvidence, ads, pset, GetStrongName([Assembly].GetExecutingAssembly()))
            sandbox.ExecuteAssemblyByName("Test")

        End Sub 'Main


        Public Shared Function GetStrongName(ByVal [assembly] As [Assembly]) As StrongName
            If [assembly] Is Nothing Then 
                Throw New ArgumentNullException("assembly")
            End If 
            Dim assemblyName As AssemblyName = [assembly].GetName()
            Debug.Assert(Not (assemblyName Is Nothing), "Could not get assembly name")

            ' Get the public key blob. 
            Dim publicKey As Byte() = assemblyName.GetPublicKey()
            If publicKey Is Nothing OrElse publicKey.Length = 0 Then 
                Throw New InvalidOperationException("Assembly is not strongly named")
            End If 
            Dim keyBlob As New StrongNamePublicKeyBlob(publicKey)

            ' Return the strong name. 
            Return New StrongName(keyBlob, assemblyName.Name, assemblyName.Version)

        End Function 'GetStrongName

        Private Shared Function GetNamedPermissionSet(ByVal name As String) As PermissionSet
            Dim policyEnumerator As IEnumerator = SecurityManager.PolicyHierarchy()

            ' Move through the policy levels to the machine policy level. 
            While policyEnumerator.MoveNext()
                Dim currentLevel As PolicyLevel = CType(policyEnumerator.Current, PolicyLevel)

                If currentLevel.Label = "Machine" Then 
                    Dim copy As NamedPermissionSet = currentLevel.GetNamedPermissionSet(name)
                    Return CType(copy, PermissionSet)
                End If 
            End While 
            Return Nothing 

        End Function 'GetNamedPermissionSet
    End Class 'Program 
End Namespace
using System;
using System.Collections;
using System.Diagnostics;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Reflection;
using System.IO;
[assembly: FileIOPermission(SecurityAction.RequestMinimum, Unrestricted=true)]
namespace SimpleSandboxing
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create the permission set to grant to other assemblies. 
            // In this case we are granting the permissions found in the LocalIntranet zone.
            PermissionSet pset = GetNamedPermissionSet("LocalIntranet");
            if (pset == null)
                return;
            AppDomainSetup ads = new AppDomainSetup();
            // Identify the folder to use for the sandbox.
            Directory.CreateDirectory("C:\\Sandbox");
            ads.ApplicationBase = "C:\\Sandbox";
            // Copy the application to be executed to the sandbox.
            File.Copy(@"..\..\..\Test\Bin\Debug\Test.exe", "C:\\sandbox\\Test.exe", true);
            File.Copy(@"..\..\..\Test\Bin\Debug\Test.pdb", "C:\\sandbox\\Test.pdb", true);

            Evidence hostEvidence = new Evidence();

            // Create the sandboxed domain.
            AppDomain sandbox = AppDomain.CreateDomain(
                "Sandboxed Domain",
                hostEvidence,
                ads,
                pset,
                GetStrongName(Assembly.GetExecutingAssembly()));
            sandbox.ExecuteAssemblyByName("Test");
        }

        public static StrongName GetStrongName(Assembly assembly)
        {
            if (assembly == null)
                throw new ArgumentNullException("assembly");

            AssemblyName assemblyName = assembly.GetName();
            Debug.Assert(assemblyName != null, "Could not get assembly name");

            // Get the public key blob. 
            byte[] publicKey = assemblyName.GetPublicKey();
            if (publicKey == null || publicKey.Length == 0)
                throw new InvalidOperationException("Assembly is not strongly named");

            StrongNamePublicKeyBlob keyBlob = new StrongNamePublicKeyBlob(publicKey);

            // Return the strong name. 
            return new StrongName(keyBlob, assemblyName.Name, assemblyName.Version);
        }
        private static PermissionSet GetNamedPermissionSet(string name)
        {
            IEnumerator policyEnumerator = SecurityManager.PolicyHierarchy();

            // Move through the policy levels to the machine policy level. 
            while (policyEnumerator.MoveNext())
            {
                PolicyLevel currentLevel = (PolicyLevel)policyEnumerator.Current;

                if (currentLevel.Label == "Machine")
                {
                    NamedPermissionSet copy = currentLevel.GetNamedPermissionSet(name);
                    return (PermissionSet)copy;
                }
            }
            return null;
        }

    }
}

See Also

Concepts

Requesting Permissions

Reference

SecurityAction

FileIOPermission

UIPermission

Other Resources

Extending Metadata Using Attributes

Code Access Security

Change History

Date

History

Reason

January 2010

Replaced the sample to be run in the sandbox.

Customer feedback.

September 2008

Expanded the information.

Customer feedback.