Ok, so long time no see. I was terribly busy and couldn’t contribute for a post. I am dealing with various projects and in various languages.
Here is a simple web service that I implemented in JAX-RPC Java which extracts, signs and verifies a PDF document. I gave this as an assignment during my studies in ICSS in KTH.
This is as said Java-RPC JAX web service which extracts a pdf file and outputs in the console, signs the pdf and verifies the pdf. You can directly run it on eclipse or with a little tweak in Netbeans.
Please note that I didn’t use a code highlighter or so, you have to live with that.
I used itext and bouncycastle libraries to fulfill for this task. You can run this project directly in eclipse (which I included the libraries), or you can deploy this to a server (which you can prefer Tomcat or others). For a feasible deployment, you may need an ANT script which is also a mere XML file to produce a WAR file. I will talk upon Tomcat deployment in another post.
To run the project, first run the the endpoint, “BaranTopalCVPublisher.java” which resides in the package, “com.icss.endpoint”. Then, you will run the “BaranTopalCVClient.java” which is in “com.icss.client” package. Then you can follow both outputs in console instances of both server and client. You can also trace the signed pdf file in the project folder.
The culprit is that in the old versions of itext libraries, you may encounter some problems if you google for the related work. I also didn’t find itext examples itself not very educative since there are references which are not fixed in their example code.
Now, a simple background in SOA idea is required, but I don’t want you to get drowned in theory. The basic idea for SOA is the following metaphor.
“Oh, I need to implement this web or standalone project and the source I need is really hard to parse and process. Hmm, let’s parse it, but how? Let’s use XML or JSON.”
So, in order to deal with requests of a client or a source which is hard to process, you can go for web services.
From my point of view, Java web services especially some examples I have seen while googling, are extremely complicated or terribly trivial. Trivial ones helps you to understand the coding style for a web service but the context for SOA in those are not certain.
Ok, here is the work to be conducted in full context.
First, let’s examine the project hierarchy:
The libraries I used are given in the hierarchy. The libraries I used are itext and bouncy castle ones which are latest ones for today. hal.gif is my signature or watermark in this context which will be applied on the PDF file. I will explain the keystore right in the comments in the code. You can create a JavaKeyStore in your favourite operating system. All you need is a console in which you are root or elevated privileged user. This time, I used W7-64 bit command prompt.
Now, let’s get back to code.
Let’s check the source folder, which is src. There are 3 packages in that src folder, com.icss.client, com.icss.endpoint and com.icss.ws.
com.icss.client has 2 java files named as BaranTopalCVClient.java and BaranTopalCVSign.java.
BaranTopalCVClient.java is as follows:
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Company: KTH-IK2001 *
* Assignment: Baran Topal Trivial CV Extractor/Signer/Verifier Web Service *
* Deadline: – *
* To: Hao Zhao *
* Programmer: Baran Topal *
* Project name: BaranTopal *
* Folder name: src *
* Package name: com.icss.client *
* File name: BaranTopalCVClient.java *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* LICENSE: This source file is subject to have the protection of GNU General Public License. *
* You can distribute the code freely but storing this license information. *
* Contact Baran Topal if you have any questions. barantopal@barantopal.com || jazzIIIlove@gmail.com || topal@kth.se *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
package com.icss.client;
import java.io.File;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import com.icss.ws.*;
public class BaranTopalCVClient{
public static void main(String[] args) throws Exception {
URL url = new URL(“http://localhost:9999/ws/baran?wsdl”);
//1st argument service URI, refer to wsdl document above
//2nd argument is service name, refer to wsdl document above
QName qname = new QName(“http://ws.icss.com/”, “BaranTopalCVImplService”);
Service service = Service.create(url, qname);
BaranTopalCV cv = service.getPort(BaranTopalCV.class);
System.out.println(“Baran Topal CV\n”);
//extract the CV in server side
System.out.println(cv.getCVAsString(new File(“BaranTopal_CV.pdf”)));
System.out.println();
BaranTopalCVSign sign = new BaranTopalCVSign();
//sign the CV in client side
sign.sign();
//verify the CV in server side
System.out.println(“Baran Topal CV Verified\n”);
System.out.println(cv.verifyCVAsString(new File(“BaranTopal_CV_signed.pdf”)));
System.out.println();
}
}
BaranTopalCVSign.java is as follows:
As you can see, you need to have a keystore, I used JavaKeyStore and in the comments, I showed how you can create a keystore for your need.
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Company: KTH-IK2001 *
* Assignment: Baran Topal Trivial CV Extractor/Signer/Verifier Web Service * *
* Deadline: – *
* To: Hao Zhao *
* Programmer: Baran Topal *
* Project name: BaranTopal *
* Folder name: src *
* Package name: com.icss.client *
* File name: BaranTopalCVSign.java *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* LICENSE: This source file is subject to have the protection of GNU General Public License. *
* You can distribute the code freely but storing this license information. *
* Contact Baran Topal if you have any questions. barantopal@barantopal.com || jazzIIIlove@gmail.com || topal@kth.se *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
/*
* Sign sequence:
* c:\>keytool -list -v -keystore KEYSTORE2.jks
* Enter keystore password:
* Keystore type: JKS
* Keystore provider: SUN
* Your keystore contains 1 entry
* Alias name: selfsigned
* Creation date: Jan 4, 2013
* Entry type: PrivateKeyEntry
* Certificate chain length: 1
* Certificate[1]:
* Owner: CN=baran topal, OU=ICSS, O=KTH, L=Stockholm, ST=Sweden, C=SV
* Issuer: CN=baran topal, OU=ICSS, O=KTH, L=Stockholm, ST=Sweden, C=SV
* Serial number: 299be07a
* Valid from: Fri Jan 04 23:19:46 CET 2013 until: Mon Dec 30 23:19:46 CET 2013
* Certificate fingerprints:
MD5: D7:5F:4C:DC:B2:3F:93:06:40:07:7A:32:7B:B9:96:30
SHA1: 90:44:2A:C5:AD:F4:BA:A7:4E:98:48:4E:DC:0C:8B:3B:55:EE:24:A3
SHA256: 40:F7:BB:C4:DC:5B:D3:A5:ED:0A:EB:1F:DA:EF:4A:F9:FA:80:3D:FF:D4:
6F:D4:BE:52:17:DA:D8:BA:B0:E4:82
Signature algorithm name: SHA256withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 28 CB DC 76 6C 11 A1 F0 4F B2 EE 1E CA 71 24 D9 (..vl…O….q$.
0010: D2 88 A1 E4 ….
]
]
*******************************************
*******************************************
c:\>
*/
package com.icss.client;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.*;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.PrivateKeySignature;
public class BaranTopalCVSign {
//signing the pdf
public void sign()
{
try{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
String keystore_password = “barantopal”;
String key_password = “barantopal”;
//Java Key store
KeyStore ks = KeyStore.getInstance(“JKS”);
ks.load(new FileInputStream(“keystore2.jks”), keystore_password.toCharArray());
String alias = (String)ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, key_password.toCharArray());
Certificate[] chain = ks.getCertificateChain(alias);
// reader and stamper
PdfReader reader = new PdfReader(“BaranTopal_CV.pdf”);
FileOutputStream os = new FileOutputStream(“BaranTopal_CV_signed.pdf”);
PdfStamper stamper = PdfStamper.createSignature(reader, os, ‘\0’);
// appearance
PdfSignatureAppearance appearance = stamper .getSignatureAppearance();
appearance.setImage(Image.getInstance(“hal.gif”));
appearance.setReason(“I’ve written this.”);
appearance.setLocation(“Foobar”);
appearance.setVisibleSignature(new Rectangle(72, 732, 144, 780), 1, “first”);
// digital signature
ExternalSignature es = new PrivateKeySignature(pk, “SHA-256”, “BC”);
ExternalDigest digest = new BouncyCastleDigest();
MakeSignature.signDetached(appearance, digest, es, chain, null, null, null, 0, CryptoStandard.CMS);
}catch(Exception ex){ex.printStackTrace();}
}
}
Next is the webservice implementation which is in the package com.icss.ws package. It has 2 Java files, BaranTopalCV.java and BaranTopalCVImpl.java:
BaranTopalCV.java which is actually a sketch, is as follows:
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Company: KTH-IK2001 * *
* Assignment: Baran Topal Trivial CV Extractor/Signer/Verifier Web Service *
* Deadline: – *
* To: Hao Zhao *
* Programmer: Baran Topal *
* Project name: BaranTopal *
* Folder name: src *
* Package name: com.icss.ws *
* File name: BaranTopalCV.java *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* LICENSE: This source file is subject to have the protection of GNU General Public License. *
* You can distribute the code freely but storing this license information. *
* Contact Baran Topal if you have any questions. barantopal@barantopal.com || jazzIIIlove@gmail.com || topal@kth.se *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
package com.icss.ws;
import java.io.File;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
//Service Endpoint Interface
@WebService
@SOAPBinding(style = Style.RPC)
public interface BaranTopalCV{
@WebMethod String getCVAsString(File file);
@WebMethod String verifyCVAsString(File file);
}
Now, the real implementation takes place in BaranTopalCVImpl.java:
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Company: KTH-IK2001 *
* Assignment: Baran Topal Trivial CV Extractor/Signer/Verifier Web Service * *
* Deadline: – *
* To: Hao Zhao *
* Programmer: Baran Topal *
* Project name: BaranTopal *
* Folder name: src *
* Package name: com.icss.ws *
* File name: BaranTopalCVImpl.java *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* LICENSE: This source file is subject to have the protection of GNU General Public License. *
* You can distribute the code freely but storing this license information. *
* Contact Baran Topal if you have any questions. barantopal@barantopal.com || jazzIIIlove@gmail.com || topal@kth.se *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
package com.icss.ws;
import javax.jws.WebService;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
import com.itextpdf.text.pdf.security.PdfPKCS7;
import java.security.*;
//Service Implementation
@WebService(endpointInterface = “com.icss.ws.BaranTopalCV”)
public class BaranTopalCVImpl implements BaranTopalCV{
//process CV and extract the data
public String getCVAsString(File file)
{
return process(file.getAbsolutePath());
}
//verify CV and signed data
public String verifyCVAsString(File file)
{
return verify(file.getAbsolutePath());
}
public static String verify(String path)
{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
StringBuilder stringbuilder = new StringBuilder();
try{
PdfReader reader = new PdfReader(path);
AcroFields af = reader.getAcroFields();
//Search of the whole signature
ArrayList names = af.getSignatureNames();
//For every signature :
for (int k = 0; k < names.size(); ++k) {
String name = (String)names.get(k);
//Signature name
System.out.println(“Signature name: ” + name);
stringbuilder.append(“\nSignature name: ” + name);
System.out.println(“Signature covers whole document: ”
+ af.signatureCoversWholeDocument(name));
stringbuilder.append(“\nSignature covers whole document: ” + af.signatureCoversWholeDocument(name));
//Start of extraction revision
System.out.println(“Document revision: ” + af.getRevision(name) + ” of ”
+ af.getTotalRevisions());
FileOutputStream out = new FileOutputStream(“revision_”
+ af.getRevision(name) + “.pdf”);
byte bb[] = new byte[8192];
InputStream ip = af.extractRevision(name);
int n = 0;
while ((n = ip.read(bb)) > 0) out.write(bb, 0, n);
out.close();
ip.close();
//End of extraction revision
stringbuilder.append(“\nDocument revision: ” + af.getRevision(name) + ” of ” + af.getTotalRevisions());
PdfPKCS7 pkcs7 = af.verifySignature(name);
System.out.println(“Integrity check OK? ” + pkcs7.verify());
stringbuilder.append(“\nIntegrity check OK? ” + pkcs7.verify());
}
}
catch(Exception ex)
{ex.printStackTrace();}
return (new String(stringbuilder));
}
public static String process(String filePath)
{
StringBuilder stringbuilder = new StringBuilder();
try {
PdfReader reader = new PdfReader(filePath);
int n = reader.getNumberOfPages();
// just retrieve the size of the first page
Rectangle psize = reader.getPageSize(1);
//build Pdf version
stringbuilder.append(“PDF version used: ” + reader.getPdfVersion() + “\n”);
//build file length
stringbuilder.append(“File length: ” + reader.getFileLength() + “\n”);
//build height of the first document
stringbuilder.append(“First page height: ” + psize.getHeight() + “\n”);
//build height of the first document
stringbuilder.append(“First page width: ” + psize.getWidth() + “\n”);
stringbuilder.append(“\n//////////\n”);
//initialize extraction
stringbuilder.append(“\nExtract CV:\n”);
//Loop per pdf page content
for(int i = 1; i <= n; i++)
{
//build the pages
stringbuilder.append(PdfTextExtractor.getTextFromPage(reader, i));
stringbuilder.append(“\n”);
}
}
catch (Exception de) {
de.printStackTrace();
}
return (new String(stringbuilder));
}
}
Finally, the endpoint which is in the package com.icss.endpoint. This is for publishing the pdf file:
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Company: KTH-IK2001 *
* Assignment: Baran Topal Trivial CV Extractor/Signer/Verifier Web Service *
* Deadline: – *
* To: Hao Zhao *
* Programmer: Baran Topal *
* Project name: BaranTopal *
* Folder name: src *
* Package name: com.icss.endpoint *
* File name: BaranTopalCVPublisher.java *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* LICENSE: This source file is subject to have the protection of GNU General Public License. *
* You can distribute the code freely but storing this license information. *
* Contact Baran Topal if you have any questions. barantopal@barantopal.com || jazzIIIlove@gmail.com || topal@kth.se *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
package com.icss.endpoint;
import javax.xml.ws.Endpoint;
import com.icss.ws.BaranTopalCVImpl;
//Endpoint publisher
public class BaranTopalCVPublisher{
public static void main(String[] args) {
Endpoint.publish(“http://localhost:9999/ws/baran”, new BaranTopalCVImpl());
}
}
This is all for now. I think this will give a brief understanding what you are capable of with web services. I may contribute to this post later on.
I know, I can give more details but the comments in the code should be enough and I am sure that the code will run smoothly. If it won’t and gave an error, toss a mail.
I also shared this project as a rar file in dropbox public folder, I removed the pdf files, so you can try it on your own pdf:
https://dl.dropbox.com/u/1327371/BaranTopal-IK2001-PDFOperations.rar
I may update this in future, depends on my schedule.