カスタム アクセス許可の実装
すべてのアクセス許可オブジェクトは、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 メソッドを実装し、Copy、Intersect、IsSubsetOf、ToXML、および 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;
}
}