HELP with Code Access Security!
-
Hello, I am wondering if there is a way to programatically find a code group in the configuration wizard? Basically, I have a c# app (local) that calls c# apps (remote share). If I try to call an app without the proper permissions set up, the CALLED app seems to throw a security exception. Since I have no idea how to trap an exception in localApp that is thrown by calledApp, I want to try something else: What I want to do is this: 1) Before calling remote app, somehow query the Machine Code Groups in .NET Framework Configuration (programatically). 2) If the required code group does not exist, create it. 3) Finally, call the remote app. Is this possible? Thanks, Ian
-
Hello, I am wondering if there is a way to programatically find a code group in the configuration wizard? Basically, I have a c# app (local) that calls c# apps (remote share). If I try to call an app without the proper permissions set up, the CALLED app seems to throw a security exception. Since I have no idea how to trap an exception in localApp that is thrown by calledApp, I want to try something else: What I want to do is this: 1) Before calling remote app, somehow query the Machine Code Groups in .NET Framework Configuration (programatically). 2) If the required code group does not exist, create it. 3) Finally, call the remote app. Is this possible? Thanks, Ian
Yes, you can enumerate the code groups. You can enumerate the
SecurityManager.PolicyHierarchy
to get the right policy (like Machine), then enumerate the code groups underneath that. I do it in are installer for our touchless-deployment app (well, not completely touchless since a one-time installation is required). You can further add code groups using this mechanism, but you should at least prompt the user. Companies and savvy users don't like you messing with security unless it's clear that you are and why you are messing with security. Really, though - if both of these applications are managed applications, you should consider another approach. If you don't mind that one "process" runs within the first, you can create a new managedAppDomain
and load the assembly that contains the entry pointMain
from the second application usingAppDomain.ExecuteAssembly
. You can either pass your currentAppDomain
's evidence, or gather host and assembly evidence for the newAppDomain
and pass that toExecuteAssembly
. If the executable does not have the necessary permissions, aSecurityException
is thrown at that time.Microsoft MVP, Visual C# My Articles
-
Yes, you can enumerate the code groups. You can enumerate the
SecurityManager.PolicyHierarchy
to get the right policy (like Machine), then enumerate the code groups underneath that. I do it in are installer for our touchless-deployment app (well, not completely touchless since a one-time installation is required). You can further add code groups using this mechanism, but you should at least prompt the user. Companies and savvy users don't like you messing with security unless it's clear that you are and why you are messing with security. Really, though - if both of these applications are managed applications, you should consider another approach. If you don't mind that one "process" runs within the first, you can create a new managedAppDomain
and load the assembly that contains the entry pointMain
from the second application usingAppDomain.ExecuteAssembly
. You can either pass your currentAppDomain
's evidence, or gather host and assembly evidence for the newAppDomain
and pass that toExecuteAssembly
. If the executable does not have the necessary permissions, aSecurityException
is thrown at that time.Microsoft MVP, Visual C# My Articles
Thanks Heath - I hate to ask but given that I am a total noob at this - can you provide (or point me to) a more specific example of enumerating the PolicyHierarchy and searching for specific groups? I am unable to actually resolve specific group names or at least cannot figure out how to. Right now I have: IEnumerator levels = SecurityManager.PolicyHierarchy(); while(levels.MoveNext()) { PolicyLevel pl = (PolicyLevel)levels.Current; Console.WriteLine("Policy Level: {0}", pl.Label); } Which prints: Policy Level: Enterprise Policy Level: Machine Policy Level: User I see a method in there called ResolveMatchingCodeGroups() but it wants an "evidence" and no matter what I try in the Evidence object it always returns the same things, something like: All_Code All_Code All_Code I want to check if "MyCustomCodeGroup" exists. It is located here:
- Runtime Security Policy
- Machine
- Code Groups
- All_Code
- LocalIntranet_Zone
- MyCustomCodeGroupThe membership condition type is "URL" and the URL is "file://MyServer/*". The permission set on this group is FullTrust. As for the other part of your reply - The appdomain/assembly stuff is complete greek to me. I will have to learn more about it. However I would say that the local exe calls remote exe's. The remote exe's can be managed code but also they can be .cmd/.bat files or even .msi, or .exe (C++ apps). Thanks for your help, Ian
-
Thanks Heath - I hate to ask but given that I am a total noob at this - can you provide (or point me to) a more specific example of enumerating the PolicyHierarchy and searching for specific groups? I am unable to actually resolve specific group names or at least cannot figure out how to. Right now I have: IEnumerator levels = SecurityManager.PolicyHierarchy(); while(levels.MoveNext()) { PolicyLevel pl = (PolicyLevel)levels.Current; Console.WriteLine("Policy Level: {0}", pl.Label); } Which prints: Policy Level: Enterprise Policy Level: Machine Policy Level: User I see a method in there called ResolveMatchingCodeGroups() but it wants an "evidence" and no matter what I try in the Evidence object it always returns the same things, something like: All_Code All_Code All_Code I want to check if "MyCustomCodeGroup" exists. It is located here:
- Runtime Security Policy
- Machine
- Code Groups
- All_Code
- LocalIntranet_Zone
- MyCustomCodeGroupThe membership condition type is "URL" and the URL is "file://MyServer/*". The permission set on this group is FullTrust. As for the other part of your reply - The appdomain/assembly stuff is complete greek to me. I will have to learn more about it. However I would say that the local exe calls remote exe's. The remote exe's can be managed code but also they can be .cmd/.bat files or even .msi, or .exe (C++ apps). Thanks for your help, Ian
Ahh I figured it out finally :)
-
Thanks Heath - I hate to ask but given that I am a total noob at this - can you provide (or point me to) a more specific example of enumerating the PolicyHierarchy and searching for specific groups? I am unable to actually resolve specific group names or at least cannot figure out how to. Right now I have: IEnumerator levels = SecurityManager.PolicyHierarchy(); while(levels.MoveNext()) { PolicyLevel pl = (PolicyLevel)levels.Current; Console.WriteLine("Policy Level: {0}", pl.Label); } Which prints: Policy Level: Enterprise Policy Level: Machine Policy Level: User I see a method in there called ResolveMatchingCodeGroups() but it wants an "evidence" and no matter what I try in the Evidence object it always returns the same things, something like: All_Code All_Code All_Code I want to check if "MyCustomCodeGroup" exists. It is located here:
- Runtime Security Policy
- Machine
- Code Groups
- All_Code
- LocalIntranet_Zone
- MyCustomCodeGroupThe membership condition type is "URL" and the URL is "file://MyServer/*". The permission set on this group is FullTrust. As for the other part of your reply - The appdomain/assembly stuff is complete greek to me. I will have to learn more about it. However I would say that the local exe calls remote exe's. The remote exe's can be managed code but also they can be .cmd/.bat files or even .msi, or .exe (C++ apps). Thanks for your help, Ian
The important thing is not the name of the code group, but that the permission set assigned to the code group is sufficient to run your code. What if someone changed the name of the code group or created their own? It's the
CodeGroup.PolicyStatement
- or rather thePermissionSet
that thePolicyStatement
contains - that is important. Instead of checking that, though - as there would be much more to do - you could get the evidence for your new assembly and compare that against theCodeGroup.MembershipCondition
to see if they match. As far as launching any executables besides .NET assemblies, code access security doesn't really matter except for the ability to access that file on whatever media it resides. Your application that launches that application must have permissions to access that resource (read access, in order to launch it). It is your application that must have it, so if you want to determine whether or not you can before you launch it, you should create aFileIOPermission
with the path to the resource and in a try/catch callAssert
. If no exception is thrown, you can go ahead and launch the executable. Catch anySecurityException
that is thrown and display and error, log it, or whatever.Microsoft MVP, Visual C# My Articles
-
The important thing is not the name of the code group, but that the permission set assigned to the code group is sufficient to run your code. What if someone changed the name of the code group or created their own? It's the
CodeGroup.PolicyStatement
- or rather thePermissionSet
that thePolicyStatement
contains - that is important. Instead of checking that, though - as there would be much more to do - you could get the evidence for your new assembly and compare that against theCodeGroup.MembershipCondition
to see if they match. As far as launching any executables besides .NET assemblies, code access security doesn't really matter except for the ability to access that file on whatever media it resides. Your application that launches that application must have permissions to access that resource (read access, in order to launch it). It is your application that must have it, so if you want to determine whether or not you can before you launch it, you should create aFileIOPermission
with the path to the resource and in a try/catch callAssert
. If no exception is thrown, you can go ahead and launch the executable. Catch anySecurityException
that is thrown and display and error, log it, or whatever.Microsoft MVP, Visual C# My Articles
Thanks again, I think I have this working to my satisfaction (for the time being at least - till I figure out more of how all this works). What I do is enumerate down to the groups below LocalIntranet_Zone and look for MyCustomAccess. Then I also check that it is type URL and points to the appropriate share location. I also check that it has FullTrust permission set. Here's my next problem: If I do NOT find the proper code group with proper permissions, I want to add one. I have seen many examples in various places. Every example creates a new code group at the same level as LocalIntranet_Zone (siblings(?)). I want to create a new group that is a child of LocalIntranet_Zone. While I haven't keyed in the examples, I assume they work. The issue I have is when I call SecurityManager.SavePolicy() - it does not actually get saved, even though the group was added or at least seems to have been added. Here is my code: can you tell me what is wrong? Why doesn't it save?
static bool addCodeGroup() { // Enumerate all the policies IEnumerator policyEnumerator = SecurityManager.PolicyHierarchy(); // Move through policies until we hit Machine while (policyEnumerator.MoveNext()) { PolicyLevel machineLevel = (PolicyLevel)policyEnumerator.Current; // If we are in the Machine Security Policy... if (machineLevel.Label == "Machine") { // Build an enumerator to move through the machine level groups IEnumerator ie_MachineLevelGroups = machineLevel.RootCodeGroup.Children.GetEnumerator(); while (ie_MachineLevelGroups.MoveNext()) { CodeGroup machineLevelGroup = (CodeGroup)ie_MachineLevelGroups.Current; // if we are in the LocalIntranet_Zone Code Group... if (machineLevelGroup.Name == "LocalIntranet_Zone") { PermissionSet permSet1 = new NamedPermissionSet("FullTrust"); IMembershipCondition membership1 = new UrlMembershipCondition("file://wstltest/*"); PolicyStatement policy1 = new PolicyStatement(permSet1); CodeGroup codeGroup1 = new UnionCodeGroup(membership1, policy1); codeGroup1.Name = "WSTLTEST_ACCESS"; machineLevelGroup.AddChild(codeGroup1); SecurityManager.SavePolicy(); } // end if (machineLevelGroup.Name == "LocalIntranet_Zone") } // end while (ie_MachineLevelGroups.MoveNext()) } // end if (machineLevel.Label == "Machine") } // end while (policyEnumerator.MoveNext()) return true; }
-
Thanks again, I think I have this working to my satisfaction (for the time being at least - till I figure out more of how all this works). What I do is enumerate down to the groups below LocalIntranet_Zone and look for MyCustomAccess. Then I also check that it is type URL and points to the appropriate share location. I also check that it has FullTrust permission set. Here's my next problem: If I do NOT find the proper code group with proper permissions, I want to add one. I have seen many examples in various places. Every example creates a new code group at the same level as LocalIntranet_Zone (siblings(?)). I want to create a new group that is a child of LocalIntranet_Zone. While I haven't keyed in the examples, I assume they work. The issue I have is when I call SecurityManager.SavePolicy() - it does not actually get saved, even though the group was added or at least seems to have been added. Here is my code: can you tell me what is wrong? Why doesn't it save?
static bool addCodeGroup() { // Enumerate all the policies IEnumerator policyEnumerator = SecurityManager.PolicyHierarchy(); // Move through policies until we hit Machine while (policyEnumerator.MoveNext()) { PolicyLevel machineLevel = (PolicyLevel)policyEnumerator.Current; // If we are in the Machine Security Policy... if (machineLevel.Label == "Machine") { // Build an enumerator to move through the machine level groups IEnumerator ie_MachineLevelGroups = machineLevel.RootCodeGroup.Children.GetEnumerator(); while (ie_MachineLevelGroups.MoveNext()) { CodeGroup machineLevelGroup = (CodeGroup)ie_MachineLevelGroups.Current; // if we are in the LocalIntranet_Zone Code Group... if (machineLevelGroup.Name == "LocalIntranet_Zone") { PermissionSet permSet1 = new NamedPermissionSet("FullTrust"); IMembershipCondition membership1 = new UrlMembershipCondition("file://wstltest/*"); PolicyStatement policy1 = new PolicyStatement(permSet1); CodeGroup codeGroup1 = new UnionCodeGroup(membership1, policy1); codeGroup1.Name = "WSTLTEST_ACCESS"; machineLevelGroup.AddChild(codeGroup1); SecurityManager.SavePolicy(); } // end if (machineLevelGroup.Name == "LocalIntranet_Zone") } // end while (ie_MachineLevelGroups.MoveNext()) } // end if (machineLevel.Label == "Machine") } // end while (policyEnumerator.MoveNext()) return true; }
While the reference is correct for the
machinePolicy
object you use, trySecurityManager.SavePolicyLevel(machinePolicy);
. I use this in our installer with no problems.Microsoft MVP, Visual C# My Articles
-
While the reference is correct for the
machinePolicy
object you use, trySecurityManager.SavePolicyLevel(machinePolicy);
. I use this in our installer with no problems.Microsoft MVP, Visual C# My Articles
Thanks Heath, but still not working - Where would I add SecurityManager.SavePolicyLevel(machineLevel) call? I tried adding it just before SavePolicy() call... Just after SavePolicy() call... In place of SavePolicy() call... Still doesn't save the machine policy.
-
Thanks Heath, but still not working - Where would I add SecurityManager.SavePolicyLevel(machineLevel) call? I tried adding it just before SavePolicy() call... Just after SavePolicy() call... In place of SavePolicy() call... Still doesn't save the machine policy.
Compare it with this...which works:
// Create the policy statement.
NamedPermissionSet namedPS = new NamedPermissionSet("FullTrust");
PolicyStatement ps = new PolicyStatement(namedPS);
ps.Attributes = PolicyStatementAttribute.Exclusive;
// Create the membership condition.
string url = "http://www.dummycorp.com";
UrlMembershipCondition condition = new UrlMembershipCondition(url);
// Create the code group.
UnionCodeGroup proplanner = new UnionCodeGroup(condition, ps);
proplanner.Name = "MyCodeGroup";
proplanner.Description = "Allows fully-trusted access to the URL.";
// Find the machine policy level.
PolicyLevel machine = null;
IEnumerator ie = SecurityManager.PolicyHierarchy();
while (ie.MoveNext())
if (String.Compare(((PolicyLevel)ie.Current).Label, "Machine", true) == 0)
machine = (PolicyLevel)ie.Current;
// If the machine policy level was not found, throw an exception.
if (machine == null)
throw new InstallException("Unable to find the Machine policy level.");
// Enumerate the root code group children and
// determine if the Proplanner group already exists.
bool exists = false;
foreach (CodeGroup group in machine.RootCodeGroup.Children)
{
if (proplanner.Equals(group))
{
exists = true;
break;
}
}
// If the code group doesn't exist, add it.
if (!exists)
{
// Add our code group to the root code group.
machine.RootCodeGroup.AddChild(proplanner);
SecurityManager.SavePolicyLevel(machine);
}Microsoft MVP, Visual C# My Articles