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.io.registry.reflect.Instantiations.SINGLETON; 021import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE; 022import static org.nuxeo.ecm.permissions.Constants.ACE_INFO_COMMENT; 023import static org.nuxeo.ecm.permissions.Constants.ACE_INFO_DIRECTORY; 024import static org.nuxeo.ecm.permissions.Constants.ACE_INFO_NOTIFY; 025 026import java.io.IOException; 027import java.io.Serializable; 028import java.util.HashMap; 029import java.util.Map; 030 031import org.codehaus.jackson.JsonGenerator; 032import org.nuxeo.ecm.core.api.DocumentModel; 033import org.nuxeo.ecm.core.api.security.ACE; 034import org.nuxeo.ecm.core.api.security.ACL; 035import org.nuxeo.ecm.core.api.security.ACP; 036import org.nuxeo.ecm.core.io.marshallers.json.enrichers.AbstractJsonEnricher; 037import org.nuxeo.ecm.core.io.registry.reflect.Setup; 038import org.nuxeo.ecm.core.schema.utils.DateParser; 039import org.nuxeo.ecm.directory.Session; 040import org.nuxeo.ecm.directory.api.DirectoryService; 041import org.nuxeo.runtime.api.Framework; 042 043/** 044 * Enrich {@link DocumentModel} Json. 045 * <p> 046 * Add {@link DocumentModel}'s ACP as json attachment with notifications info for each ACE (such as whether a 047 * notification should be send and the notification comment). 048 * </p> 049 * <p> 050 * Enable if parameter enrichers.document=extendedAcls is present. 051 * </p> 052 * <p> 053 * Format is: 054 * 055 * <pre> 056 * {@code 057 * { 058 * "entity-type":"document", 059 * ... 060 * "contextParameters": { 061 * "acls": [ 062 * { 063 * "name":" inherited", 064 * "ace": [ 065 * { 066 * "username": "administrators", 067 * "permission": "Everything", 068 * "granted": true, 069 * "notify": false, 070 * "comment": "" 071 * }, 072 * ... 073 * ] 074 * }, 075 * ... 076 * ] 077 * } 078 * } 079 * </pre> 080 * </p> 081 * 082 * @since 7.4 083 */ 084@Setup(mode = SINGLETON, priority = REFERENCE) 085public class ExtendedACLJsonEnricher extends AbstractJsonEnricher<DocumentModel> { 086 087 public static final String NAME = "extendedAcls"; 088 089 public ExtendedACLJsonEnricher() { 090 super(NAME); 091 } 092 093 @Override 094 public void write(JsonGenerator jg, DocumentModel document) throws IOException { 095 ACP item = document.getACP(); 096 jg.writeArrayFieldStart("acls"); 097 for (ACL acl : item.getACLs()) { 098 jg.writeStartObject(); 099 jg.writeStringField("name", acl.getName()); 100 jg.writeArrayFieldStart("ace"); 101 for (ACE ace : acl.getACEs()) { 102 jg.writeStartObject(); 103 jg.writeStringField("id", ace.getId()); 104 jg.writeStringField("username", ace.getUsername()); 105 jg.writeStringField("permission", ace.getPermission()); 106 jg.writeBooleanField("granted", ace.isGranted()); 107 jg.writeStringField("creator", ace.getCreator()); 108 jg.writeStringField("begin", 109 ace.getBegin() != null ? DateParser.formatW3CDateTime(ace.getBegin().getTime()) : null); 110 jg.writeStringField("end", 111 ace.getEnd() != null ? DateParser.formatW3CDateTime(ace.getEnd().getTime()) : null); 112 jg.writeStringField("status", ace.getStatus().toString().toLowerCase()); 113 Map<String, Serializable> m = computeAdditionalFields(document, acl.getName(), ace.getId()); 114 for (Map.Entry<String, Serializable> entry : m.entrySet()) { 115 jg.writeObjectField(entry.getKey(), entry.getValue()); 116 } 117 jg.writeEndObject(); 118 } 119 jg.writeEndArray(); 120 jg.writeEndObject(); 121 } 122 jg.writeEndArray(); 123 } 124 125 protected Map<String, Serializable> computeAdditionalFields(DocumentModel doc, String aclName, String aceId) { 126 Map<String, Serializable> m = new HashMap<>(); 127 128 DirectoryService directoryService = Framework.getLocalService(DirectoryService.class); 129 Session session = null; 130 try { 131 session = directoryService.open(ACE_INFO_DIRECTORY); 132 String id = computeDirectoryId(doc, aclName, aceId); 133 DocumentModel entry = session.getEntry(id); 134 if (entry != null) { 135 m.put("notify", entry.getPropertyValue(ACE_INFO_NOTIFY)); 136 m.put("comment", entry.getPropertyValue(ACE_INFO_COMMENT)); 137 } 138 } finally { 139 if (session != null) { 140 session.close(); 141 } 142 } 143 144 return m; 145 } 146 147 protected String computeDirectoryId(DocumentModel doc, String aclName, String aceId) { 148 return String.format("%s:%s:%s:%s", doc.getId(), doc.getRepositoryName(), aclName, aceId); 149 } 150 151}