eaco 0.7.0 → 0.8.0

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: 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