eaco 0.7.0 → 0.8.0

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: 2c8f2901fb8524328d3e14a6c08607c553912b7a
4
- data.tar.gz: cf36cc16c76467699d29576720a06e1ca612663e
3
+ metadata.gz: 9384ef5a98077f6557e1e69eb7f54fb0463d35d5
4
+ data.tar.gz: 5728d953f8b9aef185fc97a84ae1a236c35ae9eb
5
5
  SHA512:
6
- metadata.gz: 0bf06b2c70e7dda0a6790d89d7b5e23ce0ebe97e49026001bff0af29f69844eeb7a5b8c1f54f8d01151d86e7d4b4a9911301ef2edbdafac1958cccfdf6be3522
7
- data.tar.gz: 2c1c4a9acc88bd4b814e99e1110cabe9e5f5622f29183a90c95180ba378887463091eec7d58dd88436cdb843f1e296b8cd5708adc82062ecf9d866375f22e8ae
6
+ metadata.gz: 7f5c5de62937bef96163b634a895903cdc4fa76368ac7b1dc56765d395bb5445ca0c41e3ef9b49c6992b5dda264210ecb50b79613a574c31887ec7da83d35aec
7
+ data.tar.gz: 15d230d2416a2fd7a0ddaf5479433759d494d7a285944d38606f05630567a321f0baf4a787ecbd4a993ff155a9d1031a66c53fb97dbb9ba5876f9ba6b6801b47
data/Guardfile CHANGED
@@ -34,5 +34,5 @@ end
34
34
 
35
35
  guard :shell do
36
36
  # Rerun scenarios when source code changes
37
- watch(%r{^lib/.+\.rb$}) { system 'cucumber' }
37
+ watch(%r{^lib/.+\.rb$}) { system 'cucumber -f progress' }
38
38
  end
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Eaco
2
2
 
3
3
  [![Build Status](https://travis-ci.org/ifad/eaco.svg)](https://travis-ci.org/ifad/eaco)
4
- [![Coverage Status](https://coveralls.io/repos/ifad/eaco/badge.svg)](https://coveralls.io/r/ifad/eaco) (*currently writing specs*)
4
+ [![Coverage Status](https://coveralls.io/repos/ifad/eaco/badge.svg)](https://coveralls.io/r/ifad/eaco)
5
5
  [![Code Climate](https://codeclimate.com/github/ifad/eaco/badges/gpa.svg)](https://codeclimate.com/github/ifad/eaco)
6
6
  [![Inline docs](http://inch-ci.org/github/ifad/eaco.svg?branch=master)](http://inch-ci.org/github/ifad/eaco)
7
7
  [![Gem Version](https://badge.fury.io/rb/eaco.svg)](http://badge.fury.io/rb/eaco)
@@ -58,6 +58,25 @@ Feature: Role-based, flexible authorization
58
58
  | Cafeteria Menu | {"position:3":"writer", "authenticated:Eaco::Cucumber::ActiveRecord::User":"reader"} |
59
59
  | Tim's Web Project | {"user:5":"writer", "position:2":"reader"} |
60
60
 
61
+ Scenario: Granting access in batches
62
+ When I have a confidential Document named "For BAR and ICT"
63
+ And I grant access to Document "For BAR and ICT" to the following designators as reader
64
+ | department:BAR |
65
+ | department:ICT |
66
+ When I am "Dennis Ritchie"
67
+ Then I can read the Document "For BAR and ICT" being a reader
68
+ But I can not write the Document "For BAR and ICT" being a reader
69
+ When I am "Rob Pike"
70
+ Then I can read the Document "For BAR and ICT" being a reader
71
+ But I can not write the Document "For BAR and ICT" being a reader
72
+ When I am "William Gates"
73
+ Then I can read the Document "For BAR and ICT" being a reader
74
+ But I can not write the Document "For BAR and ICT" being a reader
75
+ When I am "Steve Jobs"
76
+ Then I can not read the Document "For BAR and ICT"
77
+ And I can not write the Document "For BAR and ICT"
78
+
79
+
61
80
  Scenario: The Director can access confidential document
62
81
  When I am "Dennis Ritchie"
63
82
  Then I can read the Document "ICT Status Report" being a writer
@@ -106,6 +125,7 @@ Feature: Role-based, flexible authorization
106
125
  When I parse the Designator "user:4"
107
126
  Then it should describe itself as "User 'Steve Jobs'"
108
127
  And it should have a label of "User"
128
+ And it should serialize to JSON as {"label": "User 'Steve Jobs'", "value": "user:4"}
109
129
  And it should resolve itself to
110
130
  | Steve Jobs |
111
131
 
@@ -113,6 +133,7 @@ Feature: Role-based, flexible authorization
113
133
  When I make a Designator with "position" and "1"
114
134
  Then it should describe itself as "Director in ICT"
115
135
  And it should have a label of "Position"
136
+ And it should serialize to JSON as {"label": "Director in ICT", "value": "position:1"}
116
137
  And it should resolve itself to
117
138
  | Dennis Ritchie |
118
139
 
@@ -120,6 +141,7 @@ Feature: Role-based, flexible authorization
120
141
  When I parse the Designator "department:ICT"
121
142
  Then it should describe itself as "ICT"
122
143
  And it should have a label of "Department"
144
+ And it should serialize to JSON as {"label": "ICT", "value": "department:ICT"}
123
145
  And it should resolve itself to
124
146
  | Dennis Ritchie |
125
147
  | Rob Pike |
@@ -128,6 +150,7 @@ Feature: Role-based, flexible authorization
128
150
  When I make a Designator with "authenticated" and "Eaco::Cucumber::ActiveRecord::User"
129
151
  Then it should describe itself as "Any authenticated user"
130
152
  And it should have a label of "Any user"
153
+ And it should serialize to JSON as {"label": "Any authenticated user", "value": "authenticated:Eaco::Cucumber::ActiveRecord::User"}
131
154
  And it should resolve itself to
132
155
  | Dennis Ritchie |
133
156
  | Rob Pike |
@@ -152,8 +175,76 @@ Feature: Role-based, flexible authorization
152
175
  Designator not found: "foo"
153
176
  """
154
177
 
178
+ Scenario: Obtaining the role of a valid designator
179
+ When I parse the Designator "department:ICT"
180
+ Then its role on the Document "ICT Status Report" should be reader
181
+ And its role on the Documents "Cafeteria Menu, ICT Budget Report, Tim's Web Project" should be nil
182
+ When I make a Designator with "position" and "1"
183
+ Then its role on the Documents "ICT Status Report, ICT Budget Report" should be writer
184
+ And its role on the Documents "Cafeteria Menu, Tim's Web Project" should be nil
185
+
186
+ Scenario: Obtaining the role of an invalid object
187
+ When I have a plain object as a Designator
188
+ Then its role on the Document "ICT Status Report" should give an Eaco::Error error saying
189
+ """
190
+ role_of expects .+Object.+ to be a Designator or to .+respond_to.+:designators
191
+ """
192
+
155
193
  Scenario: Obtaining labels for roles
156
194
  When I ask the Document the list of roles and labels
157
195
  Then I should get the following roles and labels
158
196
  | writer | R/W |
159
197
  | reader | R/O |
198
+
199
+ Scenario: Authorizing a controller
200
+ When I have an authorized Controller defined as
201
+ """
202
+ before_filter :find_document
203
+
204
+ authorize :show, [:document, :read ]
205
+ authorize :edit, [:document, :write]
206
+
207
+ def show
208
+ head :ok
209
+ end
210
+
211
+ def edit
212
+ head :ok
213
+ end
214
+
215
+ private
216
+
217
+ def find_document
218
+ @document = Eaco::Cucumber::ActiveRecord::Document.where(name: params[:name]).first
219
+ end
220
+ """
221
+ When I am "Dennis Ritchie"
222
+ And I invoke the Controller "show" action with query string "name=ICT Status Report"
223
+ Then the Controller should not raise an error
224
+ And I invoke the Controller "edit" action with query string "name=ICT Status Report"
225
+ Then the Controller should not raise an error
226
+
227
+ When I am "Rob Pike"
228
+ And I invoke the Controller "show" action with query string "name=ICT Status Report"
229
+ Then the Controller should not raise an error
230
+ And I invoke the Controller "edit" action with query string "name=ICT Status Report"
231
+ Then the Controller should raise an Eaco::Forbidden error saying
232
+ """
233
+ User.+not authorized to `edit' on .+Document
234
+ """
235
+
236
+ When I am "William Gates"
237
+ And I invoke the Controller "edit" action with query string "name=Cafeteria Menu"
238
+ Then the Controller should not raise an error
239
+ And I invoke the Controller "show" action with query string "name=ICT Status Report"
240
+ Then the Controller should raise an Eaco::Forbidden error saying
241
+ """
242
+ User.+not authorized to `show' on .+Document
243
+ """
244
+
245
+ When I am "Steve Jobs"
246
+ And I invoke the Controller "show" action with query string "name=One More Thing"
247
+ Then the Controller should raise an Eaco::Error error saying
248
+ """
249
+ @document is not set, can't authorize .+show
250
+ """
@@ -18,6 +18,14 @@ When(/I grant (\w+) access to (\w+) "(.+?)" as a (\w+) in quality of (\w+)/) do
18
18
  resource.save!
19
19
  end
20
20
 
21
+ When(/I grant access to (\w+) "(.+?)" to the following designators as (\w+)/) do |resource_model, resource_name, role, table|
22
+ resource = fetch_resource(resource_model, resource_name)
23
+ designators = table.raw.flatten.map {|d| Eaco::Designator.parse(d) }
24
+
25
+ resource.batch_grant role, designators
26
+ resource.save!
27
+ end
28
+
21
29
  When(/I revoke (\w+) access to (\w+) "(.+?)" in quality of (\w+)/) do |actor_name, resource_model, resource_name, designator|
22
30
  actor = fetch_actor(actor_name)
23
31
  resource = fetch_resource(resource_model, resource_name)
@@ -0,0 +1,34 @@
1
+ When(/I have an authorized Controller defined as/) do |controller_code|
2
+ require 'action_controller'
3
+ require 'eaco/controller'
4
+
5
+ @controller_class = Class.new(ActionController::Base)
6
+ @controller_class.send(:attr_accessor, :current_user)
7
+ @controller_class.instance_eval { include Eaco::Controller }
8
+ @controller_class.class_eval controller_code
9
+ end
10
+
11
+ When(/I invoke the Controller "(.+?)" action with query string "(.+?)"$/) do |action_name, query|
12
+ @controller = @controller_class.new
13
+ @action_name = action_name
14
+
15
+ @controller.current_user = @current_user
16
+
17
+ @controller.request = ActionDispatch::TestRequest.new('QUERY_STRING' => query).tap do |request|
18
+ request.params.update('action' => @action_name)
19
+ end
20
+
21
+ @controller.response = ActionDispatch::TestResponse.new
22
+ end
23
+
24
+ Then(/the Controller should not raise an error/) do
25
+ expect { @controller.process @action_name }.to_not raise_error
26
+ end
27
+
28
+ Then(/the Controller should raise an (.+?) error saying/) do |error_class, error_contents|
29
+ error_class = error_class.constantize
30
+
31
+ expect { @controller.process @action_name }.to \
32
+ raise_error(error_class).
33
+ with_message(/#{error_contents}/)
34
+ end
@@ -5,22 +5,14 @@ When(/I am "(.+?)"$/) do |user_name|
5
5
  end
6
6
 
7
7
  Then(/I can (\w+) the Documents? "(.+?)" being a (\w+)$/) do |permission, document_names, role|
8
- model = find_model('Document')
9
- names = document_names.split(/,\s*/)
10
- documents = model.where(name: names)
11
-
12
- documents.each do |document|
8
+ check_documents document_names do |document|
13
9
  expect(@current_user.can?(permission, document)).to eq(true)
14
10
  expect(document.role_of(@current_user)).to eq(role.intern)
15
11
  end
16
12
  end
17
13
 
18
14
  Then(/I can not (\w+) the Documents? "(.+?)" *(?:being a (\w+))?$/) do |permission, document_names, role|
19
- model = find_model('Document')
20
- names = document_names.split(/,\s*/)
21
- documents = model.where(name: names)
22
-
23
- documents.each do |document|
15
+ check_documents document_names do |document|
24
16
  expect(@current_user.cannot?(permission, document)).to eq(true)
25
17
  expect(document.role_of(@current_user)).to eq(role ? role.intern : nil)
26
18
  end
@@ -41,10 +33,20 @@ When(/I parse the Designator "(.+?)"/) do |text|
41
33
  @designator = Eaco::Designator.parse(text)
42
34
  end
43
35
 
36
+ When(/I have a plain object as a Designator/) do
37
+ @designator = Object.new
38
+ end
39
+
44
40
  Then(/it should describe itself as "(.+?)"/) do |description|
45
41
  expect(@designator.describe).to eq(description)
46
42
  end
47
43
 
44
+ Then(/it should serialize to JSON as (.+?)$/) do |json|
45
+ json = MultiJson.load(json).symbolize_keys
46
+
47
+ expect(@designator.as_json).to eq(json)
48
+ end
49
+
48
50
  Then(/it should have a label of "(.+?)"/) do |label|
49
51
  expect(@designator.label).to eq(label)
50
52
  end
@@ -66,6 +68,24 @@ Then(/they should resolve to/) do |table|
66
68
  expect(resolved.map(&:name)).to match_array(names)
67
69
  end
68
70
 
71
+ Then(/its role on the Documents? "(.+?)" should be (\w+)/) do |document_names, role|
72
+ role = role == 'nil' ? nil : role.intern
73
+
74
+ check_documents document_names do |document|
75
+ expect(document.role_of(@designator)).to eq(role)
76
+ end
77
+ end
78
+
79
+ Then(/its role on the Documents? "(.+?)" should give an (.+?) error saying/) do |document_names, error_class, error_contents|
80
+ error_class = error_class.constantize
81
+
82
+ check_documents document_names do |document|
83
+ expect { document.role_of(@designator) }.to \
84
+ raise_error(error_class).
85
+ with_message(/#{error_contents}/)
86
+ end
87
+ end
88
+
69
89
  When(/I ask the Document the list of roles and labels/) do
70
90
  model = find_model('Document')
71
91
 
@@ -9,6 +9,8 @@ module Eaco
9
9
  # @see ACL
10
10
  # @see CouchDBLucene
11
11
  #
12
+ # :nocov: because there are too many moving parts here and anyway we are
13
+ # going to deprecate this in favour of jsonb
12
14
  module CouchrestModel
13
15
  autoload :CouchDBLucene, 'eaco/adapters/couchrest_model/couchdb_lucene'
14
16
 
@@ -32,6 +34,7 @@ module Eaco
32
34
  end
33
35
  end
34
36
  end
37
+ # :nocov:
35
38
 
36
39
  end
37
40
  end
@@ -48,6 +48,8 @@ module Eaco
48
48
  # @see Actor
49
49
  # @see Resource
50
50
  #
51
+ # :nocov: because there are too many moving parts here and anyway we are
52
+ # going to deprecate this in favour of jsonb
51
53
  module CouchDBLucene
52
54
 
53
55
  ##
@@ -58,13 +60,14 @@ module Eaco
58
60
  # @return [CouchRest::Model::Search::View] the authorized collection scope.
59
61
  #
60
62
  def accessible_by(actor)
61
- return search(nil) if actor.is_admin?
63
+ return search(nil) if actor.is_admin?
62
64
 
63
- designators = actor.designators.map {|item| '"%s"' % item }
65
+ designators = actor.designators.map {|item| '"%s"' % item }
64
66
 
65
- search "acl:(#{designators.join(' OR ')})"
67
+ search "acl:(#{designators.join(' OR ')})"
66
68
  end
67
69
  end
70
+ # :nocov:
68
71
 
69
72
  end
70
73
  end
@@ -2,7 +2,7 @@ begin
2
2
  require 'active_support/concern'
3
3
  rescue LoadError
4
4
  # :nocov: This is falsely true during specs ran by Guard. FIXME.
5
- abort 'Eaco::Controller requires activesupport. Please add it to Gemfile.'
5
+ abort 'Eaco::Controller requires actioncontroller. Please add it to Gemfile.'
6
6
  # :nocov:
7
7
  end
8
8
 
@@ -87,6 +87,8 @@ module Eaco
87
87
  end
88
88
  end
89
89
 
90
+ protected
91
+
90
92
  ##
91
93
  # Asks Eaco whether thou shalt pass or not.
92
94
  #
@@ -220,7 +220,7 @@ module Eaco
220
220
  resources.fetch(model).fetch(name)
221
221
  rescue KeyError
222
222
  # :nocov:
223
- raise "Resource #{model} '#{resource}' not found in registry"
223
+ raise "Resource #{model} '#{name}' not found in registry"
224
224
  # :nocov:
225
225
  end
226
226
 
@@ -243,6 +243,22 @@ module Eaco
243
243
  @resources ||= {}
244
244
  end
245
245
 
246
+ ##
247
+ # Checks the given block on the given set of +Document+
248
+ #
249
+ # @param names [String] the document names, separated by +,+
250
+ # @param block [Proc] the code to run on each +Document+
251
+ #
252
+ # @return [void]
253
+ #
254
+ # @see Eaco::Cucumber::ActiveRecord::Document
255
+ #
256
+ def check_documents(names, &block)
257
+ model = find_model('Document')
258
+ names = names.split(/,\s*/)
259
+ model.where(name: names).each(&block)
260
+ end
261
+
246
262
  ##
247
263
  # Returns a model in the {ActiveRecord} namespace.
248
264
  #
@@ -175,7 +175,9 @@ module Eaco
175
175
  # @raise [NotImplementedError]
176
176
  #
177
177
  def search(query)
178
+ # :nocov:
178
179
  raise NotImplementedError
180
+ # :nocov:
179
181
  end
180
182
  end
181
183
 
@@ -224,7 +226,9 @@ module Eaco
224
226
  # @raise [NotImplementedError]
225
227
  #
226
228
  def resolve
229
+ # :nocov:
227
230
  raise NotImplementedError
231
+ # :nocov:
228
232
  end
229
233
 
230
234
  ##
@@ -2,6 +2,6 @@ module Eaco
2
2
 
3
3
  # Current version
4
4
  #
5
- VERSION = '0.7.0'
5
+ VERSION = '0.8.0'
6
6
 
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eaco
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcello Barnaba
@@ -217,6 +217,7 @@ files:
217
217
  - features/rails_integration.feature
218
218
  - features/role_based_authorization.feature
219
219
  - features/step_definitions/actor_steps.rb
220
+ - features/step_definitions/controller_steps.rb
220
221
  - features/step_definitions/enterprise_steps.rb
221
222
  - features/step_definitions/error_steps.rb
222
223
  - features/step_definitions/fixture_steps.rb
@@ -319,6 +320,7 @@ test_files:
319
320
  - features/rails_integration.feature
320
321
  - features/role_based_authorization.feature
321
322
  - features/step_definitions/actor_steps.rb
323
+ - features/step_definitions/controller_steps.rb
322
324
  - features/step_definitions/enterprise_steps.rb
323
325
  - features/step_definitions/error_steps.rb
324
326
  - features/step_definitions/fixture_steps.rb