/// <summary> /// Deletes some entries. /// </summary> /// <param name="entries">The entries to delete.</param> protected override void DeleteEntries(AclEntry[] entries) { lock(this) { AclEntry[] allEntries = LoadDataInternal(); StringBuilder sb = new StringBuilder(10000); foreach(AclEntry originalEntry in allEntries) { // If the current entry is not contained in the entries array, then preserve it bool delete = false; foreach(AclEntry entryToDelete in entries) { if(AclEntry.Equals(originalEntry, entryToDelete)) { delete = true; break; } } if(!delete) { sb.Append(DumpAclEntry(originalEntry)); sb.Append("\r\n"); } } File.WriteAllText(file, sb.ToString()); } }
/// <summary> /// Initializes a new instance of the <see cref="T:AclChangedEventArgs" /> class. /// </summary> /// <param name="entries">The entries that changed.</param> /// <param name="change">The change.</param> /// <exception cref="ArgumentNullException">If <paramref name="entries"/> is <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="entries"/> is empty.</exception> public AclChangedEventArgs(AclEntry[] entries, Change change) { if(entries == null) throw new ArgumentNullException("entry"); if(entries.Length == 0) throw new ArgumentException("Entries cannot be empty", "entries"); this.entries = entries; this.change = change; }
/// <summary> /// Determines whether this instance equals another (by value). /// </summary> /// <param name="other">The other instance.</param> /// <returns><c>true</c> if this instance equals <b>other</b>, <c>false</c> otherwise.</returns> public bool Equals(AclEntry other) { if (ReferenceEquals(other, null)) { return(false); } return(resource == other.Resource && action == other.Action && subject == other.Subject); }
/// <summary> /// Stores a new ACL entry. /// </summary> /// <param name="resource">The controlled resource.</param> /// <param name="action">The action on the controlled resource.</param> /// <param name="subject">The subject whose access to the resource/action is controlled.</param> /// <param name="value">The value of the entry.</param> /// <returns><c>true</c> if the entry is stored, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <paramref name="resource"/>, <paramref name="action"/> or <paramref name="subject"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="resource"/>, <paramref name="action"/> or <paramref name="subject"/> are empty.</exception> 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 entry = new AclEntry(resource, action, subject, value); return _storeEntry(entry); }
/// <summary> /// Determines whether this object equals another (by value). /// </summary> /// <param name="obj">The other object.</param> /// <returns><c>true</c> if this object equals <b>obj</b>, <c>false</c> otherwise.</returns> public override bool Equals(object obj) { AclEntry other = obj as AclEntry; if (other != null) { return(Equals(other)); } else { return(false); } }
/// <summary> /// Deletes an ACL entry. /// </summary> /// <param name="resource">The controlled resource.</param> /// <param name="action">The action on the controlled resource.</param> /// <param name="subject">The subject whose access to the resource/action is controlled.</param> /// <returns><c>true</c> if the entry is deleted, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <paramref name="resource"/>, <paramref name="action"/> or <paramref name="subject"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="resource"/>, <paramref name="action"/> or <paramref name="subject"/> are empty.</exception> 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); } } }
/// <summary> /// Determines whether two instances of <see cref="T:AclEntry" /> are equal (by value). /// </summary> /// <param name="x">The first instance.</param> /// <param name="y">The second instance.</param> /// <returns><c>true</c> if <b>x</b> equals <b>y</b>, <c>false</c> otherwise.</returns> public static bool Equals(AclEntry x, AclEntry y) { if (object.ReferenceEquals(x, null) && !object.ReferenceEquals(x, null)) { return(false); } if (!object.ReferenceEquals(x, null) && object.ReferenceEquals(x, null)) { return(false); } if (object.ReferenceEquals(x, null) && object.ReferenceEquals(x, null)) { return(true); } return(x.Equals(y)); }
/// <summary> /// Stores a new ACL entry. /// </summary> /// <param name="resource">The controlled resource.</param> /// <param name="action">The action on the controlled resource.</param> /// <param name="subject">The subject whose access to the resource/action is controlled.</param> /// <param name="value">The value of the entry.</param> /// <returns><c>true</c> if the entry is stored, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException"> /// If <paramref name="resource" />, <paramref name="action" /> or /// <paramref name="subject" /> are <c>null</c>. /// </exception> /// <exception cref="ArgumentException"> /// If <paramref name="resource" />, <paramref name="action" /> or /// <paramref name="subject" /> are empty. /// </exception> 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"); } var result = new AclEntry(resource, action, subject, value); lock (this) { var index = entries.FindIndex(delegate(AclEntry x) { return(AclEntry.Equals(x, result)); }); if (index >= 0) { var removed = entries[index]; entries.RemoveAt(index); OnAclChanged(new[] { removed }, Change.EntryDeleted); } entries.Add(result); OnAclChanged(new[] { result }, Change.EntryStored); } return(true); }
/// <summary> /// Stores a ACL entry. /// </summary> /// <param name="entry">The entry to store.</param> /// <returns><c>true</c> if the entry was stored, <c>false</c> otherwise.</returns> private bool StoreEntry(AclEntry entry) { ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); AclEntry[] allAclEntries = RetrieveAllAclEntries(); for(int i=0;i<allAclEntries.Length;i++) { if(entry.Equals(allAclEntries[i])) return true; } string query = queryBuilder.InsertInto("AclEntry", new string[] { "Resource", "Action", "Subject", "Value" }, new string[] { "Resource", "Action", "Subject", "Value" }); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Resource", entry.Resource)); parameters.Add(new Parameter(ParameterType.String, "Action", entry.Action)); parameters.Add(new Parameter(ParameterType.String, "Subject", entry.Subject)); parameters.Add(new Parameter(ParameterType.Char, "Value", AclEntryValueToChar(entry.Value))); DbCommand command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false) != 1) { RollbackTransaction(transaction); return false; } CommitTransaction(transaction); return true; }
/// <summary> /// Deletes some ACL entries. /// </summary> /// <param name="entries">The entries to delete.</param> /// <returns><c>true</c> if one or more entries were deleted, <c>false</c> otherwise.</returns> private bool DeleteEntries(AclEntry[] entries) { ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); foreach(AclEntry entry in entries) { string query = queryBuilder.DeleteFrom("AclEntry"); query = queryBuilder.Where(query, "Resource", WhereOperator.Equals, "Resource"); query = queryBuilder.AndWhere(query, "Action", WhereOperator.Equals, "Action"); query = queryBuilder.AndWhere(query, "Subject", WhereOperator.Equals, "Subject"); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Resource", entry.Resource)); parameters.Add(new Parameter(ParameterType.String, "Action", entry.Action)); parameters.Add(new Parameter(ParameterType.String, "Subject", entry.Subject)); DbCommand command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false) <= 0) { RollbackTransaction(transaction); return false; } } CommitTransaction(transaction); return true; }
private void AssertAclEntriesAreEqual(AclEntry expected, AclEntry actual) { Assert.AreEqual(expected.Resource, actual.Resource, "Wrong resource"); Assert.AreEqual(expected.Action, actual.Action, "Wrong action"); Assert.AreEqual(expected.Subject, actual.Subject, "Wrong subject"); Assert.AreEqual(expected.Value, actual.Value, "Wrong value"); }
/// <summary> /// Loads data from storage. /// </summary> /// <returns>The loaded ACL entries.</returns> protected override AclEntry[] LoadDataInternal() { lock(this) { if(!File.Exists(file)) { File.Create(file).Close(); return new AclEntry[0]; } // Format // Resource|Action|Subject|(1|0) string[] lines = File.ReadAllLines(file); AclEntry[] result = new AclEntry[lines.Length]; string[] fields; for(int i = 0; i < lines.Length; i++) { fields = lines[i].Split('|'); result[i] = new AclEntry(fields[0], fields[1], fields[2], (fields[3] == "1" ? Value.Grant : Value.Deny)); } return result; } }
/// <summary> /// Stores a new ACL entry. /// </summary> /// <param name="resource">The controlled resource.</param> /// <param name="action">The action on the controlled resource.</param> /// <param name="subject">The subject whose access to the resource/action is controlled.</param> /// <param name="value">The value of the entry.</param> /// <returns><c>true</c> if the entry is stored, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <paramref name="resource"/>, <paramref name="action"/> or <paramref name="subject"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="resource"/>, <paramref name="action"/> or <paramref name="subject"/> are empty.</exception> 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; }
/// <summary> /// Deletes some entries. /// </summary> /// <param name="entries">The entries to delete.</param> protected abstract void DeleteEntries(AclEntry[] entries);
public void CopySettingsStorageProviderData() { MockRepository mocks = new MockRepository(); ISettingsStorageProviderV30 source = mocks.StrictMock<ISettingsStorageProviderV30>(); ISettingsStorageProviderV30 destination = mocks.StrictMock<ISettingsStorageProviderV30>(); IAclManager sourceAclManager = mocks.StrictMock<IAclManager>(); IAclManager destinationAclManager = mocks.StrictMock<IAclManager>(); // Setup SOURCE --------------------- // Settings Dictionary<string, string> settings = new Dictionary<string, string>() { { "Set1", "Value1" }, { "Set2", "Value2" } }; Expect.Call(source.GetAllSettings()).Return(settings); // Meta-data (global) Expect.Call(source.GetMetaDataItem(MetaDataItem.AccountActivationMessage, null)).Return("AAM"); Expect.Call(source.GetMetaDataItem(MetaDataItem.PasswordResetProcedureMessage, null)).Return("PRM"); Expect.Call(source.GetMetaDataItem(MetaDataItem.LoginNotice, null)).Return(""); Expect.Call(source.GetMetaDataItem(MetaDataItem.PageChangeMessage, null)).Return("PCM"); Expect.Call(source.GetMetaDataItem(MetaDataItem.DiscussionChangeMessage, null)).Return("DCM"); // Meta-data (root) Expect.Call(source.GetMetaDataItem(MetaDataItem.EditNotice, null)).Return(""); Expect.Call(source.GetMetaDataItem(MetaDataItem.Footer, null)).Return("FOOT"); Expect.Call(source.GetMetaDataItem(MetaDataItem.Header, null)).Return("HEADER"); Expect.Call(source.GetMetaDataItem(MetaDataItem.HtmlHead, null)).Return("HTML"); Expect.Call(source.GetMetaDataItem(MetaDataItem.PageFooter, null)).Return("P_FOOT"); Expect.Call(source.GetMetaDataItem(MetaDataItem.PageHeader, null)).Return("P_HEADER"); Expect.Call(source.GetMetaDataItem(MetaDataItem.Sidebar, null)).Return("SIDEBAR"); // Meta-data ("NS" namespace) Expect.Call(source.GetMetaDataItem(MetaDataItem.EditNotice, "NS")).Return("NS_EDIT"); Expect.Call(source.GetMetaDataItem(MetaDataItem.Footer, "NS")).Return("NS_FOOT"); Expect.Call(source.GetMetaDataItem(MetaDataItem.Header, "NS")).Return("NS_HEADER"); Expect.Call(source.GetMetaDataItem(MetaDataItem.HtmlHead, "NS")).Return("NS_HTML"); Expect.Call(source.GetMetaDataItem(MetaDataItem.PageFooter, "NS")).Return("NS_P_FOOT"); Expect.Call(source.GetMetaDataItem(MetaDataItem.PageHeader, "NS")).Return("NS_P_HEADER"); Expect.Call(source.GetMetaDataItem(MetaDataItem.Sidebar, "NS")).Return("NS_SIDEBAR"); // Plugin assemblies byte[] asm1 = new byte[] { 1, 2, 3, 4, 5 }; byte[] asm2 = new byte[] { 6, 7, 8, 9, 10, 11, 12 }; Expect.Call(source.ListPluginAssemblies()).Return(new string[] { "Plugins1.dll", "Plugins2.dll" }); Expect.Call(source.RetrievePluginAssembly("Plugins1.dll")).Return(asm1); Expect.Call(source.RetrievePluginAssembly("Plugins2.dll")).Return(asm2); // Plugin status Expect.Call(source.GetPluginStatus("Test1.Plugin1")).Return(true); Expect.Call(source.GetPluginStatus("Test2.Plugin2")).Return(false); // Plugin config Expect.Call(source.GetPluginConfiguration("Test1.Plugin1")).Return("Config1"); Expect.Call(source.GetPluginConfiguration("Test2.Plugin2")).Return(""); // Outgoing links Dictionary<string, string[]> outgoingLinks = new Dictionary<string, string[]>() { { "Page1", new string[] { "Page2", "Page3" } }, { "Page2", new string[] { "Page3" } }, { "Page3", new string[] { "Page4", "Page3" } } }; Expect.Call(source.GetAllOutgoingLinks()).Return(outgoingLinks); // ACLs Expect.Call(source.AclManager).Return(sourceAclManager); AclEntry[] entries = new AclEntry[] { new AclEntry("Res1", "Act1", "Subj1", Value.Grant), new AclEntry("Res2", "Act2", "Subj2", Value.Deny) }; Expect.Call(sourceAclManager.RetrieveAllEntries()).Return(entries); // Setup DESTINATION ----------------- // Settings destination.BeginBulkUpdate(); LastCall.On(destination).Repeat.Once(); foreach(KeyValuePair<string, string> pair in settings) { Expect.Call(destination.SetSetting(pair.Key, pair.Value)).Return(true); } destination.EndBulkUpdate(); LastCall.On(destination).Repeat.Once(); // Meta-data (global) Expect.Call(destination.SetMetaDataItem(MetaDataItem.AccountActivationMessage, null, "AAM")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.PasswordResetProcedureMessage, null, "PRM")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.LoginNotice, null, "")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.PageChangeMessage, null, "PCM")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.DiscussionChangeMessage, null, "DCM")).Return(true); // Meta-data (root) Expect.Call(destination.SetMetaDataItem(MetaDataItem.EditNotice, null, "")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.Footer, null, "FOOT")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.Header, null, "HEADER")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.HtmlHead, null, "HTML")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.PageFooter, null, "P_FOOT")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.PageHeader, null, "P_HEADER")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.Sidebar, null, "SIDEBAR")).Return(true); // Meta-data ("NS" namespace) Expect.Call(destination.SetMetaDataItem(MetaDataItem.EditNotice, "NS", "NS_EDIT")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.Footer, "NS", "NS_FOOT")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.Header, "NS", "NS_HEADER")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.HtmlHead, "NS", "NS_HTML")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.PageFooter, "NS", "NS_P_FOOT")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.PageHeader, "NS", "NS_P_HEADER")).Return(true); Expect.Call(destination.SetMetaDataItem(MetaDataItem.Sidebar, "NS", "NS_SIDEBAR")).Return(true); // Plugin assemblies Expect.Call(destination.StorePluginAssembly("Plugins1.dll", asm1)).Return(true); Expect.Call(destination.StorePluginAssembly("Plugins2.dll", asm2)).Return(true); // Plugin status Expect.Call(destination.SetPluginStatus("Test1.Plugin1", true)).Return(true); Expect.Call(destination.SetPluginStatus("Test2.Plugin2", false)).Return(true); // Plugin config Expect.Call(destination.SetPluginConfiguration("Test1.Plugin1", "Config1")).Return(true); Expect.Call(destination.SetPluginConfiguration("Test2.Plugin2", "")).Return(true); // Outgoing links foreach(KeyValuePair<string, string[]> pair in outgoingLinks) { Expect.Call(destination.StoreOutgoingLinks(pair.Key, pair.Value)).Return(true); } // ACLs Expect.Call(destination.AclManager).Return(destinationAclManager).Repeat.Any(); foreach(AclEntry e in entries) { Expect.Call(destinationAclManager.StoreEntry(e.Resource, e.Action, e.Subject, e.Value)).Return(true); } mocks.ReplayAll(); DataMigrator.CopySettingsStorageProviderData(source, destination, new string[] { "NS" }, new string[] { "Test1.Plugin1", "Test2.Plugin2" }); mocks.VerifyAll(); }
/// <summary> /// Determines whether this instance equals another (by value). /// </summary> /// <param name="other">The other instance.</param> /// <returns><c>true</c> if this instance equals <b>other</b>, <c>false</c> otherwise.</returns> public bool Equals(AclEntry other) { if(object.ReferenceEquals(other, null)) return false; else return resource == other.Resource && action == other.Action && subject == other.Subject; }
/// <summary> /// Determines whether two instances of <see cref="T:AclEntry" /> are equal (by value). /// </summary> /// <param name="x">The first instance.</param> /// <param name="y">The second instance.</param> /// <returns><c>true</c> if <b>x</b> equals <b>y</b>, <c>false</c> otherwise.</returns> public static bool Equals(AclEntry x, AclEntry y) { if(object.ReferenceEquals(x, null) && !object.ReferenceEquals(x, null)) return false; if(!object.ReferenceEquals(x, null) && object.ReferenceEquals(x, null)) return false; if(object.ReferenceEquals(x, null) && object.ReferenceEquals(x, null)) return true; return x.Equals(y); }
/// <summary> /// Decides whether a user, member of some groups, is authorized to perform an action on a resource. /// </summary> /// <param name="resource">The resource.</param> /// <param name="action">The action on the resource.</param> /// <param name="user">The user, in the form 'U.Name'.</param> /// <param name="groups">The groups the user is member of, in the form 'G.Name'.</param> /// <param name="entries">The available ACL entries for the resource.</param> /// <returns>The positive, negative, or indeterminate result.</returns> /// <exception cref="ArgumentNullException">If <paramref name="resource"/>, <paramref name="action"/>, <paramref name="user"/>, <paramref name="groups"/> or <paramref name="entries"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="resource"/>, <paramref name="action"/>, <paramref name="user"/> are empty, or if <paramref name="action"/> equals <see cref="AclEntry.FullControlAction"/>.</exception> public static Authorization AuthorizeAction(string resource, string action, string user, string[] groups, AclEntry[] entries) { 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(action == AclEntry.FullControlAction) throw new ArgumentException("Action cannot be the FullControl flag", "action"); if(user == null) throw new ArgumentNullException("user"); if(user.Length == 0) throw new ArgumentException("User cannot be empty", "user"); if(groups == null) throw new ArgumentNullException("groups"); if(entries == null) throw new ArgumentNullException("entries"); // Simple ACL model // Sort entries so that FullControl ones are at the bottom // First look for an entry specific for the user // If not found, look for a group that denies the permission AclEntry[] sortedEntries = new AclEntry[entries.Length]; Array.Copy(entries, sortedEntries, entries.Length); Array.Sort(sortedEntries, delegate(AclEntry x, AclEntry y) { return x.Action.CompareTo(y.Action); }); Array.Reverse(sortedEntries); foreach(AclEntry entry in sortedEntries) { if(entry.Resource == resource && (entry.Action == action || entry.Action == AclEntry.FullControlAction) && entry.Subject == user) { if(entry.Value == Value.Grant) return Authorization.Granted; else if(entry.Value == Value.Deny) return Authorization.Denied; else throw new NotSupportedException("Entry value not supported"); } } // For each group, a decision is made Dictionary<string, bool> groupFullControlGrant = new Dictionary<string, bool>(); Dictionary<string, bool> groupExplicitGrant = new Dictionary<string, bool>(); Dictionary<string, bool> groupFullControlDeny = new Dictionary<string, bool>(); foreach(string group in groups) { foreach(AclEntry entry in entries) { if(entry.Resource == resource && entry.Subject == group) { if(!groupFullControlGrant.ContainsKey(group)) { groupFullControlGrant.Add(group, false); groupExplicitGrant.Add(group, false); groupFullControlDeny.Add(group, false); } if(entry.Action == action) { // Explicit action if(entry.Value == Value.Grant) { // An explicit grant only wins if there are no other explicit deny groupExplicitGrant[group] = true; } else if(entry.Value == Value.Deny) { // An explicit deny wins over all other entries return Authorization.Denied; } } else if(entry.Action == AclEntry.FullControlAction) { // Full control, lower priority if(entry.Value == Value.Deny) { groupFullControlDeny[group] = true; } else if(entry.Value == Value.Grant) { groupFullControlGrant[group] = true; } } } } } // Any explicit grant found at this step wins, because all explicit deny have been processed previously bool tentativeGrant = false; bool tentativeDeny = false; foreach(string group in groupFullControlGrant.Keys) { if(groupExplicitGrant[group]) return Authorization.Granted; if(groupFullControlGrant[group] && !groupFullControlDeny[group]) tentativeGrant = true; if(!groupFullControlGrant[group] && groupFullControlDeny[group]) tentativeDeny = true; } if(tentativeGrant && !tentativeDeny) return Authorization.Granted; else if(tentativeDeny) return Authorization.Denied; else return Authorization.Unknown; }
/// <summary> /// Initializes the manager data. /// </summary> /// <param name="entries">The ACL entries.</param> /// <exception cref="ArgumentNullException">If <paramref name="entries"/> is <c>null</c>.</exception> public void InitializeData(AclEntry[] entries) { if(entries == null) throw new ArgumentNullException("entries"); }
/// <summary> /// Stores some entries. /// </summary> /// <param name="entries">The entries to store.</param> protected abstract void StoreEntries(AclEntry[] entries);
/// <summary> /// Decides whether a user, member of some groups, is authorized to perform an action on a resource. /// </summary> /// <param name="resource">The resource.</param> /// <param name="action">The action on the resource.</param> /// <param name="user">The user, in the form 'U.Name'.</param> /// <param name="groups">The groups the user is member of, in the form 'G.Name'.</param> /// <param name="entries">The available ACL entries for the resource.</param> /// <returns>The positive, negative, or indeterminate result.</returns> /// <exception cref="ArgumentNullException">If <paramref name="resource"/>, <paramref name="action"/>, <paramref name="user"/>, <paramref name="groups"/> or <paramref name="entries"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="resource"/>, <paramref name="action"/>, <paramref name="user"/> are empty, or if <paramref name="action"/> equals <see cref="AclEntry.FullControlAction"/>.</exception> public static Authorization AuthorizeAction(string resource, string action, string user, string[] groups, AclEntry[] entries) { 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 (action == AclEntry.FullControlAction) { throw new ArgumentException("Action cannot be the FullControl flag", "action"); } if (user == null) { throw new ArgumentNullException("user"); } if (user.Length == 0) { throw new ArgumentException("User cannot be empty", "user"); } if (groups == null) { throw new ArgumentNullException("groups"); } if (entries == null) { throw new ArgumentNullException("entries"); } // Simple ACL model // Sort entries so that FullControl ones are at the bottom // First look for an entry specific for the user // If not found, look for a group that denies the permission AclEntry[] sortedEntries = new AclEntry[entries.Length]; Array.Copy(entries, sortedEntries, entries.Length); Array.Sort(sortedEntries, delegate(AclEntry x, AclEntry y) { return(x.Action.CompareTo(y.Action)); }); Array.Reverse(sortedEntries); foreach (AclEntry entry in sortedEntries) { if (entry.Resource == resource && (entry.Action == action || entry.Action == AclEntry.FullControlAction) && entry.Subject == user) { if (entry.Value == Value.Grant) { return(Authorization.Granted); } else if (entry.Value == Value.Deny) { return(Authorization.Denied); } else { throw new NotSupportedException("Entry value not supported"); } } } // For each group, a decision is made Dictionary <string, bool> groupFullControlGrant = new Dictionary <string, bool>(); Dictionary <string, bool> groupExplicitGrant = new Dictionary <string, bool>(); Dictionary <string, bool> groupFullControlDeny = new Dictionary <string, bool>(); foreach (string group in groups) { foreach (AclEntry entry in entries) { if (entry.Resource == resource && entry.Subject == group) { if (!groupFullControlGrant.ContainsKey(group)) { groupFullControlGrant.Add(group, false); groupExplicitGrant.Add(group, false); groupFullControlDeny.Add(group, false); } if (entry.Action == action) { // Explicit action if (entry.Value == Value.Grant) { // An explicit grant only wins if there are no other explicit deny groupExplicitGrant[group] = true; } else if (entry.Value == Value.Deny) { // An explicit deny wins over all other entries return(Authorization.Denied); } } else if (entry.Action == AclEntry.FullControlAction) { // Full control, lower priority if (entry.Value == Value.Deny) { groupFullControlDeny[group] = true; } else if (entry.Value == Value.Grant) { groupFullControlGrant[group] = true; } } } } } // Any explicit grant found at this step wins, because all explicit deny have been processed previously bool tentativeGrant = false; bool tentativeDeny = false; foreach (string group in groupFullControlGrant.Keys) { if (groupExplicitGrant[group]) { return(Authorization.Granted); } if (groupFullControlGrant[group] && !groupFullControlDeny[group]) { tentativeGrant = true; } if (!groupFullControlGrant[group] && groupFullControlDeny[group]) { tentativeDeny = true; } } if (tentativeGrant && !tentativeDeny) { return(Authorization.Granted); } else if (tentativeDeny) { return(Authorization.Denied); } else { return(Authorization.Unknown); } }
/// <summary> /// Stores some entries. /// </summary> /// <param name="entries">The entries to store.</param> protected override void StoreEntries(AclEntry[] entries) { lock(this) { StringBuilder sb = new StringBuilder(100); foreach(AclEntry entry in entries) { sb.Append(DumpAclEntry(entry)); sb.Append("\r\n"); } File.AppendAllText(file, sb.ToString()); } }
private void OnAclChanged(AclEntry[] entries, Change change) { if(AclChanged != null) { AclChanged(this, new AclChangedEventArgs(entries, change)); } }
/// <summary> /// Dumps a <see cref="T:AclEntry" /> into a string. /// </summary> /// <param name="entry">The entry to dump.</param> /// <returns>The resulting string.</returns> private static string DumpAclEntry(AclEntry entry) { return string.Format("{0}|{1}|{2}|{3}", entry.Resource, entry.Action, entry.Subject, (entry.Value == Value.Grant ? "1" : "0")); }
/// <summary> /// Deletes an ACL entry. /// </summary> /// <param name="resource">The controlled resource.</param> /// <param name="action">The action on the controlled resource.</param> /// <param name="subject">The subject whose access to the resource/action is controlled.</param> /// <returns><c>true</c> if the entry is deleted, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <paramref name="resource"/>, <paramref name="action"/> or <paramref name="subject"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="resource"/>, <paramref name="action"/> or <paramref name="subject"/> are empty.</exception> 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 entry = new AclEntry(resource, action, subject, Value.Deny); return _deleteEntries(new[] { entry }); }
/// <summary> /// Initializes the manager data. /// </summary> /// <param name="entries">The ACL entries.</param> /// <exception cref="ArgumentNullException">If <paramref name="entries"/> is <c>null</c>.</exception> public void InitializeData(AclEntry[] entries) { if(entries == null) throw new ArgumentNullException("entries"); lock(this) { this.entries = new List<AclEntry>(entries); } }