カスタム アクセス許可の実装

すべてのアクセス許可オブジェクトは、IPermission インターフェイスを実装する必要があります。 CodeAccessPermission クラスは IPermission を実装しており、アクセス許可に必要なほとんどのメソッドを備えているため、カスタム アクセス許可を作成するには CodeAccessPermission から継承する方法が最も簡単です。 さらに、すべてのカスタムのコード アクセス許可には、IUnrestrictedPermission インターフェイスも実装する必要があります。 カスタム アクセス許可クラスは、強制セキュリティと宣言セキュリティの両方をサポートするために必要とされるため、宣言セキュリティしか使用しない場合でも作成する必要があります。

メモメモ

カスタム アクセス許可は、自身を参照しているアセンブリ以外のアセンブリで定義されている必要があります。カスタム アクセス許可に宣言セキュリティのセキュリティ属性が含まれる場合、カスタム アクセス許可と属性は別のアセンブリで定義されている必要があります。セキュリティ属性はアセンブリが読み込まれるときに実行され、参照が発生した時点で属性が作成されていない場合があるためです。宣言によるアクセス許可が定義されているアセンブリ内でそのアクセス許可を使用すると、TypeLoadException がスローされます。

アクセス許可クラスの定義

CodeAccessPermission クラスから派生するには、次に示す 5 つの主要メソッドをオーバーライドし、独自の実装を用意する必要があります。

  • Copy は、現在のアクセス許可オブジェクトの複製を作成します。

  • Intersect は、現在のクラスと渡されたクラスによって許可されているアクセス許可の積集合を返します。

  • IsSubsetOf は、渡されたアクセス許可に、現在のアクセス許可によって許可されているすべての操作が含まれている場合に true を返します。

  • FromXml は、カスタム アクセス許可の XML 表現をデコードします。

  • ToXml は、カスタム アクセス許可の XML 表現をエンコードします。

  • Union は、現在のアクセス許可と指定したアクセス許可を統合して 1 つのアクセス許可を作成します。

IUnrestrictedPermission インターフェイスを使用するには、IsUnrestrictedPermission というメソッドをオーバーライドして、独自の実装を用意する必要があります。 IUnrestrictedPermission インターフェイスをサポートするには、現在のオブジェクトにおける制限の状態を表す Boolean 値など、アクセス許可の現在のインスタンスが無制限かどうかを定義するためのシステムを実装する必要があります。

カスタム アクセス許可クラスを定義する方法を次のコード片に示します。 このコード片では、PermissionState 列挙型を受け入れるコンストラクターと、unrestricted という Boolean 値の両方が作成されます。 PermissionState 列挙型には、Unrestricted または None の値があります。 渡された列挙型の値が Unrestricted の場合は、コンストラクターは unrestricted を true に設定します。 それ以外の場合、unrestricted は false に設定されます。 作成したカスタム アクセス許可に固有のコンストラクターだけでなく、PermissionState 列挙型だけを受け取るコンストラクターをすべてのコード アクセス許可 (CodeAccessPermission から継承されたすべてのアクセス許可) がサポートする必要があります。

次の例に示すコードの他に、IsUnrestricted メソッドを実装し、CopyIntersectIsSubsetOfToXML、および FromXML の各メソッドをオーバーライドする必要もあります。 これらの手順を完了するための情報については、この例の後に続くセクションを参照してください。

Option Strict
Option Explicit
Imports System
Imports System.Security
Imports System.Security.Permissions
<SerializableAttribute()> NotInheritable Public Class CustomPermission
   Inherits CodeAccessPermission
   Implements IUnrestrictedPermission
   Private unrestricted As Boolean
   
   
   Public Sub New(state As PermissionState)
      If state = PermissionState.Unrestricted Then
         unrestricted = True
      Else
         unrestricted = False
      End If
   End Sub
   'Define the rest of your custom permission here. You must 
   'implement IsUnrestricted and override the Copy, Intersect, 
   'IsSubsetOf, ToXML, and FromXML methods.
End Class
using System;
using System.Security;
using System.Security.Permissions;

[SerializableAttribute()]
public sealed class CustomPermission: CodeAccessPermission, IUnrestrictedPermission
{  
   private bool unrestricted;

   public CustomPermission(PermissionState state)
   {
      if(state == PermissionState.Unrestricted)
      {
         unrestricted = true;
      }
      else
      {
         unrestricted = false;
      }
   }     

   //Define the rest of your custom permission here. You must 
   //implement IsUnrestricted and override the Copy, Intersect, 
   //IsSubsetOf, ToXML, and FromXML methods.
}

このクラスは、SerializableAttribute でマークされています。 属性を使用する宣言構文をサポートするには、クラスを SerializableAttribute でマークする必要があります。 カスタム セキュリティ オブジェクトを使用するカスタム属性の作成については、「宣言セキュリティのサポートの追加」を参照してください。

IsUnrestricted メソッドの実装

IsUnrestricted メソッドは、IUnrestrictedPermission インターフェイスによって要求され、アクセス許可の現在のインスタンスがそのアクセス許可によって保護されているリソースへの無制限のアクセス権を持っているかどうかを示す Boolean 値を返します。 このメソッドを実装するには、単純に unrestricted の値を返します。

IsUnrestricted メソッドを実装するコード例を次に示します。

Public Function IsUnrestricted() As Boolean Implements IUnrestrictedPermission.IsUnrestricted
   Return unrestricted
End Function
public bool IsUnrestricted()
{
   return unrestricted;
}

Copy メソッドのオーバーライド

Copy メソッドは CodeAccessPermission クラスによって要求され、現在のアクセス許可クラスのコピーを返します。

Copy メソッドをオーバーライドする方法を次のコードに示します。

Public Overrides Function Copy() As IPermission
   Dim myCopy As New CustomPermission(PermissionState.None)
   
   If Me.IsUnrestricted() Then
      myCopy.unrestricted = True
   Else
      myCopy.unrestricted = False
   End If
   Return myCopy
End Function
public override IPermission Copy()
{
   CustomPermission copy = new CustomPermission(PermissionState.None);

   if(this.IsUnrestricted())
   {
      copy.unrestricted = true;
   }
   else
   {
      copy.unrestricted = false;
   }
   return copy;
} 

Intersect メソッドと IsSubsetOf メソッドのオーバーライド

すべてのアクセス許可は、Intersect メソッドと IsSubsetOf メソッドを実装する必要があります。 これらのメソッドの動作は、次に示すように実装する必要があります。

  • アクセス許可 X によって許可されるすべての操作がアクセス許可 Y に含まれている場合、X.IsSubsetOf(Y) は true になります。

  • X.Intersect(Y) は、アクセス許可 X とアクセス許可 Y の両方によって許可される操作だけを許可するアクセス許可になります。

Intersect メソッドをオーバーライドして実装する方法を次の例に示します。 このメソッドは、IPermission から派生したクラスを受け入れ、このクラスを CustomPermisison オブジェクトの新しいインスタンスとして初期化します。 この例では、現在のオブジェクトと渡されたオブジェクトの両方が unrestricted の値を持つときには、これらのオブジェクトの積集合が、unrestricted の値を持つ最終的なオブジェクトとなります。 しかし、いずれかのオブジェクトが unrestricted の値として false を持つときには、最終的なオブジェクトの unrestricted の値も false になります。 このコードは、両方のオブジェクトが unrestricted の場合に限り、unrestricted オブジェクトを返します。

Public Overrides Function Intersect(target As IPermission) As IPermission
   If Nothing Is target Then
      Return Nothing
   End If
   Try
      Dim PassedPermission As CustomPermission = CType(target, CustomPermission)
      If Not PassedPermission.IsUnrestricted() Then
         Return PassedPermission
      End If
      Return Me.Copy()
   Catch InvalidCastException As Exception
      Throw New ArgumentException("Argument_WrongType", Me.GetType().FullName)
      End Try
End Function
public override IPermission Intersect(IPermission target)
{
   try
   {
      if(null == target)
      {
         return null;
      }
      CustomPermission PassedPermission = (CustomPermission)target;

      if(!PassedPermission.IsUnrestricted())
      {
         return PassedPermission;
      }
      return this.Copy();
   }
   catch (InvalidCastException)
   {
      throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
   }                
}

IsSubsetOf メソッドをオーバーライドする例を次に示します。 このメソッドが true を返すようにするには、現在のインスタンスと渡されたインスタンスが許可する操作のセットが、正確に一致する必要があります。 この場合、オーバーライドされたメソッドは、CustomPermission オブジェクトの新しいインスタンスを、渡されたアクセス許可オブジェクトとして初期化します。 両方のオブジェクトの unrestricted の値が同じ場合、このメソッドは true を返します。 2 つの値が異なる場合は false を返します。

Public Overrides Function IsSubsetOf(target As IPermission) As Boolean
   If Nothing Is target Then
      Return Not Me.unrestricted
   End If
   Try
      Dim passedpermission As CustomPermission = CType(target, CustomPermission)
      If Me.unrestricted = passedpermission.unrestricted Then
         Return True
      Else
         Return False
      End If
   Catch InvalidCastException As Exception
      Throw New ArgumentException("Argument_WrongType", Me.GetType().FullName)
      End Try
End Function
public override bool IsSubsetOf(IPermission target)
{  
   if(null == target)
   {
      return !this.unrestricted;
   }
   try
   {        
      CustomPermission passedpermission = (CustomPermission)target;
      if(this.unrestricted == passedpermission.unrestricted)
      {
         return true;
      }
      else
      {
         return false;
      }
   }
   catch (InvalidCastException)
   {
      throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
   }                
}

ToXml メソッドと FromXml メソッドのオーバーライド

アクセス許可では XML エンコーディングをサポートし、アクセス許可オブジェクトを XML として保存し、その XML ファイルを使用して別のアクセス許可オブジェクトを元のオブジェクトの値に復元できるようにします。 XML エンコーディングをサポートするには、ToXml メソッドと FromXml メソッドを定義する ISecurityEncodable インターフェイスをカスタム アクセス許可に実装する必要があります。 どちらのメソッドも CodeAccessPermission によって実装されているため、カスタム アクセス許可クラスが CodeAccessPermission から派生されている場合には、これらのメソッドをオーバーライドする必要があります。

オブジェクトの状態を表す XML 要素の内容は、そのオブジェクト自身によって決定されます。 FromXML メソッドは、ToXML メソッドがその XML を解釈でき、同じ状態を復元できる場合は、任意の XML 表現を使用できます。 ただし、Permission 要素を含める場合は、標準の書式に従う必要があります。 たとえば、CustomPermission の書式は次のようになります。

<IPermission class="CustomPermissions.CustomPermission, CustomPermissionAssembly " version="1" Unrestricted="True">

IPermission 要素には、次の 3 つの属性が含まれています。

  • class : 型名をその型を含んでいるアセンブリの名前によって一意に識別して指定します。

  • version : クラスのアセンブリのバージョンではなく、XML エンコーディングのバージョンを指定します。

  • Unrestricted : アクセス許可に無制限の権限が与えられているかどうかを指定します。

すべてのアクセス許可は、共通言語ランタイムのセキュリティ システムで使用するためには、IPermission という XML 要素でエンコードする必要があります。

新しいバージョンのアクセス許可では、XML に永続化されている以前のバージョンの情報との下位互換性を維持する必要があります。 version タグによって、データを最初にエンコードしたバージョンについての情報が、アクセス許可オブジェクトに提供されます。

SecurityElement クラスは、XML でエンコードされたアクセス許可オブジェクトを作成したり、それらのオブジェクトと対話したりするために必要となる主要機能をカプセル化します。 しかし、.NET Framework のセキュリティで使用される XML オブジェクト モデルは、他の XML オブジェクト モデルとは異なるため、他の種類の XML ファイルを生成するためには SecurityElement クラスを使用しないでください。 SecurityElement クラスのメンバーの完全な一覧については、このクラスのトピックを参照してください。

XML の Permission 要素を作成するコード例を次に示します。

Public Overrides Function ToXml() As SecurityElement
   Dim element As New SecurityElement("IPermission")
   Dim type As Type = Me.GetType()
   Dim AssemblyName As New StringBuilder(type.Assembly.ToString())
   AssemblyName.Replace(ControlChars.Quote, "'"c)
   element.AddAttribute("class", type.FullName & ", " & AssemblyName.ToString)
   element.AddAttribute("version", "1")
   element.AddAttribute("Unrestricted", unrestricted.ToString())
   Return element
End Function
public override SecurityElement ToXml()
{
   SecurityElement element = new SecurityElement("IPermission");
   Type type = this.GetType();
   StringBuilder AssemblyName = new StringBuilder(type.Assembly.ToString());
   AssemblyName.Replace('\"', '\'');
   element.AddAttribute("class", type.FullName + ", " + AssemblyName);
   element.AddAttribute("version", "1");
   element.AddAttribute("Unrestricted", unrestricted.ToString());
   return element;
}

上記の例では StringBuilder.Replace メソッドが使用されています。 SecurityElement クラス内の属性に二重引用符を含めることはできませんが、一部のアセンブリ名情報は二重引用符で囲まれています。 この状況に対処するために、Replace メソッドでアセンブリ名の二重引用符 (") を単一引用符 (') に変換しています。

次に示すメソッドは、上に示したメソッドが作成した SecurityElement オブジェクトを読み取り、Unrestricted プロパティの現在の値として、渡されたオブジェクトによって指定されている値を設定します。 このメソッドは、ToXml メソッドによって保存されたすべての情報を取得できる必要があります。

Public Overrides Sub FromXml(PassedElement As SecurityElement)
   Dim element As String = PassedElement.Attribute("Unrestricted")
   If Not element Is Nothing Then
      Me.unrestricted = Convert.ToBoolean(element)
   End If
End Sub
public override void FromXml(SecurityElement PassedElement)
{
   string element = PassedElement.Attribute("Unrestricted");
   if(null != element)
   {  
      this.unrestricted = Convert.ToBoolean(element);
   }
}

カスタム アクセス許可の例

カスタム アクセス許可クラスの完全なコード例を次に示します。

Option Explicit
Option Strict
Imports System
Imports System.Text
Imports System.Security
Imports System.Security.Permissions
Imports Microsoft.VisualBasic

<Serializable()>NotInheritable Public Class CustomPermission
   Inherits CodeAccessPermission
   Implements IUnrestrictedPermission
   Private unrestricted As Boolean
   Public Sub New(state As PermissionState)
      If state = PermissionState.Unrestricted Then
         unrestricted = True
      Else
         unrestricted = False
      End If
   End Sub

   Public Function IsUnrestricted() As Boolean Implements IUnrestrictedPermission.IsUnrestricted
      Return unrestricted
   End Function

   Public Overrides Function Copy() As IPermission
      'Create a new instance of CustomPermission with the current
      'value of unrestricted.
      Dim myCopy As New CustomPermission(PermissionState.None)
      
      If Me.IsUnrestricted() Then
         myCopy.unrestricted = True
      Else
         myCopy.unrestricted = False
      End If
      'Return the copy.
      Return copy
   End Function

   Public Overrides Function Intersect(target As IPermission) As IPermission
      'If nothing was passed, return null.
      If Nothing Is target Then
         Return Nothing
      End If
      Try
         'Create a new instance of CustomPermission from the passed object.
         Dim PassedPermission As CustomPermission = CType(target, CustomPermission)
         'If one class has an unrestricted value of false, then the
         'intersection will have an unrestricted value of false.
         'Return the passed class with the unrestricted value of false.
         If Not PassedPermission.unrestricted Then
            Return target
         End If
         'Return a copy of the current class if the passed one has
         'an unrestricted value of true.
         Return Me.Copy()

      'Catch an InvalidCastException.
      'Throw ArgumentException to notify the user.
      Catch InvalidCastException As Exception
         Throw New ArgumentException("Argument_WrongType", Me.GetType().FullName)
      End Try

   End Function

   Public Overrides Function IsSubsetOf(target As IPermission) As Boolean
      'If nothing was passed and unrestricted is false,
      ' return true. 
 
      If Nothing Is target Then
         Return Not Me.unrestricted
      End If
      Try
         'Create a new instance of CustomPermission from the passed object.
         Dim passedpermission As CustomPermission = CType(target, CustomPermission)
         'If unrestricted has the same value in both objects, then
         'one is the subset of the other.
         If Me.unrestricted = passedpermission.unrestricted Then
            Return True
         Else
            Return False
         End If

      'Catch an InvalidCastException.
      'Throw ArgumentException to notify the user.
      Catch InvalidCastException As Exception
         Throw New ArgumentException("Argument_WrongType", Me.GetType().FullName)
      End Try

   End Function
   
   
   Public Overrides Sub FromXml(PassedElement As SecurityElement)
      'Get the unrestricted value from the XML and initialize 
      'the current instance of unrestricted to that value.
      Dim element As String = PassedElement.Attribute("Unrestricted")
      If Not element Is Nothing Then
         Me.unrestricted = Convert.ToBoolean(element)
   End If
   End Sub
   
   
   Public Overrides Function ToXml() As SecurityElement
      'Encode the current permission to XML using the 
      'SecurityElement class.
      Dim element As New SecurityElement("IPermission")
      Dim type As Type = Me.GetType()
      Dim AssemblyName As New StringBuilder(type.Assembly.ToString())
      AssemblyName.Replace(ControlChars.Quote, "'"c)
      element.AddAttribute("class", type.FullName & ", " & AssemblyName.ToString)
      element.AddAttribute("version", "1")
      element.AddAttribute("Unrestricted", unrestricted.ToString())
      Return element
   End Function
End Class
using System;
using System.Text;
using System.Security;
using System.Security.Permissions;

[Serializable()]
public sealed class CustomPermission: CodeAccessPermission , IUnrestrictedPermission
{
   private bool unrestricted;

   public CustomPermission(PermissionState state)
   {
      if(state == PermissionState.Unrestricted)
      {
         unrestricted = true;
      }
      else
      {
         unrestricted = false;
      }
   }
      
   public bool IsUnrestricted()
   {
      return unrestricted;
   }

   public override IPermission Copy()
   {
      //Create a new instance of CustomPermission with the current
      //value of unrestricted.
      CustomPermission copy = new CustomPermission(PermissionState.None);

      if(this.IsUnrestricted())
      {
         copy.unrestricted = true;
      }
      else
      {
         copy.unrestricted = false;
      }
      //Return the copy.
      return copy;
   }

   public override IPermission Intersect(IPermission target)
   {
      //If nothing was passed, return null.
      if(null == target)
      {
         return null;
      }
      try
      {
         //Create a new instance of CustomPermission from the passed object.
         CustomPermission PassedPermission = (CustomPermission)target;

         //If one class has an unrestricted value of false, then the
         //intersection will have an unrestricted value of false.
         //Return the passed class with the unrestricted value of false.
         if(!PassedPermission.unrestricted)
         {
            return target;
         }
         //Return a copy of the current class if the passed one has
         //an unrestricted value of true.
         return this.Copy();
      }
      //Catch an InvalidCastException.
      //Throw ArgumentException to notify the user.
      catch (InvalidCastException)
      {
         throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
      }                
   }

   public override bool IsSubsetOf(IPermission target)
   {
      //If nothing was passed and unrestricted is false,
      //then return true. 
      if(null == target)
      {
         return !this.unrestricted;
      }
       try
      {        
         //Create a new instance of CustomPermission from the passed object.
         CustomPermission passedpermission = (CustomPermission)target;

         //If unrestricted has the same value in both objects, then
         //one is the subset of the other.
         if(this.unrestricted == passedpermission.unrestricted)
         {
            return true;
         }
         else
         {
            return false;
         } 
      }
      //Catch an InvalidCastException.
      //Throw ArgumentException to notify the user.
      catch (InvalidCastException)
      {
         throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
      }                    
   }

   public override void FromXml(SecurityElement PassedElement)
   {
      //Get the unrestricted value from the XML and initialize 
      //the current instance of unrestricted to that value.
      string element = PassedElement.Attribute("Unrestricted");         
 
      if(null != element)
      {  
         this.unrestricted = Convert.ToBoolean(element);
      }
   }

   public override SecurityElement ToXml()
   {
      //Encode the current permission to XML using the 
      //SecurityElement class.
      SecurityElement element = new SecurityElement("IPermission");
      Type type = this.GetType();
      StringBuilder AssemblyName = new StringBuilder(type.Assembly.ToString());
      AssemblyName.Replace('\"', '\'');
      element.AddAttribute("class", type.FullName + ", " + AssemblyName);
      element.AddAttribute("version", "1");
      element.AddAttribute("Unrestricted", unrestricted.ToString());
      return element;
   }
}

参照

参照

IPermission

CodeAccessPermission

IUnrestrictedPermission

SerializableAttribute

ISecurityEncodable

SecurityElement

概念

独自のコード アクセス許可の作成

コード アクセス セキュリティ

宣言セキュリティのサポートの追加