|
Designing Web Services with XML Signatures, by Mark Young
WSJ Vol 02 Issue 10 - pg.12
Listing 1
<xsd:element name=""Claim"" type=""tns:ClaimType""/>
<xsd:complexType name=""ClaimType"">
<xsd:sequence>
<xsd:element name=""AccidentReport"">
<xsd:complexType>
<xsd:sequence>
<xsd:element name=""AccidentDescription""
type=""xsd:string""/>
<xsd:element name=""AccidentDate""
type=""xsd:date""/>
</xsd:sequence>
<xsd:attribute name=""id"" type=""xsd:ID"">
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name=""Submitter"">
<xsd:complexType>
<xsd:sequence>
<xsd:element name=""Name"">
<xsd:complexType>
<xsd:sequence>
<xsd:element name=""Last""
type=""xsd:string""/>
<xsd:element name=""First""
type=""xsd:string""/>
<xsd:element name=""MiddleInitial""
type=""xsd:string""/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name=""Company""
type=""xsd:string""/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
...
<wsdl:message name=""SubmitClaimSoapIn"">
<wsdl:part name=""Claim"" element=""ns:Claim""/>
<wsdl:part name=""Signature""
element=""soap-sec:Signature""/>
</wsdl:message>
...
<wsdl:binding name=""ClaimServiceSOAPBinding""
type=""ns:ClaimServiceSOAP"">
<soap:binding style=""document"" >
<wsdl:operation name=""SubmitClaim"">
<soap:operation style=""document"">
<wsdl:input name=""SubmitClaimInput"">
<soap:body use=""literal"" parts=""Claim""/>
<soap:header use=""literal"" part=""Signature""
message=""ns:SubmitClaimSoapIn""/>
</wsdl:input>
...
</wsdl:operation>
</wsdl:binding>
Listing 2
package com.myOrg.ClaimService.Client;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Document;
import org.apache.axis.message.MessageElement;
import Java.io.FileOutputStream;
import Java.io.Writer;
public class AccidentReport {
static private Java.lang.String
nsString = ""http://www.claimsRUs.com/claimDef"";
private String mAccidentDescription;
private String mAccidentDate;
public AccidentReport() {
}
public void setDescription(String aString) {
mAccidentDescription = aString;
}
public String getDescription() {
return mAccidentDescription;
}
public void setDate(String aString) {
mAccidentDate = aString;
}
public String getDate() {
return mAccidentDate;
}
public Element asDOM(Document aDoc) {
Element accidentReportEl =
aDoc.createElementNS(nsString,
""AccidentReport"");
// this is how the signature will refer
// to this element
accidentReportEl.setAttribute(""Id"", ""Ar1"");
Element descriptionEl =
aDoc.createElementNS(nsString,
""AccidentDescription"");
Node descriptionTxt =
aDoc.createTextNode(mAccidentDescription);
descriptionEl.appendChild(descriptionTxt);
accidentReportEl.appendChild(descriptionEl);
Element dateEl = aDoc.createElementNS(
nsString, ""AccidentDate"");
Node dateTxt =
aDoc.createTextNode(mAccidentDate);
dateEl.appendChild(dateTxt);
accidentReportEl.appendChild(dateEl);
return accidentReportEl;
}
static public AccidentReport populate() {
// stuff with some test data
AccidentReport aReport = new AccidentReport();
aReport.setDescription(""Fender bender."");
aReport.setDate(""1-2-2002"");
return aReport;
}
}
Listing 3
package com.myOrg.ClaimService.Client;
import org.apache.axis.AxisFault;
import org.apache.axis.MessageContext;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.message.SOAPBodyElement;
import org.apache.axis.message.SOAPEnvelope;
import org.apache.axis.utils.Options;
import org.apache.axis.utils.XMLUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Document;
public class ClaimClient {
private static final String nsString =
""http://www.myOrg.com/ClaimService"";
public static void main(String[] args)
throws Exception {
try {
Options opts = new Options(args);
Service service = new Service();
Call call = (Call)service.createCall();
// set port to 8081 so that can observe
// the messages with tcpmon
// Java org.apache.axis.utils.tcpmon
opts.setDefaultURL(""http://localhost:""
+ ""8081/axis/servlet/AxisServlet"");
call.setTargetEndpointAddress
(new Java.net.URL(opts.getURL()));
Document doc = XMLUtils.newDocument();
// set up the soap envelope
SOAPEnvelope env = new SOAPEnvelope();
// add an element for the method we'll
// invoke needs to have ns = to the
// path of the service
Element anEl = doc.createElementNS(
""http://localhost:8080/"" +
""LogTestService"", ""testMethod"");
SOAPBodyElement sbe =
new SOAPBodyElement(anEl);
env.addBodyElement(sbe);
// and add an element that holds
// the insurance Claim we're
// submitting. It isn't signed yet.
Claim aClaim = Claim.populate();
Element claimEl = aClaim.asDOM(doc);
SOAPBodyElement sbe2 =
new SOAPBodyElement(claimEl);
env.addBodyElement(sbe2);
// now change the envelope into a
// signed envelope, byadding a
// signature (in the SOAPHeader)
// that refers to the AccidentReport
// element added by aClaim.asDOM()
env = new SignedSOAPEnvelope(env,
""http://xml-security"");
// and invoke the web service method
call.invoke(env);
}
catch (Exception e) {
}
}
}
Listing 4
package com.myOrg.ClaimService.Client;
...
public class SignedSOAPEnvelope
extends SOAPEnvelope {
static String SOAPSECNS =
""http://schemas.xmlsoap.org/""
+ ""soap/security/2000-12"";
static String SOAPSECprefix = ""SOAP-SEC"";
static String keystoreType = ""JKS"";
static String keystoreFile = "".keystore"";
static String keystorePass = ""security"";
static String privateKeyAlias = ""georgia"";
static String privateKeyPass = ""secret"";
static String certificateAlias = ""georgia"";
static {
org.apache.xml.security.Init.init();
}
public SignedSOAPEnvelope(MessageContext
msgContext, SOAPEnvelope env, String
baseURI, String keystoreFile) {
this.msgContext = msgContext;
init(env, baseURI, keystoreFile);
}
public SignedSOAPEnvelope(SOAPEnvelope env,
String baseURI) {
init(env, baseURI, keystoreFile);
}
// fill this object by adding a signature to
// the passed envelope env, and serializing/
// deserializing the result back into this
// object
private void init(SOAPEnvelope env, String
baseURI, String
keystoreFile) {
try {
…
// create new header element to hold
// the signature per WS-Security
…
// grab the contents of env as a
// Document (which we'll later
// parse back into this object) so
// that we can operate at the
// DOM level
...
// get the keystore
KeyStore ks =
KeyStore.getInstance(keystoreType);
FileInputStream fis = new
FileInputStream(keystoreFile);
ks.load(fis,
keystorePass.toCharArray());
// get private key from keystore
PrivateKey privateKey =
(PrivateKey) ks.
getKey(privateKeyAlias,
privateKeyPass.toCharArray());
// find the new header element
// (in doc) we added above
Element soapHeaderElement =
(Element) ((Element) doc.
getFirstChild()).
getElementsByTagNameNS(""*"",
""Header"").item(0);
Element soapSignatureElement =
(Element) soapHeaderElement.
getElementsByTagNameNS(""*"",
""Signature"").item(0);
// create a signature object
XMLSignature sig =
new XMLSignature(doc, baseURI,
XMLSignature.ALGO_ID_SIGNATURE_DSA);
// have it create a signature element
// and append that as a child of the
// header element
soapSignatureElement.
appendChild(sig.getElement());
// set up the reference in the
// signature element --
// refers to the AccidentReport
// element created elsewhere
Transforms transforms =
new Transforms(doc);
transforms.addTransform(Transforms.
TRANSFORM_ENVELOPED_SIGNATURE);
transforms.addTransform(Transforms.
TRANSFORM_C14N_WITH_COMMENTS);
sig.addDocument(""#Ar1"", transforms,
org.apache.xml.security.utils.
Constants.ALGO_ID_DIGEST_SHA1);
// add x509 certificate information
// taken from the keystore
X509Certificate cert =
(X509Certificate) ks.
getCertificate(certificateAlias);
sig.addKeyInfo(cert);
// including the public key
sig.addKeyInfo(cert.getPublicKey());
// and finally, sign the message
sig.sign(privateKey);
// now canonicalize the entire document
// (envelope) and parse it back into
// this object (an extension of
// SOAPEnvelope)
…
} catch (Exception e) {
}
}
...
}"
|