blaxter-lockdown 0.9.8.99

Sign up to get free protection for your applications and to get access to all the features.
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