HomeDigital EditionSys-Con RadioSearch Web Services Cd
B2B Beginning WS Business Process Management Case Studies Content Management Distributing Computing e-Business Electronic Data Interchange Enterprise Industry Insight Integration Interviews Java & Web Services .NET Portal Product Reviews Scalability & Performance Security SOAP Source Code UDDI Wireless WS Standards WS Tips & Techniques WSDL WS Editorials XML

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) {
        }
    }

    ...
}"