Groovy, Twitter, and Basic Authentication

The other day, Scott Davis published an article at developerWorks entitled Practically Groovy:  SwingBuilder and the Twitter API, Part 2.  I’m sure you won’t be surprised to hear that it’s a good article.  No surprise there, given Scott’s excellent reputation and abilities.

As it turned out, though, I was teaching a Java Web Security class when the article came out and we’d already discussed mechanisms for doing authentication.  In the article, Scott pointed out that while Twitter prefers OAuth authentication (see here for details), they allow for HTTP Basic authentication.

Scott wrote a nice Groovy GUI client, based on Groovy’s excellent SwingBuilder.  The authentication part looked like this:
[sourcecode language=”groovy”]
def authString = "username:password".getBytes().encodeBase64().toString()
def conn = addr.toURL().openConnection()
conn.setRequestProperty("Authorization", "Basic ${authString}")
The process starts with a username and a password and concatenates them together with a colon in the middle. Then you convert the result into a byte array by calling getBytes(). Then, as you can see from the GroovyDocs, Groovy adds an encodeBase64() method to byte[]. The return type is a Writable, which is then converted back to a String using the normal toString() method.

Add the word “Basic” in front of it and you’ve got an authorization header that can be used in an HTTP request.

Okay, that’s cool, and it works, but whoa is that dangerous. Say I’m a sniffer on the network. I see a request go by, and inside it I find:
Authorization: dXNlcm5hbWU6cGFzc3dvcmQ=
We now have a beautiful illustration of the difference between encoding and encrypting. Just because this is Base 64 encoded doesn’t mean it can’t be read. All I have to do is write:
[sourcecode language=”groovy”]
def (user,pass) = new String("dXNlcm5hbWU6cGFzc3dvcmQ=".decodeBase64()).split(‘:’)
and lo and behold, I’ve got the username and password. This works because Groovy gives the String class a nice, convenient decodeBase64() method, and String has a constructor that takes the resulting byte array as an argument. I’m also using the new (as of Groovy 1.6) mechanism that allows me to return two separate values from a method call, so here I return the username and password separately from the split() method.

Of course, the real reason this works is that HTTP basic authentication passes the encoded string in nice, clear text. No decryption is required. If this was being transmitted over HTTPS, at least the network would be encrypted, but there’s no requirement for that.

Yikes. I’d guess the Twitter web site itself uses form authentication over HTTPS, but I wonder how many of those client-side Twitter applications are just doing basic authentication like this?

Maybe I should change my Twitter password.

Just for reference, here’s a complete script showing both encoding and decoding, with some assertions for completeness:
[sourcecode language=”groovy”]
def u = ‘username’
def p = ‘password’
def encoded = "$u:$p".getBytes().encodeBase64().toString()
println "$u:$p -> $encoded"
assert encoded == ‘dXNlcm5hbWU6cGFzc3dvcmQ=’
def (user,pass) = new String(encoded.decodeBase64()).split(‘:’)
println "(user,pass) = ($user,$pass)"
assert user == u
assert pass == p

3 responses to “Groovy, Twitter, and Basic Authentication”

  1. Indeed, basic auth is convenient, but the only thing that can keep it secure is dictating(and enforcing) a policy where https is ALWAYS used.
    Thanks for the clear description of the problem! And for pointing out the encode/decode methods that Groovy provides for simplifying the creation of the credential string.

  2. Twitter is turning off basic authentication June 2010.

  3. Yeah, I heard about that. I think that’s a good idea. Now I have to dig into this OAuth stuff, though. 🙂

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.