0

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 
4
  • What does the SecurityException say is the problem? Commented Sep 4, 2014 at 16:59
  • I updated the error with the full exception message and stack trace. Commented Sep 4, 2014 at 19:54
  • I noticed you mentioned the state at the breakpoint. However, I can't help noticing that this exception is from a test method called ActAsTestPersonWhoHasPreventActAs(). This method name seems to imply this is in fact a test of the opposite case, i.e., the exception is expected as the successful test result because this person should not be granted the permission. Is it possible that, far from breaking your test, the upgrade has caused it to start working? Commented Sep 4, 2014 at 21:29
  • I see your thought on this, but the point of the test is to verify that a person isn't allowed to "act as" a specific other person. It should just display an error message to them on the ActAs page rather than preventing them to get to the page in the first place. Also, I have roughly 60+ other tests that are now failing with this error. Given that the behavior in the production site seems generally correct, I doubt all of these tests were broken to begin with. Commented Sep 5, 2014 at 12:36

1 Answer 1

0

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; 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.