[SalesForce] Render Visualforce page as PDF not working in a Community

I have a VisualForce page that contains an image that I want to render as a PDF. This rendering is done as part of a controller call, which will take the rendered PDF blob and attach it as a File to an Object. If I go through these pages in regular Salesforce, it works just fine rendering the PDF to include the image. If I do it as part of a community, the image does not render (though the rest of the PDF is generated), and the data is not queried for (the PDF form is empty). The image is hosted on Salesforce as a File attachment, and is available at the time of PDF rendering.

Controller snippet:

// Get PDF...
PageReference pdf = Page.CustomReport;
pdf.getParameters().put('id', Id);
pdf.getParameters().put('imageUrl', prepareUrl(Id));
Blob body = pdf.getContent();
// Attach Blob to Object...

VF Page snippet:

<apex:image id="customImage" value="{!imageUrl}" alt="Custom Image" />

I've verified that the URL is indeed populated, and indeed references the image in question, which I can access with a GET request in my browser. My understanding is that the PDF rendering engine may be run in a different context than the original controller, but it leaves me at a loss explaining why this works in regular Salesforce but not the community.

Best Answer

Well, I had sort of answered my own question, but haven't found any documentation to support this.

The PDF rendering indeed happens as its own call with its own context. In regular Salesforce, this continues to execute as the user who made the initial controller call. In the community, this doesn't happen as the authenticated user, but rather the unauthenticated Community Guest User. The URL in question for the image is protected, and requires an authenticated user to access it. The underlying data is also protected, hence no values populating the PDF. This is borne out both in the Debug Logs, and that I was also able to render an image from an unprotected URL (e.g. https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png).

It seems, therefore, the options are:

  • Follow other, similar answers and host these images in Static Resources (which, pushing them up would require the Metadata API, and hanging on to the reference for it). Pass the rest of the data into the page as well (likely unacceptable for sensitive data).
  • Push the images up to be hosted elsewhere, where they would be unprotected resources, and again, hang on to the reference.
  • Pass the base64 encoded image to the page, have the page pass it to an unprotected webservice in a regular GET request, and receive the image back. Confirmed to work, ugly as it is.
  • Get Salesforce or the underlying Flying Saucer library fixed so that PDFs can render base64 encoded images, and use the base64 encoding in the VF page rather than a URL.
  • Use a different PDF rendering engine entirely.
  • Access the VF Page with an HTTPRequest, rather than PageReference.getContent(). In this manner, you can manipulate Request fields like headers, and you can set authentication in the request. The VF Page will then run as the user of the provided authentication.

I would have liked to have seen some documentation in Salesforce stating the difference in behavior between regular use and Community, but so far I haven't had any luck.