master_api_key 1.2.0 → 2.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f75677aba0568a14af93356d92719e7bd4f9747
4
- data.tar.gz: c98007363459cb0f65fa503a5e5328035977d78d
3
+ metadata.gz: d0cff3200309d508ad6502fe55696994199253c0
4
+ data.tar.gz: 286d74139877380870179c6072da522cd264af71
5
5
  SHA512:
6
- metadata.gz: 03edcd5e444de7703abea5851f4bc9251d5862a3d08daa2acb74efcc7210cd20e2083eda3edc0cf51cbf25d520a6683f3de9ac5663ae606a0b8d3ac03528f3bf
7
- data.tar.gz: 6ecf94acdaeb3047f1522b69f12f3ce6dfd7d53a931cc5df323429cd4a290228bdfc384ff0000c5ee38caa5f8fa693816d20cb18a53c30c844eecc310e70312a
6
+ metadata.gz: aaf0adfc3781b6915d600519f73e128d5d28e9599a8b0b9731becee4bb91a767f4dd6da1d0aff50d5d1f3c5a25f48ee80bac65626cfa45821237c9c949543bc0
7
+ data.tar.gz: 209db5a8c3577db0533bae9843f4a228bfeabd59cb9bd44ba49bb8adf9f3030acd17fb34ef5cb768a580ba4ce12a8bd25bf127f6f6bae9e8449bc837691f2326
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -4,43 +4,92 @@ module MasterApiKey
4
4
  class ApiKeysController < ApplicationController
5
5
  belongs_to_api_group :master_key
6
6
  skip_before_filter :verify_authenticity_token
7
- before_filter :authorize_action
7
+ authorize_with :authorizers => [:write_authorizer], :only => [:update_by_access_token, :destroy_by_access_token]
8
8
 
9
- # POST /api_keys
9
+ rescue_from ActionController::ParameterMissing do |exception|
10
+ respond_with_error(exception.message, :bad_request)
11
+ end
12
+
13
+ rescue_from ArgumentError do |exception|
14
+ respond_with_error(exception.message, :bad_request)
15
+ end
16
+
17
+ #GET /api_keys
18
+ def index
19
+ found_api_key = ApiKey.find_by_api_token(access_token_param)
20
+
21
+ check_presence_before_action(found_api_key) do |api_key|
22
+ render json: { api_key: api_key}, status: :ok
23
+ end
24
+ end
25
+
26
+ #POST /api_keys
10
27
  def create
11
- begin
12
- @api_key = ApiKey.create! do |api_key|
13
- api_key.group = group_param
28
+ authorizers = authorizer_params
29
+ created_api_key = ApiKey.create! do |api_key|
30
+ api_key.group = group_param
31
+ unless authorizers.nil?
32
+ access_types = [TrueClass, FalseClass]
33
+ read_access = authorizers[:read_access]
34
+ write_access = authorizers[:write_access]
35
+ api_key.read_access = enforce_param_type(read_access, :read_access, *access_types) unless read_access.nil?
36
+ api_key.write_access = enforce_param_type(write_access, :write_access, *access_types) unless write_access.nil?
14
37
  end
15
- render json: { apiKey: @api_key}, status: :created
16
- rescue ActionController::ParameterMissing => e
17
- respond_with_error(e.message, :bad_request)
38
+ end
39
+
40
+ render json: { api_key: created_api_key}, status: :created
41
+ end
42
+
43
+ #PATCH /api_keys/
44
+ def update_by_access_token
45
+ updated_api_key = ApiKey.find_by_api_token(access_token_param)
46
+
47
+ check_presence_before_action(updated_api_key) do |api_key|
48
+ api_key.update_attributes(required_auth_params)
49
+ render json: { api_key: api_key}, status: :ok
18
50
  end
19
51
  end
20
52
 
21
53
  # DELETE /api_keys/1
54
+ #deprecated
22
55
  def destroy
23
- begin
24
- ApiKey.delete_all(['id = ?', access_id_param])
25
- head :ok
26
- rescue ActionController::ParameterMissing => e
27
- respond_with_error(e.message, :bad_request)
28
- end
56
+ ApiKey.delete_all(['id = ?', access_id_param])
57
+ message = 'This method has been deprecated since this is less secure than access by token. It will be removed in v2.0.0'
58
+ render text: message, status: :ok
29
59
  end
30
60
 
31
61
  # DELETE /api_keys
32
62
  def destroy_by_access_token
33
- begin
34
- Rails.logger.warn "the api token is #{access_token_param}"
35
- ApiKey.delete_all(['api_token = ?', access_token_param])
36
- head :ok
37
- rescue ActionController::ParameterMissing => e
38
- respond_with_error(e.message, :bad_request)
39
- end
63
+ Rails.logger.warn "The api token is #{access_token_param}"
64
+ ApiKey.delete_all(['api_token = ?', access_token_param])
65
+ head :ok
40
66
  end
41
67
 
42
68
  private
43
69
 
70
+ def enforce_param_type(param, param_name, *types)
71
+ raise ArgumentError.new "Type parameter #{param_name} type should be #{types} " unless types.any? do |type|
72
+ param.is_a? type
73
+ end
74
+ param
75
+ end
76
+
77
+ def check_presence_before_action(api_key)
78
+ if api_key.present?
79
+ yield(api_key)
80
+ else
81
+ head :not_found
82
+ end
83
+ end
84
+
85
+ def required_auth_params
86
+ params.require(:authorizations).permit(:read_access, :write_access)
87
+ end
88
+
89
+ def authorizer_params
90
+ params.permit(:authorizations => [:read_access, :write_access])[:authorizations]
91
+ end
92
+
44
93
  def group_param
45
94
  params.require(:group)
46
95
  end
@@ -4,7 +4,7 @@ module MasterApiKey
4
4
  before_create :generate_api_token
5
5
 
6
6
  def as_json(options = {})
7
- super(options.reverse_merge({only: [:id, :api_token, :group]}))
7
+ super(options.reverse_merge({only: [:id, :api_token, :group, :read_access, :write_access]}))
8
8
  end
9
9
 
10
10
  private
@@ -1 +1 @@
1
- 1.2.0
1
+ 2.0.1
data/config/routes.rb CHANGED
@@ -1,5 +1,7 @@
1
1
 
2
2
  MasterApiKey::Engine.routes.draw do
3
- delete '/api_keys', to: 'api_keys#destroy_by_access_token'
3
+ delete :api_keys, to: 'api_keys#destroy_by_access_token'
4
+ get :api_keys, to: 'api_keys#index'
5
+ patch :api_keys, to: 'api_keys#update_by_access_token'
4
6
  resources :api_keys, only: [:create, :destroy]
5
7
  end
@@ -0,0 +1,12 @@
1
+ class AddReadWriteAccess < ActiveRecord::Migration
2
+
3
+ def up
4
+ add_column :master_api_key_api_keys, :read_access, :boolean, :default => false, :null => false
5
+ add_column :master_api_key_api_keys, :write_access, :boolean, :default => false, :null => false
6
+ MasterApiKey::ApiKey.update_all(:read_access => true, :write_access => true)
7
+ end
8
+
9
+ def down
10
+ remove_columns :master_api_key_api_keys, :read_access, :write_access
11
+ end
12
+ end
data/db/seeds.rb CHANGED
@@ -8,5 +8,7 @@
8
8
  unless MasterApiKey::ApiKey.where(:group => :master_key).count > 0
9
9
  MasterApiKey::ApiKey.create do |master_key|
10
10
  master_key.group = :master_key
11
+ master_key.read_access = true
12
+ master_key.write_access = true
11
13
  end
12
14
  end
@@ -2,3 +2,7 @@ require 'master_api_key/api_gatekeeper'
2
2
  require 'master_api_key/engine'
3
3
 
4
4
  ActionController::Base.send :include, MasterApiKey::ApiGatekeeper
5
+ ActionController::Base.class_exec do
6
+ authorize_with :authorizers => [:write_authorizer], :only => [:create, :update, :destroy, :new, :edit]
7
+ authorize_with :authorizers => [:read_authorizer], :only => [:index, :show]
8
+ end
@@ -29,8 +29,11 @@ module MasterApiKey
29
29
 
30
30
  def passes_authorizers?(authorizers)
31
31
  method_definitions = authorizers.respond_to?(:inject) ? authorizers : [authorizers]
32
- method_definitions.inject(true) do |authorized, authorizer|
33
- authorized &= self.send(authorizer)
32
+ method_definitions.inject(true) do |is_authorized, authorizer|
33
+ was_authorized = is_authorized
34
+ is_authorized &= self.send(authorizer)
35
+ log_failed_authorization(authorizer, is_authorized, was_authorized)
36
+ is_authorized
34
37
  end
35
38
  end
36
39
 
@@ -56,10 +59,28 @@ module MasterApiKey
56
59
  head(:forbidden)
57
60
  end
58
61
 
62
+ protected
63
+
64
+ def write_authorizer
65
+ @api_key.write_access
66
+ end
67
+
68
+ def read_authorizer
69
+ @api_key.read_access
70
+ end
71
+
59
72
  private
60
73
 
74
+ def log_failed_authorization(authorizer, is_authorized, was_authorized)
75
+ unless was_authorized == is_authorized
76
+ Rails.logger.info "#{authorizer} failed for user of api token #{@api_key.api_token}"
77
+ end
78
+ end
79
+
61
80
  def authorized_with_group?
62
- @api_key.group.casecmp(self.api_group.to_s) == 0
81
+ is_authorized = @api_key.group.casecmp(self.api_group.to_s) == 0
82
+ log_failed_authorization(:authorized_with_group?, is_authorized, true)
83
+ is_authorized
63
84
  end
64
85
 
65
86
  def user_authenticated?
@@ -1,21 +1,84 @@
1
1
  require 'rails_helper'
2
+ require 'support/access_shared_examples'
3
+ require 'support/auth_shared_examples'
2
4
 
3
5
  module MasterApiKey
4
6
  RSpec.describe ApiKeysController, type: :controller do
5
-
6
7
  before(:each) do
7
8
  @routes = Engine.routes
8
9
  end
9
10
 
10
- # This should return the minimal set of values that should be in the session
11
- # in order to pass any filters (e.g. authentication) defined in
12
- # ApiKeysController. Be sure to keep this updated too.
13
- let(:valid_session) { {} }
11
+ describe 'GET #index' do
12
+ context 'with master key' do
13
+ before(:each) do
14
+ @master_key = ApiKey.create!(:group => :master_key, :read_access => true, :write_access => true)
15
+ controller.request.headers['X-API-TOKEN'] = @master_key.api_token
16
+ end
17
+
18
+ context 'with valid params' do
19
+ before(:each) do
20
+ @group_name = 'group_1'
21
+ @api_key = ApiKey.create!(:group => @group_name, write_access: true)
22
+ @valid_attributes = {:api_token => @api_key.api_token}
23
+ end
24
+
25
+ it 'should return valid json of api_key' do
26
+ get :index, @valid_attributes
27
+
28
+ json_object = (JSON.parse response.body).with_indifferent_access
29
+ expect(json_object[:api_key][:api_token]).to eq @api_key.api_token
30
+ expect(json_object[:api_key][:group]).to eq @group_name
31
+ expect(json_object[:api_key][:read_access]).to be_falsey
32
+ expect(json_object[:api_key][:write_access]).to be_truthy
33
+ end
34
+
35
+ it "should return 404 when the key doesn't exist" do
36
+ get :index, @valid_attributes.merge(:api_token => 'invalid_token')
37
+
38
+ expect(response).to have_http_status(404)
39
+ end
40
+
41
+ context 'for access rights' do
42
+ before(:each) do
43
+ @action = lambda { get :index, @valid_attributes }
44
+ end
45
+
46
+ include_examples :read_access_rights, :master_key, :ok
47
+ end
48
+
49
+ context 'for group authorizations' do
50
+ before(:each) do
51
+ @api_key = ApiKey.create!(:group => @group_name)
52
+ @action = lambda { get :index, @valid_attributes }
53
+ end
54
+
55
+ include_examples :group_authorizations, :master_key, :ok
56
+ end
57
+
58
+ context 'for api authentication' do
59
+ before(:each) do
60
+ @api_key = ApiKey.create!(:group => @group_name)
61
+ @action = lambda { get :index, @valid_attributes }
62
+ end
63
+
64
+ include_examples :api_authorizations, :master_key, :ok
65
+ end
66
+ end
67
+
68
+ context 'with invalid params' do
69
+ it "should raise missing param exception when the required param api_token isn't one of the params" do
70
+ get :index, {:wrong_param => 'invalid_token'}
71
+
72
+ expect(response).to have_http_status(400)
73
+ end
74
+ end
75
+ end
76
+ end
14
77
 
15
78
  describe 'POST #create' do
16
79
  context 'with master key' do
17
80
  before(:each) do
18
- @master_key = ApiKey.create!(:group => :master_key)
81
+ @master_key = ApiKey.create!(:group => :master_key, :read_access => true, :write_access => true)
19
82
  controller.request.headers['X-API-TOKEN'] = @master_key.api_token
20
83
  end
21
84
 
@@ -36,6 +99,53 @@ module MasterApiKey
36
99
  expect(assigns(:api_key)).to be_a(ApiKey)
37
100
  expect(assigns(:api_key)).to be_persisted
38
101
  end
102
+
103
+ it 'assigns a new api key with default read/write access' do
104
+ post :create, @valid_attributes
105
+
106
+ json_object = (JSON.parse response.body).with_indifferent_access
107
+ created_key = ApiKey.find_by_api_token(json_object[:api_key][:api_token])
108
+
109
+ expect(created_key.group).to eq(@valid_attributes[:group])
110
+ expect(created_key.read_access).to be_falsey
111
+ expect(created_key.write_access).to be_falsey
112
+ end
113
+
114
+ it 'assigns a new api key with read/write access' do
115
+ post :create, @valid_attributes.merge(authorizations:{ read_access: true, write_access: true })
116
+
117
+ json_object = (JSON.parse response.body).with_indifferent_access
118
+ created_key = ApiKey.find_by_api_token(json_object[:api_key][:api_token])
119
+
120
+ expect(created_key.group).to eq(@valid_attributes[:group])
121
+ expect(created_key.read_access).to be_truthy
122
+ expect(created_key.write_access).to be_truthy
123
+ end
124
+
125
+ context 'for group authorizations' do
126
+ before(:each) do
127
+ @api_key = ApiKey.create!(:group => 'group_1')
128
+ @action = lambda { post :create, @valid_attributes }
129
+ end
130
+
131
+ include_examples :group_authorizations, :master_key, :created
132
+ end
133
+
134
+ context 'for access rights' do
135
+ before(:each) do
136
+ @action = lambda { post :create, @valid_attributes }
137
+ end
138
+
139
+ include_examples :write_access_rights, :master_key, :created
140
+ end
141
+
142
+ context 'for api authentication' do
143
+ before(:each) do
144
+ @action = lambda { post :create, @valid_attributes }
145
+ end
146
+
147
+ include_examples :api_authorizations, :master_key, :created
148
+ end
39
149
  end
40
150
 
41
151
  context 'with invalid params' do
@@ -46,29 +156,124 @@ module MasterApiKey
46
156
  expect {
47
157
  post :create, {:group => nil}
48
158
  }.to_not change(ApiKey, :count)
159
+
160
+ expect(response).to have_http_status(400)
49
161
  end
50
162
 
51
163
  it 'should not change ApiKey count when group param does not exist' do
52
164
  expect {
53
165
  post :create, {}
54
166
  }.to_not change(ApiKey, :count)
167
+
168
+ expect(response).to have_http_status(400)
169
+ end
170
+
171
+ it "should not change ApiKey count when read param isn't a boolean" do
172
+ expect {
173
+ post :create, {:group => 'group_name', authorizations: { read_access: 'wrong type' }}
174
+ }.to_not change(ApiKey, :count)
175
+
176
+ expect(response).to have_http_status(400)
177
+ end
178
+
179
+ it "should not change ApiKey count when write param isn't a boolean" do
180
+ expect {
181
+ post :create, {:group => 'group_name', authorizations: { write_access: 'wrong type'}}
182
+ }.to_not change(ApiKey, :count)
183
+
184
+ expect(response).to have_http_status(400)
55
185
  end
56
186
  end
57
187
  end
188
+ end
58
189
 
59
- context 'with incorrect api key' do
190
+ describe 'PATCH #update' do
191
+ context 'with master key' do
60
192
  before(:each) do
61
- @master_key = ApiKey.create!(:group => :wrong_group)
193
+ @master_key = ApiKey.create!(:group => :master_key, :read_access => true, :write_access => true)
62
194
  controller.request.headers['X-API-TOKEN'] = @master_key.api_token
63
- @valid_attributes = {:group => 'group_1'}
64
195
  end
65
196
 
66
- it 'fails to create a new ApiKey' do
67
- expect {
68
- post :create, @valid_attributes
69
- }.to_not change(ApiKey, :count)
197
+ context 'with valid params' do
198
+ before(:each) do
199
+ @api_key = ApiKey.create!(:group => :group_1)
200
+ @valid_attributes = { api_token: @api_key.api_token, authorizations: { read_access:true }}
201
+ end
70
202
 
71
- expect(response.status).to be 403
203
+ it 'should update the api key so read access is false and write access is true' do
204
+ patch :update_by_access_token, @valid_attributes.merge(authorizations: { read_access:false, write_access:true })
205
+
206
+ json_object = (JSON.parse response.body).with_indifferent_access
207
+ updated_key = ApiKey.find_by_api_token(json_object[:api_key][:api_token])
208
+
209
+ expect(updated_key.read_access).to be_falsey
210
+ expect(updated_key.write_access).to be_truthy
211
+ end
212
+
213
+ it 'should not update the api key group' do
214
+ patch :update_by_access_token, @valid_attributes.merge({:group => :group_2, authorizations:{read_access:true}})
215
+
216
+ json_object = (JSON.parse response.body).with_indifferent_access
217
+ updated_key = ApiKey.find_by_api_token(json_object[:api_key][:api_token])
218
+
219
+ expect(updated_key.group).to eq('group_1')
220
+ expect(updated_key.read_access).to be_truthy
221
+ expect(updated_key.write_access).to be_falsey
222
+ end
223
+
224
+ context 'for group authorizations' do
225
+ before(:each) do
226
+ @action = lambda { patch :update_by_access_token, @valid_attributes }
227
+ end
228
+
229
+ include_examples :group_authorizations, :master_key, :ok
230
+ end
231
+
232
+ context 'for access rights' do
233
+ before(:each) do
234
+ @action = lambda { patch :update_by_access_token, @valid_attributes }
235
+ end
236
+
237
+ include_examples :write_access_rights, :master_key, :ok
238
+ end
239
+
240
+ context 'for api authentication' do
241
+ before(:each) do
242
+ @action = lambda { patch :update_by_access_token, @valid_attributes }
243
+ end
244
+
245
+ include_examples :api_authorizations, :master_key, :ok
246
+ end
247
+ end
248
+
249
+ context 'with invalid params' do
250
+ it 'should return 400 if there are no authorizations' do
251
+ patch :update_by_access_token, { authorizations:{} }
252
+
253
+ expect(response).to have_http_status(400)
254
+ end
255
+
256
+ it "should return 400 if the authorizations json doesn't exist" do
257
+ patch :update_by_access_token, {}
258
+
259
+ expect(response).to have_http_status(400)
260
+ end
261
+
262
+ it "should not change ApiKey count when read param isn't a boolean" do
263
+ expect {
264
+ patch :update_by_access_token, {authorizations: { read_access: 'wrong type' }}
265
+ }.to_not change(ApiKey, :count)
266
+
267
+ expect(response).to have_http_status(400)
268
+ end
269
+
270
+ it "should not change ApiKey count when write param isn't a boolean" do
271
+ expect {
272
+ patch :update_by_access_token, {authorizations: { write_access: 'wrong type'}}
273
+ }.to_not change(ApiKey, :count)
274
+
275
+ expect(response).to have_http_status(400)
276
+ end
72
277
  end
73
278
  end
74
279
  end
@@ -76,7 +281,7 @@ module MasterApiKey
76
281
  describe 'DELETE #destroy' do
77
282
  context 'with master key' do
78
283
  before(:each) do
79
- @master_key = ApiKey.create(:group => :master_key)
284
+ @master_key = ApiKey.create(:group => :master_key, :read_access => true, :write_access => true)
80
285
  @api_key = ApiKey.create!(:group => 'group_1')
81
286
  controller.request.headers['X-API-TOKEN'] = @master_key.api_token
82
287
  end
@@ -100,29 +305,65 @@ module MasterApiKey
100
305
 
101
306
  expect(response).to be_success
102
307
  end
308
+
309
+ context 'for access rights for removal by id' do
310
+ before(:each) do
311
+ @action = lambda { delete :destroy, {id: @api_key.to_param.to_i} }
312
+ end
313
+
314
+ include_examples :write_access_rights, :master_key, :ok
315
+ end
316
+
317
+ context 'for access rights for removal by token' do
318
+ before(:each) do
319
+ @action = lambda { delete :destroy_by_access_token, {api_token: @api_key.api_token} }
320
+ end
321
+
322
+ include_examples :write_access_rights, :master_key, :ok
323
+ end
103
324
  end
104
325
 
105
- context 'with incorrect api key' do
326
+ context 'for group authorizations' do
106
327
  before(:each) do
107
- @master_key = ApiKey.create!(:group => :wrong_group)
108
328
  @api_key = ApiKey.create!(:group => 'group_1')
109
- controller.request.headers['X-API-TOKEN'] = @master_key.api_token
110
329
  end
111
330
 
112
- it 'fails to destroy the ApiKey by id' do
113
- expect {
114
- delete :destroy, {:id => @api_key.to_param.to_i}
115
- }.to_not change(ApiKey, :count)
331
+ context 'with delete by id' do
332
+ before(:each) do
333
+ @action = lambda { delete :destroy, {:id => @api_key.to_param.to_i} }
334
+ end
335
+ include_examples :group_authorizations, :master_key, :ok
116
336
 
117
- expect(response.status).to be 403
118
337
  end
119
338
 
120
- it 'fails to destroy the ApiKey by api token' do
121
- expect {
122
- delete :destroy_by_access_token, {:api_token => @api_key.api_token}
123
- }.to_not change(ApiKey, :count)
339
+ context 'with delete by api token' do
340
+ before(:each) do
341
+ @action = lambda { delete :destroy_by_access_token, {:api_token => @api_key.api_token} }
342
+ end
343
+
344
+ include_examples :group_authorizations, :master_key, :ok
345
+ end
346
+ end
347
+
348
+ context 'for api authorizations' do
349
+ before(:each) do
350
+ @api_key = ApiKey.create!(:group => 'group_1')
351
+ end
352
+
353
+ context 'with delete by id' do
354
+ before(:each) do
355
+ @action = lambda { delete :destroy, {:id => @api_key.to_param.to_i} }
356
+ end
357
+
358
+ include_examples :api_authorizations, :master_key, :ok
359
+ end
360
+
361
+ context 'with delete by api token' do
362
+ before(:each) do
363
+ @action = lambda { delete :destroy_by_access_token, {:api_token => @api_key.api_token} }
364
+ end
124
365
 
125
- expect(response.status).to be 403
366
+ include_examples :api_authorizations, :master_key, :ok
126
367
  end
127
368
  end
128
369
  end