/* Index ECM Engine - A system for managing the capture (when created * or received), classification (cataloguing), storage, retrieval, * revision, sharing, reuse and disposition of documents. * * Copyright (C) 2008 Regione Piemonte * Copyright (C) 2008 Provincia di Torino * Copyright (C) 2008 Comune di Torino * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ package it.doqui.index.ecmengine.business.personalization.security.acl; import it.doqui.index.ecmengine.business.personalization.security.ReadersService; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.StringTokenizer; import net.sf.acegisecurity.AccessDeniedException; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.ConfigAttribute; import net.sf.acegisecurity.ConfigAttributeDefinition; import org.alfresco.repo.search.SimpleResultSetMetaData; import org.alfresco.repo.search.impl.lucene.LuceneResultSet; import org.alfresco.repo.security.permissions.PermissionReference; import org.alfresco.repo.security.permissions.impl.ModelDAO; import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; import org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterException; import org.alfresco.service.cmr.search.LimitBy; import org.alfresco.service.cmr.search.PermissionEvaluationMode; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.ResultSetMetaData; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class ACLEntryAfterInvocationProvider extends org.alfresco.repo.security.permissions.impl.acegi.ACLEntryAfterInvocationProvider { private static Log log = LogFactory.getLog(AclCheckDao.ECMENGINE_PERSONALIZATION_ACL_CHECK); private static final String AFTER_ACL_NODE = "AFTER_ACL_NODE"; private ReadersService readersService; private AclCheckDao aclCheckDao; private ModelDAO modelDao; public ResultSet decide(Authentication authentication, Object object, ConfigAttributeDefinition config, ResultSet returnedObject) throws AccessDeniedException { if (returnedObject == null) { return null; } boolean isCheckResultSetACL = false; Iterator<?> iter = config.getConfigAttributes(); while (iter.hasNext()) { ConfigAttribute attr = (ConfigAttribute) iter.next(); if (attr.getAttribute().startsWith(AFTER_ACL_NODE)) { isCheckResultSetACL = true; } } if (returnedObject instanceof LuceneResultSet && isCheckResultSetACL) { if (log.isDebugEnabled()) { log.debug("[ACLEntryAfterInvocationProvider::decide] Delegating..."); } return decideLucene(authentication, object, config, (LuceneResultSet) returnedObject); } else { return super.decide(authentication, object, config, returnedObject); } } public ResultSet decideLucene(Authentication authentication, Object object, ConfigAttributeDefinition config, LuceneResultSet resultSet) throws AccessDeniedException { if (log.isDebugEnabled()) { log.debug("[ACLEntryAfterInvocationProvider::decideLucene] BEGIN"); log.debug("[ACLEntryAfterInvocationProvider::decideLucene] resultset.length: "+resultSet.length()); for(int i=0;i<resultSet.length();i++){ log.debug("[ACLEntryAfterInvocationProvider::decideLucene] resultset["+i+"]: "+resultSet.getDocument(i)); } } try { final long prepareStart = System.currentTimeMillis(); HashMap<Long, Integer> toCheck = new HashMap<Long, Integer>(); Set<String> authorities = readersService.getAuthoritiesForCurrentUser(); if (log.isDebugEnabled()) { log.debug("[ACLEntryAfterInvocationProvider::decideLucene] Authorities: " + authorities); } FilteringResultSet filteringResultSet = new FilteringResultSet(resultSet); ResultSetMetaData rsInfo = resultSet.getResultSetMetaData(); Integer maxSize = null; if (rsInfo.getSearchParameters().getLimitBy() == LimitBy.FINAL_SIZE) { maxSize = new Integer(rsInfo.getSearchParameters().getLimit()); } if (authorities == null) { // L'utente ha privilegi amministrativi if (maxSize != null && maxSize.intValue() > 0 && resultSet.length() > maxSize.intValue()) { // Filtriamo in base alla dimensione massima impostata for (int i = 0; i < resultSet.length(); i++) { filteringResultSet.setIncluded(i, (i < maxSize.intValue())); } filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData( LimitBy.FINAL_SIZE, PermissionEvaluationMode.EAGER, rsInfo.getSearchParameters())); return filteringResultSet; } else { for (int i = 0; i < resultSet.length(); i++) { filteringResultSet.setIncluded(i, true); } // La lunghezza del RS originale non supera la dimensione massima impostata filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData( LimitBy.UNLIMITED, PermissionEvaluationMode.EAGER, rsInfo.getSearchParameters())); return filteringResultSet; // L'utente ha i privilegi amministrativi o di sistema. } } if (log.isDebugEnabled()) { log.debug("[ACLEntryAfterInvocationProvider::decideLucene] Esecuzione codice per utente non admin."); } PermissionReference required = null; boolean configContainsSupportedDefinitions = false; Iterator<?> iter = config.getConfigAttributes(); while (iter.hasNext()) { ConfigAttribute attr = (ConfigAttribute) iter.next(); if (supports(attr)) { configContainsSupportedDefinitions = true; } if (attr.getAttribute().startsWith(AFTER_ACL_NODE)) { StringTokenizer st = new StringTokenizer(attr.getAttribute(), ".", false); if (st.countTokens() != 3) { throw new ACLEntryVoterException("There must be three . separated tokens in each config attribute"); } @SuppressWarnings("unused") String typeString = st.nextToken(); String qNameString = st.nextToken(); String permissionString = st.nextToken(); required = new SimplePermissionReference(QName.createQName(qNameString, getNamespacePrefixResolver()), permissionString); } } // Insieme dei permission group che includono il permesso di Read if (log.isDebugEnabled()) { log.debug("[ACLEntryAfterInvocationProvider::decideLucene] required permission: "+required); } Set<PermissionReference> permissions = new HashSet<PermissionReference>(10); permissions.addAll(modelDao.getGrantingPermissions(required)); permissions.add(modelDao.getPermissionReference(null, PermissionService.ALL_PERMISSIONS)); for (int i = 0; i < resultSet.length(); i++) { if (log.isDebugEnabled()) { log.debug("[ACLEntryAfterInvocationProvider::decideLucene] i: "+i); log.debug("[ACLEntryAfterInvocationProvider::decideLucene] document[i]: "+resultSet.getDocument(i)); } String id = resultSet.getDocument(i).get("DBID"); if (log.isDebugEnabled()) { log.debug("[ACLEntryAfterInvocationProvider::decideLucene] id: "+id); } toCheck.put(new Long(id), new Integer(i)); } final List<Long> toCheckList = new ArrayList<Long>(toCheck.keySet()); if (log.isDebugEnabled()) { final long prepareStop = System.currentTimeMillis(); log.debug("[ACLEntryAfterInvocationProvider::decideLucene] Prepare duration: " + (prepareStop - prepareStart) + " ms [toCheck: " + toCheck.size() + "]"); } final long start = System.currentTimeMillis(); List<Long> readables = aclCheckDao.checkHasPermissionsOnNodes(toCheckList, authorities, permissions); if (log.isDebugEnabled()) { final long stop = System.currentTimeMillis(); log.debug("[ACLEntryAfterInvocationProvider::decideLucene] Check duration: " + (stop - start) + " ms [readables: " + readables.size() + "]"); } final long filteringStart = System.currentTimeMillis(); for (Long readable : readables) { filteringResultSet.setIncluded( toCheck.get(readable).intValue(), true); } if (!configContainsSupportedDefinitions) { if (maxSize == null) { return resultSet; } else if (resultSet.length() > maxSize.intValue()) { for (int i = 0; i < maxSize.intValue(); i++) { filteringResultSet.setIncluded(i, true); } filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData( LimitBy.FINAL_SIZE, PermissionEvaluationMode.EAGER, rsInfo.getSearchParameters())); } else { for (int i = 0; i < resultSet.length(); i++) { filteringResultSet.setIncluded(i, true); } filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData( LimitBy.UNLIMITED, PermissionEvaluationMode.EAGER, rsInfo.getSearchParameters())); } } else { if (maxSize != null) { if (log.isDebugEnabled()) { log.debug("[ACLEntryAfterInvocationProvider::decideLucene] Max RS size: " + maxSize.toString()); } int counter = 0; int included = 0; maxSize = (maxSize <= resultSet.length()) ? maxSize : resultSet.length(); while (counter < maxSize) { if (filteringResultSet.getIncluded(counter)) { included++; } counter++; } while (counter < resultSet.length()) { filteringResultSet.setIncluded(counter, false); counter++; } filteringResultSet.setResultSetMetaData( new SimpleResultSetMetaData(LimitBy.FINAL_SIZE, PermissionEvaluationMode.EAGER, rsInfo.getSearchParameters())); } } // set the default, unlimited result set type filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData( LimitBy.UNLIMITED, PermissionEvaluationMode.EAGER, rsInfo.getSearchParameters())); if (log.isDebugEnabled()) { final long filteringStop = System.currentTimeMillis(); log.debug("[ACLEntryAfterInvocationProvider::decideLucene] Filtering duration: " + (filteringStop - filteringStart) + " ms"); } return filteringResultSet; } finally { log.debug("[ACLEntryAfterInvocationProvider::decideLucene] END"); } } public void setReadersService(ReadersService readersService) { this.readersService = readersService; } public void setAclCheckDao(AclCheckDao aclCheckDao) { this.aclCheckDao = aclCheckDao; } public void setModelDao(ModelDAO modelDao) { this.modelDao = modelDao; } }