Repository navigation
GH Issue #1445: Check wiki TOC target container perms before render #8127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
9335293
89bf47a
a93c663
78631a0
10ebad7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,14 +16,26 @@ | |
|
|
||
| package org.labkey.wiki; | ||
|
|
||
| import jakarta.servlet.http.HttpServletResponse; | ||
| import org.jetbrains.annotations.NotNull; | ||
| import org.jetbrains.annotations.Nullable; | ||
| import org.json.JSONObject; | ||
| import org.junit.Before; | ||
| import org.junit.Test; | ||
| import org.labkey.api.data.Container; | ||
| import org.labkey.api.data.ContainerManager; | ||
| import org.labkey.api.security.Group; | ||
| import org.labkey.api.security.MutableSecurityPolicy; | ||
| import org.labkey.api.security.SecurityManager; | ||
| import org.labkey.api.security.SecurityPolicyManager; | ||
| import org.labkey.api.security.User; | ||
| import org.labkey.api.security.permissions.AbstractContainerScopingTest; | ||
| import org.labkey.api.security.permissions.AdminPermission; | ||
| import org.labkey.api.security.permissions.InsertPermission; | ||
| import org.labkey.api.security.permissions.ReadPermission; | ||
| import org.labkey.api.security.permissions.UpdatePermission; | ||
| import org.labkey.api.security.roles.ReaderRole; | ||
| import org.labkey.api.security.roles.SubmitterRole; | ||
| import org.labkey.api.util.DOM; | ||
| import org.labkey.api.util.HtmlString; | ||
| import org.labkey.api.util.LinkBuilder; | ||
|
|
@@ -36,8 +48,10 @@ | |
| import org.labkey.api.view.ViewContext; | ||
| import org.labkey.api.view.menu.NavTreeMenu; | ||
| import org.labkey.api.view.template.ClientDependency; | ||
| import org.labkey.api.wiki.WikiRendererType; | ||
| import org.labkey.api.writer.HtmlWriter; | ||
| import org.labkey.wiki.model.Wiki; | ||
| import org.springframework.mock.web.MockHttpServletResponse; | ||
|
|
||
| import java.util.LinkedHashSet; | ||
| import java.util.List; | ||
|
|
@@ -55,6 +69,7 @@ public class WikiTOC extends NavTreeMenu | |
| { | ||
| private String _selectedLink; | ||
| private final Container _cToc; | ||
| private final boolean _canRead; | ||
|
|
||
| public WikiTOC(ViewContext context) | ||
| { | ||
|
|
@@ -90,10 +105,16 @@ public WikiTOC(ViewContext context, @Nullable Portal.WebPart part) | |
| if (null == _cToc) | ||
| throw new NotFoundException("Could not find container for id: \"" + id + "\""); | ||
|
|
||
| setId(getNavTreeId(_cToc)); | ||
| setElements(context, getNavTree()); | ||
| setCollapsible(false); | ||
| setNavMenu(createNavMenu()); | ||
| // Render the no-permission message in renderView() rather than throwing, to match wiki webpart | ||
| _canRead = _cToc.hasPermission(context.getUser(), ReadPermission.class); | ||
|
|
||
| if (_canRead) | ||
| { | ||
| setId(getNavTreeId(_cToc)); | ||
| setElements(context, getNavTree()); | ||
| setCollapsible(false); | ||
| setNavMenu(createNavMenu()); | ||
| } | ||
| } | ||
|
|
||
| private NavTree createNavMenu() | ||
|
|
@@ -185,6 +206,14 @@ public LinkedHashSet<ClientDependency> getClientDependencies() | |
| protected void renderView(Object model, HtmlWriter out) | ||
| { | ||
| ViewContext context = getViewContext(); | ||
| User user = context.getUser(); | ||
|
|
||
| // Check read permission in target container before rendering anything, GH Issue 1445 | ||
| if (!_canRead) | ||
| { | ||
| out.write(WikiManager.get().getNoPermissionsMessage(user)); | ||
| return; | ||
| } | ||
|
|
||
| boolean isInWebPart = isInWebPart(context); | ||
|
|
||
|
|
@@ -316,4 +345,65 @@ private boolean isInWebPart(ViewContext context) | |
| //is page being rendered in web part or in module? | ||
| return context.getActionURL().getController().equalsIgnoreCase("Project"); | ||
| } | ||
|
|
||
| public static class TestCase extends AbstractContainerScopingTest | ||
| { | ||
| private static final String PAGE_TITLE = "WikiTocTargetPage"; | ||
| private static final String NEW_MENU_ITEM = ">New</a>"; | ||
|
|
||
| private Container _host; | ||
| private Container _target; | ||
|
|
||
| @Before | ||
| public void createFolders() | ||
| { | ||
| _host = createContainer("Host"); | ||
| _target = createContainer("Target"); | ||
| WikiManager.get().insertWiki(getAdmin(), _target, "tocPage", "body", WikiRendererType.HTML, PAGE_TITLE); | ||
| } | ||
|
|
||
| @Test | ||
| public void testTocRequiresReadInTargetFolder() throws Exception | ||
| { | ||
| User user = createUserInRole(_host, ReaderRole.class); | ||
| String html = renderToc(user); | ||
| assertTrue("Expected no-permission message, html was: " + html, html.contains(WikiManager.get().getNoPermissionsMessage(user).toString())); | ||
| assertFalse("Target folder's page leaked into the TOC", html.contains(PAGE_TITLE)); | ||
|
|
||
| grantRole(user, _target, ReaderRole.class); | ||
| html = renderToc(user); | ||
| assertTrue("Reader in the target folder should see its pages, html was: " + html, html.contains(PAGE_TITLE)); | ||
|
|
||
| MutableSecurityPolicy policy = new MutableSecurityPolicy(_host.getPolicy()); | ||
| policy.addRoleAssignment(SecurityManager.getGroup(Group.groupGuests), ReaderRole.class); | ||
| SecurityPolicyManager.savePolicyForTests(policy, getAdmin()); | ||
| html = renderToc(User.guest); | ||
| assertTrue("Expected guest login prompt, html was: " + html, html.contains("Please log in to see this data.")); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this use |
||
| assertFalse("Target folder's page leaked into the guest TOC", html.contains(PAGE_TITLE)); | ||
| } | ||
|
|
||
| @Test | ||
| public void testTocHidesMenuWithoutReadInTargetFolder() throws Exception | ||
| { | ||
| // Submitter has Insert but not Read, so it would otherwise get the "New" menu item | ||
| User user = createUserInRole(_host, ReaderRole.class); | ||
| grantRole(user, _target, SubmitterRole.class); | ||
| String html = renderToc(user); | ||
| assertFalse("Menu should be suppressed without read, html was: " + html, html.contains(NEW_MENU_ITEM)); | ||
|
|
||
| grantRole(user, _target, ReaderRole.class); | ||
| html = renderToc(user); | ||
| assertTrue("Insert + read in the target folder should show the \"New\" menu item, html was: " + html, html.contains(NEW_MENU_ITEM)); | ||
| } | ||
|
|
||
| private String renderToc(User user) throws Exception | ||
| { | ||
| ActionURL url = new ActionURL("project", "getWebPart", _host) | ||
| .addParameter("webpart.name", "Wiki Table of Contents") | ||
| .addParameter("webPartContainer", _target.getId()); | ||
| MockHttpServletResponse response = get(url, user); | ||
| assertStatus(HttpServletResponse.SC_OK, response); | ||
| return new JSONObject(response.getContentAsString()).getString("html"); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,31 +27,25 @@ | |
| <%@ page import="org.labkey.wiki.WikiController.VersionBean" %> | ||
| <%@ page import="org.labkey.wiki.WikiSelectManager" %> | ||
| <%@ page import="org.labkey.wiki.model.WikiVersion" %> | ||
| <%@ page import="org.labkey.wiki.WikiManager" %> | ||
| <%@ taglib prefix="labkey" uri="http://www.labkey.org/taglib" %> | ||
| <%@ page extends="org.labkey.api.jsp.JspBase" %> | ||
| <% | ||
| JspView<VersionBean> me = HttpView.currentView(); | ||
| VersionBean bean = me.getModelBean(); | ||
| User user = getUser(); | ||
| Container c = getContainer(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The unused Container import can be removed since this line was deleted and there are no other Container usages. |
||
| %> | ||
| <!--wiki--> | ||
| <table width="100%"> | ||
| <tr><td align=left colspan="2"> | ||
| <% | ||
| if (!bean.hasReadPermission) | ||
| { | ||
| if (user.isGuest()) | ||
| { | ||
| %>Please log in to see this data.<% | ||
| } | ||
| else | ||
| { | ||
| %>You do not have permission to see this data.<% | ||
| }%> | ||
| %> | ||
| <%=WikiManager.get().getNoPermissionsMessage(user)%> | ||
| </td></tr></table> | ||
|
|
||
| <%} | ||
| <% | ||
| } | ||
| else | ||
| { | ||
| HtmlString formattedHtml = bean.html; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this makes sense, but does this intentionally change the previous behavior where getQueryString() always returned null? (the parent method returned this.queryString, which was never set)