/* This file is part of Cyclos (www.cyclos.org). A project of the Social Trade Organisation (www.socialtrade.org). Cyclos is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Cyclos 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 Cyclos; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package nl.strohalm.cyclos.utils.access; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import nl.strohalm.cyclos.access.AdminAdminPermission; import nl.strohalm.cyclos.access.AdminMemberPermission; import nl.strohalm.cyclos.access.AdminSystemPermission; import nl.strohalm.cyclos.access.BasicPermission; import nl.strohalm.cyclos.access.BrokerPermission; import nl.strohalm.cyclos.access.MemberPermission; import nl.strohalm.cyclos.access.Module; import nl.strohalm.cyclos.access.ModuleType; import nl.strohalm.cyclos.access.OperatorPermission; import nl.strohalm.cyclos.access.Permission; import nl.strohalm.cyclos.entities.Entity; import nl.strohalm.cyclos.entities.groups.AdminGroup; import nl.strohalm.cyclos.entities.groups.BrokerGroup; import nl.strohalm.cyclos.entities.groups.Group; import nl.strohalm.cyclos.entities.groups.MemberGroup; import nl.strohalm.cyclos.entities.groups.OperatorGroup; import nl.strohalm.cyclos.exceptions.PermissionDeniedException; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.WordUtils; /** * Contains utility methods to manipulate and check permissions * * @author luis */ public class PermissionHelper { private static final char[] NAME_DELIMITERS = new char[] { '_' }; private static Map<String, Class<?>> permissionsBySimpleName; static { permissionsBySimpleName = new HashMap<String, Class<?>>(); permissionsBySimpleName.put(BasicPermission.class.getSimpleName(), BasicPermission.class); permissionsBySimpleName.put(AdminSystemPermission.class.getSimpleName(), AdminSystemPermission.class); permissionsBySimpleName.put(AdminAdminPermission.class.getSimpleName(), AdminAdminPermission.class); permissionsBySimpleName.put(AdminMemberPermission.class.getSimpleName(), AdminMemberPermission.class); permissionsBySimpleName.put(MemberPermission.class.getSimpleName(), MemberPermission.class); permissionsBySimpleName.put(OperatorPermission.class.getSimpleName(), OperatorPermission.class); permissionsBySimpleName.put(BrokerPermission.class.getSimpleName(), BrokerPermission.class); } /** * Throws a {@link PermissionDeniedException} allowed is empty or not contains the given element */ public static <T> void checkContains(final Collection<? super T> allowed, final T element) { if (allowed == null || !allowed.contains(element)) { throw new PermissionDeniedException(); } } /** * Throws a {@link PermissionDeniedException} allowed is empty or not contains the given element */ public static void checkEquals(final Object expected, final Object actual) { if (!ObjectUtils.equals(expected, actual)) { throw new PermissionDeniedException(); } } /** * Same as {@link checkSelection} but not supporting an empty collection for the allowed elements. * @see #checkSelection(Collection, Collection, boolean) */ public static <T> Collection<T> checkSelection(final Collection<T> allowed, final Collection<T> selection) { return checkSelection(allowed, selection, false); } /** * Used for query filter semantics with collections.<br> * Given a collection with the selected elements and another one with the allowed elements:<br> * If the allowed elements are empty (and empty for the allowed is not supported) it throws a PermissionDeniedException. Else, if elements is * empty, then allowed is returned. Otherwise, the selected elements must be contained in the allowed collection. */ public static <T> Collection<T> checkSelection(final Collection<T> allowed, final Collection<T> selection, final boolean isEmptyAllowedSupported) { if (CollectionUtils.isEmpty(allowed)) { if (!isEmptyAllowedSupported || CollectionUtils.isNotEmpty(selection)) { throw new PermissionDeniedException(); } else { return null; } } if (CollectionUtils.isEmpty(selection)) { return allowed; } if (!allowed.containsAll(selection)) { throw new PermissionDeniedException(); } return selection; } /** * Finds (by name) the specified permission as a valid value in the permission enum. * @return the permission if found otherwise null. */ public static <T extends Enum<T>> Permission find(final Permission perm, final Class<T> enumType) { try { final T enumItem = Enum.<T> valueOf(enumType, perm.name()); return (Permission) enumItem; } catch (final IllegalArgumentException e) { return null; } } public static Collection<? extends Entity> getAllowedValues(final Group group, final Permission permission) { Collection<? extends Entity> current; final Class<?> clazz = permission.getClass(); if (clazz == BrokerPermission.class) { current = getCurrentValues((BrokerGroup) group, (BrokerPermission) permission); } else if (clazz == MemberPermission.class) { current = getCurrentValues((MemberGroup) group, (MemberPermission) permission); } else if (clazz == OperatorPermission.class) { current = getCurrentValues((OperatorGroup) group, (OperatorPermission) permission); } else if (clazz == AdminAdminPermission.class) { current = getCurrentValues((AdminGroup) group, (AdminAdminPermission) permission); } else if (clazz == AdminMemberPermission.class) { current = getCurrentValues((AdminGroup) group, (AdminMemberPermission) permission); } else if (clazz == AdminSystemPermission.class) { current = getCurrentValues((AdminGroup) group, (AdminSystemPermission) permission); } else { throw new IllegalArgumentException("Unsupported permission class: " + clazz); } return current; } /** * @param groupNature the group's nature * @return a collection of permissions having a relationship to its possible values according to the specified group's nature */ public static Collection<Permission> getMultivaluedPermissions(final Group.Nature groupNature) { final Collection<Permission> list = new ArrayList<Permission>(); for (final ModuleType moduleType : ModuleType.getModuleTypes(groupNature)) { for (final Module module : moduleType.getModules()) { for (final Permission permission : module.getPermissions()) { addListPermission(list, permission); } } } return Collections.unmodifiableCollection(list); } @SuppressWarnings({ "unchecked", "rawtypes" }) public static Permission getPermission(final String qualifiedPermissionName) { final String[] valueParts = StringUtils.split(qualifiedPermissionName, "."); final Class permissionClass = permissionsBySimpleName.get(valueParts[0]); if (permissionClass == null) { throw new IllegalArgumentException("Invalid permission class simple name: " + valueParts[0]); } return (Permission) Enum.valueOf(permissionClass, valueParts[1]); } public static String getQualifiedPermissionName(final Permission permission) { return permission.getClass().getSimpleName() + "." + permission.name(); } public static String getValue(final Module module) { return process(getValue(module.name())); } public static String getValue(final Permission permission) { final String prefix = getValue(permission.getModule().name()); String suffix = getValue(permission.name()); final String[] parts = suffix.split("\\_"); // Remove the redundant part from the suffix for (int i = 0; i < parts.length; i++) { final StringBuilder sb = new StringBuilder(); for (int j = 0; j <= i; j++) { if (sb.length() > 0) { sb.append('_'); } sb.append(parts[j]); } if (prefix.endsWith(sb.toString())) { suffix = suffix.substring(sb.length()); if (suffix.startsWith("_")) { suffix = suffix.substring(1); } break; } } return process(prefix) + "." + process(suffix); } private static void addListPermission(final Collection<Permission> list, final Permission permission) { if (permission.relationship() != null) { list.add(permission); } } private static Collection<? extends Entity> getCurrentValues(final AdminGroup adminGroup, final AdminAdminPermission permission) { Collection<? extends Entity> current; switch (permission) { case RECORDS_CREATE: current = adminGroup.getCreateAdminRecordTypes(); break; case RECORDS_DELETE: current = adminGroup.getDeleteAdminRecordTypes(); break; case RECORDS_MODIFY: current = adminGroup.getModifyAdminRecordTypes(); break; case RECORDS_VIEW: current = adminGroup.getViewAdminRecordTypes(); break; default: throw new IllegalArgumentException(String.format("Unsupported list permission: %1$s.%2$s", permission.getClass().getSimpleName(), permission)); } return current; } private static Collection<? extends Entity> getCurrentValues(final AdminGroup adminGroup, final AdminMemberPermission permission) { Collection<? extends Entity> current; switch (permission) { case MEMBERS_VIEW: current = adminGroup.getManagesGroups(); break; case DOCUMENTS_DETAILS: current = adminGroup.getDocuments(); break; case GUARANTEES_REGISTER_GUARANTEES: current = adminGroup.getGuaranteeTypes(); break; case LOANS_GRANT: current = adminGroup.getTransferTypes(); break; case MESSAGES_VIEW: current = adminGroup.getMessageCategories(); break; case PAYMENTS_CHARGEBACK: current = adminGroup.getChargebackTransferTypes(); break; case PAYMENTS_PAYMENT: current = adminGroup.getTransferTypes(); break; case PAYMENTS_PAYMENT_AS_MEMBER_TO_MEMBER: current = adminGroup.getTransferTypesAsMember(); break; case PAYMENTS_PAYMENT_AS_MEMBER_TO_SELF: current = adminGroup.getTransferTypesAsMember(); break; case PAYMENTS_PAYMENT_AS_MEMBER_TO_SYSTEM: current = adminGroup.getTransferTypesAsMember(); break; case RECORDS_CREATE: current = adminGroup.getCreateMemberRecordTypes(); break; case RECORDS_DELETE: current = adminGroup.getDeleteMemberRecordTypes(); break; case RECORDS_MODIFY: current = adminGroup.getModifyMemberRecordTypes(); break; case RECORDS_VIEW: current = adminGroup.getViewMemberRecordTypes(); break; default: throw new IllegalArgumentException(String.format("Unsupported list permission: %1$s.%2$s", permission.getClass().getSimpleName(), permission)); } return current; } private static Collection<? extends Entity> getCurrentValues(final AdminGroup adminGroup, final AdminSystemPermission permission) { Collection<? extends Entity> current; switch (permission) { case ACCOUNTS_INFORMATION: current = adminGroup.getViewInformationOf(); break; case PAYMENTS_CHARGEBACK: current = adminGroup.getChargebackTransferTypes(); break; case PAYMENTS_PAYMENT: current = adminGroup.getTransferTypes(); break; case STATUS_VIEW_CONNECTED_ADMINS: current = adminGroup.getViewConnectedAdminsOf(); break; default: throw new IllegalArgumentException(String.format("Unsupported list permission: %1$s.%2$s", permission.getClass().getSimpleName(), permission)); } return current; } private static Collection<? extends Entity> getCurrentValues(final BrokerGroup brokerGroup, final BrokerPermission permission) { Collection<? extends Entity> current; switch (permission) { case DOCUMENTS_VIEW: current = brokerGroup.getBrokerDocuments(); break; case MEMBER_PAYMENTS_PAYMENT_AS_MEMBER_TO_MEMBER: current = brokerGroup.getTransferTypesAsMember(); break; case MEMBER_PAYMENTS_PAYMENT_AS_MEMBER_TO_SELF: current = brokerGroup.getTransferTypesAsMember(); break; case MEMBER_PAYMENTS_PAYMENT_AS_MEMBER_TO_SYSTEM: current = brokerGroup.getTransferTypesAsMember(); break; case MEMBER_RECORDS_CREATE: current = brokerGroup.getBrokerCreateMemberRecordTypes(); break; case MEMBER_RECORDS_DELETE: current = brokerGroup.getBrokerDeleteMemberRecordTypes(); break; case MEMBER_RECORDS_MODIFY: current = brokerGroup.getBrokerModifyMemberRecordTypes(); break; case MEMBER_RECORDS_VIEW: current = brokerGroup.getBrokerMemberRecordTypes(); break; case REPORTS_SHOW_ACCOUNT_INFORMATION: current = brokerGroup.getBrokerCanViewInformationOf(); break; default: throw new IllegalArgumentException(String.format("Unsupported list permission: %1$s.%2$s", permission.getClass().getSimpleName(), permission)); } return current; } private static Collection<? extends Entity> getCurrentValues(final MemberGroup memberGroup, final MemberPermission permission) { Collection<? extends Entity> current; switch (permission) { case ADS_VIEW: current = memberGroup.getCanViewAdsOfGroups(); break; case DOCUMENTS_VIEW: current = memberGroup.getDocuments(); break; case GUARANTEES_BUY_WITH_PAYMENT_OBLIGATIONS: current = memberGroup.getCanBuyWithPaymentObligationsFromGroups(); break; case GUARANTEES_ISSUE_CERTIFICATIONS: current = memberGroup.getCanIssueCertificationToGroups(); break; case GUARANTEES_ISSUE_GUARANTEES: current = memberGroup.getGuaranteeTypes(); break; case MESSAGES_SEND_TO_ADMINISTRATION: current = memberGroup.getMessageCategories(); break; case PAYMENTS_CHARGEBACK: current = memberGroup.getChargebackTransferTypes(); break; case PAYMENTS_PAYMENT_TO_MEMBER: current = memberGroup.getTransferTypes(); break; case PAYMENTS_PAYMENT_TO_SELF: current = memberGroup.getTransferTypes(); break; case PAYMENTS_PAYMENT_TO_SYSTEM: current = memberGroup.getTransferTypes(); break; case PAYMENTS_REQUEST: current = memberGroup.getRequestPaymentByChannels(); break; case PROFILE_VIEW: current = memberGroup.getCanViewProfileOfGroups(); break; case REPORTS_SHOW_ACCOUNT_INFORMATION: current = memberGroup.getCanViewInformationOf(); break; default: throw new IllegalArgumentException(String.format("Unsupported list permission: %1$s.%2$s", permission.getClass().getSimpleName(), permission)); } return current; } private static Collection<? extends Entity> getCurrentValues(final OperatorGroup operatorGroup, final OperatorPermission permission) { Collection<? extends Entity> current; switch (permission) { case ACCOUNT_ACCOUNT_INFORMATION: current = operatorGroup.getCanViewInformationOf(); break; case GUARANTEES_ISSUE_GUARANTEES: current = operatorGroup.getGuaranteeTypes(); break; default: throw new IllegalArgumentException(String.format("Unsupported list permission: %1$s.%2$s", permission.getClass().getSimpleName(), permission)); } return current; } private static String getValue(final String name) { return name.toLowerCase(); } private static String process(final String string) { return StringUtils.uncapitalize(WordUtils.capitalizeFully(string, NAME_DELIMITERS).replaceAll("\\_", "")); } }