Thursday, October 14, 2004

Change DotNet Policy settings thro Code

Once upon a time, i was very desperate to get a piece of windows control work for a web, i needed some code to change the policy settings, so it was then when i stumbled at this wonderful piece of code that describes how to change policy and assembly trust settings through code.

the orignal url for the article goes like this.

http://blogs.msdn.com/shawnfa/archive/2004/09/09/227534.aspx

1
2 Modify the security policy to give an assembly FullTrust from the LocalIntranet
3
4
5 This method modifies the machine policy level and adds a code group that
6 matches the given application's key and name but does not take into account
7 version information.
8
9 If the policy is set up in a way that is different from the default CLR security policy,
10 this method may not produce the intended results. Assuming a default security policy, the
11 goal of this method is to produce a policy that looks like this:
12
13 Machine level:
14 1. All code: Nothing
15 1.1 Zone - MyComputer: FullTrust
16 1.1.1 StrongName - MS Key: FullTrust
17 1.1.2 StrongName - ECMA Key: FullTrust
18 1.2 Zone - Intranet: LocalIntranet
19 1.2.1 All code: Same site Web
20 1.2.2 All code: Same directory FileIO
21 1.2.3 StrongName - appKey, assemblyName: FullTrust
22 1.3 Zone - Internet: Internet
23 1.3.1 - All code: Same site Web
24 1.4 Zone - Untrusted: Nothing
25 1.5 Zone - Trusted: Internet
26 1.5.1 All code: Same site Web
27
28 assembly to grant FullTrust form the Intranet
29 Key of the assembly
30
31 If or are null
32
33
34 If is empty
35
36 true if the policy was modified, false otherwise
37 public static bool TrustIntranetAssembly(string assemblyName, StrongNamePublicKeyBlob appKey)
38 {
39 Debug.Assert(assemblyName != null && assemblyName != String.Empty, "assemblyName cannot be empty");
40 Debug.Assert(appKey != null, "appKey cannot be null");
41
42 if(assemblyName == null)
43 throw new ArgumentNullException("assemblyName");
44 if(assemblyName == String.Empty)
45 throw new ArgumentOutOfRangeException("assemblyName", assemblyName, "assemblyName cannot be empty");
46 if(appKey == null)
47 throw new ArgumentNullException("appKey");
48
49 bool addedGroup = false;
50
51 IEnumerator policyEnumerator = SecurityManager.PolicyHierarchy();
52
53 iterate over each policy level until we find the machine level group
54 while(policyEnumerator.MoveNext())
55 {
56 PolicyLevel policyLevel = policyEnumerator.Current as PolicyLevel;
57 Debug.Assert(policyLevel != null, "Unexpected object in policy enumerator");
58
59 if(policyLevel.Label.Equals("Machine"))
60 {
61 get a list of all the code groups on the machine level
62 CodeGroup root = policyLevel.RootCodeGroup;
63 IList children = root.Children;
64
65 iterate over each child until we find the LocalIntranet zone
66 for(int i = 0; i < children.Count; i++)
67 {
68 CodeGroup currentGroup = children[i] as CodeGroup;
69 Debug.Assert(currentGroup != null, "Unexpected object in code group's children");
70
71 if(currentGroup.Name.Equals("LocalIntranet_Zone"))
72 {
73 create permission objects that can be used to give the application FullTrust
74 IMembershipCondition membershipCondition = new StrongNameMembershipCondition(appKey, assemblyName, null);
75 PermissionSet permissionSet = new PermissionSet(PermissionState.Unrestricted);
76 PolicyStatement statement = new PolicyStatement(permissionSet);
77
78 now combine these objects into a CodeGroup
79 CodeGroup appCodeGroup = new UnionCodeGroup(membershipCondition, statement);
80 appCodeGroup.Description = String.Format("Allow {0} to run off the Intranet with FullTrust", assemblyName);
81 appCodeGroup.Name = assemblyName;
82
83 and make this CodeGroup a child of the Intranet zone
84 currentGroup.AddChild(appCodeGroup);
85 addedGroup = true;
86 break;
87 }
88 }
89 break;
90 }
91 }
92
93 Commit the changes to the policy
95 if(addedGroup)
95 SecurityManager.SavePolicy();
96
97 return addedGroup;
98 }

The CodeGroup.Children property (called at line 63) returns a copy of the child nodes, not a reference to the underlying child node collection. Modifying an item from this copy won't do much to alter the actual policy hierarchy.
To fix this, one would need to remove the LocalIntranet_Zone group from its parent group, then add the modified copy back as a new child. The "quick fix" version of this would be to add the following lines between your lines 84 and 85:
root.RemoveChild(currentGroup); root.AddChild(currentGroup);
There would still be at least two remaining problems:
1. Neither your original code nor my modification account for the possibility of concurrent modifications to the policy. The only way to be sure that no other process has modified the saved policy between the read and the write would be to place a write lock on the underlying file (security.config in this case) before starting the read. Of course, this would probably block the various SecurityManager operations as well, which means one would need to modify the file's XML directly.
2. Members of the local Users group cannot write to the underlying security configuration files, so policy modification is not functionality that should really be built into very many applications via code like this.

No comments: