// System.Security.Permissions.PrincipalPermission.cs
//
// Author
-// Sebastien Pouliot <spouliot@motus.com>
+// Sebastien Pouliot <sebastien@ximian.com>
//
// Copyright (C) 2003 Motus Technologies. http://www.motus.com
-//
-
-//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System;
using System.Collections;
+using System.Runtime.InteropServices;
using System.Security.Principal;
-using System.Text;
using System.Threading;
namespace System.Security.Permissions {
+ [ComVisible (true)]
[Serializable]
public sealed class PrincipalPermission : IPermission, IUnrestrictedPermission, IBuiltInPermission {
+ private const int version = 1;
+
internal class PrincipalInfo {
private string _name;
private string _role;
private bool _isAuthenticated;
- public PrincipalInfo (string name, string role, bool isAuthenticated) {
+ public PrincipalInfo (string name, string role, bool isAuthenticated)
+ {
_name = name;
_role = role;
_isAuthenticated = isAuthenticated;
public PrincipalPermission (PermissionState state)
{
principals = new ArrayList ();
- switch (state) {
- case PermissionState.None:
- break;
- case PermissionState.Unrestricted:
- PrincipalInfo pi = new PrincipalInfo (null, null, true);
- principals.Add (pi);
- break;
- default:
- throw new ArgumentException ("unknown PermissionState");
+ if (CodeAccessPermission.CheckPermissionState (state, true) == PermissionState.Unrestricted) {
+ PrincipalInfo pi = new PrincipalInfo (null, null, true);
+ principals.Add (pi);
}
}
}
if (!demand)
- throw new SecurityException ("invalid Principal");
+ throw new SecurityException ("Demand for principal refused.");
}
}
- public void FromXml (SecurityElement esd)
+ public void FromXml (SecurityElement elem)
{
- if (esd == null)
- throw new ArgumentNullException ("esd");
- if (esd.Tag != "IPermission")
- throw new ArgumentException ("not IPermission");
- if (!(esd.Attributes ["class"] as string).StartsWith ("System.Security.Permissions.PrincipalPermission"))
- throw new ArgumentException ("not PrincipalPermission");
- if ((esd.Attributes ["version"] as string) != "1")
- throw new ArgumentException ("wrong version");
+ // General validation in CodeAccessPermission
+ CheckSecurityElement (elem, "elem", version, version);
+ // Note: we do not (yet) care about the return value
+ // as we only accept version 1 (min/max values)
principals.Clear ();
// Children is null, not empty, when no child is present
- if (esd.Children != null) {
- foreach (SecurityElement se in esd.Children) {
+ if (elem.Children != null) {
+ foreach (SecurityElement se in elem.Children) {
if (se.Tag != "Identity")
throw new ArgumentException ("not IPermission/Identity");
- string name = (se.Attributes ["Name"] as string);
- string role = (se.Attributes ["Role"] as string);
- bool isAuthenticated = ((se.Attributes ["Authenticated"] as string) == "true");
+ string name = se.Attribute ("ID");
+ string role = se.Attribute ("Role");
+ string auth = se.Attribute ("Authenticated");
+ bool isAuthenticated = false;
+ if (auth != null) {
+ try {
+ isAuthenticated = Boolean.Parse (auth);
+ }
+ catch {}
+ }
PrincipalInfo pi = new PrincipalInfo (name, role, isAuthenticated);
principals.Add (pi);
}
public IPermission Intersect (IPermission target)
{
- if (target == null)
+ PrincipalPermission pp = Cast (target);
+ if (pp == null)
return null;
- if (! (target is PrincipalPermission))
- throw new ArgumentException ("wrong type");
- PrincipalPermission o = (PrincipalPermission) target;
if (IsUnrestricted ())
- return o.Copy ();
- if (o.IsUnrestricted ())
+ return pp.Copy ();
+ if (pp.IsUnrestricted ())
return Copy ();
PrincipalPermission intersect = new PrincipalPermission (PermissionState.None);
foreach (PrincipalInfo pi in principals) {
- foreach (PrincipalInfo opi in o.principals) {
+ foreach (PrincipalInfo opi in pp.principals) {
if (pi.IsAuthenticated == opi.IsAuthenticated) {
string name = null;
if ((pi.Name == opi.Name) || (opi.Name == null))
name = pi.Name;
+ else if (pi.Name == null)
+ name = opi.Name;
string role = null;
if ((pi.Role == opi.Role) || (opi.Role == null))
role = pi.Role;
+ else if (pi.Role == null)
+ role = opi.Role;
if ((name != null) || (role != null)) {
PrincipalInfo ipi = new PrincipalInfo (name, role, pi.IsAuthenticated);
intersect.principals.Add (ipi);
public bool IsSubsetOf (IPermission target)
{
- if (target == null)
- return false;
+ PrincipalPermission pp = Cast (target);
+ if (pp == null)
+ return IsEmpty ();
- if (! (target is PrincipalPermission))
- throw new ArgumentException ("wrong type");
-
- PrincipalPermission o = (PrincipalPermission) target;
if (IsUnrestricted ())
- return o.IsUnrestricted ();
- else if (o.IsUnrestricted ())
+ return pp.IsUnrestricted ();
+ else if (pp.IsUnrestricted ())
return true;
// each must be a subset of the target
foreach (PrincipalInfo pi in principals) {
bool thisItem = false;
- foreach (PrincipalInfo opi in o.principals) {
+ foreach (PrincipalInfo opi in pp.principals) {
if (((pi.Name == opi.Name) || (opi.Name == null)) &&
((pi.Role == opi.Role) || (opi.Role == null)) &&
(pi.IsAuthenticated == opi.IsAuthenticated))
public SecurityElement ToXml ()
{
- SecurityElement se = new SecurityElement ("IPermission");
+ SecurityElement se = new SecurityElement ("Permission");
Type type = this.GetType ();
- StringBuilder asmName = new StringBuilder (type.Assembly.ToString ());
- asmName.Replace ('\"', '\'');
- se.AddAttribute ("class", type.FullName + ", " + asmName);
- se.AddAttribute ("version", "1");
+ se.AddAttribute ("class", type.FullName + ", " + type.Assembly.ToString ().Replace ('\"', '\''));
+ se.AddAttribute ("version", version.ToString ());
+
foreach (PrincipalInfo pi in principals) {
SecurityElement sec = new SecurityElement ("Identity");
if (pi.Name != null)
- sec.AddAttribute ("Name", pi.Name);
+ sec.AddAttribute ("ID", pi.Name);
if (pi.Role != null)
sec.AddAttribute ("Role", pi.Role);
if (pi.IsAuthenticated)
return se;
}
- public IPermission Union (IPermission target)
+ public IPermission Union (IPermission other)
{
- if (target == null)
+ PrincipalPermission pp = Cast (other);
+ if (pp == null)
return Copy ();
- if (! (target is PrincipalPermission))
- throw new ArgumentException ("wrong type");
- PrincipalPermission o = (PrincipalPermission) target;
- if (IsUnrestricted () || o.IsUnrestricted ())
+ if (IsUnrestricted () || pp.IsUnrestricted ())
return new PrincipalPermission (PermissionState.Unrestricted);
PrincipalPermission union = new PrincipalPermission (principals);
- foreach (PrincipalInfo pi in o.principals)
+ foreach (PrincipalInfo pi in pp.principals)
union.principals.Add (pi);
return union;
}
+ [ComVisible (false)]
+ public override bool Equals (object obj)
+ {
+ if (obj == null)
+ return false;
+
+ PrincipalPermission pp = (obj as PrincipalPermission);
+ if (pp == null)
+ return false;
+
+ // same number of principals ?
+ if (principals.Count != pp.principals.Count)
+ return false;
+
+ // then all principals in "this" should be in "pp"
+ foreach (PrincipalInfo pi in principals) {
+ bool thisItem = false;
+ foreach (PrincipalInfo opi in pp.principals) {
+ if (((pi.Name == opi.Name) || (opi.Name == null)) &&
+ ((pi.Role == opi.Role) || (opi.Role == null)) &&
+ (pi.IsAuthenticated == opi.IsAuthenticated)) {
+ thisItem = true;
+ break;
+ }
+ }
+ if (!thisItem)
+ return false;
+ }
+ return true;
+ }
+
+ // according to documentation (fx 2.0 beta 1) we can have
+ // different hash code even if both a Equals
+ [ComVisible (false)]
+ public override int GetHashCode ()
+ {
+ return base.GetHashCode ();
+ }
+
// IBuiltInPermission
int IBuiltInPermission.GetTokenIndex ()
{
- return 8;
+ return (int) BuiltInToken.Principal;
+ }
+
+ // helpers
+
+ private PrincipalPermission Cast (IPermission target)
+ {
+ if (target == null)
+ return null;
+
+ PrincipalPermission pp = (target as PrincipalPermission);
+ if (pp == null) {
+ CodeAccessPermission.ThrowInvalidPermission (target, typeof (PrincipalPermission));
+ }
+
+ return pp;
+ }
+
+ private bool IsEmpty ()
+ {
+ return (principals.Count == 0);
+ }
+
+ // Normally permissions tags are "IPermission" but this (non-CAS) permission use "Permission"
+ internal int CheckSecurityElement (SecurityElement se, string parameterName, int minimumVersion, int maximumVersion)
+ {
+ if (se == null)
+ throw new ArgumentNullException (parameterName);
+
+ // Tag is case-sensitive
+ if (se.Tag != "Permission") {
+ string msg = String.Format (Locale.GetText ("Invalid tag {0}"), se.Tag);
+ throw new ArgumentException (msg, parameterName);
+ }
+
+ // Note: we do not care about the class attribute at
+ // this stage (in fact we don't even if the class
+ // attribute is present or not). Anyway the object has
+ // already be created, with success, if we're loading it
+
+ // we assume minimum version if no version number is supplied
+ int version = minimumVersion;
+ string v = se.Attribute ("version");
+ if (v != null) {
+ try {
+ version = Int32.Parse (v);
+ }
+ catch (Exception e) {
+ string msg = Locale.GetText ("Couldn't parse version from '{0}'.");
+ msg = String.Format (msg, v);
+ throw new ArgumentException (msg, parameterName, e);
+ }
+ }
+
+ if ((version < minimumVersion) || (version > maximumVersion)) {
+ string msg = Locale.GetText ("Unknown version '{0}', expected versions between ['{1}','{2}'].");
+ msg = String.Format (msg, version, minimumVersion, maximumVersion);
+ throw new ArgumentException (msg, parameterName);
+ }
+ return version;
}
}
}