GenericParameter.cs: override Module properly
[mcs.git] / class / corlib / System.Security.Permissions / PrincipalPermission.cs
blob5052eef0b07e37cbdbfb7a7131c5931c07377970
1 //
2 // System.Security.Permissions.PrincipalPermission.cs
3 //
4 // Author
5 // Sebastien Pouliot <sebastien@ximian.com>
6 //
7 // Copyright (C) 2003 Motus Technologies. http://www.motus.com
8 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections;
31 using System.Runtime.InteropServices;
32 using System.Security.Principal;
33 using System.Threading;
35 namespace System.Security.Permissions {
37 [ComVisible (true)]
38 [Serializable]
39 public sealed class PrincipalPermission : IPermission, IUnrestrictedPermission, IBuiltInPermission {
41 private const int version = 1;
43 internal class PrincipalInfo {
45 private string _name;
46 private string _role;
47 private bool _isAuthenticated;
49 public PrincipalInfo (string name, string role, bool isAuthenticated)
51 _name = name;
52 _role = role;
53 _isAuthenticated = isAuthenticated;
56 public string Name {
57 get { return _name; }
60 public string Role {
61 get { return _role; }
64 public bool IsAuthenticated {
65 get { return _isAuthenticated; }
69 private ArrayList principals;
71 // Constructors
73 public PrincipalPermission (PermissionState state)
75 principals = new ArrayList ();
76 if (CodeAccessPermission.CheckPermissionState (state, true) == PermissionState.Unrestricted) {
77 PrincipalInfo pi = new PrincipalInfo (null, null, true);
78 principals.Add (pi);
82 public PrincipalPermission (string name, string role) : this (name, role, true)
86 public PrincipalPermission (string name, string role, bool isAuthenticated)
88 principals = new ArrayList ();
89 PrincipalInfo pi = new PrincipalInfo (name, role, isAuthenticated);
90 principals.Add (pi);
93 internal PrincipalPermission (ArrayList principals)
95 this.principals = (ArrayList) principals.Clone ();
98 // Properties
100 // Methods
102 public IPermission Copy ()
104 return new PrincipalPermission (principals);
107 public void Demand ()
109 IPrincipal p = Thread.CurrentPrincipal;
110 if (p == null)
111 throw new SecurityException ("no Principal");
113 if (principals.Count > 0) {
114 // check restrictions
115 bool demand = false;
116 foreach (PrincipalInfo pi in principals) {
117 // if a name is present then it must be equal
118 // if a role is present then the identity must be a member of this role
119 // if authentication is required then the identity must be authenticated
120 if (((pi.Name == null) || (pi.Name == p.Identity.Name)) &&
121 ((pi.Role == null) || (p.IsInRole (pi.Role))) &&
122 ((pi.IsAuthenticated && p.Identity.IsAuthenticated) || (!pi.IsAuthenticated))) {
123 demand = true;
124 break;
128 if (!demand)
129 throw new SecurityException ("Demand for principal refused.");
133 public void FromXml (SecurityElement elem)
135 // General validation in CodeAccessPermission
136 CheckSecurityElement (elem, "elem", version, version);
137 // Note: we do not (yet) care about the return value
138 // as we only accept version 1 (min/max values)
140 principals.Clear ();
141 // Children is null, not empty, when no child is present
142 if (elem.Children != null) {
143 foreach (SecurityElement se in elem.Children) {
144 if (se.Tag != "Identity")
145 throw new ArgumentException ("not IPermission/Identity");
146 string name = se.Attribute ("ID");
147 string role = se.Attribute ("Role");
148 string auth = se.Attribute ("Authenticated");
149 bool isAuthenticated = false;
150 if (auth != null) {
151 try {
152 isAuthenticated = Boolean.Parse (auth);
154 catch {}
156 PrincipalInfo pi = new PrincipalInfo (name, role, isAuthenticated);
157 principals.Add (pi);
162 public IPermission Intersect (IPermission target)
164 PrincipalPermission pp = Cast (target);
165 if (pp == null)
166 return null;
168 if (IsUnrestricted ())
169 return pp.Copy ();
170 if (pp.IsUnrestricted ())
171 return Copy ();
173 PrincipalPermission intersect = new PrincipalPermission (PermissionState.None);
174 foreach (PrincipalInfo pi in principals) {
175 foreach (PrincipalInfo opi in pp.principals) {
176 if (pi.IsAuthenticated == opi.IsAuthenticated) {
177 string name = null;
178 if ((pi.Name == opi.Name) || (opi.Name == null))
179 name = pi.Name;
180 else if (pi.Name == null)
181 name = opi.Name;
182 string role = null;
183 if ((pi.Role == opi.Role) || (opi.Role == null))
184 role = pi.Role;
185 else if (pi.Role == null)
186 role = opi.Role;
187 if ((name != null) || (role != null)) {
188 PrincipalInfo ipi = new PrincipalInfo (name, role, pi.IsAuthenticated);
189 intersect.principals.Add (ipi);
195 return ((intersect.principals.Count > 0) ? intersect : null);
198 public bool IsSubsetOf (IPermission target)
200 PrincipalPermission pp = Cast (target);
201 if (pp == null)
202 return IsEmpty ();
204 if (IsUnrestricted ())
205 return pp.IsUnrestricted ();
206 else if (pp.IsUnrestricted ())
207 return true;
209 // each must be a subset of the target
210 foreach (PrincipalInfo pi in principals) {
211 bool thisItem = false;
212 foreach (PrincipalInfo opi in pp.principals) {
213 if (((pi.Name == opi.Name) || (opi.Name == null)) &&
214 ((pi.Role == opi.Role) || (opi.Role == null)) &&
215 (pi.IsAuthenticated == opi.IsAuthenticated))
216 thisItem = true;
218 if (!thisItem)
219 return false;
222 return true;
225 public bool IsUnrestricted ()
227 foreach (PrincipalInfo pi in principals) {
228 if ((pi.Name == null) && (pi.Role == null) && (pi.IsAuthenticated))
229 return true;
231 return false;
234 public override string ToString ()
236 return ToXml ().ToString ();
239 public SecurityElement ToXml ()
241 SecurityElement se = new SecurityElement ("Permission");
242 Type type = this.GetType ();
243 se.AddAttribute ("class", type.FullName + ", " + type.Assembly.ToString ().Replace ('\"', '\''));
244 se.AddAttribute ("version", version.ToString ());
246 foreach (PrincipalInfo pi in principals) {
247 SecurityElement sec = new SecurityElement ("Identity");
248 if (pi.Name != null)
249 sec.AddAttribute ("ID", pi.Name);
250 if (pi.Role != null)
251 sec.AddAttribute ("Role", pi.Role);
252 if (pi.IsAuthenticated)
253 sec.AddAttribute ("Authenticated", "true");
254 se.AddChild (sec);
256 return se;
259 public IPermission Union (IPermission other)
261 PrincipalPermission pp = Cast (other);
262 if (pp == null)
263 return Copy ();
265 if (IsUnrestricted () || pp.IsUnrestricted ())
266 return new PrincipalPermission (PermissionState.Unrestricted);
268 PrincipalPermission union = new PrincipalPermission (principals);
269 foreach (PrincipalInfo pi in pp.principals)
270 union.principals.Add (pi);
272 return union;
275 [ComVisible (false)]
276 public override bool Equals (object obj)
278 if (obj == null)
279 return false;
281 PrincipalPermission pp = (obj as PrincipalPermission);
282 if (pp == null)
283 return false;
285 // same number of principals ?
286 if (principals.Count != pp.principals.Count)
287 return false;
289 // then all principals in "this" should be in "pp"
290 foreach (PrincipalInfo pi in principals) {
291 bool thisItem = false;
292 foreach (PrincipalInfo opi in pp.principals) {
293 if (((pi.Name == opi.Name) || (opi.Name == null)) &&
294 ((pi.Role == opi.Role) || (opi.Role == null)) &&
295 (pi.IsAuthenticated == opi.IsAuthenticated)) {
296 thisItem = true;
297 break;
300 if (!thisItem)
301 return false;
303 return true;
306 // according to documentation (fx 2.0 beta 1) we can have
307 // different hash code even if both a Equals
308 [ComVisible (false)]
309 public override int GetHashCode ()
311 return base.GetHashCode ();
314 // IBuiltInPermission
315 int IBuiltInPermission.GetTokenIndex ()
317 return (int) BuiltInToken.Principal;
320 // helpers
322 private PrincipalPermission Cast (IPermission target)
324 if (target == null)
325 return null;
327 PrincipalPermission pp = (target as PrincipalPermission);
328 if (pp == null) {
329 CodeAccessPermission.ThrowInvalidPermission (target, typeof (PrincipalPermission));
332 return pp;
335 private bool IsEmpty ()
337 return (principals.Count == 0);
340 // Normally permissions tags are "IPermission" but this (non-CAS) permission use "Permission"
341 internal int CheckSecurityElement (SecurityElement se, string parameterName, int minimumVersion, int maximumVersion)
343 if (se == null)
344 throw new ArgumentNullException (parameterName);
346 // Tag is case-sensitive
347 if (se.Tag != "Permission") {
348 string msg = String.Format (Locale.GetText ("Invalid tag {0}"), se.Tag);
349 throw new ArgumentException (msg, parameterName);
352 // Note: we do not care about the class attribute at
353 // this stage (in fact we don't even if the class
354 // attribute is present or not). Anyway the object has
355 // already be created, with success, if we're loading it
357 // we assume minimum version if no version number is supplied
358 int version = minimumVersion;
359 string v = se.Attribute ("version");
360 if (v != null) {
361 try {
362 version = Int32.Parse (v);
364 catch (Exception e) {
365 string msg = Locale.GetText ("Couldn't parse version from '{0}'.");
366 msg = String.Format (msg, v);
367 throw new ArgumentException (msg, parameterName, e);
371 if ((version < minimumVersion) || (version > maximumVersion)) {
372 string msg = Locale.GetText ("Unknown version '{0}', expected versions between ['{1}','{2}'].");
373 msg = String.Format (msg, version, minimumVersion, maximumVersion);
374 throw new ArgumentException (msg, parameterName);
376 return version;