001/* 002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Thomas Roger 016 */ 017 018package org.nuxeo.ecm.permissions; 019 020import static org.nuxeo.ecm.core.api.event.CoreEventConstants.DOCUMENT_REFS; 021import static org.nuxeo.ecm.core.api.event.CoreEventConstants.REPOSITORY_NAME; 022import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.ACE_STATUS_UPDATED; 023import static org.nuxeo.ecm.core.api.security.ACL.INHERITED_ACL; 024import static org.nuxeo.ecm.permissions.Constants.ACE_INFO_COMMENT; 025import static org.nuxeo.ecm.permissions.Constants.ACE_INFO_DIRECTORY; 026import static org.nuxeo.ecm.permissions.Constants.ACE_INFO_NOTIFY; 027import static org.nuxeo.ecm.permissions.Constants.ACE_KEY; 028import static org.nuxeo.ecm.permissions.Constants.ACL_NAME_KEY; 029import static org.nuxeo.ecm.permissions.Constants.COMMENT_KEY; 030import static org.nuxeo.ecm.permissions.Constants.PERMISSION_NOTIFICATION_EVENT; 031import static org.nuxeo.ecm.permissions.PermissionHelper.computeDirectoryId; 032 033import java.util.List; 034 035import org.nuxeo.ecm.core.api.CoreInstance; 036import org.nuxeo.ecm.core.api.CoreSession; 037import org.nuxeo.ecm.core.api.DocumentModel; 038import org.nuxeo.ecm.core.api.DocumentRef; 039import org.nuxeo.ecm.core.api.security.ACE; 040import org.nuxeo.ecm.core.api.security.ACL; 041import org.nuxeo.ecm.core.api.security.ACP; 042import org.nuxeo.ecm.core.event.Event; 043import org.nuxeo.ecm.core.event.EventBundle; 044import org.nuxeo.ecm.core.event.EventContext; 045import org.nuxeo.ecm.core.event.EventService; 046import org.nuxeo.ecm.core.event.PostCommitFilteringEventListener; 047import org.nuxeo.ecm.core.event.impl.DocumentEventContext; 048import org.nuxeo.ecm.directory.Session; 049import org.nuxeo.ecm.directory.api.DirectoryService; 050import org.nuxeo.runtime.api.Framework; 051 052/** 053 * Listener listening for {@code ACEStatusUpdated} event to send a notification for ACEs becoming effective. 054 * 055 * @since 7.4 056 */ 057public class ACEStatusUpdatedListener implements PostCommitFilteringEventListener { 058 059 @Override 060 public void handleEvent(EventBundle events) { 061 for (Event event : events) { 062 handleEvent(event); 063 } 064 } 065 066 @SuppressWarnings("unchecked") 067 protected void handleEvent(Event event) { 068 EventContext ctx = event.getContext(); 069 String repositoryName = (String) ctx.getProperty(REPOSITORY_NAME); 070 List<DocumentRef> docRefs = (List<DocumentRef>) ctx.getProperty(DOCUMENT_REFS); 071 if (repositoryName == null || docRefs == null) { 072 return; 073 } 074 075 try (CoreSession session = CoreInstance.openCoreSessionSystem(repositoryName)) { 076 docRefs.stream().filter(session::exists).forEach(ref -> { 077 DocumentModel doc = session.getDocument(ref); 078 checkForEffectiveACE(session, doc); 079 }); 080 } 081 } 082 083 protected void checkForEffectiveACE(CoreSession session, DocumentModel doc) { 084 DirectoryService directoryService = Framework.getService(DirectoryService.class); 085 ACP acp = doc.getACP(); 086 for (ACL acl : acp.getACLs()) { 087 String aclName = acl.getName(); 088 if (INHERITED_ACL.equals(aclName)) { 089 // ignore inherited acl 090 continue; 091 } 092 093 for (ACE ace : acl) { 094 if (ace.isGranted() && ace.isEffective()) { 095 try (Session dirSession = directoryService.open(ACE_INFO_DIRECTORY)) { 096 String id = computeDirectoryId(doc, acl.getName(), ace.getId()); 097 DocumentModel entry = dirSession.getEntry(id); 098 if (entry != null) { 099 boolean notify = (boolean) entry.getPropertyValue(ACE_INFO_NOTIFY); 100 String comment = (String) entry.getPropertyValue(ACE_INFO_COMMENT); 101 if (notify) { 102 // send the event for the notification 103 ace.putContextData(COMMENT_KEY, comment); 104 firePermissionNotificationEvent(session, doc, aclName, ace); 105 } 106 } 107 } 108 } 109 } 110 } 111 } 112 113 protected void firePermissionNotificationEvent(CoreSession session, DocumentModel doc, String aclName, ACE ace) { 114 DocumentEventContext docCtx = new DocumentEventContext(session, session.getPrincipal(), doc); 115 docCtx.setProperty(ACE_KEY, ace); 116 docCtx.setProperty(ACL_NAME_KEY, aclName); 117 EventService eventService = Framework.getService(EventService.class); 118 eventService.fireEvent(PERMISSION_NOTIFICATION_EVENT, docCtx); 119 } 120 121 @Override 122 public boolean acceptEvent(Event event) { 123 return ACE_STATUS_UPDATED.equals(event.getName()); 124 } 125}