using System;
using System.Collections.Generic;
using System.Text;
namespace ScrewTurn.Wiki.AclEngine {
///
/// Implements a base class for an ACL Manager.
///
/// All instance and static members are thread-safe.
public abstract class AclManagerBase : IAclManager {
private List entries;
///
/// Initializes a new instance of the abstract class.
///
public AclManagerBase() {
entries = new List(100);
}
///
/// Handles the invokation of event.
///
/// The changed entries.
/// The change.
protected void OnAclChanged(AclEntry[] entries, Change change) {
if(AclChanged != null) {
AclChanged(this, new AclChangedEventArgs(entries, change));
}
}
///
/// Stores a new ACL entry.
///
/// The controlled resource.
/// The action on the controlled resource.
/// The subject whose access to the resource/action is controlled.
/// The value of the entry.
/// true if the entry is stored, false otherwise.
/// If , or are null.
/// If , or are empty.
public bool StoreEntry(string resource, string action, string subject, Value value) {
if(resource == null) throw new ArgumentNullException("resource");
if(resource.Length == 0) throw new ArgumentException("Resource cannot be empty", "resource");
if(action == null) throw new ArgumentNullException("action");
if(action.Length == 0) throw new ArgumentException("Action cannot be empty", "action");
if(subject == null) throw new ArgumentNullException("subject");
if(subject.Length == 0) throw new ArgumentException("Subject cannot be empty", "subject");
AclEntry result = new AclEntry(resource, action, subject, value);
lock(this) {
int index = entries.FindIndex(delegate(AclEntry x) { return AclEntry.Equals(x, result); });
if(index >= 0) {
AclEntry removed = entries[index];
entries.RemoveAt(index);
OnAclChanged(new AclEntry[] { removed }, Change.EntryDeleted);
}
entries.Add(result);
OnAclChanged(new AclEntry[] { result }, Change.EntryStored);
}
return true;
}
///
/// Deletes an ACL entry.
///
/// The controlled resource.
/// The action on the controlled resource.
/// The subject whose access to the resource/action is controlled.
/// true if the entry is deleted, false otherwise.
/// If , or are null.
/// If , or are empty.
public bool DeleteEntry(string resource, string action, string subject) {
if(resource == null) throw new ArgumentNullException("resource");
if(resource.Length == 0) throw new ArgumentException("Resource cannot be empty", "resource");
if(action == null) throw new ArgumentNullException("action");
if(action.Length == 0) throw new ArgumentException("Action cannot be empty", "action");
if(subject == null) throw new ArgumentNullException("subject");
if(subject.Length == 0) throw new ArgumentException("Subject cannot be empty", "subject");
AclEntry result = new AclEntry(resource, action, subject, Value.Deny);
lock(this) {
int index = entries.FindIndex(delegate(AclEntry x) { return AclEntry.Equals(x, result); });
if(index >= 0) {
AclEntry entry = entries[index];
entries.RemoveAt(index);
OnAclChanged(new AclEntry[] { entry }, Change.EntryDeleted);
return true;
}
else return false;
}
}
///
/// Deletes all the ACL entries for a resource.
///
/// The controlled resource.
/// true if the entries are deleted, false otherwise.
/// If is null.
/// If is empty.
public bool DeleteEntriesForResource(string resource) {
if(resource == null) throw new ArgumentNullException("resource");
if(resource.Length == 0) throw new ArgumentException("Resource cannot be empty", "resource");
lock(this) {
List indexesToRemove = new List(30);
List entriesToRemove = new List(30);
for(int i = 0; i < entries.Count; i++) {
if(entries[i].Resource == resource) {
indexesToRemove.Add(i);
entriesToRemove.Add(entries[i]);
}
}
if(indexesToRemove.Count > 0) {
// Work in opposite direction to preserve smaller indexes
for(int i = indexesToRemove.Count - 1; i >= 0; i--) {
entries.RemoveAt(indexesToRemove[i]);
}
OnAclChanged(entriesToRemove.ToArray(), Change.EntryDeleted);
return true;
}
else return false;
}
}
///
/// Deletes all the ACL entries for a subject.
///
/// The subject.
/// true if the entries are deleted, false otherwise.
/// If is null.
/// If is empty.
public bool DeleteEntriesForSubject(string subject) {
if(subject == null) throw new ArgumentNullException("subject");
if(subject.Length == 0) throw new ArgumentException("Subject cannot be empty", "subject");
lock(this) {
List indexesToRemove = new List(30);
List entriesToRemove = new List(30);
for(int i = 0; i < entries.Count; i++) {
if(entries[i].Subject == subject) {
indexesToRemove.Add(i);
entriesToRemove.Add(entries[i]);
}
}
if(indexesToRemove.Count > 0) {
// Work in opposite direction to preserve smaller indexes
for(int i = indexesToRemove.Count - 1; i >= 0; i--) {
entries.RemoveAt(indexesToRemove[i]);
}
OnAclChanged(entriesToRemove.ToArray(), Change.EntryDeleted);
return true;
}
else return false;
}
}
///
/// Renames a resource.
///
/// The resource.
/// The new name of the resource.
/// true if the resource is renamed, false otherwise.
/// If or are null.
/// If or are empty.
public bool RenameResource(string resource, string newName) {
if(resource == null) throw new ArgumentNullException("resource");
if(resource.Length == 0) throw new ArgumentException("Resource cannot be empty", "resource");
if(newName == null) throw new ArgumentNullException("newName");
if(newName.Length == 0) throw new ArgumentException("New Name cannot be empty", "newName");
lock(this) {
AclEntry[] entries = RetrieveEntriesForResource(resource);
bool renamed = false;
foreach(AclEntry entry in entries) {
bool deleted = DeleteEntry(entry.Resource, entry.Action, entry.Subject);
if(deleted) {
bool stored = StoreEntry(newName, entry.Action, entry.Subject, entry.Value);
if(stored) renamed = true;
else return false;
}
else return false;
}
return renamed;
}
}
///
/// Retrieves all the ACL entries for a resource.
///
/// The entries.
public AclEntry[] RetrieveAllEntries() {
lock(this) {
return entries.ToArray();
}
}
///
/// Retrieves all the ACL entries for a resource.
///
/// The resource.
/// The entries.
/// If is null.
/// If is empty.
public AclEntry[] RetrieveEntriesForResource(string resource) {
if(resource == null) throw new ArgumentNullException("resource");
if(resource.Length == 0) throw new ArgumentException("Resource cannot be empty", "resource");
lock(this) {
List result = new List(10);
foreach(AclEntry e in entries) {
if(e.Resource == resource) result.Add(e);
}
return result.ToArray();
}
}
///
/// Retrieves all the ACL entries for a subject.
///
/// The subject.
/// The entries.
/// If is null.
/// If is empty.
public AclEntry[] RetrieveEntriesForSubject(string subject) {
if(subject == null) throw new ArgumentNullException("subject");
if(subject.Length == 0) throw new ArgumentException("Subject cannot be empty", "subject");
lock(this) {
List result = new List(10);
foreach(AclEntry e in entries) {
if(e.Subject == subject) result.Add(e);
}
return result.ToArray();
}
}
///
/// Initializes the manager data.
///
/// The ACL entries.
/// If is null.
public void InitializeData(AclEntry[] entries) {
if(entries == null) throw new ArgumentNullException("entries");
lock(this) {
this.entries = new List(entries);
}
}
///
/// Gets the total number of ACL entries.
///
public int TotalEntries {
get {
lock(this) {
return entries.Count;
}
}
}
///
/// Event fired when an ACL entry is stored or deleted.
///
public event EventHandler AclChanged;
}
}