Skip to content

Commit

Permalink
fix : Administrators are added in spaces they are not members - EXO-7…
Browse files Browse the repository at this point in the history
…6387

Before this fix, platform administrators are added in chat space room for all spaces.
This problem comes from the chat login listener which get 'accessible' spaces of users.
With recents changes, accessibles spaces are spaces with template user can administrate.
User must be only added in space he is member. To fix it, we replace the call in listener to getMemberSpacesByFilter instead of getAccessibleSpaces

In addition, to fix current data, we add an Upgrade Plugin which check all space rooms and remove users which are not member of the space
  • Loading branch information
rdenarie authored Jan 17, 2025
1 parent 9fe1685 commit cfb96e4
Show file tree
Hide file tree
Showing 9 changed files with 268 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ default public void setExternalUser(String user, String isExternal) {

public void setSpaces(String user, List<SpaceBean> spaces);

public void removeUserFromSpace(String user, SpaceBean space);

public void addTeamRoom(String user, String teamRoomId);

public void addTeamUsers(String teamRoomId, List<String> users);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,10 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S
setSpaces(req, resp);
break;
}
case "/removeUserFromSpace": {
removeUserFromSpace(req, resp);
break;
}
case "/delete": {
delete(req, resp);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.exoplatform.chat.listener.ConnectionManager;
import org.exoplatform.chat.listener.GuiceManager;
import org.exoplatform.chat.model.RealTimeMessageBean;
import org.exoplatform.chat.model.SpaceBean;
import org.exoplatform.chat.model.SpaceBeans;
import org.exoplatform.chat.model.UserBean;
import org.exoplatform.chat.services.ChatException;
Expand Down Expand Up @@ -316,6 +317,25 @@ protected void setSpaces(HttpServletRequest request, HttpServletResponse respons

writeTextResponse(response, "OK");
}
protected void removeUserFromSpace(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter(USERNAME_PARAM);
String space = request.getParameter("space");
String passphrase = request.getParameter(PASSPHRASE_PARAM);
if (!checkPassphrase(passphrase)) {
writeJsonResponse(response, PASSPHRASE_DOESN_T_MATCH_MESSAGE, HttpStatus.SC_NOT_FOUND);
return;
}

try {
SpaceBean spaceBean = (SpaceBean) ChatUtils.fromString(space);
userService.removeUserFromSpace(username, spaceBean);
} catch (IOException | ClassNotFoundException e) {
LOG.warning(e.getMessage());
}

writeTextResponse(response, "OK");
}


protected void getUserFullName(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter(USERNAME_PARAM);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ default void setExternalUser(String user, String external) {
}

void setSpaces(String user, List<SpaceBean> spaces);
void removeUserFromSpace(String user, SpaceBean space);

void addTeamRoom(String user, String teamRoomId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ public void setSpaces(String user, List<SpaceBean> spaces) {
userStorage.setSpaces(user, spaces);
}

public void removeUserFromSpace(String user, SpaceBean space) {
userStorage.removeUserFromSpace(user, space);
}

public void addTeamRoom(String user, String teamRoomId) {
userStorage.addTeamRoom(user, teamRoomId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.DeleteOneModel;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -465,6 +466,26 @@ public void setSpaces(String user, List<SpaceBean> spaces) {
}
}

@Override
public void removeUserFromSpace(String user, SpaceBean space) {
String spaceRoomId =ChatUtils.getRoomId(space.getId());
MongoCollection<Document> coll = db().getCollection(M_USERS_COLLECTION);
BasicDBObject query = new BasicDBObject();
query.put(USER, user);
MongoCursor<Document> cursor = coll.find(query).cursor();
if (cursor.hasNext()) {
Document doc = cursor.next();
if (doc.containsKey(SPACES)) {
List<String> spaces = (List<String>) doc.get(SPACES);
if (spaces.contains(spaceRoomId)) {
spaces.remove(spaceRoomId);
doc.put(SPACES, spaces);
coll.replaceOne(query, doc);
}
}
}
}

@Override
public void addTeamRoom(String user, String teamRoomId) {
List<String> teamIds = new ArrayList<String>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.exoplatform.commons.utils.ListAccess;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.social.core.space.SpaceFilter;
import org.exoplatform.social.core.space.model.Space;
import org.exoplatform.social.core.space.spi.SpaceService;

Expand All @@ -56,10 +57,22 @@ public static String getUsers(String username, String token, String room) {
return callServer("users", "user=" + username + "&room=" + room + "&token=" + token);
}

public static String getUsersWithLimit(String username, String token, String room, int limit) {
return callServer("users", "user=" + username + "&room=" + room + "&token=" + token + "&limit="+limit);
}

public static String getUserCount(String username, String token, String room) {
return callServer("usersCount", "user=" + username + "&room=" + room + "&token=" + token);
}

public static String getRoom(String username, String token, String room) {
return callServer("getRoom", "user=" + username + "&room=" + room + "&targetUser=" + room + "&token=" + token + "&withDetail=true");
}

public static String getSpaceRoom(String username, String token, String spaceName) {
return callServer("getRoom", "user=" + username + "&targetUser=" + spaceName + "&type=space-id&token=" + token + "&withDetail=true");
}

public static String getUserFullName(String username) {
return callServer("getUserFullName", "username=" + username);
}
Expand Down Expand Up @@ -114,7 +127,7 @@ public static String getToken(String username) {
public static void saveSpaces(String username) {
try {
SpaceService spaceService = CommonsUtils.getService(SpaceService.class);
ListAccess<Space> spacesListAccess = spaceService.getAccessibleSpacesWithListAccess(username);
ListAccess<Space> spacesListAccess = spaceService.getMemberSpacesByFilter(username,new SpaceFilter());
List<Space> spaces = Arrays.asList(spacesListAccess.load(0, spacesListAccess.getSize()));
ArrayList<SpaceBean> beans = new ArrayList<>();
for (Space space : spaces) {
Expand All @@ -132,6 +145,25 @@ public static void saveSpaces(String username) {
}
}

public static void removeUserFromSpace(String username, String spaceId) {
try {
SpaceService spaceService = CommonsUtils.getService(SpaceService.class);
Space space = spaceService.getSpaceById(spaceId);
if (space != null) {
SpaceBean spaceBean = new SpaceBean();
spaceBean.setDisplayName(space.getDisplayName());
spaceBean.setGroupId(space.getGroupId());
spaceBean.setId(space.getId());
spaceBean.setShortName(space.getShortName());
spaceBean.setPrettyName(space.getPrettyName());
removeUserFromSpace(username, spaceBean);

}
} catch (Exception e) {
LOG.warn("Error while removing user from spaces'" + username + "'", e);
}
}

public static void setSpaces(String username, SpaceBeans beans) {
String params = "username=" + username;
String serSpaces = "";
Expand All @@ -145,6 +177,19 @@ public static void setSpaces(String username, SpaceBeans beans) {
postServer("setSpaces", params);
}

public static void removeUserFromSpace(String username, SpaceBean bean) {
String params = "username=" + username;
String serSpace = "";
try {
serSpace = ChatUtils.toString(bean);
serSpace = URLEncoder.encode(serSpace, "UTF-8");
} catch (IOException e) {
LOG.error("Error encoding spaces", e);
}
params += "&space=" + serSpace;
postServer("removeUserFromSpace", params);
}

private static String callServer(String serviceUri, String params) {
String serverURLBase = getServiceURL() + "/" + serviceUri;
String serviceUrl = serverURLBase + "?passphrase=" + PropertyManager.getProperty(PropertyManager.PROPERTY_PASSPHRASE) + "&"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package org.exoplatform.addons.chat.upgrade;

import org.exoplatform.addons.chat.listener.ServerBootstrap;
import org.exoplatform.commons.upgrade.UpgradePluginExecutionContext;
import org.exoplatform.commons.upgrade.UpgradeProductPlugin;
import org.exoplatform.commons.utils.ListAccess;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.portal.config.UserACL;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.social.core.space.SpaceFilter;
import org.exoplatform.social.core.space.model.Space;
import org.exoplatform.social.core.space.spi.SpaceService;
import org.exoplatform.ws.frameworks.cometd.ContinuationService;
import org.json.JSONArray;
import org.json.JSONObject;

import java.util.Arrays;

public class ChatSpacesAdministratorsUpgradePlugin extends UpgradeProductPlugin {

private static final Log log = ExoLogger.getExoLogger(ChatSpacesAdministratorsUpgradePlugin.class);

private SpaceService spaceService;
private ContinuationService continuationService;
private String superUser;
private String superUserChatToken;
private int LIMIT = 100;

public ChatSpacesAdministratorsUpgradePlugin(InitParams initParams, SpaceService spaceService,UserACL userACL, ContinuationService continuationService) {
super(initParams);
this.spaceService=spaceService;
this.continuationService=continuationService;

this.superUser = userACL.getSuperUser();
this.superUserChatToken = ServerBootstrap.getToken(this.superUser);
}

@Override
public void processUpgrade(String oldVersion, String newVersion) {
long startupTime = System.currentTimeMillis();
log.info("Start Remove Space administrator from all space chat room");

boolean chatServerStarted = false;
int nbTest = 0;
while (!chatServerStarted && nbTest<100) {
try {
Thread.sleep(1000);
} catch (Exception e2) {
//do nothing
}
nbTest++;
log.debug("Test if chatServer is running ({} times)", nbTest);
ServerBootstrap.addUser(this.superUser, this.superUserChatToken);
String result = ServerBootstrap.getStatus(this.superUser, this.superUserChatToken, this.superUser);
if (result!=null) {
chatServerStarted=true;
}
}

if (!chatServerStarted) {
throw new RuntimeException("Unable to join chatServer");
}

try {
ListAccess<Space> allSpaces = spaceService.getAllSpacesByFilter(new SpaceFilter());
int current = 0;

do {
Space[] spaces = allSpaces.load(current, LIMIT);
Arrays.stream(spaces).forEach(space -> checkSpace(space));
current+=spaces.length;
log.info("Run upgrade on {}/{} spaces",current,allSpaces.getSize());
} while (current<allSpaces.getSize());
} catch (Exception e) {
log.error("Unable to treat all spaces",e);
throw new RuntimeException(e);
}
log.info("End Remove Space administrator from all space chat room, execution time={}ms",
System.currentTimeMillis() - startupTime);

}

private void checkSpace(Space space) {
String spaceString = ServerBootstrap.getSpaceRoom(this.superUser, this.superUserChatToken, space.getId());
log.debug("Check space {}, result={}",space.getPrettyName(), spaceString);
if (spaceString != null) {
JSONObject jsonSpace = new JSONObject(spaceString);
if (jsonSpace.has("user")) {
String spaceRoomId = jsonSpace.getString("user");
String userCountInSpace = ServerBootstrap.getUserCount(this.superUser,this.superUserChatToken,spaceRoomId);
if (userCountInSpace != null) {
JSONObject jsonCountUsers = new JSONObject(userCountInSpace);
if (jsonCountUsers.has("usersCount")) {
int spaceUserCount = jsonCountUsers.getInt("usersCount");
log.debug("Space Room with name {} and id {} has {} users", spaceRoomId, space.getPrettyName(), spaceUserCount);
String usersInSpaceRoom = ServerBootstrap.getUsersWithLimit(this.superUser,this.superUserChatToken, spaceRoomId,spaceUserCount);
JSONObject users = new JSONObject(usersInSpaceRoom);
if (users.has("users")) {
checkUsers(users.getJSONArray("users"),space);
if (spaceUserCount != users.getJSONArray("users").length()) {
checkUser(space,this.superUser);
}
}
}

}
}

}
}

private void checkUsers(JSONArray users, Space space) {
for (int i=0; i<users.length();i++) {
JSONObject user = users.getJSONObject(i);
String username = user.getString("name");
checkUser(space, username);
}

}

private void checkUser(Space space, String username) {
if (!spaceService.isMember(space, username)) {
log.debug("User {} is member of space room, but not member of space {}, remove it from the space room", username, space.getPrettyName());
ServerBootstrap.removeUserFromSpace(username,space.getId());
}
}

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

}
37 changes: 36 additions & 1 deletion services/src/main/resources/conf/portal/configuration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,40 @@
</init-params>
</component-plugin>
</external-component-plugins>

<external-component-plugins>
<target-component>org.exoplatform.commons.upgrade.UpgradeProductService</target-component>
<component-plugin profiles="chat">
<name>ChatSpacesAdministratorsUpgradePlugin</name>
<set-method>addUpgradePlugin</set-method>
<type>org.exoplatform.addons.chat.upgrade.ChatSpacesAdministratorsUpgradePlugin</type>
<description>Check and fix administrators space room</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>7.0.0</value>
</value-param>
<value-param>
<name>plugin.execution.order</name>
<description>The plugin execution order</description>
<value>10</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>

0 comments on commit cfb96e4

Please sign in to comment.