Skip to content

Commit

Permalink
fix: Fix permissions for space notes node - EXO-68358 (#183)
Browse files Browse the repository at this point in the history
Prior to this change , note images was not accessible for space members , this issue was due to the incorrect permissions set on the space notes node during the creation process , This change is going to update the notes node permission
  • Loading branch information
sofyenne committed Jan 12, 2024
1 parent 7f228fc commit 15ea1e8
Show file tree
Hide file tree
Showing 4 changed files with 298 additions and 0 deletions.
5 changes: 5 additions & 0 deletions data-upgrade-wiki/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,10 @@
<scope>test</scope>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>org.exoplatform.jcr</groupId>
<artifactId>exo.jcr.component.ext</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package org.exoplatform.wiki.upgrade;

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;

import org.exoplatform.commons.upgrade.UpgradePluginExecutionContext;
import org.exoplatform.commons.upgrade.UpgradeProductPlugin;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.jcr.access.PermissionType;
import org.exoplatform.services.jcr.core.ExtendedNode;
import org.exoplatform.services.jcr.ext.app.SessionProviderService;
import org.exoplatform.services.jcr.ext.common.SessionProvider;
import org.exoplatform.services.jcr.impl.core.query.QueryImpl;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;

public class NotesFolderPermissionsUpgradePlugin extends UpgradeProductPlugin {

private static final Log LOG = ExoLogger.getLogger(NotesFolderPermissionsUpgradePlugin.class);

private final RepositoryService repositoryService;

private final SessionProviderService sessionProviderService;

private int notesCount;

public NotesFolderPermissionsUpgradePlugin(InitParams initParams,
RepositoryService repositoryService,
SessionProviderService sessionProviderService) {
super(initParams);
this.repositoryService = repositoryService;
this.sessionProviderService = sessionProviderService;
}

@Override
public boolean shouldProceedToUpgrade(String newVersion,
String previousGroupVersion,
UpgradePluginExecutionContext previousUpgradePluginExecution) {
int executionCount = previousUpgradePluginExecution == null ? 0 : previousUpgradePluginExecution.getExecutionCount();
return !isExecuteOnlyOnce() || executionCount == 0;
}

@Override
public void processUpgrade(String s, String s1) {
long startupTime = System.currentTimeMillis();
LOG.info("Start upgrade of space notes node permission");
SessionProvider sessionProvider = null;
try {
sessionProvider = sessionProviderService.getSystemSessionProvider(null);
Session session = sessionProvider.getSession(
repositoryService.getCurrentRepository()
.getConfiguration()
.getDefaultWorkspaceName(),
repositoryService.getCurrentRepository());
QueryManager qm = session.getWorkspace().getQueryManager();
int limit = 10, offset = 0;
String stringQuery =
"select * from nt:folder WHERE jcr:path LIKE '/Groups/spaces/%/notes'";
Query jcrQuery = qm.createQuery(stringQuery, Query.SQL);
boolean hasMoreElements = true;
while (hasMoreElements) {
((QueryImpl) jcrQuery).setOffset(offset);
((QueryImpl) jcrQuery).setLimit(limit);
NodeIterator nodeIterator = jcrQuery.execute().getNodes();
if (nodeIterator != null) {
while (nodeIterator.hasNext()) {
Node notesNode = nodeIterator.nextNode();
updateNotesNodePermissions(notesNode);
}
if (nodeIterator.getSize() < limit) {
// no more elements
hasMoreElements = false;
} else {
offset += limit;
}
}
}
LOG.info("End updating of '{}' space notes node permissions. It took {} ms.",
notesCount,
(System.currentTimeMillis() - startupTime));

} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error("An unexpected error occurs when updating notes jcr node permissions:", e);
}
} finally {
if (sessionProvider != null) {
sessionProvider.close();
}
}
}

private void updateNotesNodePermissions(Node node) {
try {
String nodePath = node.getPath();
String groupId = nodePath.substring(nodePath.indexOf("/spaces/"), nodePath.indexOf("/notes"));
if (node.canAddMixin("exo:privilegeable")) {
node.addMixin("exo:privilegeable");
}
// check if the permission is equal to the group id without the *:
boolean isWrongPermission = ((ExtendedNode) node).getACL()
.getPermissionEntries()
.stream()
.anyMatch(accessControlEntry -> accessControlEntry.getIdentity()
.equals(groupId));
if (isWrongPermission) {
// remove the wrong permission
((ExtendedNode) node).removePermission(groupId);
// add the correct space permission
((ExtendedNode) node).setPermission("*:"
+ groupId, new String[] { PermissionType.READ, PermissionType.ADD_NODE, PermissionType.SET_PROPERTY });
node.save();
this.notesCount += 1;
NodeIterator nodeIterator = node.getNodes();
if (nodeIterator.hasNext()) {
updateNotesNodePermissions(nodeIterator.nextNode());
}
}
} catch (RepositoryException e) {
if (LOG.isErrorEnabled()) {
LOG.error("An unexpected error occurs when updating notes jcr node permissions:", e);
}
}
}
}
34 changes: 34 additions & 0 deletions data-upgrade-wiki/src/main/resources/conf/portal/configuration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,40 @@
</value-param>
</init-params>
</component-plugin>

<component-plugin profiles="notes">
<name>NotesFolderPermissionsUpgradePlugin</name>
<set-method>addUpgradePlugin</set-method>
<type>org.exoplatform.wiki.upgrade.NotesFolderPermissionsUpgradePlugin</type>
<description>update the notes node permissions</description>
<init-params>
<value-param>
<name>product.group.id</name>
<description>The groupId of the product</description>
<value>org.exoplatform.platform</value>
</value-param>
<value-param>
<name>plugin.upgrade.target.version</name>
<description>The plugin target version of selected groupId</description>
<value>6.5.1</value>
</value-param>
<value-param>
<name>plugin.execution.order</name>
<description>The plugin execution order</description>
<value>130</value>
</value-param>
<value-param>
<name>plugin.upgrade.execute.once</name>
<description>The plugin must be executed only once</description>
<value>true</value>
</value-param>
<value-param>
<name>plugin.upgrade.async.execution</name>
<description>The plugin will be executed in an asynchronous mode</description>
<value>true</value>
</value-param>
</init-params>
</component-plugin>
</external-component-plugins>
</configuration>

Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package org.exoplatform.wiki.upgrade;

import static org.exoplatform.services.jcr.impl.Constants.EXO_PRIVILEGEABLE;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;

import java.util.List;

import javax.jcr.NodeIterator;
import javax.jcr.Session;
import javax.jcr.Workspace;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import org.exoplatform.container.xml.InitParams;
import org.exoplatform.container.xml.ValueParam;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.jcr.access.AccessControlEntry;
import org.exoplatform.services.jcr.access.AccessControlList;
import org.exoplatform.services.jcr.access.PermissionType;
import org.exoplatform.services.jcr.config.RepositoryEntry;
import org.exoplatform.services.jcr.core.ExtendedNode;
import org.exoplatform.services.jcr.core.ManageableRepository;
import org.exoplatform.services.jcr.ext.app.SessionProviderService;
import org.exoplatform.services.jcr.ext.common.SessionProvider;
import org.exoplatform.services.jcr.impl.core.query.QueryImpl;

@RunWith(MockitoJUnitRunner.class)
public class NotesFolderPermissionsUpgradePluginTest {

@Mock
RepositoryService repositoryService;

@Mock
ManageableRepository repository;

@Mock
RepositoryEntry repositoryEntry;

@Mock
Session session;

@Mock
SessionProviderService sessionProviderService;

@Mock
SessionProvider sessionProvider;

@Test
public void NotesFolderPermissionsUpgradePluginTest() throws Exception {
InitParams initParams = new InitParams();
ValueParam valueParam = new ValueParam();
valueParam.setName("product.group.id");
valueParam.setValue("org.exoplatform.news");

when(sessionProviderService.getSystemSessionProvider(any())).thenReturn(sessionProvider);
when(repositoryService.getCurrentRepository()).thenReturn(repository);
when(repository.getConfiguration()).thenReturn(repositoryEntry);
when(sessionProvider.getSession(any(), any())).thenReturn(session);
QueryManager qm = mock(QueryManager.class);
Workspace workSpace = mock(Workspace.class);
when(session.getWorkspace()).thenReturn(workSpace);
when(workSpace.getQueryManager()).thenReturn(qm);
Query query = mock(QueryImpl.class);
when(qm.createQuery(anyString(), anyString())).thenReturn(query);
QueryResult queryResult = mock(QueryResult.class);
when(query.execute()).thenReturn(queryResult);
NodeIterator nodeIterator = mock(NodeIterator.class);
when(queryResult.getNodes()).thenReturn(nodeIterator);
when(nodeIterator.hasNext()).thenReturn(true, false);
ExtendedNode notesNode = mock(ExtendedNode.class);
when(notesNode.getPath()).thenReturn("Group/spaces/test/notes");
when(nodeIterator.nextNode()).thenReturn(notesNode);
AccessControlList accessControlList = mock(AccessControlList.class);
when(notesNode.getACL()).thenReturn(accessControlList);
AccessControlEntry accessControlEntry = new AccessControlEntry("/spaces/test", "read");
when(accessControlList.getPermissionEntries()).thenReturn(List.of(accessControlEntry));
NodeIterator imagesNodeIterator = mock(NodeIterator.class);
when(notesNode.getNodes()).thenReturn(imagesNodeIterator);
when(imagesNodeIterator.hasNext()).thenReturn(true, false);
ExtendedNode imagesNode = mock(ExtendedNode.class);
when(imagesNodeIterator.nextNode()).thenReturn(imagesNode);
when(imagesNode.getPath()).thenReturn("Group/spaces/test/notes/images");
when(imagesNode.getNodes()).thenReturn(imagesNodeIterator);
when(imagesNode.getACL()).thenReturn(accessControlList);

// when
NotesFolderPermissionsUpgradePlugin notesFolderPermissionsUpgradePlugin =
new NotesFolderPermissionsUpgradePlugin(initParams,
repositoryService,
sessionProviderService);
notesFolderPermissionsUpgradePlugin.processUpgrade(null, null);
// then
verify(notesNode, times(1)).removePermission("/spaces/test");
verify(notesNode,
times(1)).setPermission("*:/spaces/test",
new String[] { PermissionType.READ, PermissionType.ADD_NODE, PermissionType.SET_PROPERTY });
verify(notesNode, times(1)).save();

verify(imagesNode, times(1)).removePermission("/spaces/test");
verify(imagesNode,
times(1)).setPermission("*:/spaces/test",
new String[] { PermissionType.READ, PermissionType.ADD_NODE, PermissionType.SET_PROPERTY });
verify(imagesNode, times(1)).save();
//
accessControlEntry = new AccessControlEntry("*:/spaces/test", "read");
when(accessControlList.getPermissionEntries()).thenReturn(List.of(accessControlEntry));
when(nodeIterator.hasNext()).thenReturn(true, false);
notesFolderPermissionsUpgradePlugin.processUpgrade(null, null);
// then
// no invocation with the correct permission
verify(notesNode,
atLeast(0)).setPermission("*:/spaces/test",
new String[] { PermissionType.READ, PermissionType.ADD_NODE, PermissionType.SET_PROPERTY });
verify(notesNode, atLeast(0)).save();


}
}

0 comments on commit 15ea1e8

Please sign in to comment.