Привет всем.
[VS2012, .NET 4.5]
По мотивам статьи
"Управление доступом для кода и ADO.NET" накатал тест, который работает как ожидалось:
Вкратце:
— Создается отдельный домен с минимальными правами.
— Внутри этого домена создается тестовый объект.
— Тестовый объект пытается открыть OLEDB-подключение (System.Data.OleDb.Connection).
| Скрытый текст |
| ////////////////////////////////////////////////////////////////////////////////
using System;
using System.Reflection;
using System.Security;
using System.Security.Policy;
using System.Security.Permissions;
using NUnit;
using NUnit.Framework;
namespace lcpi_data_oledb_tests.OleDbPermission{
////////////////////////////////////////////////////////////////////////////////
//class PartialTrustHelper
public class Test_000__Helper:MarshalByRefObject
{
public void TestConnectionOpen(string connectionString)
{
// Try to open a connection.
using (var connection=new System.Data.OleDb.OleDbConnection(connectionString))
{
connection.Open();
}//using cn
}//TestConnectionOpen
};//class Test_000__Helper
////////////////////////////////////////////////////////////////////////////////
//class Test_000
public static class Test_000
{
[Test]
public static void Test_000__NoSqlPermissions()
{
//----------------------------------------
// Create permission set for sandbox AppDomain.
// This example only allows execution.
var permissions
=new PermissionSet(PermissionState.None);
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
// Create sandbox AppDomain with permission set that only allows execution,
// and has no SqlClientPermissions.
var appDomainSetup
=new AppDomainSetup();
appDomainSetup.ApplicationBase
=AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
var firstDomain
=AppDomain.CreateDomain("NoSqlPermissions",
null,
appDomainSetup,
permissions);
// Create helper object in sandbox AppDomain so that code can be executed in that AppDomain.
var helperType
=typeof(Test_000__Helper);
var Helper
=(Test_000__Helper)firstDomain.CreateInstanceAndUnwrap(helperType.Assembly.FullName,
helperType.FullName);
try
{
// Attempt to open a connection in the sandbox AppDomain.
// This is expected to fail.
Helper.TestConnectionOpen(TestServices.Conf__GetCnStr());
}
catch (System.Security.SecurityException ex)
{
Console.WriteLine("Failed, as expected: {0}",ex.FirstPermissionThatFailed);
// Uncomment the following line to see Exception details.
Console.WriteLine("BaseException: " + ex.GetBaseException());
return;
}//catch
throw new ApplicationException("Connection opened, unexpected.");
}//Test_000__NoSqlPermissions
};//class Test_000
////////////////////////////////////////////////////////////////////////////////
}//namespace lcpi_data_oledb_tests.OleDbPermission
|
| |
Все создается, работает и выкидывает исключение SecurityException.
Теперь пытаюсь вместо System.Data.OleDb.OleDbConnection создавать и работать с собственной эквивалентной компонентой, которая живет в отдельной сборке (в ней есть unsafe код и используется CER).
public class Test_001__Helper:MarshalByRefObject
{
public void TestConnectionOpen(string connectionString)
{
//Try to open a connection.
using (var connection=new lcpi.data.oledb.OleDbConnection(connectionString))
{
connection.Open();
}//using cn
}//TestConnectionOpen
};//class Test_001__Helper
Она создается (отрабатывает конструктор). Но сваливается внутри Open, который косвенно вызывает RuntimeHelpers.PrepareConstrainedRegions().
lcpi_data_oledb_tests.OleDbPermission.Test_001.Test_001__NoSqlPermissions:
System.MethodAccessException : Методу "lcpi.data.oledb.structure.Structure_ComponentLifeManager.Dispose(lcpi.data.oledb.structure.Structure_IComponentLifeTerminator, Boolean)", прозрачному для безопасности, не удалось получить доступ к критически важному методу безопасности "System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions()".
Сборка "lcpi.data.oledb.net4_5.debug, Version=1.0.0.1533, Culture=neutral, PublicKeyToken=ff716095e8002e7e" является частично доверенной, поэтому среда CLR делает ее полностью прозрачной с точки зрения безопасности независимо от содержащихся в ней аннотаций прозрачности. Для доступа к коду, критическому с точки зрения безопасности, данная сборка должна быть полностью доверенной.
И я уже башку сломал — как заставить этот код работать. Я так понимаю, нужно сделать "lcpi.data.oledb.net4_5.debug" полностью доверенной.
Однако когда я эту сборку указываю в списке fullTrustAssemblies метода CreateDomain, сбой идет при вызове конструктора:
lcpi_data_oledb_tests.OleDbPermission.Test_001.Test_001__NoSqlPermissions:
System.MethodAccessException : Методу "lcpi_data_oledb_tests.OleDbPermission.Test_001__Helper.TestConnectionOpen(System.String)", прозрачному для безопасности, не удалось получить доступ к критически важному методу безопасности "lcpi.data.oledb.OleDbConnection..ctor(System.String)".
Сборка "lcpi.data.oledb.ntest.net4_5.debug, Version=1.0.0.936, Culture=neutral, PublicKeyToken=ff716095e8002e7e" является частично доверенной, поэтому среда CLR делает ее полностью прозрачной с точки зрения безопасности независимо от содержащихся в ней аннотаций прозрачности. Для доступа к коду, критическому с точки зрения безопасности, данная сборка должна быть полностью доверенной.
Если и эту сборку добавить в список fullTrustAssemblies, то получаем исключение из метода CreateInstanceAndUnwrap
lcpi_data_oledb_tests.OleDbPermission.Test_001.Test_001__NoSqlPermissions:
System.Security.SecurityException : Сбой при запросе.
Все сборки (тест и моя компонента) находятся в одном каталоге. Пробовал помещать сборки в GAC — не помогает.
Вообщем, похоже я что-то конкретно не догоняю. И буду признателен за любую полезную подсказку
Если использовать PermissionState.Unrestricted, то вышеперечисленных проблем нет. Но интересует именно работа с PermissionState.None.
Вот полный код, где я мучал свои сборки:
| Скрытый текст |
| ////////////////////////////////////////////////////////////////////////////////
using System;
using System.Reflection;
using System.Security;
using System.Security.Policy;
using System.Security.Permissions;
using NUnit;
using NUnit.Framework;
namespace OleDbPermission{
////////////////////////////////////////////////////////////////////////////////
//class PartialTrustHelper
public class Test_001__Helper:MarshalByRefObject
{
public void TestConnectionOpen(string connectionString)
{
// Try to open a connection.
using (var connection=new lcpi.data.oledb.OleDbConnection(connectionString))
{
connection.Open();
}//using cn
}//TestConnectionOpen
};//class Test_001__Helper
////////////////////////////////////////////////////////////////////////////////
//class Test_001
public static class Test_001
{
//one for all
private const string c_public_key
="002400000480000094000000060200000024000052534131000400000100010031585520470334"
+"64ce90aec77287bc095f857b499eb5ca5ecfb8a6aaa74c1d1e46cd19f22a92180c33eff2fa5440"
+"69998755360dbb067548b42857da0c6292b5a64eda7c358c212424f04793b39e0dc48eaa1b01ce"
+"617f6ef741782d0e05595ddb0068e266e547eff0ca7a09f0c484260005a27fe2bb2b07ac359f15"
+"e4b3a7b7";
//-----------------------------------------------------------------------
private static byte ToHex(char c)
{
if(c>='0' && c<='9')
return (byte)(c-'0');
if(c>='A' && c<='F')
return (byte)((c-'A')+10);
if(c>='a' && c<='f')
return (byte)((c-'a')+10);
throw new ApplicationException("Bad HEX");
}//ToHex
//-----------------------------------------------------------------------
private static byte[] get_public_key()
{
var result=new byte[c_public_key.Length/2];
for(int i=0,x=0,_c=c_public_key.Length;i!=_c;i+=2,++x)
{
result[x]=(byte)(16*ToHex(c_public_key[i])+ToHex(c_public_key[i+1]));
}
return result;
}//get_public_key
//-----------------------------------------------------------------------
[Test]
public static void Test_001__NoSqlPermissions()
{
//----------------------------------------
// Create permission set for sandbox AppDomain.
// This example only allows execution.
var permissions
=new PermissionSet(PermissionState.None);
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.AllFlags));
// Create sandbox AppDomain with permission set that only allows execution,
// and has no SqlClientPermissions.
var appDomainSetup
=new AppDomainSetup();
appDomainSetup.ApplicationBase
=AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
//----------------------------------------
var skey=new StrongNamePublicKeyBlob(get_public_key());
//lcpi.data.oledb.net4_5.debug.dll
var a1_name=new AssemblyName(typeof(lcpi.data.oledb.OleDbConnection).Assembly.FullName);
//lcpi.lib.net4_5.debug.dll HELPER ASSEMBLY
var a2_name=new AssemblyName(typeof(lcpi.lib.com.ClsCtxCode).Assembly.FullName);
//lcpi.data.oledb.ntest.net4_5.debug.pdb OUR ASSEMBLY
var a3_name=new AssemblyName(typeof(Test_001__Helper).Assembly.FullName);
//-----
var a1_sname=new StrongName(skey,
a1_name.Name,
a1_name.Version);
var a2_sname=new StrongName(skey,
a2_name.Name,
a2_name.Version);
var a3_sname=new StrongName(skey,
a3_name.Name,
a3_name.Version);
//----------------------------------------
var firstDomain
=AppDomain.CreateDomain("NoSqlPermissions",
null,
appDomainSetup,
permissions,
a1_sname,
//a2_sname,
a3_sname);
// Create helper object in sandbox AppDomain so that code can be executed in that AppDomain.
var helperType
=typeof(Test_001__Helper);
var Helper
=(Test_001__Helper)firstDomain.CreateInstanceAndUnwrap(helperType.Assembly.FullName,
helperType.FullName);
try
{
// Attempt to open a connection in the sandbox AppDomain.
// This is expected to fail.
Helper.TestConnectionOpen(TestServices.Conf__GetCnStr());
}
catch (System.Security.SecurityException ex)
{
Console.WriteLine("Failed, as expected: {0}",ex.FirstPermissionThatFailed);
// Uncomment the following line to see Exception details.
Console.WriteLine("BaseException: " + ex.GetBaseException());
return;
}//catch
throw new ApplicationException("Connection opened, unexpected.");
}//Test_001__NoSqlPermissions
};//class Test_001
////////////////////////////////////////////////////////////////////////////////
}//namespace OleDbPermission
|
| |
-- Пользователи не приняли программу. Всех пришлось уничтожить. --