/** * 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.security.provider; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.Vector; import net.sf.ehcache.Ehcache; import net.sf.ehcache.Element; import net.sf.ehcache.constructs.blocking.CacheEntryFactory; import net.sf.ehcache.constructs.blocking.SelfPopulatingCache; import org.apereo.portal.AuthorizationException; import org.apereo.portal.concurrency.CachingException; import org.apereo.portal.concurrency.caching.RequestCache; import org.apereo.portal.groups.GroupsException; import org.apereo.portal.groups.ICompositeGroupService; import org.apereo.portal.groups.IEntityGroup; import org.apereo.portal.groups.IGroupMember; 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.portlet.om.IPortletDefinition; import org.apereo.portal.portlet.om.PortletCategory; import org.apereo.portal.portlet.om.PortletLifecycleState; import org.apereo.portal.portlet.registry.IPortletDefinitionRegistry; import org.apereo.portal.security.IAuthorizationPrincipal; import org.apereo.portal.security.IAuthorizationService; import org.apereo.portal.security.IPermission; import org.apereo.portal.security.IPermissionManager; import org.apereo.portal.security.IPermissionPolicy; import org.apereo.portal.security.IPermissionSet; import org.apereo.portal.security.IPermissionStore; import org.apereo.portal.security.IPerson; import org.apereo.portal.security.IUpdatingPermissionManager; import org.apereo.portal.security.PermissionHelper; import org.apereo.portal.services.EntityCachingService; import org.apereo.portal.services.GroupService; import org.apereo.portal.spring.locator.EntityTypesLocator; import org.apereo.portal.spring.locator.PortletCategoryRegistryLocator; import org.apereo.portal.utils.Tuple; import org.apereo.portal.utils.cache.CacheFactory; import org.apereo.portal.utils.cache.CacheKey; import org.apereo.portal.utils.cache.CacheKey.CacheKeyBuilder; import org.apereo.portal.utils.cache.UsernameTaggedCacheEntryPurger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; /** */ @Service("authorizationService") public class AuthorizationImpl implements IAuthorizationService { /** Instance of log in order to log events. */ protected final Logger log = LoggerFactory.getLogger(getClass()); /** Constant representing the separator used in the principal key. */ private static final String PRINCIPAL_SEPARATOR = "."; /** Instance of the Permission Store for storing permission information. */ private IPermissionStore permissionStore; /** The default Permission Policy this Authorization implementation will use. */ private IPermissionPolicy defaultPermissionPolicy; /** Spring-configured portlet definition registry instance */ private IPortletDefinitionRegistry portletDefinitionRegistry; /** Indicates permission activity to permissionTargetProvider. */ private IPermissionOwnerDao permissionOwner; /** The cache to hold the list of principals. */ private Ehcache principalCache; /** The cache to hold the list of principals. */ private Ehcache entityParentsCache; /** The cache to hold permission resolution. */ private Ehcache doesPrincipalHavePermissionCache; /** The class representing the permission set type. */ private static final Class<IPermissionSet> PERMISSION_SET_TYPE = IPermissionSet.class; /** variable to determine if we should cache permissions or not. */ private boolean cachePermissions = true; private Set<String> nonEntityPermissionTargetProviders = new HashSet<>(); @Autowired private IPermissionOwnerDao permissionOwnerDao; @Autowired private IPermissionTargetProviderRegistry targetProviderRegistry; @Autowired public void setDefaultPermissionPolicy(IPermissionPolicy newDefaultPermissionPolicy) { this.defaultPermissionPolicy = newDefaultPermissionPolicy; } @Autowired public void setPermissionStore(IPermissionStore permissionStore) { this.permissionStore = permissionStore; } @Value("${org.apereo.portal.security.IAuthorizationService.cachePermissions}") public void setCachePermissions(boolean cachePermissions) { this.cachePermissions = cachePermissions; } @Autowired public void setPrincipalCache(@Qualifier(CacheFactory.PRINCIPAL_CACHE) Ehcache principalCache) { this.principalCache = new SelfPopulatingCache( principalCache, new CacheEntryFactory() { @Override public Object createEntry(Object key) throws Exception { final Tuple<String, Class> principalKey = (Tuple<String, Class>) key; return primNewPrincipal(principalKey.first, principalKey.second); } }); } @Autowired public void setEntityParentsCache( @Qualifier(CacheFactory.ENTITY_PARENTS_CACHE) Ehcache entityParentsCache) { this.entityParentsCache = entityParentsCache; } @Autowired public void setDoesPrincipalHavePermissionCache( @Qualifier( "org.apereo.portal.security.provider.AuthorizationImpl.PRINCIPAL_HAS_PERMISSION") Ehcache doesPrincipalHavePermissionCache) { this.doesPrincipalHavePermissionCache = doesPrincipalHavePermissionCache; } @Autowired public void setPortletDefinitionRegistry(IPortletDefinitionRegistry portletDefinitionRegistry) { this.portletDefinitionRegistry = portletDefinitionRegistry; } @Autowired public void setPermissionOwner(IPermissionOwnerDao permissionOwner) { this.permissionOwner = permissionOwner; } public void setNonEntityPermissionTargetProviders( Set<String> nonEntityPermissionTargetProviders) { this.nonEntityPermissionTargetProviders = nonEntityPermissionTargetProviders; } /** * Adds <code>IPermissions</code> to the back end store. * * @param permissions IPermission[] * @exception AuthorizationException */ public void addPermissions(IPermission[] permissions) throws AuthorizationException { if (permissions.length > 0) { getPermissionStore().add(permissions); if (this.cachePermissions) { removeFromPermissionsCache(permissions); } } } /** Adds the <code>IPermissionSet</code> to the entity cache. */ protected void cacheAdd(IPermissionSet ps) throws AuthorizationException { try { EntityCachingService.getEntityCachingService().add(ps); } catch (CachingException ce) { throw new AuthorizationException( "Problem adding permissions for " + ps + " to cache", ce); } } /** * Retrieves the <code>IPermissionSet</code> for the <code>IPermissionSet</code> from the entity * cache. */ protected IPermissionSet cacheGet(IAuthorizationPrincipal principal) throws AuthorizationException { try { return (IPermissionSet) EntityCachingService.getEntityCachingService() .get(this.PERMISSION_SET_TYPE, principal.getPrincipalString()); } catch (CachingException ce) { throw new AuthorizationException( "Problem getting permissions for " + principal + " from cache", ce); } } /** Removes the <code>IPermissionSet</code> for this principal from the entity cache. */ protected void cacheRemove(IAuthorizationPrincipal ap) throws AuthorizationException { try { EntityCachingService.getEntityCachingService() .remove(this.PERMISSION_SET_TYPE, ap.getPrincipalString()); } catch (CachingException ce) { throw new AuthorizationException( "Problem removing permissions for " + ap + " from cache", ce); } } @Override @RequestCache public boolean canPrincipalConfigure( IAuthorizationPrincipal principal, String portletDefinitionId) throws AuthorizationException { String owner = IPermission.PORTAL_PUBLISH; String target = IPermission.PORTLET_PREFIX + portletDefinitionId; // retrieve the indicated channel from the channel registry store and // determine its current lifecycle state IPortletDefinition portlet = this.portletDefinitionRegistry.getPortletDefinition(portletDefinitionId); if (portlet == null) { throw new AuthorizationException("Unable to locate portlet " + portletDefinitionId); } final String activity = IPermission.PORTLET_MODE_CONFIG; return doesPrincipalHavePermission(principal, owner, activity, target); } /** * Answers if the principal has permission to MANAGE this Channel. * * @return boolean * @param principal IAuthorizationPrincipal * @param portletDefinitionId * @exception AuthorizationException indicates authorization information could not be retrieved. */ @RequestCache public boolean canPrincipalManage(IAuthorizationPrincipal principal, String portletDefinitionId) throws AuthorizationException { String owner = IPermission.PORTAL_PUBLISH; String target = IPermission.PORTLET_PREFIX + portletDefinitionId; // retrieve the indicated channel from the channel registry store and // determine its current lifecycle state IPortletDefinition portlet = this.portletDefinitionRegistry.getPortletDefinition(portletDefinitionId); if (portlet == null) { return doesPrincipalHavePermission( principal, owner, IPermission.PORTLET_MANAGER_APPROVED_ACTIVITY, target); // throw new AuthorizationException("Unable to locate channel " + channelPublishId); } PortletLifecycleState state = portlet.getLifecycleState(); int order = state.getOrder(); /* * The following code assumes that later lifecycle states imply permission * for earlier lifecycle states. For example, if a user has permission to * manage an expired channel, we assume s/he also has permission to * create, approve, and publish channels. The following code counts * channels with auto-publish or auto-expiration dates set as requiring * publish or expiration permissions for management, even though the channel * may not yet be published or expired. */ String activity = IPermission.PORTLET_MANAGER_MAINTENANCE_ACTIVITY; if (order <= PortletLifecycleState.MAINTENANCE.getOrder() && doesPrincipalHavePermission(principal, owner, activity, target)) { return true; } activity = IPermission.PORTLET_MANAGER_EXPIRED_ACTIVITY; if ((order <= PortletLifecycleState.EXPIRED.getOrder() || portlet.getExpirationDate() != null) && doesPrincipalHavePermission(principal, owner, activity, target)) { return true; } activity = IPermission.PORTLET_MANAGER_ACTIVITY; if ((order <= PortletLifecycleState.PUBLISHED.getOrder() || portlet.getPublishDate() != null) && doesPrincipalHavePermission(principal, owner, activity, target)) { return true; } activity = IPermission.PORTLET_MANAGER_APPROVED_ACTIVITY; log.debug( "order: " + order + ", approved order: " + PortletLifecycleState.APPROVED.getOrder()); if (order <= PortletLifecycleState.APPROVED.getOrder() && doesPrincipalHavePermission(principal, owner, activity, target)) { return true; } activity = IPermission.PORTLET_MANAGER_CREATED_ACTIVITY; if (order <= PortletLifecycleState.CREATED.getOrder() && doesPrincipalHavePermission(principal, owner, activity, target)) { return true; } // if no permissions were found, return false return false; } /** * This checks if the framework has granted principal a right to publish. DO WE WANT SOMETHING * THIS COARSE (de)? * * @param principal IAuthorizationPrincipal * @return boolean */ @RequestCache public boolean canPrincipalManage( IAuthorizationPrincipal principal, PortletLifecycleState state, String categoryId) throws AuthorizationException { // return doesPrincipalHavePermission // (principal, IPermission.PORTAL_FRAMEWORK, IPermission.CHANNEL_PUBLISHER_ACTIVITY, null); String owner = IPermission.PORTAL_PUBLISH; // retrieve the indicated channel from the channel registry store and // determine its current lifecycle state PortletCategory category = PortletCategoryRegistryLocator.getPortletCategoryRegistry() .getPortletCategory(categoryId); if (category == null) { // return doesPrincipalHavePermission(principal, owner, // IPermission.CHANNEL_MANAGER_APPROVED_ACTIVITY, target); throw new AuthorizationException("Unable to locate category " + categoryId); } int order = state.getOrder(); String activity = IPermission.PORTLET_MANAGER_MAINTENANCE_ACTIVITY; if (order <= PortletLifecycleState.MAINTENANCE.getOrder() && doesPrincipalHavePermission(principal, owner, activity, categoryId)) { return true; } activity = IPermission.PORTLET_MANAGER_EXPIRED_ACTIVITY; if (order <= PortletLifecycleState.EXPIRED.getOrder() && doesPrincipalHavePermission(principal, owner, activity, categoryId)) { return true; } activity = IPermission.PORTLET_MANAGER_ACTIVITY; if (order <= PortletLifecycleState.PUBLISHED.getOrder() && doesPrincipalHavePermission(principal, owner, activity, categoryId)) { return true; } activity = IPermission.PORTLET_MANAGER_APPROVED_ACTIVITY; if (order <= PortletLifecycleState.APPROVED.getOrder() && doesPrincipalHavePermission(principal, owner, activity, categoryId)) { return true; } activity = IPermission.PORTLET_MANAGER_CREATED_ACTIVITY; if (order <= PortletLifecycleState.CREATED.getOrder() && doesPrincipalHavePermission(principal, owner, activity, categoryId)) { return true; } return false; } /** * Answers if the principal has permission to RENDER this Channel. This implementation currently * delegates to the SUBSCRIBE permission. * * @return boolean * @param principal IAuthorizationPrincipal * @param portletDefinitionId * @exception AuthorizationException indicates authorization information could not be retrieved. */ @RequestCache public boolean canPrincipalRender(IAuthorizationPrincipal principal, String portletDefinitionId) throws AuthorizationException { // This code simply assumes that anyone who can subscribe to a channel // should be able to render it. In the future, we'd like to update this // implementation to use a separate permission for rendering. return canPrincipalSubscribe(principal, portletDefinitionId); } @Override @RequestCache public boolean canPrincipalBrowse( IAuthorizationPrincipal principal, String portletDefinitionId) { // Retrieve the indicated portlet from the channel registry store. IPortletDefinition portlet = this.portletDefinitionRegistry.getPortletDefinition(portletDefinitionId); if (portlet == null) { return false; } return canPrincipalBrowse(principal, portlet); } @Override @RequestCache public boolean canPrincipalBrowse( IAuthorizationPrincipal principal, IPortletDefinition portlet) { String target = PermissionHelper.permissionTargetIdForPortletDefinition(portlet); return doesPrincipalHavePermission( principal, IPermission.PORTAL_SUBSCRIBE, IPermission.PORTLET_BROWSE_ACTIVITY, target); } /** * Answers if the principal has permission to SUBSCRIBE to this Channel. * * @return boolean * @param principal IAuthorizationPrincipal * @param portletDefinitionId * @exception AuthorizationException indicates authorization information could not be retrieved. */ @RequestCache public boolean canPrincipalSubscribe( IAuthorizationPrincipal principal, String portletDefinitionId) { String owner = IPermission.PORTAL_SUBSCRIBE; // retrieve the indicated channel from the channel registry store and // determine its current lifecycle state IPortletDefinition portlet = this.portletDefinitionRegistry.getPortletDefinition(portletDefinitionId); if (portlet == null) { return false; } String target = PermissionHelper.permissionTargetIdForPortletDefinition(portlet); PortletLifecycleState state = portlet.getLifecycleState(); /* * Each channel lifecycle state now has its own subscribe permission. The * following logic checks the appropriate permission for the lifecycle. */ String permission; if (state.equals(PortletLifecycleState.PUBLISHED) || state.equals(PortletLifecycleState.MAINTENANCE)) { // NB: There is no separate SUBSCRIBE permission for MAINTENANCE // mode; everyone simply sees the 'out of service' message permission = IPermission.PORTLET_SUBSCRIBER_ACTIVITY; } else if (state.equals(PortletLifecycleState.APPROVED)) { permission = IPermission.PORTLET_SUBSCRIBER_APPROVED_ACTIVITY; } else if (state.equals(PortletLifecycleState.CREATED)) { permission = IPermission.PORTLET_SUBSCRIBER_CREATED_ACTIVITY; } else if (state.equals(PortletLifecycleState.EXPIRED)) { permission = IPermission.PORTLET_SUBSCRIBER_EXPIRED_ACTIVITY; } else { throw new AuthorizationException( "Unrecognized lifecycle state for channel " + portletDefinitionId); } // Test the appropriate permission. return doesPrincipalHavePermission(principal, owner, permission, target); } /** * Answers if the owner has given the principal (or any of its parents) permission to perform * the activity on the target. Params <code>owner</code> and <code>activity</code> must be * non-null. If <code>target</code> is null, then target is not checked. * * @return boolean * @param principal IAuthorizationPrincipal * @param owner java.lang.String * @param activity java.lang.String * @param target java.lang.String * @exception AuthorizationException indicates authorization information could not be retrieved. */ @RequestCache public boolean doesPrincipalHavePermission( IAuthorizationPrincipal principal, String owner, String activity, String target) throws AuthorizationException { return doesPrincipalHavePermission( principal, owner, activity, target, getDefaultPermissionPolicy()); } /** * Answers if the owner has given the principal permission to perform the activity on the * target, as evaluated by the policy. Params <code>policy</code>, <code>owner</code> and <code> * activity</code> must be non-null. * * @return boolean * @param principal IAuthorizationPrincipal * @param owner java.lang.String * @param activity java.lang.String * @param target java.lang.String * @exception AuthorizationException indicates authorization information could not be retrieved. */ @Override @RequestCache public boolean doesPrincipalHavePermission( IAuthorizationPrincipal principal, String owner, String activity, String target, IPermissionPolicy policy) throws AuthorizationException { final CacheKeyBuilder<Serializable, Serializable> cacheKeyBuilder = CacheKey.builder(AuthorizationImpl.class.getName()); final String username = principal.getKey(); if (IPerson.class.equals(principal.getType())) { cacheKeyBuilder.addTag(UsernameTaggedCacheEntryPurger.createCacheEntryTag(username)); } cacheKeyBuilder.addAll( policy.getClass(), username, principal.getType(), owner, activity, target); final CacheKey key = cacheKeyBuilder.build(); final Element element = this.doesPrincipalHavePermissionCache.get(key); if (element != null) { return (Boolean) element.getValue(); } /* * Convert to (strongly-typed) Java objects based on interfaces in * o.j.p.permission before we make the actual check with IPermissionPolicy; * parameters that communicate something of the nature of the things they * represent helps us make the check(s) more intelligently. This objects * were retro-fitted to IPermissionPolicy in uP 4.3; perhaps we should do * the same to IAuthorizationService itself? */ final IPermissionOwner ipOwner = permissionOwnerDao.getPermissionOwner(owner); final IPermissionActivity ipActivity = permissionOwnerDao.getPermissionActivity(owner, activity); if (ipActivity == null) { // Means needed data is missing; much clearer than NPE String msg = "The following activity is not defined for owner '" + owner + "': " + activity; throw new RuntimeException(msg); } final IPermissionTargetProvider targetProvider = targetProviderRegistry.getTargetProvider(ipActivity.getTargetProviderKey()); final IPermissionTarget ipTarget = targetProvider.getTarget(target); final boolean doesPrincipalHavePermission = policy.doesPrincipalHavePermission(this, principal, ipOwner, ipActivity, ipTarget); this.doesPrincipalHavePermissionCache.put(new Element(key, doesPrincipalHavePermission)); return doesPrincipalHavePermission; } /** * Returns the <code>IPermissions</code> owner has granted this <code>Principal</code> for the * specified activity and target. Null parameters will be ignored, that is, all <code> * IPermissions</code> matching the non-null parameters are retrieved. So, <code> * getPermissions(principal,null, null, null)</code> should retrieve all <code>IPermissions * </code> for a <code>Principal</code>. Note that this includes <code>IPermissions</code> * inherited from groups the <code>Principal</code> belongs to. * * @return org.apereo.portal.security.IPermission[] * @param principal IAuthorizationPrincipal * @param owner java.lang.String * @param activity java.lang.String * @param target java.lang.String * @exception AuthorizationException indicates authorization information could not be retrieved. */ public IPermission[] getAllPermissionsForPrincipal( IAuthorizationPrincipal principal, String owner, String activity, String target) throws AuthorizationException { IPermission[] perms = getPermissionsForPrincipal(principal, owner, activity, target); ArrayList<IPermission> al = new ArrayList<IPermission>(Arrays.asList(perms)); Iterator i = getInheritedPrincipals(principal); while (i.hasNext()) { IAuthorizationPrincipal p = (IAuthorizationPrincipal) i.next(); perms = getPermissionsForPrincipal(p, owner, activity, target); al.addAll(Arrays.asList(perms)); } if (log.isTraceEnabled()) { log.trace( "query for all permissions for principal=[" + principal + "], owner=[" + owner + "], activity=[" + activity + "], target=[" + target + "] returned permissions [" + al + "]"); } return ((IPermission[]) al.toArray(new IPermission[al.size()])); } /** * Does this mean all channels the principal could conceivably subscribe to or all channels * principal is specifically authorized to subscribe to, or what? * * @param principal IAuthorizationPrincipal * @return Vector (of channels?) * @exception AuthorizationException indicates authorization information could not */ public Vector getAuthorizedChannels(IAuthorizationPrincipal principal) throws AuthorizationException { return new Vector(); } /** * Returns <code>IAuthorizationPrincipals</code> that have <code>IPermissions</code> for the * given owner, activity and target. * * @return IAuthorizationPrincipal[] * @param owner * @param activity * @param target */ public IAuthorizationPrincipal[] getAuthorizedPrincipals( String owner, String activity, String target) throws AuthorizationException { IPermission[] permissions = getPermissionsForOwner(owner, activity, target); return getPrincipalsFromPermissions(permissions); } /** @return org.apereo.portal.security.IPermissionPolicy */ protected IPermissionPolicy getDefaultPermissionPolicy() { return this.defaultPermissionPolicy; } /** * @return org.apereo.portal.groups.IGroupMember * @param principal org.apereo.portal.security.IAuthorizationPrincipal */ public IGroupMember getGroupMember(IAuthorizationPrincipal principal) throws GroupsException { return getGroupMemberForPrincipal(principal); } /** * @return org.apereo.portal.groups.IGroupMember * @param principal org.apereo.portal.security.IAuthorizationPrincipal */ private IGroupMember getGroupMemberForPrincipal(IAuthorizationPrincipal principal) throws GroupsException { IGroupMember gm = GroupService.getGroupMember(principal.getKey(), principal.getType()); if (log.isDebugEnabled()) { log.debug( "AuthorizationImpl.getGroupMemberForPrincipal(): principal [" + principal + "] " + "got group member [" + gm + "]"); } return gm; } /** * Hook into the Groups system by converting the <code>IAuthorizationPrincipal</code> to an * <code>IGroupMember</code>. Returns ALL the groups the <code>IGroupMember</code> (recursively) * belongs to. * * @param principal - org.apereo.portal.security.IAuthorizationPrincipal * @return java.util.Iterator over Collection of IEntityGroups */ private Iterator getGroupsForPrincipal(IAuthorizationPrincipal principal) throws GroupsException { IGroupMember gm = getGroupMemberForPrincipal(principal); return gm.getAncestorGroups().iterator(); } /** * Hook into the Groups system, find all containing groups, and convert the them to <code> * IAuthorizationPrincipals</code>. * * @param principal - org.apereo.portal.security.IAuthorizationPrincipal * @return java.util.Iterator over Collection of IEntityGroups */ private Iterator getInheritedPrincipals(IAuthorizationPrincipal principal) throws AuthorizationException { Iterator i = null; ArrayList<IAuthorizationPrincipal> al = new ArrayList<IAuthorizationPrincipal>(5); try { i = getGroupsForPrincipal(principal); } catch (GroupsException ge) { throw new AuthorizationException("Could not retrieve Groups for " + principal, ge); } while (i.hasNext()) { IEntityGroup group = (IEntityGroup) i.next(); IAuthorizationPrincipal p = getPrincipalForGroup(group); al.add(p); } return al.iterator(); } /** * Returns the <code>IPermissions</code> owner has granted for the specified activity and * target. Null parameters will be ignored, that is, all <code>IPermissions</code> matching the * non-null parameters are retrieved. * * @return org.apereo.portal.security.IPermission[] * @param owner java.lang.String * @param activity java.lang.String * @param target java.lang.String * @exception AuthorizationException indicates authorization information could not be retrieved. */ public IPermission[] getPermissionsForOwner(String owner, String activity, String target) throws AuthorizationException { return primRetrievePermissions(owner, null, activity, target); } /** * Returns the <code>IPermissions</code> owner has granted this <code>Principal</code> for the * specified activity and target. Null parameters will be ignored, that is, all <code> * IPermissions</code> matching the non-null parameters are retrieved. So, <code> * getPermissions(principal,null, null, null)</code> should retrieve all <code>IPermissions * </code> for a <code>Principal</code>. * * @return org.apereo.portal.security.IPermission[] * @param principal IAuthorizationPrincipal * @param owner java.lang.String * @param activity java.lang.String * @param target java.lang.String * @exception AuthorizationException indicates authorization information could not be retrieved. */ @RequestCache public IPermission[] getPermissionsForPrincipal( IAuthorizationPrincipal principal, String owner, String activity, String target) throws AuthorizationException { return primGetPermissionsForPrincipal(principal, owner, activity, target); } public IPermission[] getPermissionsForTarget(final String owner, final String target) { return getPermissionStore().select(owner, null, null, target, null); } /** @return org.apereo.portal.security.IPermissionStore */ private IPermissionStore getPermissionStore() { return this.permissionStore; } /** * Returns <code>IAuthorizationPrincipal</code> associated with the <code>IPermission</code>. * * @return IAuthorizationPrincipal * @param permission IPermission */ public IAuthorizationPrincipal getPrincipal(IPermission permission) throws AuthorizationException { String principalString = permission.getPrincipal(); int idx = principalString.indexOf(PRINCIPAL_SEPARATOR); Integer typeId = new Integer(principalString.substring(0, idx)); Class type = EntityTypesLocator.getEntityTypes().getEntityTypeFromID(typeId); String key = principalString.substring(idx + 1); return newPrincipal(key, type); } /** * @param group * @return user org.apereo.portal.security.IAuthorizationPrincipal */ private IAuthorizationPrincipal getPrincipalForGroup(IEntityGroup group) { String key = group.getKey(); Class type = ICompositeGroupService.GROUP_ENTITY_TYPE; return newPrincipal(key, type); } /** * Returns <code>IAuthorizationPrincipals</code> associated with the <code>IPermission[]</code>. * * @return IAuthorizationPrincipal[] * @param permissions IPermission[] */ private IAuthorizationPrincipal[] getPrincipalsFromPermissions(IPermission[] permissions) throws AuthorizationException { Set principals = new HashSet(); for (int i = 0; i < permissions.length; i++) { IAuthorizationPrincipal principal = getPrincipal(permissions[i]); principals.add(principal); } return ((IAuthorizationPrincipal[]) principals.toArray(new IAuthorizationPrincipal[principals.size()])); } /** * Returns the String used by an <code>IPermission</code> to represent an <code> * IAuthorizationPrincipal</code>. * * @param principal org.apereo.portal.security.IAuthorizationPrincipal */ public String getPrincipalString(IAuthorizationPrincipal principal) { return getPrincipalString(principal.getType(), principal.getKey()); } private String getPrincipalString(Class pType, String pKey) { Integer type = EntityTypesLocator.getEntityTypes().getEntityIDFromType(pType); return type + PRINCIPAL_SEPARATOR + pKey; } /** * Returns the <code>IPermissions</code> owner has granted this <code>Principal</code> for the * specified activity and target. Null parameters will be ignored, that is, all <code> * IPermissions</code> matching the non-null parameters are retrieved. So, <code> * getPermissions(principal,null, null, null)</code> should retrieve all <code>IPermissions * </code> for a <code>Principal</code>. Ignore any cached <code>IPermissions</code>. * * @return org.apereo.portal.security.IPermission[] * @param principal IAuthorizationPrincipal * @param owner java.lang.String * @param activity java.lang.String * @param target java.lang.String * @exception AuthorizationException indicates authorization information could not be retrieved. */ public IPermission[] getUncachedPermissionsForPrincipal( IAuthorizationPrincipal principal, String owner, String activity, String target) throws AuthorizationException { String pString = getPrincipalString(principal); return primRetrievePermissions(owner, pString, activity, target); } /** * Factory method for an <code>IPermission</code>. * * @param owner String * @param principal IAuthorizationPrincipal * @return org.apereo.portal.security.IPermission */ public IPermission newPermission(String owner, IAuthorizationPrincipal principal) { IPermission p = getPermissionStore().newInstance(owner); if (principal != null) { String pString = getPrincipalString(principal); p.setPrincipal(pString); } return p; } /** * Factory method for IPermissionManager. * * @return org.apereo.portal.security.IPermissionManager * @param owner java.lang.String */ public IPermissionManager newPermissionManager(String owner) { return new PermissionManagerImpl(owner, this); } /** * Factory method for IAuthorizationPrincipal. First check the principal cache, and if not * present, create the principal and cache it. * * @return org.apereo.portal.security.IAuthorizationPrincipal * @param key java.lang.String * @param type java.lang.Class */ public IAuthorizationPrincipal newPrincipal(String key, Class type) { final Tuple<String, Class> principalKey = new Tuple<String, Class>(key, type); final Element element = this.principalCache.get(principalKey); //principalCache is self populating, it can never return a null entry return (IAuthorizationPrincipal) element.getObjectValue(); } /** * Converts an <code>IGroupMember</code> into an <code>IAuthorizationPrincipal</code>. * * @return org.apereo.portal.security.IAuthorizationPrincipal * @param groupMember org.apereo.portal.groups.IGroupMember */ public IAuthorizationPrincipal newPrincipal(IGroupMember groupMember) throws GroupsException { String key = groupMember.getKey(); Class type = groupMember.getType(); if (log.isDebugEnabled()) log.debug("AuthorizationImpl.newPrincipal(): for " + type + "(" + key + ")"); return newPrincipal(key, type); } private IAuthorizationPrincipal primNewPrincipal(String key, Class type) { return new AuthorizationPrincipalImpl(key, type, this); } /** * Factory method for IUpdatingPermissionManager. * * @return org.apereo.portal.security.IUpdatingPermissionManager * @param owner java.lang.String */ public IUpdatingPermissionManager newUpdatingPermissionManager(String owner) { return new UpdatingPermissionManagerImpl(owner, this); } /** * Returns permissions for a principal. First check the entity caching service, and if the * permissions have not been cached, retrieve and cache them. * * @return IPermission[] * @param principal org.apereo.portal.security.IAuthorizationPrincipal */ private IPermission[] primGetPermissionsForPrincipal(IAuthorizationPrincipal principal) throws AuthorizationException { if (!this.cachePermissions) { return getUncachedPermissionsForPrincipal(principal, null, null, null); } IPermissionSet ps = null; // Check the caching service for the Permissions first. ps = cacheGet(principal); if (ps == null) synchronized (principal) { ps = cacheGet(principal); if (ps == null) { IPermission[] permissions = getUncachedPermissionsForPrincipal(principal, null, null, null); ps = new PermissionSetImpl(permissions, principal); cacheAdd(ps); } } // end synchronized return ps.getPermissions(); } /** * @return IPermission[] * @param principal org.apereo.portal.security.IAuthorizationPrincipal * @param owner String * @param activity String * @param target String */ private IPermission[] primGetPermissionsForPrincipal( IAuthorizationPrincipal principal, String owner, String activity, String target) throws AuthorizationException { /* * Get a list of all permissions for the specified principal, then iterate * through them to build a list of the permissions matching the specified criteria. */ IPermission[] perms = primGetPermissionsForPrincipal(principal); if (owner == null && activity == null && target == null) { return perms; } // If there are no permissions left, no need to look through group mappings. if (perms.length == 0) { return perms; } Set<String> containingGroups; if (target != null) { final Element element = this.entityParentsCache.get(target); if (element != null) { containingGroups = (Set<String>) element.getObjectValue(); } else { containingGroups = new HashSet<String>(); //Ignore target entity lookups for the various synthetic ALL targets if (!IPermission.ALL_CATEGORIES_TARGET.equals(target) && !IPermission.ALL_GROUPS_TARGET.equals(target) && !IPermission.ALL_PORTLETS_TARGET.equals(target) && !IPermission.ALL_TARGET.equals(target)) { // UP-4410; It would be ideal if the target string indicated it was a group or entity that might be // a member of a group so we could determine whether to check what groups the target entity might be // contained within to see if the principal has permission to the containing group, but it does not // (too significant to refactor database values at this point). If the owner and activity strings map to // a type of target that might be a group name or entity name, create a set of the groups the target // entity is contained in. boolean checkTargetForContainingGroups = true; if (owner != null && activity != null) { IPermissionActivity permissionActivity = permissionOwner.getPermissionActivity(owner, activity); if (nonEntityPermissionTargetProviders.contains( permissionActivity.getTargetProviderKey())) { checkTargetForContainingGroups = false; } } if (checkTargetForContainingGroups) { log.debug( "Target '{}' is an entity. Checking for group or groups containing entity", target); IGroupMember targetEntity = GroupService.findGroup(target); if (targetEntity == null) { if (target.startsWith(IPermission.PORTLET_PREFIX)) { targetEntity = GroupService.getGroupMember( target.replace(IPermission.PORTLET_PREFIX, ""), IPortletDefinition.class); } else { targetEntity = GroupService.getGroupMember(target, IPerson.class); } } if (targetEntity != null) { for (IEntityGroup ancestor : targetEntity.getAncestorGroups()) { containingGroups.add(ancestor.getKey()); } } } } this.entityParentsCache.put(new Element(target, containingGroups)); } } else { containingGroups = new HashSet<String>(); } List<IPermission> al = new ArrayList<IPermission>(perms.length); for (int i = 0; i < perms.length; i++) { String permissionTarget = perms[i].getTarget(); if ( // owner matches (owner == null || owner.equals(perms[i].getOwner())) && // activity matches (activity == null || activity.equals(perms[i].getActivity())) && // target matches or is a member of the current permission target (target == null || target.equals(permissionTarget) || containingGroups.contains(permissionTarget))) { al.add(perms[i]); } } if (log.isTraceEnabled()) { log.trace( "AuthorizationImpl.primGetPermissionsForPrincipal(): " + "Principal: " + principal + " owner: " + owner + " activity: " + activity + " target: " + target + " : permissions retrieved: " + al); } else if (log.isDebugEnabled()) { log.debug( "AuthorizationImpl.primGetPermissionsForPrincipal(): " + "Principal: " + principal + " owner: " + owner + " activity: " + activity + " target: " + target + " : number of permissions retrieved: " + al.size()); } return ((IPermission[]) al.toArray(new IPermission[al.size()])); } /** * @return IPermission[] * @param owner String * @param principal String * @param activity String * @param target String */ private IPermission[] primRetrievePermissions( String owner, String principal, String activity, String target) throws AuthorizationException { return getPermissionStore().select(owner, principal, activity, target, null); } /** * Removes <code>IPermissions</code> for the <code>IAuthorizationPrincipals</code> from the * cache. * * @param principals IAuthorizationPrincipal[] */ private void removeFromPermissionsCache(IAuthorizationPrincipal[] principals) throws AuthorizationException { for (int i = 0; i < principals.length; i++) { cacheRemove(principals[i]); } } /** * Removes <code>IPermissions</code> from the cache. * * @param permissions IPermission[] */ private void removeFromPermissionsCache(IPermission[] permissions) throws AuthorizationException { IAuthorizationPrincipal[] principals = getPrincipalsFromPermissions(permissions); removeFromPermissionsCache(principals); } /** * Removes <code>IPermissions</code> from the back end store. * * @param permissions IPermission[] * @exception AuthorizationException */ public void removePermissions(IPermission[] permissions) throws AuthorizationException { if (permissions.length > 0) { getPermissionStore().delete(permissions); if (this.cachePermissions) { removeFromPermissionsCache(permissions); } } } /** * Updates <code>IPermissions</code> in the back end store. * * @param permissions IPermission[] * @exception AuthorizationException */ public void updatePermissions(IPermission[] permissions) throws AuthorizationException { if (permissions.length > 0) { getPermissionStore().update(permissions); if (this.cachePermissions) { removeFromPermissionsCache(permissions); } } } }