bali 2.0.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0e4656b297055440ffa3f95c4b402ef9205944e3
4
- data.tar.gz: 00793b60bed79d06ac0ae2d9edaf07a8b6331bc4
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OGE5M2M0ZmE1MGJmMDc4M2ZmM2Q3NzlkNGY3OTAxMDUzNGEwYTBiNg==
5
+ data.tar.gz: !binary |-
6
+ NmQ0MGNkOGRiMjJlZjc1YTFmZmMzN2FjNDNiNTU1N2I3OTZkZjMyYg==
5
7
  SHA512:
6
- metadata.gz: f29d7f76ca30d09aeb996f7bf1a7ad8ccb340552ff68744fd75a1ba7b5a823dabb033022176f545fa5c439495dfa3bfe5b7a8620dad6a62766f3196398c17f5e
7
- data.tar.gz: a275d79a14aab95e03efb0401f152884c16cfe02f256eb6c16d16bb5936989421c51a6a4318c8885174d09006fcbec92a828d89ac46549bee9404eb44ec0bcfb
8
+ metadata.gz: !binary |-
9
+ NWUxZDA3YmFkMDI1YzIwMDUzMjdmNTIxNjBhZmZjNTZmNzc3NWUxMjNmNDU4
10
+ MmYzNDgxNzczZjc1ODcxMDU0N2FkN2U0ZDM0NDhmYzI1NzY5N2ZjZTAyZGY1
11
+ MTBiYTQ1ZjU2ZjhhNmUxNjZhZjJkYWM1NTk1Yzk4ZDAyNjM2OWM=
12
+ data.tar.gz: !binary |-
13
+ NWUwZTM5NTA5NGFiZDI3NDgxMGM5YTlkYzM2Mzc0Y2NjM2IyMmZiYTNiODFh
14
+ NWMzMzMzZjgyY2QyZWM4MTc1YzdlNGI0NmE0YzM3YmZjNTg4M2I0OWFmZTAw
15
+ MWE0Mzk4OWY3YzI2NTVhZjIxOGNkYWRjOGE0NzhiMzYzZWQ2NjE=
@@ -0,0 +1,69 @@
1
+ ## Changelog
2
+
3
+ == Version 1.0.0beta1
4
+
5
+ 1. Initial version
6
+
7
+ == Version 1.0.0rc1
8
+
9
+ 1. Fix bug where user can't check on class
10
+ 2. Adding new clause: cant_all
11
+
12
+ == Version 1.0.0rc2
13
+
14
+ 1. [Fix bug when class's name, as a constant, is reloaded](http://stackoverflow.com/questions/2509350/rails-class-object-id-changes-after-i-make-a-request) (re-allocated to different address in the memory)
15
+ 2. Allow describing rule for `nil`, useful if user is not authenticated thus role is probably `nil`
16
+ 3. Remove pry from development dependency
17
+
18
+ == Version 1.0.0rc3
19
+
20
+ 1. Each target class should includes `Bali::Objector`, for the following reasons:
21
+ - Makes it clear that class do want to include the Bali::Objector
22
+ - Transparant, and thus less confusing as to where "can?" and "cant" come from
23
+ - When ruby re-parse the class's codes for any reasons, parser will be for sure include Bali::Objector
24
+ 2. Return `true` to any `can?` for undefined target/subtarget alike
25
+ 3. Return `false` to any `cant?` for undefined target/subtarget alike
26
+
27
+ == Version 1.0.0
28
+
29
+ 1. Released the stable version of this gem
30
+
31
+ == Version 1.1.0rc1
32
+
33
+ 1. Ability for rule class to be parsed later by passing `later: true` to rule class definition
34
+ 2. Add `Bali.parse` and `Bali.parse!` (`Bali.parse!` executes "later"-tagged rule class, Bali.parse executes automatically after all rules are defined)
35
+ 3. Added more thorough testing specs
36
+ 4. Proc can be served under `unless` for defining the rule's decider
37
+
38
+ == Version 1.1.0rc2
39
+
40
+ 1. Ability to check `can?` and `cant?` for subtarget with multiple roles
41
+ 2. Describe multiple rules at once for multiple subtarget
42
+
43
+ == Version 1.2.0
44
+
45
+ 1. Passing real object as subtarget's role, instead of symbol or array of symbol
46
+ 2. Clause can also yielding user, along with the object in question
47
+
48
+ == Version 2.0.0rc1
49
+
50
+ 1. `Bali::AuthorizationError` subclass of `StandardError` tailored for raising error regarding with authorisation
51
+ 2. Deprecating `cant`, `cant?`, and `cant_all` in favor of `cannot`, `cannot?` and `cannot_all`
52
+ 3. new objectors `can!` and `cannot!` to raise error on inappropriate access
53
+
54
+ == Version 2.0.0
55
+
56
+ 1. Release!
57
+
58
+ == Version 2.1.0
59
+
60
+ 1. `others` block would allow for rule definitions within it to be applied for all undefined subtargets of a target
61
+ 2. Fixing bug when roles_for of a user object retrieves `nil` as the user's role, it won't acknowledge that the user is indeed having `nil`-role and raising an error instead.
62
+ 3. Inherits rules by passing `:inherits` option when defining `rules_for`
63
+ 4. `clear_rules` within `describe` or `others` block to remove all inherited rules (or any rules previously defined) for that subtarget
64
+ 5. Adding `Bali::Printer` that would enable for rules to be printed by calling `.pretty_print` on it
65
+
66
+ == Version 2.1.1
67
+
68
+ 1. Bug fixes on `clear_rules` which it clear rules defined in `others` even when not asked to
69
+ 2. Bug fixes on `Bali::Printer` where inherited rules print the wrong target class due to another bug in an internal file (but doesn't hamper rules-checking logic)
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  [ ![Codeship Status for saveav/bali](https://codeship.com/projects/d2f3ded0-20cf-0133-e425-0eade5a669ff/status?branch=release)](https://codeship.com/projects/95727)
4
4
 
5
+ [![Code Climate](https://codeclimate.com/github/saveav/bali/badges/gpa.svg)](https://codeclimate.com/github/saveav/bali)
6
+
5
7
  Bali is a powerful, framework-agnostic, thread-safe Ruby language authorization library. It is a universal authorization library, in the sense that it does not assume you to use specific Ruby library/gem/framework in order for successful use of this gem.
6
8
 
7
9
  Bali is short for Bulwark Authorization Library.
@@ -29,49 +31,7 @@ And then execute:
29
31
 
30
32
  ## Usage
31
33
 
32
- ### Defining access rules
33
-
34
- Rule in Bali is the law determining whether a user (called `subtarget`) can do or perform a specific operation on a target (which is your resource/model).
35
-
36
- ```ruby
37
- Bali.map_rules do
38
- rules_for My::Transaction, as: :transaction do
39
- describe(:supreme_user) { can_all }
40
- describe :admin_user do
41
- can_all
42
- # a more specific rule would be executed even if can_all is present
43
- can :cancel,
44
- if: proc { |record| record.payment_channel == "CREDIT_CARD" &&
45
- !record.is_settled? }
46
- end
47
- describe "general user", can: [:update, :edit], cant: [:delete]
48
- describe "finance user" do
49
- can :update, :delete, :edit
50
- can :delete, if: proc { |record| record.is_settled? }
51
- can :cancel, unless: proc { |record| record.is_settled? }
52
- end # finance_user description
53
- describe :guest { cant_all }
54
- describe nil { cant_all }
55
- end # rules_for
56
- end
57
- ```
58
-
59
- You may or may not assign an alias name (`as`). Make sure to keep it unique had you decided to give alias name to your rules group.
60
-
61
- It is also possible for a rule to be defined for multiple subtarget at once:
62
-
63
- ```ruby
64
- Bali.map_rules do
65
- rules_for My::Transaction do
66
- # rules described bellow will affect both :general_user and :finance_user
67
- describe :general_user, :finance_user do
68
- can :update, :edit
69
- end
70
- end
71
- end
72
- ```
73
-
74
- ### Can and Cant? testing
34
+ Please access [wiki pages](https://github.com/saveav/bali/wiki) for a more detailed, guided explanation, and see what Bali can do. This usage is a simple demonstration what average, standard use of Bali would looks like.
75
35
 
76
36
  Say:
77
37
 
@@ -96,143 +56,94 @@ class My::Employee
96
56
  end
97
57
  ```
98
58
 
99
- Assuming that there exist a variable `transaction` which is an instance of `My::Transaction`, we can query about whether the subtarget is granted to perform certain operation:
100
-
101
- ```ruby
102
- transaction.cant?(:general_user, :delete) # => true
103
- transaction.can("general user", :update) # => true
104
- transaction.can?(:finance_user, :delete) # depend on context
105
- transaction.can?(:monitoring_user, :view) # => true
106
- transaction.can?(:admin_user, :cancel) # depend on context
107
- transaction.can?(:supreme_user, :cancel) # => true
108
- transaction.can?(:guest, :view) # => false
109
- transaction.can?(:undefined_subtarget, :see) # => false
110
- transaction.cant?(:undefined_subtarget, :new) # => true
111
- ```
112
-
113
- If a rule is depending on a certain context, then the context will be evaluated to determine whether the subtarget is authorized or not.
114
-
115
- In the above example, deletion of `transaction` is only allowed if the subtarget is a "finance user" and, the `transaction` itself is already settled.
116
-
117
- Also, asking `can?` on which the subtarget is not yet defined will always return `false`. In the example above, as `undefined_subtarget` is by itself has never been defined in `describe` under `My::Transaction` rule class, `can?` for `undefined_subtarget` will always return `false`. But, `cant` on simillar ocassion will return `true`.
118
-
119
- Rule can also be tested on a class:
120
-
121
- ```ruby
122
- My::Transaction.can?(:supreme_user, :new) # => true
123
- My::Transaction.can?(:guest, :view) # => false
124
- My::Employee.can?(:undefined_subtarget, :new) # => false, rule class for this is by its own undefined
125
- ```
126
-
127
- As we have never define the `rules_for` My::Employee before, any attempt to `can?` for `My::Employee` will return `false`, so does any attempt to object `cant?` on which will only return `true` for any given subtarget and operation.
128
-
129
- ### Can and Cant testing with multiple-roles subtarget
130
-
131
- A subtarget may have multiple roles. For eg., a user may have a role of `finance_user` and `general_user`. A general user normally by itself cannot `delete`, or `cancel`; but a `finance_user` does can, so long the condition is met. But, if a subtarget has role of both `finance_user` and `general_user`, he/she can perform `delete` or `cancel` (so far that the condition is met.)
132
-
133
- Thus, if we have:
134
-
135
- ```ruby
136
- txn = My::Transaction.new
137
- txn.process_transaction(from_user_input)
138
-
139
- # delete or cancel can only happen when a transaction is settled
140
- # as per rule definition
141
- txn.is_settled = true
142
- txn.save
143
-
144
- subtarget = User.new
145
- subtarget.roles = [:finance_user, :general_user]
146
-
147
- txn.can?(subtarget.roles, :delete) # => true
148
- txn.cant?(subtarget.roles, :delete) # => false
149
- txn.can?(:general_user, :delete) # => false
150
- ```
151
-
152
- That is, we can check `can?` and `cant?` with multiple roles by passing array of roles to it.
153
-
154
- ### Using subtarget's instance for Can and Cant testing
155
-
156
- You may pass in real subtarget instance rather than (1) a symbol, (2) string or (3) array of string/symbol for can/cant testing.
157
-
158
- In order to do so, you need to specify the field/method in the subtarget that will be used to evaluating the subtarget's role(s). To do that, we define `roles_for` as follow inside `Bali.map_rules` block:
159
-
160
- ```ruby
161
- Bali.map_rules do
162
- roles_for My::Employee, :roles
163
- roles_for My::AdminUser, :admin_roles
164
- roles_for My::BankUser, :roles
165
-
166
- # rules definition
167
- # may follow
168
- end
169
- ```
170
-
171
- `roles_for` accept two parameters, namely the class of the subtarget, and the field/method that will be invoked on it to gain data about its role(s).
172
-
173
- By doing so, we can now perform authorisation testing as follow:
59
+ Your task is to define rule, with context to `My::Transaction` object, in which:
60
+
61
+ 1. Supreme user can do everything
62
+ 2. Admin user can do everything, but:
63
+ - Can only cancel transaction if the transaction is done using credit card, and the transaction itself is not settled yet
64
+ 3. General user can:
65
+ - Download transaction
66
+ 4. Finance user can:
67
+ - Index transaction
68
+ - Download transaction
69
+ - Delete transaction if the transaction is settled
70
+ - Cancel transaction if the transaction is settled
71
+ 5. Monitoring user can:
72
+ - Index transaction
73
+ - Download transaction
74
+ 6. Sales team can:
75
+ - Index transaction
76
+ - Download transaction
77
+ 6. Unlogged in user can:
78
+ - Index transaction
79
+ - Download transaction
80
+ - Report fraud
81
+ 7. Guest user can:
82
+ - Index transaction
83
+ - Download transaction
84
+ - Report fraud
85
+
86
+ The specification above seems very terrifying, but with Bali, those can be defined in a succinct way, as follow:
174
87
 
175
88
  ```ruby
176
- txn = My::Transaction.new
177
- current_employee = My::Employee.find_by_id(1)
178
- txn.can?(current_employee, :print)
179
- ```
180
-
181
- ### Raises error on unauthorized access
182
-
183
- `can?` and `cant?` just return boolean values on whether access is granted or not. If you want to raise an exception when an operation is inappropriate, use its variant: `can!` and `cant!`
184
-
185
- When `can!` result in denied operation, it will raise `Bali::AuthorizationError`. In the other hand, `cant!` will raise `Bali::AuthorizationError` if it allows an operation.
186
-
187
- `can!` and `cant` are invoked with a similar fashion as you would invoke `can?` and `cant?`
188
-
189
- `Bali::AuthorizationError` is more than an exception, it also store information regarding:
190
-
191
- 1. `auth_level`: whether it is can, or cant testing.
192
- 2. `role`: the role under which authorisation is performed
193
- 3. `subtarget`: the object (if passing an object), or string/symbol representing the role
194
- 4. `operation`: the action
195
- 5. `target`: targeted object/class of the authorization
196
-
197
- ### Rule clause if/unless
198
-
199
- Rule clause may contain `if` and `unless` (decider) proc as already seen before. This `if` and `unless` `proc` have three variants that can be used to express your rule in sufficient detail:
200
-
201
- 1. Zero arity
202
- 2. One arity
203
- 3. Two arity
204
-
205
- When rule is very brief, use zero-arity rule clause as below:
206
-
207
- ```ruby
208
- Bali.map_rules do
209
- rules_for My::Transaction do
210
- describe(:staff) { can :cancel }
211
- describe(:finance) { can :cancel }
89
+ Bali.map_rules do
90
+ rules_for My::Transaction do
91
+ describe(:supreme_user) { can_all }
92
+ describe :admin_user do
93
+ can_all
94
+ # a more specific rule would be executed even if can_all is present
95
+ can :cancel,
96
+ if: proc { |record| record.payment_channel == "CREDIT_CARD" &&
97
+ !record.is_settled? }
98
+ end
99
+ describe "general user", can: [:download]
100
+ describe "finance" do
101
+ can :delete, if: proc { |record| record.is_settled? }
102
+ can :cancel, unless: proc { |record| record.is_settled? }
103
+ end # finance_user description
104
+ describe :guest, nil { can :report_fraud }
105
+ describe :client do
106
+ can :create
107
+ end
108
+ others do
109
+ cannot_all
110
+ can :download, :index
111
+ cannot :create
112
+ end
113
+ end # rules_for
212
114
  end
213
- end
214
115
  ```
215
116
 
216
- Say that (for staff) to cancel a transaction, the transaction must have not been settled yet, you need to define the rule by using one-arity rule clause decider:
117
+ ## Can and Cant? testing
118
+
119
+ Assuming that there exist a variable `transaction` which is an instance of `My::Transaction`:
217
120
 
218
121
  ```ruby
219
- describe :staff do
220
- can :cancel, if: { |txn| txn.is_settled? }
221
- end
122
+ transaction.cant?(:general_user, :delete) # => false
123
+ transaction.can("general user", :download) # => true
124
+ transaction.can?(:finance, :delete) # depends on context
125
+ transaction.can?(:monitoring, :index) # => true
126
+ transaction.can?(:sales, :download) # => true
127
+ transaction.can?(:admin_user, :cancel) # depends on context
128
+ transaction.can?(:supreme_user, :cancel) # => true
129
+ transaction.can?(:guest, :download) # => false
130
+ transaction.can?(nil, :download) # => true
131
+ transaction.can?(nil, :report_fraud) # => true
132
+ transaction.can?(:undefined_subtarget, :see) # => false
133
+ transaction.cant?(:undefined_subtarget, :index) # => true
134
+ transaction.can?(:client, :create) # => true
135
+ transaction.can?(:finance, :create) # => false
136
+ transaction.can?(:admin, :create) # => true
222
137
  ```
223
138
 
224
- Good, but, in addition to that, how to allow transaction cancellation only to staff who has 3 years or so experience in working with the company?
225
-
226
- In order to do that, we need to resort to 2-arity decider, as follow:
139
+ Rule can also be tested on a class:
227
140
 
228
141
  ```ruby
229
- describe :staff do
230
- can :cancel, if: { |txn, usr| txn.is_settled? && usr.exp_years >= 3 }
231
- end
142
+ My::Transaction.can?(:client, :create) # => true
143
+ My::Transaction.can?(:guest, :create) # => false
144
+ My::Employee.can?(:undefined_subtarget, :create) # => false
232
145
  ```
233
146
 
234
- This way, we can keep our controller/logic/model clean from unnecessary and un-DRY role-testing logic.
235
-
236
147
  ## Contributing
237
148
 
238
149
  Bug reports and pull requests are welcome on GitHub at https://github.com/saveav/bali. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
@@ -243,57 +154,4 @@ Bali is proudly available as open source under the terms of the [MIT License](ht
243
154
 
244
155
  ## Changelog
245
156
 
246
- == Version 1.0.0beta1
247
-
248
- 1. Initial version
249
-
250
- == Version 1.0.0rc1
251
-
252
- 1. Fix bug where user can't check on class
253
- 2. Adding new clause: cant_all
254
-
255
- == Version 1.0.0rc2
256
-
257
- 1. [Fix bug when class's name, as a constant, is reloaded](http://stackoverflow.com/questions/2509350/rails-class-object-id-changes-after-i-make-a-request) (re-allocated to different address in the memory)
258
- 2. Allow describing rule for `nil`, useful if user is not authenticated thus role is probably `nil`
259
- 3. Remove pry from development dependency
260
-
261
- == Version 1.0.0rc3
262
-
263
- 1. Each target class should includes `Bali::Objector`, for the following reasons:
264
- - Makes it clear that class do want to include the Bali::Objector
265
- - Transparant, and thus less confusing as to where "can?" and "cant" come from
266
- - When ruby re-parse the class's codes for any reasons, parser will be for sure include Bali::Objector
267
- 2. Return `true` to any `can?` for undefined target/subtarget alike
268
- 3. Return `false` to any `cant?` for undefined target/subtarget alike
269
-
270
- == Version 1.0.0
271
-
272
- 1. Released the stable version of this gem
273
-
274
- == Version 1.1.0rc1
275
-
276
- 1. Ability for rule class to be parsed later by passing `later: true` to rule class definition
277
- 2. Add `Bali.parse` and `Bali.parse!` (`Bali.parse!` executes "later"-tagged rule class, Bali.parse executes automatically after all rules are defined)
278
- 3. Added more thorough testing specs
279
- 4. Proc can be served under `unless` for defining the rule's decider
280
-
281
- == Version 1.1.0rc2
282
-
283
- 1. Ability to check `can?` and `cant?` for subtarget with multiple roles
284
- 2. Describe multiple rules at once for multiple subtarget
285
-
286
- == Version 1.2.0
287
-
288
- 1. Passing real object as subtarget's role, instead of symbol or array of symbol
289
- 2. Clause can also yielding user, along with the object in question
290
-
291
- == Version 2.0.0rc1
292
-
293
- 1. `Bali::AuthorizationError` subclass of `StandardError` tailored for raising error regarding with authorisation
294
- 2. Deprecating `cant`, `cant?`, and `cant_all` in favor of `cannot`, `cannot?` and `cannot_all`
295
- 3. new objectors `can!` and `cannot!` to raise error on inappropriate access
296
-
297
- == Version 2.0.0
298
-
299
- 1. Release!
157
+ Please refer to CHANGELOG.md to see it
@@ -3,12 +3,5 @@
3
3
  require "bundler/setup"
4
4
  require "bali"
5
5
 
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
6
  require "irb"
14
7
  IRB.start
@@ -5,6 +5,7 @@ require_relative "bali/dsl/map_rules_dsl"
5
5
  require_relative "bali/dsl/rules_for_dsl"
6
6
 
7
7
  require_relative "bali/objector"
8
+ require_relative "bali/printer"
8
9
 
9
10
  require_relative "bali/foundations/all_foundations"
10
11
  require_relative "bali/integrators/all_integrators"
@@ -13,12 +14,6 @@ module Bali
13
14
  # mapping class to a RuleClass
14
15
  RULE_CLASS_MAP = {}
15
16
 
16
- # from symbol to full class name
17
- ALIASED_RULE_CLASS_MAP = {}
18
-
19
- # from full class name to symbol
20
- REVERSE_ALIASED_RULE_CLASS_MAP = {}
21
-
22
17
  # {
23
18
  # User: :roles,
24
19
  # AdminUser: :admin_roles
@@ -38,8 +33,6 @@ module Bali
38
33
 
39
34
  def clear_rules
40
35
  Bali::RULE_CLASS_MAP.clear
41
- Bali::REVERSE_ALIASED_RULE_CLASS_MAP.clear
42
- Bali::ALIASED_RULE_CLASS_MAP.clear
43
36
  true
44
37
  end
45
38
  end