domingo, 28 de noviembre de 2010

Integrar el pago electrónico con paypal en java

Es increíble lo complicado que a veces puede resultar encontrar información sencilla sobre algo concreto. A la hora de la integración de una aplicación con sistemas de pago electrónico puedes encontrar algunos de los mejores ejemplos. Lo que voy a explicar es producto de un número demasiado elevado de horas buscando, leyendo, consultando y quebrándome la cabeza.

Y no solo con el caso específico de PayPal, sino con el resto de plataformas de pago con las que me he encontrado. Estoy pensando seriamente en crear un grupo en facebook "En contra de las explicaciones ambiguas para integrar plataformas de pago".

Bueno pues lo primero es saber si es complicado lo que tienes que hacer, porque lo que voy a contar es un pago estandar, es decir, una vez que en tu app ya sabes la cantidad que hay que pagar, quieres que se haga. Si quieres hacer pagos o gestionar tus cobros, o cosas más complejas con la interfaz SOAP, no es este tu artículo, jeje... Lo que vas a encontrar es lo que llaman:

  • Pago Express
  • Interfaz para NVP (abreviado de name-value pair)
  • Pago Estándar

Siempre hay un entorno de pruebas, como ya esperabas, y que funcionará exactamente igual que en el entorno real. Esta es una de las diferencias (entre otras) con plataformas con las que he trabajado y PayPal.

En esta última, el proceso que en principio creemos sencillo, que es el de obtener un número de tarjeta ficticio que sea aceptado por la validación de la tarjeta en la plataforma de pruebas, me implicó crear una cuenta ficticia de cliente en Paypal Sandbox y asociarle tarjetas.

Después de mucho clickar y urgar por el sandbox, trás intentar comprender que tipo de pago quiero realizar (..ufff) o ver mil veces el esquema de pago, tienes que tener una cuenta de empresa (o también llamado comerciante) e ir al menú "Perfil" para encontrar lo que buscas.
  • Preferencias de notificación de pago instantánea (IPN)
  • Configuración de pago codificado

1. Preferencias de notificación de pago instantánea IPN

En la primera opción tienes que indicar la url a la que se notifica el pago mediante petición POST. Esto quiere decir que cuando el pago se confirma, desde paypal se hará una solicitud a esa url que pongas, e incluirá además de una copia de los valores en la petición que mandamos desde nuestra web (desde el navegador del usuario) algunos parámetros más como el identificador de operación, que es el que a ti te interesa. ¿Problemas con el IPN? Se pueden deber a varios factores:

  • El pago no se confirma: Esto ocurre con cantidades elevadas, paypal desde hace poco está obligado a retener las cantidades elevadas (no recuerdo ahora el intervalo exacto) y las contrasta. Tu tendrás que acceder a tu cuenta de paypal (del sandbox) y confirmar el pago manualmente. Probablemente ya te habrá caducado la sesión, y tendrás que tirarte un rato logeandote de nuevo, pero de tanto hacerlo, tienes la contraseña grabada a fuego en tu cerebro... ¿verdad? :P
  • La url de respuesta no es correcta: Claro suele pasar... cámbiala

2. Configuración de pago codificado

En la segunda opción, configuras el certificado que vas a usar para "firmar un botón". Esta impresionante acción, como todas, al final no es para tanto y no es más que tomar una cadena con la información del pago, firmarla, y añadir el texto de la firma (...en PEM) a un formulario que se dirija a Paypal y que los navegantes presionan en tu página cuando quieren realizar el pago. Y con esto pues ya está, ahora:
  • Te descargas El SDK para java, descomprimes e incluyes las librerías en tu aplicación en /WEB-INF/lib
  • Descárgate todos los jars de las librerías criptográficas bouncycastle latest releases e incluyes las librerías en tu aplicación en /WEB-INF/lib
  • Creas tus certificados para firmar e identificarte con paypal: Para esto necesitas instalar OpenSSL (en ubuntu con "sudo apt-get install openssl"... en windows... no lo sé...) y ejecutar:

    #Generas la clave privada, el CSR
    openssl genrsa -out prvkey.pem 1024
    #La auto firmas y obtienes un certificado público
    openssl req -new -key prvkey.pem -x509 -days 365 -out pubcert.pem
    #Generas un almacen de certificados pkcs12 con ellos
    openssl pkcs12 -export -inkey prvkey.pem -in pubcert.pem -out prvkey.p12


    Después de todo esto te aparecen un montón de ficheros de los cuales solo te hace falta el almacén de certificados prvkey.p12 y el certificado de paypal que debes descargarlo desde paypal en la opción de "Configuración de pago codificado".

Pues nada, ten a buen recaudo la contraseña para el acceso al almacen de certificados y el archivo p12 por que ahora viene cuando se usa.

Realización del pago, datos del pago y firma

Bueno pues ya estás en tu aplicación y estás desarrollando la parte en la que se realiza el pago, entonces, tu objetivo va a ser crear una página donde se indique al cliente lo que va a pagar y se muestre un botón que ponga "Pagar con Paypal". El código HTML del formulario lo pones tú, pero asegúrate de que tienes dos campos:

<input type="hidden" name="cmd" value="_s-xclick" />
<input type="hidden" name="encrypted" value="<%= signedPaymentStr %>" />


que se envían a la url que te pasan desde paypal (algo de documentación tendrás que leer).

Los datos del pago van en la cadena firmada del campo encrypted, y básicamente tendrás que rellenarlos creando una cadena con algunos parámetros. Aquí os dejo el código de un metodito que devuelve directamente la cadena que buscamos. Cópialo, pégalo y míra el Javadoc, te resultará fácil. Ten en cuenta que el pago está configurado para EUROS!!...



import com.paypal.wpstoolkit.util.PPCrypto;
import java.util.Properties;
import org.apache.log4j.Logger;

.....
.....



/**
*
* Obtiene la cadena del botón encriptada para una compra. Una cadena de
* ejemplo sería:
*
* cert_id=...
* cmd=_xclick
* business=....
* item_name=Lorem Ipsum Dolor sit amet...
* item_number=1234
* custom=sc-id-789
* amount=500.00
* currency_code=EUR
* tax=41.25
* shipping=20.00
* address_override=1
* address1=Calle inventada
* city=Ciudad
* state=Estado
* zip=23452345
* country=ES
* no_note=1
* cancel_return=http://url.de.retorno
* @param paymentData Variables adicionales que se quieran adjuntar.
* @param concepto Descripción de concepto por el que se va a pagar.
* @param codigoVenta Identificador de la venta
* @param cantidad Cantidad en euros que se va a cobrar
* @param impuesto Cantidad que se va a cobrar de impuestos
* @param direccion Dirección del pagador
* @param numero numero de la direccion postal
* @param cp Codigo postal
* @param localidad Localidad de la dirección postal
* @param pais País de la dirección postal
* @param nombre Nombre del pagador
* @param apellidos Apellidos del pagador
* @param pruebas Booleano que indica si se dirigirá al entorno de pruebas o no
* @return cadena de la firma de los datos.
* @throws Exception
*/
public String getButtonEncryptionValue(String paymentData,
String concepto, String codigoVenta, Float cantidad, Float impuesto,
String direccion, String numero, String piso, String puerta,
String cp, String localidad, String pais, String nombre,
String apellidos, String email, Boolean pruebas) throws Exception {

Properties oProps = new Properties();
ClassLoader oCL = Thread.currentThread().getContextClassLoader();

InputStream oIStr = oCL.
getResourceAsStream("archivodeconfiguracionenclasspathquesiempreexiste.properties");
oProperties.load(oIStr);
oIStr.close();

String env = ".sandbox";
if (!pruebas) {
env = "";
}

String signedStr = null;

String _keyPass = "password_que_tienes_que_poner_bien";
String user = "userquetienesqueponerbien";
String certId = oProps.getProperty("propiedad_con_el_valor_que_te_da_paypal_al_registrarte");
String returnURL = oProps.getProperty("propiedad_url_de_vuelta_en_navegador_despues_de_pagar");
String returnCURL = oProps.getProperty("propieda_de_la_url_si_cancela_el_pago");
if (piso == null) {
piso = "";
}
if (puerta == null) {
puerta = "";
}
if (_data == null) {
_data = "";
}
if (numero != null && numero.length() > 0) {
direccion += " nº " + numero;
}
if (piso != null && piso.length() > 0) {
direccion += " - " + piso + "º";
}
if (puerta != null && puerta.length() > 0) {
direccion += " " + puerta;
}

paymentData += "cert_id=" + certId + ","
+"item_name=" + concepto.replaceAll(",", "") + ","
+"item_number=" + codigoVenta + ","
+"amount=" + String.format("%1.2f", cantidad).replaceAll(",", ".") + ","
+"tax=" + String.format("%1.2f", impuesto).replaceAll(",", ".") + ","
+"address_override=1,"
+"address1=" + direccion.replaceAll(",", "") + ","
+"city=" + localidad + ","
+"zip=" + cp + ","
+"country=" + pais + ","
+"first_name=" + nombre + ","
+"last_name=" + apellidos + ","
+"payer_email=" + email + ","
+"cmd=_xclick,"
+"business=" + user + ","
+"currency_code=EUR,"
+"lc=" + pais + ","
+"cbt=Volver a la página,"
+"return=" + returnURL + ","
+"cancel_return=" + returnCURL + "";

logger.info("Encoding data: " + paymentData);

paymentData = paymentData.replace(',', '\n');
try {
signedStr = new String(PPCrypto.getButtonEncryptionValue(paymentData.getBytes("UTF-8"),
oProps.getProperty("ruta_al_archivo_p12"),
oProps.getProperty("ruta_al_certificado_de_paypal"),
_keyPass));
} catch (Exception ex) {
logger.error("Excepcion firmando: " + ex.getMessage());
}
return signedStr;
}

domingo, 6 de junio de 2010

El usuario de una petición WS con Axis y WSS4J

Hace tiempo que andaba buscando la manera de obtener las credenciales de identificación enviadas en una petición a un Web Service.

El problema viene dado por la necesidad de asegurar el acceso a los métodos que se ofrecen por XML-RPC y posteriormente en su implementación, identificar al usuario, pero resulta que Axis 1.4 (en su configuración más.. cómoda), realiza el despliegue de un servicio a partir de un POJO especificado en el wsdd, y entonces ¿Como podemos hacer referencia al contexto del mensaje recibido?

Pues todo viene a partir de la clase MessageContext de Axis. En cualquier momento de una petición, está disponible la llamada a dicho objeto, y a su método estático getCurrentContext mediante el cual tendremos acceso al mensaje objeto de la petición realizada.

La identificación del usuario ya se realiza por parte de WSS4J, y ahora nosotros queremos asociar los datos enviados al usuario que se identificó, de forma que en estos POJO's podremos escribir el siguiente código:


String username = null;
Iterator<SOAPHeaderElement> oItHeaderEnv = MessageContext.
        getCurrentContext().getMessage().getSOAPHeader().
        examineAllHeaderElements();
while (oItHeaderEnv.hasNext()) {
    Iterator<MessageElement> oItHeaderElems = oItHeaderEnv.next().
         getChildElements();
    while (oItHeaderElems.hasNext()) {
        Iterator<MessageElement> oItParams = oItHeaderElems.next().
            getChildElements();
        while (oItParams.hasNext()) {
            MessageElement oWSSParam = oItParams.next();
            if("Username".equals(oWSSParam.getName())) {
                username = oWSSParam.getValue().trim();
                break;
            }
        }
    }
}


Este código nos permitirá acceder al nombre de usuario enviado, o a cualquier otro parámetro enviado en la cabecera Security.

Otra de las opciónes, es la implementación de sesiones de Axis, ya que en la misma PasswordCallbackClass del Handler de WSS4J, podríamos implementar el inicio de la sesión, y después recuperarla en el método ofrecido por XML-RPC, previa configuración del manejador de sesiones de Axis en el wsdd.

viernes, 4 de junio de 2010

Tendencias musicales

Estoy harto de tener que explicar que tipo de música me gusta. Por eso normalmente digo que me gusta "el heavy" porque, ¿Cómo le explicas a alguien que es para mí la buena música?. Para mí la buena música es tantas cosas que no sé...

Ciertamente me gustan las guitarras, me gusta la distorsión y he escuchado mucho "heavy", desde Pantera, a Soziedad Alkoholica, pasando por Narco, Koma o System of a Down y como no, Metallica, Iron Maiden, Helloween...

Y también me gusta el blues, mucho blues, como la primera banda con la que empecé a tocar, y también me gusta Triana, uno de los mejores grupos de rock andaluz, que se acercan al rock progresivo en algunos de sus temas, y ahí es cuando viene la sorpresa. ¿Como le explicas a alguien que te gusta el rock progresivo? ¿Cómo llega a gustarte?

Creo que para eso hay que escuchar mucha música y no a las locas, empezando por el blues de los 60, y llegar al rock (y blues) de Cream, de Jimi Hendrix, y de Led Zeppelin. Es extraño que hoy en día pocos recuerden temas como No quarter de Led Zeppelin... para la mayoría, acaban en Stairway To Heaven.



Tengo la sensación de que hoy en día la gente cree que escuchar mucha música consiste en escuchar todos los grupos nuevos que sacan "más de lo mismo", letras de amor (que pesadilla), techno, modas retro, rap... ¿Y de que te saca escuchar lo mismo por distintos grupos que se copian entre si? ¿Porque no vale con los originales? no se, a lo mejor me estoy haciendo mayor, pero tengo la sensación de que ese tipo de personas solo pretenden mencionar un grupo que no conoces para que parezca que saben más de música. Y luego resulta que no han escuchado a Leño, a Rosendo, a Los Suaves o a Barricada... pero si no conoces a los que imitan el estilo de Platero y tu, o Extremoduro, no sabes de música ¿Pero son mejores? ¿Es que aportan algo más?

¿Quieren escuchar algo realmente bueno y que nadie conoce? pues que tengan criterio, conozcan los instrumentos, y entonces podrán valorar. Porque cuando ves los conciertos de Radio 3 con cuatro mindundis vestidos de retros y haciendo tonterias con un moog, y un batería que parece un albañil, pues me da la risa. Si John Bonham levantara la cabeza... ¿Realmente saben lo que hacen? Antes hay que demostrar que eres bueno, para saber expresarte, y poder hacer algo tan fantástico como esto:



Esto es el rock sinfónico, y progresivo. Y ¿Cómo explico que me encanta el solo de batería de In-A-Gadda-Da-Vida? pues esto es lo que no puedo explicar cuando me preguntan por mis gustos musicales. Y ¿Como explico que también me gusta El Ultimo de la Fila o U2 u O'funk'illo?

Y lo más gracioso es la tendencia a creer que el rock siempre es estridente. Me gustan las guitarras así, pero también las que no lo son, como las de Fito y Fitipaldis o dentro del rock progresivo cosas como esta:



Y esque claro, se suele decir que el rock no vende, aunque el segundo disco más vendido de la historia sea de AC/DC, y poco despues uno de Meatloaf. Pero claro el rock según algunos listos, está muerto, y yo les digo... toma esto:



Por cierto, nos vemos en Córdoba en el concierto de Deep Purple, o el de Joe Bonamassa, o en Sevilla en el concierto de AC/DC!!!!

Crisis

Politicos ineptos, que solo piensan en su ombligo, que solo saben quedar bien. Y para eso enchufan a los que pueden y viven como reyes, y nos piden que les ayudemos.

Y ahora, después de que hace algún tiempo "inyectaran" dinero a los bancos, nos piden que trabajemos más, más barato, y con más facilidad para echarnos. ¿Así se arregla? Menudos "Robin Hood" a la inversa, tiene delito robarle a los pobres para pagar a los ricos.

Y nos machacan a impuestos para pagar excesos y subvenciones a quienes no colaboran con la sociedad. Pues a los que no colaboran con la sociedad, la sociedad no debería colaborar con ellos.

Y muchos nos preguntamos porqué las mejores mentes, como notarios, médicos, e ingenieros que aprueban unas oposiciones imposibles, están dirigidas por unos ineptos, sin cultura, que no han demostrado nada acerca de su aptitud para el puesto de dirigente político. ¿No debería un alcalde, un concejal y ya no digamos un ministro demostrar su valía para el puesto? Así lo hacen las mejores mentes de este país en empresa privada y pública, demostrarlo día a día, y claro... así nos vá.

Y los sindicatos... bueno... no me quiero enfadar ahora, pero.. hay que cambiar el sistema como sea. ¿Que alternativas tenemos? Ya no es tiempo de revoluciones sangrientas, y la ley electoral impide votar libremente, a las personas, no a los partidos, y además se aseguran la perpetuidad.

Nos han quitado el poder, y ahora, el espabilado del hijo de la vecina, ese tontaina que se creía superior, y que lo más cercano a la lectura que conoce es el Marca, está dirigiendo tu ciudad, y tu país, porque ha estado de fiesta con los peces gordos de su partido.

Lo malo es que las buenas personas no se meten a políticos ni a sindicalistas. Las buenas personas trabajan, todos los días, con gana y con ánimo de hacer algo, de progresar y de conseguir por su propio esfuerzo vivir en un mundo mejor cada día y los políticos no, solo en contentar a sectores de población que les voten, y seguir como cabestros los designios del partido. Ni tienen personalidad ni quieren tenerla, porque si llevan la contraria, se les echa. Es extraño que se destroce la carrera de un político que piensa por si mismo, y se defienda a políticos corruptos.

Pues así pasan estas cosas, ahora a remediarlo como siempre, incrementando desigualdades y apretando las tuercas más todavía, hasta que no podamos más. Pero, ¿Que vamos a hacer? ¿Que podemos hacer? Sinceramente, ya no se me ocurre nada.

viernes, 25 de septiembre de 2009

Las nuevas tecnologías

La comunicación de texto, imágenes y vídeo de forma fácil y rápida, permite que una empresa local de pequeño tamaño sea vista desde el otro lado del planeta, o que escuchemos a grupos musicales de cualquier lugar, algo impensable hace algunas décadas de forma tan sencilla. Pero además permite a cualquier ciudadano opinar, y escribir sus vivencias y ponerlas a disposición de todo el mundo. Esto es la verdadera revolución de internet. Las fronteras han caído en lo que respecta a cualquier ámbito de la vida, económico, social o político.

El concepto (ya casi obsoleto) de Web 2.0 centra sus directrices en una web más clara, más ligera y más interactiva, que son las claves para conseguir una innovación real a parte de las buenas ideas que despierten la curiosidad del navegante, y por ello debería seguir vigente y tenido en cuenta. Una buena idea sin el respaldo de una buena navegabilidad, y velocidad de respuesta, no tiene cabida hoy en día. El triunfo de Google, aunque no pasa por respetar demasiados estandares, si corrobora que sus diseños simples, son de gran utilidad, y así facebook etc, etc. Este mismo blog, tampoco lo hará (imagino), pero es algo que siempre pretendo tener en cuenta en mis proyectos.

Y en base a estas directrices es en las que hay que seguir trabajando. Los estándares del W3C son claves para el éxito de una web, pese a que "los grandes" no los respeten, o no los tengan en cuenta en sus barómetros, todos deberíamos ser más exigentes respecto a ello. Llevar a cabo un proyecto cuidando estos factores es una clave en la recurrencia de las visitas

Hoy en día no es dificil encontrar webs con una saturación de contenidos en cada página que se visita, y carecen de un menú completo y descriptivo. En ese sentido deberíamos educar a los clientes, a las personas a las que realizamos la consultoría. ¿o no?