faye-authentication 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -2
- data/README.md +12 -0
- data/app/assets/javascripts/faye-authentication.js +14 -5
- data/lib/faye/authentication/client_extension.rb +1 -1
- data/lib/faye/authentication/server_extension.rb +1 -1
- data/lib/faye/authentication/version.rb +1 -1
- data/lib/faye/authentication.rb +10 -0
- data/spec/javascripts/faye-authentication_spec.js +14 -24
- data/spec/javascripts/faye-extension_spec.js +27 -0
- data/spec/lib/faye/authentication/server_extension_spec.rb +52 -19
- 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: 9a617e82b1d7184dc0ce7016b8736c6e412500f3
|
4
|
+
data.tar.gz: 640960f50c1a742c704bd4ded7930817caf22ee4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c130a9cef8388dcc2666842339aea83206c3500e155c45b67ab5751ba29a339a8786e95c54cf754aeb8362d78cca94d120f8d2a3151bece77ee44c47e4121609
|
7
|
+
data.tar.gz: 09ef066a4f2cbaddb41ac92175a0dbe58e9c3d6e8e78cb21c775bf9300a0f8026eea4cf0d89dc0b5a5a09bbaba1aa7f0c7b1d91549ad5db5a3209d8f220dff25
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
+
## 0.4.0
|
2
|
+
- Channels beginning by ``/public/`` do not require authentication anymore,
|
3
|
+
However, globbing with public channels still require authentication.
|
4
|
+
|
1
5
|
## 0.3.0
|
2
|
-
- Rename ``Faye::Authentication::Extension`` to ``Faye::Authentication::ServerExtension``
|
3
|
-
- Add extension for faye Ruby Client : ``Faye::Authentication::ClientExtension``
|
6
|
+
- Rename ``Faye::Authentication::Extension`` to ``Faye::Authentication::ServerExtension``
|
7
|
+
- Add extension for faye Ruby Client : ``Faye::Authentication::ClientExtension``
|
4
8
|
|
5
9
|
## 0.2.0
|
6
10
|
|
data/README.md
CHANGED
@@ -38,6 +38,18 @@ Or install it yourself as:
|
|
38
38
|
|
39
39
|
## Usage
|
40
40
|
|
41
|
+
### Channels requiring authentication
|
42
|
+
|
43
|
+
All channels require authentication, except channels beginning by ``/public/``
|
44
|
+
|
45
|
+
However, globbing, even on ``/public/`` channels will require authentication.
|
46
|
+
|
47
|
+
Example :
|
48
|
+
|
49
|
+
- ``/public/foo`` does not require authentication
|
50
|
+
- ``/public/bar/*`` requires authentication
|
51
|
+
|
52
|
+
|
41
53
|
### Authentication endpoint requirements
|
42
54
|
|
43
55
|
The endpoint will receive a POST request, and shall return a JSON hash with a ``signature`` key.
|
@@ -42,16 +42,25 @@ FayeAuthentication.prototype.signMessage = function(message, callback) {
|
|
42
42
|
}
|
43
43
|
|
44
44
|
FayeAuthentication.prototype.outgoing = function(message, callback) {
|
45
|
-
if (message
|
45
|
+
if (this.authentication_required(message))
|
46
46
|
this.signMessage(message, callback);
|
47
|
-
}
|
48
|
-
else if (!/^\/meta\/(.*)/.test(message.channel)) { // Publish
|
49
|
-
this.signMessage(message, callback);
|
50
|
-
}
|
51
47
|
else
|
52
48
|
callback(message);
|
53
49
|
};
|
54
50
|
|
51
|
+
FayeAuthentication.prototype.authentication_required = function(message) {
|
52
|
+
var subscription_or_channel = message.subscription || message.channel
|
53
|
+
return (!this.public_channel(subscription_or_channel) && (message.channel == '/meta/subscribe' || message.channel.lastIndexOf('/meta/', 0) !== 0))
|
54
|
+
};
|
55
|
+
|
56
|
+
FayeAuthentication.prototype.public_channel = function(channel) {
|
57
|
+
if (channel.lastIndexOf('/public/', 0) === 0) {
|
58
|
+
return (channel.indexOf('*') == -1);
|
59
|
+
} else {
|
60
|
+
return (false);
|
61
|
+
}
|
62
|
+
};
|
63
|
+
|
55
64
|
FayeAuthentication.prototype.incoming = function(message, callback) {
|
56
65
|
var outbox_message = this._outbox[message.id];
|
57
66
|
if (outbox_message && message.error) {
|
@@ -8,7 +8,7 @@ module Faye
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def outgoing(message, callback)
|
11
|
-
if
|
11
|
+
if Faye::Authentication.authentication_required?(message)
|
12
12
|
message['signature'] = Faye::Authentication.sign({channel: message['subscription'] || message['channel'], clientId: message['clientId']}, @secret, @options)
|
13
13
|
end
|
14
14
|
callback.call(message)
|
@@ -10,7 +10,7 @@ module Faye
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def incoming(message, callback)
|
13
|
-
if
|
13
|
+
if Faye::Authentication.authentication_required?(message)
|
14
14
|
begin
|
15
15
|
Faye::Authentication.validate(message['signature'],
|
16
16
|
message['subscription'] || message['channel'],
|
data/lib/faye/authentication.rb
CHANGED
@@ -31,5 +31,15 @@ module Faye
|
|
31
31
|
raise PayloadError unless channel == payload['channel'] && clientId == payload['clientId']
|
32
32
|
true
|
33
33
|
end
|
34
|
+
|
35
|
+
def self.authentication_required?(message)
|
36
|
+
subscription_or_channel = message['subscription'] || message['channel']
|
37
|
+
!public_channel?(subscription_or_channel) && (message['channel'] == '/meta/subscribe' || (!(message['channel'].start_with?('/meta/'))))
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.public_channel?(channel)
|
41
|
+
channel.start_with?('/public/') and not channel.include?('*')
|
42
|
+
end
|
43
|
+
|
34
44
|
end
|
35
45
|
end
|
@@ -17,8 +17,8 @@ describe('faye-authentication', function() {
|
|
17
17
|
describe('extension', function() {
|
18
18
|
beforeEach(function() {
|
19
19
|
jasmine.Ajax.install();
|
20
|
-
this.auth = new FayeAuthentication();
|
21
20
|
this.client = new Faye.Client('http://localhost:9296/faye');
|
21
|
+
this.auth = new FayeAuthentication(this.client);
|
22
22
|
this.client.addExtension(this.auth);
|
23
23
|
});
|
24
24
|
|
@@ -118,35 +118,25 @@ describe('faye-authentication', function() {
|
|
118
118
|
}, 500);
|
119
119
|
});
|
120
120
|
|
121
|
-
it('should make only one ajax call when dealing with one channel', function(done) {
|
122
|
-
this.client.subscribe('/foobar');
|
123
|
-
this.client.publish('/foobar', {text: 'hallo'});
|
124
|
-
this.client.publish('/foobar', {text: 'hallo'});
|
125
121
|
|
126
|
-
|
127
|
-
|
128
|
-
done();
|
129
|
-
}, 500);
|
130
|
-
|
131
|
-
})
|
132
|
-
|
133
|
-
it('should make two ajax calls when dealing with two channels', function(done) {
|
134
|
-
this.client.subscribe('/foo');
|
135
|
-
this.client.publish('/foo', {text: 'hallo'});
|
136
|
-
this.client.publish('/foo', {text: 'hallo'});
|
122
|
+
it('does not add the signature to a public message', function(done) {
|
123
|
+
var self = this;
|
137
124
|
|
138
|
-
this.client.
|
139
|
-
|
140
|
-
|
125
|
+
this.client.handshake(function() {
|
126
|
+
self.client._transport = self.fake_transport
|
127
|
+
self.client.publish('/public/foo', {text: 'hallo'});
|
128
|
+
}, this.client);
|
141
129
|
|
142
130
|
setTimeout(function() {
|
143
|
-
|
131
|
+
var calls = self.fake_transport.send.calls.all();
|
132
|
+
var last_call = calls[calls.length - 1];
|
133
|
+
var message = last_call.args[0].message;
|
134
|
+
expect(message.channel).toBe('/public/foo');
|
135
|
+
expect(message.signature).toBe(undefined);
|
144
136
|
done();
|
145
137
|
}, 500);
|
146
138
|
});
|
147
|
-
});
|
148
139
|
|
140
|
+
});
|
149
141
|
});
|
150
|
-
|
151
|
-
|
152
|
-
})
|
142
|
+
});
|
@@ -59,6 +59,33 @@ describe('Faye extension', function() {
|
|
59
59
|
});
|
60
60
|
});
|
61
61
|
|
62
|
+
it('should make only one ajax call when dealing with one channel', function(done) {
|
63
|
+
this.client.subscribe('/foobar');
|
64
|
+
this.client.publish('/foobar', {text: 'hallo'});
|
65
|
+
this.client.publish('/foobar', {text: 'hallo'});
|
66
|
+
|
67
|
+
setTimeout(function() {
|
68
|
+
expect(jasmine.Ajax.requests.count()).toBe(2); // Handshake + auth * 1
|
69
|
+
done();
|
70
|
+
}, 500);
|
71
|
+
|
72
|
+
})
|
73
|
+
|
74
|
+
it('should make two ajax calls when dealing with two channels', function(done) {
|
75
|
+
this.client.subscribe('/foobar');
|
76
|
+
this.client.publish('/foobar', {text: 'hallo'});
|
77
|
+
this.client.publish('/foobar', {text: 'hallo'});
|
78
|
+
|
79
|
+
this.client.subscribe('/bar');
|
80
|
+
this.client.publish('/bar', {text: 'hallo'});
|
81
|
+
this.client.publish('/bar', {text: 'hallo'});
|
82
|
+
|
83
|
+
setTimeout(function() {
|
84
|
+
expect(jasmine.Ajax.requests.count()).toBe(3); // Handshake + auth * 2
|
85
|
+
done();
|
86
|
+
}, 500);
|
87
|
+
});
|
88
|
+
|
62
89
|
it('tries to get a new signature immediately when the used signature is bad or expired', function(done) {
|
63
90
|
jasmine.Ajax.stubRequest('/faye/auth').andReturn({
|
64
91
|
'responseText': '{"signature": "bad"}'
|
@@ -6,32 +6,65 @@ describe Faye::Authentication::ServerExtension do
|
|
6
6
|
let(:secret) { 'macaroni' }
|
7
7
|
let(:extension) { Faye::Authentication::ServerExtension.new(secret) }
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
describe '#incoming' do
|
10
|
+
shared_examples 'signature_has_error' do
|
11
|
+
it 'adds an error' do
|
12
|
+
subject
|
13
|
+
expect(@result).to have_key('error')
|
14
|
+
end
|
15
|
+
end
|
13
16
|
|
14
|
-
|
17
|
+
shared_examples 'signature_has_no_error' do
|
18
|
+
it 'adds no error' do
|
19
|
+
subject
|
20
|
+
expect(@result).to_not have_key('error')
|
21
|
+
end
|
22
|
+
end
|
15
23
|
|
16
|
-
|
24
|
+
shared_examples 'authentication_actions' do
|
25
|
+
context 'not signed' do
|
26
|
+
context '/public' do
|
27
|
+
context 'no globbing' do
|
28
|
+
let(:channel) { '/public/foo' }
|
29
|
+
it_should_behave_like 'signature_has_no_error'
|
30
|
+
end
|
17
31
|
|
18
|
-
|
19
|
-
|
32
|
+
context 'globbing' do
|
33
|
+
let(:channel) { '/public/foo/*'}
|
34
|
+
it_should_behave_like 'signature_has_error'
|
35
|
+
end
|
36
|
+
end
|
20
37
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
38
|
+
context 'not public' do
|
39
|
+
context 'not signed' do
|
40
|
+
let(:channel) { '/whatever' }
|
41
|
+
it_should_behave_like 'signature_has_error'
|
42
|
+
end
|
25
43
|
|
26
|
-
|
27
|
-
|
44
|
+
context 'signed' do
|
45
|
+
let(:channel) { '/foo/bar' }
|
46
|
+
before { message['signature'] = Faye::Authentication.sign(message.merge({'channel' => channel}), secret) }
|
47
|
+
it_should_behave_like 'signature_has_no_error'
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
28
53
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
54
|
+
let(:message) { {'channel' => channel, 'clientId' => '42', 'text' => 'whatever'} }
|
55
|
+
subject do
|
56
|
+
extension.incoming(message, ->(m) { @result = m });
|
57
|
+
end
|
33
58
|
|
34
|
-
|
59
|
+
context 'publish' do
|
60
|
+
it_should_behave_like 'authentication_actions'
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'subscribe' do
|
64
|
+
before { message['channel'] = '/meta/subscribe'}
|
65
|
+
before { message['subscription'] = channel}
|
66
|
+
it_should_behave_like 'authentication_actions'
|
67
|
+
end
|
35
68
|
end
|
36
69
|
|
37
70
|
['/meta/handshake', '/meta/connect', '/meta/unsubscribe', '/meta/disconnect'].each do |channel|
|
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: 0.
|
4
|
+
version: 0.4.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-
|
11
|
+
date: 2014-07-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jwt
|