lockdown 0.7.1 → 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.
Files changed (46) hide show
  1. data/.DS_Store +0 -0
  2. data/History.txt +3 -0
  3. data/README.txt +1 -1
  4. data/Rakefile +16 -1
  5. data/lib/lockdown/context.rb +41 -0
  6. data/lib/lockdown/database.rb +11 -14
  7. data/lib/lockdown/frameworks/rails/controller.rb +57 -4
  8. data/lib/lockdown/frameworks/rails/view.rb +1 -1
  9. data/lib/lockdown/frameworks/rails.rb +21 -10
  10. data/lib/lockdown/helper.rb +1 -1
  11. data/lib/lockdown/permission.rb +204 -0
  12. data/lib/lockdown/rules.rb +287 -0
  13. data/lib/lockdown/session.rb +8 -6
  14. data/lib/lockdown/system.rb +35 -88
  15. data/lib/lockdown.rb +52 -49
  16. data/rails_generators/.DS_Store +0 -0
  17. data/rails_generators/lockdown/.DS_Store +0 -0
  18. data/rails_generators/lockdown/lockdown_generator.rb +5 -5
  19. data/rails_generators/lockdown/templates/.DS_Store +0 -0
  20. data/rails_generators/lockdown/templates/lib/.DS_Store +0 -0
  21. data/rails_generators/lockdown/templates/lib/lockdown/init.rb +27 -19
  22. data/rails_generators/lockdown/templates/lib/lockdown/session.rb +1 -3
  23. data/spec/lockdown/database_spec.rb +158 -0
  24. data/spec/lockdown/frameworks/rails/controller_spec.rb +220 -0
  25. data/spec/lockdown/frameworks/rails/view_spec.rb +87 -0
  26. data/spec/lockdown/frameworks/rails_spec.rb +170 -0
  27. data/spec/lockdown/permission_spec.rb +156 -0
  28. data/spec/lockdown/rules_spec.rb +109 -0
  29. data/spec/lockdown/session_spec.rb +88 -0
  30. data/spec/lockdown/system_spec.rb +59 -0
  31. data/spec/lockdown_spec.rb +19 -0
  32. data/spec/rcov.opts +5 -0
  33. data/spec/spec.opts +3 -0
  34. data/spec/spec_helper.rb +1 -0
  35. data/tasks/post_load.rake +2 -7
  36. data/tasks/setup.rb +24 -3
  37. metadata +23 -12
  38. data/.gitignore +0 -5
  39. data/Manifest.txt +0 -51
  40. data/lib/lockdown/controller.rb +0 -64
  41. data/lib/lockdown/frameworks/merb/controller.rb +0 -63
  42. data/lib/lockdown/frameworks/merb/view.rb +0 -32
  43. data/lib/lockdown/frameworks/merb.rb +0 -84
  44. data/lib/lockdown/orms/data_mapper.rb +0 -70
  45. data/lib/lockdown/rights.rb +0 -208
  46. data/tasks/manifest.rake +0 -48
@@ -22,6 +22,9 @@ Lockdown::System.configure do
22
22
  # Set redirect to path on successful login:
23
23
  # options[:successful_login_path] = "/"
24
24
  #
25
+ # Set separator on links call
26
+ # options[:links_separator] = "|"
27
+ #
25
28
  # If deploying to a subdirectory, set that here. Defaults to nil
26
29
  # options[:subdirectory] = "blog"
27
30
  # *Notice: Do not add leading or trailing slashes,
@@ -31,17 +34,15 @@ Lockdown::System.configure do
31
34
  # Define permissions
32
35
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
33
36
  #
34
- # set_permission(:product_management, all_methods(:products))
37
+ # set_permission(:product_management).
38
+ # with_controller(:products)
35
39
  #
36
40
  # :product_management is the name of the permission which is later
37
41
  # referenced by the set_user_group method
38
42
  #
39
- # :all_methods(:products) will return an array of all controller actions
40
- # for the products controller
41
- #
42
- # If you need to reference a namespaced controller use two underscores:
43
- # :admin__products would tell lockdown to look for:
44
- # app/controllers/admin/products_controller.rb
43
+ # .with_controller(:products) defaults to all action_methods available on that
44
+ # controller. You can change this behaviour by chaining on except_methods or
45
+ # only_methods. (see examples below)
45
46
  #
46
47
  # if products is your standard RESTful resource you'll get:
47
48
  # ["products/index , "products/show",
@@ -49,23 +50,30 @@ Lockdown::System.configure do
49
50
  # "products/create", "products/update",
50
51
  # "products/destroy"]
51
52
  #
52
- # You can pass multiple parameters to concat permissions such as:
53
+ # You can chain method calls to restrict the methods for one controller
54
+ # or you can add multiple controllers to one permission.
53
55
  #
54
- # set_permission(:security_management,all_methods(:users),
55
- # all_methods(:user_groups),
56
- # all_methods(:permissions) )
56
+ # set_permission(:security_management).
57
+ # with_controller(:users).
58
+ # and_controller(:user_groups).
59
+ # and_controller(:permissions)
57
60
  #
58
- # In addition to all_methods(:controller) there are:
61
+ # In addition to with_controller(:controller) there are:
59
62
  #
60
- # only_methods(:controller, :only_method_1, :only_method_2)
63
+ # set_permission(:some_nice_permission_name).
64
+ # with_controller(:some_controller_name).
65
+ # only_methods(:only_method_1, :only_method_2)
61
66
  #
62
- # all_except_methods(:controller, :except_method_1, :except_method_2)
67
+ # set_permission(:some_nice_permission_name).
68
+ # with_controller(:some_controller_name).
69
+ # except_methods(:except_method_1, :except_method_2)
70
+ #
71
+ # set_permission(:some_nice_permission_name).
72
+ # with_controller(:some_controller_name).
73
+ # except_methods(:except_method_1, :except_method_2).
74
+ # and_controller(:another_controller_name).
75
+ # and_controller(:yet_another_controller_name)
63
76
  #
64
- # Some other sample permissions:
65
- #
66
- # set_permission(:sessions, all_methods(:sessions))
67
- # set_permission(:my_account, only_methods(:users, :edit, :update, :show))
68
- #
69
77
  # Define your permissions here:
70
78
 
71
79
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -56,10 +56,8 @@ module Lockdown
56
56
  end # Lockdown module
57
57
 
58
58
  ActionController::Base.class_eval do
59
- include Lockdown::Session
60
- end
59
+ include Lockdown::Session
61
60
 
62
- ActionController::Base.class_eval do
63
61
  helper_method :logged_in?,
64
62
  :current_user,
65
63
  :current_user_name,
@@ -0,0 +1,158 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. spec_helper])
2
+
3
+ describe Lockdown::Database do
4
+ before do
5
+ Lockdown::System.stub!(:get_permissions).and_return([:permission])
6
+ Lockdown::System.stub!(:get_user_groups).and_return([:user_group])
7
+ end
8
+
9
+ describe "#sync_with_db" do
10
+ it "should call create_new_permissions, delete_extinct_permissions and maintain_user_groups" do
11
+ Lockdown::Database.should_receive :create_new_permissions
12
+ Lockdown::Database.should_receive :delete_extinct_permissions
13
+ Lockdown::Database.should_receive :maintain_user_groups
14
+
15
+ Lockdown::Database.sync_with_db
16
+ end
17
+ end
18
+
19
+ describe "#create_new_permissions" do
20
+ it "should create permission from @permissions" do
21
+ Lockdown::System.stub!(:permission_assigned_automatically?).and_return(false)
22
+
23
+ Permission = mock('Permission') unless defined?(Permission)
24
+ Permission.stub!(:find).and_return(false)
25
+ Permission.should_receive(:create).with(:name => 'Permission')
26
+
27
+ Lockdown::Database.create_new_permissions
28
+ end
29
+ end
30
+
31
+ describe "#delete_extinct_permissions" do
32
+ it "should create permission from @permissions" do
33
+ permission = mock('permission')
34
+ permission.stub!(:id).and_return("3344")
35
+ permission.stub!(:name).and_return("sweet permission")
36
+ permissions = [permission]
37
+
38
+ Permission = mock('Permission') unless defined?(Permission)
39
+ Permission.stub!(:find).with(:all).and_return(permissions)
40
+
41
+ Lockdown.should_receive(:database_execute).
42
+ with("delete from permissions_user_groups where permission_id = 3344")
43
+ permission.should_receive(:destroy)
44
+
45
+ Lockdown::Database.delete_extinct_permissions
46
+ end
47
+ end
48
+
49
+ describe "#maintain_user_groups" do
50
+ before do
51
+ UserGroup = mock('UserGroup') unless defined?(UserGroup)
52
+ end
53
+
54
+ it "should create user group for non-existent user group" do
55
+ UserGroup.should_receive(:find).
56
+ with(:first, :conditions => ["name = ?", "User Group"]).
57
+ and_return(false)
58
+
59
+ Lockdown::Database.should_receive(:create_user_group).
60
+ with("User Group",:user_group)
61
+
62
+ Lockdown::Database.maintain_user_groups
63
+ end
64
+
65
+ it "should sync user group permissions for existing user group" do
66
+ ug = mock('user group')
67
+
68
+ UserGroup.should_receive(:find).
69
+ with(:first, :conditions => ["name = ?", "User Group"]).
70
+ and_return(ug)
71
+
72
+ Lockdown::Database.should_receive(:remove_invalid_permissions).
73
+ with(ug,:user_group)
74
+
75
+ Lockdown::Database.should_receive(:add_valid_permissions).
76
+ with(ug,:user_group)
77
+
78
+ Lockdown::Database.maintain_user_groups
79
+ end
80
+ end
81
+
82
+ describe "#create_user_group" do
83
+ it "should create new user group" do
84
+ ug = mock('user group')
85
+ ug.stub!(:id).and_return(123)
86
+
87
+ UserGroup = mock('UserGroup') unless defined?(UserGroup)
88
+
89
+ UserGroup.should_receive(:create).
90
+ with(:name => "some group").
91
+ and_return(ug)
92
+
93
+ Lockdown::System.stub!(:permissions_for_user_group).
94
+ and_return([:perm])
95
+
96
+ perm = mock('permission')
97
+ perm.stub!(:id).and_return(3344)
98
+
99
+ Permission = mock('Permission') unless defined?(Permission)
100
+
101
+ Permission.should_receive(:find).
102
+ with(:first, :conditions => ["name = ?",'Perm']).
103
+ and_return(perm)
104
+
105
+ Lockdown.should_receive(:database_execute).
106
+ with("insert into permissions_user_groups(permission_id, user_group_id) values(3344, 123)")
107
+
108
+ Lockdown::Database.create_user_group("some group", :some_group)
109
+ end
110
+ end
111
+
112
+ describe "#remove_invalid_permissions" do
113
+ it "should remove permissions that no longer exist" do
114
+ permissions = [:good_perm, :bad_perm]
115
+
116
+ user_group = mock("user group", :name => "user group")
117
+
118
+ #returns what's in the database
119
+ user_group.stub!(:permissions).and_return(permissions)
120
+
121
+ #return what's defined in init.rb
122
+ Lockdown::System.stub!(:permissions_for_user_group).
123
+ and_return([:good_perm])
124
+
125
+ #delete what's not in init.rb
126
+ permissions.should_receive(:delete).with(:bad_perm)
127
+
128
+ Lockdown::Database.remove_invalid_permissions(user_group, :user_group)
129
+ end
130
+ end
131
+
132
+ describe "#add_invalid_permissions" do
133
+ it "should add permissions that are defined in init.rb" do
134
+ #return what's defined in init.rb
135
+ Lockdown::System.stub!(:permissions_for_user_group).
136
+ and_return([:defined_perm, :undefined_perm])
137
+
138
+ permissions = [:defined_perm]
139
+
140
+ user_group = mock("user group", :name => "user group")
141
+
142
+ #returns what's in the database
143
+ user_group.stub!(:permissions).and_return(permissions)
144
+
145
+ Permission = mock('Permission') unless defined?(Permission)
146
+
147
+ #get the permission object for the undefined_perm
148
+ Permission.should_receive(:find).
149
+ with(:first, :conditions => ["name = ?",'Undefined Perm']).
150
+ and_return(:undefined_perm)
151
+
152
+ #add the perm to the user group
153
+ permissions.should_receive(:<<).with(:undefined_perm)
154
+
155
+ Lockdown::Database.add_valid_permissions(user_group, :user_group)
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,220 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. .. .. spec_helper])
2
+
3
+ class TestAController
4
+ extend Lockdown::Frameworks::Rails::Controller
5
+ include Lockdown::Frameworks::Rails::Controller::Lock::InstanceMethods
6
+ end
7
+
8
+ describe Lockdown::Frameworks::Rails::Controller do
9
+ before do
10
+ @controller = TestAController
11
+
12
+ @actions = %w(posts/index posts/show posts/new posts/edit posts/create posts/update posts/destroy)
13
+
14
+ @lockdown = mock("lockdown")
15
+ end
16
+
17
+ describe "#available_actions" do
18
+ it "should return action_methods" do
19
+ post_controller = mock("PostController")
20
+ post_controller.stub!(:action_methods).and_return(@actions)
21
+
22
+ @controller.available_actions(post_controller).
23
+ should == @actions
24
+ end
25
+
26
+ it "should eql public_instance_methods - hidden_actions unless action_methods" do
27
+ post_controller = mock("PostController")
28
+ post_controller.stub!(:public_instance_methods).and_return(["m1", "m2", "h1"])
29
+ post_controller.stub!(:hidden_actions).and_return(["h1"])
30
+ @controller.available_actions(post_controller).
31
+ should == ["m1", "m2"]
32
+ end
33
+ end
34
+
35
+ describe "#controller_name" do
36
+ it "should return action_methods" do
37
+ post_controller = mock("PostController")
38
+ post_controller.stub!(:controller_name).and_return("PostController")
39
+
40
+ @controller.controller_name(post_controller).should == "PostController"
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ describe Lockdown::Frameworks::Rails::Controller::Lock do
47
+ before do
48
+ @controller = TestAController.new
49
+
50
+ @actions = %w(posts/index posts/show posts/new posts/edit posts/create posts/update posts/destroy)
51
+
52
+ @session = {:access_rights => @actions}
53
+
54
+ @controller.stub!(:session).and_return(@session)
55
+ end
56
+
57
+ describe "#configure_lockdown" do
58
+ it "should call check_session_expiry and store_location" do
59
+ @controller.should_receive(:check_session_expiry)
60
+ @controller.should_receive(:store_location)
61
+
62
+ @controller.configure_lockdown
63
+ end
64
+ end
65
+
66
+ describe "#set_current_user" do
67
+ it "should set the profile_id in Thread.current" do
68
+ @controller.stub!(:logged_in?).and_return(true)
69
+ @controller.stub!(:current_profile_id).and_return(1234)
70
+
71
+ @controller.set_current_user
72
+
73
+ Thread.current[:profile_id].should == 1234
74
+ end
75
+ end
76
+
77
+ describe "#check_request_authorization" do
78
+ it "should raise SecurityError if not authorized" do
79
+ @controller.stub!(:authorized?).and_return(false)
80
+ @controller.stub!(:params).and_return({:p => 1})
81
+
82
+ lambda{@controller.check_request_authorization}.
83
+ should raise_error(SecurityError)
84
+
85
+ end
86
+ end
87
+
88
+ describe "#path_allowed" do
89
+ it "should return false for an invalid path" do
90
+ @controller.path_allowed?("/no/good").should be_false
91
+ end
92
+ end
93
+
94
+ describe "#check_session_expiry" do
95
+ it "should set expiry if null" do
96
+ Lockdown::System.stub!(:fetch).with(:session_timeout).and_return(10)
97
+ @session[:expiry_time].should be_nil
98
+ @controller.check_session_expiry
99
+ @session[:expiry_time].should_not be_nil
100
+ end
101
+ end
102
+
103
+ describe "#store_location" do
104
+ it "should set prevpage and thispage" do
105
+ request = mock("request")
106
+ request.stub!(:method).and_return(:get)
107
+ @controller.stub!(:request).and_return(request)
108
+
109
+ @controller.stub!(:sent_from_uri).and_return("/blop")
110
+ @controller.store_location
111
+
112
+ @session[:prevpage].should == ''
113
+ @session[:thispage].should == '/blop'
114
+ end
115
+ end
116
+
117
+ describe "#sent_from_uri" do
118
+ it "should return request.request_uri" do
119
+ request = mock("request")
120
+ request.stub!(:request_uri).and_return("/blip")
121
+
122
+ @controller.stub!(:request).and_return(request)
123
+
124
+ @controller.sent_from_uri.should == "/blip"
125
+ end
126
+ end
127
+
128
+ describe "#authorized?" do
129
+ before do
130
+ @sample_url = "http://stonean.com/posts/index"
131
+ @a_path = "/a_path"
132
+
133
+ request = mock("request")
134
+ request.stub!(:method).and_return(:get)
135
+ @controller.stub!(:request).and_return(request)
136
+
137
+ stonean_parts = ["http", nil, "stonean.com", nil, nil, "posts/index", nil, nil, nil]
138
+
139
+ a_path_parts = [nil, nil, nil, nil, nil, "/a_path", nil, nil, nil]
140
+
141
+ URI = mock('uri class') unless defined?(URI)
142
+ URI.stub!(:split).with(@sample_url).and_return(stonean_parts)
143
+ URI.stub!(:split).with(@a_path).and_return(a_path_parts)
144
+ end
145
+
146
+ it "should return false if url is nil" do
147
+ @controller.authorized?(nil).should be_false
148
+ end
149
+
150
+ it "should return true if current_user_is_admin" do
151
+ @controller.stub!(:current_user_is_admin?).and_return(true)
152
+ @controller.authorized?(@a_path).should be_true
153
+ end
154
+
155
+ it "should return false if path not in access_rights" do
156
+ @controller.authorized?(@a_path).should be_false
157
+ end
158
+
159
+ it "should return true if path is in access_rights" do
160
+ @controller.authorized?(@sample_url).should be_true
161
+ end
162
+
163
+ end
164
+
165
+ describe "#access_denied" do
166
+ end
167
+
168
+ describe "#path_from_hash" do
169
+ it "should return controller/action string" do
170
+ hash = {:controller => "users", :action => "show", :id => "1"}
171
+ @controller.path_from_hash(hash).should == "users/show"
172
+ end
173
+ end
174
+
175
+ describe "#remote_url?" do
176
+ it "should return false if domain is nil" do
177
+ @controller.remote_url?.should be_false
178
+ end
179
+
180
+ it "should return false if domain matches request domain" do
181
+ request = mock("request")
182
+ request.stub!(:host).and_return("stonean.com")
183
+ @controller.stub!(:request).and_return(request)
184
+ @controller.remote_url?("stonean.com").should be_false
185
+ end
186
+
187
+ it "should return true if subdomain differs" do
188
+ request = mock("request")
189
+ request.stub!(:host).and_return("blog.stonean.com")
190
+ @controller.stub!(:request).and_return(request)
191
+ @controller.remote_url?("stonean.com").should be_true
192
+ end
193
+
194
+ it "should return true if host doesn't match domain" do
195
+ request = mock("request")
196
+ request.stub!(:host).and_return("stonean.com")
197
+ @controller.stub!(:request).and_return(request)
198
+ @controller.remote_url?("google.com").should be_true
199
+ end
200
+ end
201
+
202
+ describe "#redirect_back_or_default" do
203
+ it "should redirect to default without session[:prevpage]" do
204
+ @controller.should_receive(:redirect_to).with("/")
205
+ @controller.redirect_back_or_default("/")
206
+ end
207
+
208
+ it "should redirect to session[:prevpage]" do
209
+ @session[:prevpage] = "/previous"
210
+ @controller.should_receive(:redirect_to).with("/previous")
211
+ @controller.redirect_back_or_default("/")
212
+ end
213
+ end
214
+
215
+ describe "#login_from_basic_auth?" do
216
+ end
217
+
218
+ describe "#get_auth_data" do
219
+ end
220
+ end
@@ -0,0 +1,87 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. .. .. spec_helper])
2
+
3
+ class TestAView
4
+ def link_to
5
+ "link_to"
6
+ end
7
+
8
+ def button_to
9
+ "button_to"
10
+ end
11
+
12
+ include Lockdown::Frameworks::Rails::View
13
+ end
14
+
15
+ describe Lockdown::Frameworks::Rails::Controller do
16
+
17
+ before do
18
+ @view = TestAView.new
19
+
20
+ @view.stub!(:url_for).and_return("posts/new")
21
+
22
+ @options = {:controller => "posts", :action => "new"}
23
+ end
24
+
25
+ describe "#link_to_secured" do
26
+ it "should return the link if authorized" do
27
+ link = "<a href='http://a.com'>my_link</a>"
28
+ @view.stub!(:authorized?).and_return(true)
29
+ @view.stub!(:link_to_open).and_return(link)
30
+
31
+ @view.link_to_secured("my link", @options).should == link
32
+ end
33
+
34
+ it "should return an empty string if authorized" do
35
+ @view.stub!(:authorized?).and_return(false)
36
+
37
+ @view.link_to_secured("my link", @options).should == ""
38
+ end
39
+ end
40
+
41
+ describe "#button_to_secured" do
42
+ it "should return the link if authorized" do
43
+ link = "<a href='http://a.com'>my_link</a>"
44
+ @view.stub!(:authorized?).and_return(true)
45
+ @view.stub!(:button_to_open).and_return(link)
46
+
47
+ @view.button_to_secured("my link", @options).should == link
48
+ end
49
+
50
+ it "should return an empty string if authorized" do
51
+ @view.stub!(:authorized?).and_return(false)
52
+
53
+ @view.button_to_secured("my link", @options).should == ""
54
+ end
55
+ end
56
+
57
+ describe "#link_to_or_show" do
58
+ it "should return the name if link_to returned an empty string" do
59
+ @view.stub!(:link_to).and_return('')
60
+
61
+ @view.link_to_or_show("my_link", @options).
62
+ should == "my_link"
63
+ end
64
+
65
+ it "should return the link if access is allowed" do
66
+ link = "<a href='http://a.com'>my_link</a>"
67
+ @view.stub!(:link_to).and_return(link)
68
+
69
+ @view.link_to_or_show("my_link", @options).
70
+ should == link
71
+ end
72
+ end
73
+
74
+ describe "#link_to_or_show" do
75
+ it "should return links separated by | " do
76
+ links = ["link_one", "link_two"]
77
+
78
+ @view.links(links).should == links.join(' | ')
79
+ end
80
+
81
+ it "should return links separated by | and handle empty strings" do
82
+ links = ["link_one", "link_two", ""]
83
+
84
+ @view.links(links).should == links.join(' | ')
85
+ end
86
+ end
87
+ end