Referencia API SOAP Webpay Transbank S.A. D OCUMENTO DE ESPECIFI CACIONES TRANSACCIÓN M ALL N ORMAL ( V 1.4) Transbank S.A. 10/10/2012 0 Contenido 1 Control de cambios ................................................................................................................ 2 2 Prefacio.................................................................................................................................. 2 3 2.1 Acerca de esta guía ......................................................................................................... 2 2.2 Audiencia ....................................................................................................................... 2 2.3 Feedback para esta documentación ................................................................................ 2 Transacción de Autorización Mall Normal............................................................................... 3 3.1 Descripción de la Transacción de Autorización Mall Normal ............................................ 3 3.2 Secuencia de pago en una transacción de autorización Mall Normal ............................... 5 3.3 Flujo Alternativo: Secuencia de pago en una transacción mall normal anulada en formulario de pago .................................................................................................................... 8 3.4 Flujo Alternativo: Secuencia de pago en una transacción mall normal con evento de timeout .................................................................................................................................... 10 3.5 4 Descripción de métodos del Servicio Web de Transacción de Autorización Mall Normal 12 3.5.1 Operación initTransaction .................................................................................... 12 3.5.2 Operación getTransactionResult........................................................................... 15 3.5.3 Operación acknowledgeTransaction ..................................................................... 19 Ejemplos de integración con API SOAP Webpay – Transacción Mall Normal ......................... 20 4.1 Ejemplo Java................................................................................................................. 21 4.2 Ejemplos PHP ............................................................................................................... 25 4.3 Ejemplos .Net ............................................................................................................... 34 Página 1 1 Control de cambios Fecha 12-12-12 Version 1.0 14-02-13 18-11-14 26-11-14 12-03-2015 1.1 1.2 1.3 1.4 Descripción del cambio Liberación inicial de documento general de API de integración con WS Transacción mall normal. Futuros Release: Ejemplos de integración PHP, .NET. Ejemplos PHP y .Net Mejoras según observaciones Mejoras según observaciones Actualizaciones y mejoras en especificaciones de métodos 2 Prefacio 2.1 Acerca de esta guía Esta guía describe los aspectos técnicos que deben ser considerados en la integración con Webpay utilizando API SOAP, describe el servicio Web para Transacción de Autorización Mall Normal, sus operaciones y cómo estas deben ser utilizadas en un flujo de pago. 2.2 Audiencia Esta guía está dirigida a implementadores que realizan la integración de Webpay en comercios utilizando la API SOAP para soportar en estos el pago con tarjetas bancarias. Se recomienda que quién realice la integración posea conocimiento técnico de al menos en los siguientes temas: Servicios Web WS-Security Firma digital, generación y validación. 2.3 Feedback para esta documentación Ayúdanos a mejorar esta información enviándonos comentarios a soporte@transbank.cl Página 2 3 Transacción de Autorización Mall Normal 3.1 Descripción de la Transacción de Autorización Mall Normal Una transacción Mall Normal corresponde a una solicitud de autorización financiera de un conjunto de pagos con tarjetas de crédito o débito, en donde quién realiza el pago ingresa al sitio del comercio, selecciona productos o servicios, y el ingreso asociado a los datos de la tarjeta de crédito o débito lo realiza una única vez en forma segura en Webpay para el conjunto de pagos. Cada pago tendrá su propio resultado, autorizado o rechazado. El Mall Webpay agrupa múltiples tiendas, son estas últimas las que pueden generar transacciones. Tanto el mall como las tiendas asociadas son identificadas a través de un número denominado código de comercio. Tienda Mall Tienda virtual 1 Pago $1.000 Tienda Virtual 2 Pago $2.000 Tienda Virtual N Pago $3.000 El flujo de páginas para la transacción es el siguiente: Sitio del Comercio Webpay Formulario de Pago Autenticación en Banco Emisor Sitio del Comercio Webpay Comprobante de pago Sitio del Comercio ……. Página 3 Resumen de los métodos del servicio Web de Transacción Mall Normal Método initTransaction getTransactionResult acknowledgeTransaction Descripción general Permite inicializar una transacción en Webpay. Como respuesta a la invocación se genera un token que representa en forma única una transacción. Es importante considerar que una vez invocado este método, el token que es entregado tiene un periodo reducido de vida de 5 minutos, posterior a esto el token es caducado y no podrá ser utilizado en un pago. Permite obtener el resultado de la transacción una vez Webpay ha resuelto su autorización financiera. Indica a Webpay que se ha recibido conforme el resultado de la transacción. El método acknowledgeTransaction debe ser invocado siempre, independientemente del resultado entregado por el método getTransactionResult. Si la invocación no se realiza en un período de 30segundos, Webpay reversará la transacción, asumiendo que el comercio no pudo informarse de su resultado, evitando así el cobro al tarjetahabiente. Página 4 3.2 Secuencia de pago en una transacción de autorización Mall Normal El siguiente diagrama ilustra la secuencia de pago y cómo participan los distintos actores en una transacción Mall Normal. sd Secuencia Fluj o Webpay Transaccion Mall Normal Comercio Webpay WS Tarjetahabiente 1.- Pagar con Webpay() 2.- initTransaction() 3 Response() :token, urfFormOfPayment 4.- Redirect(token...) 5.-Request(token...) 6.-Formulario Webpay() 7.-Pagar() 8.-Autoriza() 9.-Redirect() 10.-Request(token) 11.-getTransacionResult(token...) 12.-Response() 13.-acknowledgeTransaction(token) 14.-Redirection(token) 15.-Request(token) 16.-Comprobanre Webpay() 17.-Request(token) 18.-Pagina final() Ilustración 1:Diagrama de secuencia de Transacción Mall Normal Página 5 Descripción de la secuencia: 1. Una vez seleccionado los bienes o servicios, tarjetahabiente decide pagar a través de Webpay. 2. El comercio inicia una transacción en Webpay, invocando el método initTransaction(…). 3. Webpay procesa el requerimiento y entrega como resultado de la operación el token de la transacción y URL de redireccionamiento a la cual se deberá redirigir al tarjetahabiente. 4. Comercio redirecciona al tarjetahabiente hacia Webpay, con el token de la transacción a la URL indicada en punto 3. La redirección se realiza enviando por método POST el token en variable token_ws. 5. El navegador Web del tarjetahabiente realiza una petición HTTPS a Webpay, en base al redireccionamiento generado por el comercio en el punto 4. 6. Webpay responde al requerimiento desplegando el formulario de pago de Webpay. Desde este punto la comunicación es entre Webpay y el tarjetahabiente, sin interferir el comercio. El formulario de pago de Webpay despliega, entre otras cosas, el monto de la transacción, información del mall como nombre y logotipo,nombre y monto por cada tienda, las opciones de pago a través de crédito o débito. 7. Tarjetahabiente ingresa los datos de la tarjeta, hace clic en pagar en formulario Webpay. 8. Webpay procesa la solicitud de autorización para cada uno de los pagos de las tiendas. 9. Una vez resuelta la autorización de cada pago, Webpay retorna el control al comercio, realizando un redireccionamiento HTTP/HTTPS hacia el sitio del comercio, en donde se envía por método POST el token de la transacción en la variable token_ws. 10. El navegador Web del tarjetahabiente realiza una petición HTTP/HTTPS al sitio del comercio, en base a la redirección generada por Webpay en el punto 9. 11. El sitio del comercio recibe la variable token_ws e invoca el segundo método Web, getTransactionResult () (mientras se despliega la página de transición1), para obtener el 1 El detalle de la página de transición se encuentra descrito en Anexo A, del documento de descripción general de la API SOAP. Página 6 resultado de la autorización. Se recomienda que el resultado de la autorización sea persistida en los sistemas del comercio, ya que este método se puede invocar una única vez por transacción. 12. Webpay responde el resultado de la invocación del método getTransactionResult(). 13. Para informar a Webpay que el resultado de la transacción se ha recibido sin problemas, el sistema del comercio consume el tercer método acknowledgeTransaction(). NOTA: De no ser consumido ó demorar más de 30 segundos en su consumo, Webpay realizará la reversa de la transacción, asumiendo que existieron problemas de comunicación. 14. Una vez recibido el resultado de la transacción e informado a Webpay su correcta recepción, el sitio del comercio debe redirigir al tarjetahabiente nuevamente a Webpay, con la finalidad de desplegar el comprobante de pago. Es importante realizar este punto para que el tarjetahabiente entienda que el proceso de pago fue exitoso, y que involucrará un cargo a su tarjeta bancaria. El redirecionamiento a Webpay se hace utilizando como destino la URL informada por el método getTransactionResult() enviando por método POST el token de la transacción en la variable token_ws. 15. Webpay recibe un requerimiento con el token en la variable token_ws valida que la transacción se encuentre aprobada. 16. Webpay identifica la transacción y despliega el comprobante de pago al tarjetahabiente. 17. Una vez visualizado el comprobante de pago, el tarjetahabiente es redirigido de vuelta al sitio del comercio, por medio de redireccionamiento con el token en la variable token_ws enviada por método POS, hacia la página final informada por el comercio en el método initTransaction(). 18. Sitio del comercio despliega página final de pago2. 2 El detalle de la página de transición se encuentra descrito en Anexo A, del documento de descripción general de la API SOAP. Página 7 3.3 Flujo Alternativo: Secuencia de pago en una transacción mall normalanulada en formulario de pago El siguiente diagrama ilustra la secuencia de una transacción normal donde el TH anula la transacción en el formulario de pago de Webpay y cómo participan los distintos actores en esta situación. Ilustración 2. Botón anular formulario de pago en Webpay sd Secuencia Fluj o Webpay Transaccion Anulada Comercio Webpay WS T rajetahabiente 1.- Pagar con Webpay() 2.- initTransaction() 3 Response() :token, urfFormOfPayment 4.- Redirect(token...) 5.-Request(token...) 6.-Formulario Webpay() 7.-Anular() 8.-Redirect() 9.-Request(token) 10.-Pagina final() Ilustración 3: Diagrama de secuencia de pago en una transacción mall normal anulada en formulario de pago Página 8 Descripción de secuencia alternativa, anular: 1. Pasos de 1 a 6 son idénticos a la secuencia normal. 7. Tarjetahabiente hace clic en “anular”, en formulario Webpay. 8. Webpay retorna el control al comercio, realizando un redireccionamiento HTTP/HTTPS hacia la página de final del comercio, en donde se envía por método POST el token de la transacción en la variable TBK_TOKEN. 9. El comercio con la variable TBK_TOKEN debe, invocar el segundo método Web, getTransactionResult()(mientras se despliega la página de transición3), para obtener el resultado de la autorización. En este caso debe obtener una excepción, pues el pago fue abortado. 10. El comercio debe informar al tarjeta habiente que su pago no se completó, según anexo glosa transacción no autorizada 3 El detalle de la página de transición se encuentra descrito en Anexo A, 6.1.1 del documento de descripción general de la API SOAP. Página 9 3.4 Flujo Alternativo: Secuencia de pago en una transacción mall normal con evento de timeout sd Secuencia Fluj o Webpay Webserv ice Transaccion Comercio Webpay WS T arjetahabiente 1.- Pagar con Webpay() 2.- initTransaction() 3 Response() :token, urfFormOfPayment 4.- Redirect(token...) 5.-Request(token...) 6.-Formulario Webpay() 7.-timeout() 8.-error() :Pagina de error Ilustración 4:Diagrama de secuencia de Transacción con Timeout en Formulario Página 10 Descripción de secuencia alternativa, timeout: 1. Pasos de 1 a 6 son idénticos a la secuencia normal. 7. Tarjetahabiente esta en formulario Webpay, pero no presiona pagar durante 10 minutos. Esto causa un timeout en dicho formulario. 8. Webpay genera un error de timeout, se presenta una pantalla indicando que ocurrió un error. No se regresa automáticamente al comercio. Página 11 3.5 Descripción de métodos del Servicio Web de Transacción de Autorización Mall Normal A continuación se describen cada uno de las operaciones que deben ser utilizadas en una Transacción Mall Normal. 3.5.1 Operación initTransaction Método que permite iniciar una transacción de pago Webpay. 3.5.1.1 Parámetro de entrada Nombre WSTransactionType Descripción tns:wsTransactionType sessionId Indica el tipo de transacción, su valor debe ser siempre TR_NORMAL_WS xs:string (Opcional) Identificador de sesión, uso interno de comercio, este valor es devuelto al final de la transacción. returnURL Largo máximo: 61 xs:anyURI finalURL (Obligatorio) URL del comercio, a la cual Webpayredireccionará posterior al proceso de autorización. Largo máximo: 256 xs:anyURI transactionDetails (Obligatorio) URL del comercio a la cual Webpayredireccionará posterior al voucher de éxito de Webpay. Largo máximo: 256 tns:wsTransactionDetail wPMDetail (Obligatorio) Lista de objetos del tipo wsTransactionDetail, el cual contiene datos de la transacción. Máxima cantidad de repeticiones es de 1 para este tipo de transacción. wsTransactionDetailestá descrito más adelante. tns:wPMDetail (No se utiliza para Transacción Normal)Este campo contiene la transacción webpay mensual. commerceId xs:string (Obligatorio)Es el código único de identificación del comercio entregado por Transbank. En este caso el commerceID corresponde al código asignado al PST (o código mall), y que agrupa los códigos de comercio que recibirán los pagos. Largo: 12 Página 12 buyOrder xs:string (Obligatorio)Es el código único de la orden de compra generada por el comercio mall. Largo máximo: 26 La orden de compra puede tener: Números, letras, mayúsculas y minúsculas, y los signos |_=&%.,~:/?[+!@()>TYPEWS T RANSACTION D ETAIL Descripción: Tipo de dato contiene detalles de la transacción Campo amount Descripción xs:decimal Monto de la transacción. Máximo 2 decimales para USD. buyOrder Largo máximo: 10 xs:string Orden de compra del tienda. 4 Largo máximo: 26 commerceCode La orden de compra puede tener: Números, letras, mayúsculas y minúsculas, y los signos |_=&%.,~:/?[+!@()>xs:string Código comercio de la tienda entregado por Transbank. 4 sharesAmount Largo: 12 Campo no utilizado sharesNumber Campo no utilizado Debe cumplir con el formato de caracteres permitidos Página 13 3.5.1.2 Parámetros de salida:TypewsInitTransactionOutput Campo token Descripción xs:string Token de la transacción. url Largo: 64 xs:string URL de formulario de pago Webpay Largo máximo: 256 Página 14 3.5.2 Operación getTransactionResult Método que permite obtener el resultado de la transacción y los datos de la misma. 3.5.2.1 Parámetros de entrada Campo tokenInput Descripción xs:string Token de la transacción. Largo: 64 3.5.2.2 Parámetros de salida: TypeTransactionResultOutput Campo buyOrder Descripción xs:string Orden de compra del mall. sessionId Largo máximo: 26 xs:string cardDetails Identificador de sesión, uso interno de comercio, este valor es devuelto al final de la transacción. Largo máximo: 61 Tns:carddetails Objeto que representa los datos de la tarjeta de crédito del tarjetahabiente.cardDetails descrito más adelante. accoutingDate xs:string Fecha de la autorización. transactionDate Largo: 4, formato MMDD xs:string Fecha y hora de la autorización. VCI Largo: 6 formato: MMDDHHmm xs:string Resultado de la autenticación para comercios Webpay Plus y/o 3D Secure, los valores posibles son los siguientes: Página 15 Campo Descripción TSY: Autenticación exitosa TSN: autenticación fallida. 5 TO : Tiempo máximo excedido para autenticación. ABO: Autenticación abortada por tarjetahabiente. U3: Error interno en la autenticación. Puede ser vacío si la transacción no se autentico. urlRedirection Largo máximo: 3 xs:string URL de redirección para visualización de voucher. detailsOutput Largo máximo: 256 tns:wsTransactionDetailOutput detailsOutputObjeto que contiene el detalle de la transacción financiera. Descrito más adelante TYPECARDDETAIL Descripción: Tipo de dato contiene detalles de la tarjeta de crédito. Campo cardNumber Descripción xs:string 4 últimos números de la tarjeta de crédito del tarjeta habiente. Solo para comercios autorizados por Transbank se envía el número completo. La fecha de expiración llegara nula. cardExpirationDate Largo máximo: 16 xs:string (Opcional) Fecha de expiración de la tarjeta de crédito del tarjetahabiente. Formato YYMM Solo para comercios autorizados por Transbank. Largo máximo: 4 5 VCI=TO indica que se produjo un time-out en el proceso de autenticación bancaria. Esta transacción no será autorizada y seguirá el flujo normal de eventos. Página 16 TYPEWSTRANSACTIONDETAILOUTPUT Descripción: Tipo de dato contiene el detalle del resultado de la transacción. Campo authorizationCode Descripción xs:string Código de autorización de la transacción paymentTypeCode Largo máximo: 6 xs:string Tipo de pago de la transacción. VD = Venta Debito VN = Venta Normal VC = Venta en cuotas SI = 3 cuotas sin interés S2=2 cuotas sin interés NC = N Cuotas sin interés responseCode Amount xs:string Código de respuesta de la autorización. Valores posibles: 0 Transacción aprobada. -1 Rechazo de transacción. -2 Transacción debe reintentarse. -3 Error en transacción. -4 Rechazo de transacción. -5 Rechazo por error de tasa. -6 Excede cupo máximo mensual. -7 Excede límite diario por transacción. -8 Rubro no autorizado. xs:decimal Monto de la transacción. Largo máximo: 10 Página 17 Campo sharesNumber Descripción xs:int Cantidad de cuotas commerceCode Largo máximo: 2 xs:string Código comercio de la tienda buyOrder Largo: 12 xs:string Orden de compra del mall. Largo máximo: 26 Página 18 3.5.3 Operación acknowledgeTransaction Método que permite informar a Webpay la correcta recepción del resultado de la transacción. 3.5.3.1 Parámetros de entrada: acknowledgeTransaction Campo tokenInput Descripción xs:string Token de la transacción. Largo: 64 En caso de llamar al método acknowledgeTransaction posterior a 30 segundos de ocurrida la autorización, se informará la excepción descrita más abajo y el comercio no debe entregar producto o servicio ya que la transacción es reversada por Transbank: Timeout error (Transactions REVERSED) con código 277. Página 19 4 Ejemplos de integración con API SOAP Webpay – Transacción Mall Normal La presente sección, entrega ejemplos de uso de la API SOAP para transacción Mall normal en los lenguajes Java, PHP y .Net. Tienen por objetivo exponer una forma factible de integración con API SOAP Webpay para resolver los siguientes puntos asociados a la integración: Generación de cliente o herramienta para consumir los servicios Web, lo cual permite abstraerse de la complejidad de mensajería SOAP asociada a los Webservice y hacer uso de las operaciones del servicio. Firma del mensaje y validación de firma en la respuesta, existen frameworks y herramientas asociadas a cada lenguaje de programación que implementan el estándar WS Security, lo que se requiere es utilizar una de estas, configurarla y que realice el proceso de firma digital del mensaje. Estos ejemplos son sólo una guía / ayuda de integración, y no abarcan el proceso completo de llamada a los WS. En ningún caso son una obligatoriedad su implementación, y el comercio es libre de realizar la integración como más le acomode. Página 20 4.1 Ejemplo Java Este ejemplo hará uso de los siguientes frameworks para consumir los servicios Web de Webpay utilizando WS Security: Apache CXF, es un framewok open source que ayuda a construir y consumir servicios Web en Java. En este ejemplo se utilizará para: o Generar el cliente del Webservice o STUBS. o Consumir los servicios Web Apache WSS4J, proporciona la implementación del estándar WS Security, nos permitirá: o Firmar los mensajes SOAP antes de enviarlo a Webpay. o Validar la firma de la respuesta del servicio Web de Webpay. Spring framewok 3.0, permite que CXF y WSS4J trabajen en conjunto, también se utiliza para configurar WS Security en la firma del mensaje SOAP. Pasos a seguir: 1. Generación de cliente del Webservice. Para generar el código Java que implementará el cliente SOAP se utilizará wsdl2java de CXF, el cual toma el WSDL del servicio y genera todas las clases necesarias para invocar el servicio Web. Más información en http://cxf.apache.org/docs/wsdl-to-java.html wsdl2java -autoNameResolution <URL del wsdl> Página 21 2. Configuración de WS Security Para configurar WS Security en CXF se deben habilitar y configurar los interceptores que realizaran el trabajo de firmado del mensaje. La configuración de los interceptores se puede realizar a través de la API de servicios Web o a través del XML de configuración de Spring, en este caso se realizará a través de Spring en el archivo applicationContext.xml de la aplicación. Se deben habilitar y configurar 2 interceptores, uno para realizar la firma de los mensajes enviados al invocar una operación del servicio Web de Webpay y otro para validar la firma de la respuesta del servicio Web. Interceptor de salida <bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor" id="signOutRequestInterceptor"> <constructor-arg> <map> <entry key="signaturePropFile" value="signatureOut.properties"/> <entry key="user" value="${alias.client}"/> <entry key="action" value="Signature"/> <entry key="passwordCallbackClass" value="com.transbank.webpay.wsse.ClientCallBack"/> <entry key="signatureParts" value="{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body"/> </map> </constructor-arg> </bean> Interceptor de entrada <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor" id="signInRequestInterceptor"> <constructor-arg> <map> <entry key="action" value="Signature" /> <entry key="signaturePropFile" value="signatureIn.properties"/> <entry key="passwordCallbackClass" value="com.transbank.webpay.wsse.ServerCallBack"/> <entry key="signatureParts" value="{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body"/> </map> </constructor-arg> </bean> LasclasesClientCallbackyServerCallBackimplementan interfaz javax.security.auth.callback.CallbackHandler, su implementaciónpermite al framework de seguridad recuperar la contraseña para acceder al almacen de llaves de la aplicación (Java Key Store) que almacena los certificados digitales. Página 22 la 3. Llamada a operaciones del Webservice Operación initTransaction private WSWebpayService service; private List<WsTransactionDetail> transactionDetails= new ArrayList< WsTransactionDetail> private WsTransactionDetail transactionDetail = new WsTransactionDetail(); private WsTransactionDetail transactionDetail2 = new WsTransactionDetail(); private WsInitTransactionInput transactionInput = new WsInitTransactionInput(); private WsInitTransactionOutput transactionOutput = new WsInitTransactionOutput(); transactionInput.setCommerceCode(“59702512300”); /*Código de comercio del Mall*/ transactionInput.setSessionId(“12312423”); transactionInput.setReturnURL(“http://www.midominio.com/recibetoken.do”); transactionInput.setFinalURL(“http://www.midominio.com/resultado.do”); transactionDetail.setAmount(new BigDecimal(1000)); transactionDetail.setCommerceCode(“59702512345”); transactionDetail.setBuyOrder(“OC111111111”); transactionDetail2.setAmount(new BigDecimal(2000)); transactionDetail2.setCommerceCode(“59702512346”); transactionDetail2.setBuyOrder(“OC222222222”); transactionDetails.add(transactionDetail); transactionDetails.add(transactionDetail2); transactioInput.setWSTransactionType(WsTransactionType.TR_MALL_WS); transactionInput.getTransactionDetails().add(transactionDetails); transactionOutput = service.initTransaction(transactionInput); /*Token y URL de redirección*/ transactionOutput.getUrl(); transactionOutput.getToken(); Página 23 OperacióngetTransactionResult /*Se asume que se obtuvo el token, el cual fue enviado por Webpay a la URL notificada en el parámetro returnURL al invocar al método initTransaction, el parámetro enviado por post se llama token_ws*/ private WSWebpayService service; private TransactionResultOutput transactionResultOutput; transactionResultOutput = service.getTransactionResult(token); /* transactionResultOutput contendrá los parámetros de resultado de la transacción*/ OperaciónacknowledgeTransaction() /*Se asume que se obtuvo el token, este método tiene por objetivo indicarle a Webpay que se obtuvo el resultado de la transacción correctamente. Este método es void*/ private WSWebpayService service; service.acknowledgeTransaction(token); URL: http://cxf.apache.org/docs/ws-security.html http://ws.apache.org/wss4j/ http://cxf.apache.org/docs/wsdl-to-java.html Página 24 4.2 Ejemplos PHP El siguiente ejemplo está basado en PHP versión 5, sobre el cual se utilizaron las siguientes bibliotecas de software para realizar la invocación de los servicios web de Webpay bajo el estándar WSS: Biblioteca de seguridad: archivo compuesto de tres clases que integran librerías nativas PHP de validación y verificación. Estas clases nos permitirán generar la seguridad suficiente a través de métodos de encriptación y desencriptación. WSSE-PHP: integra las librerías de seguridad XML y genera un documento XML-SOAP seguro. Depende de las librerías de seguridad XML. SOAP-VALIDATION: clase encargada de la validación de mensajes SOAP seguros de respuesta. Verifica la autenticidad e integridad del mensaje. Depende de WSSE-PHP. Las fuentes pueden ser descargadas desde https://github.com/OrangePeople/php-wss-validation Pasos a seguir: 1. Generación de cliente del Servicio Web: Antes de la integración se debe tener instalado y funcionando un servidor HTTP Apache y configurar el directorio para generar una salida a través del navegador web. Si se quiere optar por una alternativa más sencilla, Apache provee un directorio por omisión, que varía según el sistema operativo. Generalmente en plataformas Linux es “/var/www” y en Windows “C:\<directorio hacia Apache>/htdocs”. A continuación, para generar las clases necesarias que conectan a los servicios Web, se puede utilizar la herramienta Easy WSDL2PHP. La documentación necesaria e información de descarga se encuentra en http://sourceforge.net/projects/easywsdl2php/. Una vez descargados los fuentes, se deben copiar en el directorio de apache que posee la salida por navegador. Se hace la llamada por navegador del archivo wsdl2php.php y se obtiene la siguiente pantalla: Página 25 Se escribe la URL del archivo wsdl al se quiere conectar, un nombre de clase y luego se presiona el botón GenerateCode. Luego de esto se muestra una pantalla como la siguiente: Una vez que se obtiene el resultado mostrado en la imagen se copia el código PHP generado y se guarda en un archivo, el cual representará el stub del servicio Web. Una vez realizado este proceso ya se tienen las clases necesarias para poder integrarse con los servicios web de Webpay. Página 26 2. Crear una clase que extienda de SoapClient (SoapClient es la clase nativa que provee PHP para utilización de servicios Web)(En el ejemplo se denominará MySoap) <?php //Notar que se incluyen dos archivos que se proveen en la librería de encriptación require_once('xmlseclibs.php'); require_once('soap-wsse.php'); define('PRIVATE_KEY', dirname(__FILE__).'/privadacomercio.pem'); define('CERT_FILE', dirname(__FILE__).'/certificadocomercio.pem'); class MySoap extends SoapClient { private $useSSL=false; function __construct($wsdl,$options){ $locationparts = parse_url($wsdl); $this->useSSL = $locationparts['scheme']=="https" ? true:false; return parent::__construct($wsdl,$options); } function __doRequest($request, $location, $saction, $version) { if ($this->useSSL){ $locationparts = parse_url($location); $location = 'https://'; if(isset($locationparts['host'])) $location .= $locationparts['host']; if(isset($locationparts['port'])) $location .= ':'.$locationparts['port']; if(isset($locationparts['path'])) $location .= $locationparts['path']; if(isset($locationparts['query'])) $location .= '?'.$locationparts['query']; } $doc = new DOMDocument('1.0'); $doc->loadXML($request); $objWSSE = new WSSESoap($doc); $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1,array('type' => 'private')); $objKey->loadKey(PRIVATE_KEY, TRUE) $options = array("insertBefore" => TRUE); $objWSSE->signSoapDoc($objKey, $options); $objWSSE->addIssuerSerial(CERT_FILE); $objKey = new XMLSecurityKey(XMLSecurityKey::AES256_CBC); $objKey->generateSessionKey(); $retVal = parent::__doRequest($objWSSE->saveXML(), $location, $saction, $version); $doc = new DOMDocument(); $doc->loadXML($retVal); return $doc->saveXML(); } } ?> Las constantes PRIVATE_KEY Y CERT_FILE son las rutas de la llave privada y certificado del comercio, respectivamente. Página 27 3. Incluir la clase generada en el paso anterior en el archivo principal de los servicios. Se debe incluir con la sentencia require_once la clase generada en el paso anterior. Ejemplo: require_once(“mysoap.php”); 4. Editar el archivo stub creado en el paso 1 Se debe editar el método __contruct del stub tal como se muestra en el ejemplo: Donde dice: $this->soapClient = new SoapClient($url, array("classmap" => self::$classmap, "trace" => true, "exceptions" => true)); Debe quedar: (utilizando el nombre de clase del paso 2) $this->soapClient = new MySoap($url, array("classmap" => self::$classmap, "trace" => true, "exceptions" => true)); Página 28 5. Invocación de operaciones del servicio web de Webpay. Para todos los ejemplos se debe hacer referencia a los archivos de la librería descargada require_once('soap-wsse.php'); require_once('soap-validation.php'); /* WebpayService.php es el archivo que contiene la clasestub creado en el paso 1*/ require_once('WebpayService.php'); Adicionalmente se recomienda definir la constante SERVER_CERT, la que representa la ruta del certificado público de Transbank. define('SERVER_CERT', dirname(__FILE__).'/servidorwebpay.pem'); Página 29 OperaciónInitTransaction: $wsInitTransactionInput = new wsInitTransactionInput(); $wsTransactionDetail = new wsTransactionDetail(); $detailArray = array(); $wsInitTransactionInput->wSTransactionType = “TR_MALL_WS”; $wsInitTransactionInput->commerceId = “597026000002”; $wsInitTransactionInput->buyOrder = “123456789”; $wsInitTransactionInput->sessionId = “11111” $wsInitTransactionInput->returnURL = <URL de retorno, en la cual se deberá llamar a getTransactionResult> $wsInitTransactionInput->finalURL = <URL donde Webpay redirigirá el Flujo luego del resultado de la autorización> /*Primera tienda*/ $wsTransactionDetail->commerceCode = “597026000012”; $wsTransactionDetail->buyOrder = “00001” $wsTransactionDetail->amount = “100”; /*Se agrega al arreglo de tiendas*/ $detailArray[0] = $wsTransactionDetail; $wsTransactionDetail = new wsTransactionDetail(); /*Segunda tienda*/ $wsTransactionDetail->commerceCode = “597026000022”; $wsTransactionDetail->buyOrder = “00002” $wsTransactionDetail->amount = “300”; /*Se agrega al arreglo de tiendas*/ $detailArray[1] = $wsTransactionDetail; $wsInitTransactionInput->transactionDetails = $detailArray; $endpoint = <acá va el endpoint entregado por Transbank según ambiente>; $webpayService = new WebpayService($endpoint); $initTransactionResponse = $webpayService->initTransaction( array("wsInitTransactionInput" => $wsInitTransactionInput) ); $xmlResponse = $webpayService->soapClient->__getLastResponse(); $soapValidation = new SoapValidation($xmlResponse, SERVER_CERT); $validationResult = $soapValidation->getValidationResult(); /*Invocar sólo sí $validationResult es TRUE*/ if ($validationResult) { $wsInitTransactionOutput = $initTransactionResponse->return; /*TOKEN de Transacción entregado por Webpay*/ $tokenWebpay = $wsInitTransactionOutput->token; /*URL donde se debe continuar el flujo*/ $urlRedirect = $wsInitTransactionOutput->url; } Página 30 Observaciones: La clase WebpayService contiene los servicios principales y es el nombre que se generó el stub en el paso 1. La constante SERVER_CERT es la ruta del archivo del certificado cliente entregado por Transbank. initTransaction es un método de la clase WebpayService y representa la llamada el servicio initTransaction. La variable $xmlResponsees un string del xml-soap que responde el servidor. La variable $validationResult es el resultado de tipo boolean de la validación del mensaje de respuesta. Para un caso correcto el valor es TRUE, de lo contrario es FALSE. La variable $wsInitTransactionOutputcontiene los datos que entrega el servidor. Esta variable sólo debe invocarse después de un resultado correcto en el mensaje SOAP de respuesta. OperacióngetTransactionResult: $webpayService = new WebpayService($url_wsdl); $getTransactionResult = new getTransactionResult(); $getTransactionResult->tokenInput = $_POST['token_ws']; $getTransactionResultResponse = $webpayService->getTransactionResult( $getTransactionResult); $transactionResultOutput = $getTransactionResultResponse->return; /*Validación de firma del requerimiento de respuesta enviado por Webpay*/ $xmlResponse = $webpayService->soapClient->__getLastResponse(); $soapValidation = new SoapValidation($xmlResponse, SERVER_CERT); $validationResult = $soapValidation->getValidationResult(); if ($validationResult) { /* Validación de firma correcta */ $transactionResultOutput = $getTransactionResultResponse->return; /*Fecha Contable*/ $accountingDate = $transactionResultOutput->accountingDate; /*Fecha Transacción*/ $transactionDate = $transactionResultOutput->transactionDate; /*Resultado de la autenticación*/ $authenticationCode = $transactionResultOutput->VCI; /*Orden de compra del MALL*/ $mallBuyOrder = $transactionResultOutput->buyOrder; /*Objeto que contiene los datos de la tarjeta*/ $cardDetail = $transactionResultOutput->cardDetail; /*Ultimo cuatro digitos*/ $cardNumber = $cardDetail->cardNumber; Página 31 /*Fecha de expiración*/ $cardExpirationDate = $cardDetail->cardExpirationDate; /*Obtención de los detalles de la transacción*/ $wsTransactionDetailOutput = $transactionResultOutput->detailOutput; /*URL de retorno para el paso siguiente*/ $url = $transactionResultOutput->urlRedirection; /*Obtención del resultado por tienda*/ $firstDetail = $wsTransactionDetailOutput[0]; $secondDetail = $wsTransactionDetailOutput[1]; /*Código de autorización de cada tienda según el ejemplo*/ $cod1 = $firstDetail->authorizationCode; $cod2 = $secondDetail->authorizationCode; /*Código del tipo de pago de cada tienda según el ejemplo*/ $ptCode1 = $firstDetail->paymentTypeCode; $ptCode2 = $secondDetail->paymentTypeCode; /*Código de respuesta de cada tienda según ejemplo*/ $rCode1 = $firstDetail->responseCode; $rCode2 = $secondDetail->responseCode; /*Número de cuotas de cada tienda según ejemplo*/ $sh1 = $firstDetail->sharesNumber; $sh2 = $secondDetail->sharesNumber; /*Monto de transacción de cada tienda según ejemplo*/ $txAmount1 = $firstDetail->amount; $txAmount2 = $secondDetail->amount; /*Orden de compra de cada tienda según ejemplo*/ $bOrder1 = $firstDetail->buyOrder; $bOrder2 = $secondDetail->buyOrder; } OperaciónacknowledgeTransaction: $webpayService = new WebpayService($url_wsdl); $acknowledgeTransaction = new acknowledgeTransaction(); $acknowledgeTransaction->tokenInput = $_POST['token_ws']; $acknowledgeTransactionResponse = $webpayService->acknowledgeTransaction( $acknowledgeTransaction); $xmlResponse = $webpayService->soapClient->__getLastResponse(); $soapValidation = new SoapValidation($xmlResponse, SERVER_CERT); $validationResult = $soapValidation->getValidationResult(); Página 32 Observaciones: El valor de $_POST['token_ws'] contiene un string del token de la transacción que entrega Webpay. Página 33 4.3 Ejemplos .Net Este ejemplo hará uso de los siguientes frameworks y componentes para consumir los servicios Web de Webpay utilizando WS Security: Microsoft .NET 4.0, es un framework de Microsoft que permite la independencia de hardware e integra todos sus productos desde el sistema operativo hasta las herramientas de mercado. o Soporte y Core para el desarrollo e implementación Web ServicesEnhancements 3.0, proporciona la implementación para desarrollo de Web Service e interoperabilidad con otros sistemas. o Generar el cliente del WebService o Proxy o Consumir los servicios Web Componente Intergrup.Core4.Soap.dll Componente para validación y firma digital para WS Security. Estos componentes representan una posible solución al problema del no soporte nativo de WSS en .Net IMPORTANTE. Se debe tener presente que el framework WSE 3.0 no es compatible en su totalidad con WSSecurity, requiere de algunas adaptaciones. Entre estas adaptaciones se encuentra la validación de firma digital sobre el XML de SOAP del WSE. La firma que se exige en el consumo del servicio Web se debe realizar sobre el body del XML, el cual debe ser marcado con un ID, es este caso el ID lleva un prefijo impuesto por la definición de WSS, WSE 3.0 no permite validar la firma sobre elementos cuyo identificado de referencia presenta un prefijo. Una posible solución se presenta en el sitio StackOverflow, en donde se plantea una forma de sobrescribir el método GetIdElement de la subclase System.Security.Cryptography.Xml.SignedXml, que es utilizada al momento de firmar y validar firmas digitales con el método nativo ComputeSignature. Nota: WSE 3.0 puede ser utilizado también con Framework .NET 2.0 y 3.5 respectivamente Página 34 Pasos a seguir: 1. Generación de cliente del Webservice. Para generar el código .NET que implementará el cliente SOAP se utilizará wsewsdl3 de WSE 3.0, el cual toma el WSDL del servicio y genera todas las clases necesarias para invocar el servicio Web. wsewsdl3 <URL del wsdl> /language:c# /namespace:<Opcional> /type:webClient Nota: Una vez instalado WSE 3.0 en Windows puede ser encontrado en C:\Program Files\Microsoft WSE\v3.0\Tools 2. Configuración de WS Security Para configurar WS Security en WSE 3.0 se implementó un conjunto de clases para definir y personalizar clases que entreguen el soporte para WS Security. Nota: La personalización de clases está definido dentro de WSE 3.0 para lograr la interoperabilidad entre sistemas. o Página 35 CustomPolicyAssertion: esta clase permite crear una Política para Assertion, donde podemos capturar el Mensaje SOAP de Request y Response respectivamente. Esto realizado a través de filtros: o ClientOutputFilter (Interceptor Salida): permite definir y personalizar el mensaje de Response hacia el servicio. Dentro de esta clase es interceptado el mensaje Soap y se realiza la firma digital. o ClientInputFilter (Interceptor de Entrada): permite definir y personalizar el mensaje de Request hacia el servicio. Dentro de esta clase es interceptado el mensaje SOAP y se realiza la validación de firma digital con la llave pública del certificado. Definición de política de proceso public class CustomPolicyAssertion : PolicyAssertion { private String issuerNameCertificate = null; publicCustomPolicyAssertion(String issuerNameCertificate) : base() { this.issuerNameCertificate = issuerNameCertificate; } public override SoapFilterCreateClientInputFilter( FilterCreationContext context) { return new ClientInputFilter(); } public override SoapFilterCreateClientOutputFilter( FilterCreationContext context) { return new ClientOutputFilter(this.issuerNameCertificate); } public override SoapFilterCreateServiceInputFilter( FilterCreationContext context) { return null; } public override SoapFilterCreateServiceOutputFilter( FilterCreationContext context) { return null; } public override IEnumerable<KeyValuePair<string, Type>>GetExtensions() { return new KeyValuePair<string, Type>[] { new KeyValuePair<string, Type>("CustomPolicyAssertion", this.GetType()) }; } public override void ReadXml(XmlReader reader, IDictionary<string, Type> extensions) { reader.ReadStartElement("CustomPolicyAssertion"); } } Página 36 La creación de una política permite definir al stub o proxy cómo activar los interceptores para envió o recepción de mensaje SOAP al consumir un WebService. Esto es permite en WSE 3.0 a modo de Custom de los objetos para lograr la interoperabilidad. Interceptor de salida public class ClientOutputFilter : SoapFilter { private String issuerNameCertificate = null; publicClientOutputFilter(String issuerNameCertificate) : base() { this.issuerNameCertificate = issuerNameCertificate; } public override SoapFilterResultProcessMessage(SoapEnvelope envelope) { WSSecuritySignature<SoapEnvelope, X509Certificate2> signed = new WSSecuritySignature<SoapEnvelope, X509Certificate2>(); String issuerName = HelperSetting.GetSetting(this.issuerNameCertificate); X509Certificate2 certificate = HelperCertificate.GetCertificate(issuerName); signed.Signature(envelope, certificate); returnSoapFilterResult.Continue; } } Se rescata el certificado digital del comercio y se procede a la firma digital. El componente de firma digital para WS Security se encuentra en la clase WSSecuritySignature. Página 37 Interceptor de Entrada public class ClientInputFilter:SoapFilter { public override SoapFilterResultProcessMessage(SoapEnvelope envelope) { WSSecuritySignature<SoapEnvelope, X509Certificate2> signed = new WSSecuritySignature<SoapEnvelope, X509Certificate2>(); String issuerName = HelperSetting.GetSetting(Constant.ISSUER_NAME_CERTIFICATE_SERVER); X509Certificate2 certificate = HelperCertificate.GetCertificate(issuerName); if (signed.CheckSignature(envelope, certificate)) { returnSoapFilterResult.Continue; } returnSoapFilterResult.Terminate; } } Se rescata el certificado digital del servidor (llave pública) y se procede a la validación de firma digital. Nota: los certificados digitales son almacenados en el Store de Windows para certificados digital y desde este repositorio son obtenidos mediante IssuerName o número del comercio. Página 38 Llamada a operaciones del Webservice Operación InitTransaction: wsInitTransactionInputinitTransaction = newwsInitTransactionInput(); initTransaction.wSTransactionType = wsTransactionType.TR_MALL_WS; initTransaction.commerceId = “597000000000”; initTransaction.buyOrder = “123456789”; initTransaction.sessionId = “1234567”; initTransaction.returnURL = “http://www.midominio.com/recibetoken.aspx”; initTransaction.finalURL = “http://www.midominio.com/resultado.aspx”; inttotalDetalle=2; //Como ejemplo se agregar dos detalles de comercios wsTransactionDetail[] details = new wsTransactionDetail[totalDetalle]; details[0] = newwsTransactionDetail { amount = Convert.ToDecimal(“12000”), buyOrder = “123456789-1”; commerceCode = “597000000001”; sharesAmount = newDecimal(4000); sharesNumber = “3”; sharesAmountSpecified = true; sharesNumberSpecified = true; }; details[1] = newwsTransactionDetail { amount = Convert.ToDecimal(“16000”), buyOrder = “123456789-2”; commerceCode = “597000000002”; sharesAmount = newDecimal(4000); sharesNumber = “4”; sharesAmountSpecified = true; sharesNumberSpecified = true; }; wsInitTransactionInputresult=null; String issuerNameCertificate=”597000000000”; using (WSWebpayServiceImplService proxy = newWSWebpayServiceImplService()) { /*Define el ENDPOINT del Web Service Webpay*/ proxy.Url = “http://localhost/WSWebpayTransaction/cxf/WSWebpayService”; PolicymyPolicy = newPolicy(); myPolicy.Assertions.Add(newCustomPolicyAssertion(issuerNameCertificate)); proxy.SetPolicy(myPolicy); proxy.Timeout = 60000; proxy.UseDefaultCredentials = false; result = proxy.initTransaction(initTransaction); Página 39 } /*Token y URL de redirección*/ String token=result.token; String urlRedireccion=result.url; Operación getTransactionResult /*Se asume que se obtuvo el token, el cual fue enviado por Webpay a la URL notificada en el parámetro returnURL al invocar al método initTransaction, el parámetro enviado por post se llama token_ws*/ transactionResultOutput result=null; String issuerNameCertificate=”597000000000”; using (WSWebpayServiceImplService proxy = new WSWebpayServiceImplService()) { /*Define el ENDPOINT del Web Service Webpay*/ proxy.Url = “http://localhost/WSWebpayTransaction/cxf/WSWebpayService”; Policy myPolicy = new Policy(); myPolicy.Assertions.Add(new CustomPolicyAssertion(issuerNameCertificate)); proxy.SetPolicy(myPolicy); proxy.Timeout = 60000; proxy.UseDefaultCredentials = false; result = proxy.getTransactionResult(token); } /* transactionResultOutput contendrá los parámetros de resultado de la transacción*/ Página 40 Operación acknowledgeTransaction() /*Se asume que se obtuvo el token, este método tiene por objetivo indicarle a Webpay que se obtuvo el resultado de la transacción correctamente. Este método es void*/ String issuerNameCertificate=”597000000000”; using (WSWebpayServiceImplService proxy = new WSWebpayServiceImplService()) { /*Define el ENDPOINT del Web Service Webpay*/ proxy.Url = “http://localhost/WSWebpayTransaction/cxf/WSWebpayService”; Policy myPolicy = new Policy(); myPolicy.Assertions.Add(new CustomPolicyAssertion(issuerNameCertificate)); proxy.SetPolicy(myPolicy); proxy.Timeout = 60000; proxy.UseDefaultCredentials = false; proxy.acknowledgeTransaction(token); } Referencias: WSE 3.0: http://www.microsoft.com/en-us/download/details.aspx?id=14089 Framework .NET 4.0: http://www.microsoft.com/en-us/download/details.aspx?id=17851 Herramientawsewsdl3 para generación de proxy http://www.microsoft.com/enus/download/details.aspx?id=14089 Componente Intergrup.Core4.Soap.dllhttp://www.intergrup.cl/software/ws-security.html Web Services Security X.509 Certificate Token Profile 1.1.https://www.oasisopen.org/committees/download.php/16785/wss-v1.1-spec-os-x509TokenProfile.pdf StackOverflow, firma en elementos con ID que utilizan prefijos. http://stackoverflow.com/questions/5099156/malformed-reference-element-whenadding-a-reference-based-on-an-id-attribute-w Página 41