hone-lockdown 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.gitignore +6 -0
  2. data/History.txt +195 -0
  3. data/README.txt +36 -0
  4. data/Rakefile +14 -0
  5. data/VERSION +1 -0
  6. data/lib/lockdown.rb +73 -0
  7. data/lib/lockdown/context.rb +48 -0
  8. data/lib/lockdown/database.rb +117 -0
  9. data/lib/lockdown/frameworks/rails.rb +105 -0
  10. data/lib/lockdown/frameworks/rails/controller.rb +163 -0
  11. data/lib/lockdown/frameworks/rails/view.rb +50 -0
  12. data/lib/lockdown/helper.rb +101 -0
  13. data/lib/lockdown/orms/active_record.rb +68 -0
  14. data/lib/lockdown/permission.rb +240 -0
  15. data/lib/lockdown/rules.rb +378 -0
  16. data/lib/lockdown/session.rb +57 -0
  17. data/lib/lockdown/system.rb +52 -0
  18. data/rails_generators/lockdown/lockdown_generator.rb +273 -0
  19. data/rails_generators/lockdown/templates/app/controllers/permissions_controller.rb +22 -0
  20. data/rails_generators/lockdown/templates/app/controllers/sessions_controller.rb +39 -0
  21. data/rails_generators/lockdown/templates/app/controllers/user_groups_controller.rb +122 -0
  22. data/rails_generators/lockdown/templates/app/controllers/users_controller.rb +117 -0
  23. data/rails_generators/lockdown/templates/app/helpers/permissions_helper.rb +2 -0
  24. data/rails_generators/lockdown/templates/app/helpers/user_groups_helper.rb +2 -0
  25. data/rails_generators/lockdown/templates/app/helpers/users_helper.rb +2 -0
  26. data/rails_generators/lockdown/templates/app/models/permission.rb +13 -0
  27. data/rails_generators/lockdown/templates/app/models/profile.rb +10 -0
  28. data/rails_generators/lockdown/templates/app/models/user.rb +95 -0
  29. data/rails_generators/lockdown/templates/app/models/user_group.rb +15 -0
  30. data/rails_generators/lockdown/templates/app/views/permissions/index.html.erb +16 -0
  31. data/rails_generators/lockdown/templates/app/views/permissions/show.html.erb +26 -0
  32. data/rails_generators/lockdown/templates/app/views/sessions/new.html.erb +12 -0
  33. data/rails_generators/lockdown/templates/app/views/user_groups/edit.html.erb +33 -0
  34. data/rails_generators/lockdown/templates/app/views/user_groups/index.html.erb +20 -0
  35. data/rails_generators/lockdown/templates/app/views/user_groups/new.html.erb +31 -0
  36. data/rails_generators/lockdown/templates/app/views/user_groups/show.html.erb +29 -0
  37. data/rails_generators/lockdown/templates/app/views/users/edit.html.erb +51 -0
  38. data/rails_generators/lockdown/templates/app/views/users/index.html.erb +22 -0
  39. data/rails_generators/lockdown/templates/app/views/users/new.html.erb +50 -0
  40. data/rails_generators/lockdown/templates/app/views/users/show.html.erb +33 -0
  41. data/rails_generators/lockdown/templates/config/initializers/lockit.rb +1 -0
  42. data/rails_generators/lockdown/templates/db/migrate/create_admin_user.rb +17 -0
  43. data/rails_generators/lockdown/templates/db/migrate/create_permissions.rb +19 -0
  44. data/rails_generators/lockdown/templates/db/migrate/create_profiles.rb +26 -0
  45. data/rails_generators/lockdown/templates/db/migrate/create_user_groups.rb +19 -0
  46. data/rails_generators/lockdown/templates/db/migrate/create_users.rb +17 -0
  47. data/rails_generators/lockdown/templates/lib/lockdown/README +42 -0
  48. data/rails_generators/lockdown/templates/lib/lockdown/init.rb +131 -0
  49. data/spec/lockdown/database_spec.rb +158 -0
  50. data/spec/lockdown/frameworks/rails/controller_spec.rb +224 -0
  51. data/spec/lockdown/frameworks/rails/view_spec.rb +87 -0
  52. data/spec/lockdown/frameworks/rails_spec.rb +175 -0
  53. data/spec/lockdown/permission_spec.rb +166 -0
  54. data/spec/lockdown/rules_spec.rb +109 -0
  55. data/spec/lockdown/session_spec.rb +89 -0
  56. data/spec/lockdown/system_spec.rb +59 -0
  57. data/spec/lockdown_spec.rb +19 -0
  58. data/spec/rcov.opts +5 -0
  59. data/spec/spec.opts +3 -0
  60. data/spec/spec_helper.rb +1 -0
  61. metadata +131 -0
@@ -0,0 +1,105 @@
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
+ mixin_controller
19
+
20
+ Lockdown.view_helper.class_eval do
21
+ include Lockdown::Frameworks::Rails::View
22
+ end
23
+
24
+ Lockdown::System.class_eval do
25
+ extend Lockdown::Frameworks::Rails::System
26
+ end
27
+ end
28
+
29
+ def mixin_controller(klass = Lockdown.controller_parent)
30
+ klass.class_eval do
31
+ include Lockdown::Session
32
+ include Lockdown::Frameworks::Rails::Controller::Lock
33
+ end
34
+
35
+ klass.helper_method :authorized?
36
+
37
+ klass.hide_action(:set_current_user, :configure_lockdown, :check_request_authorization)
38
+
39
+ klass.before_filter do |c|
40
+ c.set_current_user
41
+ c.configure_lockdown
42
+ c.check_request_authorization
43
+ c.check_model_authorization
44
+ end
45
+
46
+ klass.filter_parameter_logging :password, :password_confirmation
47
+
48
+ klass.rescue_from SecurityError, :with => proc{|e| access_denied(e)}
49
+ end
50
+ end # class block
51
+
52
+ module Environment
53
+
54
+ def project_root
55
+ ::RAILS_ROOT
56
+ end
57
+
58
+ def init_file
59
+ "#{project_root}/lib/lockdown/init.rb"
60
+ end
61
+
62
+ def view_helper
63
+ ::ActionView::Base
64
+ end
65
+
66
+ # cache_classes is true in production and testing, need to
67
+ # modify the ApplicationController
68
+ def controller_parent
69
+ if ::Rails.configuration.cache_classes
70
+ ApplicationController
71
+ else
72
+ ActionController::Base
73
+ end
74
+ end
75
+
76
+ # cache_classes is true in production and testing, need to
77
+ # do an instance eval instead
78
+ def add_controller_method(code)
79
+ Lockdown.controller_parent.class_eval code, __FILE__,__LINE__ +1
80
+ end
81
+
82
+ def controller_class_name(str)
83
+ str = "#{str}Controller"
84
+ if str.include?("__")
85
+ str.split("__").collect{|p| Lockdown.camelize(p)}.join("::")
86
+ else
87
+ Lockdown.camelize(str)
88
+ end
89
+ end
90
+
91
+ def fetch_controller_class(str)
92
+ eval("::#{controller_class_name(str)}")
93
+ end
94
+ end
95
+
96
+ module System
97
+ include Lockdown::Frameworks::Rails::Controller
98
+
99
+ def skip_sync?
100
+ Lockdown::System.fetch(:skip_db_sync_in).include?(ENV['RAILS_ENV'])
101
+ end
102
+ end # System
103
+ end # Rails
104
+ end # Frameworks
105
+ end # Lockdown
@@ -0,0 +1,163 @@
1
+ module Lockdown
2
+ module Frameworks
3
+ module Rails
4
+ module Controller
5
+
6
+ def available_actions(klass)
7
+ klass.action_methods
8
+ end
9
+
10
+ def controller_name(klass)
11
+ klass.controller_name
12
+ end
13
+
14
+ # Locking methods
15
+ module Lock
16
+
17
+ def configure_lockdown
18
+ check_session_expiry
19
+ store_location
20
+ end
21
+
22
+ # Basic auth functionality needs to be reworked as
23
+ # Lockdown doesn't provide authentication functionality.
24
+ def set_current_user
25
+ #login_from_basic_auth? unless logged_in?
26
+ if logged_in?
27
+ Thread.current[:who_did_it] = Lockdown::System.
28
+ call(self, :who_did_it)
29
+ end
30
+ end
31
+
32
+ def check_request_authorization
33
+ unless authorized?(path_from_hash(params))
34
+ raise SecurityError, "Authorization failed! \nparams: #{params.inspect}\nsession: #{session.inspect}"
35
+ end
36
+ end
37
+
38
+ protected
39
+
40
+ def path_allowed?(url)
41
+ session[:access_rights] ||= Lockdown::System.public_access
42
+ #
43
+ # If it isn't in the list of non-nested url's,
44
+ # try matching the allowed path with /controller_name/nnn/ tacked onto the front
45
+ #
46
+ if ret = session[:access_rights].include?(url)
47
+ return ret
48
+ else
49
+ return !session[:access_rights].detect { |v| url =~ /\/\w+\/\d+\/#{v}/ }.nil?
50
+ end
51
+ end
52
+
53
+ def check_session_expiry
54
+ if session[:expiry_time] && session[:expiry_time] < Time.now
55
+ nil_lockdown_values
56
+ Lockdown::System.call(self, :session_timeout_method)
57
+ end
58
+ session[:expiry_time] = Time.now + Lockdown::System.fetch(:session_timeout)
59
+ end
60
+
61
+ def store_location
62
+ if (request.method == :get) && (session[:thispage] != sent_from_uri)
63
+ session[:prevpage] = session[:thispage] || ''
64
+ session[:thispage] = sent_from_uri
65
+ end
66
+ end
67
+
68
+ def sent_from_uri
69
+ request.request_uri
70
+ end
71
+
72
+ def authorized?(url, method = nil)
73
+ return false unless url
74
+
75
+ return true if current_user_is_admin?
76
+
77
+ method ||= (params[:method] || request.method)
78
+
79
+ url_parts = URI::split(url.strip)
80
+
81
+ path = url_parts[5]
82
+
83
+ return true if path_allowed?(path)
84
+
85
+ begin
86
+ hash = ActionController::Routing::Routes.recognize_path(path, :method => method)
87
+ return path_allowed?(path_from_hash(hash)) if hash
88
+ rescue Exception => e
89
+ # continue on
90
+ end
91
+
92
+ # Mailto link
93
+ return true if url =~ /^mailto:/
94
+
95
+ # Public file
96
+ file = File.join(RAILS_ROOT, 'public', url)
97
+ return true if File.exists?(file)
98
+
99
+ # Passing in different domain
100
+ return remote_url?(url_parts[2])
101
+ end
102
+
103
+ def access_denied(e)
104
+
105
+ RAILS_DEFAULT_LOGGER.info "Access denied: #{e}"
106
+
107
+ if Lockdown::System.fetch(:logout_on_access_violation)
108
+ reset_session
109
+ end
110
+ respond_to do |format|
111
+ format.html do
112
+ store_location
113
+ redirect_to Lockdown::System.fetch(:access_denied_path)
114
+ return
115
+ end
116
+ format.xml do
117
+ headers["Status"] = "Unauthorized"
118
+ headers["WWW-Authenticate"] = %(Basic realm="Web Password")
119
+ render :text => e.message, :status => "401 Unauthorized"
120
+ return
121
+ end
122
+ end
123
+ end
124
+
125
+ def path_from_hash(hash)
126
+ hash[:controller].to_s + "/" + hash[:action].to_s
127
+ end
128
+
129
+ def remote_url?(domain = nil)
130
+ return false if domain.nil? || domain.strip.length == 0
131
+ request.host.downcase != domain.downcase
132
+ end
133
+
134
+ def redirect_back_or_default(default)
135
+ if session[:prevpage].nil? || session[:prevpage].blank?
136
+ redirect_to(default)
137
+ else
138
+ redirect_to(session[:prevpage])
139
+ end
140
+ end
141
+
142
+ # Called from current_user. Now, attempt to login by
143
+ # basic authentication information.
144
+ def login_from_basic_auth?
145
+ username, passwd = get_auth_data
146
+ if username && passwd
147
+ set_session_user ::User.authenticate(username, passwd)
148
+ end
149
+ end
150
+
151
+ @@http_auth_headers = %w(X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION Authorization)
152
+ # gets BASIC auth info
153
+ def get_auth_data
154
+ auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) }
155
+ auth_data = request.env[auth_key].to_s.split unless auth_key.blank?
156
+ return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil]
157
+ end
158
+ end # Lock
159
+ end # Controller
160
+ end # Rails
161
+ end # Frameworks
162
+ end # Lockdown
163
+
@@ -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] : :get
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] : :get
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,101 @@
1
+ module Lockdown
2
+ module Helper
3
+ def class_name_from_file(str)
4
+ str.split(".")[0].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 user_group_class
18
+ eval(Lockdown::System.fetch(:user_group_model))
19
+ end
20
+
21
+ def user_groups_hbtm_reference
22
+ underscore(Lockdown::System.fetch(:user_group_model)).pluralize.to_sym
23
+ end
24
+
25
+ def user_group_id_reference
26
+ underscore(Lockdown::System.fetch(:user_group_model)) + "_id"
27
+ end
28
+
29
+ def user_class
30
+ eval(Lockdown::System.fetch(:user_model))
31
+ end
32
+
33
+ def users_hbtm_reference
34
+ underscore(Lockdown::System.fetch(:user_model)).pluralize.to_sym
35
+ end
36
+
37
+ def user_id_reference
38
+ underscore(Lockdown::System.fetch(:user_model)) + "_id"
39
+ end
40
+
41
+ def get_string(value)
42
+ if value.respond_to?(:name)
43
+ string_name(value.name)
44
+ else
45
+ string_name(value)
46
+ end
47
+ end
48
+
49
+ def get_symbol(value)
50
+ if value.respond_to?(:name)
51
+ symbol_name(value.name)
52
+ elsif value.is_a?(String)
53
+ symbol_name(value)
54
+ else
55
+ value
56
+ end
57
+ end
58
+
59
+ def camelize(str)
60
+ str.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
61
+ end
62
+
63
+ def random_string(len = 10)
64
+ chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
65
+ Array.new(len){||chars[rand(chars.size)]}.join
66
+ end
67
+
68
+ def administrator_group_string
69
+ string_name(administrator_group_symbol)
70
+ end
71
+
72
+ def administrator_group_symbol
73
+ :administrators
74
+ end
75
+
76
+ private
77
+
78
+ def string_name(str_sym)
79
+ str_sym.is_a?(Symbol) ? convert_reference_name(str_sym) : str_sym
80
+ end
81
+
82
+ def symbol_name(str_sym)
83
+ str_sym.is_a?(String) ? convert_reference_name(str_sym) : str_sym
84
+ end
85
+
86
+ def titleize(str)
87
+ humanize(underscore(str)).gsub(/\b([a-z])/) { $1.capitalize }
88
+ end
89
+
90
+ def humanize(str)
91
+ str.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
92
+ end
93
+
94
+ def underscore(str)
95
+ str.to_s.gsub(/::/, '/').
96
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
97
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
98
+ tr("-", "_").downcase
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,68 @@
1
+ module Lockdown
2
+ module Orms
3
+ module ActiveRecord
4
+ class << self
5
+ def use_me?
6
+ Object.const_defined?("ActiveRecord") && ::ActiveRecord.const_defined?("Base")
7
+ end
8
+
9
+ def included(mod)
10
+ mod.extend Lockdown::Orms::ActiveRecord::Helper
11
+ mixin
12
+ end
13
+
14
+ def mixin
15
+ Lockdown.orm_parent.class_eval do
16
+ include Lockdown::Orms::ActiveRecord::Stamps
17
+ end
18
+ end
19
+ end # class block
20
+
21
+ module Helper
22
+ def orm_parent
23
+ ::ActiveRecord::Base
24
+ end
25
+
26
+ def database_execute(query)
27
+ orm_parent.connection.execute(query)
28
+ end
29
+
30
+ def database_query(query)
31
+ orm_parent.connection.execute(query)
32
+ end
33
+
34
+ def database_table_exists?(klass)
35
+ klass.table_exists?
36
+ end
37
+ end
38
+
39
+ module Stamps
40
+ def self.included(base)
41
+ base.class_eval do
42
+ alias_method :create_without_stamps, :create
43
+ alias_method :create, :create_with_stamps
44
+ alias_method :update_without_stamps, :update
45
+ alias_method :update, :update_with_stamps
46
+ end
47
+ end
48
+
49
+ def current_who_did_it
50
+ Thread.current[:who_did_it]
51
+ end
52
+
53
+ def create_with_stamps
54
+ pid = current_who_did_it || Lockdown::System.fetch(:default_who_did_it)
55
+ self[:created_by] = pid if self.respond_to?(:created_by)
56
+ self[:updated_by] = pid if self.respond_to?(:updated_by)
57
+ create_without_stamps
58
+ end
59
+
60
+ def update_with_stamps
61
+ pid = current_who_did_it || Lockdown::System.fetch(:default_who_did_it)
62
+ self[:updated_by] = pid if self.respond_to?(:updated_by)
63
+ update_without_stamps
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end