master_api_key 1.2.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
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