/***************************************************************************
* Copyright (C) 2003-2009 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see<http://www.gnu.org/licenses/>.
***************************************************************************/
package org.exoplatform.forum.service;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.jcr.Node;
import org.exoplatform.commons.utils.CommonsUtils;
import org.exoplatform.commons.utils.ListAccess;
import org.exoplatform.forum.common.CommonUtils;
import org.exoplatform.forum.common.UserHelper;
import org.exoplatform.forum.common.cache.model.key.SimpleCacheKey;
import org.exoplatform.forum.common.jcr.KSDataLocation;
import org.exoplatform.forum.common.jcr.SessionManager;
import org.exoplatform.services.cache.CacheService;
import org.exoplatform.services.cache.ExoCache;
import org.exoplatform.services.jcr.access.AccessControlEntry;
import org.exoplatform.services.jcr.access.PermissionType;
import org.exoplatform.services.jcr.core.ExtendedNode;
import org.exoplatform.services.organization.Membership;
import org.exoplatform.services.organization.MembershipHandler;
import org.exoplatform.services.organization.MembershipTypeHandler;
import org.exoplatform.services.organization.User;
import org.exoplatform.services.organization.UserStatus;
import org.exoplatform.services.security.ConversationState;
import org.exoplatform.services.security.Identity;
import org.exoplatform.services.security.IdentityRegistry;
import org.exoplatform.services.security.MembershipEntry;
public class ForumServiceUtils {
private static final String COLON = ":".intern();
private static final String SLASH = "/".intern();
/**
* Verify if a user match user, group, membership expressions.
* This method apply for checking canView, canPost, canCreateTopic and check have permission access category with property userPrivate
*
* @param userGroupMembership is that may contain userNames or group names or membership expressions in the form MEMBERSHIPTYPE:GROUP
* @param userId userName to match against the expressions
* @return true if the user match at least one of the expressions or expressions is empty
* @throws Exception
*/
public static boolean hasPermission(String[] userGroupMembership, String userId) throws Exception {
// when userGroupMembership is empty, user has permission.
if (isPermissionEmpty(userGroupMembership)) {
return true;
}
if (CommonUtils.isEmpty(userId)) {
return false;
}
//
Identity identity = null;
ConversationState state = ConversationState.getCurrent();
if (state != null) {
identity = state.getIdentity();
if (!userId.equals(identity.getUserId())) {
IdentityRegistry identityRegistry = CommonsUtils.getService(IdentityRegistry.class);
identity = identityRegistry.getIdentity(userId);
}
}
if (identity == null) {
Collection<Membership> memberships = UserHelper.findMembershipsByUser(userId);
//
List<MembershipEntry> entries = new ArrayList<MembershipEntry>();
if (memberships != null) {
for (Membership membership : memberships) {
entries.add(new MembershipEntry(membership.getGroupId(), membership.getMembershipType()));
}
}
//
identity = new Identity(userId, entries);
}
for (String item : userGroupMembership) {
String expr = item.trim();
if (isMembershipExpression(expr)) {
String[] array = expr.split(COLON);
String membershipType = array[0];
String group = array[1];
if (identity.isMemberOf(group, membershipType)) {
return true;
}
} else if (isGroupExpression(expr)) {
String group = expr;
if (identity.isMemberOf(group)) {
return true;
}
} else {
String username = expr;
if (username.equals(userId)) {
return true;
}
}
}
return false; // no match found
}
/**
* Verify if a user is moderator of forum or not, match with user, group, membership expressions
* This method apply for checking user is moderator or not of categories/forum.
*
* @param userGroupMembership is that may contain userNames or group names
* or membership expressions in the form MEMBERSHIPTYPE:GROUP
* @param userId userName to match against the expressions
* @return true if the user match at least one of the expressions
* @throws Exception
*/
public static boolean isModerator(String[] userGroupMembership, String userId) throws Exception {
// when userGroupMembership is empty, user is not moderator.
if (isPermissionEmpty(userGroupMembership)) {
return false;
}
return hasPermission(userGroupMembership, userId);
}
/**
* Is the expression a group expression
* @param expr
* @return
*/
public static boolean isGroupExpression(String expr) {
return ((expr.indexOf(SLASH) >= 0) && !(expr.indexOf(COLON) >= 0));
}
/**
* Is the expression a membership expression (MEMBERSHIPTYPE:GROUP)
* @param expr
* @return
*/
public static boolean isMembershipExpression(String expr) {
return ((expr.indexOf(SLASH) >= 0) && (expr.indexOf(COLON) >= 0));
}
private static ListAccess<User> getUserByGroup(String group){
try {
return UserHelper.getUserHandler().findUsersByGroupId(group, UserStatus.ENABLED);
} catch (Exception e) {
return null;
}
}
/**
* Find userNames matching membership expressions
* + When membership have pattern member:/platform/users
*
* @param organizationService
* @param memberShip the membership, ex: member:/platform/users , *:/platform/users.
* @return list of users that mach at least one of the membership
* @throws Exception
*/
private static List<String> getUserByMembershipType(String memberShip) throws Exception {
List<String> users = getFromCache(new String[] { memberShip });
if (users != null) {
return users;
}
users = new ArrayList<String>();
String[] array = memberShip.trim().split(COLON);
String groupId = array[1];
String memberShipType = array[0];
//
if (MembershipTypeHandler.ANY_MEMBERSHIP_TYPE.equals(memberShipType)) {
users.addAll(getUserByGroupId(groupId));
} else {
MembershipHandler membershipHandler = UserHelper.getMembershipHandler();
ListAccess<Membership> listAccess = membershipHandler.findAllMembershipsByGroup(UserHelper.getGroupHandler().findGroupById(groupId));
Membership[] mbs = listAccess.load(0, listAccess.getSize());
for (Membership mb : mbs) {
if (!isDisableUser(mb.getUserName()) &&
(mb.getMembershipType().equals(memberShipType) || mb.getMembershipType().equals(MembershipTypeHandler.ANY_MEMBERSHIP_TYPE))) {
users.add(mb.getUserName());
}
}
}
//
storeInCache(new String[] { memberShip }, users);
return users;
}
/**
* Find usernames matching group id expressions
* @param userHandler
* @param groupId the group Id, ex: /platform/users .
* @return list of users that mach at least one of the group id
* @throws Exception
*/
private static List<String> getUserByGroupId(String groupId) throws Exception {
List<String> users = getFromCache(new String[] { groupId });
if (users != null) {
return users;
}
users = new ArrayList<String>();
ListAccess<User> pageList = getUserByGroup(groupId);
if (pageList == null){
return users;
}
User[] userArray = (User[]) pageList.load(0, pageList.getSize());
for (int i = 0; i < pageList.getSize(); i++) {
users.add(userArray[i].getUserName());
}
storeInCache(new String[]{groupId}, users);
return users;
}
/**
* Find usernames matching user, group or membership expressions
* @param userGroupMembership list that may contain usernames or group names or membership expressions in the form MEMBERSHIPTYPE:GROUP
* @return list of users that mach at least one of the userGroupMembership
* @throws Exception
*/
public static List<String> getUserPermission(String[] userGroupMembership) throws Exception {
if (isPermissionEmpty(userGroupMembership)) {
return new ArrayList<String>();
}
List<String> list = getFromCache(userGroupMembership);
if (list != null) {
return list;
}
Set<String> users = new HashSet<String>();
for (int j = 0; j < userGroupMembership.length; j++) {
String inputValue = userGroupMembership[j].trim();
if (isMembershipExpression(inputValue)) {
users.addAll(getUserByMembershipType(inputValue));
} else if (isGroupExpression(inputValue)) {
users.addAll(getUserByGroupId(inputValue));
} else if (!isDisableUser(inputValue)) {
users.add(inputValue);
}
}
storeInCache(userGroupMembership, new ArrayList<String>(users));
return new ArrayList<String>(users);
}
/**
* @param userGroupMembership
* @return
*/
private static boolean isPermissionEmpty(String[] userGroupMembership) {
if (CommonUtils.isEmpty(userGroupMembership) || (userGroupMembership.length == 1 && userGroupMembership[0].equals(" "))) {
return true;
}
return false;
}
/**
* Check user disable on forum or not.
*
* @param useId The user id of user
* @return
*/
public static boolean isDisableUser(String useId) {
try {
UserProfile profile = CommonsUtils.getService(ForumService.class).getQuickProfile(useId);
return profile == null || profile.isDisabled();
} catch (Exception e) {
return true;
}
}
/**
* Clear the ForumPermissionsUsers cache
*/
public static void clearCache() {
getCache().clearCache();
}
/**
* Store the list of user for the permission expressions in cache
* @param userGroupMembership
* @param users
* @throws Exception
*/
private static void storeInCache(String[] userGroupMembership, List<String> users) throws Exception {
ExoCache<Serializable, List<String>> cache = getCache();
Serializable cacheKey = getCacheKey(userGroupMembership);
cache.put(cacheKey, users);
}
/**
* Load a list of user for the permission expressions in cache
* @param userGroupMembership
* @return
* @throws Exception
*/
private static List<String> getFromCache(String[] userGroupMembership) {
ExoCache<Serializable, List<String>> cache = getCache();
Serializable cacheKey = getCacheKey(userGroupMembership);
return cache.get(cacheKey);
}
private static SimpleCacheKey getCacheKey(String[] userGroupMembership) {
StringBuilder sb = new StringBuilder();
for (String item : userGroupMembership) {
sb.append("#").append(item);
}
return new SimpleCacheKey(sb.toString());
}
private static ExoCache<Serializable, List<String>> getCache(){
CacheService cacheService = CommonsUtils.getService(CacheService.class);
return cacheService.getCacheInstance("user.PermissionCache");
}
public static void reparePermissions(Node node, String owner) throws Exception {
ExtendedNode extNode = (ExtendedNode) node;
if (extNode.canAddMixin("exo:privilegeable"))
extNode.addMixin("exo:privilegeable");
String[] arrayPers = { PermissionType.READ, PermissionType.ADD_NODE, PermissionType.SET_PROPERTY, PermissionType.REMOVE };
extNode.setPermission(owner, arrayPers);
List<AccessControlEntry> permsList = extNode.getACL().getPermissionEntries();
for (AccessControlEntry accessControlEntry : permsList) {
extNode.setPermission(accessControlEntry.getIdentity(), arrayPers);
}
}
public static SessionManager getSessionManager() {
KSDataLocation location = CommonsUtils.getService(KSDataLocation.class);
return location.getSessionManager();
}
}