db52b0349d8ee0bba1fe7c69835f8794d0999641
[mono.git] / mcs / class / corlib / System.Security.Policy / CodeGroup.cs
1 // System.Security.Policy.CodeGroup
2 //
3 // Author(s):
4 //   Nick Drochak (ndrochak@gol.com)
5 //
6 // (C) 2001 Nick Drochak, All rights reserved.
7
8 //
9 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.Collections;
32 using System.Globalization;
33 using System.Reflection;
34 using System.Security.Policy;
35 using System.Security.Permissions;
36 //using System;  // for MonoTODO attribute
37
38 namespace System.Security.Policy {
39
40         [Serializable]
41         public abstract class CodeGroup {
42                 PolicyStatement m_policy = null;
43                 IMembershipCondition m_membershipCondition = null;
44                 string m_description = null;
45                 string m_name = null;
46                 ArrayList m_children = new ArrayList();
47                 PolicyLevel m_level;
48
49                 public CodeGroup (IMembershipCondition membershipCondition, PolicyStatement policy)
50                 {
51                         if (null == membershipCondition)
52                                 throw new ArgumentNullException("Value cannot be null.");
53
54                         m_policy = policy;
55                         m_membershipCondition = membershipCondition;
56                 }
57
58                 // for PolicyLevel (to avoid validation duplication)
59                 internal CodeGroup (SecurityElement e) 
60                 {
61                         FromXml (e);
62                 }
63
64                 // abstract
65
66                 public abstract CodeGroup Copy();
67                 public abstract string MergeLogic {get;}
68                 public abstract PolicyStatement Resolve (Evidence evidence);
69                 public abstract CodeGroup ResolveMatchingCodeGroups(Evidence evidence);
70
71                 public PolicyStatement PolicyStatement {
72
73                         get { return m_policy; }
74
75                         set { m_policy = value; }
76                 }
77
78                 public string Description {
79
80                         get { return m_description; }
81
82                         set { m_description = value; }
83                 }
84
85                 public IMembershipCondition MembershipCondition  {
86
87                         get {
88                                 return m_membershipCondition;
89                         }
90
91                         set {
92                                 if (null == value)
93                                         throw new ArgumentException("Value cannot be null");
94                                 m_membershipCondition = value;
95                         }
96                 }
97
98                 public string Name {
99                         get { return m_name; }
100                         set { m_name = value; }
101                 }
102
103                 public IList Children {
104                         get { return m_children; }
105                         set {
106                                 if (null == value)
107                                         throw new ArgumentNullException ("value");
108                                 m_children = new ArrayList(value);
109                         }
110                 }
111
112                 public virtual string AttributeString {
113                         get {
114                                 if (null != m_policy)
115                                         return m_policy.AttributeString;
116                                 return null;
117                         }
118                 }
119
120                 public virtual string PermissionSetName {
121                         get {
122                                 if (m_policy.PermissionSet is Security.NamedPermissionSet)
123                                         return ((NamedPermissionSet)(m_policy.PermissionSet)).Name;
124                                 return null;
125                         }
126                 }
127
128                 public void AddChild(CodeGroup group)
129                 {
130                         if (null == group)
131                                 throw new ArgumentNullException("The group parameter cannot be null");
132                         m_children.Add(group);
133                 }
134
135                 public override bool Equals(object o)
136                 {
137                         if (!(o is CodeGroup))
138                                 return false;
139
140                         return Equals((CodeGroup)o, false);
141                 }
142
143                 public bool Equals(CodeGroup cg, bool compareChildren)
144                 {
145                         if (cg.Name != this.Name)
146                                 return false;
147
148                         if (cg.Description != this.Description)
149                                 return false;
150
151 // FIXME: this compiles with CSC. Didn't succeed at creating a smaller/different test case :(
152 //                      if (!cg.MembershipCondition.Equals (m_membershipCondition))
153                         if (((object) cg.MembershipCondition).ToString () !=
154                             ((object) m_membershipCondition).ToString ())
155                                 return false;
156
157                         if (compareChildren) {
158                                 int childCount = cg.Children.Count;
159                                 if (this.Children.Count != childCount)
160                                         return false;
161
162                                 for (int index = 0; index < childCount; index++) {
163                                         // LAMESPEC: are we supposed to check child equality recursively?
164                                         //              The docs imply 'no' but it seems natural to do a 'deep' compare.
165                                         //              Will check the children's children, and so-on unless we find out that
166                                         //              we shouldn't
167                                         if (!((CodeGroup)(this.Children[index])).Equals((CodeGroup)(cg.Children[index]), true))
168                                                 return false;
169                                 }
170                         }
171                         return true;
172                 }
173
174                 public void RemoveChild (CodeGroup group)
175                 {
176                         if (group != null)
177                                 m_children.Remove (group);
178                 }
179
180                 public override int GetHashCode ()
181                 {
182                         int hashCode = m_membershipCondition.GetHashCode ();
183                         if (m_policy != null)
184                                 hashCode += m_policy.GetHashCode ();
185                         return hashCode;
186                 }
187
188                 public void FromXml (SecurityElement e)
189                 {
190                         FromXml (e, null);
191                 }
192
193                 public void FromXml (SecurityElement e, PolicyLevel level)
194                 {
195                         if (null == e)
196                                 throw new ArgumentNullException("e");
197
198                         PermissionSet ps = null;
199                         SecurityElement pset = e.SearchForChildByTag ("PermissionSet");
200                         if (pset != null) {
201                                 Type classType = Type.GetType (pset.Attribute ("class"));
202                                 ps = (PermissionSet) Activator.CreateInstance (classType, true);
203                                 ps.FromXml (pset);
204                         }
205                         else
206                                 ps = new NamedPermissionSet ("Nothing", new PermissionSet (PermissionState.None));
207                         m_policy = new PolicyStatement (ps);
208
209                         m_children.Clear ();
210                         if ((e.Children != null) && (e.Children.Count > 0)) {
211                                 foreach (SecurityElement se in e.Children) {
212                                         if (se.Tag == "CodeGroup") {
213                                                 this.AddChild (CodeGroup.CreateFromXml (se));
214                                         }
215                                 }
216                         }
217                         
218                         m_membershipCondition = null;
219                         SecurityElement mc = e.SearchForChildByTag ("IMembershipCondition");
220                         if (mc != null) {
221                                 string className = mc.Attribute ("class");
222                                 Type classType = Type.GetType (className);
223                                 if (classType == null)
224                                         classType = Type.GetType ("System.Security.Policy." + className);
225                                 m_membershipCondition = (IMembershipCondition) Activator.CreateInstance (classType);
226                                 m_membershipCondition.FromXml (mc, level);
227                         }
228
229                         m_name = e.Attribute("Name");
230                         m_description = e.Attribute("Description");
231
232                         // seems like we might need this to Resolve() in subclasses
233                         m_level = level;
234
235                         ParseXml (e, level);
236                 }
237
238                 protected virtual void ParseXml(SecurityElement e, PolicyLevel level)
239                 {
240                 }
241                 
242                 public SecurityElement ToXml()
243                 {
244                         return ToXml (null);
245                 }
246
247                 public SecurityElement ToXml (PolicyLevel level)
248                 {
249                         SecurityElement e = new SecurityElement("CodeGroup");
250                         e.AddAttribute("class", this.GetType().AssemblyQualifiedName);
251                         e.AddAttribute("version", "1");
252
253                         if (null != Name)
254                                 e.AddAttribute("Name", Name);
255
256                         if (null != Description)
257                                 e.AddAttribute("Description", Description);
258
259                         if (null != MembershipCondition)
260                                 e.AddChild(MembershipCondition.ToXml());
261
262                         if ((PolicyStatement != null) && (PolicyStatement.PermissionSet != null))
263                                 e.AddChild (PolicyStatement.PermissionSet.ToXml ());
264
265                         foreach (CodeGroup child in Children)
266                                 e.AddChild(child.ToXml());
267
268                         CreateXml(e, level);
269                         return e;
270                 }
271                 
272                 protected virtual void CreateXml(SecurityElement element, PolicyLevel level)
273                 {
274                 }
275
276                 // internal stuff
277
278                 internal static CodeGroup CreateFromXml (SecurityElement se) 
279                 {
280                         string fullClassName = se.Attribute ("class");
281                         string className = fullClassName;
282                         // many possible formats
283                         // a. "FirstMatchCodeGroup"
284                         // b. "System.Security.Policy.FirstMatchCodeGroup"
285                         // c. "System.Security.Policy.FirstMatchCodeGroup, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"\r\n           version=\"1\">\r\n   <IMembershipCondition class=\"System.Security.Policy.AllMembershipCondition, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
286                         int n = className.IndexOf (",");
287                         if (n > 0) {
288                                 className = className.Substring (0, n);
289                         }
290                         n = className.LastIndexOf (".");
291                         if (n > 0)
292                                 className = className.Substring (n + 1);
293                         // much faster than calling Activator.CreateInstance
294                         switch (className) {
295                                 case "FileCodeGroup":
296                                         return new FileCodeGroup (se);
297                                 case "FirstMatchCodeGroup":
298                                         return new FirstMatchCodeGroup (se);
299                                 case "NetCodeGroup":
300                                         return new NetCodeGroup (se);
301                                 case "UnionCodeGroup":
302                                         return new UnionCodeGroup (se);
303                                 default: // unknown
304                                         Type classType = Type.GetType (fullClassName);
305                                         return (CodeGroup) Activator.CreateInstance (classType, true);
306                         }
307                 }
308         }  // public abstract class CodeGroup
309 }  // namespace System.Security.Policy