/** * Licensed to Jasig under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Jasig * 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: * * <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.permission.target; import java.io.Serializable; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apereo.portal.layout.dlm.remoting.IGroupListHelper; import org.apereo.portal.layout.dlm.remoting.JsonEntityBean; import org.apereo.portal.permission.target.IPermissionTarget.TargetType; import org.apereo.portal.security.IPermission; import org.springframework.beans.factory.annotation.Autowired; /** * EntityTargetProviderImpl provides uPortal entity keys as targets. Instances of this * implementation may indicate which entity types may be used as targets. Target keys will be the * key of the underlying entity itself, while the target human-readable name will similarly be the * name of the entity. * * <p>TODO: This implementation currently has a number of problems. The code uses the EntityEnum * class and is hardcoded to only recognize four types of entities: uPortal person groups, person * entities, portlet categories, and portlet entities. This code also may perform poorly for large * portal installations for searches that return many results. * * @since 3.3 */ public class EntityTargetProviderImpl implements IPermissionTargetProvider, Serializable { private static final IPermissionTarget ALL_CATEGORIES_TARGET = new PermissionTargetImpl( IPermission.ALL_CATEGORIES_TARGET, IPermission.ALL_CATEGORIES_TARGET, TargetType.CATEGORY); private static final IPermissionTarget ALL_GROUPS_TARGET = new PermissionTargetImpl( IPermission.ALL_GROUPS_TARGET, IPermission.ALL_GROUPS_TARGET, TargetType.GROUP); private static final IPermissionTarget ALL_PORTLETS_TARGET = new PermissionTargetImpl( IPermission.ALL_PORTLETS_TARGET, IPermission.ALL_PORTLETS_TARGET, TargetType.PORTLET); private static final long serialVersionUID = 1L; private Set<TargetType> allowedTargetTypes = new HashSet<>(); protected final transient Log log = LogFactory.getLog(getClass()); private transient IGroupListHelper groupListHelper; @Autowired(required = true) public void setGroupListHelper(IGroupListHelper helper) { this.groupListHelper = helper; } /** * Construct a new instance of targets matching the set of allowed target entity types. * * @param targetTypeNames */ public EntityTargetProviderImpl(Set<String> targetTypeNames) { /* * Arguably this logic should be moved to the TargetType enum itself; * but this sort of mapping only occurs (afaik) for "entities." */ for (String name : targetTypeNames) { switch (name) { case "person": allowedTargetTypes.add(TargetType.PERSON); break; case "group": allowedTargetTypes.add(TargetType.GROUP); break; case "portlet": allowedTargetTypes.add(TargetType.PORTLET); break; case "category": allowedTargetTypes.add(TargetType.CATEGORY); break; default: String msg = "Unrecognized targetTypeName: " + name; throw new RuntimeException(msg); } } } /** * The <code>key</code> parameter <em>should</em> specify a unique entity across all 4 supported * types: people, groups, portlets, and categories. * * <p>Concrete examples of working keys: * * <ul> * <li>defaultTemplateUser (user) * <li>local.0 (group) * <li>PORTLET_ID.82 (portlet) * <li>local.1 (category) * </ul> */ public IPermissionTarget getTarget(String key) { /* * If the specified key matches one of the "all entity" style targets, * just return the appropriate target. */ switch (key) { case IPermission.ALL_CATEGORIES_TARGET: return ALL_CATEGORIES_TARGET; case IPermission.ALL_PORTLETS_TARGET: return ALL_PORTLETS_TARGET; case IPermission.ALL_GROUPS_TARGET: return ALL_GROUPS_TARGET; // Else just fall through... } /* * Attempt to find a matching entity for each allowed entity type. This * implementation will return the first entity that it finds. If the * portal contains duplicate entity keys across multiple types, it's * possible that this implementation would demonstrate inconsistent * behavior. */ for (TargetType targetType : allowedTargetTypes) { JsonEntityBean entity = groupListHelper.getEntity(targetType.toString(), key, false); if (entity != null) { IPermissionTarget target = new PermissionTargetImpl(entity.getId(), entity.getName(), targetType); return target; } } return null; } /* * (non-Javadoc) * @see org.apereo.portal.permission.target.IPermissionTargetProvider#searchTargets(java.lang.String) */ public Collection<IPermissionTarget> searchTargets(String term) { // Initialize a new collection of matching targets. We use a HashSet // implementation here to prevent duplicate target entries. Collection<IPermissionTarget> matching = new HashSet<IPermissionTarget>(); /* * Attempt to find matching entities for each allowed entity type. * Any matching entities will be added to our collection. */ for (TargetType targetType : allowedTargetTypes) { Set<JsonEntityBean> entities = groupListHelper.search(targetType.toString(), term); for (JsonEntityBean entity : entities) { IPermissionTarget target = new PermissionTargetImpl(entity.getId(), entity.getName(), targetType); matching.add(target); } } if (IPermission.ALL_CATEGORIES_TARGET.contains(term)) { matching.add(ALL_CATEGORIES_TARGET); } else if (IPermission.ALL_PORTLETS_TARGET.contains(term)) { matching.add(ALL_PORTLETS_TARGET); } else if (IPermission.ALL_GROUPS_TARGET.contains(term)) { matching.add(ALL_GROUPS_TARGET); } // return the list of matching targets return matching; } }