hone-lockdown 1.2.1

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 (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