My understanding has always been that security attributes on methods will override security attributes on class, but that doesn't seem to be the case any more as the simple code below demonstrates:
class Program
{
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)] //<-- this passes
class DumbClass
{
[PrincipalPermission(SecurityAction.Demand, Role = "ffff")] //<-- this passes (but shouldn't)
public string EchoMethod(string input)
{
return input;
}
}
static void Main(string[] args)
{
Thread.CurrentPrincipal = new ClaimsPrincipal(new ClaimsIdentity("manual"));
//this should throw becuase the principal is not in the role "ffff"
//BUT DOESN'T
Console.WriteLine(new DumbClass().EchoMethod("this"));
}
}
If I remove the declaration on the class then I get the expected security exception.
Am I missing something really obvious. I'm using .Net 4.5
Because PrincipalPermissionAttribute
Demands are combined using OR, and a class attribute is essentially the same as adding the attribute to each method, your example is equivalent to:
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
class DumbClass
{
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
public DumbClass()
{
}
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
[PrincipalPermission(SecurityAction.Demand, Role = "ffff")]
public string EchoMethod(string input)
{
return input;
}
}
and because of OR logic, your demand for Role="ffff" is redundant.
If you want to restrict EchoMethod
to role "ffff", and allow authenticated users for all other methods, change your code to:
class DumbClass
{
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
public DumbClass()
{
}
[PrincipalPermission(SecurityAction.Demand, Role = "ffff")]
public string EchoMethod(string input)
{
return input;
}
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
public string OtherMethod(string input)
{
return input;
}
}
Change your code as so:
[PrincipalPermission(SecurityAction.Demand)] //<-- REMOVE Authenticated = true
class DumbClass
{
[PrincipalPermission(SecurityAction.Demand, Role = "ffff")] //<-- this passes (but shouldn't)
public string EchoMethod(string input)
{
return input;
}
}
By setting Authenticated = true you are explicitly indicating that the user has already been authenticated when they may or may not have been.