2011-09-29 16 views
21

Me gustaría escribir un servicio web JAX-WS que firme mis mensajes SOAP utilizando la recomendación http://www.w3.org/TR/xmldsig-core/.Firmar la solicitud JAX-WS SOAP

Con lo que encontré en el Internet me escribió un controlador de JAX-WS (SOAPHandler<SOAPMessageContext>) que logra cambiar una copia de la solicitud SOAP:

@Override 
public boolean handleMessage(SOAPMessageContext smc) { 
    Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); 
    SOAPMessage message = smc.getMessage(); 

    if (outboundProperty) { 
     try { 
      SOAPPart soapPart = message.getSOAPPart(); 
      SOAPEnvelope soapEnvelope = soapPart.getEnvelope(); 

      Source source = soapPart.getContent(); 

      Node root = null; 
      Document doc22 = null; 
      if (source instanceof DOMSource) { 
       root = ((DOMSource) source).getNode(); 
      } else if (source instanceof SAXSource) { 
       InputSource inSource = ((SAXSource) source).getInputSource(); 
       DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
       dbf.setNamespaceAware(true); 
       DocumentBuilder db = null; 

       db = dbf.newDocumentBuilder(); 

       doc22 = db.parse(inSource); 
       root = (Node) doc22.getDocumentElement(); 
      } 

      XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); 

      Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null), 
        Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), 
        null, null); 

      SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, 
        (C14NMethodParameterSpec) null), 
        fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), 
        Collections.singletonList(ref)); 

      // Load the KeyStore and get the signing key and certificate. 
      KeyStore ks = KeyStore.getInstance("JKS"); 
      ks.load(new FileInputStream("client_keystore.jks"), "changeit".toCharArray()); 
      KeyStore.PrivateKeyEntry keyEntry = 
        (KeyStore.PrivateKeyEntry) ks.getEntry("client", new KeyStore.PasswordProtection("changeit".toCharArray())); 
      X509Certificate cert = (X509Certificate) keyEntry.getCertificate(); 
      // Create the KeyInfo containing the X509Data. 
      KeyInfoFactory kif2 = fac.getKeyInfoFactory(); 
      List x509Content = new ArrayList(); 
      x509Content.add(cert.getSubjectX500Principal().getName()); 
      x509Content.add(cert); 
      X509Data xd = kif2.newX509Data(x509Content); 
      KeyInfo ki = kif2.newKeyInfo(Collections.singletonList(xd)); 

      Element header = getFirstChildElement(root/*.getDocumentElement()*/); 
      DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), header /*doc.getDocumentElement()*/); 

      XMLSignature signature = fac.newXMLSignature(si, ki); 

      signature.sign(dsc); 

      //TODO: change this to update the SOAP message, not write it to disks 
      OutputStream os = new FileOutputStream("out.xml"); 
      TransformerFactory tf = TransformerFactory.newInstance(); 
      Transformer trans = tf.newTransformer(); 
      trans.transform(new DOMSource(root), new StreamResult(os)); 

     } catch (Exception ex) { 
      System.out.println(ex); 
     } 
    } 

    return true; 
} 

Pero no puedo encontrar la manera de actualizar la Solicitud de SOAP?

+0

¿Does soapPart.setContent (nuevo DOMSource (root)) no funciona? Solo estoy adivinando, no lo he hecho yo mismo. –

+0

Desafortunadamente, esto vacía los elementos de bode y encabezado. ¡Gracias por mirar, sin embargo! – AndrewBourgeois

+0

¿Ya ha encontrado una solución a este problema? Tengo curiosidad porque voy a hacer algo similar –

Respuesta

6

La manera más simple es utilizar la funcionalidad integrada en el servidor de aplicaciones. Por ejemplo: Securing JAX-WS Web services using message-level security with WebSphere App Server

Cómo configurar la firma en WAS puede encontrar here.

Y aquí está WebLogic documentation about Configuring Message-Level Security.

+0

Se trata de la firma, no de la seguridad general, que es bien conocida. ¿Tal vez podría proporcionar un enlace y/o ejemplo más detallado? –

+0

@LukasEder: seguridad a nivel de mensaje se refiere a la firma también. En esta página también puede encontrar un enlace a la configuración de firma. Lo agregué ahora a la respuesta. – zacheusz

+1

Muy bueno. Especialmente el segundo enlace! Muchas gracias –

6

Desarrollo un SOAPHandler para Xml Firma digital de Soap Request.

public class SOAPSecurityHandler implements 
     LogicalHandler<LogicalMessageContext> { 

    static final String KEYSTORE_FILE = "keystore_name.jks"; 
    static final String KEYSTORE_INSTANCE = "JKS"; 
    static final String KEYSTORE_PWD = "123456"; 
    static final String KEYSTORE_ALIAS = "keystore"; 

    public Set<QName> getHeaders() { 
     return Collections.emptySet(); 
    } 

    @Override 
    public boolean handleMessage(LogicalMessageContext smc) { 
     Boolean outboundProperty = (Boolean) smc 
       .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); 

     try { 

      if (outboundProperty) { 

       Source source = smc.getMessage().getPayload(); 

       Node root = null; 

       root = ((DOMSource) source).getNode(); 

       XMLSignatureFactory fac = XMLSignatureFactory 
         .getInstance("DOM"); 

       Reference ref = fac.newReference("", fac.newDigestMethod(
         DigestMethod.SHA1, null), Collections.singletonList(fac 
         .newTransform(Transform.ENVELOPED, 
           (TransformParameterSpec) null)), null, null); 

       SignedInfo si = fac.newSignedInfo(fac 
         .newCanonicalizationMethod(
           CanonicalizationMethod.INCLUSIVE, 
           (C14NMethodParameterSpec) null), fac 
         .newSignatureMethod(SignatureMethod.RSA_SHA1, null), 
         Collections.singletonList(ref)); 

       // Load the KeyStore and get the signing key and certificate. 
       KeyStore ks = KeyStore.getInstance(KEYSTORE_INSTANCE); 
       ks.load(new FileInputStream(KEYSTORE_FILE), 
         KEYSTORE_PWD.toCharArray()); 
       KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks 
         .getEntry(
           KEYSTORE_ALIAS, 
           new KeyStore.PasswordProtection(KEYSTORE_PWD 
             .toCharArray())); 
       X509Certificate cert = (X509Certificate) keyEntry 
         .getCertificate(); 
       // Create the KeyInfo containing the X509Data. 
       KeyInfoFactory kif2 = fac.getKeyInfoFactory(); 
       List x509Content = new ArrayList(); 
       x509Content.add(cert.getSubjectX500Principal().getName()); 
       x509Content.add(cert); 
       X509Data xd = kif2.newX509Data(x509Content); 
       KeyInfo ki = kif2.newKeyInfo(Collections.singletonList(xd)); 

       Element header = DOMUtils.getFirstChildElement(root); 
       DOMSignContext dsc = new DOMSignContext(
         keyEntry.getPrivateKey(), header); 

       XMLSignature signature = fac.newXMLSignature(si, ki); 

       signature.sign(dsc); 

      } 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return true; 

    } 

    public boolean handleFault(SOAPMessageContext smc) { 
     // addDigitalSignature(smc); 
     return true; 
    } 

    // nothing to clean up 
    public void close(MessageContext messageContext) { 
    } 

    @Override 
    public boolean handleFault(LogicalMessageContext arg0) { 
     // TODO Auto-generated method stub 
     return false; 
    } 

} 

Creo que el problema en el código de @AndrewBourgeois es la forma de obtener Source.

Saludos,

+0

¿Dónde está la lógica para DomUtils? – lordoku

1

Usted puede intentar soapPart.saveChanges();

0

Después de la línea de código:

signature.sign(dsc); 

insertar esta declaración:

soapMsg.saveChanges(); 

Será guardar los cambios.

Cuestiones relacionadas