/** * 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.rest.permissions; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apereo.portal.groups.IEntityGroup; import org.apereo.portal.groups.IGroupMember; import org.apereo.portal.layout.dlm.remoting.IGroupListHelper; import org.apereo.portal.layout.dlm.remoting.JsonEntityBean; import org.apereo.portal.permission.IPermissionActivity; import org.apereo.portal.permission.IPermissionOwner; import org.apereo.portal.permission.dao.IPermissionOwnerDao; import org.apereo.portal.permission.target.IPermissionTarget; import org.apereo.portal.permission.target.IPermissionTargetProvider; import org.apereo.portal.permission.target.IPermissionTargetProviderRegistry; import org.apereo.portal.portlets.groupselector.EntityEnum; import org.apereo.portal.security.IAuthorizationPrincipal; import org.apereo.portal.security.IAuthorizationService; import org.apereo.portal.security.IPermission; import org.apereo.portal.security.IPermissionStore; import org.apereo.portal.services.GroupService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; /** * PermissionsRESTController provides a REST endpoing for permission owners and activities. * */ @Controller public class PermissionsRESTController { protected final Log log = LogFactory.getLog(getClass()); private IPermissionOwnerDao permissionOwnerDao; @Autowired(required = true) public void setPermissionOwnerDao(IPermissionOwnerDao permissionOwnerDao) { this.permissionOwnerDao = permissionOwnerDao; } private IPermissionTargetProviderRegistry targetProviderRegistry; @Autowired(required = true) public void setPermissionTargetProviderRegistry(IPermissionTargetProviderRegistry registry) { this.targetProviderRegistry = registry; } private IPermissionStore permissionStore; @Autowired public void setPermissionStore(IPermissionStore permissionStore) { this.permissionStore = permissionStore; } private IGroupListHelper groupListHelper; @Autowired public void setGroupListHelper(IGroupListHelper groupListHelper) { this.groupListHelper = groupListHelper; } private IAuthorizationService authorizationService; @Autowired public void setAuthorizationService(IAuthorizationService authorizationService) { this.authorizationService = authorizationService; } /** * Provide a JSON view of all known permission owners registered with uPortal. * * @param req * @param response * @return * @throws Exception */ @PreAuthorize( "hasPermission('string', 'ALL', new org.apereo.portal.spring.security.evaluator.AuthorizableActivity('UP_PERMISSIONS', 'VIEW_PERMISSIONS'))") @RequestMapping(value = "/permissions/owners.json", method = RequestMethod.GET) public ModelAndView getOwners(HttpServletRequest req, HttpServletResponse response) throws Exception { // get a list of all currently defined permission owners List<IPermissionOwner> owners = permissionOwnerDao.getAllPermissionOwners(); ModelAndView mv = new ModelAndView(); mv.addObject("owners", owners); mv.setViewName("json"); return mv; } /** * Provide a detailed view of the specified IPermissionOwner. This view should contain a list of * the owner's defined activities. * * @param ownerParam * @param req * @param response * @return * @throws Exception */ @PreAuthorize( "hasPermission('string', 'ALL', new org.apereo.portal.spring.security.evaluator.AuthorizableActivity('UP_PERMISSIONS', 'VIEW_PERMISSIONS'))") @RequestMapping(value = "/permissions/owners/{owner}.json", method = RequestMethod.GET) public ModelAndView getOwners( @PathVariable("owner") String ownerParam, HttpServletRequest req, HttpServletResponse response) throws Exception { IPermissionOwner owner = null; if (StringUtils.isNumeric(ownerParam)) { Long id = Long.valueOf(ownerParam); owner = permissionOwnerDao.getPermissionOwner(id); } else { owner = permissionOwnerDao.getPermissionOwner(ownerParam); } // if the IPermissionOwner was found, add it to the JSON model if (owner != null) { ModelAndView mv = new ModelAndView(); mv.addObject("owner", owner); mv.setViewName("json"); return mv; } // otherwise return a 404 not found error code else { response.setStatus(HttpServletResponse.SC_NOT_FOUND); return null; } } /** * Provide a list of all registered IPermissionActivities. If an optional search string is * provided, the returned list will be restricted to activities matching the query. * * @param query optional search query * @param request * @param response * @return * @throws Exception */ @PreAuthorize( "hasPermission('string', 'ALL', new org.apereo.portal.spring.security.evaluator.AuthorizableActivity('UP_PERMISSIONS', 'VIEW_PERMISSIONS'))") @RequestMapping(value = "/permissions/activities.json", method = RequestMethod.GET) public ModelAndView getActivities( @RequestParam(value = "q", required = false) String query, HttpServletRequest request, HttpServletResponse response) throws Exception { if (StringUtils.isNotBlank(query)) { query = query.toLowerCase(); } List<IPermissionActivity> activities = new ArrayList<IPermissionActivity>(); Collection<IPermissionOwner> owners = permissionOwnerDao.getAllPermissionOwners(); for (IPermissionOwner owner : owners) { for (IPermissionActivity activity : owner.getActivities()) { if (StringUtils.isBlank(query) || activity.getName().toLowerCase().contains(query)) { activities.add(activity); } } } Collections.sort(activities); ModelAndView mv = new ModelAndView(); mv.addObject("activities", activities); mv.setViewName("json"); return mv; } /** * Return a list of targets defined for a particular IPermissionActivity matching the specified * search query. * * @param activityId * @param query * @param req * @param response * @return * @throws Exception */ @PreAuthorize( "hasPermission('string', 'ALL', new org.apereo.portal.spring.security.evaluator.AuthorizableActivity('UP_PERMISSIONS', 'VIEW_PERMISSIONS'))") @RequestMapping(value = "/permissions/{activity}/targets.json", method = RequestMethod.GET) public ModelAndView getTargets( @PathVariable("activity") Long activityId, @RequestParam("q") String query, HttpServletRequest req, HttpServletResponse response) throws Exception { IPermissionActivity activity = permissionOwnerDao.getPermissionActivity(activityId); IPermissionTargetProvider provider = targetProviderRegistry.getTargetProvider(activity.getTargetProviderKey()); SortedSet<IPermissionTarget> matchingTargets = new TreeSet<IPermissionTarget>(); // add matching results for this identifier provider to the set Collection<IPermissionTarget> targets = provider.searchTargets(query); for (IPermissionTarget target : targets) { if ((StringUtils.isNotBlank(target.getName()) && target.getName().toLowerCase().contains(query)) || target.getKey().toLowerCase().contains(query)) { matchingTargets.addAll(targets); } } ModelAndView mv = new ModelAndView(); mv.addObject("targets", targets); mv.setViewName("json"); return mv; } @PreAuthorize( "hasPermission('string', 'ALL', new org.apereo.portal.spring.security.evaluator.AuthorizableActivity('UP_PERMISSIONS', 'VIEW_PERMISSIONS'))") @RequestMapping("/assignments/principal/{principal}.json") public ModelAndView getAssignmentsForPrincipal( @PathVariable("principal") String principal, @RequestParam(value = "includeInherited", required = false) boolean includeInherited, HttpServletRequest request, HttpServletResponse response) { JsonEntityBean entity = groupListHelper.getEntityForPrincipal(principal); List<JsonPermission> permissions = getPermissionsForEntity(entity, includeInherited); ModelAndView mv = new ModelAndView(); mv.addObject("assignments", permissions); mv.setViewName("json"); return mv; } @PreAuthorize( "(#entityType == 'person' and #id == authentication.name) or hasPermission('string', 'ALL', new org.apereo.portal.spring.security.evaluator.AuthorizableActivity('UP_PERMISSIONS', 'VIEW_PERMISSIONS'))") @RequestMapping("/assignments/{entityType}/{id}.json") public ModelAndView getAssignmentsForEntity( @PathVariable("entityType") String entityType, @PathVariable("id") String id, @RequestParam(value = "includeInherited", required = false) boolean includeInherited, HttpServletRequest request, HttpServletResponse response) { JsonEntityBean entity = groupListHelper.getEntity(entityType, id, false); List<JsonPermission> permissions = getPermissionsForEntity(entity, includeInherited); ModelAndView mv = new ModelAndView(); mv.addObject("assignments", permissions); mv.setViewName("json"); return mv; } @PreAuthorize( "hasPermission('string', 'ALL', new org.apereo.portal.spring.security.evaluator.AuthorizableActivity('UP_PERMISSIONS', 'VIEW_PERMISSIONS'))") @RequestMapping("/assignments/target/{target}.json") public ModelAndView getAssignmentsOnTarget( @PathVariable("target") String target, @RequestParam(value = "includeInherited", required = false) boolean includeInherited, HttpServletRequest request, HttpServletResponse response) { Set<UniquePermission> directAssignments = new HashSet<UniquePermission>(); // first get the permissions explicitly set for this principal IPermission[] directPermissions = permissionStore.select(null, null, null, target, null); for (IPermission permission : directPermissions) { directAssignments.add( new UniquePermission( permission.getOwner(), permission.getActivity(), permission.getPrincipal(), false)); } JsonEntityBean entity = groupListHelper.getEntityForPrincipal(target); IAuthorizationPrincipal p = this.authorizationService.newPrincipal( entity.getId(), entity.getEntityType().getClazz()); Set<UniquePermission> inheritedAssignments = new HashSet<UniquePermission>(); if (includeInherited) { IGroupMember member = GroupService.getGroupMember(p.getKey(), p.getType()); for (IEntityGroup parent : member.getAncestorGroups()) { IAuthorizationPrincipal parentPrincipal = this.authorizationService.newPrincipal(parent); IPermission[] parentPermissions = permissionStore.select(null, null, null, parentPrincipal.getKey(), null); for (IPermission permission : parentPermissions) { inheritedAssignments.add( new UniquePermission( permission.getOwner(), permission.getActivity(), permission.getPrincipal(), true)); } } } List<JsonPermission> permissions = new ArrayList<JsonPermission>(); for (UniquePermission permission : directAssignments) { JsonEntityBean e = groupListHelper.getEntityForPrincipal(permission.getIdentifier()); Class<?> clazz; EntityEnum entityType = EntityEnum.getEntityEnum(e.getEntityTypeAsString()); if (entityType.isGroup()) { clazz = IEntityGroup.class; } else { clazz = entityType.getClazz(); } IAuthorizationPrincipal principal = this.authorizationService.newPrincipal(e.getId(), clazz); if (principal.hasPermission( permission.getOwner(), permission.getActivity(), p.getKey())) { permissions.add(getPermissionOnTarget(permission, entity)); } } for (UniquePermission permission : inheritedAssignments) { JsonEntityBean e = groupListHelper.getEntityForPrincipal(permission.getIdentifier()); Class<?> clazz; EntityEnum entityType = EntityEnum.getEntityEnum(e.getEntityTypeAsString()); if (entityType.isGroup()) { clazz = IEntityGroup.class; } else { clazz = entityType.getClazz(); } IAuthorizationPrincipal principal = this.authorizationService.newPrincipal(e.getId(), clazz); if (principal.hasPermission( permission.getOwner(), permission.getActivity(), p.getKey())) { permissions.add(getPermissionOnTarget(permission, entity)); } } Collections.sort(permissions); ModelAndView mv = new ModelAndView(); mv.addObject("assignments", permissions); mv.setViewName("json"); return mv; } protected List<JsonPermission> getPermissionsForEntity( JsonEntityBean entity, boolean includeInherited) { Set<UniquePermission> directAssignments = new HashSet<UniquePermission>(); IAuthorizationPrincipal p = this.authorizationService.newPrincipal( entity.getId(), entity.getEntityType().getClazz()); // first get the permissions explicitly set for this principal IPermission[] directPermissions = permissionStore.select(null, p.getPrincipalString(), null, null, null); for (IPermission permission : directPermissions) { directAssignments.add( new UniquePermission( permission.getOwner(), permission.getActivity(), permission.getTarget(), false)); } Set<UniquePermission> inheritedAssignments = new HashSet<UniquePermission>(); if (includeInherited) { IGroupMember member = GroupService.getGroupMember(p.getKey(), p.getType()); for (IEntityGroup parent : member.getAncestorGroups()) { IAuthorizationPrincipal parentPrincipal = this.authorizationService.newPrincipal(parent); IPermission[] parentPermissions = permissionStore.select( null, parentPrincipal.getPrincipalString(), null, null, null); for (IPermission permission : parentPermissions) { inheritedAssignments.add( new UniquePermission( permission.getOwner(), permission.getActivity(), permission.getTarget(), true)); } } } List<JsonPermission> rslt = new ArrayList<JsonPermission>(); for (UniquePermission permission : directAssignments) { if (p.hasPermission( permission.getOwner(), permission.getActivity(), permission.getIdentifier())) { rslt.add(getPermissionForPrincipal(permission, entity)); } } for (UniquePermission permission : inheritedAssignments) { if (p.hasPermission( permission.getOwner(), permission.getActivity(), permission.getIdentifier())) { rslt.add(getPermissionForPrincipal(permission, entity)); } } Collections.sort(rslt); return rslt; } protected JsonPermission getPermissionForPrincipal( UniquePermission permission, JsonEntityBean entity) { JsonPermission perm = new JsonPermission(); perm.setOwnerKey(permission.getOwner()); perm.setActivityKey(permission.getActivity()); perm.setTargetKey(permission.getIdentifier()); perm.setPrincipalKey(entity.getId()); perm.setPrincipalName(entity.getName()); perm.setInherited(permission.isInherited()); try { IPermissionOwner owner = permissionOwnerDao.getPermissionOwner(permission.getOwner()); if (owner != null) { perm.setOwnerName(owner.getName()); } IPermissionActivity activity = permissionOwnerDao.getPermissionActivity( permission.getOwner(), permission.getActivity()); if (activity != null) { perm.setActivityName(activity.getName()); IPermissionTargetProvider targetProvider = targetProviderRegistry.getTargetProvider(activity.getTargetProviderKey()); if (targetProvider != null) { IPermissionTarget target = targetProvider.getTarget(permission.getIdentifier()); if (target != null) { perm.setTargetName(target.getName()); } } } } catch (RuntimeException e) { log.warn("Exception while adding permission", e); } return perm; } protected JsonPermission getPermissionOnTarget( UniquePermission permission, JsonEntityBean entity) { JsonPermission perm = new JsonPermission(); perm.setOwnerKey(permission.getOwner()); perm.setActivityKey(permission.getActivity()); perm.setTargetKey(entity.getId()); perm.setTargetName(entity.getName()); perm.setInherited(permission.isInherited()); try { IPermissionOwner owner = permissionOwnerDao.getPermissionOwner(permission.getOwner()); if (owner != null) { perm.setOwnerName(owner.getName()); } else { perm.setOwnerName(permission.getOwner()); } IPermissionActivity activity = permissionOwnerDao.getPermissionActivity( permission.getOwner(), permission.getActivity()); if (activity != null) { perm.setActivityName(activity.getName()); } else { perm.setActivityName(permission.getActivity()); } JsonEntityBean principal = groupListHelper.getEntityForPrincipal(permission.getIdentifier()); if (principal != null) { perm.setPrincipalKey(principal.getId()); perm.setPrincipalName(principal.getName()); } } catch (RuntimeException e) { log.warn("Exception while adding permission", e); } return perm; } protected static final class UniquePermission { private final String owner; private final String activity; private final String identifier; private final boolean inherited; public UniquePermission( String owner, String activity, String identifier, boolean inherited) { this.owner = owner; this.activity = activity; this.identifier = identifier; this.inherited = inherited; } public String getOwner() { return owner; } public String getActivity() { return activity; } public String getIdentifier() { return identifier; } public boolean isInherited() { return inherited; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((this.activity == null) ? 0 : this.activity.hashCode()); result = prime * result + ((this.identifier == null) ? 0 : this.identifier.hashCode()); result = prime * result + (this.inherited ? 1231 : 1237); result = prime * result + ((this.owner == null) ? 0 : this.owner.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; UniquePermission other = (UniquePermission) obj; if (this.activity == null) { if (other.activity != null) return false; } else if (!this.activity.equals(other.activity)) return false; if (this.identifier == null) { if (other.identifier != null) return false; } else if (!this.identifier.equals(other.identifier)) return false; if (this.inherited != other.inherited) return false; if (this.owner == null) { if (other.owner != null) return false; } else if (!this.owner.equals(other.owner)) return false; return true; } } }