I created a CodeAccessSecurityAttribute implementation, witch use stack information to find the target class name, but in some classes the PrincipalPermition is not created, the system uses the previews one instead. What did I miss?
[ComVisible(true)]
[AttributeUsageAttribute(AttributeTargets.Constructor | AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
public sealed class MyPrincipalPermissionAttribute : CodeAccessSecurityAttribute
{
public MyPrincipalPermissionAttribute(SecurityAction action) : base(action) { }
public override IPermission CreatePermission()
{
if (Unrestricted)
return new PrincipalPermission(PermissionState.Unrestricted);
var stackTrace = new StackTrace();
var fullnameArray = new List<String>();
foreach (var frame in stackTrace.GetFrames())
{
try
{
var method = frame.GetMethod();
if (method != null && method.ReflectedType.IsSubclassOf(typeof (BaseClass)))
fullnameArray.Add(method.ReflectedType.FullName);
} catch {}
}
if (fullnameArray.Count() > 0)
return new PrincipalPermission(null, fullnameArray[0], true);
return new PrincipalPermission(PermissionState.Unrestricted);
}
}
And the usage
public class MyClassCalledFirstWork: BaseClass
{
[MyPrincipalPermission(SecurityAction.Demand)]
public override void DoSomething()
{
return;
}
}
public class MyClassCalledSecondDontWork: BaseClass
{
[MyPrincipalPermission(SecurityAction.Demand)]
public override void DoSomething()
{
return;
}
}
This is from documentation for SecurityAttribute.CreatePermission ():
"CreatePermission method creates a permission object that can then be serialized into binary form and persistently stored along with the SecurityAction in an assembly's metadata."
"At compile time, attributes convert security declarations to a serialized form in metadata. Declarative security data in metadata is created from the permission that this method returns that corresponds to this attribute."
It looks like there can be only one permission object (of some type) corresponding with custom CodeAccessSecurityAttribute stored for a specific SecurityAction. When you check the IL for DoSomething methods you can see that they contain identical permission demands with role defined during the first CreatePermission call.
.method public hidebysig virtual instance void
DoSomething() cil managed
{
.permissionset demand
= {class 'CustomSecurityPermission.Program+MyPrincipalPermissionAttribute, CustomSecurityPermission, Version=1.0.0.0, Culture=neutral' = {}}
...
} // end of method MyClassCalledSecondDontWork::DoSomething
.method public hidebysig virtual instance void
DoSomething() cil managed
{
.permissionset demand
= {class 'CustomSecurityPermission.Program+MyPrincipalPermissionAttribute, CustomSecurityPermission, Version=1.0.0.0, Culture=neutral' = {}}
...
} // end of method MyClassCalledFirstWork::DoSomething
An answer for your second question from comments is:
Instead of using declarative CAS I would use imperative:
public sealed class Security
{
public static IPermission CreatePermission()
{
var stackTrace = new StackTrace();
var fullnameArray = new List<String>();
foreach (var frame in stackTrace.GetFrames())
{
try
{
var method = frame.GetMethod();
if (method != null && method.ReflectedType.IsSubclassOf(typeof(BaseClass)))
fullnameArray.Add(method.ReflectedType.FullName);
}
catch { }
}
if (fullnameArray.Count() > 0)
{
return new PrincipalPermission(null, fullnameArray[0]);
}
return new PrincipalPermission(PermissionState.Unrestricted);
}
}
public class MyClassCalledFirstWork : BaseClass
{
public override void DoSomething()
{
Security.CreatePermission().Demand();
return;
}
}
public class MyClassCalledSecondDontWork : BaseClass
{
public override void DoSomething()
{
Security.CreatePermission().Demand();
return;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With