/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of the License at the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ package org.apereo.portal.io.xml.portlet; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apereo.portal.EntityIdentifier; import org.apereo.portal.IUserIdentityStore; import org.apereo.portal.channel.IPortletPublishingService; import org.apereo.portal.groups.IEntity; import org.apereo.portal.groups.IEntityGroup; import org.apereo.portal.groups.IEntityNameFinder; import org.apereo.portal.groups.IGroupConstants; import org.apereo.portal.groups.IGroupMember; import org.apereo.portal.io.xml.AbstractJaxbDataHandler; import org.apereo.portal.io.xml.IPortalData; import org.apereo.portal.io.xml.IPortalDataType; import org.apereo.portal.io.xml.PortalDataKey; import org.apereo.portal.io.xml.portlettype.ExternalPermissionDefinition; import org.apereo.portal.portlet.dao.IMarketplaceRatingDao; import org.apereo.portal.portlet.dao.IPortletDefinitionDao; import org.apereo.portal.portlet.dao.jpa.PortletDefinitionImpl; import org.apereo.portal.portlet.dao.jpa.PortletDefinitionParameterImpl; import org.apereo.portal.portlet.dao.jpa.PortletPreferenceImpl; import org.apereo.portal.portlet.om.IPortletDefinition; import org.apereo.portal.portlet.om.IPortletDefinitionParameter; import org.apereo.portal.portlet.om.IPortletDescriptorKey; import org.apereo.portal.portlet.om.IPortletPreference; import org.apereo.portal.portlet.om.IPortletType; import org.apereo.portal.portlet.om.PortletCategory; import org.apereo.portal.portlet.om.PortletLifecycleState; import org.apereo.portal.portlet.registry.IPortletCategoryRegistry; import org.apereo.portal.portlet.registry.IPortletTypeRegistry; import org.apereo.portal.security.IAuthorizationPrincipal; import org.apereo.portal.security.IPermission; import org.apereo.portal.security.IPermissionManager; import org.apereo.portal.security.IPerson; import org.apereo.portal.security.IUpdatingPermissionManager; import org.apereo.portal.security.PermissionHelper; import org.apereo.portal.security.PersonFactory; import org.apereo.portal.security.SystemPerson; import org.apereo.portal.services.AuthorizationService; import org.apereo.portal.services.EntityNameFinderService; import org.apereo.portal.services.GroupService; import org.apereo.portal.utils.SafeFilenameUtils; import org.apereo.portal.xml.PortletDescriptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.transaction.annotation.Transactional; public class PortletDefinitionImporterExporter extends AbstractJaxbDataHandler<ExternalPortletDefinition> implements IPortletPublishingService { private PortletPortalDataType portletPortalDataType; private IPortletTypeRegistry portletTypeRegistry; private IPortletDefinitionDao portletDefinitionDao; private IPortletCategoryRegistry portletCategoryRegistry; private IUserIdentityStore userIdentityStore; private boolean errorOnChannel = true; @Autowired private IMarketplaceRatingDao marketplaceRatingDao; private IPerson systemUser = PersonFactory.createSystemPerson(); private String systemUsername = SystemPerson.INSTANCE.getUserName(); @Value("${org.apereo.portal.io.errorOnChannel}") public void setErrorOnChannel(boolean errorOnChannel) { this.errorOnChannel = errorOnChannel; } @Autowired public void setPortletPortalDataType(PortletPortalDataType portletPortalDataType) { this.portletPortalDataType = portletPortalDataType; } @Autowired public void setPortletTypeRegistry(IPortletTypeRegistry portletTypeRegistry) { this.portletTypeRegistry = portletTypeRegistry; } @Autowired public void setPortletDefinitionRegistry(IPortletDefinitionDao portletDefinitionRegistry) { this.portletDefinitionDao = portletDefinitionRegistry; } @Autowired public void setPortletCategoryRegistry(IPortletCategoryRegistry portletCategoryRegistry) { this.portletCategoryRegistry = portletCategoryRegistry; } @Autowired public void setUserIdentityStore(IUserIdentityStore identityStore) { this.userIdentityStore = identityStore; } @Override public Set<PortalDataKey> getImportDataKeys() { return Collections.singleton(PortletPortalDataType.IMPORT_43_DATA_KEY); } @Override public IPortalDataType getPortalDataType() { return this.portletPortalDataType; } @Override public Iterable<? extends IPortalData> getPortalData() { return this.portletDefinitionDao.getPortletDefinitions(); } @Transactional @Override public void importData(ExternalPortletDefinition portletRep) { final PortletDescriptor portletDescriptor = portletRep.getPortletDescriptor(); final Boolean isFramework = portletDescriptor.isIsFramework(); if (isFramework != null && isFramework && "UPGRADED_CHANNEL_IS_NOT_A_PORTLET".equals(portletDescriptor.getPortletName())) { if (errorOnChannel) { throw new IllegalArgumentException( portletRep.getFname() + " is not a portlet. It was likely an IChannel from a previous version of uPortal and cannot be imported."); } logger.warn( portletRep.getFname() + " is not a portlet. It was likely an IChannel from a previous version of uPortal and will not be imported."); return; } // get the portlet type final IPortletType portletType = portletTypeRegistry.getPortletType(portletRep.getType()); if (portletType == null) { throw new IllegalArgumentException( "No portlet type registered for: " + portletRep.getType()); } final List<PortletCategory> categories = new ArrayList<PortletCategory>(); for (String categoryName : portletRep.getCategories()) { EntityIdentifier[] cats = GroupService.searchForGroups( categoryName, IGroupConstants.IS, IPortletDefinition.class); PortletCategory category = null; if (cats != null && cats.length > 0) { category = portletCategoryRegistry.getPortletCategory(cats[0].getKey()); } else { category = portletCategoryRegistry.getPortletCategory(categoryName); } if (category == null) { throw new IllegalArgumentException( "No category '" + categoryName + "' found when importing portlet: " + portletRep.getFname()); } categories.add(category); } final String fname = portletRep.getFname(); final Map<ExternalPermissionDefinition, Set<IGroupMember>> permissions = new HashMap<>(); final Set<IGroupMember> subscribeMembers = toGroupMembers(portletRep.getGroups(), fname); permissions.put(ExternalPermissionDefinition.SUBSCRIBE, subscribeMembers); if (portletRep.getPermissions() != null && portletRep.getPermissions().getPermissions() != null) { for (ExternalPermissionMemberList perm : portletRep.getPermissions().getPermissions()) { Set<IGroupMember> members = toGroupMembers(perm.getGroups(), fname); ExternalPermissionDefinition permDef = toExternalPermissionDefinition(perm.getSystem(), perm.getActivity()); if (permissions.containsKey(permDef)) { permissions.get(permDef).addAll(members); } else { permissions.put(permDef, members); } } } IPortletDefinition def = portletDefinitionDao.getPortletDefinitionByFname(fname); if (def == null) { def = new PortletDefinitionImpl( portletType, fname, portletRep.getName(), portletRep.getTitle(), portletDescriptor.getWebAppName(), portletDescriptor.getPortletName(), isFramework != null ? isFramework : false); } else { final IPortletDescriptorKey portletDescriptorKey = def.getPortletDescriptorKey(); portletDescriptorKey.setPortletName(portletDescriptor.getPortletName()); if (isFramework != null && isFramework) { portletDescriptorKey.setFrameworkPortlet(true); portletDescriptorKey.setWebAppName(null); } else { portletDescriptorKey.setFrameworkPortlet(false); portletDescriptorKey.setWebAppName(portletDescriptor.getWebAppName()); } def.setName(portletRep.getName()); def.setTitle(portletRep.getTitle()); def.setType(portletType); } def.setDescription(portletRep.getDesc()); final BigInteger timeout = portletRep.getTimeout(); if (timeout != null) { def.setTimeout(timeout.intValue()); } final BigInteger actionTimeout = portletRep.getActionTimeout(); if (actionTimeout != null) { def.setActionTimeout(actionTimeout.intValue()); } final BigInteger eventTimeout = portletRep.getEventTimeout(); if (eventTimeout != null) { def.setEventTimeout(eventTimeout.intValue()); } final BigInteger renderTimeout = portletRep.getRenderTimeout(); if (renderTimeout != null) { def.setRenderTimeout(renderTimeout.intValue()); } final BigInteger resourceTimeout = portletRep.getResourceTimeout(); if (resourceTimeout != null) { def.setResourceTimeout(resourceTimeout.intValue()); } handleLifecycleApproval(def, portletRep.getLifecycle()); handleLifecyclePublished(def, portletRep.getLifecycle()); handleLifecycleExpired(def, portletRep.getLifecycle()); final Set<IPortletDefinitionParameter> parameters = new LinkedHashSet<IPortletDefinitionParameter>(); for (ExternalPortletParameter param : portletRep.getParameters()) { parameters.add(new PortletDefinitionParameterImpl(param.getName(), param.getValue())); } def.setParameters(parameters); final ArrayList<IPortletPreference> preferenceList = new ArrayList<IPortletPreference>(); for (ExternalPortletPreference pref : portletRep.getPortletPreferences()) { final List<String> valueList = pref.getValues(); final String[] values = valueList.toArray(new String[valueList.size()]); final Boolean readOnly = pref.isReadOnly(); preferenceList.add( new PortletPreferenceImpl( pref.getName(), readOnly != null ? readOnly : false, values)); } def.setPortletPreferences(preferenceList); savePortletDefinition(def, systemUser, categories, permissions); } // lifecycle not present: approved immediately // lifecycle present, approval not present nor any later lifecycle: not approved (i.e created) // lifecycle present, approval not present but later lifecycle is: approved at earliest later lifecycle datetime // lifecycle present, approval specified: approved at indicated date private void handleLifecycleApproval(IPortletDefinition def, Lifecycle lifecycle) { if (lifecycle != null) { if (lifecycle.getApproved() != null) { LifecycleEntry lifecycleEntry = lifecycle.getApproved(); def.setApprovalDate(calculateEarliestApprovalDate(lifecycle)); def.setApproverId(getUserIdForUsername(lifecycleEntry.getUser(), def)); } else if (lifecycle.getPublished() != null || lifecycle.getExpiration() != null) { def.setApprovalDate(calculateEarliestPubExpireDate(lifecycle)); def.setApproverId(systemUser.getID()); } else { def.setApprovalDate(null); def.setApproverId(-1); // Using -1 to be consistent with PortletAdministrationHelper } } else { def.setApprovalDate(new Date()); def.setApproverId(systemUser.getID()); } } // Handle improper data. If the Approval date is after either the published or expire date, return the // earlier of the latter two dates. private Date calculateEarliestApprovalDate(Lifecycle lifecycle) { Date publishOrExpireDate = calculateEarliestPubExpireDate(lifecycle); return lifecycle.getApproved() != null && publishOrExpireDate.after(lifecycle.getApproved().getValue().getTime()) ? lifecycle.getApproved().getValue().getTime() : publishOrExpireDate; } // Calculates the earliest of either the published Date or Expiration date, whichever is specified. // If neither specified, returns current time. private Date calculateEarliestPubExpireDate(Lifecycle lifecycle) { Date now = new Date(); Date publishedDate = lifecycle.getPublished() != null && lifecycle.getPublished().getValue().before(now) ? lifecycle.getPublished().getValue().getTime() : now; Date expiredDate = lifecycle.getExpiration() != null ? lifecycle.getExpiration().getValue().getTime() : now; return publishedDate.after(expiredDate) ? expiredDate : publishedDate; } // lifecycle not present: published immediately // lifecycle present, published not present nor any later lifecycle: not published // lifecycle present, published not present but later lifecycle is: published at earliest later lifecycle datetime // lifecycle present, published specified: published at indicated date private void handleLifecyclePublished(IPortletDefinition def, Lifecycle lifecycle) { if (lifecycle != null) { if (lifecycle.getPublished() != null) { LifecycleEntry lifecycleEntry = lifecycle.getPublished(); def.setPublishDate(calculateEarliestPubExpireDate(lifecycle)); def.setPublisherId(getUserIdForUsername(lifecycleEntry.getUser(), def)); } else if (lifecycle.getExpiration() != null) { def.setPublishDate(calculateEarliestPubExpireDate(lifecycle)); def.setPublisherId(systemUser.getID()); } else { def.setPublishDate(null); def.setPublisherId( -1); // Using -1 to be consistent with PortletAdministrationHelper } } else { def.setPublishDate(new Date()); def.setPublisherId(systemUser.getID()); } } // lifecycle present and expired present: expired at indicated datetime // else not expired private void handleLifecycleExpired(IPortletDefinition def, Lifecycle lifecycle) { if (lifecycle != null && lifecycle.getExpiration() != null) { LifecycleEntry lifecycleEntry = lifecycle.getExpiration(); def.setExpirationDate(lifecycleEntry.getValue().getTime()); def.setExpirerId(getUserIdForUsername(lifecycleEntry.getUser(), def)); } else { def.setExpirationDate(null); def.setExpirerId(0); } } // Returns the ID for the specified username or if not found the ID of the system user. private int getUserIdForUsername(String username, IPortletDefinition def) { if (username != null && !username.equals(systemUsername)) { Integer id = userIdentityStore.getPortalUserId(username); if (id != null) { return id; } logger.warn( "Invalid username {} in portlet lifecycle for fname={}, defaulting to system user", username, def.getFName()); } // Note this returns 0 consistent with prior import behavior, not the id in the database. // todo: Figure out if we should instead return the id of the system user in the DB return systemUser.getID(); } // Returns the username for a valid userId, else the system username private String getUsernameForUserId(int id) { if (id > 0) { String username = userIdentityStore.getPortalUserName(id); if (username != null) { return username; } logger.warn( "Invalid userID {} found when exporting a portlet; return system username instead", id); } return systemUsername; } /** {@link String} id argument is treated as the portlet fname. */ @Transactional @Override public ExternalPortletDefinition deleteData(String fname) { final IPortletDefinition def = this.portletDefinitionDao.getPortletDefinitionByFname(fname); if (null == def) { return null; } ExternalPortletDefinition result = convert(def); this.portletDefinitionDao.deletePortletDefinition(def); return result; } private final Object groupUpdateLock = new Object(); /* * (non-Javadoc) * @see org.apereo.portal.channel.IChannelPublishingService#saveChannelDefinition(org.apereo.portal.portlet.om.IPortletDefinition, org.apereo.portal.security.IPerson, org.apereo.portal.channel.ChannelLifecycleState, java.util.Date, java.util.Date, org.apereo.portal.ChannelCategory[], org.apereo.portal.groups.IGroupMember[]) */ @Override public IPortletDefinition savePortletDefinition( IPortletDefinition definition, IPerson publisher, List<PortletCategory> categories, List<IGroupMember> groupMembers) { Map<ExternalPermissionDefinition, Set<IGroupMember>> permissions = new HashMap<>(); permissions.put(ExternalPermissionDefinition.SUBSCRIBE, new HashSet<>(groupMembers)); IPortletDefinition def = savePortletDefinition(definition, publisher, categories, permissions); return def; } /** * Save a portlet definition. * * @param definition the portlet definition * @param publisher the person publishing the portlet * @param categories the list of categories for the portlet * @param permissionMap a map of permission name -> list of groups who are granted that * permission (Note: for now, only grant is supported and only for the FRAMEWORK_OWNER perm * manager) */ private IPortletDefinition savePortletDefinition( IPortletDefinition definition, IPerson publisher, List<PortletCategory> categories, Map<ExternalPermissionDefinition, Set<IGroupMember>> permissionMap) { boolean newChannel = (definition.getPortletDefinitionId() == null); // save the channel definition = portletDefinitionDao.savePortletDefinition(definition); definition = portletDefinitionDao.getPortletDefinitionByFname(definition.getFName()); final String defId = definition.getPortletDefinitionId().getStringId(); final IEntity portletDefEntity = GroupService.getEntity(defId, IPortletDefinition.class); //Sync on groups during update. This really should be a portal wide thread-safety check or //The groups service needs to deal with concurrent modification better. synchronized (this.groupUpdateLock) { // Delete existing category memberships for this channel if (!newChannel) { for (IEntityGroup group : portletDefEntity.getAncestorGroups()) { group.removeChild(portletDefEntity); group.update(); } } // For each category ID, add channel to category for (PortletCategory category : categories) { final IEntityGroup categoryGroup = GroupService.findGroup(category.getId()); categoryGroup.addChild(portletDefEntity); categoryGroup.updateMembers(); } // Set groups final AuthorizationService authService = AuthorizationService.instance(); final String target = PermissionHelper.permissionTargetIdForPortletDefinition(definition); // Loop over the affected permission managers... Map<String, Collection<ExternalPermissionDefinition>> permissionsBySystem = getPermissionsBySystem(permissionMap.keySet()); for (String system : permissionsBySystem.keySet()) { Collection<ExternalPermissionDefinition> systemPerms = permissionsBySystem.get(system); // get the permission manager for this system... final IUpdatingPermissionManager upm = authService.newUpdatingPermissionManager(system); final List<IPermission> permissions = new ArrayList<>(); // add activity grants for each permission.. for (ExternalPermissionDefinition permissionDef : systemPerms) { Set<IGroupMember> members = permissionMap.get(permissionDef); for (final IGroupMember member : members) { final IAuthorizationPrincipal authPrincipal = authService.newPrincipal(member); final IPermission permEntity = upm.newPermission(authPrincipal); permEntity.setType(IPermission.PERMISSION_TYPE_GRANT); permEntity.setActivity(permissionDef.getActivity()); permEntity.setTarget(target); permissions.add(permEntity); } } // If modifying the channel, remove the existing permissions before adding the new ones if (!newChannel) { for (ExternalPermissionDefinition permissionName : permissionMap.keySet()) { IPermission[] oldPermissions = upm.getPermissions(permissionName.getActivity(), target); upm.removePermissions(oldPermissions); } } upm.addPermissions(permissions.toArray(new IPermission[permissions.size()])); } } if (logger.isDebugEnabled()) { logger.debug( "Portlet " + defId + " has been " + (newChannel ? "published" : "modified") + "."); } return definition; } @Transactional @Override public void removePortletDefinition(IPortletDefinition portletDefinition, IPerson person) { IPortletDefinition portletDef = portletDefinitionDao.getPortletDefinition( portletDefinition.getPortletDefinitionId()); // Delete existing category memberships for this portlet String portletDefinitionId = portletDefinition.getPortletDefinitionId().getStringId(); IEntity channelDefEntity = GroupService.getEntity(portletDefinitionId, IPortletDefinition.class); for (IEntityGroup group : channelDefEntity.getAncestorGroups()) { group.removeChild(channelDefEntity); group.update(); } // Delete permissions records that refer to this portlet AuthorizationService authService = AuthorizationService.instance(); String target = PermissionHelper.permissionTargetIdForPortletDefinition(portletDefinition); IUpdatingPermissionManager upm = authService.newUpdatingPermissionManager(IPermission.PORTAL_SUBSCRIBE); IPermission[] oldPermissions = upm.getPermissionsForTarget(target); upm.removePermissions(oldPermissions); // Delete any ratings (incl. reviews) associated with the portlet marketplaceRatingDao.clearRatingsForPortlet(portletDef); //Delete the portlet itself. portletDefinitionDao.deletePortletDefinition(portletDef); } @Override public ExternalPortletDefinition exportData(String fname) { final IPortletDefinition def = this.portletDefinitionDao.getPortletDefinitionByFname(fname); if (def == null) { return null; } return convert(def); } @Override public String getFileName(ExternalPortletDefinition data) { return SafeFilenameUtils.makeSafeFilename(data.getFname()); } protected BigInteger convertToBigInteger(Integer i) { if (i == null) { return null; } return BigInteger.valueOf(i); } // Utility method to convert a date to a calendar. private static Calendar getCalendar(Date date) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); return calendar; } protected ExternalPortletDefinition convert(IPortletDefinition def) { ExternalPortletDefinition rep = new ExternalPortletDefinition(); rep.setFname(def.getFName()); rep.setDesc(def.getDescription()); rep.setName(def.getName()); rep.setTimeout(BigInteger.valueOf(def.getTimeout())); rep.setActionTimeout(convertToBigInteger(def.getActionTimeout())); rep.setEventTimeout(convertToBigInteger(def.getEventTimeout())); rep.setRenderTimeout(convertToBigInteger(def.getRenderTimeout())); rep.setResourceTimeout(convertToBigInteger(def.getResourceTimeout())); rep.setTitle(def.getTitle()); rep.setType(def.getType().getName()); if (def.getLifecycleState().isEqualToOrAfter(PortletLifecycleState.APPROVED)) { Lifecycle lifecycle = new Lifecycle(); LifecycleEntry approved = new LifecycleEntry(); approved.setUser(getUsernameForUserId(def.getApproverId())); approved.setValue(getCalendar(def.getApprovalDate())); lifecycle.setApproved(approved); if (def.getLifecycleState().isEqualToOrAfter(PortletLifecycleState.PUBLISHED)) { LifecycleEntry published = new LifecycleEntry(); published.setUser(getUsernameForUserId(def.getPublisherId())); published.setValue(getCalendar(def.getPublishDate())); lifecycle.setPublished(published); } /* An EXPIRED record in the lifecycle history requires two things: * - Current lifecycle state >= EXPIRED * - An expiration date */ if (def.getLifecycleState().isEqualToOrAfter(PortletLifecycleState.EXPIRED) && def.getExpirationDate() != null) { LifecycleEntry expired = new LifecycleEntry(); expired.setUser(getUsernameForUserId(def.getExpirerId())); expired.setValue(getCalendar(def.getExpirationDate())); lifecycle.setExpiration(expired); } // Maintenance mode is handled via a portlet publishing parameter and not a lifecycle rep.setLifecycle(lifecycle); } final org.apereo.portal.xml.PortletDescriptor portletDescriptor = new org.apereo.portal.xml.PortletDescriptor(); final IPortletDescriptorKey portletDescriptorKey = def.getPortletDescriptorKey(); if (portletDescriptorKey.isFrameworkPortlet()) { portletDescriptor.setIsFramework(true); } else { portletDescriptor.setWebAppName(portletDescriptorKey.getWebAppName()); } portletDescriptor.setPortletName(portletDescriptorKey.getPortletName()); rep.setPortletDescriptor(portletDescriptor); final List<ExternalPortletParameter> parameterList = rep.getParameters(); for (IPortletDefinitionParameter param : def.getParameters()) { final ExternalPortletParameter externalPortletParameter = new ExternalPortletParameter(); externalPortletParameter.setName(param.getName()); externalPortletParameter.setDescription(param.getDescription()); externalPortletParameter.setValue(param.getValue()); parameterList.add(externalPortletParameter); } Collections.sort(parameterList, ExternalPortletParameterNameComparator.INSTANCE); final List<ExternalPortletPreference> portletPreferenceList = rep.getPortletPreferences(); for (IPortletPreference pref : def.getPortletPreferences()) { final ExternalPortletPreference externalPortletPreference = new ExternalPortletPreference(); externalPortletPreference.setName(pref.getName()); externalPortletPreference.setReadOnly(pref.isReadOnly()); final List<String> value = externalPortletPreference.getValues(); value.addAll(Arrays.asList(pref.getValues())); //no sorting of preference values, order is specified by the portlet portletPreferenceList.add(externalPortletPreference); } Collections.sort(portletPreferenceList, ExternalPortletPreferenceNameComparator.INSTANCE); final List<String> categoryList = rep.getCategories(); final IGroupMember gm = GroupService.getGroupMember( def.getPortletDefinitionId().getStringId(), IPortletDefinition.class); @SuppressWarnings("unchecked") final Iterator<IEntityGroup> categories = GroupService.getCompositeGroupService().findParentGroups(gm); while (categories.hasNext()) { IEntityGroup category = categories.next(); categoryList.add(category.getName()); } Collections.sort(categoryList); // handle the SUBSCRIBER_ACTIVITY perm separately... final List<String> groupList = rep.getGroups(); final List<String> userList = rep.getUsers(); exportPermission(def, ExternalPermissionDefinition.SUBSCRIBE, groupList, userList); // handle other supported perms (currently just BROWSE) ExternalPermissions externalPermissions = new ExternalPermissions(); for (ExternalPermissionDefinition perm : ExternalPermissionDefinition.values()) { if (!perm.getExportForPortletDef()) { continue; } ExternalPermissionMemberList members = new ExternalPermissionMemberList(); members.setSystem(perm.getSystem()); members.setActivity(perm.getActivity()); List<String> groups = members.getGroups(); boolean found = exportPermission(def, perm, groups, null); if (found) { externalPermissions.getPermissions().add(members); } } if (!externalPermissions.getPermissions().isEmpty()) { rep.setPermissions(externalPermissions); } return rep; } private boolean exportPermission( IPortletDefinition def, ExternalPermissionDefinition permDef, List<String> groupList, List<String> userList) { final AuthorizationService authService = org.apereo.portal.services.AuthorizationService.instance(); final IPermissionManager pm = authService.newPermissionManager(permDef.getSystem()); final String portletTargetId = PermissionHelper.permissionTargetIdForPortletDefinition(def); final IAuthorizationPrincipal[] principals = pm.getAuthorizedPrincipals(permDef.getActivity(), portletTargetId); boolean permAdded = false; for (IAuthorizationPrincipal principal : principals) { IGroupMember member = authService.getGroupMember(principal); if (member.isGroup()) { final EntityNameFinderService entityNameFinderService = EntityNameFinderService.instance(); final IEntityNameFinder nameFinder = entityNameFinderService.getNameFinder(member.getType()); try { groupList.add(nameFinder.getName(member.getKey())); permAdded = true; } catch (Exception e) { throw new RuntimeException( "Could not find group name for entity: " + member.getKey(), e); } } else { if (userList != null) { userList.add(member.getKey()); permAdded = true; } } } Collections.sort(groupList); if (userList != null) { Collections.sort(userList); } return permAdded; } /** * Convert a list of group names to a list of groups. * * @param groupNames the list of group names * @return the list of groups. */ private Set<IGroupMember> toGroupMembers(List<String> groupNames, String fname) { final Set<IGroupMember> groups = new HashSet<>(); for (String groupName : groupNames) { EntityIdentifier[] gs = GroupService.searchForGroups(groupName, IGroupConstants.IS, IPerson.class); IGroupMember group; if (gs != null && gs.length > 0) { group = GroupService.findGroup(gs[0].getKey()); } else { // An actual group key might be specified, so try looking up group directly group = GroupService.findGroup(groupName); } if (group == null) { throw new IllegalArgumentException( "No group '" + groupName + "' found when importing portlet: " + fname); } groups.add(group); } return groups; } /** * Check that a permission type from the XML file matches with a real permission. * * @param system The name of the permission manager * @param activity The name of the permission to search for. * @return the permission type string to use * @throws IllegalArgumentException if an unsupported permission type is specified */ private ExternalPermissionDefinition toExternalPermissionDefinition( String system, String activity) { ExternalPermissionDefinition def = ExternalPermissionDefinition.find(system, activity); if (def != null) { return def; } String delim = ""; StringBuilder buffer = new StringBuilder(); for (ExternalPermissionDefinition perm : ExternalPermissionDefinition.values()) { buffer.append(delim); buffer.append(perm.toString()); delim = ", "; } throw new IllegalArgumentException( "Permission type " + system + "." + activity + " is not supported. " + "The only supported permissions at this time are: " + buffer.toString()); } private Map<String, Collection<ExternalPermissionDefinition>> getPermissionsBySystem( Set<ExternalPermissionDefinition> perms) { Map<String, Collection<ExternalPermissionDefinition>> mappedPerms = new HashMap<>(); for (ExternalPermissionDefinition perm : perms) { if (!mappedPerms.containsKey(perm.getSystem())) { mappedPerms.put(perm.getSystem(), new ArrayList<ExternalPermissionDefinition>()); } mappedPerms.get(perm.getSystem()).add(perm); } return mappedPerms; } }