Исключение 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;