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 +4 -4
- data/CHANGELOG.md +7 -4
- data/README.md +23 -19
- data/VERSION +1 -1
- data/app/assets/javascripts/faye-authentication.js +53 -20
- data/spec/javascripts/faye-authentication_spec.js +0 -131
- data/spec/javascripts/faye-extension_spec.js +178 -12
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf71f8b18a19f40de998593763092f543e29ece8
|
4
|
+
data.tar.gz: bdeb27cf3b04249d5cfddf381e993fc9a8a3e7e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70703294de6bcabc10ad6a69da8bfc98b62b6bb4f6c13ea9c2c70ab124c2b0e1a9cfabdf2157471fd7ab42ce88eadfc5af7ffc19d63e596b01a1696cb4974a87
|
7
|
+
data.tar.gz: 2237e1664fb593aa62c06803362670929bf719d23d4c598ed523fa6309e869ae4ea55e61f51bbadf927d612861e3170e14589745810189b57d59c43cdd53ceee
|
data/CHANGELOG.md
CHANGED
@@ -1,19 +1,22 @@
|
|
1
|
-
##
|
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
|
-
##
|
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
|
-
##
|
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
|
-
##
|
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
|
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
|
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
|
-
|
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
|
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
|
-
"
|
55
|
-
|
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
|
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
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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.
|
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(
|
29
|
-
|
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
|
-
}
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
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
|
-
|
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['
|
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['
|
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': '{"
|
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': '{"
|
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.
|
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:
|
11
|
+
date: 2015-02-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jwt
|