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. 28 // 29 30 using System.Collections; 31 using System.Runtime.InteropServices; 32 using System.Security.Principal; 33 using System.Threading; 34 35 namespace System.Security.Permissions { 36 37 [ComVisible (true)] 38 [Serializable] 39 public sealed class PrincipalPermission : IPermission, IUnrestrictedPermission, IBuiltInPermission { 40 41 private const int version = 1; 42 43 internal class PrincipalInfo { 44 45 private string _name; 46 private string _role; 47 private bool _isAuthenticated; 48 PrincipalInfo(string name, string role, bool isAuthenticated)49 public PrincipalInfo (string name, string role, bool isAuthenticated) 50 { 51 _name = name; 52 _role = role; 53 _isAuthenticated = isAuthenticated; 54 } 55 56 public string Name { 57 get { return _name; } 58 } 59 60 public string Role { 61 get { return _role; } 62 } 63 64 public bool IsAuthenticated { 65 get { return _isAuthenticated; } 66 } 67 } 68 69 private ArrayList principals; 70 71 // Constructors 72 PrincipalPermission(PermissionState state)73 public PrincipalPermission (PermissionState state) 74 { 75 principals = new ArrayList (); 76 if (CodeAccessPermission.CheckPermissionState (state, true) == PermissionState.Unrestricted) { 77 PrincipalInfo pi = new PrincipalInfo (null, null, true); 78 principals.Add (pi); 79 } 80 } 81 PrincipalPermission(string name, string role)82 public PrincipalPermission (string name, string role) : this (name, role, true) 83 { 84 } 85 PrincipalPermission(string name, string role, bool isAuthenticated)86 public PrincipalPermission (string name, string role, bool isAuthenticated) 87 { 88 principals = new ArrayList (); 89 PrincipalInfo pi = new PrincipalInfo (name, role, isAuthenticated); 90 principals.Add (pi); 91 } 92 PrincipalPermission(ArrayList principals)93 internal PrincipalPermission (ArrayList principals) 94 { 95 this.principals = (ArrayList) principals.Clone (); 96 } 97 98 // Properties 99 100 // Methods 101 Copy()102 public IPermission Copy () 103 { 104 return new PrincipalPermission (principals); 105 } 106 Demand()107 public void Demand () 108 { 109 IPrincipal p = Thread.CurrentPrincipal; 110 if (p == null) 111 throw new SecurityException ("no Principal"); 112 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; 125 } 126 } 127 128 if (!demand) 129 throw new SecurityException ("Demand for principal refused."); 130 } 131 } 132 FromXml(SecurityElement elem)133 public void FromXml (SecurityElement elem) 134 { 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) 139 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); 153 } 154 catch {} 155 } 156 PrincipalInfo pi = new PrincipalInfo (name, role, isAuthenticated); 157 principals.Add (pi); 158 } 159 } 160 } 161 Intersect(IPermission target)162 public IPermission Intersect (IPermission target) 163 { 164 PrincipalPermission pp = Cast (target); 165 if (pp == null) 166 return null; 167 168 if (IsUnrestricted ()) 169 return pp.Copy (); 170 if (pp.IsUnrestricted ()) 171 return Copy (); 172 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); 190 } 191 } 192 } 193 } 194 195 return ((intersect.principals.Count > 0) ? intersect : null); 196 } 197 IsSubsetOf(IPermission target)198 public bool IsSubsetOf (IPermission target) 199 { 200 PrincipalPermission pp = Cast (target); 201 if (pp == null) 202 return IsEmpty (); 203 204 if (IsUnrestricted ()) 205 return pp.IsUnrestricted (); 206 else if (pp.IsUnrestricted ()) 207 return true; 208 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; 217 } 218 if (!thisItem) 219 return false; 220 } 221 222 return true; 223 } 224 IsUnrestricted()225 public bool IsUnrestricted () 226 { 227 foreach (PrincipalInfo pi in principals) { 228 if ((pi.Name == null) && (pi.Role == null) && (pi.IsAuthenticated)) 229 return true; 230 } 231 return false; 232 } 233 ToString()234 public override string ToString () 235 { 236 return ToXml ().ToString (); 237 } 238 ToXml()239 public SecurityElement ToXml () 240 { 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 ()); 245 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); 255 } 256 return se; 257 } 258 Union(IPermission other)259 public IPermission Union (IPermission other) 260 { 261 PrincipalPermission pp = Cast (other); 262 if (pp == null) 263 return Copy (); 264 265 if (IsUnrestricted () || pp.IsUnrestricted ()) 266 return new PrincipalPermission (PermissionState.Unrestricted); 267 268 PrincipalPermission union = new PrincipalPermission (principals); 269 foreach (PrincipalInfo pi in pp.principals) 270 union.principals.Add (pi); 271 272 return union; 273 } 274 275 [ComVisible (false)] Equals(object obj)276 public override bool Equals (object obj) 277 { 278 if (obj == null) 279 return false; 280 281 PrincipalPermission pp = (obj as PrincipalPermission); 282 if (pp == null) 283 return false; 284 285 // same number of principals ? 286 if (principals.Count != pp.principals.Count) 287 return false; 288 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; 298 } 299 } 300 if (!thisItem) 301 return false; 302 } 303 return true; 304 } 305 306 // according to documentation (fx 2.0 beta 1) we can have 307 // different hash code even if both a Equals 308 [ComVisible (false)] GetHashCode()309 public override int GetHashCode () 310 { 311 return base.GetHashCode (); 312 } 313 314 // IBuiltInPermission IBuiltInPermission.GetTokenIndex()315 int IBuiltInPermission.GetTokenIndex () 316 { 317 return (int) BuiltInToken.Principal; 318 } 319 320 // helpers 321 Cast(IPermission target)322 private PrincipalPermission Cast (IPermission target) 323 { 324 if (target == null) 325 return null; 326 327 PrincipalPermission pp = (target as PrincipalPermission); 328 if (pp == null) { 329 CodeAccessPermission.ThrowInvalidPermission (target, typeof (PrincipalPermission)); 330 } 331 332 return pp; 333 } 334 IsEmpty()335 private bool IsEmpty () 336 { 337 return (principals.Count == 0); 338 } 339 340 // Normally permissions tags are "IPermission" but this (non-CAS) permission use "Permission" CheckSecurityElement(SecurityElement se, string parameterName, int minimumVersion, int maximumVersion)341 internal int CheckSecurityElement (SecurityElement se, string parameterName, int minimumVersion, int maximumVersion) 342 { 343 if (se == null) 344 throw new ArgumentNullException (parameterName); 345 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); 350 } 351 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 356 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); 363 } 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); 368 } 369 } 370 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); 375 } 376 return version; 377 } 378 } 379 } 380