001/* 002 * Copyright 2018 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.cms.model.restrictions; 017 018import java.util.HashMap; 019import java.util.Map; 020import java.util.UUID; 021 022import org.apache.avalon.framework.component.Component; 023import org.apache.avalon.framework.component.ComponentException; 024import org.apache.avalon.framework.configuration.Configuration; 025import org.apache.avalon.framework.configuration.ConfigurationException; 026 027import org.ametys.cms.model.restrictions.Restriction.RestrictionResult; 028import org.ametys.cms.repository.Content; 029import org.ametys.plugins.repository.AmetysRepositoryException; 030import org.ametys.runtime.model.Model; 031import org.ametys.runtime.model.ModelItem; 032import org.ametys.runtime.plugin.component.ThreadSafeComponentManager; 033 034/** 035 * Helper for definitions with restrictions on contents 036 */ 037public class ContentRestrictedModelItemHelper implements Component 038{ 039 /** The Avalon role name */ 040 public static final String ROLE = ContentRestrictedModelItemHelper.class.getName(); 041 042 private final Map<String, Map<String, RestrictedModelItem>> _restrictionsToLookup = new HashMap<>(); 043 044 /** 045 * Determine whether a model item can be read at this time. 046 * @param item the restricted model item on which check the restrictions 047 * @param content The content where item is to be written on. Can be null, on content creation. 048 * @return <code>true</code> if the current user is allowed to write the model item of this content. 049 * @throws AmetysRepositoryException if an error occurs while accessing the content workflow. 050 */ 051 @SuppressWarnings("unchecked") 052 public boolean canRead(Content content, RestrictedModelItem item) throws AmetysRepositoryException 053 { 054 Restriction restrictions = item.getRestriction(); 055 if (restrictions != null) 056 { 057 RestrictionResult firstResult = restrictions.canRead(content, item); 058 if (!RestrictionResult.UNKNOWN.equals(firstResult)) 059 { 060 return RestrictionResult.TRUE.equals(firstResult); 061 } 062 } 063 064 ModelItem parent = item.getParent(); 065 if (parent != null && parent instanceof RestrictedModelItem) 066 { 067 // Check write access on parent model item 068 return ((RestrictedModelItem<Content>) parent).canRead(content); 069 } 070 071 return true; 072 } 073 074 /** 075 * Determine whether a model item can be written at this time. 076 * @param item the restricted model item on which check the restrictions 077 * @param content The content where item is to be written on. Can be null, on content creation. 078 * @return <code>true</code> if the current user is allowed to write the model item of this content. 079 * @throws AmetysRepositoryException if an error occurs while accessing the content workflow. 080 */ 081 @SuppressWarnings("unchecked") 082 public boolean canWrite(Content content, RestrictedModelItem item) throws AmetysRepositoryException 083 { 084 Restriction restrictions = item.getRestriction(); 085 if (restrictions != null) 086 { 087 RestrictionResult firstResult = restrictions.canWrite(content, item); 088 if (!RestrictionResult.UNKNOWN.equals(firstResult)) 089 { 090 return RestrictionResult.TRUE.equals(firstResult); 091 } 092 } 093 094 ModelItem parent = item.getParent(); 095 if (parent != null && parent instanceof RestrictedModelItem) 096 { 097 // Check write access on parent model item 098 return ((RestrictedModelItem<Content>) parent).canWrite(content); 099 } 100 101 return canRead(content, item); 102 } 103 104 /** 105 * Parses the attribute definition's restrictions. 106 * @param pluginName the plugin name 107 * @param attributeConfiguration the attribute configuration to use. 108 * @param restrictedModelItem the restricted model item 109 * @param restrictionManager the restrictions component manager. 110 * @throws ConfigurationException if the configuration is not valid. 111 */ 112 @SuppressWarnings("unchecked") 113 public void parseAndSetRestriction(String pluginName, RestrictedModelItem restrictedModelItem, Configuration attributeConfiguration, ThreadSafeComponentManager<Restriction> restrictionManager) throws ConfigurationException 114 { 115 Configuration restrictToConf = attributeConfiguration.getChild("restrict-to", false); 116 117 if (restrictToConf != null) 118 { 119 Configuration customRestriction = restrictToConf.getChild("custom-restriction", false); 120 String restrictionClassName; 121 122 if (customRestriction != null) 123 { 124 restrictionClassName = customRestriction.getAttribute("class"); 125 } 126 else 127 { 128 restrictionClassName = DefaultRestriction.class.getName(); 129 } 130 131 String modelId = restrictedModelItem.getModel().getId(); 132 final String restrictionRole = modelId + "$" + restrictedModelItem.getPath() + "$" + UUID.randomUUID().toString(); 133 134 try 135 { 136 Class restrictionClass = Class.forName(restrictionClassName); 137 restrictionManager.addComponent(pluginName, null, restrictionRole, restrictionClass, restrictToConf); 138 } 139 catch (Exception e) 140 { 141 throw new ConfigurationException("Unable to instantiate restrictions for class: " + restrictionClassName, e); 142 } 143 144 if (!_restrictionsToLookup.containsKey(modelId)) 145 { 146 _restrictionsToLookup.put(modelId, new HashMap<>()); 147 } 148 149 Map<String, RestrictedModelItem> restrictionsByModel = _restrictionsToLookup.get(modelId); 150 151 // Will be affected later when restrictionManager will be initialized 152 // in lookupRestrictions() call 153 restrictionsByModel.put(restrictionRole, restrictedModelItem); 154 155 } 156 } 157 158 /** 159 * Retrieves local restrictions components and set them into 160 * previously parsed element definition. 161 * @param model the model 162 * @param restrictionManager the restrictions component manager. 163 * @throws Exception if an error occurs. 164 */ 165 public void lookupRestrictions(Model model, ThreadSafeComponentManager<Restriction> restrictionManager) throws Exception 166 { 167 restrictionManager.initialize(); 168 169 if (_restrictionsToLookup.containsKey(model.getId())) 170 { 171 for (Map.Entry<String, RestrictedModelItem> entry : _restrictionsToLookup.get(model.getId()).entrySet()) 172 { 173 String restrictionRole = entry.getKey(); 174 RestrictedModelItem modelItem = entry.getValue(); 175 176 try 177 { 178 modelItem.setRestriction(restrictionManager.lookup(restrictionRole)); 179 } 180 catch (ComponentException e) 181 { 182 throw new Exception("Unable to lookup restriction role: '" + restrictionRole + "' for model item: " + modelItem, e); 183 } 184 } 185 } 186 187 } 188}