//
// System.Data.Common.DbDataPermission.cs
//
// Authors:
// Rodrigo Moya (rodrigo@ximian.com)
// Tim Coleman (tim@timcoleman.com)
// Sebastien Pouliot <sebastien@ximian.com>
//
// (C) Ximian, Inc
// Copyright (C) Tim Coleman, 2002-2003
// Copyright (C) 2004 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
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.Collections;
using System.Security;
using System.Security.Permissions;
namespace System.Data.Common{
[Serializable]
public abstract class DBDataPermission : CodeAccessPermission, IUnrestrictedPermission {
#region Fields
private const int version = 1;
private bool allowBlankPassword;
private PermissionState state;
private Hashtable _connections;
#endregion // Fields
#region Constructors
#if NET_2_0
[Obsolete ("use DBDataPermission (PermissionState.None)", true)]
#endif
protected DBDataPermission ()
: this (PermissionState.None)
{
}
protected DBDataPermission (DBDataPermission permission)
{
if (permission == null)
throw new ArgumentNullException ("permission");
state = permission.state;
if (state != PermissionState.Unrestricted) {
allowBlankPassword = permission.allowBlankPassword;
_connections = (Hashtable) permission._connections.Clone ();
}
}
protected DBDataPermission (DBDataPermissionAttribute permissionAttribute)
{
if (permissionAttribute == null)
throw new ArgumentNullException ("permissionAttribute");
_connections = new Hashtable ();
if (permissionAttribute.Unrestricted) {
state = PermissionState.Unrestricted;
}
else {
state = PermissionState.None;
allowBlankPassword = permissionAttribute.AllowBlankPassword;
if (permissionAttribute.ConnectionString.Length > 0) {
Add (permissionAttribute.ConnectionString, permissionAttribute.KeyRestrictions,
permissionAttribute.KeyRestrictionBehavior);
}
}
}
protected DBDataPermission (PermissionState state)
{
this.state = PermissionHelper.CheckPermissionState (state, true);
_connections = new Hashtable ();
}
#if NET_2_0
[Obsolete ("use DBDataPermission (PermissionState.None)", true)]
protected
#else
public
#endif
DBDataPermission (PermissionState state, bool allowBlankPassword)
: this (state)
{
this.allowBlankPassword = allowBlankPassword;
}
#endregion // Constructors
#region Properties
public bool AllowBlankPassword {
get { return allowBlankPassword; }
set { allowBlankPassword = value; }
}
#endregion // Properties
#region Methods
public virtual void Add (string connectionString, string restrictions, KeyRestrictionBehavior behavior)
{
state = PermissionState.None;
_connections [connectionString] = new object [2] { restrictions, behavior };
}
protected void Clear ()
{
_connections.Clear ();
}
public override IPermission Copy ()
{
DBDataPermission dbdp = CreateInstance ();
dbdp.allowBlankPassword = this.allowBlankPassword;
dbdp._connections = (Hashtable) this._connections.Clone ();
return dbdp;
}
protected virtual DBDataPermission CreateInstance ()
{
return (DBDataPermission) Activator.CreateInstance (this.GetType (), new object [1] { PermissionState.None });
}
public override void FromXml (SecurityElement securityElement)
{
PermissionHelper.CheckSecurityElement (securityElement, "securityElement", version, version);
// Note: we do not (yet) care about the return value
// as we only accept version 1 (min/max values)
state = (PermissionHelper.IsUnrestricted (securityElement) ?
PermissionState.Unrestricted : PermissionState.None);
allowBlankPassword = false;
string blank = securityElement.Attribute ("AllowBlankPassword");
if (blank != null) {
#if NET_2_0
// avoid possible exceptions with Fx 2.0
if (!Boolean.TryParse (blank, out allowBlankPassword))
allowBlankPassword = false;
#else
try {
allowBlankPassword = Boolean.Parse (blank);
}
catch {
allowBlankPassword = false;
}
#endif
}
if (securityElement.Children != null) {
foreach (SecurityElement child in securityElement.Children) {
string connect = child.Attribute ("ConnectionString");
string restricts = child.Attribute ("KeyRestrictions");
KeyRestrictionBehavior behavior = (KeyRestrictionBehavior) Enum.Parse (
typeof (KeyRestrictionBehavior), child.Attribute ("KeyRestrictionBehavior"));
if ((connect != null) && (connect.Length > 0))
Add (connect, restricts, behavior);
}
}
}
public override IPermission Intersect (IPermission target)
{
// FIXME: restrictions not completely implemented - nor documented
DBDataPermission dbdp = Cast (target);
if (dbdp == null)
return null;
if (IsUnrestricted ()) {
if (dbdp.IsUnrestricted ()) {
DBDataPermission u = CreateInstance ();
u.state = PermissionState.Unrestricted;
return u;
}
return dbdp.Copy ();
}
if (dbdp.IsUnrestricted ())
return Copy ();
if (IsEmpty () || dbdp.IsEmpty ())
return null;
DBDataPermission p = CreateInstance ();
p.allowBlankPassword = (allowBlankPassword && dbdp.allowBlankPassword);
foreach (DictionaryEntry de in _connections) {
object o = dbdp._connections [de.Key];
if (o != null)
p._connections.Add (de.Key, de.Value);
}
return (p._connections.Count > 0) ? p : null;
}
public override bool IsSubsetOf (IPermission target)
{
// FIXME: restrictions not completely implemented - nor documented
DBDataPermission dbdp = Cast (target);
if (dbdp == null)
return IsEmpty ();
if (dbdp.IsUnrestricted ())
return true;
if (IsUnrestricted ())
return dbdp.IsUnrestricted ();
if (allowBlankPassword && !dbdp.allowBlankPassword)
return false;
if (_connections.Count > dbdp._connections.Count)
return false;
foreach (DictionaryEntry de in _connections) {
object o = dbdp._connections [de.Key];
if (o == null)
return false;
// FIXME: this is a subset of what is required
// it seems that we must process both the connect string
// and the restrictions - but this has other effects :-/
}
return true;
}
public bool IsUnrestricted ()
{
return (state == PermissionState.Unrestricted);
}
public override SecurityElement ToXml ()
{
SecurityElement se = PermissionHelper.Element (this.GetType (), version);
if (IsUnrestricted ()) {
se.AddAttribute ("Unrestricted", "true");
}
else {
// attribute is present for both True and False
se.AddAttribute ("AllowBlankPassword", allowBlankPassword.ToString ());
foreach (DictionaryEntry de in _connections) {
SecurityElement child = new SecurityElement ("add");
child.AddAttribute ("ConnectionString", (string) de.Key);
object[] restrictionsInfo = (object[]) de.Value;
child.AddAttribute ("KeyRestrictions", (string) restrictionsInfo [0]);
KeyRestrictionBehavior krb = (KeyRestrictionBehavior) restrictionsInfo [1];
child.AddAttribute ("KeyRestrictionBehavior", krb.ToString ());
se.AddChild (child);
}
}
return se;
}
public override IPermission Union (IPermission target)
{
// FIXME: restrictions not completely implemented - nor documented
DBDataPermission dbdp = Cast (target);
if (dbdp == null)
return Copy ();
if (IsEmpty () && dbdp.IsEmpty ())
return Copy ();
DBDataPermission p = CreateInstance ();
if (IsUnrestricted () || dbdp.IsUnrestricted ()) {
p.state = PermissionState.Unrestricted;
}
else {
p.allowBlankPassword = (allowBlankPassword || dbdp.allowBlankPassword);
p._connections = new Hashtable (_connections.Count + dbdp._connections.Count);
foreach (DictionaryEntry de in _connections)
p._connections.Add (de.Key, de.Value);
// don't duplicate
foreach (DictionaryEntry de in dbdp._connections)
p._connections [de.Key] = de.Value;
}
return p;
}
// helpers
private bool IsEmpty ()
{
return ((state != PermissionState.Unrestricted) && (_connections.Count == 0));
}
private DBDataPermission Cast (IPermission target)
{
if (target == null)
return null;
DBDataPermission dbdp = (target as DBDataPermission);
if (dbdp == null) {
PermissionHelper.ThrowInvalidPermission (target, this.GetType ());
}
return dbdp;
}
#endregion // Methods
}
}
|