Generate pdf file in Secured mode - java

I have written a code for pdf generation and it is working fine but now I to generate a pdf file in secured mode.
Here is my code for Secured mode
try {
HttpServletResponse response = ServletActionContext.getResponse();
PDFGenerator pdf = new PDFGenerator();
PDFGenerator generator=new PDFGenerator();
/* byte[] bytes = null;
bytes = (generator.generatepdf(sosValues.getCmaId(), null)).toByteArray();
//bytes = buffer.toByteArray();
response.setContentLength(bytes.length);
if (bytes != null) {
bis = new ByteArrayInputStream(bytes);
}*/
ByteArrayOutputStream baos=generator.generatepdf(sosValues.getCmaId(), null);
bis = new ByteArrayInputStream(baos.toByteArray());
PdfReader pdfReader=new PdfReader(bis);
PdfStamper pdfStamper=new PdfStamper(pdfReader, baos);
pdfStamper.setEncryption(null,null, PdfWriter.HideToolbar, PdfWriter.STRENGTH40BITS);
pdfStamper.setEncryption("Hello".getBytes(), "World".getBytes(), PdfWriter.AllowPrinting
| PdfWriter.AllowCopy, PdfWriter.STRENGTH40BITS);
pdfStamper.close();
baos.close();
} catch (Exception e) {
e.printStackTrace();
}
While debugging I was getting an exception at this line pdfStamper.setEncryption(null,null, PdfWriter.HideToolbar, PdfWriter.STRENGTH40BITS);
Exception in browser was:
The server encountered an internal error that prevented it from fulfilling this request.

PdfWriter.HideToolbar is a viewer preference, not a permission.
This is the list of permissions:
PdfWriter.ALLOW_PRINTING
PdfWriter.ALLOW_MODIFY_CONTENTS
PdfWriter.ALLOW_COPY
PdfWriter.ALLOW_MODIFY_ANNOTATIONS
PdfWriter.ALLOW_FILL_IN
PdfWriter.ALLOW_SCREEN_READERS
PdfWriter.ALLOW_ASSEMBLY
PdfWriter.ALLOW_DEGRADED_PRINTING
Moreover: hiding the toolbar in the hope to secure a PDF is wrong. Please read my answer to How to disable download option of pdf file in c# ?
Even using encryption to avoid printing may not be the best of ideas. See How to protect a PDF with a username and password?
However, this isn't what causes your problem. The internal error is caused by the strange way you're using the ByteArrayOutputStream. You generate a PDF in memory in the generatepdf() method. You didn't share that method, but:
if you're closing that stream, you get the exception because you're trying to add new bytes to it with your stamper object. You can't add extra bytes to a closed OutputStream.
if you're not closing that stream, your PDF isn't completer and you'll get an exception when PdfReader tries to read the (unfinished) PDF.
Furthermore, it's very strange that you would first create the PDF, and then read that PDF to encrypt it. Why not encrypt it right away? That saves you CPU-time.

Related

Convert byteArray to XSSFWorkbook using Apache POI

I am using Apache POI and I am trying to send a xlsx file as HTTP request and get it back as response. I am using jayway restassured for making HTTP requests.
Here is the part of the code where I send the request
File file = new File("path");
String response = given().multipart(file).when().post("URL").getBody().asString();
byte[] bytes = response.getBytes("ISO-8859-1");
InputStream stream = new ByteArrayOutputStream(bytes);
try
{
XSSFWorkbook workbook = new XSSFWorkbook(stream);
}
catch(Exception e){
e.printStackTrace();
}
Here is the code where the response is generated for the request
XSSFWorkbook workBook; //this workBook has the workbook sent as HTTP request
//code to make changes in workBook
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
workBook.write(outStream);
byte[] byteArray = outStream.toByteArray();
String responseBody = new String(byteArray, "ISO-8859-1");
context.response().putHeader("Content-Type", "multipart/form-data").setStatusCode(200).end(responseBody);
So, what I am trying to do is send a xlsx file as request make some changes and get it back as a string response, convert it back to xssfworkbook. When converting back I get error in the following line-
XSSFWorkbook workbook = new XSSFWorkbook(stream);
The error I get is
java.util.zip.ZipException: invalid code lengths set
You cannot simply send the byte-array as ISO-8859-1 encoded text the way you attempt.
There will be special characters that might get replaced/truncated/modified.
Currently you mix binary data and a text-only channel (HTTP). You will need to do it differently, either use a binary data transfer and not convert it to String or use some binary-to-text representation, see e.g. https://en.wikipedia.org/wiki/Binary-to-text_encoding, the most common one being Base64
Use
InputStream stream = new ByteArrayInputStream(bytes);

PDF merging with itext and pdfbox

I have multi module maven project, in that there is a process of request generation and in this process there are some upload component of vaadin in these we are uploading some documents that must be only png, jpgs, pdf and bmp.
Now at last of this process i am merging all the document types into one pdf and then downloading it with file downloader.
The function i am calling on a button click event is:
/**
* This function is responsible for getting
* all documents from request and merge
* them in a single pdf file for
* download purposes
* #throws Exception
*/
protected void downloadMergedDocument() throws Exception {
// Calling create pdf function for merged pdf
createPDF();
// Setting the merged file as a resource for file downloader
Resource myResource = new FileResource(new File (mergedReportPath +request.getWebProtocol()+ ".pdf"));
FileDownloader fileDownloader = new FileDownloader(myResource);
// Extending the download button for download
fileDownloader.extend(downloadButton);
}
/**
* This function is responsible for providing
* the PDF related to a particular request that
* contains all the documents merged inside it
* #throws Exception
*/
private void createPDF() throws Exception {
try{
// Getting the current request
request = evaluationRequestUI.getRequest();
// Fetching all documents of the request
Collection<DocumentBean> docCollection = request.getDocuments();
// Initializing Document of using itext library
Document doc = new Document();
// Setting PdfWriter for getting the merged images file
PdfWriter.getInstance(doc, new FileOutputStream(mergedReportPath+ "/mergedImages_" + request.getWebProtocol()+ ".pdf"));
// Opening document
l_doc.open();
/**
* Here iterating on document collection for the images type
* document for merging them into one pdf
*/
for (DocumentBean documentBean : docCollection) {
byte[] documents = documentBean.getByteArray();
if(documentBean.getFilename().toLowerCase().contains("png") ||
documentBean.getFilename().toLowerCase().contains("jpeg") ||
documentBean.getFilename().toLowerCase().contains("jpg") ||
documentBean.getFilename().toLowerCase().contains("bmp")){
Image img = Image.getInstance(documents);
doc.setPageSize(img);
doc.newPage();
img.setAbsolutePosition(0, 0);
doc.add(img);
}
}
// Closing the document
doc.close();
/**
* Here we get all the images type documents merged into
* one pdf, now moving to pdfbox for searching the pdf related
* document types in the request and merging the above resultant
* pdf and the pdf document in the request into one pdf
*/
PDFMergerUtility utility = new PDFMergerUtility();
// Adding the above resultant pdf as a source
utility.addSource(new File(mergedReportPath+ "/mergedImages_" + request.getWebProtocol()+ ".pdf"));
// Iterating for the pdf document types in the collection
for (DocumentBean documentBean : docCollection) {
byte[] documents = documentBean.getByteArray();
if(documentBean.getFilename().toLowerCase().contains("pdf")){
utility.addSource(new ByteArrayInputStream(documents));
}
}
// Here setting the final pdf name
utility.setDestinationFileName(mergedReportPath +request.getWebProtocol()+ ".pdf");
// Here final merging and then result
utility.mergeDocuments();
}catch(Exception e){
m_logger.error("CATCH", e);
throw e;
}
}
Note: mergedReportPath is a path defined for pdf files to be stored and then
retreive from there for download purposes.
Now, i have two problems in that:
When i do this process for a first request , it give me the pdfs in the
destination folder but it does not download it.
When i again do the this process for the second request, it get stuck on
the utility.mergedocuments(), i mean if it found that the pdf is already
present in the destination folder it get stuck. I dont know where the
problem is. Please Help
In the 2.0 version of PDFBox, you can set an output stream with setDestinationStream(). Thus, you just call
response.setContentType("application/pdf");
OutputStream os = response.getOutputStream();
utility.setDestinationStream(os);
utility.mergeDocuments();
os.flush();
os.close();
You can't set the response size this way; if you have to, use ByteArrayOutputStream like in Bruno's answer or this one.
In the comment section of your question, you have clarified that you don't need the file on disk, but that you want to send the PDF to the browser. You want to know how to achieve this. This is explained in the official documentation: How can I serve a PDF to a browser without storing a file on the server side?
This is how you create a PDF in memory:
// step 1
Document document = new Document();
// step 2
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter.getInstance(document, baos);
// step 3
document.open();
// step 4
document.add(new Paragraph("Hello"));
// step 5
document.close();
Merging PDFs is done with PdfCopy: How to merge documents correctly?
You need to apply the same principle as above to those examples: replace the FileOutputStream by a ByteArrayOutputStream.
Now you have PDF bytes that are stored in the baos object. We can send it to the browser like this:
// setting some response headers
response.setHeader("Expires", "0");
response.setHeader("Cache-Control",
"must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
// setting the content type
response.setContentType("application/pdf");
// the contentlength
response.setContentLength(baos.size());
// write ByteArrayOutputStream to the ServletOutputStream
OutputStream os = response.getOutputStream();
baos.writeTo(os);
os.flush();
os.close();
Make sure to read the documentation if you have further questions.

Is it possible to save pdf document to byte array (aspose.pdf for java)

I need to save a pdf document, generated by aspose.pdf for java library to memory (without using temporary file)
I was looking at the documentation and didn't find the save method with the appropriate signature. (I was looking for some kind of outputstream, or at least byte array).
Is it possible? If it is, how can I manage that?
Thanks
Aspose.Pdf for Java supports saving output to both file and stream. Please check following code snippet, It will help you to accomplish the task.
byte[] input = getBytesFromFile(new File("C:/data/HelloWorld.pdf"));
ByteArrayOutputStream output = new ByteArrayOutputStream();
com.aspose.pdf.Document pdfDocument = new com.aspose.pdf.Document(new ByteArrayInputStream(input));
pdfDocument.save(output);
//If you want to read the result into a Document object again, in Java you need to get the
//data bytes and wrap into an input stream.
InputStream inputStream=new ByteArrayInputStream(output.toByteArray());
I am Tilal Ahmad, developer evangelist at Aspose.
I did similar thing.
Here is method to write data to byte:
public byte[] toBytes() {
//create byte array output stream object
ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
//create new data output stream object
DataOutputStream outStream = new DataOutputStream(byteOutStream);
try {//write data to bytes stream
if (data != null) {
outStream.write(data);//write data
}//return array of bytes
return byteOutStream.toByteArray();
}
Then you do something like
yourFileName.toBytes;

How to log inputstream to file in android and then parse it

I am receiving an InputStream from HttpUrlConnection (connection.getInputStream()), and I am parsing the input stream using DocumentBuilder (documenbtBuilder.parse(inputStream)). Before parsing, I want to write the received data to log file. When I do that, I get org.xml.sax.SAXParseException: Unexpected end of document Exception in the parse method. My code works fine if I don't write to file, but I need to log the data received.
Please find the code that writes to file below :
final InputStream input = connection.getInputStream();
writeLogInfo(input);
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(input);
//Method that writes tito log file.
private void writeLogInfo(InputStream input){
OutputStream os = new FileOutputStream("mylogfile.txt");
byte[] buffer = new byte[1024];
int byteRead;
while((byteRead = input.read(buffer)) != -1){
os.write(buffer,0,byteRead);
}
os.flush();
os.close();
}
I suspect it is because of multiple use of InputStream, since the code works when I don't invode writeLogInfo(). I am not closing the inputstream anywhere in my code. What am I doing wrong here ?
When you are writing the content to a file, you are reaching the end of the inputstream.
So after that, when you are trying to parse, you get the exception.
You need to use mark and reset methods on the inputstream before passing it to documentbuilder.
Also, first you need to check if the input stream supports mark.
Here is the javadoc, for your reference
http://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html
Are you sure the size of the file is under 1024 bytes. If not why don't you put your "inputstream" to BufferredInputstream, and create the byte array..
BufferedInputStream bin= new BufferedInputStream(new DataInputStream(input));
byte[] buffer= new byte[bin.available()];
bin.read(buffer);
os.write(buffer);
......
......
bin.close();
......

iText mergeFields in PdfCopy creates invalid pdf

I am working on the task of merging some input PDF documents using iText 5.4.5. The input documents may or may not contain AcroForms and I want to merge the forms as well.
I am using the example pdf files found here and this is the code example:
public class TestForms {
#Test
public void testNoForms() throws DocumentException, IOException {
test("pdf/hello.pdf", "pdf/hello_memory.pdf");
}
#Test
public void testForms() throws DocumentException, IOException {
test("pdf/subscribe.pdf", "pdf/filled_form_1.pdf");
}
private void test(String first, String second) throws DocumentException, IOException {
OutputStream out = new FileOutputStream("/tmp/out.pdf");
InputStream stream = getClass().getClassLoader().getResourceAsStream(first);
PdfReader reader = new PdfReader(new RandomAccessFileOrArray(
new RandomAccessSourceFactory().createSource(stream)), null);
InputStream stream2 = getClass().getClassLoader().getResourceAsStream(second);
PdfReader reader2 = new PdfReader(new RandomAccessFileOrArray(
new RandomAccessSourceFactory().createSource(stream2)), null);
Document pdfDocument = new Document(reader.getPageSizeWithRotation(1));
PdfCopy pdfCopy = new PdfCopy(pdfDocument, out);
pdfCopy.setFullCompression();
pdfCopy.setCompressionLevel(PdfStream.BEST_COMPRESSION);
pdfCopy.setMergeFields();
pdfDocument.open();
pdfCopy.addDocument(reader);
pdfCopy.addDocument(reader2);
pdfCopy.close();
reader.close();
reader2.close();
}
}
With input files containing forms I get a NullPointerException with or without compression enabled.
With standard input docs, the output file is created but when I open it with Acrobat it says there was a problem (14) and no content is displayed.
With standard input docs AND compression disabled the output is created and Acrobat displays it.
Questions
I previously did this using PdfCopyFields but it's now deprecated in favor of the boolean flag mergeFields in the PdfCopy, is this correct? There's no javadoc on that flag and I couldn't find documentation about it.
Assuming the answer to the previous question is Yes, is there anything wrong with my code?
Thanks
We are using PdfCopy to merge differents files, some of files may have fields. We use the version 5.5.3.0. The code is simple and it seems to work fine, BUT sometimes the result file is impossible to print!
Our code :
Public Shared Function MergeFiles(ByVal sourceFiles As List(Of Byte())) As Byte()
Dim document As New Document()
Dim output As New MemoryStream()
Dim copy As iTextSharp.text.pdf.PdfCopy = Nothing
Dim readers As New List(Of iTextSharp.text.pdf.PdfReader)
Try
copy = New iTextSharp.text.pdf.PdfCopy(document, output)
copy.SetMergeFields()
document.Open()
For fileCounter As Integer = 0 To sourceFiles.Count - 1
Dim reader As New PdfReader(sourceFiles(fileCounter))
reader.MakeRemoteNamedDestinationsLocal()
readers.Add(reader)
copy.AddDocument(reader)
Next
Catch exception As Exception
Throw exception
Finally
If copy IsNot Nothing Then copy.Close()
document.Close()
For Each reader As PdfReader In readers
reader.Close()
Next
End Try
Return output.GetBuffer()
End Function
Your usage of PdfCopy.setMergeFields() is correct and your merging code is fine.
The issues you described are because of bugs that have crept into 5.4.5. They should be fixed in rev. 6152 and the fixes will be included in the next release.
Thanks for bringing this to our attention.
Its just to say that we have the same probleme : iText mergeFields in PdfCopy creates invalid pdf. So it is still not fixed in the version 5.5.3.0

Categories