PDFBox - sign PDF have existing signed by another - pdfbox

Trying to sign a PDF existing signed with PDFBox
with this test function :
/**
* Test creating visual signature with the modernized example.
*
* #throws IOException
* #throws CMSException
* #throws OperatorCreationException
* #throws GeneralSecurityException
* #throws TSPException
* #throws CertificateVerificationException
*/
#ParameterizedTest
#MethodSource("signingTypes")
void testCreateVisibleSignature2(boolean externallySign)
throws IOException, CMSException, OperatorCreationException, GeneralSecurityException,
TSPException, CertificateVerificationException
{
// sign PDF
String inPath = IN_DIR + "pdf.pdf";
File destFile;
CreateVisibleSignature2 signing = new CreateVisibleSignature2(keyStore, PASSWORD.toCharArray());
Rectangle2D humanRect = new Rectangle2D.Float(200, 300, 200, 100);
signing.setImageFile(new File(JPEG_PATH));
signing.setExternalSigning(externallySign);
destFile = new File(OUT_DIR + getOutputFileName("Signed.pdf", externallySign));
signing.signPDF(new File(inPath), destFile, humanRect, tsa);
checkSignature(new File(inPath), destFile, false);
}
when try to setMDPPermission process :
if (doc.getVersion() >= 1.5f && accessPermissions == 0)
{
SigUtils.setMDPPermission(doc, signature, 2);
}
if (sig.getCOSObject().containsKey(COSName.CONTENTS))
{
throw new IOException("DocMDP transform method not allowed if an approval signature exists");
}
but on this function SigUtils got error :
java.io.IOException: DocMDP transform method not allowed if an
approval signature exists
how can i pass the document to sign ?

The error message "DocMDP transform method not allowed if an approval signature exists" is correct.
If you want to add a signature to an already signed PDF, simply remove the
if (doc.getVersion() >= 1.5f && accessPermissions == 0)
{
SigUtils.setMDPPermission(doc, signature, 2);
}
block.

Related

How to send extent report in email to stackholders after running all the test cases in cucumber?

I want to send an email with extent report attachment that I have generated. I am using cucumber. Currently report is generated using latest timestamp with below name
D:\DAAutomation1\NewFeature1\output\10062021_071218798\Report_10062021_071218798.html
Now I want to send this dynamically generated report in email. I am trying to send using the below code in SequentialRunnerTestbut it is not working.
How can I attach a dynamically generated report which stored in a dynamically generated folder?
From which location I need to call this code?
#BeforeClass
public static void Setup() {
if (CustomFormatter.getReportInstance() == null) {
Date d = new Date();
String today = new SimpleDateFormat(Constants.SCREENSHOT_SDF).format(d);
String reportName = String.format("Report_%s%s", today, Constants.HTML_EXTENSION);
File dir = new File(today);
dir = new File(Constants.REPORT_PATH + dir);
if (!dir.exists()) {
dir.mkdir();
Variables.reportFolderName = dir;
}
reportPath = new File(dir + "/" + reportName);
File folderPath = new File(dir + "/");
CustomFormatter.initiateCustomFormatter(reportPath, folderPath);
File extentConfig = new File(Constants.CONFIG_FILES_URI + Constants.EXTENT_FILE);
CustomFormatter.loadConfig(extentConfig);
CustomFormatter.addSystemInfo("user", System.getProperty("user.name"));
CustomFormatter.addSystemInfo("os", System.getProperty("os.name"));
CustomFormatter.addSystemInfo("browser", CONFIG.getProperty("browser"));
CustomFormatter.addSystemInfo("Tenant", CONFIG.getProperty("application.url"));
} else {
CustomFormatter.initiateCustomFormatter();
}
#AfterClass
public static void SendEmail() throws EmailException {
// Create the attachment
EmailAttachment attachment = new EmailAttachment();
attachment.setPath(System.getProperty("user.dir")+"output/folderPath/"+reportPath);
attachment.setDisposition(EmailAttachment.ATTACHMENT);
attachment.setDescription(" Test Execution Report");
attachment.setName("Automation Test Execution Report");
// Create the email message
MultiPartEmail email = new MultiPartEmail();
email.setHostName("smtp.gmail.com");
email.setSSLOnConnect(true);
email.setSmtpPort(465);
email.setAuthenticator(new DefaultAuthenticator("xyz#gmail.com", "xyz#123"));
email.addTo("xyz#gmail.com", "Test");
email.setFrom("xyz#gmail.com", "Me");
email.setSubject("Automation Test Execution Report");
email.setMsg("Automation Test Execution Report");
// add the attachment
email.attach(attachment);
// send the email
email.send();
}
please write seperate simple java program that should be executed after your cucumber run.
After the complete execution only, you will see the latest report in your target folder. your secondary program should pick the report from the target folder and mail to them.
In My case,
I have written separate java program and JAR packed that will do following actions,
Zip screenshot, css and html report from target folder,
Move them to separate folder with current date and time to identify
Then mail the zip folder
My Execution like,
Created a .bat/sh file
added my cucumber execution
added secondary program execution as JAR execution
mvn test -DCucumber.Options="--tags #temp"
java -jar ZippingAndEmailing.jar [reportLocation] [targetlocation] [emailReciptents]
java -jar ZippingAndEmailing.jar target/cucumber Results jayanthbala1993#gmail.com
From which location I need to call this code?
You have to call that under #AfterClass as you want to send report after executing all tests.
#AfterClass
public static void sendReport() {
SendReport sendReport = new SendReport();
sendReport.triggerMail("Report", "\\NewFeature1\\output\\10062021_071218798\\Report_10062021_071218798.html);
}
How can I attach a dynamically generated report which stored in a
dynamically generated folder
public class SendReport{
public String[] ToAdresses = { "nandan#gmail.com"
,"nandan2#gmail.com"
public void triggerMail(String reportName, String reportPath)
throws IOException, AddressException, MessagingException {
Properties sysmProp = System.getProperties();
sysmProp.put("mail.smtp.starttls.enable", "true");
sysmProp.put("mail.smtp.host", host);
sysmProp.put("mail.smtp.user", from);
sysmProp.put("mail.smtp.password", password);
sysmProp.put("mail.smtp.port", "587");
sysmProp.put("mail.smtp.auth", "true");
/*Create session object*/
Session session = Session.getInstance(sysmProp, null);
/*Create MimeMessage object and add recipients */
MimeMessage message = new MimeMessage(session);
/* Setting the string value type as address */
InternetAddress[] recipients = new InternetAddress[ToAdresses.length];
for (int i = 0; i < ToAdresses.length; i++) {
recipients[i] = new InternetAddress(ToAdresses[i]);
}
/* Adding the recipients to the message object. */
for (int j = 0; j < ToAdresses.length; j++) {
message.addRecipient(Message.RecipientType.TO, recipients[j]);
}
message.setSubject("Test report");
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText("Body of email.")
/* Adding the attachment to the mail. */
File file = new File(System.getProperty("user.dir") + reportPath);
BodyPart messageBodyPart_2 = new MimeBodyPart();
DataSource source = new FileDataSource(file.getAbsolutePath());
messageBodyPart_2.setDataHandler(new DataHandler(source));
messageBodyPart_2.setFileName("Test_" + reportName + ".html");
/* Clubbing the subject of mail. */
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
multipart.addBodyPart(messageBodyPart_2);
message.setContent(multipart);
/* Triggers mail. */
Transport.send(message);
}
}

mapreduce job on yarn exited with exitCode: -1000 beacuse of resource changed on src filesystem

Application application_1552978163044_0016 failed 5 times due to AM Container for appattempt_1552978163044_0016_000005 exited with exitCode: -1000
Diagnostics:
java.io.IOException: Resource
abfs://xxx#xxx.dfs.core.windows.net/hdp/apps/2.6.5.3006-29/mapreduce/mapreduce.tar.gz
changed on src filesystem (expected 1552949440000, was 1552978240000
Failing this attempt. Failing the application.
Just based on the exception information, it seems to be caused by Azure Storage could not keep the original timestamp of the copied file. I searched a workaround that recommended to change the source code of yarn-common to disable the code block of timestamp check when copy file to avoid the exception throws to make the MR job continous to work.
Here is the source code in the latest version of yarn-common which check the timestamp for copied file and throws the exception.
/** #L255
* Localize files.
* #param destination destination directory
* #throws IOException cannot read or write file
* #throws YarnException subcommand returned an error
*/
private void verifyAndCopy(Path destination)
throws IOException, YarnException {
final Path sCopy;
try {
sCopy = resource.getResource().toPath();
} catch (URISyntaxException e) {
throw new IOException("Invalid resource", e);
}
FileSystem sourceFs = sCopy.getFileSystem(conf);
FileStatus sStat = sourceFs.getFileStatus(sCopy);
if (sStat.getModificationTime() != resource.getTimestamp()) {
throw new IOException("Resource " + sCopy +
" changed on src filesystem (expected " + resource.getTimestamp() +
", was " + sStat.getModificationTime());
}
if (resource.getVisibility() == LocalResourceVisibility.PUBLIC) {
if (!isPublic(sourceFs, sCopy, sStat, statCache)) {
throw new IOException("Resource " + sCopy +
" is not publicly accessible and as such cannot be part of the" +
" public cache.");
}
}
downloadAndUnpack(sCopy, destination);
}

How to download Images from a dynamic website using Selenium Webdriver

I'm learning automation these days. So I was wondering if there any way I can download images from a dynamic website using Selenium? I'm using Java for this.
I'm able to get the links to about 40 images but not all. I don't know how dynamic website works but I think some of the links gets loaded/shown when the user is scrolling through the page or something like that!
Can you try this method
/**
* #author mbn
* #Date 05/11/2018
* #Purpose This method will download file from url
* #param href
* --> The hyper link of the file we want to download
* #param fileName
* --> the name of the file
* #return N/A
* #Note Path is set to .//OutputData// and will need to be chnaged as per your
* need
*/
public static void downloadFile(String href, String fileName) throws Exception {
URL url = null;
URLConnection con = null;
int i;
url = new URL(href);
con = url.openConnection();
File file = new File(".//OutputData//" + fileName);
BufferedInputStream bis = new BufferedInputStream(con.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
while ((i = bis.read()) != -1) {
bos.write(i);
}
bos.flush();
bis.close();
}

Converting XDP to PDF using Live Cycle replaces question marks(?) with space at multiple places. How can that be fixed?

I have been trying to convert XDP to PDF using Adobe Live Cycle. Most of my forms turn up good. But while converting some of them, I fine ??? replaced in place of blank spaces at certain places. Any suggestions to how can I rectify that?
Below is the code snippet that I am using:
public byte[] generatePDF(TextDocument xdpDocument) {
try {
Assert.notNull(xdpDocument, "XDP Document must be passed.");
Assert.hasLength(xdpDocument.getContent(), "XDPDocument content cannot be null");
// Create a ServiceClientFactory object
ServiceClientFactory myFactory = ServiceClientFactory.createInstance(createConnectionProperties());
// Create an OutputClient object
FormsServiceClient formsClient = new FormsServiceClient(myFactory);
formsClient.resetCache();
String text = xdpDocument.getContent();
String charSet = xdpDocument.getCharsetName();
if (charSet == null || charSet.trim().length() == 0) {
charSet = StandardCharsets.UTF_8.name();
}
byte[] bytes = text.getBytes();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
Document inTemplate = new Document(byteArrayInputStream);
// Set PDF run-time options
// Set rendering run-time options
RenderOptionsSpec renderOptionsSpec = new RenderOptionsSpec();
renderOptionsSpec.setLinearizedPDF(true);
renderOptionsSpec.setAcrobatVersion(AcrobatVersion.Acrobat_9);
PDFFormRenderSpec pdfFormRenderSpec = new PDFFormRenderSpec();
pdfFormRenderSpec.setGenerateServerAppearance(true);
pdfFormRenderSpec.setCharset("UTF8");
FormsResult formOut = formsClient.renderPDFForm2(inTemplate, null, pdfFormRenderSpec, null, null);
Document xfaPdfOutput = formOut.getOutputContent();
//If the input file is already static PDF, then below method will throw an exception - handle it
OutputClient outClient = new OutputClient(myFactory);
outClient.resetCache();
Document staticPdfOutput = outClient.transformPDF(xfaPdfOutput, TransformationFormat.PDF, null, null, null);
byte[] data = StreamIO.toBytes(staticPdfOutput.getInputStream());
return data;
} catch(IllegalArgumentException ex) {
logger.error("Input validation failed for generatePDF request " + ex.getMessage());
throw new EformsException(ErrorExceptionCode.INPUT_REQUIRED + " - " + ex.getMessage(), ErrorExceptionCode.INPUT_REQUIRED);
} catch (Exception e) {
logger.error("Exception occurred in Adobe Services while generating PDF from xdpDocument..", e);
throw new EformsException(ErrorExceptionCode.PDF_XDP_CONVERSION_EXCEPTION, e);
}
}
I suggest trying 2 things:
Check the font. Switch to something very common like Arial / Times New Roman and see if the characters are still lost
Check the character encoding. It might not be a simple question mark character you are using and if so the character encoding will be important. The easiest way is to make sure your question mark is ascii char 63 (decimal).
I hope that helps.

Java jsch and resuming file upload after interruption?

I'm currently using in my code the com.jcraft.jsch library so that I can upload a file(or multiple files) from my local machine to a certain remote one. With file sizes of 5KB, 100KB, 200KB I don't have any concerns. However, I have one big concern when I tend to upload a file with file size 500MB , 1GB, 2GB and above, because there is always the possibility that the internet connection could fail on either side (local machine or remote)
I did a little research of my own and found that the Library has a field called RESUME, which refers to "file transfer mode" , but I haven't found an explanation about its proper use.
So my question is : Is there a way if the connection fails , after it is fixed, the file transfer continues from the point it was interrupted ?
I just "solved" this on my application and thought I would share what I learned.
I looked into how the RESUME is working and found that it depends on which methods you are using. For me I was using both a PipedInputStream and a PipedOutputStream since I might be transferring to/from local files or even both to/from remote servers.
I found that for me I provided my PipedOutputStream to the get method with no mode provided (defaults to OVERWRITE) and then provided my PipedInputStream to the put method with a parameter of RESUME. The put method progressed my InputStream the number of bytes equal to the current size of the file I am sending to.
This took a while as I was already progressing my PipedOutputStream X number of bytes and then the PipedInputStream was progressing another X bytes and I was getting significant gaps. I found this out by looking at the ChannelSftp source code
Of course this will be different if you are not doing the exact same thing as me, but if your source or destination are local you may not need to worry about that. I would try looking at the source code if you can't figure out how you are doing it.
I am using Grails so this may not work exactly for you, but here is what I did
/*
* This was initially copied from
* <a href="http://www.intelligrape.com/blog/2013/04/04/using-ftp-with-grails/">
* http://www.intelligrape.com/blog/2013/04/04/using-ftp-with-grails/</a> for
* the basic structure. JavaDoc and additional method were added as needed.
*
* #author Puneet Behl
* #author jonathan.tinsman
*/
class FtpService {
/**
* Gets the file from the server and loads it into the provided output stream
*
* #param outputStream
* - the output stream to have the file loaded to
* #param fileName
* - the desired file
* #param ftpCredential
* -the server credentials
*/
def load(OutputStream outputStream, String fileName, FtpCredential ftpCredential) {
connect(ftpCredential) { ChannelSftp sftp ->
sftp.get fileName, outputStream, new FtpMonitor()
}
}
/**
* Writes the file on the server
*
* #param inputStream
* - the input stream for writing
* #param fileName
* - the file name
* #param mode
* - the mode for the transfer (defaults to {#link ChannelSftp#OVERWRITE}
* #param ftpCredential
* - the server credentials
*/
def save(InputStream inputStream, String fileName, Integer mode = ChannelSftp.OVERWRITE, FtpCredential ftpCredential) {
connect(ftpCredential) { ChannelSftp sftp ->
sftp.put inputStream, fileName, mode
}
}
/**
* Transfers the file from the input server to the output server.
* <p>
* The usage of {#link PipedInputStream} and {#link PipedOutputStream} is
* from OsterMiller.org
*
* #param fileName
* - the file name
* #param inputFtpCredential
* - the input server
* #param outputFtpCredential
* - the output server
* #param mode
* - the mode for the transfer (defaults to {#link ChannelSftp#OVERWRITE}
*/
def transfer(String fileName, FtpCredential inputFtpCredential, FtpCredential outputFtpCredential, Integer mode = ChannelSftp.OVERWRITE) {
// To change the size of the buffer, add an int with the desired pipe
// size. The default is 1024
PipedInputStream input = new PipedInputStream();
PipedOutputStream output = new PipedOutputStream(input);
// Starting in different threads so they do not deadlock each other
new Thread(
new Runnable(){
public void run(){
new FtpService().load output, fileName, inputFtpCredential
}
}
).start();
/*
* only passing the mode to the "save" as the save will progress the
* input stream on it's own.
*
* If we pass the mode to the "load" method, then there will be a gap
* in the data as the "load" will progress the stream xx bytes and the
* "save" will progress it another xx bytes (the size of the existing
* file).
*/
save input, fileName, mode, outputFtpCredential
}
/**
* Connect to the server and call the provided ChannelSftp Closure.
*
* #param ftpCredential
* - the server to connect to
* #param closure
* - the closure to call
* #param disconnectOnFinish
* - to disconnect the Session when the Closure is done (defaults to true)
*/
private def connect(FtpCredential ftpCredential, Closure closure, boolean disconnectOnFinish = true) {
Session session = null
ChannelSftp sftp = null
try {
JSch jSch = new JSch()
session = jSch.getSession ftpCredential?.username, ftpCredential?.server, ftpCredential?.port
session.setConfig "StrictHostKeyChecking", "no"
if (ftpCredential?.password) {
session.password = ftpCredential?.password
} else {
File keyFile = new File("${grailsApplication.config.pathToKeyFile}")
jSch.addIdentity(keyFile?.absolutePath)
}
session.connect()
Channel sFtpChannel = session.openChannel "sftp"
sFtpChannel.connect()
sftp = sFtpChannel as ChannelSftp
sftp.cd ftpCredential?.remoteBaseDir
closure.call sftp
} catch (Exception ex) {
ex.printStackTrace()
} finally {
if (disconnectOnFinish) {
sftp?.exit()
session?.disconnect()
}
}
}
}