faye-authentication 1.6.1 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5fad8ac96a666e80843039ab6fa912eb1fc6544b
4
- data.tar.gz: 668b783f2b2ebfb837d321682e2315b9ca86d15a
3
+ metadata.gz: bf71f8b18a19f40de998593763092f543e29ece8
4
+ data.tar.gz: bdeb27cf3b04249d5cfddf381e993fc9a8a3e7e4
5
5
  SHA512:
6
- metadata.gz: 79ed0f302ec3db027cd3522b321c495c86c496a9156f74a887081e3d17aaa97ac67d68df5262828fc85080504ca8f7c9e42c59c5f2c08e7c4fe582655f30e657
7
- data.tar.gz: 2dd7664727dc9d2c32bd45b02b1500dd260f52f163f0b8a2e2cfbc307823be8742c5a43d72a463963f4776c7571e3511e1dfe335c51e4e10a5573377f3567277
6
+ metadata.gz: 70703294de6bcabc10ad6a69da8bfc98b62b6bb4f6c13ea9c2c70ab124c2b0e1a9cfabdf2157471fd7ab42ce88eadfc5af7ffc19d63e596b01a1696cb4974a87
7
+ data.tar.gz: 2237e1664fb593aa62c06803362670929bf719d23d4c598ed523fa6309e869ae4ea55e61f51bbadf927d612861e3170e14589745810189b57d59c43cdd53ceee
data/CHANGELOG.md CHANGED
@@ -1,19 +1,22 @@
1
- ## 0.5.0
1
+ ## 1.7.0
2
+ - Improve preformance by batching authentication requests (backward incompatible!)
3
+
4
+ ## 1.5.0
2
5
  - Add support for faye 1.1 (unreleased for now)
3
6
  - Drop support for faye < 1.1
4
7
  - More extensibility regarding public channels, extensions now take an options
5
8
  hash with a whitelist lambda / function that will be called with the channel
6
9
  name so developers can implement their own logic
7
10
 
8
- ## 0.4.0
11
+ ## 1.4.0
9
12
  - Channels beginning by ``/public/`` do not require authentication anymore,
10
13
  However, globbing with public channels still require authentication.
11
14
 
12
- ## 0.3.0
15
+ ## 1.3.0
13
16
  - Rename ``Faye::Authentication::Extension`` to ``Faye::Authentication::ServerExtension``
14
17
  - Add extension for faye Ruby Client : ``Faye::Authentication::ClientExtension``
15
18
 
16
- ## 0.2.0
19
+ ## 1.2.0
17
20
 
18
21
  - Use JWT instead of HMAC for signing the messages
19
22
  - Allow expiration of the signature
data/README.md CHANGED
@@ -6,12 +6,11 @@ Authentification implementation for faye
6
6
 
7
7
  This project implements (channel,client_id) authentication on channel subscription and publication and delegate it to an external HTTP endpoint through JWT tupple signature based on a shared secret key between Faye server and the endpoint.
8
8
 
9
- On channel subscription the JS client performe an Ajax Call to an HTTP endpoint to be granted a signature that will be provided to Faye Server to connect and publish to channel. The authentication of the endpoint itself is up to you but in the general case this will be a session authenticated resource of your app and you will decide to provide the signature or not depending on your own business logic.
9
+ On channel subscription the JS client performs an Ajax Call to an HTTP endpoint to be granted a signature that will be provided to Faye Server to connect and publish to channel. The authentication of the endpoint itself is up to you but in the general case this will be a session authenticated resource of your app and you will decide to provide the signature or not depending on your own business logic.
10
10
 
11
- This signature is required and valid for each channel and client id tupple and rely on JWT for security.
11
+ This signature is required for each channel and client id tupple and relies on JWT for security. The Faye server will verify the (channel,client_id) tupple signature and reject the message if the signature is incorrect or not present.
12
12
 
13
- The Faye server will verify the (channel,client_id) tupple signature and reject the message if the signature
14
- is incorrect or not present.
13
+ If the browser needs multiple signatures (for multiple channels), they'll automatically be batched together into one signature HTTP request to your server.
15
14
 
16
15
  ## Current support
17
16
 
@@ -40,25 +39,30 @@ Or install it yourself as:
40
39
 
41
40
  ### Channels requiring authentication
42
41
 
43
- All channels require authentication by default, however, it is possible to provide
44
- a lambda to the faye extensions to let them know which channels are public.
42
+ All channels require authentication by default, however, it is possible to provide a lambda to the faye extensions to let them know which channels are public.
45
43
 
46
44
  ### Authentication endpoint requirements
47
45
 
48
- The endpoint will receive a POST request, and shall return a JSON hash with a ``signature`` key.
46
+ The endpoint will receive a POST request with one or more channels, and shall return a JSON document with the signatures.
49
47
 
50
48
  The parameters sent to the endpoint are the following :
51
49
 
52
50
  ```json
53
51
  {
54
- "message" : {
55
- "channel": "/foo/bar",
52
+ "messages": {
53
+ "0": {
54
+ "channel": "/foo",
56
55
  "clientId": "123abc"
56
+ },
57
+ "1": {
58
+ "channel": "/bar",
59
+ "clientId": "123abc"
60
+ }
57
61
  }
58
62
  }
59
63
  ```
60
64
 
61
- If the endpoint returns an error, the message won't be signed and the server will reject it.
65
+ If the endpoint returns an error, the messages won't be signed and the server will reject them.
62
66
 
63
67
  You can use ``Faye::Authentication.sign`` to generate the signature from the message and a private key.
64
68
 
@@ -66,17 +70,19 @@ Example (For a Rails application)
66
70
 
67
71
  ```ruby
68
72
  def auth
69
- if current_user.can?(:read, params[:message][:channel])
70
- render json: {signature: Faye::Authentication.sign(params[:message].slice(:channel,:clientId), 'your shared secret key')}
71
- else
72
- render json: {error: 'Not authorized'}, status: 403
73
+ response = params[:messages].values.map do |message|
74
+ if current_user.can?(:read, message[:channel])
75
+ message.merge(signature: Faye::Authentication.sign(message, FAYE_CONFIG['secret']))
76
+ else
77
+ message.merge(error: 'Forbidden')
78
+ end
73
79
  end
80
+ render json: {signatures: response}
74
81
  end
75
82
 
76
83
  ```
77
84
 
78
- A Ruby HTTP Client is also available for publishing messages to your faye server
79
- without the hassle of using EventMachine :
85
+ A Ruby HTTP Client is also available for publishing messages to your faye server without the hassle of using EventMachine :
80
86
 
81
87
  ```ruby
82
88
  Faye::Authentication::HTTPClient.publish('http://localhost:9290/faye', '/channel', 'data', 'your private key')
@@ -128,9 +134,7 @@ Faye::Authentication::ServerExtension expect that :
128
134
 
129
135
  Otherwise Faye Server will refuse the message.
130
136
 
131
- If you want to specify some channels for which you don't want the extension require
132
- authentication, you can pass an options hash with a ``whitelist`` key mapping
133
- to a lambda :
137
+ If you want to specify some channels for which you don't want the extension require authentication, you can pass an options hash with a ``whitelist`` key mapping to a lambda :
134
138
 
135
139
  ````ruby
136
140
  channel_whitelist = lambda do |channel|
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.6.1
1
+ 1.7.0
@@ -4,64 +4,97 @@ function FayeAuthentication(client, endpoint, options) {
4
4
  this._signatures = {};
5
5
  this._outbox = {};
6
6
  this._options = options || {};
7
+ this._waiting_signatures = [];
8
+ this._timer = null;
7
9
  }
8
10
 
9
11
  FayeAuthentication.prototype.endpoint = function() {
10
12
  return (this._endpoint);
11
13
  };
12
14
 
15
+ FayeAuthentication.prototype.resolveWaitingSignatures = function() {
16
+ if (this._waiting_signatures.length == 0) {
17
+ return ;
18
+ }
19
+ var self = this;
20
+ var messages = [];
21
+ $.each(this._waiting_signatures, function(key, params) {
22
+ messages.push(params);
23
+ });
24
+ this._waiting_signatures = [];
25
+ messages = messages.sort(function(a, b) {
26
+ return (a.channel > b.channel);
27
+ });
28
+
29
+ $.post(self.endpoint(), {messages: messages}, function(response) {
30
+ $.each(messages, function(key, params) {
31
+ var signature = $.grep(response.signatures || [], function(e) {
32
+ return (e.channel == params.channel && e.clientId == params.clientId);
33
+ })[0];
34
+ Faye.Promise.resolve(self._signatures[params.clientId][params.channel], signature ? signature.signature : null);
35
+ });
36
+ }, 'json').fail(function(xhr, textStatus, e) {
37
+ self.error('Failure when trying to fetch JWT signature for data "' + JSON.stringify(messages) + '", error was : ' + textStatus);
38
+ $.each(messages, function(key, params) {
39
+ Faye.Promise.resolve(self._signatures[params.clientId][params.channel], null);
40
+ });
41
+ });
42
+ };
43
+
13
44
  FayeAuthentication.prototype.signMessage = function(message, callback) {
14
45
  var channel = message.subscription || message.channel;
15
46
  var clientId = message.clientId;
16
47
 
17
48
  var self = this;
18
- if (!this._signatures[clientId])
49
+ if (!this._signatures[clientId]) {
19
50
  this._signatures[clientId] = {};
51
+ }
20
52
  if (this._signatures[clientId][channel]) {
21
53
  this._signatures[clientId][channel].then(function(signature) {
22
54
  message.signature = signature;
23
- if (!message.retried)
55
+ if (!message.retried) {
24
56
  self._outbox[message.id] = {message: message, clientId: clientId};
57
+ }
25
58
  callback(message);
26
59
  });
27
60
  } else {
28
- self._signatures[clientId][channel] = new Faye.Promise(function(success, failure) {
29
- $.post(self.endpoint(), {message: {channel: channel, clientId: clientId}}, function(response) {
30
- success(response.signature);
31
- }, 'json').fail(function(xhr, textStatus, e) {
32
- success(null);
33
- });
34
- });
35
- self._signatures[clientId][channel].then(function(signature) {
61
+ var promise = self._signatures[clientId][channel] = new Faye.Promise();
62
+ promise.then(function(signature) {
36
63
  message.signature = signature;
37
- if (!message.retried){
64
+ if (!message.retried) {
38
65
  self._outbox[message.id] = {message: message, clientId: clientId};
39
66
  }
40
67
  callback(message);
41
68
  });
69
+ this._waiting_signatures.push({channel: channel, clientId: clientId});
70
+ clearTimeout(this._timer);
71
+ this._timer = setTimeout(function() {
72
+ self.resolveWaitingSignatures();
73
+ }, 200);
42
74
  }
43
75
  }
44
76
 
45
77
  FayeAuthentication.prototype.outgoing = function(message, callback) {
46
- if (this.authentication_required(message))
78
+ if (this.authentication_required(message)) {
47
79
  this.signMessage(message, callback);
48
- else
80
+ } else {
49
81
  callback(message);
82
+ }
50
83
  };
51
84
 
52
85
  FayeAuthentication.prototype.authentication_required = function(message) {
53
86
  var subscription_or_channel = message.subscription || message.channel;
54
- if (message.channel == '/meta/subscribe' || message.channel.lastIndexOf('/meta/', 0) !== 0)
87
+ if (message.channel == '/meta/subscribe' || message.channel.lastIndexOf('/meta/', 0) !== 0) {
55
88
  if(this._options.whitelist) {
56
89
  try {
57
90
  return (!this._options.whitelist(subscription_or_channel));
58
91
  } catch (e) {
59
92
  this.error("Error caught when evaluating whitelist function : " + e.message);
60
93
  }
61
- } else
62
- return (true);
63
- else
64
- return (false);
94
+ }
95
+ return (true);
96
+ }
97
+ return (false);
65
98
  };
66
99
 
67
100
  FayeAuthentication.prototype.incoming = function(message, callback) {
@@ -73,9 +106,9 @@ FayeAuthentication.prototype.incoming = function(message, callback) {
73
106
  delete outbox_message.message.id;
74
107
  delete this._outbox[message.id];
75
108
  this._client._sendMessage(outbox_message.message, {}, callback);
76
- }
77
- else
109
+ } else {
78
110
  callback(message);
111
+ }
79
112
  };
80
113
 
81
114
  $(function() {
@@ -111,135 +111,4 @@ describe('faye-authentication', function() {
111
111
 
112
112
  });
113
113
 
114
- describe('extension', function() {
115
- beforeEach(function() {
116
- jasmine.Ajax.install();
117
- this.client = new Faye.Client('http://localhost:9296/faye');
118
- this.auth = new FayeAuthentication(this.client);
119
- this.client.addExtension(this.auth);
120
- });
121
-
122
- afterEach(function() {
123
- jasmine.Ajax.uninstall();
124
- });
125
-
126
- it('should make an ajax request to the extension endpoint', function(done) {
127
- this.client.subscribe('/foobar');
128
- var self = this;
129
- setTimeout(function() {
130
- var request = jasmine.Ajax.requests.mostRecent();
131
- expect(request.url).toBe(self.auth.endpoint());
132
- done();
133
- }, 500);
134
- });
135
-
136
- it('should make an ajax request with the correct params', function(done) {
137
- this.client.subscribe('/foobar');
138
- var self = this;
139
- setTimeout(function() {
140
- var request = jasmine.Ajax.requests.mostRecent();
141
- expect(request.data()['message[channel]'][0]).toBe('/foobar');
142
- done();
143
- }, 500);
144
- });
145
-
146
-
147
- describe('signature', function() {
148
-
149
- beforeEach(function() {
150
- jasmine.Ajax.stubRequest('/faye/auth').andReturn({
151
- 'responseText': '{"signature": "foobarsignature"}'
152
- });
153
-
154
- this.dispatcher = {connectionType: "fake", sendMessage: function() {}, selectTransport: function() { }};
155
- spyOn(this.dispatcher, 'sendMessage');
156
- spyOn(this.dispatcher, 'selectTransport');
157
- Faye.extend(this.dispatcher, Faye.Publisher)
158
- });
159
-
160
- it('should add the signature to subscribe message', function(done) {
161
- var self = this;
162
-
163
- this.client.handshake(function() {
164
- self.client._dispatcher = self.dispatcher;
165
- self.client.subscribe('/foobar');
166
-
167
- setTimeout(function() {
168
- var calls = self.dispatcher.sendMessage.calls.all();
169
- var last_call = calls[calls.length - 1];
170
- var message = last_call.args[0];
171
- expect(message.channel).toBe('/meta/subscribe');
172
- expect(message.signature).toBe('foobarsignature');
173
- done();
174
- }, 300);
175
-
176
- }, this.client);
177
- });
178
-
179
- it('should add the signature to publish message', function(done) {
180
- var self = this;
181
-
182
- this.client.handshake(function() {
183
- self.client._dispatcher = self.dispatcher;
184
- self.client.publish('/foobar', {text: 'hallo'});
185
-
186
- setTimeout(function() {
187
- var calls = self.dispatcher.sendMessage.calls.all();
188
- var last_call = calls[calls.length - 1];
189
- var message = last_call.args[0];
190
- expect(message.channel).toBe('/foobar');
191
- expect(message.signature).toBe('foobarsignature');
192
- done();
193
- }, 300);
194
-
195
- }, this.client);
196
- });
197
-
198
- it('preserves messages integrity', function(done) {
199
- var self = this;
200
-
201
- this.client.handshake(function() {
202
- self.client._dispatcher = self.dispatcher;
203
- self.client.publish('/foo', {text: 'hallo'});
204
- self.client.subscribe('/foo');
205
-
206
- setTimeout(function() {
207
- var calls = self.dispatcher.sendMessage.calls.all();
208
- var subscribe_call = calls[calls.length - 1];
209
- var publish_call = calls[calls.length - 2];
210
- var subscribe_message = subscribe_call.args[0];
211
- var publish_message = publish_call.args[0];
212
- expect(publish_message.channel).toBe('/foo');
213
- expect(subscribe_message.channel).toBe('/meta/subscribe');
214
- expect(publish_message.signature).toBe('foobarsignature');
215
- expect(subscribe_message.signature).toBe('foobarsignature');
216
- done();
217
- }, 300);
218
-
219
- }, this.client);
220
- });
221
-
222
- it('does not add the signature if authentication is not required', function(done) {
223
- var self = this;
224
-
225
- spyOn(this.auth, 'authentication_required').and.returnValue(false);
226
-
227
- this.client.handshake(function() {
228
- self.client._dispatcher = self.dispatcher;
229
- self.client.publish('/foobar', {text: 'hallo'});
230
-
231
- setTimeout(function() {
232
- var calls = self.dispatcher.sendMessage.calls.all();
233
- var last_call = calls[calls.length - 1];
234
- var message = last_call.args[0];
235
- expect(message.channel).toBe('/foobar');
236
- expect(message.signature).toBe(undefined);
237
- done();
238
- }, 300);
239
- }, this.client);
240
-
241
- });
242
-
243
- });
244
- });
245
114
  });
@@ -35,12 +35,131 @@ describe('Faye extension', function() {
35
35
  var signature = jwtsign.serialize("macaroni");
36
36
 
37
37
  jasmine.Ajax.stubRequest('/faye/auth').andReturn({
38
- 'responseText': '{"signature": "' + signature + '"}'
38
+ 'responseText': '{"signatures": [{"channel" : "/foobar", "clientId": "'+ self.client._dispatcher.clientId +'", "signature" : "' + signature + '"}]}'
39
39
  });
40
40
  callback();
41
41
  }, self.client);
42
42
  }
43
43
 
44
+ it('should make an ajax request to the extension endpoint', function(done) {
45
+ this.client.subscribe('/foobar');
46
+ var self = this;
47
+ setTimeout(function() {
48
+ var request = jasmine.Ajax.requests.mostRecent();
49
+ expect(request.url).toBe(self.extension.endpoint());
50
+ done();
51
+ }, 500);
52
+ });
53
+
54
+ it('should make an ajax request with the correct params', function(done) {
55
+ this.client.subscribe('/foobar');
56
+ var self = this;
57
+ setTimeout(function() {
58
+ var request = jasmine.Ajax.requests.mostRecent();
59
+ expect(request.data()['messages[0][channel]'][0]).toBe('/foobar');
60
+ done();
61
+ }, 500);
62
+ });
63
+
64
+ describe('signature', function() {
65
+
66
+ beforeEach(function() {
67
+ jasmine.Ajax.stubRequest('/faye/auth').andReturn({
68
+ 'responseText': '{"signatures": [{"channel": "/foobar", "clientId": "1234", "signature": "foobarsignature"}]}'
69
+ });
70
+
71
+ this.dispatcher = {connectionType: "fake", clientId: '1234', sendMessage: function() {}, selectTransport: function() { }};
72
+ spyOn(this.dispatcher, 'sendMessage');
73
+ spyOn(this.dispatcher, 'selectTransport');
74
+ Faye.extend(this.dispatcher, Faye.Publisher)
75
+ });
76
+
77
+ it('should add the signature to subscribe message', function(done) {
78
+ var self = this;
79
+
80
+ this.client.handshake(function() {
81
+ self.client._dispatcher = self.dispatcher;
82
+
83
+ self.client.subscribe('/foobar');
84
+
85
+ setTimeout(function() {
86
+ var calls = self.dispatcher.sendMessage.calls.all();
87
+ var last_call = calls[calls.length - 1];
88
+ var message = last_call.args[0];
89
+ expect(message.channel).toBe('/meta/subscribe');
90
+ expect(message.signature).toBe('foobarsignature');
91
+ done();
92
+ }, 300);
93
+
94
+ }, this.client);
95
+ });
96
+
97
+ it('should add the signature to publish message', function(done) {
98
+ var self = this;
99
+
100
+ this.client.handshake(function() {
101
+ self.client._dispatcher = self.dispatcher;
102
+ self.client.publish('/foobar', {text: 'hallo'});
103
+
104
+ setTimeout(function() {
105
+ var calls = self.dispatcher.sendMessage.calls.all();
106
+ var last_call = calls[calls.length - 1];
107
+ var message = last_call.args[0];
108
+ expect(message.channel).toBe('/foobar');
109
+ expect(message.signature).toBe('foobarsignature');
110
+ done();
111
+ }, 300);
112
+
113
+ }, this.client);
114
+ });
115
+
116
+ it('preserves messages integrity', function(done) {
117
+ var self = this;
118
+
119
+ this.client.handshake(function() {
120
+ self.client._dispatcher = self.dispatcher;
121
+ self.client.publish('/foobar', {text: 'hallo'});
122
+ self.client.subscribe('/foobar');
123
+
124
+ setTimeout(function() {
125
+ var calls = self.dispatcher.sendMessage.calls.all();
126
+ var subscribe_call = calls[calls.length - 1];
127
+ var publish_call = calls[calls.length - 2];
128
+ var subscribe_message = subscribe_call.args[0];
129
+ var publish_message = publish_call.args[0];
130
+ expect(publish_message.channel).toBe('/foobar');
131
+ expect(subscribe_message.channel).toBe('/meta/subscribe');
132
+ expect(publish_message.signature).toBe('foobarsignature');
133
+ expect(subscribe_message.signature).toBe('foobarsignature');
134
+ done();
135
+ }, 300);
136
+
137
+ }, this.client);
138
+ });
139
+
140
+ it('does not add the signature if authentication is not required', function(done) {
141
+ var self = this;
142
+
143
+ spyOn(this.extension, 'authentication_required').and.returnValue(false);
144
+
145
+ this.client.handshake(function() {
146
+ self.client._dispatcher = self.dispatcher;
147
+ self.client.publish('/foobar', {text: 'hallo'});
148
+
149
+ setTimeout(function() {
150
+ var calls = self.dispatcher.sendMessage.calls.all();
151
+ var last_call = calls[calls.length - 1];
152
+ var message = last_call.args[0];
153
+ expect(message.channel).toBe('/foobar');
154
+ expect(message.signature).toBe(undefined);
155
+ done();
156
+ }, 300);
157
+ }, this.client);
158
+
159
+ });
160
+
161
+ });
162
+
44
163
  it('succeeds to subscribe', function(done) {
45
164
  var self = this;
46
165
  stubSignature(this, function() {
@@ -62,26 +181,73 @@ describe('Faye extension', function() {
62
181
  it('should make only one ajax call when dealing with one channel', function(done) {
63
182
  this.client.subscribe('/foobar');
64
183
  this.client.publish('/foobar', {text: 'hallo'});
65
- this.client.publish('/foobar', {text: 'hallo'});
66
184
 
67
185
  setTimeout(function() {
68
186
  expect(jasmine.Ajax.requests.count()).toBe(2); // Handshake + auth * 1
69
187
  done();
70
188
  }, 500);
71
189
 
72
- })
190
+ });
73
191
 
74
- it('should make two ajax calls when dealing with two channels', function(done) {
192
+ it('should make two ajax calls when dealing with two channels in a not-so-short period', function(done) {
75
193
  this.client.subscribe('/foobar');
76
194
  this.client.publish('/foobar', {text: 'hallo'});
195
+
196
+ var self = this;
197
+
198
+ setTimeout(function() {
199
+ self.client.subscribe('/bar');
200
+ self.client.publish('/bar', {text: 'hallo'});
201
+
202
+ setTimeout(function() {
203
+ expect(jasmine.Ajax.requests.count()).toBe(3); // Handshake + auth * 2
204
+ done();
205
+ }, 500);
206
+ }, 250);
207
+ });
208
+
209
+ it('should make two ajax calls when dealing with three channels and separating calls', function(done) {
210
+ this.client.subscribe('/foobar');
77
211
  this.client.publish('/foobar', {text: 'hallo'});
78
212
 
79
- this.client.subscribe('/bar');
80
- this.client.publish('/bar', {text: 'hallo'});
81
- this.client.publish('/bar', {text: 'hallo'});
213
+ var self = this;
82
214
 
83
215
  setTimeout(function() {
84
- expect(jasmine.Ajax.requests.count()).toBe(3); // Handshake + auth * 2
216
+ self.client.subscribe('/bar');
217
+ self.client.publish('/bar', {text: 'hallo'});
218
+
219
+ self.client.subscribe('/baz');
220
+ self.client.publish('/baz', {text: 'hallo'});
221
+
222
+ setTimeout(function() {
223
+ expect(jasmine.Ajax.requests.count()).toBe(3); // Handshake + auth * 2
224
+ var first_auth = jasmine.Ajax.requests.at(1);
225
+ var second_auth = jasmine.Ajax.requests.at(2);
226
+ expect(first_auth.data()['messages[0][channel]'][0]).toBe('/foobar');
227
+ expect(first_auth.data()['messages[1]']).toBe(undefined);
228
+
229
+ expect(second_auth.data()['messages[0][channel]'][0]).toBe('/bar');
230
+ expect(second_auth.data()['messages[1][channel]'][0]).toBe('/baz');
231
+ done();
232
+ }, 500);
233
+ }, 250);
234
+ });
235
+
236
+ it('should make only one ajax calls when subscribing several times in a short period', function(done) {
237
+ var self = this;
238
+ this.client.subscribe('/foobar');
239
+ setTimeout(function() {
240
+ self.client.subscribe('/foobar2');
241
+ setTimeout(function() {
242
+ self.client.subscribe('/foobar3');
243
+ }, 50)
244
+ }, 50);
245
+ setTimeout(function() {
246
+ expect(jasmine.Ajax.requests.count()).toBe(2); // Handshake + auth
247
+ var request = jasmine.Ajax.requests.mostRecent();
248
+ expect(request.data()['messages[0][channel]'][0]).toBe('/foobar');
249
+ expect(request.data()['messages[1][channel]'][0]).toBe('/foobar2');
250
+ expect(request.data()['messages[2][channel]'][0]).toBe('/foobar3');
85
251
  done();
86
252
  }, 500);
87
253
  });
@@ -108,19 +274,19 @@ describe('Faye extension', function() {
108
274
  var request = jasmine.Ajax.requests.mostRecent();
109
275
  var params = queryString.parse(request.params);
110
276
 
111
- var jwtsign_bad = new jwt.WebToken('{"clientId": "' + params['message[clientId]'] + '", "channel": "/foo", "exp": 1}', '{"alg": "HS256"}');
277
+ var jwtsign_bad = new jwt.WebToken('{"clientId": "' + params['messages[0][clientId]'] + '", "channel": "/foo", "exp": 1}', '{"alg": "HS256"}');
112
278
  var signature_bad = jwtsign_bad.serialize("macaroni");
113
279
 
114
- var jwtsign_good = new jwt.WebToken('{"clientId": "' + params['message[clientId]'] + '", "channel": "/foo", "exp": 2803694528}', '{"alg": "HS256"}');
280
+ var jwtsign_good = new jwt.WebToken('{"clientId": "' + params['messages[0][clientId]'] + '", "channel": "/foo", "exp": 2803694528}', '{"alg": "HS256"}');
115
281
  var signature_good = jwtsign_good.serialize("macaroni");
116
282
 
117
283
  request.response({
118
284
  'status' : 200,
119
- 'responseText': '{"signature": "' + signature_bad + '"}'
285
+ 'responseText': '{"signatures": [{"channel": "/foo", "clientId": "'+ params['messages[0][clientId]'] +'", "signature": "' + signature_bad + '"}]}'
120
286
  });
121
287
 
122
288
  jasmine.Ajax.stubRequest('/faye/auth').andReturn({
123
- 'responseText': '{"signature": "' + signature_good + '"}'
289
+ 'responseText': '{"signatures": [{"channel": "/foo", "clientId": "'+ params['messages[0][clientId]'] +'", "signature": "' + signature_good + '"}]}'
124
290
  });
125
291
 
126
292
  }, 1000);
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faye-authentication
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.1
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrien Siami
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-15 00:00:00.000000000 Z
11
+ date: 2015-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jwt