IntelliJ 11 Subversion Problems - Maybe Solved

Ever since upgrading to IntelliJ 11 a couple of days ago I've been having issues with Subversion. It's a big multimodule maven project, and a full "svn update" can take of the order of 10 minutes or more.

I found that IntelliJ would take a rather long time, sometimes forever (ie it was actually time to go home and stop work before IntelliJ caught up). It would always say "updating...":

Screen_shot_2011-12-09_at_12

I could change files and they would not show up as changed (neither could I revert them). Or I could check in changed files and they'd still show as changed in the changes view.

Finally, after trawling the IntelliJ bug tracker I found hints of related problems from earlier version. Nothing clear to go on, but some suggestions of some metadata being mismatched between svnkit and the svn command line.

Up till now I'd been updating from the command line, then launching IntelliJ. Just habit really. So I decided to do a full update from within IntelliJ, and with a depth of infinity for good measure.

Once this had finished, everything was hunky dory - updates are now reflected instantly. I shall keep updating within IntelliJ only for now to see if this sticks.

So I'll carry on with IntelliJ 11. Next up: why can't I jump from the source editor to the source file in the Favorites view any more? 

 

 

 

OAuth 2.0, Java & Facebook, Part 1

OAuth 2.0

Recently I've been working on a simple Facebook app called SyncitySync, which updates your Facebook status with your tweets. One of the fiddlier bits of work involved authorising the app with Facebook in order to make offline updates to the user's status. In theory OAuth 2.0 is straightforward, but Facebook adds its own wrinkles, particularly when using an iframe.

Here's a quick overview of the OAuth 2.0 web flow:
  1. The client (eg our app) redirects the user to an authorisation server.
  2. The user authenticates themselves with the authorisation server.
  3. The authorisation server sends back a verification code.
  4. The client requests an access token using the verification code and its own credentials.
  5. The authorisation server sends back an access token, assuming all is well.
  6. The access token can then be used by the client.
There's a helpful page in the Facebook Developer Docs which describes this in terms of a typical Facebook app. If you haven't already read this, please read it first! Here are some implementation notes gathered while doing this in practice. As discussed before, all this is written in Java, using Spring MVC with annotations, hosted on Google App Engine.

Configuring Facebook

I'm going to assume you have already created an app record in Facebook, complete with client id and secret etc. Now we need to configure the settings for our app in Facebook. We set the following settings under "Facebook Integration":

Syncitysync_facebook_settings

We also enable OAuth 2.0 under "Advanced":

Syncitysync_facebook_oauth_set

Pre-Authorised Users

The first thing to do is to check that the user has already authorised your app. This is quite straightforward to do in a controller:

                final String encryptedSignedRequest = request.getParameter("signed_request");

                if (!StringUtils.isEmpty(encryptedSignedRequest)) {

                        final String decryptedSignedRequest = FacebookUtil.validateSignature(encryptedSignedRequest,

                                        facebookConfiguration.getClientSecret());

                        Gson gson = new Gson();

                        final LoggedInUser user = gson.fromJson(decryptedSignedRequest, LoggedInUser.class);

                        if (user.getUser_id() != null && user.getUser_id() != 0L) {

                                request.getSession().setAttribute(SessionAttributes.LOGGED_IN_USER, user);

                                return "redirect:register.do";

                        }

                }

                return "facebookLogin"; 

Here I extract the signed_request parameter, and decrypt it (see below) into a JSON object called LoggedInUser using Gson. LoggedInUser is simply a representation of the signed_request as per the Canvas OAuth docs. In particular, we check for the existence of the user_id property. This will be null unless the user has already authorised the app.

If the user is already authorised, we redirect to the registration form (register.do). Otherwise we redirect to the authorisation server in order to get the verification code. Well, that would be the case if you weren't using an iframe.

FacebookUtil.validateSignature is a simple library method that validates a signed_request and decrypts it if valid.

                String[] parts = signed_request.split("\\.");

                String encSig = parts[0];

                String encPayload = parts[1];

                Base64 decoder = new Base64(true);

                String data = new String(decoder.decode(encPayload));

                try {

                        Mac mac = Mac.getInstance("HMACSHA256");

                        mac.init(new SecretKeySpec(appSecret.getBytes(), mac.getAlgorithm()));

                        byte[] calcSig = mac.doFinal(encPayload.getBytes());

                        if (Arrays.equals(decoder.decode(encSig), calcSig)) {

                           return data;

                        } else {

                            return null;

                        }

                 } catch (InvalidKeyException e) {

                     throw new Exception("Failed to perform crypt operation.", e); 

                 }

I originally found this in a helpful discussion by Gennady Shumakher, but here's another example.

In theory one can redirect the user immediately to https://graph.facebook.com/oauth/authorize at this point in the controller. However, for an iframe this will not work. You will end up with Facebook within Facebook (i.e. your iframe will contain the whole facebook surround plus your app, not just your app) and other weirdness. This caused some head scratching but I eventually found this discussion

What you have to do is redirect to a page containing some javascript which will then do the redirection - where it says "facebookLogin" in the controller code above, it takes us to a jsp which contains only this javascript:

A quick word about the parameters here. The scope declares that the permissions sought will be to update the user's stream, and to be able to do so after the user has logged out. We need these to be able to update the user's status in Facebook from Twitter while they are not logged into the former. Without the scope, the app's permissions will lapse after a short time.

The redirect_uri will be called upon successful authorisation, and is the subject of Part 2.

Pottering, pottering

I've been taking some time off to look after our new arrival, Griffin. Actually, most of my time is taken up with our old arrival, Morgan, who is something of a handful.

Anyway, the coding part of my brain is starting to itch, so I've started mucking about with Facebook and Twitter applications. One persistent minor annoyance I find is that I can never get Facebook to update my status from Twitter in a reliable or timely fashion. There are plenty of options out there to be sure, but none of them seem quite right. The official Twitter app for Facebook won't update my status, it will only post on the wall. Selective Tweets will update my status, but only if I include a special hashtag. Kipdola Sync works well enough, but I have problems stopping it posting everything, including replies and retweets. I just want my tweets, no replies, retweets etc. to update my status.

Of course, the real reason I'm doing this is to keep writing code.

I've chosen a basic set of technologies to use here. I'm going to take a leap of faith and use the Google App Engine to host this app. I know there are a number of problems with GAE, but it seems like it would be a good fit for prototyping a small app like this.

I'm going to stick with Java for this. I've never been a big fan of Python, and I don't have enough free time to start learning right now.

I'm also going to try using Spring Social.

I'll try to keep this blog updated with my progress. I've never used OAuth before, so I imagine there'll be lots of fun to be had along the way.

James Shore: Alternatives to Acceptance Testing

Instead, I have the customers illustrate their descriptions with concrete examples. I'll say, "Okay, so we have a customer named Fred, and he's paying with a credit card. He buys a ring-tone that costs fifty cents. He's already purchased 12 dollars of merchandise this month. How much do we charge his card for?" Once the dam has broken, the customers are able to provide additional examples in the same vein, and we keep going until we have examples for all of the edge cases we need.

Excellent article on agile testing practices. Although I'm fond of Fitnesse, Selenium and jBehave in particular, I usually run into the exact problems James mentioned previously: I can't get the customer to come anywhere near such tools, and I always find they need considerable coding effort that consequently doesn't pay off. James' description of "customer examples" is spot on.