using System; using System.Collections.Generic; using System.Text; using ScrewTurn.Wiki.PluginFramework; using ScrewTurn.Wiki.AclEngine; namespace ScrewTurn.Wiki { /// /// Utility class for writing permissions and authorizations. /// public static class AuthWriter { private const string Delete = "DELETE"; private const string Set = "SET-"; private const string MessageDeleteSuccess = "Deleted ACL Entry: "; private const string MessageDeleteFailure = "Deletion failed for ACL Entry: "; private const string MessageSetSuccess = "Set ACL Entry: "; private const string MessageSetFailure = "Setting failed for ACL Entry: "; /// /// Gets the settings storage provider. /// private static ISettingsStorageProviderV30 SettingsProvider { get { return Collectors.SettingsProvider; } } /// /// Sets a permission for a global resource. /// /// The authorization status. /// The action of which to modify the authorization status. /// The group subject of the authorization change. /// true if the authorization status is changed, false otherwise. public static bool SetPermissionForGlobals(AuthStatus status, string action, UserGroup group) { if(group == null) throw new ArgumentNullException("group"); return SetPermissionForGlobals(status, action, AuthTools.PrepareGroup(group.Name)); } /// /// Sets a permission for a global resource. /// /// The authorization status. /// The action of which to modify the authorization status. /// The user subject of the authorization change. /// true if the authorization status is changed, false otherwise. public static bool SetPermissionForGlobals(AuthStatus status, string action, UserInfo user) { if(user == null) throw new ArgumentNullException("user"); return SetPermissionForGlobals(status, action, AuthTools.PrepareUsername(user.Username)); } /// /// Sets a permission for a global resource. /// /// The authorization status. /// The action of which to modify the authorization status. /// The subject of the authorization change. /// true if the authorization status is changed, false otherwise. private static bool SetPermissionForGlobals(AuthStatus status, string action, string subject) { if(action == null) throw new ArgumentNullException("action"); if(action.Length == 0) throw new ArgumentException("Action cannot be empty", "action"); if(action != Actions.FullControl && !AuthTools.IsValidAction(action, Actions.ForGlobals.All)) { throw new ArgumentException("Invalid action", "action"); } if(status == AuthStatus.Delete) { bool done = SettingsProvider.AclManager.DeleteEntry(Actions.ForGlobals.ResourceMasterPrefix, action, subject); if(done) { Log.LogEntry(MessageDeleteSuccess + GetLogMessage(Actions.ForGlobals.ResourceMasterPrefix, "", action, subject, Delete), EntryType.General, Log.SystemUsername); } else { Log.LogEntry(MessageDeleteFailure + GetLogMessage(Actions.ForGlobals.ResourceMasterPrefix, "", action, subject, Delete), EntryType.Error, Log.SystemUsername); } return done; } else { bool done = SettingsProvider.AclManager.StoreEntry(Actions.ForGlobals.ResourceMasterPrefix, action, subject, status == AuthStatus.Grant ? Value.Grant : Value.Deny); if(done) { Log.LogEntry(MessageSetSuccess + GetLogMessage(Actions.ForGlobals.ResourceMasterPrefix, "", action, subject, Set + status.ToString()), EntryType.General, Log.SystemUsername); } else { Log.LogEntry(MessageSetFailure + GetLogMessage(Actions.ForGlobals.ResourceMasterPrefix, "", action, subject, Set + status.ToString()), EntryType.Error, Log.SystemUsername); } return done; } } /// /// Sets a permission for a namespace. /// /// The authorization status. /// The namespace (null for the root). /// The action of which to modify the authorization status. /// The group subject of the authorization change. /// true if the authorization status is changed, false otherwise. public static bool SetPermissionForNamespace(AuthStatus status, NamespaceInfo nspace, string action, UserGroup group) { if(group == null) throw new ArgumentNullException("group"); return SetPermissionForNamespace(status, nspace, action, AuthTools.PrepareGroup(group.Name)); } /// /// Sets a permission for a namespace. /// /// The authorization status. /// The namespace (null for the root). /// The action of which to modify the authorization status. /// The user subject of the authorization change. /// true if the authorization status is changed, false otherwise. public static bool SetPermissionForNamespace(AuthStatus status, NamespaceInfo nspace, string action, UserInfo user) { if(user == null) throw new ArgumentNullException("user"); return SetPermissionForNamespace(status, nspace, action, AuthTools.PrepareUsername(user.Username)); } /// /// Sets a permission for a namespace. /// /// The authorization status. /// The namespace (null for the root). /// The action of which to modify the authorization status. /// The subject of the authorization change. /// true if the authorization status is changed, false otherwise. private static bool SetPermissionForNamespace(AuthStatus status, NamespaceInfo nspace, string action, string subject) { if(action == null) throw new ArgumentNullException("action"); if(action.Length == 0) throw new ArgumentException("Action cannot be empty", "action"); if(action != Actions.FullControl && !AuthTools.IsValidAction(action, Actions.ForNamespaces.All)) { throw new ArgumentException("Invalid action", "action"); } string namespaceName = nspace != null ? nspace.Name : ""; if(status == AuthStatus.Delete) { bool done = SettingsProvider.AclManager.DeleteEntry(Actions.ForNamespaces.ResourceMasterPrefix + namespaceName, action, subject); if(done) { Log.LogEntry(MessageDeleteSuccess + GetLogMessage(Actions.ForNamespaces.ResourceMasterPrefix, namespaceName, action, subject, Delete), EntryType.General, Log.SystemUsername); } else { Log.LogEntry(MessageDeleteFailure + GetLogMessage(Actions.ForNamespaces.ResourceMasterPrefix, namespaceName, action, subject, Delete), EntryType.Error, Log.SystemUsername); } return done; } else { bool done = SettingsProvider.AclManager.StoreEntry(Actions.ForNamespaces.ResourceMasterPrefix + namespaceName, action, subject, status == AuthStatus.Grant ? Value.Grant : Value.Deny); if(done) { Log.LogEntry(MessageSetSuccess + GetLogMessage(Actions.ForNamespaces.ResourceMasterPrefix, namespaceName, action, subject, Set + status.ToString()), EntryType.General, Log.SystemUsername); } else { Log.LogEntry(MessageSetFailure + GetLogMessage(Actions.ForNamespaces.ResourceMasterPrefix, namespaceName, action, subject, Set + status.ToString()), EntryType.Error, Log.SystemUsername); } return done; } } /// /// Sets a permission for a directory. /// /// The authorization status. /// The provider that handles the directory. /// The directory. /// The action of which to modify the authorization status. /// The group subject of the authorization change. /// true if the authorization status is changed, false otherwise. public static bool SetPermissionForDirectory(AuthStatus status, IFilesStorageProviderV30 provider, string directory, string action, UserGroup group) { if(group == null) throw new ArgumentNullException("group"); return SetPermissionForDirectory(status, provider, directory, action, AuthTools.PrepareGroup(group.Name)); } /// /// Sets a permission for a directory. /// /// The authorization status. /// The provider that handles the directory. /// The directory. /// The action of which to modify the authorization status. /// The user subject of the authorization change. /// true if the authorization status is changed, false otherwise. public static bool SetPermissionForDirectory(AuthStatus status, IFilesStorageProviderV30 provider, string directory, string action, UserInfo user) { if(user == null) throw new ArgumentNullException("user"); return SetPermissionForDirectory(status, provider, directory, action, AuthTools.PrepareUsername(user.Username)); } /// /// Sets a permission for a directory. /// /// The authorization status. /// The provider that handles the directory. /// The directory. /// The action of which to modify the authorization status. /// The subject of the authorization change. /// true if the authorization status is changed, false otherwise. private static bool SetPermissionForDirectory(AuthStatus status, IFilesStorageProviderV30 provider, string directory, string action, string subject) { if(provider == null) throw new ArgumentNullException("provider"); if(directory == null) throw new ArgumentNullException("directory"); if(directory.Length == 0) throw new ArgumentException("Directory cannot be empty", "directory"); if(action == null) throw new ArgumentNullException("action"); if(action.Length == 0) throw new ArgumentException("Action cannot be empty", "action"); if(action != Actions.FullControl && !AuthTools.IsValidAction(action, Actions.ForDirectories.All)) { throw new ArgumentException("Invalid action", "action"); } string directoryName = AuthTools.GetDirectoryName(provider, directory); if(status == AuthStatus.Delete) { bool done = SettingsProvider.AclManager.DeleteEntry(Actions.ForDirectories.ResourceMasterPrefix + directoryName, action, subject); if(done) { Log.LogEntry(MessageDeleteSuccess + GetLogMessage(Actions.ForDirectories.ResourceMasterPrefix, directoryName, action, subject, Delete), EntryType.General, Log.SystemUsername); } else { Log.LogEntry(MessageDeleteFailure + GetLogMessage(Actions.ForDirectories.ResourceMasterPrefix, directoryName, action, subject, Delete), EntryType.Error, Log.SystemUsername); } return done; } else { bool done = SettingsProvider.AclManager.StoreEntry(Actions.ForDirectories.ResourceMasterPrefix + directoryName, action, subject, status == AuthStatus.Grant ? Value.Grant : Value.Deny); if(done) { Log.LogEntry(MessageSetSuccess + GetLogMessage(Actions.ForDirectories.ResourceMasterPrefix, directoryName, action, subject, Set + status.ToString()), EntryType.General, Log.SystemUsername); } else { Log.LogEntry(MessageSetFailure + GetLogMessage(Actions.ForDirectories.ResourceMasterPrefix, directoryName, action, subject, Set + status.ToString()), EntryType.Error, Log.SystemUsername); } return done; } } /// /// Sets a permission for a page. /// /// The authorization status. /// The page. /// The action of which to modify the authorization status. /// The group subject of the authorization change. /// true if the authorization status is changed, false otherwise. public static bool SetPermissionForPage(AuthStatus status, PageInfo page, string action, UserGroup group) { if(group == null) throw new ArgumentNullException("group"); return SetPermissionForPage(status, page, action, AuthTools.PrepareGroup(group.Name)); } /// /// Sets a permission for a page. /// /// The authorization status. /// The page. /// The action of which to modify the authorization status. /// The user subject of the authorization change. /// true if the authorization status is changed, false otherwise. public static bool SetPermissionForPage(AuthStatus status, PageInfo page, string action, UserInfo user) { if(user == null) throw new ArgumentNullException("user"); return SetPermissionForPage(status, page, action, AuthTools.PrepareUsername(user.Username)); } /// /// Sets a permission for a page. /// /// The authorization status. /// The page. /// The action of which to modify the authorization status. /// The subject of the authorization change. /// true if the authorization status is changed, false otherwise. private static bool SetPermissionForPage(AuthStatus status, PageInfo page, string action, string subject) { if(page == null) throw new ArgumentNullException("page"); if(action == null) throw new ArgumentNullException("action"); if(action.Length == 0) throw new ArgumentException("Action cannot be empty", "action"); if(action != Actions.FullControl && !AuthTools.IsValidAction(action, Actions.ForPages.All)) { throw new ArgumentException("Invalid action", "action"); } if(status == AuthStatus.Delete) { bool done = SettingsProvider.AclManager.DeleteEntry(Actions.ForPages.ResourceMasterPrefix + page.FullName, action, subject); if(done) { Log.LogEntry(MessageDeleteSuccess + GetLogMessage(Actions.ForPages.ResourceMasterPrefix, page.FullName, action, subject, Delete), EntryType.General, Log.SystemUsername); } else { Log.LogEntry(MessageDeleteFailure + GetLogMessage(Actions.ForPages.ResourceMasterPrefix, page.FullName, action, subject, Delete), EntryType.Error, Log.SystemUsername); } return done; } else { bool done = SettingsProvider.AclManager.StoreEntry(Actions.ForPages.ResourceMasterPrefix + page.FullName, action, subject, status == AuthStatus.Grant ? Value.Grant : Value.Deny); if(done) { Log.LogEntry(MessageSetSuccess + GetLogMessage(Actions.ForPages.ResourceMasterPrefix, page.FullName, action, subject, Set + status.ToString()), EntryType.General, Log.SystemUsername); } else { Log.LogEntry(MessageSetFailure + GetLogMessage(Actions.ForPages.ResourceMasterPrefix, page.FullName, action, subject, Set + status.ToString()), EntryType.Error, Log.SystemUsername); } return done; } } /// /// Removes all the ACL Entries for global resources that are bound to a user group. /// /// The user group. /// true if the operation succeeded, false otherwise. public static bool RemoveEntriesForGlobals(UserGroup group) { if(group == null) throw new ArgumentNullException("group"); return RemoveEntriesForGlobals(AuthTools.PrepareGroup(group.Name)); } /// /// Removes all the ACL Entries for global resources that are bound to a user. /// /// The user. /// true if the operation succeeded, false otherwise. public static bool RemoveEntriesForGlobals(UserInfo user) { if(user == null) throw new ArgumentNullException("user"); return RemoveEntriesForGlobals(AuthTools.PrepareUsername(user.Username)); } /// /// Removes all the ACL Entries for global resources that are bound to a subject. /// /// The subject. /// true if the operation succeeded, false otherwise. private static bool RemoveEntriesForGlobals(string subject) { AclEntry[] entries = SettingsProvider.AclManager.RetrieveEntriesForSubject(subject); foreach(AclEntry entry in entries) { if(entry.Resource == Actions.ForGlobals.ResourceMasterPrefix) { // This call automatically logs the operation result bool done = SetPermissionForGlobals(AuthStatus.Delete, entry.Action, subject); if(!done) return false; } } return true; } /// /// Removes all the ACL Entries for a namespace that are bound to a user group. /// /// The user group. /// The namespace (null for the root). /// true if the operation succeeded, false otherwise. public static bool RemoveEntriesForNamespace(UserGroup group, NamespaceInfo nspace) { if(group == null) throw new ArgumentNullException("group"); return RemoveEntriesForNamespace(AuthTools.PrepareGroup(group.Name), nspace); } /// /// Removes all the ACL Entries for a namespace that are bound to a user. /// /// The user. /// The namespace (null for the root). /// true if the operation succeeded, false otherwise. public static bool RemoveEntriesForNamespace(UserInfo user, NamespaceInfo nspace) { if(user == null) throw new ArgumentNullException("user"); return RemoveEntriesForNamespace(AuthTools.PrepareUsername(user.Username), nspace); } /// /// Removes all the ACL Entries for a namespace that are bound to a subject. /// /// The subject. /// The namespace (null for the root). /// true if the operation succeeded, false otherwise. private static bool RemoveEntriesForNamespace(string subject, NamespaceInfo nspace) { string resourceName = Actions.ForNamespaces.ResourceMasterPrefix; if(nspace != null) resourceName += nspace.Name; AclEntry[] entries = SettingsProvider.AclManager.RetrieveEntriesForSubject(subject); foreach(AclEntry entry in entries) { if(entry.Resource == resourceName) { // This call automatically logs the operation result bool done = SetPermissionForNamespace(AuthStatus.Delete, nspace, entry.Action, subject); if(!done) return false; } } return true; } /// /// Removes all the ACL Entries for a page that are bound to a user group. /// /// The user group. /// The page. /// true if the operation succeeded, false otherwise. public static bool RemoveEntriesForPage(UserGroup group, PageInfo page) { if(group == null) throw new ArgumentNullException("group"); return RemoveEntriesForPage(AuthTools.PrepareGroup(group.Name), page); } /// /// Removes all the ACL Entries for a page that are bound to a user. /// /// The user. /// The page. /// true if the operation succeeded, false otherwise. public static bool RemoveEntriesForPage(UserInfo user, PageInfo page) { if(user == null) throw new ArgumentNullException("user"); return RemoveEntriesForPage(AuthTools.PrepareUsername(user.Username), page); } /// /// Removes all the ACL Entries for a page that are bound to a subject. /// /// The subject. /// The page. /// true if the operation succeeded, false otherwise. private static bool RemoveEntriesForPage(string subject, PageInfo page) { if(page == null) throw new ArgumentNullException("page"); string resourceName = Actions.ForPages.ResourceMasterPrefix + page.FullName; AclEntry[] entries = SettingsProvider.AclManager.RetrieveEntriesForSubject(subject); foreach(AclEntry entry in entries) { if(entry.Resource == resourceName) { // This call automatically logs the operation result bool done = SetPermissionForPage(AuthStatus.Delete, page, entry.Action, subject); if(!done) return false; } } return true; } /// /// Removes all the ACL Entries for a directory that are bound to a user group. /// /// The group. /// The provider. /// The directory. /// true if the operation succeeded, false otherwise. public static bool RemoveEntriesForDirectory(UserGroup group, IFilesStorageProviderV30 provider, string directory) { if(group == null) throw new ArgumentNullException("group"); return RemoveEntriesForDirectory(AuthTools.PrepareGroup(group.Name), provider, directory); } /// /// Removes all the ACL Entries for a directory that are bound to a user. /// /// The user. /// The provider. /// The directory. /// true if the operation succeeded, false otherwise. public static bool RemoveEntriesForDirectory(UserInfo user, IFilesStorageProviderV30 provider, string directory) { if(user == null) throw new ArgumentNullException("user"); return RemoveEntriesForDirectory(AuthTools.PrepareUsername(user.Username), provider, directory); } /// /// Removes all the ACL Entries for a directory that are bound to a subject. /// /// The subject. /// The provider. /// The directory. /// true if the operation succeeded, false otherwise. private static bool RemoveEntriesForDirectory(string subject, IFilesStorageProviderV30 provider, string directory) { if(provider == null) throw new ArgumentNullException("provider"); if(directory == null) throw new ArgumentNullException("directory"); if(directory.Length == 0) throw new ArgumentException("Directory cannot be empty", "directory"); string resourceName = Actions.ForDirectories.ResourceMasterPrefix + AuthTools.GetDirectoryName(provider, directory); AclEntry[] entries = SettingsProvider.AclManager.RetrieveEntriesForSubject(subject); foreach(AclEntry entry in entries) { if(entry.Resource == resourceName) { // This call automatically logs the operation result bool done = SetPermissionForDirectory(AuthStatus.Delete, provider, directory, entry.Action, subject); if(!done) return false; } } return true; } /// /// Clears all the ACL entries for a directory. /// /// The provider. /// The directory. public static void ClearEntriesForDirectory(IFilesStorageProviderV30 provider, string directory) { if(provider == null) throw new ArgumentNullException("provider"); if(directory == null) throw new ArgumentNullException("directory"); if(directory.Length == 0) throw new ArgumentException("Directory cannot be empty", "directory"); string resourceName = Actions.ForDirectories.ResourceMasterPrefix + AuthTools.GetDirectoryName(provider, directory); SettingsProvider.AclManager.DeleteEntriesForResource(resourceName); } /// /// Clears all the ACL entries for a namespace. /// /// The namespace. /// The local names of the pages in the namespace. public static void ClearEntriesForNamespace(string nspace, List pages) { if(nspace == null) throw new ArgumentNullException("nspac"); if(nspace.Length == 0) throw new ArgumentException("Namespace cannot be empty", "nspace"); if(pages == null) throw new ArgumentNullException("pages"); foreach(string p in pages) { if(p == null) throw new ArgumentNullException("pages"); if(p.Length == 0) throw new ArgumentException("Page Element cannot be empty", "pages"); } string resourceName; foreach(string p in pages) { resourceName = Actions.ForPages.ResourceMasterPrefix + NameTools.GetFullName(nspace, p); SettingsProvider.AclManager.DeleteEntriesForResource(resourceName); } resourceName = Actions.ForNamespaces.ResourceMasterPrefix + nspace; SettingsProvider.AclManager.DeleteEntriesForResource(resourceName); } /// /// Clears all the ACL entries for a page. /// /// The page full name. public static void ClearEntriesForPage(string page) { if(page == null) throw new ArgumentNullException("page"); if(page.Length == 0) throw new ArgumentException("Page cannot be empty", "page"); string resourceName = Actions.ForPages.ResourceMasterPrefix + page; SettingsProvider.AclManager.DeleteEntriesForResource(resourceName); } /// /// Processes the renaming of a directory. /// /// The provider. /// The old directory name (full path). /// The new directory name (full path). /// true if the operation completed successfully, false otherwise. /// The method does not recurse in sub-directories. public static bool ProcessDirectoryRenaming(IFilesStorageProviderV30 provider, string oldName, string newName) { if(provider == null) throw new ArgumentNullException("provider"); if(oldName == null) throw new ArgumentNullException("oldName"); if(oldName.Length == 0) throw new ArgumentException("Old Name cannot be empty", "oldName"); if(newName == null) throw new ArgumentNullException("newName"); if(newName.Length == 0) throw new ArgumentException("New Name cannot be empty", "newName"); return SettingsProvider.AclManager.RenameResource( Actions.ForDirectories.ResourceMasterPrefix + AuthTools.GetDirectoryName(provider, oldName), Actions.ForDirectories.ResourceMasterPrefix + AuthTools.GetDirectoryName(provider, newName)); } /// /// Processes the renaming of a namespace. /// /// The old name of the namespace. /// The list of local names of the pages in the renamed namespace. /// The new name of the namespace. /// true if the operation completed successfully, false otherwise. public static bool ProcessNamespaceRenaming(string oldName, List oldPages, string newName) { if(oldName == null) throw new ArgumentNullException("oldName"); if(oldName.Length == 0) throw new ArgumentException("Old Name cannot be empty", "oldName"); if(oldPages == null) throw new ArgumentNullException("oldPages"); foreach(string p in oldPages) { if(p == null) throw new ArgumentNullException("oldPages"); if(p.Length == 0) throw new ArgumentException("Page cannot be empty", "oldPages"); } if(newName == null) throw new ArgumentNullException("newName"); if(newName.Length == 0) throw new ArgumentException("New Name cannot be empty", "newName"); foreach(string p in oldPages) { SettingsProvider.AclManager.RenameResource( Actions.ForPages.ResourceMasterPrefix + NameTools.GetFullName(oldName, p), Actions.ForPages.ResourceMasterPrefix + NameTools.GetFullName(newName, p)); } return SettingsProvider.AclManager.RenameResource( Actions.ForNamespaces.ResourceMasterPrefix + oldName, Actions.ForNamespaces.ResourceMasterPrefix + newName); } /// /// Processes the renaming of a page. /// /// The old full page name. /// The new full page name. /// true if the operation completed successfully, false otherwise. public static bool ProcessPageRenaming(string oldName, string newName) { if(oldName == null) throw new ArgumentNullException("oldName"); if(oldName.Length == 0) throw new ArgumentException("Old Name cannot be empty", "oldName"); if(newName == null) throw new ArgumentNullException("newName"); if(newName.Length == 0) throw new ArgumentException("New Name cannot be empty", "newName"); return SettingsProvider.AclManager.RenameResource( Actions.ForPages.ResourceMasterPrefix + oldName, Actions.ForPages.ResourceMasterPrefix + newName); } /// /// Gets the log message for an ACL entry change. /// /// The resource prefix. /// The resource name. /// The action. /// The subject. /// The status. /// The message. private static string GetLogMessage(string resourcePrefix, string resource, string action, string subject, string status) { return resourcePrefix + resource + ":" + action + ":" + subject + "->" + status; } } }