OAuth and Desktop Apps

I started to develop QuickHub some weeks ago by focusing on features and without taking into account security issues such as this critical information which are login and password credentials… As mentioned in the GitHub developer pages, I started to use Basic Auth for all the requests QuickHub does to get retrieve data from GitHub. I started to think about moving to OAuth when a user said me that he bought QuickHub but that he did not use it because of Basic Auth. He was afraid that I can rob its credentials and so have a look to its repositories and more. I totally understand this argument and so I started to think that it limits QuickHub adoption by developers and that I should do something.

So, I discussed with GitHub guys through their support channel (Here I want to say that I am really impressed on how fast and professional is the GitHub support team!). Of course, they also told me that they will never use QuickHub if OAuth is not provided. After discussions with the guys, I started to implement a workaround to provide OAuth support in QuickHub by using the OAuth Web flow and adding some stuff to QuickHub.

Let’s see how we can do that in a generic way so that you can use it in your app if needed since every serious Internet service also provide OAuth support… Note that I will not give many details about OAuth itself but I will use some terms, so have a look to OAuth documentation for more details.

Register a Web application

The first step is to register your application to the developer portal. Here you need to provide some information such as the app name and its callback URL. Even if we are developing a desktop app and not a Web one, we need to be able to provide this HTTP based callback URL. We will see in the next section what is inside this application. By registering our application, the service will generate and give us some keys to be used in the next steps, mostly to recognize us when calling the service.

Create a Web application

We need a Web application to handle callback calls from the service we want to use OAuth. This application will only be used at authorization time and just have to be able to receive the service call, get the code sent by the service, then call the service again with the code and our application keys (there is a secret one to be used here). As a result, the service will send you back your OAuth token to be used in all the future service calls. This token is used to authenticate your service calls, no more password stuff inside! Here is a quick sequence diagram showing all the exchanges between actors…

On the QuickHub side, I chose to create this Web application by using the Play Framework I already mentioned several times in this blog. I used the Heroku paas to provide the Web application publicly.

As showed in this Gist (https://gist.github.com/1466592), the callback method is really simple (as usual with Play!): just get the code and call GitHub with it and your application keys. When all lis done, just display a result page with a specific URL. Here it starts with ‘quickhubapp://oauth?’. Let’s see what it means in the next section…

Add custom URL handlers to your desktop app

Once the desktop application is authorized, our Web application redirects the user to a Web page which embeds a button targeting an URL starting by ‘quickhubapp://oauth?’. Here you already understand that by clicking on such a link must drive you to something special. The cocoa framework allows developers to register specific URL handlers for their applications. So we need to register QuickHub handlers so that OS X knows that every link  with the quickhubapp scheme must me routed to QuickHub. This is as easy as showed in this Gist https://gist.github.com/1466628.

This code snippet just tells QuickHub to invoke the getUrl method when it receives a quickhubapp event. Up to the getUrl method to handle things. In QuickHub, I just extract the OAuth token in order to persist it locally for future use.

Done!

So now we are able to use OAuth Web flows for desktop applications. In the best of the worlds, every service provider may provide a real desktop flow to be used without the need to create this additional web application. In the real world, it is not the case but as you see it can be bypassed quite easily.

I will provide more technical details on the second section ‘Create a Web application’ with real sample and code in the next weeks.

Testing Play! and WebSockets

I spent one hour playing with the [Play Framework](http://playframework.org) and WebSockets in order to push some (SOAP) messages received on some Web services hosted by the Play application to the clients browser.

The result is really amazing: We can simply push these SOAP messages to clients in less than 100 lines of code. There are some problems with some messages lost due to some conception problems but which are not Play ones. In fact, the current prototype just send the messages to all the clients but what should be done is creating streams per client with some ID to identify them…

The source code is available on GitHub at [https://github.com/chamerling/play-soap-websockets](https://github.com/chamerling/play-soap-websockets)

A quick screen capture with SOAPUI sending messages to the Play! SOAP service. The Play application pushes the SOAP message to the clients (Two browsers).

Jouons avec WebServiceProvider…

Il y a des jours où exposer ses classes annotés avec @WebService n’est pas satisfaisant…
Pour moi ce jour c’est aujourd’hui: Il m’est impossible de marshaller mes beans en document DOM à cause d’un contexte JAXB tordu et d’une API qui ne prend que du DOM en entrée (OK bon ça c’est nul mais c’est pas de moi…). Qu’a cela ne tienne, il est temps d’utiliser les WebServiceProvider puisque ils vont me permettre de directement récupérer mon message SOAP sous forme de document… Un peu moins straight forward comme approche mais qui peut convenir dans certains cas. Comme les exemples ne courent pas le Web, regardons ce que l’on peut faire pour s’en sortir…

(Tout le code source de cet article est disponible sur Github : http://github.com/chamerling/chamerling.org-samples/tree/master/cxf-serviceprovider-072011)

Une première solution simple est d’implémenter javax.xml.ws.Provider, de rajouter deux/trois annotations et le tour est quasiment joué:

package org.chamerling.blog.cxf.serviceprovider;

import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Provider;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;

/**
* @author chamerling
*
*/
@WebServiceProvider
@ServiceMode(value = javax.xml.ws.Service.Mode.MESSAGE)
public class SimpleServiceProvider implements Provider {

/*
* (non-Javadoc)
*
* @see javax.xml.ws.Provider#invoke(java.lang.Object)
*/
@Override
public SOAPMessage invoke(SOAPMessage in) {
return null;
}
}

Reste à l’exposer avec CXF en utilisant org.apache.cxf.jaxws.JaxWsServerFactoryBean. Cette approche simpliste a le mérite de marcher, il ne reste plus qu’a manipuler les SOAPMessage dans l’implémentation de la méthode invoke.

Besoin de l’opération qui est appelée? Ajoutons javax.xml.ws.WebServiceContext en tant que javax.annotation.Resource. Ce contexte sera automatiquement rempli pour nous par CXF et accessible dans le corps de la méthode invoke. Par exemple, on peut travailler de la sorte:

/**
 *
 */
package org.chamerling.blog.cxf.serviceprovider;

import javax.annotation.Resource;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Provider;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.WebServiceProvider;
import javax.xml.ws.handler.MessageContext;

/**
 * @author chamerling
 *
 */
@WebServiceProvider
@ServiceMode(value = javax.xml.ws.Service.Mode.MESSAGE)
public class SimpleServiceProvider implements Provider {

	@Resource
	WebServiceContext wsContext;

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.xml.ws.Provider#invoke(java.lang.Object)
	 */
	@Override
	public SOAPMessage invoke(SOAPMessage in) {
		System.out.println("Operation : " + getOperation());
		System.out.println("Message In :");
		try {
			in.writeTo(System.out);
		} catch (Exception e) {
			// bad
		}
		System.out.println();
		return null;
	}

	private QName getOperation() {
		QName result = null;
		if (wsContext != null && wsContext.getMessageContext() != null) {
			Object o = wsContext.getMessageContext().get(
					MessageContext.WSDL_OPERATION);
			if (o != null && o instanceof QName) {
				result = (QName) o;
			}
		}
		return result;
	}
}

Et invoquer le service:

package org.chamerling.blog.cxf.serviceprovider;

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

import junit.framework.TestCase;

/**
 * @author chamerling
 *
 */
public class SimpleServiceTest extends TestCase {

	public void testExpose() throws Exception {
		String url = "http://localhost:9999/foo/bar/SimpleService";
		final JaxWsServerFactoryBean ssf = new JaxWsServerFactoryBean();
		ssf.setAddress(url);
		ssf.setServiceBean(new SimpleServiceProvider());
		ssf.create();

		HelloService client = getClient(url);
		client.sayHello("Rock N Roll!");
	}

	/**
	 * @param url
	 * @return
	 */
	private HelloService getClient(String url) {
		JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
		factory.setAddress(url);
		factory.setServiceClass(HelloService.class);
		Object client = factory.create();
		return HelloService.class.cast(client);
	}
}

Dans ce cas, on a une opération affichée qui est {http://serviceprovider.cxf.blog.chamerling.org/}invoke et le message SOAP

Rock N Roll!

Pas très convaincant pour l’opération avec cette approche… Le mieux est de pousser un peu plus loin et partir du contrat de service (WSDL) de notre Provider. CXF permet de le spécifier via ses factories lors de la construction du service. Cette utilisation plus avancée est détaillée en partant de org.chamerling.blog.cxf.serviceprovider.CXFExposer. L’approche utilisée dans CXFExposer permet aussi de cacher toute la tambouille JAXWS à l’utilisateur, au final il a besoin d’implementer seulement org.chamerling.blog.cxf.serviceprovider.Service

package org.chamerling.blog.cxf.serviceprovider;

import javax.xml.namespace.QName;

import org.w3c.dom.Document;

/**
 * @author chamerling
 *
 */
public interface Service {

    /**
     * Get the WSDL description
     *
     * @return
     */
    String getWSDLURL();

    /**
     * Get the service URL ie where to publish it...
     *
     * @return
     */
    String getURL();

    QName getEndpoint();

    QName getInterface();

    QName getService();

    /**
     * Invoke the service
     *
     * @param request
     * @param action
     */
    Document invoke(Document in, QName operation) throws ServiceException;

}

Bye Bye SOAP, salut REST?!

En tout cas cela est vrai pour les API exposées sur le Web, je ne suis pas vraiment sûr que ce soit le cas en entreprise… Bref, je pense que j’avais déjà parlé de ce déclin il y a quelque temps mais je vais en reparler tout de même un petit peu.

Toujours est il que les faits sont là. Les moteurs ont beau crawler le Web à la recherche de services Web (les vrais avec un WSDL!), ils depuis un certain temps dans une phase stagnante. Pour preuve, le nombre de services trouvés par le moteur Seekda est aussi plat que la pleine Toulousaine, on devine un peu plus de 25000 Web services publics trouvés et ce chiffre est le même depuis presque 3 ans:

Source : Seekda.com

Source : Seekda.com

Il y a bien de nouveaux services découverts de temps en temps, mais bon, il me semble que c’est plus de l’ordre du prototype ou du test que d’autre chose, la preuve en image:

Oh la belle calculette...

Oh la belle calculette...

Bref, le déclin est annoncé. Pour preuve, on peut aussi regarder l’intérêt que portent les utilisateurs aux APIs SOAP et REST par le biais des tendances de recherche Google (via http://www.google.com/insights/search/#q=soap%20api%2Crest%20api&cmpt=q). Bien sûr l’internaute ne dicte pas la mort de SOAP et la percée de REST, mais il est clair que ce qui est ‘trendy’ de nos jours est bien REST :

SOAP vs REST

SOAP vs REST

Et vous dans la vrai vie, vous êtes plutôt SOAP ou REST?

Les classloaders des modules dans Axis2: Les ressources

J’ai expliqué le genre de choses intéressantes que l’on peut faire avec les modules dans la pile Apache Axis2 dans l’article sur le reroutage d’appels de services. J’ai eu besoin aujourd’hui d’aller un peu plus loin dans l’utilisation de ces modules et comme d’habitude, en utilisant ce genre de choses, je partage mes aventures… On va voir rapidement ici comment se comportent les ClassLoaders dans le cas d’Axis2 et des modules.

Et alors?

Je suis en train de développer un module qui reroute les appels de service. L’adresse du service à appeler est donc mis à jour lors de la traversée du module en question. Pour faire bête, je me suis dit que j’aller spécifier un jeu d’adresses dans un bon vieux fichier de propriétés et que j’allais mettre ce fichier dans le module. OK, c’est bien, ça marche (heureusement…), je peux charger mon fichier dans le Handler du module et utiliser les adresses qui y sont définies.

Ce qui m’embête, c’est que ce fichier est packagé dans l’archive du module et donc non modifiable à souhait… C’est là que le Classloader d’Axis2 entre en piste. Si je mets un fichier avec le même nom dans les ressources de mon code client, celui ci est pris en compte en priorité lors de l’appel par le module de MonModule.class.getResource(“/foo.properties”); Je peux donc cette fois ci livrer un module générique qui inclus des valeurs par défaut et les clients qui utilisent ce module peuvent ‘overrider’ les valeurs par défaut dans leur propre fichier de configuration.

Encore une fois, merci Axis2.

Axis2 : Rerouter vos appels de services sans modifier vote code client

Imaginons que vous ayez à votre disposition un client de Web service et que pour une raison (qui doit être bonne je l’accorde), vous avez besoin de rerouter vos appels de service vers un nouveau point d’accès. Le problème est que vous n’avez pas le droit de modifier le code client (ou que vous ne l’avez pas), que vous ne voulez pas regénérer ce code client à partir du WSDL du nouveau service a appeler (qui est exactement le même hormis l’adresse du endpoint)… Heureusement, votre client utilise la pile Web service Apache Axis2, et les développeurs d’Axis2 ont gentiment pensé à introduire des modules dans leur architecture. Une bonne intorduction aux modules est disponible dans le guide d’architecture d’Axis2.

Nous allons donc développer un module qui change dynamiquement l’URL de l’endpoint à appeler (on utilisera bien sûr Maven2 pour nous aider à créer et packager le projet…).

1. Créer le projet

Utilisons Maven2 pour créer un projet :

mvn archetype:generate

et je réponds bêtement a Maven quand il me pose des questions sur le groupId, l’artifactId, etc… Une fois créé, je génère le projet Eclipse associé et je l’importe (Eclipse fait aussi parti de mes grand amis) :

mvn eclipse:eclipse

Ill faut modifier le POM pour dire a Maven que l’on est en train de créer un projet qui n’est pas une librarie Java mais un module Axis2. Ceci est possible en spécifiant le type de projet dans le POM et en déclarant que l’on veut utiliser le plugin MAR fournit par Axis2 :


<project ...>

...

<groupId>foo.bar</groupId>
<artifactId>reroute</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>mar</packaging>

...

<dependencies>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-kernel</artifactId>
<version>1.5.1</version>
</dependency>
</dependencies>

...

<build>
<plugins>
<plugin>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-mar-maven-plugin</artifactId>
<version>1.5.1</version>
<extensions>true</extensions>
<configuration>
<moduleXmlFile>src/main/META-INF/module.xml</moduleXmlFile>
<includeDependencies>false</includeDependencies>
</configuration>
</plugin>
</plugins>
</build>
...
</project>

2. Business code

Créons maintenant notre handler (le module est en fait un handler Axis2 packagé dans une archive avec un descripteur de module). Pour faire simple, je vais étendre la classe AbstractHandler pour créer mon Handler de reroutage et remplacer le ‘target EPR’ par le nouveau (bien sûr on peut faire quelque chose de beaucoup plus évolué, on va dire qu’ici tout part vers un seul service) :

package net.chamerling.blog.axis2module.reroute;

import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.handlers.AbstractHandler;
import org.apache.axis2.util.LoggingControl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * @author chamerling
 *
 */
public class ReRouteHandler extends AbstractHandler {
	private static final Log log = LogFactory.getLog(AbstractHandler.class);

	private static final String FINAL_EPR_PREFIX = "http://localhost:8082/petals/proxy/";

	/**
	 * {@inheritDoc}
	 */
	public InvocationResponse invoke(MessageContext messageContext)
			throws AxisFault {
		EndpointReference toEPR = messageContext.getOptions().getTo();
		String finalEPR = FINAL_EPR_PREFIX + toEPR.getAddress();

		if (LoggingControl.debugLoggingAllowed && log.isDebugEnabled()) {
			log.debug("Reroute Handler for message : "
					+ messageContext.getMessageID());
			log.debug("Initial ToEPR is " + toEPR.getAddress()
					+ " and is changed to " + finalEPR);
		}

		toEPR.setAddress(finalEPR);
		return InvocationResponse.CONTINUE;
	}
}
<pre>

Avec Axis2 c’est ‘facile’, tout est dans le message context! Je viens de remplacer le service à appeler par le mien en modifiant le champ ‘address’ du ‘EndpointReference’.

3. Packager le module

Pour créer un module avec le Handler que l’on vient de définir, il faut passer par l’écriture du fichier de description du module, le ‘module.xml’. Ici c’est simple :

<module name="reroute">
	<OutFlow>
		<handler name="ReRouteHandler" class="net.chamerling.blog.axis2module.reroute.ReRouteHandler">
			<order phase="reroutePhase" />
		</handler>
	</OutFlow>
</module>
<pre>

Mon module s’appellera donc ‘reroute’ et sera appelé que lors de la phase d’émission de message ‘OutFlow’. Plus d’informations sur ce qui est possible avec ce fichier sur le site d’Axis2.

4. Configurer Axis2

Il y a plusieurs façcons de dire à Axis2 d’utiliser le module que l’on vient de développer. En se basant sur la contrainte de départ, je n’ai pas le droit de modifier mes services donc je ne peux pas modifier le descripteur de service ‘service.xml’. Heureusement, j’ai accès au serveur et je peux modifier le fichier de configuration d’Axis2 ‘axis2.xml’ :

...
<!-- Engage the reroute module -->
<module ref="reroute" />
...
<phaseOrder type="OutFlow">
	<!--      user can add his own phases to this area  -->
	<phase name="soapmonitorPhase" />
	<phase name="OperationOutPhase" />
	<!--system predefined phase-->
	<!--these phase will run irrespective of the service-->
	<phase name="PolicyDetermination" />
	<phase name="reroutePhase" />
	<phase name="MessageOut" />
	<phase name="Security" />
</phaseOrder>
<pre>

Je viens d’engager mon module pour tous les services et je l’ai aussi ajouté dans la collection de phases qui est appelé lors de l’émission d’un message. A chaque fois qu’un message est envoyé vers un service, on passe donc dans le module que l’on vient de développer. Je viens donc de modifier les services invoqués sans modifier le code client! Je reviendrais bientôt sur l’utilisation de ce genre de choses dans un vrai cas d’usage avec du REST, du SOAP, des PROXYs, de l’ESB distribué sur le Web (bien sûr avec Petals ESB), etc…

Resources

Le code de ce ‘tutoriel’ est bien sûr disponible sur mon Google Code sous http://code.google.com/p/chamerling/source/browse/#svn/trunk/blog/reroute-axis2.

PEtALS ESB Live Monitoring with WSDM and GWT

In one of my previous posts (Adding Registry Listener in PEtALS), I spoke about adding a registry listener in PEtALS ESB. In the current article, I want to introduce how I used this feature to implement a live monitoring Web application.

Here are the different modules which are used in this Live Monitoring Tool :

  1. PEtALS ESB. The standard behaviour has been customized by adding a registry listener and a routing module (to be detailled below).
  2. Monitoring layer. This layer is an independant process which embeds a WS-Notification engine.
  3. A WS-notification subscriber. This is the module which will receive the notifications from the monitoring layer.
  4. GWT based Web application used to display monitoring data.

PEtALS ESB Extensions

Registry Listener
The role of the registry listener is to register a new monitoring endpoint into the monitoring layer when a new endpoint is available within PEtALS.

Routing Module
Since modules can be added dynamically inside the PEtALS message router, we have created a module which timestamp the messages. Once the message exchange is complete, a message exchange report is sent to the monitoring layer.

Monitoring Layer

The monitoring is in charge of creating monitoring endpoints through a management API. Once a monitoring endpoint is created, it is also exposed as a Web service. This newly created Web service exposes a WS-notification subscribe operation.
Another role of the monitoring layer is to receive raw reports from the PEtALS ESB, to process the report in order to generate a WSDM payload which will be send to subscribers.

WS-Notification subscriber

The subscriber subscribes, receives and stores notifications from the Monitoring layer. That’s all for that module ;o)

GWT Based Web application

The GWT Web application uses comet in order to display live service response time. The data used to display response time is the one received and stored into the database and of course the server part of the Web application have access to this database.

As a result, we have a really nice live Web application (live means that the chart gives real time result and is updated automatically when messages are exchanged within PEtALS Service Bus). Here are some screenshots :

Live Response Time

Live Response Time

SLA

SLA Violation

Setting timeout on generated JAXWS CXF Clients

When generating client with the CXF (2.2.2 in this case, should apply to all…) Java API without any configuration file, here is the way to set the client timeout :

package org.ow2.petals.kernel.ws.client;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.ow2.petals.kernel.ws.api.RuntimeService;

public class Main {

    private void createService() {
        long timeout = 10000L;
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(RuntimeService.class);
        factory.setAddress("http://localhost:9999/service/Runtime");
        RuntimeService runtimeService = (RuntimeService) factory.create();

        Client client = ClientProxy.getClient(runtimeService);
        if (client != null) {
            HTTPConduit conduit = (HTTPConduit) client.getConduit();
            HTTPClientPolicy policy = new HTTPClientPolicy();
            policy.setConnectionTimeout(timeout);
            policy.setReceiveTimeout(timeout);
            conduit.setClient(policy);
        }
    }
}

Note that here the RuntimeService class is my JAXWS annotated class.

EasyWSDL 1.3 is out

One more new release of OW2-EasyWSDL, the WSDL manipulation library.

The EasyWSDL team is pleased to announce the release of EasyWSDL 1.3
You can download it from: http://forge.ow2.org/project/showfiles.php?group_id=334&release_id=3454
Available in this version :

  • Fix some bugs
  • Improve import/include management
  • Use URL instead of URI in WSDL reader
  • Add SimpleContent tag management
  • Change artifact name (More maven compliant…)

More information is available on EasyWSDL website: http://easywsdl.ow2.org/

EasyWSDL 1.2 is out

OW2 EasyWSDL WSDL manipulation library has just been released. This release fix many bugs and introduces some new tooling such as java2wsdl (create WSDL from Java interfaces) and xsd2xml (create XML from XSD definition).

EasyWSDL is easy since you can manipulate both WSDL 1.1 and WSDL 2.0 with the same object model.

// Read a WSDL 1.1 or 2.0
WSDLReader reader = WSDLFactory.newInstance().newWSDLReader();
Description desc = reader.readWSDL(new URI("http://file/path/document.wsdl"));

// Write a WSDL 1.1 or 2.0 (depend of desc version)
Document doc = WSDLFactory.newInstance().newWSDLWriter().getDocument(desc);

// Create a WSDL 1.1 or 2.0
Description desc11 = WSDLFactory.newInstance().newDescription(WSDLVersionConstants.WSDL11);
Description desc20 = WSDLFactory.newInstance().newDescription(WSDLVersionConstants.WSDL20);

Once the Description object is loaded from the WSDL document, you can maniulate all parts of the service description. Let’s look at endpoints :
// Endpoints take place in services.
// Select a service
Service service = desc.getServices().get(0);

// List endpoints
List endpoints = service.getEndpoints();

// Read specific endpoint
Endpoint specificEndpoint = service.getEndpoint("endpointName");

// Add endpoint to service
service.addEndpoint(specificEndpoint);

// Remove a specific enpoint
service.removeEndpoint("endpointName");

// Create endpoint
Endpoint createdEndpoint = service.createEndpoint();
service.addEndpoint(createdEndpoint);

Easy!

Mises à jour Twitter