|
Client SOAP Processing
The client identifies the Web service interface description to which it is submitting a request. This can be done either through a UDDI browser, which is part of the SOAP client-side toolkit or through verbal/written communication with the service provider, if it is an internal enterprise application. Once the service endpoint is identified, the client generates the stub files through the use of the SOAP toolkit generator. The client writes the code to invoke the SOAP request, providing the necessary data, such as service endpoint URL and method argument values. The following code shows how to do this:
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new
java.net.URL("http://localhost:8080/axis/servlet/AxisServlet));
SOAPEnvelope env = new SOAPEnvelope();
// XMLUtils.StringToElement() creates an XML Element for the given
// (namespace, elementName, textValue) combination
SOAPBodyElement sbe = new SOAPBodyElement(XMLUtils.StringToElement(
"http://localhost:8080/MyService", "methodName", ""));
env.addBodyElement(sbe);
// Invoke service
call.invoke(env);
// Get response
MessageContext mc = call.getMessageContext();
Message response = mc.getResponseMessage();
Next, add the logic to sign the SOAP body element. The key gains access to the SOAP body element. Once the body element has been extracted from the SOAP document, it becomes the input for the XML-Signature document processing. The following code sample does this using Apache Axis and XML Security packages.
// SOAPEnvelope has already been created and is stored in env
// Actually add the SOAP signature header
env.addMapping(new Mapping
("http://schemas.xmlsoap.org/soap/security/2000-12",
"SOAP-SEC"));
env.addAttribute(Constants.URI_SOAP_ENV, "actor", "some-uri");
env.addAttribute(Constants.URI_SOAP_ENV, "mustUnderstand", "1");
SOAPHeader header = new SOAPHeader(
XMLUtils.StringToElement(SOAPSECNS, "Signature", ""));
env.addHeader(header);
// Get the SOAPEnvelope as a XML Document so we can extract the SOAP
// Signature element just added for use in creating the XML Signature.
StringWriter writer = new StringWriter();
SerializationContext serializeContext =
new SerializationContextImpl(writer, null);
env.output(serializeContext);
writer.close();
Reader reader = new StringReader(writer.getBuffer().toString());
Document doc = XMLUtils.newDocument(new InputSource(reader));
// Get the Signature Element from the Header
Element soapHeaderElement = (Element)
((Element) doc.getFirstChild
()).getElementsByTagNameNS("*", "Header").item(0);
Element soapSignatureElement =
(Element)soapHeaderElement.getElementsByTagNameNS
("*", "Signature").item(0);
// http://xml-security is the base-uri, which needs
??to be unique within document
XMLSignature sig = new XMLSignature(doc, "http://xml-security",
XMLSignature.ALGO_ID_SIGNATURE_DSA);
// Add SOAP Body to XML Signature and sign.
soapSignatureElement.appendChild(sig.getElement());
// Neat trick: since the XMLSignature is actually a part of the
// SOAP XML document, the SOAP body is referenced as a URI fragment
sig.addDocument("#Body");
Most of the commercial cryptographic toolkits provide APIs for generating an XML-Signature document, given the data to sign, the private key, and the public key/certificate. The following code shows how to do this (again, assuming Apache Axis and Apache XML Security toolkits). For simplicity, the code retrieves the private key from a key store. This is not recommended for deployment scenarios with high security needs since the key store provides minimal protection for the private key.
// Extract the private key & certificate from the key store
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream("keyStoreFileName");
ks.load(fis, "keyStorePassword".toCharArray());
PrivateKey privateKey = (PrivateKey) ks.getKey
("privateKeyAlias",
"privateKeyPass".toCharArray());
X509Certificate cert =
(X509Certificate) ks.getCertificate
("certificateAlias");
// Add the digital certificate and public key to XML
//Signature document. Assumption is XMLSignature document
//was created earlier. See above code sample
sig.addKeyInfo(cert);
sig.addKeyInfo(cert.getPublicKey());
// Sign the XML Signature document with our private key
sig.sign(privateKey);
// Transform XML Signature Document
Canonicalizer c14n =
Canonicalizer.getInstance
(Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS);
// Assumption is Document was extracted from SOAP Envelope earlier
byte[] canonicalMessage = c14n.canonicalizeDocument(doc);
// Create a Deserializer for the XML Signature document
InputSource is = new InputSource(new
java.io.ByteArrayInputStream(canonicalMessage));
AxisClient tmpEngine = new AxisClient(new NullProvider());
// env is SOAPEnvelope instance
DeserializationContextImpl dser = new DeserializationContextImpl(
is, new MessageContext(tmpEngine), Message.REQUEST, env);
dser.parse();
Now the SOAP document, a single XML document, is ready for transport to the server.
|