Skip to content

Commit

Permalink
XWIKI-21337: Apply PDF templates with the rights of their authors
Browse files Browse the repository at this point in the history
  • Loading branch information
pjeanjean authored and michitux committed Nov 16, 2023
1 parent 95bdd6c commit d28e21a
Show file tree
Hide file tree
Showing 2 changed files with 206 additions and 55 deletions.
Expand Up @@ -29,6 +29,7 @@
import java.io.StringWriter;
import java.lang.reflect.Type;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand All @@ -37,9 +38,9 @@

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.velocity.VelocityContext;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
Expand All @@ -54,8 +55,11 @@
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.DocumentReferenceResolver;
import org.xwiki.model.reference.EntityReferenceSerializer;
import org.xwiki.security.authorization.AuthorExecutor;
import org.xwiki.security.authorization.AuthorizationManager;
import org.xwiki.security.authorization.Right;
import org.xwiki.user.UserReferenceSerializer;
import org.xwiki.velocity.VelocityManager;
import org.xwiki.velocity.XWikiVelocityException;
import org.xwiki.xml.EntityResolver;
import org.xwiki.xml.XMLReaderFactory;
import org.xwiki.xml.XMLUtils;
Expand Down Expand Up @@ -95,30 +99,37 @@ public class PdfExportImpl implements PdfExport
private static final Logger LOGGER = LoggerFactory.getLogger(PdfExportImpl.class);

/** Document name resolver. */
private static DocumentReferenceResolver<String> referenceResolver =
private final DocumentReferenceResolver<String> referenceResolver =
Utils.getComponent(DocumentReferenceResolver.TYPE_STRING, "currentmixed");

/** Document name serializer. */
private static EntityReferenceSerializer<String> referenceSerializer =
private final EntityReferenceSerializer<String> referenceSerializer =
Utils.getComponent(EntityReferenceSerializer.TYPE_STRING);

/** Provides access to document properties. */
private static DocumentAccessBridge dab = Utils.getComponent(DocumentAccessBridge.class);
private final DocumentAccessBridge dab = Utils.getComponent(DocumentAccessBridge.class);

/** Velocity engine manager, used for interpreting velocity. */
private static VelocityManager velocityManager = Utils.getComponent(VelocityManager.class);
private final VelocityManager velocityManager = Utils.getComponent(VelocityManager.class);

private static XMLReaderFactory xmlReaderFactory = Utils.getComponent(XMLReaderFactory.class);
private final XMLReaderFactory xmlReaderFactory = Utils.getComponent(XMLReaderFactory.class);

private final AuthorizationManager authorizationManager = Utils.getComponent(AuthorizationManager.class);

private final AuthorExecutor authorExecutor = Utils.getComponent(AuthorExecutor.class);

private final UserReferenceSerializer<DocumentReference> userReferenceSerializer =
Utils.getComponent(UserReferenceSerializer.TYPE_DOCUMENT_REFERENCE, "document");

/**
* Used to get the temporary directory.
*/
private Environment environment = Utils.getComponent((Type) Environment.class);
private final Environment environment = Utils.getComponent((Type) Environment.class);

/**
* Used to render XSL-FO to PDF.
*/
private XSLFORenderer xslFORenderer = Utils.getComponent(XSLFORenderer.class, "fop");
private final XSLFORenderer xslFORenderer = Utils.getComponent(XSLFORenderer.class, "fop");

@Override
public void exportToPDF(XWikiDocument doc, OutputStream out, XWikiContext context) throws XWikiException
Expand Down Expand Up @@ -184,7 +195,7 @@ private String convertToStrictXHtml(String input)

HTMLCleaner cleaner = Utils.getComponent(HTMLCleaner.class);
HTMLCleanerConfiguration config = cleaner.getDefaultConfiguration();
List<HTMLFilter> filters = new ArrayList<HTMLFilter>(config.getFilters());
List<HTMLFilter> filters = new ArrayList<>(config.getFilters());
filters.add(Utils.getComponent(HTMLFilter.class, "uniqueId"));
config.setFilters(filters);
String result = HTMLUtils.toString(cleaner.clean(new StringReader(input), config));
Expand Down Expand Up @@ -261,7 +272,7 @@ private void renderXSLFO(String xmlfo, OutputStream out, ExportType type, final
throws XWikiException
{
try {
this.xslFORenderer.render(new ByteArrayInputStream(xmlfo.getBytes("UTF-8")), out, type.getMimeType());
this.xslFORenderer.render(new ByteArrayInputStream(xmlfo.getBytes(StandardCharsets.UTF_8)), out, type.getMimeType());
} catch (IllegalStateException e) {
throw createException(e, type, XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION);
} catch (Exception e) {
Expand Down Expand Up @@ -338,7 +349,7 @@ String applyCSS(String html, String css, XWikiContext context)

// Dom4J 2.1.1 disables external DTDs by default, so we set our own XMLReader.
// See https://github.com/dom4j/dom4j/issues/51
XMLReader xmlReader = xmlReaderFactory.createXMLReader();
XMLReader xmlReader = this.xmlReaderFactory.createXMLReader();
reader.setXMLReader(xmlReader);

reader.setEntityResolver(new DefaultEntityResolver());
Expand Down Expand Up @@ -465,28 +476,47 @@ private String getPDFTemplateProperty(String propertyName, XWikiContext context)
DocumentReference templateReference;
DocumentReference classReference;
if (StringUtils.isNotEmpty(pdftemplate)) {
templateReference = referenceResolver.resolve(pdftemplate);
templateReference = this.referenceResolver.resolve(pdftemplate);
classReference = new DocumentReference(templateReference.getWikiReference().getName(), "XWiki", "PDFClass");
} else {
templateReference = dab.getCurrentDocumentReference();
String currentWiki = dab.getCurrentDocumentReference().getRoot().getName();
templateReference = this.dab.getCurrentDocumentReference();
String currentWiki = this.dab.getCurrentDocumentReference().getRoot().getName();
classReference = new DocumentReference(currentWiki, "XWiki", "PDFClass");
}

String result = (String) dab.getProperty(templateReference, classReference, propertyName);
if (StringUtils.isBlank(result)) {
String templateContent = (String) this.dab.getProperty(templateReference, classReference, propertyName);
if (StringUtils.isBlank(templateContent)) {
return "";
}
String templateName = referenceSerializer.serialize(templateReference);

String templateName = this.referenceSerializer.serialize(templateReference);
DocumentReference templateAuthorReference;
String result = templateContent;
try {
StringWriter writer = new StringWriter();
VelocityContext vcontext = velocityManager.getVelocityContext();
velocityManager.getVelocityEngine().evaluate(vcontext, writer, templateName, result);
result = writer.toString();
} catch (XWikiVelocityException e) {
LOGGER.warn("Error applying Velocity to the [{}] property of the [{}] document. Using the property's value "
+ "without applying Velocity.", propertyName, templateName, ExceptionUtils.getRootCauseMessage(e));
templateAuthorReference = this.userReferenceSerializer.serialize(
this.dab.getDocumentInstance(templateReference).getAuthors().getEffectiveMetadataAuthor());
} catch (Exception e) {
LOGGER.warn("Error fetching the author of template [{}] during PDF conversion. Using the [{}] property of "
+ "the document's value without applying Velocity.", templateName, propertyName);
return result;
}

if (this.authorizationManager.hasAccess(Right.SCRIPT, templateAuthorReference, templateReference)) {
try {
result = this.authorExecutor.call(() -> {
StringWriter writer = new StringWriter();
VelocityContext vcontext = this.velocityManager.getVelocityContext();
this.velocityManager.getVelocityEngine().evaluate(vcontext, writer, templateName,
templateContent);
return writer.toString();
}, templateAuthorReference, templateReference);
} catch (Exception e) {
LOGGER.warn("Failed to run Velocity engine in author executor. Using the [{}] property of the [{}] "
+ "document's value without applying Velocity. Reason: [{}]",
propertyName, templateName, ExceptionUtils.getRootCauseMessage(e));
}
}

return result;
}

Expand Down

0 comments on commit d28e21a

Please sign in to comment.