Creando un botón de compra de Paypal con datos cifrados

1
29004

1. Introducción

En este tutorial vamos a ver cómo podemos añadir a nuestra web un botón de compra mediante Paypal, en el que los datos que enviamos a Paypal estén cifrados y firmados, de forma que nadie pueda ver ni modificar esa información.

Básicamente existen dos formas de generar botones para Paypal: estática y dinámica.

La documentación de Paypal ofrece información sobre cómo crear botones de pago estándar estáticos utilizando sus propias herramientas. Esto es útil si queremos añadir un botón «donaciones», tenemos pocos productos que vender, etc.

Sin embargo, si tenemos bastantes productos que vender, no tiene sentido crear un botón por cada uno de ellos, y deberemos generar nuestros botones dinámicamente.

En lo que resta de tutorial vamos a ver cómo generar nuestro botón de compra dinámicamente, según el producto seleccionado. Además, los datos del formulario que se va a enviar al pulsar el botón estarán cifrados y firmados digitalmente para evitar posibles intromisiones.

2. Entorno

  • Portátil Asus G50Vseries (Core Duo P8600 2.4GHz, 4GB RAM, 320 GB HD).
  • S.O. Ubuntu Karmic 9.10
  • Eclipse 3.5.0.
  • Apache Tomcat 6.0.20

3. Abrir una cuenta de desarrollador en Paypal

Paypal ofrece un entorno para desarrolladores en el que podemos crear usuarios de prueba y realizar todas las acciones normales de compra-venta. Salvo que nada de lo que hagamos reducirá el saldo real de nuestra tarjeta de crédito, afortunadamente.

Lo primero que debemos hacer es crearnos una cuenta en el entorno de pruebas de Paypal, para lo cual abriremos la siguiente URL en un navegador: https://developer.paypal.com/

Entorno de pruebas de Paypal

Pulsamos el botón «Sign Up Now» e introducimos nuestros datos.

Introduciendo datos de la cuenta de pruebas

Una vez creada la cuenta, recibiremos un correo electrónico con un enlace que deberemos abrir para activarla. Bien, ya podemos entrar en el entorno de pruebas utilizando el mail y la password que hayamos introducido.

Entrando en el entorno de pruebas de Paypal

El siguiente paso será crear dos usuarios para utilizar en nuestras pruebas: un vendedor y un cliente. Para ello, bajo el título de «Test Accounts» pulsamos el enlace «Create a preconfigured buyer or seller account» (también podemos crear cuentas manualmente, pero para nuestros propósitos esto será suficiente).

Crear una cuenta para el vendedor

Ya hemos creado la cuenta del vendedor. Le hemos asignado un saldo inicial de 9.999 (el máximo que deja) Euros para ir tirando. Al fin y al cabo estamos en un entorno de pruebas, así que por pedir que no quede.

Hacemos lo mismo para el comprador.

Un vez creadas nuestras dos cuentas, deberían aparecer en el listado:

Listado de cuentas creadas

Ambas cuentas deben aparecer con el estado «Verified», si alguna aparece como «Unverified», deberemos pulsar sobre su botón de «Reset» e introducir una nueva password.

4. Creando un certificado

Para poder enviar los datos de compra cifrados a Paypal, debemos generar un certificado y asociarlo a nuestro usuario de pruebas.
Abrimos un terminal y ejecutamos los siguientes comandos (iremos introduciendo los datos que nos pida):

openssl genrsa -out prvkey.pem 1024
openssl req -new -key prvkey.pem -x509 -days 365 -out pubcert.pem

Generando un certificado

Ahora tenemos que asociar este certificado con nuestro usuario vendedor. Volvemos al navegador, seleccionamos nuestro usuario «seller» y pulsamos el botón «Enter Sandbox Site».

Abrir sesión del vendedor

Introducimos la password que hubiésemos asignado al usuario y pulsamos «Iniciar Sesión».

Iniciar sesión del vendedor

Dentro de la pestaña «Mi cuenta», pulsamos sobre el menú «Perfil > Más opciones».

Opciones del perfil del usuario

Y en la sección «Preferencias de ventas» seleccionamos «Configuración de pago codificado». Añadimos el certificado público que hemos generado antes (para firmar los datos que enviemos) y descargamos el certificado público de Paypal (para cifrar los datos que enviemos).

Subiendo nuestro certificado

Vamos a apuntar el «id. de certificado» que se ha generado automáticamente. Por medio de ese valor, al enviar un formulario de compra, podremos indicar el certificado que estamos utilizando.

El certificado que hemos generado no podemos utilizarlo directamente desde el API de Java, sino que tendremos que convertirlo previamente al formato aceptado: PKCS#12 (es un formato portable para almacenar y/o transportar claves privadas de usuario, certificados, etc.). Para crear un fichero PKCS#12 que contendrá nuestras claves pública y privada, ejecutamos el siguiente comando:

  openssl pkcs12 -export -in pubcert.pem -inkey prvkey.pem -out cred.p12

El fichero .p12 estará protegido por una contraseña. Introducimos y confirmamos la password y listo.

Convertir certificado

5. Descargando el API Java de pago estándar

Paypal proporciona un API con funciones para crear fácilmente botones que envíen los datos de compra en un formulario cifrado.
Abrimos la siguiente dirección(https://cms.paypal.com/es/cgi-bin/?&cmd=_render-content&content_ID=developer/library_download_sdks) y descargamos el fichero correspondiente al lenguaje Java, donde pone «pago estándar».

Descargando el Java Toolkit

Extraemos los contenidos del archivo zip en una carpeta para añadirlos posteriormente a nuestro proyecto.

6. Configurando el proyecto

Abrimos el Eclipse y creamos un nuevo proyecto web dinámico.

Creando un nuevo proyecto web

Damos un nombre al proyecto, seleccionamos el Tomcat 6 como «Target runtime» y pulsamos finalizar.

Añadimos todos los .jar descargados a la carpeta «WEB-INF/lib» de nuestro proyecto.

Añadir librerías al proyecto

Añadimos el certificado público de Paypal y nuestro certificado «cred.p12» dentro de /src/autentia/tutorial/conf.

7. Creando una aplicación de prueba

Para probar el envío de datos de compra mediante un formulario cifrado, vamos a crear una sencilla aplicación que nos permita seleccionar un producto a comprar y posteriormente presente el botón de compra mediante Paypal para el producto elegido.

Creamos una página «index.jsp» donde se mostrarán varios productos a comprar. El usuario podrá seleccionar uno y pulsar el botón para continuar.

<h1>Seleccione un producto</h1>
<form action="paypalButton" method="post">
<p><input type="radio" name="producto" value="leche">Leche</input></p> 
<p><input type="radio" name="producto" value="huevos">Huevos</input></p>
<p> <input type="radio" name="producto" value="pan">Pan</input> </p>
<p><input type="submit" value="Seleccionar" /></p> 
</form>

 

El action del formulario nos dirigirá a un servlet que crearemos posteriormente, el cual mostrará la pantalla con el nombre del producto seleccionado y un botón de pago mediante Paypal.

Antes de crear el servlet, vamos a crearnos algunas clases para dar soporte al mismo. Para empezar, crearemos las clases de nuestro modelo, que implementarán la Interfaz «Producto».

package autentia.tutorial.model;

public interface Producto { 
  public String getDescripcion();
  public double getPrice();
}

Nuestros productos serán tres: huevos, leche y pan.

package autentia.tutorial.model;

public class Leche implements Producto {

  public static final String ID = "leche"; 
  @Override public String getDescripcion() { 
      return "Leche";
  }

  @Override public double getPrice() { 
      return 10.0; 
  }
}
package autentia.tutorial.model;

public class Huevos implements Producto {

   public static final String ID= "huevos";
   @Override public String getDescripcion() { 
      return "Huevos";
   }
  @Override public double getPrice() {
       return 15.0; 
  }
}

 

package autentia.tutorial.model;
public class Pan implements Producto { 

  public static final String ID ="pan";
  @Override public String getDescripcion() { 
      return "Pan"; 
  }
  @Override public double getPrice() { 
      return 5.0; 
  }
}

 

En una aplicación «de verdad» estos productos estarían en una B.D., pero aquí he creado esta jerarquía de clases por simplificar el tutorial.

Ahora crearemos una clase de servicio que devolverá el código HTML correspondiente al botón de compra a partir de los datos de un producto.

package autentia.tutorial.service;

import java.util.Properties;

import autentia.tutorial.model.Producto;

import com.paypal.wpstoolkit.services.EWPServices;

public class PaypalManager {

    public static final String PAYPAL_NOTE = "1";

    public static final String PAYPAL_SHIPPING = "0";

    public String getButton(Producto producto, String lc) throws Exception {
        String myPublicCert = getClass().getResource("/autentia/tutorial/conf/cred.p12").getPath();
        String paypalPublicCert = getClass().getResource("/autentia/tutorial/conf/paypal_cert_pem.txt").getPath();
        Properties properties = new Properties();
        properties.load(getClass().getResourceAsStream("/autentia/tutorial/conf/paypal.properties"));

        EWPServices ewp = new EWPServices();
        StringBuffer buffer = new StringBuffer("cmd=_xclickn");
        buffer.append("business=" + properties.getProperty("business") + "n");
        buffer.append("cert_id=" + properties.getProperty("certId") + "n");
        buffer.append("charset=UTF-8n");
        buffer.append("item_name=" + producto.getDescripcion() + "n");
        buffer.append("item_number=" + producto.getDescripcion() + "n");
        buffer.append("amount=" + producto.getPrice() + "n");
        buffer.append("currency_code=" + properties.getProperty("currency") + "n");
        buffer.append("return=" + properties.getProperty("returnUrl") + "n");
        buffer.append("cancel_return=" + properties.getProperty("cancelReturn") + "n");
        buffer.append("no_shipping=" + PAYPAL_SHIPPING + "n");
        buffer.append("no_note=" + PAYPAL_NOTE + "n");
        buffer.append("lc=" + lc + "n");

        return ewp.encryptButton(buffer.toString().getBytes("UTF-8"),
                myPublicCert, properties.getProperty("certPassword"), paypalPublicCert, properties.getProperty("service"),
                properties.getProperty("buttonImage"));
    }
}

 

La función getButton recibe el producto para el cual hay que crear el botón de compra y un código de idioma. En las primeras líneas se obtienen los certificados y un fichero de propiedades donde introduciremos los datos de configuración de Paypal.

La parte principal de la función crea una cadena en la que cada línea es una pareja clave/valor. Esos son los parámetros que se van a enviar cifrados a Paypal por medio del botón.

Vamos a resumir la funcionalidad de los parámetros utilizados:

  • cmd: indica el tipo de botón (compra, donación, suscripción, etc.). El valor «_xclick» indica que es un botón de tipo «comprar ahora«. Es obligatorio.
  • business: id. de Paypal o dirección de correo electrónico asociado a nuestra cuenta de Paypal. Es obligatorio.
  • cert_id: identificador del certificado público que hemos subido a nuestra cuenta de Paypal.
  • charset: indica la codificación de caracteres utilizada.
  • item_name: descripción del artículo.
  • item_number: valor que identifica el artículo y que se devolverá tras completarse el pago.
  • amount: precio del producto.
  • currency_code: divisa utilizada para el pago.
  • return: URL a la que redirigirá el navegador tras completarse el pago.
  • cancel_return: URL a la que redirigirá el navegador si no se completa el pago.
  • no_shipping: indica si debe pedirse a los pagadores una dirección de envío. El valor 0 indica que se pida una dirección, pero sin que sea obligatoria.
  • no_note: no preguntar a los pagadores si desean incluir una nota con los pagos.
  • lc: idioma de la página de identificación en Paypal.

Hemos utilizado sólamente algunos de los posibles parámetros que podemos utilizar en nuestro botón de compra de Paypal.

Un parámetro importante que no hemos utilizado aquí a propósito es «notify_url«. Éste parámetro indica la URL a la que Paypal enviará la información sobre la transacción. De esta manera podremos saber si la transacción se ha efectuado correctamente o, por el contrario, se ha producido algún problema, y actuar en consecuencia. La recepción de esta información y su procesamiento queda fuera del alcance de este tutorial, que sólo pretende cubrir el envío cifrado de la información a Paypal.

Por último, siguiendo con nuestro código, se llama a la función «EWPServices.encryptButton» del API que nos dercargamos de Paypal, la cual recibe los parámetros del formulario, los certificados, la clave privada del fichero .p12 y la URL del servicio de Paypal; esta función devolverá el código HTML con el botón de compra de Paypal.

A continuación se muestra el contenido del fichero «paypal.properties«, que hemos guardado en la carpeta «/src/autentia/tutorial/conf«. Los valores de business, certId y certPassword del fichero deberían coincidir con los que hayamos incluido en nuestra cuenta de pruebas de Paypal.

business=seller_1267186054_biz@autentia.com
service=https://www.sandbox.paypal.com/cgi-bin/webscr
certId=EXQHMFSH7RFFS
certPassword=clavep12
returnUrl=http://localhost:8080/paypal/ok.jsp
cancelReturn=http://localhost:8080/paypal/compra.jsp
buttonImage=https://www.sandbox.paypal.com/en_US/i/btn/x-click-but23.gif
currency=EUR

 

Ahora podemos crear nuestro servlet, que utilizará las clases anteriores para generar el botón de compra.

package autentia.tutorial.web.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import autentia.tutorial.model.Huevos;
import autentia.tutorial.model.Leche;
import autentia.tutorial.model.Pan;
import autentia.tutorial.model.Producto;
import autentia.tutorial.service.PaypalManager;

/**
 * Servlet implementation class PaypalButton
 */
public class PaypalButton extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
     */
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        StringBuilder out = new StringBuilder();

        if (request.getParameter("producto") == null) {
            out.append("No ha seleccionado ningún producto");
        } else {
            String nombre = request.getParameter("producto");
            Producto producto = null;

            if (Leche.ID.equals(nombre)) {
                producto = new Leche();
            } else if (Huevos.ID.equals(nombre)) {
                producto = new Huevos();
            } else if (Pan.ID.equals(nombre)) {
                producto = new Pan();
            }

            if (producto == null) {
                out.append("El producto seleccionado no es válido");
            } else {
                // Mostrar el botón de compra
                out.append("<h1>");
                out.append("Ha seleccionado: ");
                out.append(producto.getDescripcion());
                out.append("</h1>");

                PaypalManager manager = new PaypalManager();

                try {
                    String button = manager.getButton(producto, "es");
                    out.append(button);
                } catch (Exception e) {
                    e.printStackTrace();
                    out.append("<p>");
                    out.append("Se ha producido un error al generar el botón de Paypal.");
                    out.append(" <a href="javascript:history.back()">Volver</a>");
                    out.append("</p>");
                }
            }
        }

        response.getWriter().write(out.toString());
    }

}

 

El servlet simplemente comprueba si se ha seleccionado algún producto y muestra un botón de compra para el mismo, utilizando la clase de servicio anterior.

8. Probando la aplicación

Ya podemos arrancar el tomcat y probar nuestra aplicación. Para ello, introducimos la siguiente url en un navegador:http://localhost:/paypal

Si todo va bien, veremos nuestra pantalla de selección de producto.

Pantalla de selección de producto

Seleccionamos un producto y pulsamos el botón «seleccionar». Esto llamará a nuestro servlet, que generará el botón de envío a Paypal con los datos del producto seleccionado… ¿o no?

Traza de la excepción

Se ha producido una excepción al intentar cifrar los datos para el botón. Nos dice que el tamaño de la clave es ilegal. Esto se debe a las políticas de seguridad por defecto de Java.

Para evitarlo podemos descargar: «Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files» desde la página oficial de descargas de Sun (Oracle). Deberemos extraer los ficheros .jar dentro de la carpeta «$JAVA_HOME/jre/lib/security» y reemplazar los originales (¡es altamente recomendable hacer un backup primero!).

Como podemos leer dentro del fichero README de JCE, los ficheros distribuidos con el JDK de Java tienen algunas restricciones en el código que limitan la potencia de cifrado que puede utilizarse, a causa de las restricciones existentes en algunos países. Estos ficheros no contienen ningún tipo de restricción.

Ya podemos volver a lanzar la aplicación. Esta vez todo debería ir bien.

Pantalla de compra

Si pulsamos sobre el botón, se nos redirigirá al sitio de pruebas de Paypal.

Pantalla de login en Paypal

Si observamos la parte superior, veremos el nombre del producto que estamos comprando y su precio. ¡Los datos han llegado correctamente!. Ahora tendremos la opción de identificarnos como usuario de Paypal o pagar directamente introduciendo nuestros datos bancarios.

Al finalizar el proceso de compra se nos redirigirá de nuevo a nuestra aplicación (parámetro return de nuestro formulario). Si cancelamos la compra se nos redirigirá a la página indicada por el parámetro cancel_return (normalmente una página en la que indicaremos que el usuario ha cancelado su compra).

9. Conclusiones

Hemos visto cómo podemos generar fácilmente un botón de compra mediante Paypal para nuestro sitio web, de forma que la información se envíe cifrada y firmada. A raíz de lo visto, podemos extraer las siguientes conclusiones:

  • Siempre que utilizemos un botón de compra mediante Paypal en nuestras aplicaciones deberíamos enviar la información cifrada, ya que cuesta prácticamente lo mismo, pero en cambio es mucho más seguro.
  • Es sencillo desarrollar y probar nuestros botones mediante el entorno de pruebas de Paypal, y podemos configurar todos los vendedores y compradores que necesitemos para ello.
  • La diferencia entre distintos tipos de botones radica sólo en alguno de los parámetros que enviemos en nuestro formulario, y la forma de generar el botón con los datos cifrados es exactamente la misma, por lo que debería ser bastante sencillo reutilizar nuestras clases para diferentes tipos de botón.

Y eso es todo por el momento. Iremos viendo más cosillas sobre cómo utilizar Paypal en nuestras aplicaciones en próximos tutoriales.

Un saludo.

1 COMENTARIO

  1. Muchas gracias por este tutorial, esta genial aun asi, seria brutal que abordaras la comunicacion servidor a servidor en un futuro tutorial.

    gracias

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad