From 0fba591c5cd51b9e88b2b36593bffaa04a29e31a Mon Sep 17 00:00:00 2001 From: Emmanuel Chigbo Date: Wed, 25 May 2016 16:06:46 +0100 Subject: [PATCH 1/3] Add JWT validation to for the engine - notification validation --- app/services/token_manager.rb | 3 +- app/workers/notification_system_worker.rb | 4 +- spec/services/token_manager_spec.rb | 59 ++++++++++++++++------- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/app/services/token_manager.rb b/app/services/token_manager.rb index 4378357..d9090f2 100644 --- a/app/services/token_manager.rb +++ b/app/services/token_manager.rb @@ -2,8 +2,9 @@ class TokenManager class << self - def generate_token(user_id, exp = 24.hours.from_now) + def generate_token(user_id, exp = 24.hours.from_now, notify_object = nil) payload = { user: user_id, exp: exp.to_i } + payload = { object: notify_object, exp: exp.to_i } if notify_object issue_token(payload) end diff --git a/app/workers/notification_system_worker.rb b/app/workers/notification_system_worker.rb index 86c4ef7..b1ed7a2 100644 --- a/app/workers/notification_system_worker.rb +++ b/app/workers/notification_system_worker.rb @@ -7,6 +7,8 @@ class NotificationSystemWorker def perform(klass, object_id) object = klass.constantize.find(object_id).object_for_notification - ZiNotification::Client.post(Endpoints[:new_resource], object) + token = TokenManager.generate_token(nil, 5.minutes.from_now, object) + options = { object: object, json_token: token } + ZiNotification::Client.post(Endpoints[:new_resource], options) end end diff --git a/spec/services/token_manager_spec.rb b/spec/services/token_manager_spec.rb index 99cef53..832aaa8 100644 --- a/spec/services/token_manager_spec.rb +++ b/spec/services/token_manager_spec.rb @@ -5,33 +5,56 @@ let(:user){ create(:user) } describe ".generate_token" do - let(:token){ subject.generate_token(user.id) } - - it 'generates a valid token' do - expect(token.split('.').count).to eq 3 - expect{subject.decode(token)}.not_to raise_error + describe 'arguments' do + it 'throws argument error if no arg is provided' do + expect{ subject.generate_token }.to raise_error ArgumentError + end end - describe 'token expiration' do - it 'sets expiration time to 24hrs by default' do - decoded = subject.decode(token) - expect(decoded.first['exp']).to eql 24.hours.from_now.to_i + context "when generating token for a user" do + let(:token){ subject.generate_token(user.id) } + + it 'generates a valid token' do + expect(token.split('.').count).to eq 3 + expect{subject.decode(token)}.not_to raise_error end - it 'sets expiration time to any time given' do - temp_token = subject.generate_token(user.id, 2.minutes.from_now) - decoded = subject.decode(temp_token) - expect(decoded.first['exp']).to eql 2.minutes.from_now.to_i - expect(decoded.first['exp']).not_to eql 24.hours.from_now.to_i + describe 'token expiration' do + it 'sets expiration time to 24hrs by default' do + decoded = subject.decode(token) + expect(decoded.first['exp']).to eql 24.hours.from_now.to_i + end + + it 'sets expiration time to any time given' do + temp_token = subject.generate_token(user.id, 2.minutes.from_now) + decoded = subject.decode(temp_token) + expect(decoded.first['exp']).to eql 2.minutes.from_now.to_i + expect(decoded.first['exp']).not_to eql 24.hours.from_now.to_i + end end end - describe 'arguments' do - it 'throws argument error if no arg is provided' do - expect{ subject.generate_token }.to raise_error ArgumentError + context "when generating token for notification" do + let(:object) { { "id" => 1, "title" => "sample object" } } + let(:token){ subject.generate_token(nil, 5.minutes.from_now, object) } + + it 'generates a valid token' do + expect(token.split('.').count).to eq 3 + expect{subject.decode(token)}.not_to raise_error end - end + describe 'token expiration' do + it 'sets expiration time to 5 minutes' do + decoded = subject.decode(token) + expect(decoded.first['exp']).to eql 5.minutes.from_now.to_i + end + + it 'sets the notification object' do + decoded = subject.decode(token) + expect(decoded.first['object']).to eql object + end + end + end end describe ".issue_token" do From bc317ce196387d42c11533924eb83f6a25943f65 Mon Sep 17 00:00:00 2001 From: Emmanuel Chigbo Date: Thu, 9 Jun 2016 12:33:25 +0100 Subject: [PATCH 2/3] Pass the JWT token through the header instead of the body --- app/services/token_manager.rb | 3 +-- app/workers/notification_system_worker.rb | 4 +--- lib/zi_notification/client.rb | 3 ++- lib/zi_notification/connection.rb | 7 +++++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/services/token_manager.rb b/app/services/token_manager.rb index d9090f2..de68d1d 100644 --- a/app/services/token_manager.rb +++ b/app/services/token_manager.rb @@ -3,8 +3,7 @@ class TokenManager class << self def generate_token(user_id, exp = 24.hours.from_now, notify_object = nil) - payload = { user: user_id, exp: exp.to_i } - payload = { object: notify_object, exp: exp.to_i } if notify_object + payload = { user: user_id, exp: exp.to_i, payload: notify_object } issue_token(payload) end diff --git a/app/workers/notification_system_worker.rb b/app/workers/notification_system_worker.rb index b1ed7a2..86c4ef7 100644 --- a/app/workers/notification_system_worker.rb +++ b/app/workers/notification_system_worker.rb @@ -7,8 +7,6 @@ class NotificationSystemWorker def perform(klass, object_id) object = klass.constantize.find(object_id).object_for_notification - token = TokenManager.generate_token(nil, 5.minutes.from_now, object) - options = { object: object, json_token: token } - ZiNotification::Client.post(Endpoints[:new_resource], options) + ZiNotification::Client.post(Endpoints[:new_resource], object) end end diff --git a/lib/zi_notification/client.rb b/lib/zi_notification/client.rb index f1a2b79..c5f1057 100644 --- a/lib/zi_notification/client.rb +++ b/lib/zi_notification/client.rb @@ -9,7 +9,8 @@ class << self end def request(http_method, path, options) - ZiNotification::Connection.connection.send(http_method, path, options) + token = TokenManager.generate_token(nil, 5.minutes.from_now, options) + ZiNotification::Connection.connection(token).send(http_method, path) end end end diff --git a/lib/zi_notification/connection.rb b/lib/zi_notification/connection.rb index a8f1939..43ed5d5 100644 --- a/lib/zi_notification/connection.rb +++ b/lib/zi_notification/connection.rb @@ -5,10 +5,13 @@ def self.endpoint ENV['ZI_NOTIFICATION_URL'] end - def self.connection + def self.connection(token) # NOTE we need to also add the authorization once implemented on notifications options = { - headers: { 'Accept' => 'application/json; charset=utf-8' } + headers: { + 'Accept' => 'application/json; charset=utf-8', + 'Authorization' => "Token token=#{token}" + } } ::Faraday::Connection.new(endpoint, options) do |connection| From a98e759dfbc9808e36ad5b457747d62a5f24b82b Mon Sep 17 00:00:00 2001 From: Emmanuel Chigbo Date: Thu, 9 Jun 2016 20:57:47 +0100 Subject: [PATCH 3/3] Modify the test to suit the modification in the code implementation --- spec/lib/zi_notification/connection_spec.rb | 4 ++-- spec/services/token_manager_spec.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/lib/zi_notification/connection_spec.rb b/spec/lib/zi_notification/connection_spec.rb index d3328fd..ed67a78 100644 --- a/spec/lib/zi_notification/connection_spec.rb +++ b/spec/lib/zi_notification/connection_spec.rb @@ -3,8 +3,8 @@ RSpec.describe ZiNotification::Connection do # NOTE If/when we want to switch adapter from Faraday, we only need to overide interfacing methods here describe ".connection" do - subject { described_class.connection } - + subject { described_class.connection('some.token') } + it { should be_an_instance_of Faraday::Connection } end diff --git a/spec/services/token_manager_spec.rb b/spec/services/token_manager_spec.rb index 832aaa8..035b5a9 100644 --- a/spec/services/token_manager_spec.rb +++ b/spec/services/token_manager_spec.rb @@ -51,7 +51,7 @@ it 'sets the notification object' do decoded = subject.decode(token) - expect(decoded.first['object']).to eql object + expect(decoded.first['payload']).to eql object end end end