Исключение SecurityException для метода, украшенного PrincipalPermissionAttribute, только в модульном тесте MSTest .Net 4.5

После обновления нашего веб-сайта с использования более старых классов Microsoft.IdentityModel до классов System.IdentityModel (например,.Net 4.5 framework) большинство наших модульных тестов MSTest начали давать сбои, если они вызывали методы, которые использовали PrincipalPermissionAttribute.

Например:

[RequireAuthentication]
[PrincipalPermission(SecurityAction.Demand, Role = "AllowActAs")]
public ActionResult ActAs(int id)

В наших модульных тестах мы ранее устанавливали Thread.CurrentPrincipal перед тем, как вызывать метод контроллера следующим образом:

List<Microsoft.IdentityModel.Claims.Claim> claims = new List<Microsoft.IdentityModel.Claims.Claim>();
claims.Add(new Microsoft.IdentityModel.Claims.Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", "Jamie"));
claims.Add(new Microsoft.IdentityModel.Claims.Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "1234567890"));
claims.Add(new Microsoft.IdentityModel.Claims.Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "AllowActAs"));

Microsoft.IdentityModel.Claims.ClaimsIdentityCollection claimsCollection = new Microsoft.IdentityModel.Claims.ClaimsIdentityCollection();
claimsCollection.Add(new Microsoft.IdentityModel.Claims.ClaimsIdentity(claims));

Microsoft.IdentityModel.Claims.ClaimsPrincipal new_principal = new Microsoft.IdentityModel.Claims.ClaimsPrincipal(claimsCollection);
Thread.CurrentPrincipal = new_principal;

Я попытался воссоздать этот подход, переместив объекты в новые классы:

List<System.Security.Claims.Claim> claims = new List<System.Security.Claims.Claim>();
claims.Add(new System.Security.Claims.Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", "Jamie"));
claims.Add(new System.Security.Claims.Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "1234567890"));
claims.Add(new System.Security.Claims.Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "AllowActAs"));

List<System.Security.Claims.ClaimsIdentity> claimsCollection = new List<System.Security.Claims.ClaimsIdentity>();
claimsCollection.Add(new System.Security.Claims.ClaimsIdentity(claims));

System.Security.Claims.ClaimsPrincipal new_principal = new System.Security.Claims.ClaimsPrincipal(claimsCollection);
Thread.CurrentPrincipal = new_principal;

Однако всякий раз, когда я звоню target.ActAs(id)Я получаю исключение SecurityException. Я должен отметить, что я не получаю это исключение при фактическом использовании веб-сайта, если мой пользователь не находится в указанной роли, так что это как-то специфично для среды MSTest.

Кроме того, если я устанавливаю точку останова в модульном тесте непосредственно перед вызовом метода контроллера и проверяю Thread.CurrentPrincipal.IsInRole("AllowActAs") в часах результат true,

Кроме того, если я использую GenericPrincipal в текущем потоке, ему предоставляется доступ к методу, поэтому он должен иметь какое-то отношение к ClaimsPrincipal:

GenericPrincipal new_principal = new GenericPrincipal(
    new GenericIdentity("Jamie"),
    new string[] { "AllowActAs" }
);

Thread.CurrentPrincipal = new_principal;

У кого-нибудь есть идеи о том, где может быть отключение?

Возвращено полное исключение:

System.Security.SecurityException: Request for principal permission failed.
   at System.Security.Permissions.PrincipalPermission.ThrowSecurityException()
   at System.Security.Permissions.PrincipalPermission.Demand()
   at System.Security.PermissionSet.DemandNonCAS()
   at Stepp.ProclaimCrm.PortalUI.Controllers.ImpersonateController.ActAs(Int32 id) in c:\ProclaimCRM\ProclaimCRM Portal\Portal-9373-Portal-Based-Accounts\Portal Web Front-End\Controllers\ImpersonateController.cs:line 79
   at Portal_Web_Front_End_Test.ImpersonateTests.ActAsTestPersonWhoHasPreventActAs() in c:\ProclaimCRM\ProclaimCRM Portal\Portal-9373-Portal-Based-Accounts\Portal Web Front-End Test\Controllers\ImpersonateTests.cs:line 465
The action that failed was:
Demand
The type of the first permission that failed was:
System.Security.Permissions.PrincipalPermission
The first permission that failed was:
<IPermission class="System.Security.Permissions.PrincipalPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1">
<Identity Authenticated="true"
Role="AllowActAs"/>
</IPermission>

The demand was for:
<IPermission class="System.Security.Permissions.PrincipalPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1">
<Identity Authenticated="true"
Role="AllowActAs"/>
</IPermission>

The assembly or AppDomain that failed was:
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

1 ответ

Решение

Я наконец понял это. Я неправильно понял сообщение об ошибке. Хотя он ссылался на роль, реальные проблемы заключались в том, что System.Threading.Thread.CurrentPrincipal.Identity.IsAuthenticated было false, Согласно странице MSDN на ClaimsIdentity.IsAuthenticated ( http://msdn.microsoft.com/en-us/library/system.security.claims.claimsidentity.isauthenticated(v=vs.110).aspx), IsAuthenticated возвращает значение true, если ClaimsIdentity.AuthenticationType установлен в непустую строку.

Поскольку есть конструктор для ClaimsPrincipal, который позволяет вам указать тип аутентификации, добавление типа "Тест" аутентификации решило мою проблему:

List<System.Security.Claims.Claim> claims = new List<System.Security.Claims.Claim>();
claims.Add(new System.Security.Claims.Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", "Jamie"));
claims.Add(new System.Security.Claims.Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "1234567890"));
claims.Add(new System.Security.Claims.Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "AllowActAs"));

List<System.Security.Claims.ClaimsIdentity> claimsCollection = new List<System.Security.Claims.ClaimsIdentity>();
claimsCollection.Add(new System.Security.Claims.ClaimsIdentity(claims, "Test")); // specify authentication type here!!

System.Security.Claims.ClaimsPrincipal new_principal = new System.Security.Claims.ClaimsPrincipal(claimsCollection);
Thread.CurrentPrincipal = new_principal;
Другие вопросы по тегам