Thursday, August 19, 2010

Per Message Authorization in Faye (Take 1)

‹prev | My Chain | next›

Currently in my (fab) game, I can use player Bob's Javascript Console to move player Fred:



I would like to ensure that only Fred's browser can move Fred.

Borrowing from the excellent faye documentation, I come up with this extension on the client side:
  this.faye = new Faye.Client('/faye');

var self = this;
var clientAuth = {
outgoing: function(message, callback) {
// Leave non-data messages alone
if (message.channel !== '/meta/connect')
return callback(message);

// Add ext field if it's not present
if (!message.ext) message.ext = {};

// Set the auth token
message.ext.authToken = self.uniq_id;

// Carry on and send the message to the server
return callback(message);
}
};
this.faye.addExtension(clientAuth);
Hopefully that is fairly self-explanatory. If the message is sent on a data channel (i.e. not a subscription channel), then I add the player's unique ID as an authToken message extension.

On the server side, I add code that includes the original authToken to the player store, then check subsequent messages to see if the messages include the same authToken. If not, I add an error to the message, which prevents it from being sent to attached clients:

var self = this;
var serverAuth = {
incoming: function(message, callback) {
// Let non-channel messages through
if (message.channel !== '/meta/connect')
return callback(message);

// Get subscribed channel and auth token
var subscription = message.subscription,
msgToken = message.ext && message.ext.authToken;

if (message.id) {
if (self.get_player(message.id)) {
puts("[token check] " + self.get_player(message.id).token + " " + msgToken);
if (self.get_player(message.id).token != msgToken)
message.error = 'Invalid player auth token';
}
}
// Call the server back now we're done
callback(message);
}
};

this.faye.addExtension(serverAuth);
That does not work. The code does not crash, but nothing changes. Player Bob can still move Fred from the Javascript Console.

It takes me a while to figure this one out, but ultimately, it comes to me: I did not add the serverAuth extension to the server. I added it to a client on the server side! D'oh!

Unfortunately, I do not have an easy answer for this. I am using a custom fab.js app to establish the faye server in my (fab) game:
with ( require( "fab" ) )

( fab )

// Listen on the FAB port and establish the faye server
( listen_with_faye, 0xFAB )


//...
I cannot get access to that server anywhere in the game. At least not as-is. Sigh.

I will circle back to that tomorrow. For now, I would like to make sure that other clients are not able to see faye message extensions—especially authorize tokens. Looking a tcpdump output, I can see the message extension being sent to the server:
21:59:10.137072 IP whitefall.38982 > whitefall.4011: Flags [P.], seq 420:745, ack 199, win 513, options [nop,nop,TS val 44612313 ecr 44612313], length 325
0x0000: 4500 0179 e69c 4000 4006 54e0 7f00 0001 E..y..@.@.T.....
0x0010: 7f00 0001 9846 0fab c5e0 5de9 c64e 7519 .....F....]..Nu.
0x0020: 8018 0201 ff6d 0000 0101 080a 02a8 bad9 .....m..........
0x0030: 02a8 bad9 005b 7b22 6368 616e 6e65 6c22 .....[{"channel"
0x0040: 3a22 2f70 6c61 7965 7273 2f6d 6f76 6522 :"/players/move"
0x0050: 2c22 6461 7461 223a 7b22 6964 223a 2262 ,"data":{"id":"b
0x0060: 6f62 222c 2278 223a 3435 372c 2279 223a ob","x":457,"y":
0x0070: 3230 357d 2c22 636c 6965 6e74 4964 223a 205},"clientId":
0x0080: 2234 766c 3634 7831 3664 6965 346e 3167 "4vl64x16die4n1g
0x0090: 6e73 676b 7871 3732 3872 6a22 2c22 6964 nsgkxq728rj","id
0x00a0: 223a 226a 6b71 3073 6c31 6772 7777 7832 ":"jkq0sl1grwwx2
0x00b0: 7471 3235 6366 7064 3578 3469 227d 2c7b tq25cfpd5x4i"},{
0x00c0: 2263 6861 6e6e 656c 223a 222f 6d65 7461 "channel":"/meta
0x00d0: 2f63 6f6e 6e65 6374 222c 2263 6c69 656e /connect","clien
0x00e0: 7449 6422 3a22 3476 6c36 3478 3136 6469 tId":"4vl64x16di
0x00f0: 6534 6e31 676e 7367 6b78 7137 3238 726a e4n1gnsgkxq728rj
0x0100: 222c 2263 6f6e 6e65 6374 696f 6e54 7970 ","connectionTyp
0x0110: 6522 3a22 7765 6273 6f63 6b65 7422 2c22 e":"websocket","
0x0120: 6964 223a 2231 7461 6a38 7531 6a78 3434 id":"1taj8u1jx44
0x0130: 3434 3135 7339 756d 7875 3736 3871 6b22 4415s9umxu768qk"
0x0140: 2c22 6578 7422 3a7b 2261 7574 6854 6f6b ,"ext":{"authTok
0x0150: 656e 223a 2262 6f62 2d34 3933 3222 7d2c en":"bob-4932"},
0x0160: 2261 6476 6963 6522 3a7b 2274 696d 656f "advice":{"timeo
0x0170: 7574 223a 307d 7d5d ff ut":0}}].
Happily, when I check in the browser, I only see the message, not the extension:



As I have come to expect, faye is doing the right thing on my behalf. This means, I believe, that my overall approach is sound. I just need access to the faye server to add the extension. That will be on tap for tomorrow.


Day #200

No comments:

Post a Comment