authorize 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +42 -0
  4. data/LICENSE +20 -0
  5. data/README +155 -0
  6. data/Rakefile +25 -0
  7. data/TODO.txt +9 -0
  8. data/authorize.gemspec +25 -0
  9. data/generators/authorize/USAGE +8 -0
  10. data/generators/authorize/authorize_generator.rb +7 -0
  11. data/generators/authorize/templates/migrate/create_authorizations.rb +26 -0
  12. data/install.rb +1 -0
  13. data/lib/authorize.rb +2 -0
  14. data/lib/authorize/action_controller.rb +59 -0
  15. data/lib/authorize/action_view.rb +4 -0
  16. data/lib/authorize/active_record.rb +37 -0
  17. data/lib/authorize/bitmask.rb +84 -0
  18. data/lib/authorize/exceptions.rb +30 -0
  19. data/lib/authorize/graph.rb +4 -0
  20. data/lib/authorize/graph/directed_acyclic_graph.rb +10 -0
  21. data/lib/authorize/graph/directed_acyclic_graph_reverse_traverser.rb +27 -0
  22. data/lib/authorize/graph/directed_acyclic_graph_traverser.rb +30 -0
  23. data/lib/authorize/graph/directed_graph.rb +27 -0
  24. data/lib/authorize/graph/edge.rb +58 -0
  25. data/lib/authorize/graph/factory.rb +39 -0
  26. data/lib/authorize/graph/fixtures.rb +33 -0
  27. data/lib/authorize/graph/graph.rb +55 -0
  28. data/lib/authorize/graph/traverser.rb +89 -0
  29. data/lib/authorize/graph/undirected_graph.rb +14 -0
  30. data/lib/authorize/graph/vertex.rb +53 -0
  31. data/lib/authorize/permission.rb +97 -0
  32. data/lib/authorize/redis.rb +2 -0
  33. data/lib/authorize/redis/array.rb +36 -0
  34. data/lib/authorize/redis/base.rb +165 -0
  35. data/lib/authorize/redis/connection_manager.rb +88 -0
  36. data/lib/authorize/redis/connection_specification.rb +16 -0
  37. data/lib/authorize/redis/factory.rb +64 -0
  38. data/lib/authorize/redis/fixtures.rb +22 -0
  39. data/lib/authorize/redis/hash.rb +34 -0
  40. data/lib/authorize/redis/model_reference.rb +21 -0
  41. data/lib/authorize/redis/model_set.rb +19 -0
  42. data/lib/authorize/redis/set.rb +42 -0
  43. data/lib/authorize/redis/string.rb +17 -0
  44. data/lib/authorize/resource.rb +4 -0
  45. data/lib/authorize/resource_pool.rb +87 -0
  46. data/lib/authorize/role.rb +115 -0
  47. data/lib/authorize/test_helper.rb +42 -0
  48. data/lib/authorize/trustee.rb +4 -0
  49. data/lib/authorize/version.rb +3 -0
  50. data/rails/init.rb +5 -0
  51. data/tasks/authorize_tasks.rake +4 -0
  52. data/test/Rakefile +7 -0
  53. data/test/app/controllers/application_controller.rb +5 -0
  54. data/test/app/controllers/thingy_controller.rb +11 -0
  55. data/test/app/controllers/widgets_controller.rb +2 -0
  56. data/test/app/models/public.rb +14 -0
  57. data/test/app/models/user.rb +8 -0
  58. data/test/app/models/widget.rb +7 -0
  59. data/test/config/boot.rb +109 -0
  60. data/test/config/database.yml +25 -0
  61. data/test/config/environment.rb +28 -0
  62. data/test/config/environments/development.rb +4 -0
  63. data/test/config/environments/test.rb +0 -0
  64. data/test/config/initializers/mask.rb +1 -0
  65. data/test/config/initializers/redis.rb +8 -0
  66. data/test/config/routes.rb +5 -0
  67. data/test/db/.gitignore +1 -0
  68. data/test/db/schema.rb +26 -0
  69. data/test/log/.gitignore +2 -0
  70. data/test/public/javascripts/application.js +2 -0
  71. data/test/public/javascripts/controls.js +963 -0
  72. data/test/public/javascripts/dragdrop.js +972 -0
  73. data/test/public/javascripts/effects.js +1120 -0
  74. data/test/public/javascripts/prototype.js +4225 -0
  75. data/test/script/about +3 -0
  76. data/test/script/console +3 -0
  77. data/test/script/dbconsole +3 -0
  78. data/test/script/destroy +3 -0
  79. data/test/script/generate +3 -0
  80. data/test/script/performance/benchmarker +3 -0
  81. data/test/script/performance/profiler +3 -0
  82. data/test/script/performance/request +3 -0
  83. data/test/script/plugin +3 -0
  84. data/test/script/process/inspector +3 -0
  85. data/test/script/process/reaper +3 -0
  86. data/test/script/process/spawner +3 -0
  87. data/test/script/runner +3 -0
  88. data/test/script/server +3 -0
  89. data/test/test/fixtures/authorize/role_graph.yml +11 -0
  90. data/test/test/fixtures/permissions.yml +27 -0
  91. data/test/test/fixtures/redis/redis.yml +8 -0
  92. data/test/test/fixtures/redis/role_graph.yml +29 -0
  93. data/test/test/fixtures/roles.yml +28 -0
  94. data/test/test/fixtures/users.yml +12 -0
  95. data/test/test/fixtures/widgets.yml +12 -0
  96. data/test/test/functional/controller_class_test.rb +36 -0
  97. data/test/test/functional/controller_test.rb +46 -0
  98. data/test/test/test_helper.rb +35 -0
  99. data/test/test/unit/bitmask_test.rb +112 -0
  100. data/test/test/unit/fixture_test.rb +59 -0
  101. data/test/test/unit/graph_directed_acyclic_graph_reverse_traverser_test.rb +43 -0
  102. data/test/test/unit/graph_directed_acyclic_graph_traverser_test.rb +57 -0
  103. data/test/test/unit/graph_directed_graph_test.rb +66 -0
  104. data/test/test/unit/graph_edge_test.rb +53 -0
  105. data/test/test/unit/graph_graph_test.rb +50 -0
  106. data/test/test/unit/graph_traverser_test.rb +43 -0
  107. data/test/test/unit/graph_vertex_test.rb +57 -0
  108. data/test/test/unit/permission_test.rb +123 -0
  109. data/test/test/unit/redis_array_test.rb +60 -0
  110. data/test/test/unit/redis_connection_manager_test.rb +54 -0
  111. data/test/test/unit/redis_factory_test.rb +85 -0
  112. data/test/test/unit/redis_fixture_test.rb +18 -0
  113. data/test/test/unit/redis_hash_test.rb +43 -0
  114. data/test/test/unit/redis_model_reference_test.rb +39 -0
  115. data/test/test/unit/redis_set_test.rb +68 -0
  116. data/test/test/unit/redis_string_test.rb +25 -0
  117. data/test/test/unit/redis_test.rb +121 -0
  118. data/test/test/unit/resource_pool_test.rb +93 -0
  119. data/test/test/unit/resource_test.rb +33 -0
  120. data/test/test/unit/role_test.rb +143 -0
  121. data/test/test/unit/trustee_test.rb +35 -0
  122. data/test/tmp/.gitignore +2 -0
  123. data/uninstall.rb +1 -0
  124. metadata +319 -0
data/test/script/about ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/about'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/console'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/dbconsole'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/destroy'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/generate'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../../config/boot'
3
+ require 'commands/performance/benchmarker'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../../config/boot'
3
+ require 'commands/performance/profiler'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../../config/boot'
3
+ require 'commands/performance/request'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/plugin'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../../config/boot'
3
+ require 'commands/process/inspector'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../../config/boot'
3
+ require 'commands/process/reaper'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../../config/boot'
3
+ require 'commands/process/spawner'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/runner'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/server'
@@ -0,0 +1,11 @@
1
+ --- !hapgoods.com,2010/graph
2
+ # 417269330
3
+ - administrator
4
+ # 1001664029
5
+ - public
6
+ # 428714999
7
+ - registered_users: [public]
8
+ # 782668386
9
+ - user_chris: [registered_users]
10
+ # 12918588
11
+ - user_pascale: [registered_users, administrator]
@@ -0,0 +1,27 @@
1
+ a_read_foo:
2
+ mask: <%= Authorize::Permission::Mask[:list, :read].to_i %>
3
+ role: a
4
+ _resource: foo (Widget)
5
+ a_list_bar:
6
+ mask: <%= Authorize::Permission::Mask[:list].to_i %>
7
+ role: a
8
+ _resource: bar (Widget)
9
+ b_overlord:
10
+ mask: <%= Authorize::Permission::Mask[:all].to_i %>
11
+ role: administrator
12
+ c_all_widgets:
13
+ mask: <%= Authorize::Permission::Mask[:all].to_i %>
14
+ role: c
15
+ resource_type: Widget
16
+ d_update_bar:
17
+ mask: <%= Authorize::Permission::Mask[:list, :read, :update].to_i %>
18
+ role: d
19
+ _resource: bar (Widget)
20
+ e_delete_bar:
21
+ mask: <%= Authorize::Permission::Mask[:list, :delete].to_i %>
22
+ role: e
23
+ _resource: bar (Widget)
24
+ user_chris_all_chris:
25
+ mask: <%= Authorize::Permission::Mask[:all].to_i %>
26
+ role: user_chris
27
+ _resource: chris (User)
@@ -0,0 +1,8 @@
1
+ - string: x
2
+ - list: [one, two, three]
3
+ - set: !ruby/object:Set
4
+ hash: {1: true, 2: true}
5
+ - hash: {:a: 1, :b: 2}
6
+ - value: &value <%= Marshal.dump(Date.new(1965, 11, 16))%>
7
+ - value_set: !ruby/object:Set
8
+ hash: {*value: true}
@@ -0,0 +1,29 @@
1
+ # Vertices (just markers)
2
+ - <%= "Authorize::Role::vertices::#{Fixtures.identify(:user_chris)}::_" %>: ~
3
+ - <%= "Authorize::Role::vertices::#{Fixtures.identify(:public)}::_" %>: ~
4
+ - <%= "Authorize::Role::vertices::#{Fixtures.identify(:registered_users)}::_" %>: ~
5
+ # Edge counter
6
+ - "Authorize::Role::graph::_edges": "10"
7
+ # Edges
8
+ - Authorize::Role::graph::_edges::1::l_id: <%= "Authorize::Role::vertices::#{Fixtures.identify(:user_chris)}" %>
9
+ - Authorize::Role::graph::_edges::1::r_id: <%= "Authorize::Role::vertices::#{Fixtures.identify(:registered_users)}" %>
10
+ - Authorize::Role::graph::_edges::2::l_id: <%= "Authorize::Role::vertices::#{Fixtures.identify(:registered_users)}" %>
11
+ - Authorize::Role::graph::_edges::2::r_id: <%= "Authorize::Role::vertices::#{Fixtures.identify(:public)}" %>
12
+ # Set of vertices belonging to the role graph
13
+ - "Authorize::Role::graph": !ruby/object:Set
14
+ hash:
15
+ <%= "Authorize::Role::vertices::#{Fixtures.identify(:public)}" %>: true
16
+ <%= "Authorize::Role::vertices::#{Fixtures.identify(:registered_users)}" %>: true
17
+ <%= "Authorize::Role::vertices::#{Fixtures.identify(:user_chris)}" %>: true
18
+ # Set of edges belonging to the role graph
19
+ - "Authorize::Role::graph::edge_ids": !ruby/object:Set
20
+ hash:
21
+ Authorize::Role::graph::edges::1: true
22
+ Authorize::Role::graph::edges::2: true
23
+ # Set of edges per vertex
24
+ - <%= "Authorize::Role::vertices::#{Fixtures.identify(:user_chris)}::edge_ids" %>: !ruby/object:Set
25
+ hash:
26
+ Authorize::Role::graph::_edges::1: true
27
+ - <%= "Authorize::Role::vertices::#{Fixtures.identify(:registered_users)}::edge_ids" %>: !ruby/object:Set
28
+ hash:
29
+ Authorize::Role::graph::_edges::2: true
@@ -0,0 +1,28 @@
1
+ a:
2
+ name: a
3
+ resource: foo (Widget)
4
+ administrator:
5
+ name: administrator
6
+ relation: ADM
7
+ c:
8
+ name: "%s administrator"
9
+ resource_type: Widget
10
+ d:
11
+ name: "owner of %s"
12
+ resource: bar (Widget)
13
+ e:
14
+ name: "housekeeper of %s"
15
+ relation: HSK
16
+ resource: bar (Widget)
17
+ user_chris:
18
+ name: ~
19
+ resource: chris (User)
20
+ user_pascale:
21
+ name: ~
22
+ resource: pascale (User)
23
+ registered_users:
24
+ name: Registered Users
25
+ relation: RUS
26
+ public:
27
+ name: Public
28
+ relation: PUB
@@ -0,0 +1,12 @@
1
+ chris:
2
+ login: cch1
3
+ created_at: <%= 2.days.ago.to_s :db %>
4
+ updated_at: <%= 1.days.ago.to_s :db %>
5
+ pascale:
6
+ login: pah1
7
+ created_at: <%= 2.days.ago.to_s :db %>
8
+ updated_at: <%= 1.days.ago.to_s :db %>
9
+ alex:
10
+ login: ach1
11
+ created_at: <%= 2.days.ago.to_s :db %>
12
+ updated_at: <%= 1.days.ago.to_s :db %>
@@ -0,0 +1,12 @@
1
+ foo:
2
+ name: super
3
+ created_at: <%= 2.days.ago.to_s :db %>
4
+ updated_at: <%= 1.days.ago.to_s :db %>
5
+ bar:
6
+ name: deluxe
7
+ created_at: <%= 2.days.ago.to_s :db %>
8
+ updated_at: <%= 1.days.ago.to_s :db %>
9
+ baz:
10
+ name: baz
11
+ created_at: <%= 2.days.ago.to_s :db %>
12
+ updated_at: <%= 1.days.ago.to_s :db %>
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+
3
+ class ControllerClassTest < ActionController::TestCase
4
+ fixtures :all
5
+
6
+ tests ThingyController
7
+
8
+ test 'raise exception when not permitted' do
9
+ @controller.expects(:roles).returns([])
10
+ assert_raises Authorize::AuthorizationError do
11
+ get :index
12
+ end
13
+ end
14
+
15
+ test 'rescue response' do
16
+ @controller.expects(:roles).returns([])
17
+ @request.remote_addr = "192.168.1.1"
18
+ get :index
19
+ assert_response :forbidden
20
+ end
21
+
22
+ test 'skip filter' do
23
+ assert_nothing_raised do
24
+ get :show
25
+ assert_response :success
26
+ end
27
+ end
28
+
29
+ test 'should perform action because of authorization' do
30
+ @controller.expects(:roles).returns([roles(:administrator)])
31
+ assert_nothing_raised do
32
+ get :index
33
+ assert_response :success
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+ require 'authorize/graph/fixtures'
3
+
4
+ class ControllerTest < ActionController::TestCase
5
+ fixtures :all
6
+
7
+ tests WidgetsController
8
+
9
+ def setup
10
+ ::Authorize::Graph::Fixtures.create_fixtures
11
+ end
12
+
13
+ test 'predicate not stuck on false when permitted' do
14
+ assert @controller.permit?({:list => widgets(:foo)}, {:roles => [roles(:administrator)]})
15
+ end
16
+
17
+ test 'predicate not stuck on true when not permitted' do
18
+ assert !@controller.permit?({:all => Widget}, {:roles => []})
19
+ end
20
+
21
+ test 'query controller for default roles' do
22
+ @controller.expects(:roles).returns([roles(:administrator)])
23
+ @controller.permit?(:update => widgets(:foo))
24
+ end
25
+
26
+ test 'yields to block when permitted' do
27
+ sentinel = mock('sentinel', {:trip! => true})
28
+ @controller.permit({:list => widgets(:foo)}, {:roles => [roles(:administrator)]}) {sentinel.trip!}
29
+ end
30
+
31
+ test 'calls handler and does not yield to block when not permitted' do
32
+ sentinel = mock('sentinel')
33
+ @controller.expects(:handle_authorization_failure).returns(true)
34
+ @controller.permit({:all => Widget}, {:roles => []}) {sentinel.trip!}
35
+ end
36
+
37
+ test 'handler raises authorization exception' do
38
+ assert_raises Authorize::AuthorizationError do
39
+ @controller.permit({:all => Widget}, {:roles => []}) {sentinel.trip!}
40
+ end
41
+ end
42
+
43
+ test 'mutiple authorization hash pairs' do
44
+ assert @controller.permit?({:list => widgets(:foo), :update => users(:chris)}, {:roles => [roles(:user_chris)]})
45
+ end
46
+ end
@@ -0,0 +1,35 @@
1
+ ENV['RAILS_ENV'] = 'test'
2
+ require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
3
+ require 'test_help'
4
+
5
+ # Set Test::Unit options for optimal performance/fidelity.
6
+ class ActiveSupport::TestCase
7
+ self.use_transactional_fixtures = true
8
+ self.use_instantiated_fixtures = false
9
+
10
+ set_fixture_class :permissions => Authorize::Permission, :roles => Authorize::Role
11
+
12
+ def self.uses_mocha(description)
13
+ require 'mocha'
14
+ yield
15
+ rescue LoadError
16
+ $stderr.puts "Skipping #{description} tests. `gem install mocha` and try again."
17
+ end
18
+ setup {Authorize::Redis::Base.db.flushdb}
19
+ end
20
+
21
+ # Unfortunately, setting expectations on any instance for #initialize causes #mocha_teardown
22
+ # to squirt out errors that cannot easily be suppressed in a less intrusive manner.
23
+ module Mocha
24
+ module API
25
+ def mocha_teardown_with_warning_suppression
26
+ old_verbose, $VERBOSE = $VERBOSE, nil
27
+ mocha_teardown_without_warning_suppression
28
+ $VERBOSE = old_verbose
29
+ end
30
+ alias_method :mocha_teardown_without_warning_suppression, :mocha_teardown
31
+ alias_method :mocha_teardown, :mocha_teardown_with_warning_suppression
32
+ end
33
+ end
34
+
35
+ raise "Test Database doesn't look safe (#{Authorize::Redis::Base.db.inspect} has #{Authorize::Redis::Base.db.dbsize} keys)" unless Authorize::Redis::Base.db.dbsize < 100
@@ -0,0 +1,112 @@
1
+ require 'test_helper'
2
+
3
+ class BitmaskTest < ActiveSupport::TestCase
4
+ def setup
5
+ @bitmask = Class.new(Authorize::Bitmask)
6
+ @bitmask.name_values = {:none => 0, :first => 1, :second => 2, :third => 4, :fourth => 8, :first_nibble => 15, :fifth => 16, :sixth => 32, :seventh => 64, :eighth => 128, :all => 255}
7
+ end
8
+
9
+ test 'create degenerate' do
10
+ b = @bitmask[]
11
+ assert b.empty?
12
+ end
13
+
14
+ test 'create with integer' do
15
+ b = @bitmask.new(4)
16
+ assert_equal Set[:none, :third], b
17
+ end
18
+
19
+ test 'create with invalid integer' do
20
+ assert_raises RangeError do
21
+ b = @bitmask.new(256)
22
+ end
23
+ end
24
+
25
+ test 'create with enum' do
26
+ b = @bitmask[:first, :third]
27
+ assert_equal Set[:first, :third], b
28
+ end
29
+
30
+ test 'create with invalid enum' do
31
+ assert_raises ArgumentError do
32
+ @bitmask[:first, :third, :ninth]
33
+ end
34
+ end
35
+
36
+ test 'add bit' do
37
+ b = @bitmask[]
38
+ b << :first_nibble
39
+ assert_equal 15, b.to_i
40
+ end
41
+
42
+ test 'add invalid bit' do
43
+ b = @bitmask[]
44
+ assert_raises ArgumentError do
45
+ b.add :first_word
46
+ end
47
+ end
48
+
49
+ test 'comparable' do
50
+ b0 = @bitmask[]
51
+ b1 = @bitmask[:first, :second, :third, :fourth]
52
+ b2 = @bitmask[:first_nibble]
53
+ assert_operator b0, :<, b1
54
+ assert_operator b2, :==, b1
55
+ end
56
+
57
+ test 'comparable with integers' do
58
+ b0 = @bitmask[:all]
59
+ assert_operator b0, :==, 255
60
+ assert_operator 255, :==, b0
61
+ end
62
+
63
+ test 'dynamic bit getters' do
64
+ b = @bitmask[:first, :second]
65
+ assert b._first
66
+ assert !b._third
67
+ end
68
+
69
+ test 'dynamic bit setters' do
70
+ b = @bitmask[:first, :second]
71
+ b._first = false
72
+ assert !b.include?(:first)
73
+ b._third = false
74
+ assert !b.include?(:third)
75
+ end
76
+
77
+ test 'dynamic bit predicates' do
78
+ b = @bitmask[:first, :second]
79
+ assert b._first?
80
+ assert !b._third?
81
+ end
82
+
83
+ test 'complete' do
84
+ b = @bitmask[]
85
+ assert_equal Set[:none], b.complete
86
+ b = @bitmask[:first_nibble]
87
+ assert_equal Set[:none, :first, :second, :third, :fourth, :first_nibble], b.complete
88
+ b = @bitmask[:first, :second, :third, :fourth]
89
+ assert_equal Set[:none, :first, :second, :third, :fourth, :first_nibble], b.complete
90
+ end
91
+
92
+ test 'fundamental' do
93
+ b = @bitmask[:first_nibble]
94
+ assert_equal Set[:first, :second, :third, :fourth], b.fundamental
95
+ end
96
+
97
+ test 'minimal' do
98
+ b = @bitmask[:none, :first, :second, :third, :fourth]
99
+ assert_equal Set[:first_nibble], b.minimal
100
+ end
101
+
102
+ test 'stringify' do
103
+ b = @bitmask.new(7)
104
+ assert_match /\w+(\|\w+){3}/, b.to_s
105
+ assert_match /none.*third/, b.to_s # canonical order
106
+ end
107
+
108
+ test 'stringify empty set' do
109
+ b = @bitmask[]
110
+ assert_equal "", b.to_s
111
+ end
112
+ end