From 2191bdcd220b8218f49417a7e52eb510cf776cf1 Mon Sep 17 00:00:00 2001 From: Matteo Tomasini Date: Thu, 18 Aug 2011 16:39:50 +0200 Subject: [PATCH] [completed:539] Fixed AuthChecker for wrong beahviour in namespace permissions if group has global grant permissions. --- AssemblyVersion.cs | 4 +- Core-Tests/AuthCheckerTests.cs | 90 ++++++++++++++++++++++++++++++++++ Core/AuthChecker.cs | 58 +++++++++++++++------- 3 files changed, 131 insertions(+), 21 deletions(-) diff --git a/AssemblyVersion.cs b/AssemblyVersion.cs index f71a01e..fc83053 100644 --- a/AssemblyVersion.cs +++ b/AssemblyVersion.cs @@ -16,5 +16,5 @@ using System.Reflection; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("3.0.5.602")] -[assembly: AssemblyFileVersion("3.0.5.602")] \ No newline at end of file +[assembly: AssemblyVersion("3.0.5.603")] +[assembly: AssemblyFileVersion("3.0.5.603")] \ No newline at end of file diff --git a/Core-Tests/AuthCheckerTests.cs b/Core-Tests/AuthCheckerTests.cs index 3092cff..c62f515 100644 --- a/Core-Tests/AuthCheckerTests.cs +++ b/Core-Tests/AuthCheckerTests.cs @@ -1115,6 +1115,96 @@ namespace ScrewTurn.Wiki.Tests { Actions.ForPages.ModifyPage, "User", new string[] { "Group" }), "Permission should be denied"); } + [Test] + public void CheckActionForPage_GrantGroupFullControl_DenyGroupExplicitNamespace_ExceptReadPages() { + List entries = new List(); + entries.Add(new AclEntry(Actions.ForGlobals.ResourceMasterPrefix, Actions.FullControl, "G.Group", Value.Grant)); + entries.Add(new AclEntry(Actions.ForNamespaces.ResourceMasterPrefix + "NS1", Actions.ForNamespaces.ReadPages, "G.Group", Value.Grant)); + entries.Add(new AclEntry(Actions.ForNamespaces.ResourceMasterPrefix + "NS1", Actions.FullControl, "G.Group", Value.Deny)); + + Collectors.SettingsProvider = MockProvider(entries); + Assert.IsFalse(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ModifyPage, "User", new string[] { "Group" }), "Permission should be denied"); + Assert.IsTrue(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ReadPage, "User", new string[] { "Group" }), "Permission should be granted"); + } + + [Test] + public void CheckActionForPage_GrantGroupFullControl_DenyGroupNamespaceEscalator_ExceptReadPages() { + List entries = new List(); + entries.Add(new AclEntry(Actions.ForGlobals.ResourceMasterPrefix, Actions.FullControl, "G.Group", Value.Grant)); + entries.Add(new AclEntry(Actions.ForNamespaces.ResourceMasterPrefix, Actions.ForNamespaces.ReadPages, "G.Group", Value.Grant)); + entries.Add(new AclEntry(Actions.ForNamespaces.ResourceMasterPrefix, Actions.FullControl, "G.Group", Value.Deny)); + + Collectors.SettingsProvider = MockProvider(entries); + Assert.IsFalse(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ModifyPage, "User", new string[] { "Group" }), "Permission should be denied"); + Assert.IsTrue(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ReadPage, "User", new string[] { "Group" }), "Permission should be granted"); + } + + [Test] + public void CheckActionForPage_DenyGroupFullControl_GrantGroupExplicitNamespace() { + List entries = new List(); + entries.Add(new AclEntry(Actions.ForGlobals.ResourceMasterPrefix, Actions.FullControl, "G.Group", Value.Deny)); + entries.Add(new AclEntry(Actions.ForNamespaces.ResourceMasterPrefix + "NS1", Actions.FullControl, "G.Group", Value.Grant)); + + Collectors.SettingsProvider = MockProvider(entries); + Assert.IsTrue(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ModifyPage, "User", new string[] { "Group" }), "Permission should be granted"); + Assert.IsTrue(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ReadPage, "User", new string[] { "Group" }), "Permission should be granted"); + } + + [Test] + public void CheckActionForPage_DenyGroupFullControl_GrantGroupNamespaceEscalator() { + List entries = new List(); + entries.Add(new AclEntry(Actions.ForGlobals.ResourceMasterPrefix, Actions.FullControl, "G.Group", Value.Deny)); + entries.Add(new AclEntry(Actions.ForNamespaces.ResourceMasterPrefix, Actions.FullControl, "G.Group", Value.Grant)); + + Collectors.SettingsProvider = MockProvider(entries); + Assert.IsTrue(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ModifyPage, "User", new string[] { "Group" }), "Permission should be granted"); + Assert.IsTrue(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ReadPage, "User", new string[] { "Group" }), "Permission should be granted"); + } + + [Test] + public void CheckActionForPage_DenyGroupFullControl_GrantGroupReadPagesExplicitNamespace() { + List entries = new List(); + entries.Add(new AclEntry(Actions.ForGlobals.ResourceMasterPrefix, Actions.FullControl, "G.Group", Value.Deny)); + entries.Add(new AclEntry(Actions.ForNamespaces.ResourceMasterPrefix + "NS1", Actions.ForNamespaces.ReadPages, "G.Group", Value.Grant)); + + Collectors.SettingsProvider = MockProvider(entries); + Assert.IsFalse(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ModifyPage, "User", new string[] { "Group" }), "Permission should be denied"); + Assert.IsTrue(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ReadPage, "User", new string[] { "Group" }), "Permission should be granted"); + } + + [Test] + public void CheckActionForPage_DenyGroupFullControl_GrantGroupReadPagesNamespaceEscalator() { + List entries = new List(); + entries.Add(new AclEntry(Actions.ForGlobals.ResourceMasterPrefix, Actions.FullControl, "G.Group", Value.Deny)); + entries.Add(new AclEntry(Actions.ForNamespaces.ResourceMasterPrefix, Actions.ForNamespaces.ReadPages, "G.Group", Value.Grant)); + + Collectors.SettingsProvider = MockProvider(entries); + Assert.IsFalse(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ModifyPage, "User", new string[] { "Group" }), "Permission should be denied"); + Assert.IsTrue(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ReadPage, "User", new string[] { "Group" }), "Permission should be granted"); + } + + [Test] + public void CheckActionForPage_DenyGroupFullControl_GrantGroupReadPagesExplicitNamespaceLocalEscalator() { + List entries = new List(); + entries.Add(new AclEntry(Actions.ForGlobals.ResourceMasterPrefix, Actions.FullControl, "G.Group", Value.Deny)); + entries.Add(new AclEntry(Actions.ForNamespaces.ResourceMasterPrefix + "NS1", Actions.ForNamespaces.ManagePages, "G.Group", Value.Grant)); + + Collectors.SettingsProvider = MockProvider(entries); + Assert.IsTrue(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ModifyPage, "User", new string[] { "Group" }), "Permission should be granted"); + Assert.IsTrue(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ReadPage, "User", new string[] { "Group" }), "Permission should be granted"); + } + + [Test] + public void CheckActionForPage_DenyGroupFullControl_GrantGroupReadPagesNamespaceEscalatorLocalEscalator() { + List entries = new List(); + entries.Add(new AclEntry(Actions.ForGlobals.ResourceMasterPrefix, Actions.FullControl, "G.Group", Value.Deny)); + entries.Add(new AclEntry(Actions.ForNamespaces.ResourceMasterPrefix, Actions.ForNamespaces.ManagePages, "G.Group", Value.Grant)); + + Collectors.SettingsProvider = MockProvider(entries); + Assert.IsTrue(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ModifyPage, "User", new string[] { "Group" }), "Permission should be granted"); + Assert.IsTrue(AuthChecker.CheckActionForPage(new PageInfo(NameTools.GetFullName("NS1", "Page"), null, DateTime.Now), Actions.ForPages.ReadPage, "User", new string[] { "Group" }), "Permission should be granted"); + } + [Test] public void CheckActionForPage_GrantUserRootEscalator_DenyGroupExplicitPage() { List entries = new List(); diff --git a/Core/AuthChecker.cs b/Core/AuthChecker.cs index eb3f266..97e9409 100644 --- a/Core/AuthChecker.cs +++ b/Core/AuthChecker.cs @@ -38,11 +38,15 @@ namespace ScrewTurn.Wiki { if(currentUser == "admin") return true; + return LocalCheckActionForGlobals(action, currentUser, groups) == Authorization.Granted; + } + + private static Authorization LocalCheckActionForGlobals(string action, string currentUser, string[] groups) { AclEntry[] entries = SettingsProvider.AclManager.RetrieveEntriesForResource(Actions.ForGlobals.ResourceMasterPrefix); Authorization auth = AclEvaluator.AuthorizeAction(Actions.ForGlobals.ResourceMasterPrefix, action, AuthTools.PrepareUsername(currentUser), AuthTools.PrepareGroups(groups), entries); - return auth == Authorization.Granted; + return auth; } /// @@ -52,8 +56,9 @@ namespace ScrewTurn.Wiki { /// The action the user is attempting to perform. /// The current user. /// The groups the user is member of. + /// true is the method is called in a local escalator process. /// true if the action is allowed, false otherwise. - public static bool CheckActionForNamespace(NamespaceInfo nspace, string action, string currentUser, string[] groups) { + public static bool CheckActionForNamespace(NamespaceInfo nspace, string action, string currentUser, string[] groups, bool localEscalator = false) { if(action == null) throw new ArgumentNullException("action"); if(action.Length == 0) throw new ArgumentException("Action cannot be empty", "action"); if(!AuthTools.IsValidAction(action, Actions.ForNamespaces.All)) throw new ArgumentException("Invalid action", "action"); @@ -65,6 +70,10 @@ namespace ScrewTurn.Wiki { if(currentUser == "admin") return true; + return LocalCheckActionForNamespace(nspace, action, currentUser, groups, localEscalator) == Authorization.Granted; + } + + private static Authorization LocalCheckActionForNamespace(NamespaceInfo nspace, string action, string currentUser, string[] groups, bool localEscalator = false) { string namespaceName = nspace != null ? nspace.Name : ""; AclEntry[] entries = SettingsProvider.AclManager.RetrieveEntriesForResource( @@ -73,33 +82,33 @@ namespace ScrewTurn.Wiki { Authorization auth = AclEvaluator.AuthorizeAction(Actions.ForNamespaces.ResourceMasterPrefix + namespaceName, action, AuthTools.PrepareUsername(currentUser), AuthTools.PrepareGroups(groups), entries); - if(auth != Authorization.Unknown) return auth == Authorization.Granted; + if(localEscalator || auth != Authorization.Unknown) return auth; // Try local escalators string[] localEscalators = null; if(Actions.ForNamespaces.LocalEscalators.TryGetValue(action, out localEscalators)) { foreach(string localAction in localEscalators) { - bool authorized = CheckActionForNamespace(nspace, localAction, currentUser, groups); - if(authorized) return true; + Authorization authorization = LocalCheckActionForNamespace(nspace, localAction, currentUser, groups, true); + if(authorization != Authorization.Unknown) return authorization; } } // Try root escalation if(nspace != null) { - bool authorized = CheckActionForNamespace(null, action, currentUser, groups); - if(authorized) return true; + Authorization authorization = LocalCheckActionForNamespace(null, action, currentUser, groups); + if(authorization != Authorization.Unknown) return authorization; } // Try global escalators string[] globalEscalators = null; if(Actions.ForNamespaces.GlobalEscalators.TryGetValue(action, out globalEscalators)) { foreach(string globalAction in globalEscalators) { - bool authorized = CheckActionForGlobals(globalAction, currentUser, groups); - if(authorized) return true; + Authorization authorization = LocalCheckActionForGlobals(globalAction, currentUser, groups); + if(authorization != Authorization.Unknown) return authorization; } } - return false; + return Authorization.Unknown; } /// @@ -109,8 +118,9 @@ namespace ScrewTurn.Wiki { /// The action the user is attempting to perform. /// The current user. /// The groups the user is member of. + /// true is the method is called in a local escalator process. /// true if the action is allowed, false otherwise. - public static bool CheckActionForPage(PageInfo page, string action, string currentUser, string[] groups) { + public static bool CheckActionForPage(PageInfo page, string action, string currentUser, string[] groups, bool localEscalator = false) { if(page == null) throw new ArgumentNullException("page"); if(action == null) throw new ArgumentNullException("action"); @@ -124,18 +134,22 @@ namespace ScrewTurn.Wiki { if(currentUser == "admin") return true; + return LocalCheckActionForPage(page, action, currentUser, groups, localEscalator) == Authorization.Granted; + } + + private static Authorization LocalCheckActionForPage(PageInfo page, string action, string currentUser, string[] groups, bool localEscalator = false) { AclEntry[] entries = SettingsProvider.AclManager.RetrieveEntriesForResource(Actions.ForPages.ResourceMasterPrefix + page.FullName); Authorization auth = AclEvaluator.AuthorizeAction(Actions.ForPages.ResourceMasterPrefix + page.FullName, action, AuthTools.PrepareUsername(currentUser), AuthTools.PrepareGroups(groups), entries); - if(auth != Authorization.Unknown) return auth == Authorization.Granted; + if(localEscalator || auth != Authorization.Unknown) return auth; // Try local escalators string[] localEscalators = null; if(Actions.ForPages.LocalEscalators.TryGetValue(action, out localEscalators)) { foreach(string localAction in localEscalators) { - bool authorized = CheckActionForPage(page, localAction, currentUser, groups); - if(authorized) return true; + Authorization authorization = LocalCheckActionForPage(page, localAction, currentUser, groups, true); + if(authorization != Authorization.Unknown) return authorization; } } @@ -145,8 +159,14 @@ namespace ScrewTurn.Wiki { NamespaceInfo ns = string.IsNullOrEmpty(nsName) ? null : new NamespaceInfo(nsName, null, null); if(Actions.ForPages.NamespaceEscalators.TryGetValue(action, out namespaceEscalators)) { foreach(string namespaceAction in namespaceEscalators) { - bool authorized = CheckActionForNamespace(ns, namespaceAction, currentUser, groups); - if(authorized) return true; + Authorization authorization = LocalCheckActionForNamespace(ns, namespaceAction, currentUser, groups, true); + if(authorization != Authorization.Unknown) return authorization; + + // Try root escalation + if(ns != null) { + authorization = LocalCheckActionForNamespace(null, namespaceAction, currentUser, groups, true); + if(authorization != Authorization.Unknown) return authorization; + } } } @@ -154,12 +174,12 @@ namespace ScrewTurn.Wiki { string[] globalEscalators = null; if(Actions.ForPages.GlobalEscalators.TryGetValue(action, out globalEscalators)) { foreach(string globalAction in globalEscalators) { - bool authorized = CheckActionForGlobals(globalAction, currentUser, groups); - if(authorized) return true; + Authorization authorization = LocalCheckActionForGlobals(globalAction, currentUser, groups); + if(authorization != Authorization.Unknown) return authorization; } } - return false; + return Authorization.Unknown; } ///