After upgrading our web site from using the older Microsoft.IdentityModel classes to the System.IdentityModel classes (e.g. .Net 4.5 framework), most of our MSTest unit tests started failing if they called methods that used the PrincipalPermissionAttribute.

For example:

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

Within our unit tests, we were previously setting the Thread.CurrentPrincipal before we calling the controller method like so:

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;

I have tried to recreate that approach by moving the objects over to the new classes:

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;

However, whenever I call target.ActAs(id), I get a SecurityException. I should note that I am not getting this exception when actually using the web site unless my user is not in the specified role, so this is somehow specific to the MSTest environment.

Additionally, if I set a break-point in the unit test just before calling the controller method and check Thread.CurrentPrincipal.IsInRole("AllowActAs") in the watch, the result is true.

Furthermore, if I use a GenericPrincipal on the current thread, it am granted access to the method, so it has to have something to do with the ClaimsPrincipal:

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

Thread.CurrentPrincipal = new_principal;

Does anyone have any ideas about where the disconnect might be?

The full exception returned is:

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

There are 1 best solutions below

0
On BEST ANSWER

I finally figured this out. I misunderstood the error message. Although it referenced the Role, the actual problems was that System.Threading.Thread.CurrentPrincipal.Identity.IsAuthenticated was false. According to the MSDN page on ClaimsIdentity.IsAuthenticated (http://msdn.microsoft.com/en-us/library/system.security.claims.claimsidentity.isauthenticated(v=vs.110).aspx), IsAuthenticated returns true if ClaimsIdentity.AuthenticationType is set to a non-empty string.

Since there's a constructor for ClaimsPrincipal that allows you to specify the authentication type, adding the "Test" authentication type fixed my problem:

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;