rend-acl 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ service_name: travis-ci
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.3"
4
+ - "1.9.2"
5
+ - jruby-19mode
6
+ - rbx-19mode
@@ -1,5 +1,16 @@
1
1
  # Change Log
2
2
 
3
+ ### Version 0.0.5 - June 24th, 2013
4
+
5
+ * Testing
6
+ * Added `Minitest` gem as development dependency
7
+ * Removed `Turn` gem development dependency.
8
+ * Added Travis CI.
9
+ * Added Coveralls.
10
+
11
+ * Documentation
12
+ * Added `/wiki/pages` directories.
13
+
3
14
  ### Version 0.0.4 - June 11th, 2013
4
15
 
5
16
  * Assertions
@@ -20,7 +31,7 @@
20
31
 
21
32
  * `:role`
22
33
  * `:resource`
23
- * `:prilvilege`
34
+ * `:privilege`
24
35
  * `:assertion` -- _Not utilized in `.allowed?()` method._
25
36
 
26
37
  ### Version <= 0.0.3
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in rend-acl.gemspec
4
4
  gemspec
5
+
6
+ gem 'coveralls', :require => false
7
+
8
+
data/README.md CHANGED
@@ -1,25 +1,112 @@
1
1
  # Rend Acl
2
2
 
3
+ [![Build Status](https://travis-ci.org/veloper/rend-acl.png?branch=master)](https://travis-ci.org/veloper/rend-acl)
4
+ [![Coverage Status](https://coveralls.io/repos/veloper/rend-acl/badge.png)](https://coveralls.io/r/veloper/rend-acl)
5
+ [![Dependency Status](https://gemnasium.com/veloper/rend-acl.png)](https://gemnasium.com/veloper/rend-acl)
6
+
3
7
  Rend-Acl is a port of [Zend_Acl](http://framework.zend.com/manual/1.12/en/zend.acl.html) with modifications made to bring the api more inline with Ruby conventions.
4
8
 
9
+ ## Introduction
10
+ Rend-Acl provides a lightweight and flexible access control list (ACL) implementation for privileges management. In general, an application may utilize such ACL's to control access to certain protected objects by other requesting objects.
11
+
12
+ For the purposes of this documentation:
13
+
14
+ * A **Role** is an object that may request access to a Resource or Privilege.
15
+ * _(e.g., "Passenger", "Driver", "Mechanic")_
16
+ * A **Resource** is an object to which access is controlled.
17
+ * _(e.g., "Car", "Boat", "Train")_
18
+ * A **Privilege** is an _(optional)_ level of control which enables further refinement.
19
+ * _(e.g., "Drive", "Sell", "Repair")_
20
+
21
+ Through use of an ACL an application may control how roles are granted access to resources and privilages.
22
+
23
+ ### Still Lost?
24
+ These terms and concepts become easier to understand when translated into plain english...
25
+
26
+ ```ruby
27
+ @acl.allow! :role => "Driver", :resource => "Car"
28
+ ```
29
+ > __Translation:__ Allow a **Driver** full-access to the **Car**.
30
+
31
+ ```ruby
32
+ @acl.allow! :role => "Driver", :resource => "Car", :privilege => "Sell"
33
+ ```
34
+ > __Translation:__ Allow a **Driver** to **Sell** the **Car**.
35
+
36
+ ```ruby
37
+ @acl.allow! :role => "Mechanic", :privilege => "Repair"
38
+ ```
39
+ > __Translation:__ Allow a **Mechanic** to **Repair** anything.
40
+
41
+
42
+ ## Basic Usage Example
43
+
44
+ ```ruby
45
+ # ==> Require Rend ACL
46
+ require 'rend/acl'
47
+
48
+ # ==> Initialize ACL Object
49
+ @acl = Rend::Acl.new
50
+
51
+ # ==> Add Roles & Resources to ACL
52
+ @acl.add! :role => ["Passenger", "Driver", "Mechanic"],
53
+ :resource => ["Car", "Boat", "Train"]
54
+
55
+ # ==> Declare Rules - Note: When conflicts occur the last rule always wins!
56
+
57
+ # Translation: Allow the "Driver" Role full-access to the "Car" Resource.
58
+ @acl.allow! :role => "Driver", :resource => "Car"
59
+
60
+ # Translation: Allow the "Mechanic" Role the privilege to "Repair" any Resource.
61
+ @acl.allow! :role => "Mechanic", :privilege => "Repair"
62
+
63
+ # Translation: Allow all Roles the privilege to "Look" at any Resource.
64
+ @acl.allow! :privilege => "Look"
65
+
66
+ # Translation: Deny all Roles any access to the "Train" Resource.
67
+ @acl.deny! :resource => "Train"
68
+
69
+ # ==> Querying
70
+ @acl.allowed?(:role => "Driver", :resource => "Car") # TRUE
71
+ @acl.allowed?(:role => "Passenger", :resource => "Car") # FALSE
72
+ @acl.allowed?(:role => "Mechanic", :resource => "Car") # FALSE
73
+ @acl.allowed?(:role => "Mechanic", :privilege => "Repair") # TRUE
74
+ @acl.allowed?(:role => "Passenger", :privilege => "Look") # TRUE
75
+ @acl.allowed?(:role => "Passenger", :resource => "Train") # FALSE
76
+ @acl.allowed?(:role => "Mechanic", :resource => "Train", :privilege => "Repair") # FALSE
77
+ ```
78
+
5
79
  ## Installation
6
80
 
81
+ Install this gem directly using...
82
+
7
83
  gem install rend-acl
8
84
 
85
+ ... or simply include it in your project's `Gemfile` ...
86
+
87
+ gem 'rend-acl', '~> 0.0.5'
88
+
89
+ ## Requirements
90
+
91
+ * Ruby >= 1.9.2
92
+
9
93
  ## Contributing
10
94
 
11
95
  1. Fork it
12
96
  2. Create your feature branch (`git checkout -b my-new-feature`)
13
- 3. Commit your changes (`git commit -am 'Add some feature'`)
97
+ 3. Commit your changes **(with passing tests please!)** (`git commit -am 'Add some feature'`)
14
98
  4. Push to the branch (`git push origin my-new-feature`)
15
99
  5. Create new Pull Request
100
+ 6. ???
101
+ 7. Profit!
16
102
 
17
103
  ## Licensing
18
104
 
19
- * All ported Ruby code and assoicated 'Rend' gems are under a simple [New-BSD License](http://dan.doezema.com/licenses/new-bsd).
105
+ * All ported Ruby code and associated 'Rend' gems are under a simple [New-BSD License](http://dan.doezema.com/licenses/new-bsd).
20
106
  * Original PHP code is licensed under [Zend's New-BSD License](http://framework.zend.com/license/).
21
107
  * This license can be found in `./ZEND_FRAMEWORK_LICENSE.txt`
22
108
 
23
109
  ## Acknowledgements
24
- * This project is **not** associated with, or endorsed by, Zend Technologies USA, Inc., nor any of its contributors.
25
- * Rend's modular design was heavily influced by [RSpec](https://github.com/rspec/rspec)'s approach.
110
+
111
+ * This project is **NOT** associated with, or endorsed by, Zend Technologies USA, Inc., nor any of its contributors.
112
+ * Rend's modular design was heavily influenced by [RSpec](https://github.com/rspec/rspec)'s approach.
@@ -372,9 +372,6 @@ module Rend
372
372
  privileges = options.fetch(:privilege, nil)
373
373
  assertion = options.fetch(:assertion, nil)
374
374
  end
375
- roles = nil if roles == :all
376
- resources = nil if resources == :all
377
- privileges = nil if privileges == :all
378
375
 
379
376
  type_hint! Rend::Acl::Assertion, assertion
380
377
 
@@ -397,9 +394,6 @@ module Rend
397
394
  privileges = options.fetch(:privilege, nil)
398
395
  assertion = options.fetch(:assertion, nil)
399
396
  end
400
- roles = nil if roles == :all
401
- resources = nil if resources == :all
402
- privileges = nil if privileges == :all
403
397
 
404
398
  type_hint! Rend::Acl::Assertion, assertion
405
399
 
@@ -421,9 +415,6 @@ module Rend
421
415
  privileges = options.fetch(:privilege, nil)
422
416
  assertion = options.fetch(:assertion, nil)
423
417
  end
424
- roles = nil if roles == :all
425
- resources = nil if resources == :all
426
- privileges = nil if privileges == :all
427
418
 
428
419
  set_rule!(OP_REMOVE, TYPE_ALLOW, roles, resources, privileges, assertion)
429
420
  end
@@ -443,9 +434,6 @@ module Rend
443
434
  privileges = options.fetch(:privilege, nil)
444
435
  assertion = options.fetch(:assertion, nil)
445
436
  end
446
- roles = nil if roles == :all
447
- resources = nil if resources == :all
448
- privileges = nil if privileges == :all
449
437
 
450
438
  set_rule!(OP_REMOVE, TYPE_DENY, roles, resources, privileges, assertion)
451
439
  end
@@ -491,166 +479,38 @@ module Rend
491
479
  # @uses Rend::Acl::get!()
492
480
  # @return Rend::Acl Provides a fluent interface
493
481
  def set_rule!(operation, type, roles = nil, resources = nil, privileges = nil, assertion = nil)
494
- type_hint! Rend::Acl::Assertion, assertion
482
+ type_hint! Rend::Acl::Assertion, assertion
495
483
 
496
- # ensure that the rule type is valid normalize input to uppercase
497
- type = type.upcase
498
- if type != TYPE_ALLOW && type != TYPE_DENY
499
- raise Rend::Acl::Exception, "Unsupported rule type must be either '#{TYPE_ALLOW}' or '#{TYPE_DENY}'"
500
- end
484
+ # ensure that the rule type is valid normalize input to uppercase
485
+ if type != TYPE_ALLOW && type != TYPE_DENY
486
+ raise Rend::Acl::Exception, "Unsupported rule type must be either '#{TYPE_ALLOW}' or '#{TYPE_DENY}'"
487
+ end
501
488
 
502
- # ensure that all specified Roles exist normalize input to array of Role objects or nil
503
- if !roles.is_a?(Array)
504
- roles = [roles]
505
- elsif roles.empty?
506
- roles = [nil]
507
- end
508
- roles = roles.reduce([]) do |seed, role|
509
- seed << (role ? role_registry.get!(role) : nil)
510
- end
489
+ # ensure that all specified Roles exist normalize input to array of Role objects or nil
490
+ roles = Array(roles)
491
+ roles << nil if roles.empty?
492
+ roles = roles.reduce([]) {|seed, role| seed << (role ? role_registry.get!(role) : nil)}
511
493
 
512
- # ensure that all specified Resources exist normalize input to array of Resource objects or nil
513
- if resources
514
- resources = Array(resources)
515
- resources << nil if resources.empty?
516
- resources = resources.reduce([]) do |seed, resource|
517
- seed << (resource ? resource!(resource) : nil)
518
- end
519
- else
520
- # this might be used later if resource iteration is required
521
- all_resources = @_resources.values.reduce([]) do |seed, r_target|
522
- seed << r_target[:instance]
523
- end
524
- end
525
-
526
- # normalize privileges to array
527
- if privileges.nil?
528
- privileges = []
529
- elsif !privileges.is_a?(Array)
530
- privileges = [privileges]
531
- end
494
+ # ensure that all specified Resources exist normalize input to array of Resource objects or nil
495
+ if resources
496
+ resources = Array(resources)
497
+ resources << nil if resources.empty?
498
+ resources = resources.reduce([]) {|seed, resource| seed << (resource ? resource!(resource) : nil)}
499
+ end
532
500
 
533
- case operation
534
-
535
- # add to the rules
536
- when OP_ADD
537
- if resources
538
- # this block will iterate the provided resources
539
- resources.each do |resource|
540
- roles.each do |role|
541
- rules = _rules(resource, role, true)
542
- if privileges.empty?
543
- rules[:all_privileges] = {
544
- :type => type,
545
- :assertion => assertion
546
- }
547
- rules[:by_privilege_id] = {} unless rules.has_key?(:by_privilege_id)
548
- else
549
- privileges.each do |privilege|
550
- rules[:by_privilege_id][privilege] = {
551
- :type => type,
552
- :assertion => assertion
553
- }
554
- end
555
- end
556
- end
557
- end
558
- else
559
- # this block will apply to all resources in a global rule
560
- roles.each do |role|
561
- rules = _rules(nil, role, true)
562
- if privileges.empty?
563
- rules[:all_privileges] = {
564
- :type => type,
565
- :assertion => assertion
566
- }
567
- else
568
- privileges.each do |privilege|
569
- rules[:by_privilege_id][privilege] = {
570
- :type => type,
571
- :assertion => assertion
572
- }
573
- end
574
- end
575
- end
576
- end
577
- # remove from the rules
578
- when OP_REMOVE
579
- if resources
580
- # this block will iterate the provided resources
581
- resources.each do |resource|
582
- roles.each do |role|
583
- rules = _rules(resource, role)
584
- next if rules.nil?
585
- if privileges.empty?
586
- if resource.nil? && role.nil?
587
- if rules[:all_privileges][:type] == type
588
- rules.replace({
589
- :all_privileges => {
590
- :type => TYPE_DENY,
591
- :assertion => nil
592
- },
593
- :by_privilege_id => {}
594
- })
595
- end
596
- next
597
- end
598
- if rules[:all_privileges].has_key?(:type) && rules[:all_privileges][:type] == type
599
- rules.delete(:all_privileges)
600
- end
601
- else
602
- privileges.each do |privilege|
603
- if rules[:by_privilege_id].has_key?(privilege) && rules[:by_privilege_id][privilege][:type] == type
604
- rules[:by_privilege_id].delete(privilege)
605
- end
606
- end
607
- end
608
- end
609
- end
610
- else
611
- # this block will apply to all resources in a global rule
612
- roles.each do |role|
613
-
614
- # since nil (all resources) was passed to this set_role!() call, we need
615
- # clean up all the rules for the global allResources, as well as the indivually
616
- # set resources (per privilege as well)
617
- [nil].concat(all_resources).each do |resource|
618
- rules = _rules(resource, role, true)
619
- next if rules.nil?
620
- if privileges.empty?
621
- if role.nil?
622
- if rules[:all_privileges][:type] == type
623
- rules.replace({
624
- :all_privileges => {
625
- :type => TYPE_DENY,
626
- :assertion => nil
627
- },
628
- :by_privilege_id => {}
629
- })
630
- end
631
- next
632
- end
633
-
634
- if rules[:all_privileges].has_key?(:type) && rules[:all_privileges][:type] == type
635
- rules.delete(:all_privileges)
636
- end
637
- else
638
- privileges.each do |privilege|
639
- if rules[:by_privilege_id].has_key?(privilege) && rules[:by_privilege_id][privilege][:type] == type
640
- rules[:by_privilege_id].delete(privilege)
641
- end
642
- end
643
- end
644
- end
645
- end
646
- end
647
- else
648
- raise Rend::Acl::Exception, "Unsupported operation must be either '#{OP_ADD}' or '#{OP_REMOVE}'"
649
- end
501
+ # normalize privileges to array
502
+ privileges = Array(privileges).compact
650
503
 
651
- self
504
+ case operation
505
+ when OP_ADD then _add_rule!(type, roles, resources, privileges, assertion)
506
+ when OP_REMOVE then _remove_rule!(type, roles, resources, privileges, assertion)
507
+ else
508
+ raise Rend::Acl::Exception, "Unsupported operation must be either '#{OP_ADD}' or '#{OP_REMOVE}'"
652
509
  end
653
510
 
511
+ self
512
+ end
513
+
654
514
  # Returns true if and only if the Role has access to the Resource
655
515
  #
656
516
  # The role and resource parameters may be references to, or the string identifiers for,
@@ -691,11 +551,6 @@ module Rend
691
551
  privilege = options.fetch(:privilege, nil)
692
552
  end
693
553
 
694
- # Readability
695
- role = nil if role == :all
696
- resource = nil if resource == :all
697
- privilege = nil if privilege == :all
698
-
699
554
  if role
700
555
  # keep track of originally called role
701
556
  @_is_allowed_role = role
@@ -758,6 +613,11 @@ module Rend
758
613
  end
759
614
  end
760
615
 
616
+ # Inverse of allowed? method
617
+ def denied?(*args)
618
+ !allowed?(*args)
619
+ end
620
+
761
621
  # Returns the Role registry for this ACL
762
622
  #
763
623
  # If no Role registry has been created yet, a new default Role registry
@@ -768,6 +628,27 @@ module Rend
768
628
  @_role_registry ||= Rend::Acl::Role::Registry.new
769
629
  end
770
630
 
631
+ # Returns an array of registered roles.
632
+ #
633
+ # Note that this method does not return instances of registered roles,
634
+ # but only the role identifiers.
635
+ #
636
+ # @return array of registered roles
637
+ def roles
638
+ role_registry.roles.keys
639
+ end
640
+
641
+ # @return array of registered resources
642
+ def resources
643
+ @_resources.keys
644
+ end
645
+
646
+ # == PROTECTED ================================================================================
647
+
648
+ protected
649
+
650
+ # =============================================================================================
651
+
771
652
  # Performs a depth-first search of the Role DAG, starting at role, in order to find a rule
772
653
  # allowing/denying role access to all privileges upon resource
773
654
  #
@@ -1000,19 +881,101 @@ module Rend
1000
881
  visitor[:by_role_id][role.id]
1001
882
  end
1002
883
 
1003
- # Returns an array of registered roles.
1004
- #
1005
- # Note that this method does not return instances of registered roles,
1006
- # but only the role identifiers.
1007
- #
1008
- # @return array of registered roles
1009
- def roles
1010
- role_registry.roles.keys
884
+ def _add_rule!(type, roles, resources, privileges, assertion)
885
+ if resources
886
+ # this block will iterate the provided resources
887
+ resources.each do |resource|
888
+ roles.each do |role|
889
+ rules = _rules(resource, role, true)
890
+ if privileges.empty?
891
+ rules[:all_privileges] = {:type => type, :assertion => assertion}
892
+ rules[:by_privilege_id] = {} unless rules.has_key?(:by_privilege_id)
893
+ else
894
+ privileges.each do |privilege|
895
+ rules[:by_privilege_id][privilege] = {:type => type, :assertion => assertion}
896
+ end
897
+ end
898
+ end
899
+ end
900
+ else
901
+ # this block will apply to all resources in a global rule
902
+ roles.each do |role|
903
+ rules = _rules(nil, role, true)
904
+ if privileges.empty?
905
+ rules[:all_privileges] = {:type => type, :assertion => assertion}
906
+ else
907
+ privileges.each do |privilege|
908
+ rules[:by_privilege_id][privilege] = {:type => type, :assertion => assertion}
909
+ end
910
+ end
911
+ end
912
+ end
1011
913
  end
1012
914
 
1013
- # @return array of registered resources
1014
- def resources
1015
- @_resources.keys
915
+ def _remove_rule!(type, roles, resources, privileges, assertion)
916
+ if resources
917
+ # this block will iterate the provided resources
918
+ resources.each do |resource|
919
+ roles.each do |role|
920
+ rules = _rules(resource, role)
921
+ next if rules.nil?
922
+ if privileges.empty?
923
+ if resource.nil? && role.nil?
924
+ if rules[:all_privileges][:type] == type
925
+ rules.replace({
926
+ :all_privileges => {
927
+ :type => TYPE_DENY,
928
+ :assertion => nil
929
+ },
930
+ :by_privilege_id => {}
931
+ })
932
+ end
933
+ next
934
+ end
935
+ rules.delete(:all_privileges) if rules[:all_privileges][:type] == type
936
+ else
937
+ privileges.each do |privilege|
938
+ if rules[:by_privilege_id].has_key?(privilege) && rules[:by_privilege_id][privilege][:type] == type
939
+ rules[:by_privilege_id].delete(privilege)
940
+ end
941
+ end
942
+ end
943
+ end
944
+ end
945
+ else
946
+ all_resources = @_resources.values.reduce([]) {|seed, r_target| seed << r_target[:instance]}
947
+
948
+ # this block will apply to all resources in a global rule
949
+ roles.each do |role|
950
+
951
+ # since nil (all resources) was passed to this set_role!() call, we need
952
+ # clean up all the rules for the global all_resources, as well as the indivually
953
+ # set resources (per privilege as well)
954
+ [nil].concat(all_resources).each do |resource|
955
+ rules = _rules(resource, role, true)
956
+ next if rules.nil?
957
+ if privileges.empty?
958
+ if role.nil?
959
+ if rules[:all_privileges][:type] == type
960
+ rules.replace(:all_privileges => {:type => TYPE_DENY, :assertion => nil}, :by_privilege_id => {})
961
+ end
962
+ next
963
+ end
964
+
965
+ if rules[:all_privileges].has_key?(:type) && rules[:all_privileges][:type] == type
966
+ rules.delete(:all_privileges)
967
+ end
968
+ else
969
+ privileges.each do |privilege|
970
+ if rules[:by_privilege_id].has_key?(privilege) && rules[:by_privilege_id][privilege][:type] == type
971
+ rules[:by_privilege_id].delete(privilege)
972
+ end
973
+ end
974
+ end
975
+ end
976
+ end
977
+ end
1016
978
  end
979
+
1017
980
  end
1018
981
  end
@@ -1,28 +0,0 @@
1
- # Not a required file -- used for testing
2
- module Rend
3
- class Acl
4
- class MockAssertion < Rend::Acl::Assertion
5
-
6
- attr_reader :last_acl
7
- attr_reader :last_role
8
- attr_reader :last_resource
9
- attr_reader :last_privilege
10
-
11
- attr_accessor :pass
12
-
13
- def initialize(pass = nil, &block)
14
- self.pass = block_given? ? block : pass
15
- end
16
-
17
- def pass=(value)
18
- @pass = value.is_a?(Proc) ? value : lambda {|acl, role, resource, privilege| value}
19
- end
20
-
21
- def pass?(acl, role = nil, resource = nil, privilege = nil)
22
- @last_acl, @last_role, @last_resource, @last_privilege = acl, role, resource, privilege
23
- pass.call(acl, role, resource, privilege)
24
- end
25
-
26
- end
27
- end
28
- end
@@ -1,7 +1,7 @@
1
1
  module Rend
2
2
  class Acl
3
3
  module Version
4
- STRING = "0.0.4"
4
+ STRING = "0.0.5"
5
5
  end
6
6
  end
7
7
  end
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Rend::Acl::Version::STRING
9
9
  spec.authors = ["Daniel Doezema"]
10
10
  spec.email = ["daniel.doezema@gmail.com"]
11
- spec.description = "A port of Zend_Acl with modifications made to bring the api more inline with Ruby conventions."
11
+ spec.description = "A port of Zend_Acl with modifications made to bring the API more inline with Ruby conventions."
12
12
  spec.summary = "rend-acl-#{Rend::Acl::Version::STRING}"
13
13
  spec.homepage = "https://github.com/veloper/rend-acl"
14
14
  spec.license = "New-BSD"
@@ -21,10 +21,10 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_development_dependency "bundler", "~> 1.3"
23
23
  spec.add_development_dependency "rake"
24
- spec.add_development_dependency "turn"
24
+ spec.add_development_dependency "minitest", "~> 5.0.5"
25
25
 
26
- dependency_gems = ['rend-core']
27
26
 
27
+ dependency_gems = ['rend-core']
28
28
  dependency_gems.each do |gem_name|
29
29
  if Rend::Acl::Version::STRING =~ /[a-zA-Z]+/
30
30
  spec.add_runtime_dependency "#{gem_name}", "= #{Rend::Acl::Version::STRING}"
@@ -0,0 +1,14 @@
1
+ # https://coveralls.io Integration
2
+ require 'coveralls'
3
+ Coveralls.wear!
4
+
5
+ # Gem
6
+ require 'rend/acl'
7
+
8
+ # Testing Support
9
+ require 'support/mock_assertion'
10
+ require 'support/passing_assertion'
11
+ require 'support/failing_assertion'
12
+
13
+ # Autorun tests
14
+ require "minitest/autorun"
@@ -0,0 +1,7 @@
1
+ class FailingAssertion < Rend::Acl::Assertion
2
+
3
+ def pass?(acl, role = nil, resource = nil, privilege = nil)
4
+ false
5
+ end
6
+
7
+ end
@@ -0,0 +1,23 @@
1
+ class MockAssertion < Rend::Acl::Assertion
2
+
3
+ attr_reader :last_acl
4
+ attr_reader :last_role
5
+ attr_reader :last_resource
6
+ attr_reader :last_privilege
7
+
8
+ attr_accessor :pass
9
+
10
+ def initialize(pass = nil, &block)
11
+ self.pass = block_given? ? block : pass
12
+ end
13
+
14
+ def pass=(value)
15
+ @pass = value.is_a?(Proc) ? value : lambda {|acl, role, resource, privilege| value}
16
+ end
17
+
18
+ def pass?(acl, role = nil, resource = nil, privilege = nil)
19
+ @last_acl, @last_role, @last_resource, @last_privilege = acl, role, resource, privilege
20
+ pass.call(acl, role, resource, privilege)
21
+ end
22
+
23
+ end
@@ -0,0 +1,7 @@
1
+ class PassingAssertion < Rend::Acl::Assertion
2
+
3
+ def pass?(acl, role = nil, resource = nil, privilege = nil)
4
+ true
5
+ end
6
+
7
+ end
@@ -1,28 +1,35 @@
1
- require 'test/unit'
2
- require 'rend/acl'
3
- require 'rend/acl/mock_assertion'
4
- require 'yaml'
5
- begin; require 'turn/autorun'; rescue LoadError; end
1
+ require 'helper'
6
2
 
7
-
8
- class AclTest < Test::Unit::TestCase
3
+ class AclTest < Minitest::Test
9
4
 
10
5
  def setup
11
6
  @acl = Rend::Acl.new
12
7
  end
13
8
 
9
+ def test_access_is_limited_by_privilege
10
+ @acl.add! :role => "driver", :resource => "car"
11
+ @acl.allow! :role => "driver", :resource => "car", :privilege => "sell"
12
+ assert_equal false, @acl.allowed?("driver", "car")
13
+ assert_equal true, @acl.allowed?("driver", "car", "sell")
14
+ end
15
+
14
16
  def test_storing_acl_data_for_persistence_with_marshal
15
- assert_use_case_1 Marshal.load( Marshal.dump(use_case_1) )
17
+ assert_use_case_2 Marshal.load( Marshal.dump(use_case_2) )
16
18
  end
17
19
 
18
20
  def test_storing_acl_data_for_persistence_with_yaml
19
- assert_use_case_1 YAML.load( YAML.dump(use_case_1) )
21
+ require 'yaml'
22
+ assert_use_case_2 YAML.load( YAML.dump(use_case_2) )
20
23
  end
21
24
 
22
25
  def test_use_case_1
23
26
  assert_use_case_1(use_case_1)
24
27
  end
25
28
 
29
+ def test_use_case_2
30
+ assert_use_case_2(use_case_2)
31
+ end
32
+
26
33
  def test_add_raises_argument_error_with_no_args
27
34
  assert_raises ArgumentError do
28
35
  @acl.add!
@@ -138,7 +145,54 @@ class AclTest < Test::Unit::TestCase
138
145
  assert @acl.inherits_resource? "room", "building"
139
146
  end
140
147
 
141
- # == Orignal Zend_Acl Tests Below ==
148
+ def test_alternate_syntax_hash_syntax
149
+ @acl.add!(
150
+ :resource => %w[car motorcycle plane boat bike],
151
+ :role => ["valet", "owner", "thief", "me"]
152
+ )
153
+ @acl.allow! :resource => "bike"
154
+ @acl.allow! :privilege => "clean"
155
+ @acl.allow! :role => "valet", :resource => %w[car motorcycle], :privilege => %w[park open]
156
+ @acl.allow! :role => "thief", :resource => %w[car motorcycle boat]
157
+ @acl.allow! :role => "owner"
158
+
159
+ # Nil permutations for :role, :resource, :privilege
160
+ assert_equal true, @acl.allowed?(:role => "owner")
161
+ assert_equal true, @acl.allowed?(:role => "owner", :resource => nil)
162
+ assert_equal true, @acl.allowed?(:role => "owner", :resource => nil, :privilege => nil)
163
+ assert_equal true, @acl.allowed?(:resource => "bike")
164
+ assert_equal true, @acl.allowed?(:resource => "bike", :role => nil)
165
+ assert_equal true, @acl.allowed?(:resource => "bike", :role => nil, :privilege => nil)
166
+ assert_equal true, @acl.allowed?(:privilege => "clean")
167
+ assert_equal true, @acl.allowed?(:privilege => "clean", :resource => nil)
168
+ assert_equal true, @acl.allowed?(:privilege => "clean", :resource => nil, :role => nil)
169
+
170
+ # Spot Checks
171
+ assert_equal true, @acl.allowed?(:role => "valet", :privilege => "clean")
172
+ assert_equal true, @acl.allowed?(:role => "valet", :resource => "bike")
173
+ assert_equal true, @acl.allowed?(:role => "valet", :resource => "car", :privilege => "park")
174
+ assert_equal true, @acl.allowed?(:role => "valet", :resource => "car", :privilege => "open")
175
+ assert_equal true, @acl.allowed?(:role => "valet", :resource => "motorcycle", :privilege => "park")
176
+ assert_equal true, @acl.allowed?(:role => "valet", :resource => "motorcycle", :privilege => "open")
177
+ assert_equal false, @acl.allowed?(:role => "valet", :privilege => "park")
178
+ assert_equal false, @acl.allowed?(:role => "valet", :privilege => "open")
179
+ assert_equal false, @acl.allowed?(:role => "valet", :resource => "plane", :privilege => "park")
180
+ assert_equal false, @acl.allowed?(:role => "valet", :resource => "plane", :privilege => "open")
181
+ end
182
+
183
+ def test_denied_method_is_inverse_of_allowed_method
184
+ acl = use_case_1
185
+ assert_equal true, acl.denied?('staff' , 'newsletter' , 'publish') # allowed
186
+ assert_equal false, acl.denied?('marketing' , 'newsletter' , 'publish') # denied
187
+ assert_equal true, acl.denied?('staff' , 'latest' , 'publish') # allowed
188
+ assert_equal false, acl.denied?('marketing' , 'latest' , 'publish') # denied
189
+ assert_equal false, acl.denied?('marketing' , 'latest' , 'archive') # denied
190
+ assert_equal true, acl.denied?('marketing' , 'latest' , 'revise') # allowed
191
+ assert_equal true, acl.denied?('editor' , 'announcement' , 'archive') # allowed
192
+ assert_equal true, acl.denied?('administrator' , 'announcement' , 'archive') # allowed
193
+ end
194
+
195
+ # == Tests From Zend_Acl Suite Below ==
142
196
 
143
197
  # Ensures that basic addition and retrieval of a single Role works
144
198
  def test_role_registry_add_and_get_one
@@ -616,6 +670,26 @@ class AclTest < Test::Unit::TestCase
616
670
  assert_equal false, @acl.allowed?(nil, 'area')
617
671
  end
618
672
 
673
+ def test_basic_example
674
+ @acl = Rend::Acl.new
675
+
676
+ @acl.add! :role => ["Passenger", "Driver", "Mechanic"], :resource => ["Car", "Boat", "Train"]
677
+
678
+ @acl.allow! :role => "Driver", :resource => "Car"
679
+ @acl.allow! :role => "Mechanic", :privilege => "Repair"
680
+ @acl.allow! :privilege => "Look" # Allow any role the ability to Look at any resource.
681
+ @acl.deny! :resource => "Train" # Deny all roles access to the Train resource.
682
+
683
+
684
+ assert_equal true, @acl.allowed?(:role => "Driver", :resource => "Car")
685
+ assert_equal false, @acl.allowed?(:role => "Passenger", :resource => "Car")
686
+ assert_equal false, @acl.allowed?(:role => "Mechanic", :resource => "Car")
687
+ assert_equal true, @acl.allowed?(:role => "Mechanic", :privilege => "Repair")
688
+ assert_equal true, @acl.allowed?(:role => "Passenger", :privilege => "Look")
689
+ assert_equal false, @acl.allowed?(:role => "Passenger", :resource => "Train")
690
+ assert_equal false, @acl.allowed?(:role => "Mechanic", :resource => "Train", :privilege => "Repair")
691
+ end
692
+
619
693
  # Ensures that an example for a content management system is operable
620
694
  def test_cms_example
621
695
  # Add some roles to the Role registry
@@ -777,7 +851,7 @@ class AclTest < Test::Unit::TestCase
777
851
 
778
852
  # Ensures that the default rule obeys its assertion
779
853
  def test_default_assert
780
- @acl.deny!(nil, nil, nil, Rend::Acl::MockAssertion.new(false))
854
+ @acl.deny!(nil, nil, nil, MockAssertion.new(false))
781
855
  assert_equal true, @acl.allowed?
782
856
  assert_equal true, @acl.allowed?(nil, nil, 'some_privilege')
783
857
  end
@@ -958,10 +1032,10 @@ class AclTest < Test::Unit::TestCase
958
1032
 
959
1033
  # Ensures that assertions on privileges work properly
960
1034
  def test_privilege_assert
961
- @acl.allow!(nil, nil, 'some_privilege', Rend::Acl::MockAssertion.new(true))
1035
+ @acl.allow!(nil, nil, 'some_privilege', MockAssertion.new(true))
962
1036
  assert_equal true, @acl.allowed?(nil, nil, 'some_privilege')
963
1037
 
964
- @acl.allow!(nil, nil, 'some_privilege', Rend::Acl::MockAssertion.new(false))
1038
+ @acl.allow!(nil, nil, 'some_privilege', MockAssertion.new(false))
965
1039
  assert_equal false, @acl.allowed?(nil, nil, 'some_privilege')
966
1040
  end
967
1041
 
@@ -970,16 +1044,16 @@ class AclTest < Test::Unit::TestCase
970
1044
  role_guest = Rend::Acl::Role.new('guest')
971
1045
  @acl.add_role!(role_guest)
972
1046
 
973
- @acl.allow!(role_guest, nil, 'some_privilege', Rend::Acl::MockAssertion.new(true))
1047
+ @acl.allow!(role_guest, nil, 'some_privilege', MockAssertion.new(true))
974
1048
  assert_equal true, @acl.allowed?(role_guest, nil, 'some_privilege')
975
1049
 
976
- @acl.allow!(role_guest, nil, 'some_privilege', Rend::Acl::MockAssertion.new(false))
1050
+ @acl.allow!(role_guest, nil, 'some_privilege', MockAssertion.new(false))
977
1051
  assert_equal false, @acl.allowed?(role_guest, nil, 'some_privilege')
978
1052
  end
979
1053
 
980
1054
  # # Ensures that removing the default deny rule results in assertion method being removed
981
1055
  def test_remove_default_deny_assert
982
- @acl.deny!(nil, nil, nil, Rend::Acl::MockAssertion.new(false))
1056
+ @acl.deny!(nil, nil, nil, MockAssertion.new(false))
983
1057
  assert_equal true, @acl.allowed?
984
1058
  @acl.remove_deny!
985
1059
  assert_equal false, @acl.allowed?
@@ -988,7 +1062,7 @@ class AclTest < Test::Unit::TestCase
988
1062
 
989
1063
  # @group ZF-1721
990
1064
  def test_acl_assertions_get_proper_role_when_inheritence_is_used
991
- assertion = Rend::Acl::MockAssertion.new(true)
1065
+ assertion = MockAssertion.new(true)
992
1066
 
993
1067
  @acl.add! :role => ['guest', {'contributor' => 'guest'}, {'publisher' => 'contributor'}, 'admin'], :resource => 'blog_post'
994
1068
 
@@ -1008,7 +1082,7 @@ class AclTest < Test::Unit::TestCase
1008
1082
 
1009
1083
  # @group ZF-7973
1010
1084
  def test_acl_passes_privilege_to_assert_class
1011
- assertion = Rend::Acl::MockAssertion.new do |acl, role, resource, privilege|
1085
+ assertion = MockAssertion.new do |acl, role, resource, privilege|
1012
1086
  privilege == "read"
1013
1087
  end
1014
1088
 
@@ -1078,4 +1152,18 @@ class AclTest < Test::Unit::TestCase
1078
1152
  assert_equal false, acl.allowed?('editor' , 'announcement' , 'archive') # denied
1079
1153
  assert_equal false, acl.allowed?('administrator' , 'announcement' , 'archive') # denied
1080
1154
  end
1155
+
1156
+ def use_case_2
1157
+ acl = use_case_1
1158
+ acl.allow! :privilege => 'passing_assertion', :assertion => PassingAssertion.new
1159
+ acl.allow! :privilege => 'failing_assertion', :assertion => FailingAssertion.new
1160
+ acl
1161
+ end
1162
+
1163
+ def assert_use_case_2(acl)
1164
+ assert_use_case_1(acl)
1165
+ assert_equal true, acl.allowed?(nil, nil, 'passing_assertion') # allowed
1166
+ assert_equal false, acl.allowed?(nil, nil, 'failing_assertion') # denied
1167
+ end
1168
+
1081
1169
  end
@@ -0,0 +1,25 @@
1
+ require 'helper'
2
+
3
+ class DocumentationExamplesTest < Minitest::Test
4
+
5
+ def setup
6
+ @acl = Rend::Acl.new
7
+ end
8
+
9
+ def test_wiki_resource_inheritance_example
10
+ city_resource = Rend::Acl::Resource.new("city")
11
+ building_resource = Rend::Acl::Resource.new("building")
12
+
13
+ @acl.add_resource!(city_resource)
14
+ @acl.add_resource!(building_resource, city_resource)
15
+
16
+ mayor_role = Rend::Acl::Role.new("mayor")
17
+ @acl.add_role!(mayor_role)
18
+
19
+ @acl.allow! :role => mayor_role, :resource => city_resource
20
+
21
+ assert_equal true, @acl.allowed?(:role => mayor_role, :resource => city_resource)
22
+ assert_equal true, @acl.allowed?(:role => mayor_role, :resource => building_resource)
23
+ end
24
+
25
+ end
@@ -0,0 +1,37 @@
1
+ A ***Resource*** is simply an object to which access is controlled.
2
+
3
+ ## Resource Class
4
+ Rend-Acl provides the `Rend::Acl::Resource` class as a basic resource implementation for developers to use and/or extend as needed.
5
+
6
+
7
+ ## Tree Structure
8
+ Rend-Acl provides a tree structure to which multiple resources can be added. Since resources are stored in such a tree structure, they can be organized from the general (toward the tree root) to the specific (toward the tree leaves). Queries on a specific resource will automatically search the resource's hierarchy for rules assigned to ancestor resources, allowing for simple inheritance of rules.
9
+
10
+
11
+ ## Resource Inheritance
12
+ For example, if a default ***rule*** is to be applied to each ***building*** in a ***city***, one would simply assign the ***rule*** to the ***city***, instead of assigning the same ***rule*** to each ***building***. Some ***building***s may require exceptions to such a ***rule***, however, and this can be achieved in Rend-Acl by assigning such exception ***rule***s to each ***building*** that requires such an exception. A ***resource*** may inherit from only one parent ***resource***, though this parent ***resource*** can have its own parent ***resource***, etc.
13
+
14
+ ### Example
15
+ ```ruby
16
+ @acl = Rend::Acl.new
17
+
18
+ # Define Resources
19
+ city_resource = Rend::Acl::Resource.new("city")
20
+ building_resource = Rend::Acl::Resource.new("building")
21
+
22
+ # Add Resources to ACL
23
+ @acl.add_resource!(city_resource)
24
+ @acl.add_resource!(building_resource, city_resource) # Inheritance from city_resource
25
+
26
+ # Define & Add Roles
27
+ mayor_role = Rend::Acl::Role.new("mayor")
28
+ @acl.add_role!(mayor_role)
29
+
30
+ # Define Rules
31
+ @acl.allow! :role => mayor_role, :resource => city_resource
32
+
33
+ # Querying
34
+ @acl.allowed? :role => mayor_role, :resource => city_resource # => TRUE, via explicitly set rule.
35
+ @acl.allowed? :role => mayor_role, :resource => building_resource # => TRUE, via resource rule inheritance
36
+ ```
37
+ > **Associated Test:** `rend-acl/test/test_documentation_examples.rb#test_wiki_resource_inheritance_example`
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rend-acl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-11 00:00:00.000000000 Z
12
+ date: 2013-06-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -44,21 +44,21 @@ dependencies:
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
46
  - !ruby/object:Gem::Dependency
47
- name: turn
47
+ name: minitest
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  none: false
50
50
  requirements:
51
- - - ! '>='
51
+ - - ~>
52
52
  - !ruby/object:Gem::Version
53
- version: '0'
53
+ version: 5.0.5
54
54
  type: :development
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  none: false
58
58
  requirements:
59
- - - ! '>='
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 5.0.5
62
62
  - !ruby/object:Gem::Dependency
63
63
  name: rend-core
64
64
  requirement: !ruby/object:Gem::Requirement
@@ -75,7 +75,7 @@ dependencies:
75
75
  - - ~>
76
76
  - !ruby/object:Gem::Version
77
77
  version: 0.0.0
78
- description: A port of Zend_Acl with modifications made to bring the api more inline
78
+ description: A port of Zend_Acl with modifications made to bring the API more inline
79
79
  with Ruby conventions.
80
80
  email:
81
81
  - daniel.doezema@gmail.com
@@ -83,7 +83,9 @@ executables: []
83
83
  extensions: []
84
84
  extra_rdoc_files: []
85
85
  files:
86
+ - .coveralls.yml
86
87
  - .gitignore
88
+ - .travis.yml
87
89
  - Changelog.md
88
90
  - Gemfile
89
91
  - LICENSE.txt
@@ -100,7 +102,13 @@ files:
100
102
  - lib/rend/acl/role/registry/exception.rb
101
103
  - lib/rend/acl/version.rb
102
104
  - rend-acl.gemspec
105
+ - test/helper.rb
106
+ - test/support/failing_assertion.rb
107
+ - test/support/mock_assertion.rb
108
+ - test/support/passing_assertion.rb
103
109
  - test/test_acl.rb
110
+ - test/test_documentation_examples.rb
111
+ - wiki/pages/resources.md
104
112
  homepage: https://github.com/veloper/rend-acl
105
113
  licenses:
106
114
  - New-BSD
@@ -116,7 +124,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
116
124
  version: '0'
117
125
  segments:
118
126
  - 0
119
- hash: -2809420582677817181
127
+ hash: 4151355783385604233
120
128
  required_rubygems_version: !ruby/object:Gem::Requirement
121
129
  none: false
122
130
  requirements:
@@ -125,12 +133,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
133
  version: '0'
126
134
  segments:
127
135
  - 0
128
- hash: -2809420582677817181
136
+ hash: 4151355783385604233
129
137
  requirements: []
130
138
  rubyforge_project:
131
139
  rubygems_version: 1.8.25
132
140
  signing_key:
133
141
  specification_version: 3
134
- summary: rend-acl-0.0.4
142
+ summary: rend-acl-0.0.5
135
143
  test_files:
144
+ - test/helper.rb
145
+ - test/support/failing_assertion.rb
146
+ - test/support/mock_assertion.rb
147
+ - test/support/passing_assertion.rb
136
148
  - test/test_acl.rb
149
+ - test/test_documentation_examples.rb