blaxter-lockdown 0.9.8.99

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 (59) hide show
  1. data/History.txt +195 -0
  2. data/README.txt +36 -0
  3. data/Rakefile +41 -0
  4. data/lib/lockdown.rb +70 -0
  5. data/lib/lockdown/context.rb +41 -0
  6. data/lib/lockdown/database.rb +105 -0
  7. data/lib/lockdown/frameworks/rails.rb +154 -0
  8. data/lib/lockdown/frameworks/rails/controller.rb +154 -0
  9. data/lib/lockdown/frameworks/rails/view.rb +50 -0
  10. data/lib/lockdown/helper.rb +95 -0
  11. data/lib/lockdown/orms/active_record.rb +68 -0
  12. data/lib/lockdown/permission.rb +204 -0
  13. data/lib/lockdown/rules.rb +321 -0
  14. data/lib/lockdown/session.rb +57 -0
  15. data/lib/lockdown/system.rb +60 -0
  16. data/rails_generators/lockdown/lockdown_generator.rb +273 -0
  17. data/rails_generators/lockdown/templates/app/controllers/permissions_controller.rb +22 -0
  18. data/rails_generators/lockdown/templates/app/controllers/sessions_controller.rb +39 -0
  19. data/rails_generators/lockdown/templates/app/controllers/user_groups_controller.rb +122 -0
  20. data/rails_generators/lockdown/templates/app/controllers/users_controller.rb +117 -0
  21. data/rails_generators/lockdown/templates/app/helpers/permissions_helper.rb +2 -0
  22. data/rails_generators/lockdown/templates/app/helpers/user_groups_helper.rb +2 -0
  23. data/rails_generators/lockdown/templates/app/helpers/users_helper.rb +2 -0
  24. data/rails_generators/lockdown/templates/app/models/permission.rb +13 -0
  25. data/rails_generators/lockdown/templates/app/models/profile.rb +10 -0
  26. data/rails_generators/lockdown/templates/app/models/user.rb +95 -0
  27. data/rails_generators/lockdown/templates/app/models/user_group.rb +15 -0
  28. data/rails_generators/lockdown/templates/app/views/permissions/index.html.erb +16 -0
  29. data/rails_generators/lockdown/templates/app/views/permissions/show.html.erb +26 -0
  30. data/rails_generators/lockdown/templates/app/views/sessions/new.html.erb +12 -0
  31. data/rails_generators/lockdown/templates/app/views/user_groups/edit.html.erb +33 -0
  32. data/rails_generators/lockdown/templates/app/views/user_groups/index.html.erb +20 -0
  33. data/rails_generators/lockdown/templates/app/views/user_groups/new.html.erb +31 -0
  34. data/rails_generators/lockdown/templates/app/views/user_groups/show.html.erb +29 -0
  35. data/rails_generators/lockdown/templates/app/views/users/edit.html.erb +51 -0
  36. data/rails_generators/lockdown/templates/app/views/users/index.html.erb +22 -0
  37. data/rails_generators/lockdown/templates/app/views/users/new.html.erb +50 -0
  38. data/rails_generators/lockdown/templates/app/views/users/show.html.erb +33 -0
  39. data/rails_generators/lockdown/templates/config/initializers/lockit.rb +1 -0
  40. data/rails_generators/lockdown/templates/db/migrate/create_admin_user.rb +17 -0
  41. data/rails_generators/lockdown/templates/db/migrate/create_permissions.rb +19 -0
  42. data/rails_generators/lockdown/templates/db/migrate/create_profiles.rb +26 -0
  43. data/rails_generators/lockdown/templates/db/migrate/create_user_groups.rb +19 -0
  44. data/rails_generators/lockdown/templates/db/migrate/create_users.rb +17 -0
  45. data/rails_generators/lockdown/templates/lib/lockdown/README +42 -0
  46. data/rails_generators/lockdown/templates/lib/lockdown/init.rb +122 -0
  47. data/spec/lockdown/database_spec.rb +158 -0
  48. data/spec/lockdown/frameworks/rails/controller_spec.rb +224 -0
  49. data/spec/lockdown/frameworks/rails/view_spec.rb +87 -0
  50. data/spec/lockdown/frameworks/rails_spec.rb +175 -0
  51. data/spec/lockdown/permission_spec.rb +156 -0
  52. data/spec/lockdown/rules_spec.rb +109 -0
  53. data/spec/lockdown/session_spec.rb +89 -0
  54. data/spec/lockdown/system_spec.rb +59 -0
  55. data/spec/lockdown_spec.rb +19 -0
  56. data/spec/rcov.opts +5 -0
  57. data/spec/spec.opts +3 -0
  58. data/spec/spec_helper.rb +1 -0
  59. metadata +122 -0
@@ -0,0 +1,154 @@
1
+ require File.join(File.dirname(__FILE__), "rails", "controller")
2
+ require File.join(File.dirname(__FILE__), "rails", "view")
3
+
4
+ module Lockdown
5
+ module Frameworks
6
+ module Rails
7
+ class << self
8
+ def use_me?
9
+ Object.const_defined?("ActionController") && ActionController.const_defined?("Base")
10
+ end
11
+
12
+ def included(mod)
13
+ mod.extend Lockdown::Frameworks::Rails::Environment
14
+ mixin
15
+ end
16
+
17
+ def mixin
18
+ Lockdown.controller_parent.class_eval do
19
+ include Lockdown::Session
20
+ include Lockdown::Frameworks::Rails::Controller::Lock
21
+ end
22
+
23
+ Lockdown.controller_parent.helper_method :authorized?
24
+
25
+ Lockdown.controller_parent.before_filter do |c|
26
+ c.set_current_user
27
+ c.configure_lockdown
28
+ c.check_request_authorization
29
+ end
30
+
31
+ Lockdown.controller_parent.filter_parameter_logging :password,
32
+ :password_confirmation
33
+
34
+ Lockdown.controller_parent.rescue_from SecurityError,
35
+ :with => proc{|e| access_denied(e)}
36
+
37
+ Lockdown.view_helper.class_eval do
38
+ include Lockdown::Frameworks::Rails::View
39
+ end
40
+
41
+ Lockdown::System.class_eval do
42
+ extend Lockdown::Frameworks::Rails::System
43
+ end
44
+ end
45
+ end # class block
46
+
47
+ module Environment
48
+
49
+ def project_root
50
+ ::RAILS_ROOT
51
+ end
52
+
53
+ def init_file
54
+ "#{project_root}/lib/lockdown/init.rb"
55
+ end
56
+
57
+ def controller_parent
58
+ ::ActionController::Base
59
+ end
60
+
61
+ def view_helper
62
+ ::ActionView::Base
63
+ end
64
+
65
+ def controller_class_name(str)
66
+ str = "#{str}Controller"
67
+ if str.include?("__")
68
+ str.split("__").collect{|p| Lockdown.camelize(p)}.join("::")
69
+ else
70
+ Lockdown.camelize(str)
71
+ end
72
+ end
73
+ end
74
+
75
+ module System
76
+ include Lockdown::Frameworks::Rails::Controller
77
+
78
+ def skip_sync?
79
+ Lockdown::System.fetch(:skip_db_sync_in).include?(ENV['RAILS_ENV'])
80
+ end
81
+
82
+ def load_controller_classes
83
+ @controller_classes = {}
84
+
85
+ maybe_load_framework_controller_parent
86
+
87
+ ApplicationController.helper_method :authorized?
88
+
89
+ ApplicationController.before_filter do |c|
90
+ c.set_current_user
91
+ c.configure_lockdown
92
+ c.check_request_authorization
93
+ end
94
+
95
+ ApplicationController.filter_parameter_logging :password,
96
+ :password_confirmation
97
+
98
+ ApplicationController.rescue_from SecurityError,
99
+ :with => proc{|e| access_denied(e)}
100
+
101
+
102
+ Dir.chdir("#{Lockdown.project_root}/app/controllers") do
103
+ Dir["**/*.rb"].sort.each do |c|
104
+ c = c.split('.').first
105
+ next if c == "application"
106
+ lockdown_load(c)
107
+ end
108
+ if PLATFORM =~ /java/
109
+ Dir["**/*.class"].sort.each do |c|
110
+ c = c.split('.').first
111
+ next if c == "application"
112
+ lockdown_load(c)
113
+ end
114
+ end
115
+ end
116
+
117
+ if ENV['RAILS_ENV'] != 'production'
118
+ if ActiveSupport.const_defined?("Dependencies")
119
+ ActiveSupport::Dependencies.clear
120
+ else
121
+ Dependencies.clear
122
+ end
123
+ end
124
+ end
125
+
126
+ def maybe_load_framework_controller_parent
127
+ if ::Rails::VERSION::MAJOR >= 2 && ::Rails::VERSION::MINOR >= 3
128
+ filename = "application_controller.rb"
129
+ else
130
+ filename = "application.rb"
131
+ end
132
+
133
+ require_or_load(filename)
134
+ end
135
+
136
+ def lockdown_load(filename)
137
+ klass = Lockdown.class_name_from_file(filename)
138
+
139
+ require_or_load(filename)
140
+
141
+ @controller_classes[klass] = Lockdown.qualified_const_get(klass)
142
+ end
143
+
144
+ def require_or_load(filename)
145
+ if ActiveSupport.const_defined?("Dependencies")
146
+ ActiveSupport::Dependencies.require_or_load(filename)
147
+ else
148
+ Dependencies.require_or_load(filename)
149
+ end
150
+ end
151
+ end # System
152
+ end # Rails
153
+ end # Frameworks
154
+ end # Lockdown
@@ -0,0 +1,154 @@
1
+ module Lockdown
2
+ module Frameworks
3
+ module Rails
4
+ module Controller
5
+
6
+ def available_actions(klass)
7
+ if klass.respond_to?(:action_methods)
8
+ klass.action_methods
9
+ else
10
+ klass.public_instance_methods - klass.hidden_actions
11
+ end
12
+ end
13
+
14
+ def controller_name(klass)
15
+ klass.controller_name
16
+ end
17
+
18
+ # Locking methods
19
+ module Lock
20
+ def configure_lockdown
21
+ check_session_expiry
22
+ store_location
23
+ end
24
+
25
+ def set_current_user
26
+ login_from_basic_auth? unless logged_in?
27
+ if logged_in?
28
+ Thread.current[:who_did_it] = Lockdown::System.
29
+ call(self, :who_did_it)
30
+ end
31
+ end
32
+
33
+ def check_request_authorization
34
+ unless authorized?(path_from_hash(params))
35
+ raise SecurityError, "Authorization failed for params #{params.inspect}"
36
+ end
37
+ end
38
+
39
+ def path_allowed?(url)
40
+ session[:access_rights] ||= Lockdown::System.public_access
41
+ session[:access_rights].include?(url)
42
+ end
43
+
44
+ def check_session_expiry
45
+ if session[:expiry_time] && session[:expiry_time] < Time.now
46
+ nil_lockdown_values
47
+ Lockdown::System.call(self, :session_timeout_method)
48
+ end
49
+ session[:expiry_time] = Time.now + Lockdown::System.fetch(:session_timeout)
50
+ end
51
+
52
+ def store_location
53
+ if (request.method == :get) && (session[:thispage] != sent_from_uri)
54
+ session[:prevpage] = session[:thispage] || ''
55
+ session[:thispage] = sent_from_uri
56
+ end
57
+ end
58
+
59
+ def sent_from_uri
60
+ request.request_uri
61
+ end
62
+
63
+ def authorized?(url, method = nil)
64
+ return false unless url
65
+
66
+ return true if current_user_is_admin?
67
+
68
+ method ||= (params[:method] || request.method)
69
+
70
+ url_parts = URI::split(url.strip)
71
+
72
+ path = url_parts[5]
73
+
74
+ return true if path_allowed?(path)
75
+
76
+ begin
77
+ hash = ActionController::Routing::Routes.recognize_path(path, :method => method)
78
+ return path_allowed?(path_from_hash(hash)) if hash
79
+ rescue Exception
80
+ # continue on
81
+ end
82
+
83
+ # Mailto link
84
+ return true if url =~ /^mailto:/
85
+
86
+ # Public file
87
+ file = File.join(RAILS_ROOT, 'public', url)
88
+ return true if File.exists?(file)
89
+
90
+ # Passing in different domain
91
+ return remote_url?(url_parts[2])
92
+ end
93
+
94
+ def access_denied(e)
95
+
96
+ RAILS_DEFAULT_LOGGER.info "Access denied: #{e}"
97
+
98
+ if Lockdown::System.fetch(:logout_on_access_violation)
99
+ reset_session
100
+ end
101
+ respond_to do |format|
102
+ format.html do
103
+ store_location
104
+ redirect_to Lockdown::System.fetch(:access_denied_path)
105
+ return
106
+ end
107
+ format.xml do
108
+ headers["Status"] = "Unauthorized"
109
+ headers["WWW-Authenticate"] = %(Basic realm="Web Password")
110
+ render :text => e.message, :status => "401 Unauthorized"
111
+ return
112
+ end
113
+ end
114
+ end
115
+
116
+ def path_from_hash(hash)
117
+ hash[:controller].to_s + "/" + hash[:action].to_s
118
+ end
119
+
120
+ def remote_url?(domain = nil)
121
+ return false if domain.nil? || domain.strip.length == 0
122
+ request.host.downcase != domain.downcase
123
+ end
124
+
125
+ def redirect_back_or_default(default)
126
+ if session[:prevpage].nil? || session[:prevpage].blank?
127
+ redirect_to(default)
128
+ else
129
+ redirect_to(session[:prevpage])
130
+ end
131
+ end
132
+
133
+ # Called from current_user. Now, attempt to login by
134
+ # basic authentication information.
135
+ def login_from_basic_auth?
136
+ username, passwd = get_auth_data
137
+ if username && passwd
138
+ set_session_user ::User.authenticate(username, passwd)
139
+ end
140
+ end
141
+
142
+ @@http_auth_headers = %w(X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION Authorization)
143
+ # gets BASIC auth info
144
+ def get_auth_data
145
+ auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) }
146
+ auth_data = request.env[auth_key].to_s.split unless auth_key.blank?
147
+ return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil]
148
+ end
149
+ end # Lock
150
+ end # Controller
151
+ end # Rails
152
+ end # Frameworks
153
+ end # Lockdown
154
+
@@ -0,0 +1,50 @@
1
+ module Lockdown
2
+ module Frameworks
3
+ module Rails
4
+ module View
5
+ def self.included(base)
6
+ base.class_eval do
7
+ alias_method :link_to_open, :link_to
8
+ alias_method :link_to, :link_to_secured
9
+
10
+ alias_method :button_to_open, :button_to
11
+ alias_method :button_to, :button_to_secured
12
+ end
13
+ end
14
+
15
+ def link_to_secured(name, options = {}, html_options = nil)
16
+ url = url_for(options)
17
+
18
+ method = html_options ? html_options[:method] : nil
19
+
20
+ if authorized?(url, method)
21
+ return link_to_open(name, url, html_options)
22
+ end
23
+ return ""
24
+ end
25
+
26
+ def button_to_secured(name, options = {}, html_options = nil)
27
+ url = url_for(options)
28
+
29
+ method = html_options ? html_options[:method] : nil
30
+
31
+ if authorized?(url, method)
32
+ return button_to_open(name, url, html_options)
33
+ end
34
+ return ""
35
+ end
36
+
37
+ def link_to_or_show(name, options = {}, html_options = nil)
38
+ lnk = link_to(name, options, html_options)
39
+ lnk.length == 0 ? name : lnk
40
+ end
41
+
42
+ def links(*lis)
43
+ rvalue = []
44
+ lis.each{|link| rvalue << link if link.length > 0 }
45
+ rvalue.join( Lockdown::System.fetch(:link_separator) )
46
+ end
47
+ end # View
48
+ end # Rails
49
+ end # Frameworks
50
+ end # Lockdown
@@ -0,0 +1,95 @@
1
+ module Lockdown
2
+ module Helper
3
+ def class_name_from_file(str)
4
+ str.split("/").collect{|s| camelize(s) }.join("::")
5
+ end
6
+
7
+ # If str_sym is a Symbol (:users), return "Users"
8
+ # If str_sym is a String ("Users"), return :users
9
+ def convert_reference_name(str_sym)
10
+ if str_sym.is_a?(Symbol)
11
+ titleize(str_sym)
12
+ else
13
+ underscore(str_sym).tr(' ','_').to_sym
14
+ end
15
+ end
16
+
17
+ def get_string(value)
18
+ if value.respond_to?(:name)
19
+ string_name(value.name)
20
+ else
21
+ string_name(value)
22
+ end
23
+ end
24
+
25
+ def get_symbol(value)
26
+ if value.respond_to?(:name)
27
+ symbol_name(value.name)
28
+ elsif value.is_a?(String)
29
+ symbol_name(value)
30
+ else
31
+ value
32
+ end
33
+ end
34
+
35
+ def camelize(str)
36
+ str.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
37
+ end
38
+
39
+ def random_string(len = 10)
40
+ chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
41
+ Array.new(len){||chars[rand(chars.size)]}.join
42
+ end
43
+
44
+ def administrator_group_string
45
+ string_name(administrator_group_symbol)
46
+ end
47
+
48
+ def administrator_group_symbol
49
+ :administrators
50
+ end
51
+
52
+ def qualified_const_defined?(klass)
53
+ if klass =~ /::/
54
+ namespace, klass = klass.split("::")
55
+ eval("#{namespace}.const_defined?(#{klass})") if const_defined?(namespace)
56
+ else
57
+ const_defined?(klass)
58
+ end
59
+ end
60
+
61
+ def qualified_const_get(klass)
62
+ if klass =~ /::/
63
+ namespace, klass = klass.split("::")
64
+ eval(namespace).const_get(klass)
65
+ else
66
+ const_get(klass)
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def string_name(str_sym)
73
+ str_sym.is_a?(Symbol) ? convert_reference_name(str_sym) : str_sym
74
+ end
75
+
76
+ def symbol_name(str_sym)
77
+ str_sym.is_a?(String) ? convert_reference_name(str_sym) : str_sym
78
+ end
79
+
80
+ def titleize(str)
81
+ humanize(underscore(str)).gsub(/\b([a-z])/) { $1.capitalize }
82
+ end
83
+
84
+ def humanize(str)
85
+ str.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
86
+ end
87
+
88
+ def underscore(str)
89
+ str.to_s.gsub(/::/, '/').
90
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
91
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
92
+ tr("-", "_").downcase
93
+ end
94
+ end
95
+ end