faye-authentication 0.1.0 → 0.2.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 +5 -0
- data/README.md +43 -32
- data/app/assets/javascripts/faye-authentication.js +22 -7
- data/faye-authentication.gemspec +3 -1
- data/lib/faye/authentication/extension.rb +17 -8
- data/lib/faye/authentication/http_client.rb +2 -1
- data/lib/faye/authentication/version.rb +1 -1
- data/lib/faye/authentication.rb +20 -18
- data/spec/javascripts/faye-authentication_spec.js +2 -3
- data/spec/javascripts/faye-extension_spec.js +35 -5
- data/spec/javascripts/support/jasmine_helper.rb +2 -0
- data/spec/lib/faye/authentication/http_client_spec.rb +2 -1
- data/spec/lib/faye/authentication_spec.rb +44 -10
- data/spec/utils/javascripts/jwt.js +2249 -0
- data/spec/utils/javascripts/query-string.js +66 -0
- metadata +23 -6
- data/spec/utils/javascripts/hmac.js +0 -131
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 184e59a30a70d8300c56d55355689fc266f4c1d8
|
4
|
+
data.tar.gz: e27e148c68384f0f1f8d74cec6e7bbd92769dd51
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62c1b8a62630230868e2f748219970745e72a868dcafdc3de4112c82f25a25e4ee0f7de829caa7b7e85fdf017040287b13d7ce6b47495a9475f3aa6f772a0c81
|
7
|
+
data.tar.gz: 8dd4d44413f43949c21512b3932f3f06659ee1ff5193eed99c5ef75cba04218b68dfafcb33042b9af251d1169bf984538d6e29e4b2b4e255e3d4c735e37060f3
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -1,19 +1,25 @@
|
|
1
|
-
# Faye::Authentication [![Build Status](https://travis-ci.org/
|
1
|
+
# Faye::Authentication [![Build Status](https://travis-ci.org/dimelo/faye-authentication.svg?branch=master)](https://travis-ci.org/dimelo/faye-authentication) [![Code Climate](https://codeclimate.com/github/dimelo/faye-authentication.png)](https://codeclimate.com/github/dimelo/faye-authentication)
|
2
2
|
|
3
3
|
Authentification implementation for faye
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
- Ruby utils for signing messages
|
9
|
-
- **Want another one ? Pull requests are welcome.**
|
5
|
+
## Principle
|
6
|
+
|
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.
|
10
8
|
|
11
|
-
|
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.
|
12
10
|
|
13
|
-
|
11
|
+
This signature is required and valid for each channel and client id tupple and rely on JWT for security.
|
14
12
|
|
15
|
-
|
16
|
-
|
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.
|
15
|
+
|
16
|
+
## Current support
|
17
|
+
|
18
|
+
Currently Implemented :
|
19
|
+
- Javascript Client Extention (JQuery needed)
|
20
|
+
- Ruby Faye Server Extension
|
21
|
+
- Ruby utils to signing messages in your webapp
|
22
|
+
- **Want another one ? Pull requests are welcome.**
|
17
23
|
|
18
24
|
## Installation
|
19
25
|
|
@@ -31,26 +37,9 @@ Or install it yourself as:
|
|
31
37
|
|
32
38
|
## Usage
|
33
39
|
|
34
|
-
###
|
35
|
-
|
36
|
-
Add the extension to your faye client :
|
37
|
-
|
38
|
-
````javascript
|
39
|
-
var client = new Faye.Client('http://my.server/faye');
|
40
|
-
client.add_extension(new FayeAuthentication());
|
41
|
-
````
|
42
|
-
|
43
|
-
By default, when sending a subscribe request or publishing a message, the extension
|
44
|
-
will issue an AJAX request to ``/faye/auth``
|
45
|
-
|
46
|
-
If you wish to change the endpoint, you can supply it as the first argument of the extension constructor :
|
40
|
+
### Authentication endpoint requirements
|
47
41
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
### Ruby utils
|
52
|
-
|
53
|
-
The endpoint will a POST request, and shall return a JSON hash with a ``signature`` key.
|
42
|
+
The endpoint will receive a POST request, and shall return a JSON hash with a ``signature`` key.
|
54
43
|
|
55
44
|
The parameters sent to the endpoint are the following :
|
56
45
|
|
@@ -73,7 +62,7 @@ Example (For a Rails application)
|
|
73
62
|
````ruby
|
74
63
|
def auth
|
75
64
|
if current_user.can?(:read, params[:message][:channel])
|
76
|
-
render json: {signature: Faye::Authentication.sign(params[:message], 'your
|
65
|
+
render json: {signature: Faye::Authentication.sign(params[:message].slice(:channel,:clientId), 'your shared secret key')}
|
77
66
|
else
|
78
67
|
render json: {error: 'Not authorized'}, status: 403
|
79
68
|
end
|
@@ -85,8 +74,23 @@ A Ruby HTTP Client is also available for publishing messages to your faye server
|
|
85
74
|
without the hassle of using EventMachine :
|
86
75
|
|
87
76
|
````ruby
|
88
|
-
Faye::Authentication::HTTPClient.publish('/channel', 'data', 'your private key')
|
77
|
+
Faye::Authentication::HTTPClient.publish('http://localhost:9290/faye', '/channel', 'data', 'your private key')
|
89
78
|
````
|
79
|
+
### Javascript client extension
|
80
|
+
|
81
|
+
Add the extension to your faye client :
|
82
|
+
|
83
|
+
````javascript
|
84
|
+
var client = new Faye.Client('http://my.server/faye');
|
85
|
+
client.addExtension(new FayeAuthentication(client));
|
86
|
+
````
|
87
|
+
|
88
|
+
By default, when sending a subscribe request or publishing a message, the extension
|
89
|
+
will issue an AJAX request to ``/faye/auth``
|
90
|
+
|
91
|
+
If you wish to change the endpoint, you can supply it as the second argument of the extension constructor, the first one being the client :
|
92
|
+
|
93
|
+
client.addExtension(new FayeAuthentication(client, '/my_custom_auth_endpoint'));
|
90
94
|
|
91
95
|
### Faye server extension
|
92
96
|
|
@@ -94,9 +98,16 @@ Instanciate the extension with your secret key and add it to the server :
|
|
94
98
|
|
95
99
|
````ruby
|
96
100
|
server = Faye::RackAdapter.new(:mount => '/faye', :timeout => 15)
|
97
|
-
server.add_extension Faye::Authentication::Extension.new('your
|
101
|
+
server.add_extension Faye::Authentication::Extension.new('your shared secret key')
|
98
102
|
````
|
99
103
|
|
104
|
+
Faye::Authentication::Extension expect that :
|
105
|
+
- a ``signature`` is present in the message for publish/subscribe request
|
106
|
+
- this signature is a valid JWT token
|
107
|
+
- the JWT payload contains "channel", "clientId" and a expiration timestamp "exp" that is not in the past.
|
108
|
+
|
109
|
+
Otherwise Faye Server will refuse the message.
|
110
|
+
|
100
111
|
## Contributing
|
101
112
|
|
102
113
|
1. Fork it ( https://github.com/dimelo/faye-authentication/fork )
|
@@ -1,6 +1,8 @@
|
|
1
|
-
function FayeAuthentication(endpoint) {
|
1
|
+
function FayeAuthentication(client, endpoint) {
|
2
|
+
this._client = client;
|
2
3
|
this._endpoint = endpoint || '/faye/auth';
|
3
4
|
this._signatures = {};
|
5
|
+
this._outbox = {};
|
4
6
|
}
|
5
7
|
|
6
8
|
FayeAuthentication.prototype.endpoint = function() {
|
@@ -11,15 +13,17 @@ FayeAuthentication.prototype.signMessage = function(message, callback) {
|
|
11
13
|
var channel = message.subscription || message.channel;
|
12
14
|
var clientId = message.clientId;
|
13
15
|
|
16
|
+
var self = this;
|
14
17
|
if (!this._signatures[clientId])
|
15
18
|
this._signatures[clientId] = {};
|
16
19
|
if (this._signatures[clientId][channel]) {
|
17
20
|
this._signatures[clientId][channel].then(function(signature) {
|
18
21
|
message.signature = signature;
|
22
|
+
if (!message.retried)
|
23
|
+
self._outbox[message.id] = {message: message, clientId: clientId};
|
19
24
|
callback(message);
|
20
25
|
});
|
21
26
|
} else {
|
22
|
-
var self = this;
|
23
27
|
self._signatures[clientId][channel] = new Faye.Promise(function(success, failure) {
|
24
28
|
$.post(self.endpoint(), {message: {channel: channel, clientId: clientId}}, function(response) {
|
25
29
|
success(response.signature);
|
@@ -29,16 +33,19 @@ FayeAuthentication.prototype.signMessage = function(message, callback) {
|
|
29
33
|
});
|
30
34
|
self._signatures[clientId][channel].then(function(signature) {
|
31
35
|
message.signature = signature;
|
36
|
+
if (!message.retried){
|
37
|
+
self._outbox[message.id] = {message: message, clientId: clientId};
|
38
|
+
}
|
32
39
|
callback(message);
|
33
40
|
});
|
34
41
|
}
|
35
42
|
}
|
36
43
|
|
37
44
|
FayeAuthentication.prototype.outgoing = function(message, callback) {
|
38
|
-
if (message.channel
|
45
|
+
if (message.channel == '/meta/subscribe') {
|
39
46
|
this.signMessage(message, callback);
|
40
47
|
}
|
41
|
-
else if (
|
48
|
+
else if (!/^\/meta\/(.*)/.test(message.channel)) { // Publish
|
42
49
|
this.signMessage(message, callback);
|
43
50
|
}
|
44
51
|
else
|
@@ -46,7 +53,15 @@ FayeAuthentication.prototype.outgoing = function(message, callback) {
|
|
46
53
|
};
|
47
54
|
|
48
55
|
FayeAuthentication.prototype.incoming = function(message, callback) {
|
49
|
-
|
50
|
-
|
51
|
-
|
56
|
+
var outbox_message = this._outbox[message.id];
|
57
|
+
if (outbox_message && message.error) {
|
58
|
+
var channel = outbox_message.message.subscription || outbox_message.message.channel;
|
59
|
+
this._signatures[outbox_message.clientId][channel] = null;
|
60
|
+
outbox_message.message.retried = true;
|
61
|
+
delete outbox_message.message.id;
|
62
|
+
delete this._outbox[message.id];
|
63
|
+
this._client._send(outbox_message.message, callback);
|
64
|
+
}
|
65
|
+
else
|
66
|
+
callback(message);
|
52
67
|
};
|
data/faye-authentication.gemspec
CHANGED
@@ -18,9 +18,11 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
+
spec.add_runtime_dependency 'jwt', '~> 1'
|
22
|
+
|
21
23
|
spec.add_development_dependency "bundler", "~> 1.5"
|
22
24
|
spec.add_development_dependency "rake", '~> 10.3'
|
23
|
-
spec.add_development_dependency 'rspec', '~> 3.0
|
25
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
24
26
|
spec.add_development_dependency 'jasmine', '~> 2.0'
|
25
27
|
spec.add_development_dependency 'faye', '~> 1.0'
|
26
28
|
spec.add_development_dependency 'rack', '~> 1.5'
|
@@ -1,24 +1,33 @@
|
|
1
|
+
require 'faye'
|
2
|
+
|
1
3
|
module Faye
|
2
4
|
module Authentication
|
3
5
|
class Extension
|
6
|
+
include Faye::Logging
|
4
7
|
|
5
8
|
def initialize(secret)
|
6
|
-
@secret = secret
|
9
|
+
@secret = secret.to_s
|
7
10
|
end
|
8
11
|
|
9
12
|
def incoming(message, callback)
|
10
13
|
if message['channel'] == '/meta/subscribe' || !(message['channel'] =~ /^\/meta\/.*/)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
begin
|
15
|
+
Faye::Authentication.validate(message['signature'],
|
16
|
+
message['subscription'] || message['channel'],
|
17
|
+
message['clientId'],
|
18
|
+
@secret)
|
19
|
+
debug("Authentication sucessful")
|
20
|
+
rescue AuthError => exception
|
21
|
+
message['error'] = case exception
|
22
|
+
when ExpiredError then 'Expired signature'
|
23
|
+
when PayloadError then 'Required argument not signed'
|
24
|
+
else 'Invalid signature'
|
25
|
+
end
|
26
|
+
debug("Authentication failed: #{message['error']}")
|
17
27
|
end
|
18
28
|
end
|
19
29
|
callback.call(message)
|
20
30
|
end
|
21
|
-
|
22
31
|
end
|
23
32
|
end
|
24
33
|
end
|
@@ -7,8 +7,9 @@ module Faye
|
|
7
7
|
def self.publish(url, channel, data, key)
|
8
8
|
uri = URI(url)
|
9
9
|
req = Net::HTTP::Post.new(url)
|
10
|
-
message = {'channel' => channel, '
|
10
|
+
message = {'channel' => channel, 'clientId' => 'http'}
|
11
11
|
message['signature'] = Faye::Authentication.sign(message, key)
|
12
|
+
message['data'] = data
|
12
13
|
req.set_form_data(message: JSON.dump(message))
|
13
14
|
Net::HTTP.start(uri.hostname, uri.port, :use_ssl => uri.scheme == 'https') { |http| http.request(req) }
|
14
15
|
end
|
data/lib/faye/authentication.rb
CHANGED
@@ -1,32 +1,34 @@
|
|
1
|
-
require
|
1
|
+
require 'jwt'
|
2
|
+
require 'faye/authentication/version'
|
2
3
|
require 'faye/authentication/extension'
|
3
4
|
require 'faye/authentication/http_client'
|
4
5
|
require 'faye/authentication/engine'
|
5
6
|
|
6
7
|
module Faye
|
7
8
|
module Authentication
|
9
|
+
class AuthError < StandardError; end
|
10
|
+
class ExpiredError < AuthError; end
|
11
|
+
class PayloadError < AuthError; end
|
8
12
|
|
9
|
-
|
10
|
-
|
13
|
+
# Return jwt signature, pass hash of payload including channel and client_id
|
14
|
+
def self.sign(payload, secret, options = {})
|
15
|
+
options = {expires_at: Time.now + 12*3600, algorithm: 'HS256'}.merge(options)
|
16
|
+
JWT.encode(payload.merge(exp: options[:expires_at].to_i), secret, options[:algorithm])
|
11
17
|
end
|
12
18
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
19
|
+
# Return signed payload or raise
|
20
|
+
def self.decode(signature, secret)
|
21
|
+
payload, _ = JWT.decode(signature, secret) rescue raise(AuthError)
|
22
|
+
raise ExpiredError if Time.at(payload['exp'].to_i) < Time.now
|
23
|
+
payload
|
17
24
|
end
|
18
25
|
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
res = 0
|
27
|
-
b.each_byte { |byte| res |= byte ^ l.shift }
|
28
|
-
res == 0
|
26
|
+
# Return true if signature is valid and correspond to channel and clientId or raise
|
27
|
+
def self.validate(signature, channel, clientId, secret)
|
28
|
+
payload = self.decode(signature, secret)
|
29
|
+
raise PayloadError if channel.to_s.empty? || clientId.to_s.empty?
|
30
|
+
raise PayloadError unless channel == payload['channel'] && clientId == payload['clientId']
|
31
|
+
true
|
29
32
|
end
|
30
|
-
|
31
33
|
end
|
32
34
|
end
|
@@ -3,12 +3,12 @@ describe('faye-authentication', function() {
|
|
3
3
|
describe('constructor', function() {
|
4
4
|
|
5
5
|
it('sets endpoint to /faye by default', function() {
|
6
|
-
var auth = new FayeAuthentication();
|
6
|
+
var auth = new FayeAuthentication(new Faye.Client('http://example.com'));
|
7
7
|
expect(auth.endpoint()).toBe('/faye/auth');
|
8
8
|
});
|
9
9
|
|
10
10
|
it('can specify a custom endpoint', function() {
|
11
|
-
var auth = new FayeAuthentication('/custom');
|
11
|
+
var auth = new FayeAuthentication(new Faye.Client('http://example.com'), '/custom');
|
12
12
|
expect(auth.endpoint()).toBe('/custom');
|
13
13
|
});
|
14
14
|
|
@@ -41,7 +41,6 @@ describe('faye-authentication', function() {
|
|
41
41
|
var self = this;
|
42
42
|
setTimeout(function() {
|
43
43
|
var request = jasmine.Ajax.requests.mostRecent();
|
44
|
-
console.log(request);
|
45
44
|
expect(request.data()['message[channel]'][0]).toBe('/foobar');
|
46
45
|
done();
|
47
46
|
}, 500);
|
@@ -24,14 +24,15 @@ describe('Faye extension', function() {
|
|
24
24
|
|
25
25
|
describe('With extension', function() {
|
26
26
|
beforeEach(function() {
|
27
|
-
this.extension = new FayeAuthentication();
|
27
|
+
this.extension = new FayeAuthentication(this.client);
|
28
28
|
this.client.addExtension(this.extension);
|
29
29
|
});
|
30
30
|
|
31
31
|
function stubSignature(context, callback) {
|
32
32
|
var self = context;
|
33
33
|
self.client.handshake(function() {
|
34
|
-
var
|
34
|
+
var jwtsign = new jwt.WebToken('{"clientId": "' + self.client._clientId + '", "channel": "/foobar", "exp": 2803694528}', '{"alg": "HS256"}');
|
35
|
+
var signature = jwtsign.serialize("macaroni");
|
35
36
|
|
36
37
|
jasmine.Ajax.stubRequest('/faye/auth').andReturn({
|
37
38
|
'responseText': '{"signature": "' + signature + '"}'
|
@@ -58,17 +59,46 @@ describe('Faye extension', function() {
|
|
58
59
|
});
|
59
60
|
});
|
60
61
|
|
61
|
-
it('
|
62
|
-
this.extension._signatures = {'123': []};
|
62
|
+
it('tries to get a new signature immediately when the used signature is bad or expired', function(done) {
|
63
63
|
jasmine.Ajax.stubRequest('/faye/auth').andReturn({
|
64
64
|
'responseText': '{"signature": "bad"}'
|
65
65
|
});
|
66
66
|
var self = this;
|
67
67
|
this.client.subscribe('/toto').then(undefined, function() {
|
68
|
-
expect(
|
68
|
+
expect(jasmine.Ajax.requests.count()).toBe(3); // Handshake + auth * 2
|
69
69
|
done();
|
70
70
|
});
|
71
|
+
});
|
72
|
+
|
73
|
+
it('calls the success callback for a successfully retried message', function(done) {
|
74
|
+
|
75
|
+
this.client.subscribe('/foo').then(function() {
|
76
|
+
expect(jasmine.Ajax.requests.count()).toBe(3); // Handshake + auth * 2
|
77
|
+
done();
|
78
|
+
}, function(e) { console.log(e)});
|
79
|
+
|
80
|
+
setTimeout(function() {
|
81
|
+
var request = jasmine.Ajax.requests.mostRecent();
|
82
|
+
var params = queryString.parse(request.params);
|
83
|
+
|
84
|
+
var jwtsign_bad = new jwt.WebToken('{"clientId": "' + params['message[clientId]'] + '", "channel": "/foo", "exp": 1}', '{"alg": "HS256"}');
|
85
|
+
var signature_bad = jwtsign_bad.serialize("macaroni");
|
86
|
+
|
87
|
+
var jwtsign_good = new jwt.WebToken('{"clientId": "' + params['message[clientId]'] + '", "channel": "/foo", "exp": 2803694528}', '{"alg": "HS256"}');
|
88
|
+
var signature_good = jwtsign_good.serialize("macaroni");
|
89
|
+
|
90
|
+
request.response({
|
91
|
+
'status' : 200,
|
92
|
+
'responseText': '{"signature": "' + signature_bad + '"}'
|
93
|
+
});
|
94
|
+
|
95
|
+
jasmine.Ajax.stubRequest('/faye/auth').andReturn({
|
96
|
+
'responseText': '{"signature": "' + signature_good + '"}'
|
97
|
+
});
|
98
|
+
|
99
|
+
}, 1000);
|
71
100
|
|
72
101
|
});
|
102
|
+
|
73
103
|
});
|
74
104
|
});
|
@@ -19,6 +19,8 @@ FAYE_SECRET_KEY = 'macaroni'
|
|
19
19
|
fork do
|
20
20
|
Faye::WebSocket.load_adapter('thin')
|
21
21
|
faye = Faye::RackAdapter.new(:mount => '/faye')
|
22
|
+
#require 'logger'
|
23
|
+
#Faye.logger = Logger.new(STDOUT)
|
22
24
|
faye.add_extension Faye::Authentication::Extension.new(FAYE_SECRET_KEY)
|
23
25
|
Rack::Handler::Thin.run faye, :Port => 9296
|
24
26
|
end.tap do |id|
|
@@ -6,8 +6,9 @@ describe Faye::Authentication::HTTPClient do
|
|
6
6
|
describe '.publish' do
|
7
7
|
|
8
8
|
it 'should publish a HTTP request with correct params' do
|
9
|
-
message = {'channel' => '/foo/bar', '
|
9
|
+
message = {'channel' => '/foo/bar', 'clientId' => 'http'}
|
10
10
|
message['signature'] = Faye::Authentication.sign(message, 'my private key')
|
11
|
+
message['data'] = 'hello'
|
11
12
|
request = stub_request(:post, "http://www.example.com").with(:body => {:message => JSON.dump(message)}).to_return(:status => 200, :body => "", :headers => {})
|
12
13
|
Faye::Authentication::HTTPClient.publish('http://www.example.com', '/foo/bar', "hello", 'my private key')
|
13
14
|
expect(request).to have_been_made
|
@@ -3,21 +3,55 @@ require 'faye/authentication'
|
|
3
3
|
|
4
4
|
describe Faye::Authentication do
|
5
5
|
|
6
|
+
let(:channel) { '/foo/bar' }
|
7
|
+
let(:clientId) { '42' }
|
8
|
+
let(:message) { {'channel' => channel, 'clientId' => clientId, 'text' => 'whatever'} }
|
6
9
|
let(:secret) { 'helloworld' }
|
10
|
+
let(:signature) { Faye::Authentication.sign(message, secret) }
|
11
|
+
|
12
|
+
describe '#sign' do
|
13
|
+
it 'returns with a default expiry'
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#decode' do
|
17
|
+
it 'returns the payload if the message is correctly signed' do
|
18
|
+
expect(Faye::Authentication.decode(signature, secret)).to include(message)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'raises error if the message if keys differ' do
|
22
|
+
expect { Faye::Authentication.decode(signature, secret + 'foo') }.to raise_error(Faye::Authentication::AuthError)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'raises error if the expiry is in the past' do
|
26
|
+
signature = Faye::Authentication.sign(message, secret, expires_at: Time.now - 1)
|
27
|
+
expect { Faye::Authentication.decode(signature, secret) }.to raise_error(Faye::Authentication::ExpiredError)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'return the payload if the expiry is in the future' do
|
31
|
+
signature = Faye::Authentication.sign(message, secret, expires_at: Time.now + 10)
|
32
|
+
expect { Faye::Authentication.decode(signature, secret) }.not_to raise_error
|
33
|
+
end
|
34
|
+
end
|
7
35
|
|
8
|
-
describe '#
|
36
|
+
describe '#validate' do
|
9
37
|
it 'returns true if the message is correctly signed' do
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
38
|
+
expect(Faye::Authentication.validate(signature, channel, clientId, secret)).to be(true)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'raises if the channel differs' do
|
42
|
+
expect { Faye::Authentication.validate(signature, channel + '1', clientId, secret) }.to raise_error(Faye::Authentication::PayloadError)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'raises if the channel is not defined' do
|
46
|
+
expect { Faye::Authentication.validate(signature, '', clientId, secret) }.to raise_error(Faye::Authentication::PayloadError)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'raises if the channel differs' do
|
50
|
+
expect { Faye::Authentication.validate(signature, channel, clientId + '1', secret) }.to raise_error(Faye::Authentication::PayloadError)
|
14
51
|
end
|
15
52
|
|
16
|
-
it '
|
17
|
-
|
18
|
-
signature = Faye::Authentication.sign(message, secret)
|
19
|
-
message['signature'] = signature
|
20
|
-
expect(Faye::Authentication.valid?(message, secret + 'foo')).to be(false)
|
53
|
+
it 'raises if the channel is not defined' do
|
54
|
+
expect { Faye::Authentication.validate(signature, channel, nil, secret) }.to raise_error(Faye::Authentication::PayloadError)
|
21
55
|
end
|
22
56
|
end
|
23
57
|
|