lockdown 0.5.22 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,108 @@
1
+ module Lockdown
2
+ class Database
3
+ class << self
4
+ # This is very basic and could be handled better using orm specific
5
+ # functionality, but I wanted to keep it generic to avoid creating
6
+ # an interface for each the different orm implementations.
7
+ # We'll see how it works...
8
+ def sync_with_db
9
+
10
+ @permissions = Lockdown::System.get_permissions
11
+ @user_groups = Lockdown::System.get_user_groups
12
+
13
+ create_new_permissions
14
+
15
+ delete_extinct_permissions
16
+
17
+ maintain_user_groups
18
+ rescue Exception => e
19
+ puts ">> Lockdown sync failed: #{e}"
20
+ end
21
+
22
+ private
23
+
24
+ # Create permissions not found in the database
25
+ def create_new_permissions
26
+ @permissions.each do |key|
27
+ next if Lockdown::System.permission_assigned_automatically?(key)
28
+ str = Lockdown.get_string(key)
29
+ p = Permission.find(:first, :conditions => ["name = ?", str])
30
+ unless p
31
+ puts ">> Lockdown: Permission not found in db: #{str}, creating."
32
+ Permission.create(:name => str)
33
+ end
34
+ end
35
+ end
36
+
37
+ # Delete the permissions not found in init.rb
38
+ def delete_extinct_permissions
39
+ db_perms = Permission.find(:all).dup
40
+ db_perms.each do |dbp|
41
+ unless @permissions.include?(Lockdown.get_symbol(dbp.name))
42
+ puts ">> Lockdown: Permission no longer in init.rb: #{dbp.name}, deleting."
43
+ Lockdown.database_execute("delete from permissions_user_groups where permission_id = #{dbp.id}")
44
+ dbp.destroy
45
+ end
46
+ end
47
+ end
48
+
49
+ def maintain_user_groups
50
+ # Create user groups not found in the database
51
+ @user_groups.each do |key|
52
+ str = Lockdown.get_string(key)
53
+ unless ug = UserGroup.find(:first, :conditions => ["name = ?", str])
54
+ create_user_group(str)
55
+ else
56
+ # Remove permissions from user group not found in init.rb
57
+ remove_invalid_permissions(ug, key)
58
+
59
+ # Add in permissions from init.rb not found in database
60
+ add_valid_permissions(ug, key)
61
+ end
62
+ end
63
+ end
64
+
65
+ def create_user_group(name_str)
66
+ puts ">> Lockdown: UserGroup not in the db: #{name_str}, creating."
67
+ ug = UserGroup.create(:name => name_str)
68
+ #Inefficient, definitely, but shouldn't have any issues across orms.
69
+ Lockdown::System.permissions_for_user_group(key) do |perm|
70
+ p = Permission.find(:first, :conditions => ["name = ?", Lockdown.get_string(perm)])
71
+ Lockdown.database_execute <<-SQL
72
+ insert into permissions_user_groups(permission_id, user_group_id)
73
+ values(#{p.id}, #{ug.id})
74
+ SQL
75
+ end
76
+ end
77
+
78
+ def remove_invalid_permissions(ug, key)
79
+ ug.permissions.each do |perm|
80
+ perm_sym = Lockdown.get_symbol(perm)
81
+ perm_string = Lockdown.get_string(perm)
82
+ unless @user_groups[key].include?(perm_sym)
83
+ puts ">> Lockdown: Permission: #{perm_string} no longer associated to User Group: #{ug.name}, deleting."
84
+ ug.permissions.delete(perm)
85
+ end
86
+ end
87
+ end
88
+
89
+ def add_valid_permissions(ug, key)
90
+ @user_groups[key].each do |perm|
91
+ perm_string = Lockdown.get_string(perm)
92
+ found = false
93
+ # see if permission exists
94
+ ug.permissions.each do |p|
95
+ found = true if Lockdown.get_string(p) == perm_string
96
+ end
97
+ # if not found, add it
98
+ unless found
99
+ puts ">> Lockdown: Permission: #{perm_string} not found for User Group: #{ug.name}, adding it."
100
+ p = Permission.find(:first, :conditions => ["name = ?", perm_string])
101
+ ug.permissions << p
102
+ end
103
+ end
104
+ end
105
+
106
+ end # class block
107
+ end # Database
108
+ end #Lockdown
@@ -0,0 +1,59 @@
1
+ module Lockdown
2
+ module Frameworks
3
+ module Merb
4
+ module Controller
5
+
6
+ def available_actions(klass)
7
+ klass.callable_actions.keys
8
+ end
9
+
10
+ def controller_name(klass)
11
+ klass.controller_name
12
+ end
13
+
14
+ # Locking methods
15
+ module Lock
16
+ def self.included(base)
17
+ base.send :include, Lockdown::Frameworks::Merb::Controller::Lock::InstanceMethods
18
+
19
+ base.before :set_current_user
20
+ base.before :configure_lockdown
21
+ base.before :check_request_authorization
22
+ end
23
+
24
+ module InstanceMethods
25
+ def self.included(base)
26
+ base.send :include, Lockdown::Controller::Core
27
+ end
28
+
29
+ def sent_from_uri
30
+ request.uri
31
+ end
32
+
33
+ def authorized?(path)
34
+ return true if current_user_is_admin?
35
+
36
+ path_allowed?(path)
37
+ end
38
+
39
+ # Can log Error => e if desired, I don't desire to now.
40
+ # For now, just send home, but will probably make this configurable
41
+ def access_denied(e)
42
+ redirect Lockdown::System.fetch(:access_denied_path)
43
+ end
44
+
45
+ def path_from_hash(hsh)
46
+ return hsh if hsh.is_a?(String)
47
+ hsh = hsh.to_hash if hsh.is_a?(Mash)
48
+ hsh['controller'].to_s + "/" + hsh['action'].to_s
49
+ end
50
+
51
+ def redirect_back_or_default(default)
52
+ session[:prevpage] ? redirect(session[:prevpage]) : redirect(default)
53
+ end
54
+ end # InstanceMethods
55
+ end # Lock
56
+ end # Controller
57
+ end # Merb
58
+ end # Frameworks
59
+ end # Lockdown
@@ -0,0 +1,30 @@
1
+ module Lockdown
2
+ module Frameworks
3
+ module Merb
4
+ module View
5
+ def self.included(base)
6
+ base.send :alias_method, :link_to_open, :link_to
7
+ base.send :alias_method, :link_to, :link_to_secured
8
+ end
9
+
10
+ def link_to_secured(name, url = '', options = {})
11
+ if authorized? url
12
+ return link_to_open(name, url, options)
13
+ end
14
+ return ""
15
+ end
16
+
17
+ def link_to_or_show(name, url = '', options = {})
18
+ lnk = link_to(name, url , options)
19
+ lnk.length == 0 ? name : lnk
20
+ end
21
+
22
+ def links(*lis)
23
+ rvalue = []
24
+ lis.each{|link| rvalue << link if link.length > 0 }
25
+ rvalue.join(" | ")
26
+ end
27
+ end # View
28
+ end # Merb
29
+ end # Frameworks
30
+ end # Lockdown
@@ -0,0 +1,74 @@
1
+ require File.join(File.dirname(__FILE__), "merb", "controller")
2
+ require File.join(File.dirname(__FILE__), "merb", "view")
3
+
4
+ module Lockdown
5
+ module Frameworks
6
+ module Merb
7
+ class << self
8
+ def use_me?
9
+ Object.const_defined?("Merb") && ::Merb.const_defined?("AbstractController")
10
+ end
11
+
12
+ def included(mod)
13
+ mod.extend Lockdown::Frameworks::Merb::Environment
14
+ mixin
15
+ end
16
+
17
+ def mixin
18
+ Lockdown.controller_parent.send :include, Lockdown::Frameworks::Merb::Controller::Lock
19
+ Lockdown.view_helper.send :include, Lockdown::Frameworks::Merb::View
20
+ Lockdown::System.send :extend, Lockdown::Frameworks::Merb::System
21
+ end
22
+ end # class block
23
+
24
+
25
+ module Environment
26
+ def project_root
27
+ ::Merb.root
28
+ end
29
+
30
+ def controller_parent
31
+ ::Merb::Controller
32
+ end
33
+
34
+ def view_helper
35
+ ::Merb::AssetsMixin
36
+ end
37
+
38
+ def controller_class_name(str)
39
+ if str.include?("__")
40
+ str.split("__").collect{|p| Lockdown.camelize(p)}.join("::")
41
+ else
42
+ Lockdown.camelize(str)
43
+ end
44
+ end
45
+ end
46
+
47
+ module System
48
+ include Lockdown::Frameworks::Merb::Controller
49
+
50
+ def load_controller_classes
51
+ @controller_classes = {}
52
+
53
+ maybe_load_framework_controller_parent
54
+
55
+ Dir.chdir("#{Lockdown.project_root}/app/controllers") do
56
+ Dir["**/*.rb"].sort.each do |c|
57
+ next if c == "application.rb"
58
+ lockdown_load(c)
59
+ end
60
+ end
61
+ end
62
+
63
+ def maybe_load_framework_controller_parent
64
+ load("application.rb") unless const_defined?("Application")
65
+ end
66
+
67
+ def lockdown_load(file)
68
+ klass = Lockdown.class_name_from_file(file)
69
+ @controller_classes[klass] = Lockdown.qualified_const_get(klass)
70
+ end
71
+ end # System
72
+ end # Merb
73
+ end # Frameworks
74
+ end # Lockdown
@@ -0,0 +1,110 @@
1
+ module Lockdown
2
+ module Frameworks
3
+ module Rails
4
+ module Controller
5
+
6
+ def available_actions(klass)
7
+ klass.public_instance_methods - klass.hidden_actions
8
+ end
9
+
10
+ def controller_name(klass)
11
+ klass.controller_name
12
+ end
13
+
14
+ # Locking methods
15
+ module Lock
16
+ def self.included(base)
17
+ base.send :include, Lockdown::Frameworks::Rails::Controller::Lock::InstanceMethods
18
+
19
+ base.before_filter do |c|
20
+ c.set_current_user
21
+ c.configure_lockdown
22
+ c.check_request_authorization
23
+ end
24
+
25
+ base.send :helper_method, :authorized?
26
+
27
+ base.filter_parameter_logging :password, :password_confirmation
28
+
29
+ base.rescue_from SecurityError, :with => proc{|e| access_denied(e)}
30
+ end
31
+
32
+ module InstanceMethods
33
+ def self.included(base)
34
+ base.send :include, Lockdown::Controller::Core
35
+ end
36
+
37
+ def sent_from_uri
38
+ request.request_uri
39
+ end
40
+
41
+ def authorized?(url)
42
+ return false unless url
43
+ return true if current_user_is_admin?
44
+
45
+ url_parts = URI::split(url.strip)
46
+ # remove id from path, e.g.: /users/1/edit to users/edit
47
+ path = url_parts[5].split("/").collect do |p|
48
+ p unless p =~ /\A\d+\z/ || p.strip.length == 0
49
+ end.compact.join("/")
50
+
51
+ ## See if path is known
52
+ return true if path_allowed?(path)
53
+
54
+ # Test for a named routed
55
+ begin
56
+ hsh = ActionController::Routing::Routes.recognize_path(path)
57
+ unless hsh.nil? || hsh[:id]
58
+ return true if path_allowed?(path_from_hash(hsh))
59
+ end
60
+ rescue Exception
61
+ # continue on
62
+ end
63
+
64
+ # Passing in different domain
65
+ return true if remote_url?(url_parts[2])
66
+ false
67
+ end
68
+
69
+ def access_denied(e)
70
+
71
+ RAILS_DEFAULT_LOGGER.info "Access denied: #{e}"
72
+
73
+ if Lockdown::System.fetch(:logout_on_access_violation)
74
+ reset_session
75
+ end
76
+ respond_to do |format|
77
+ format.html do
78
+ store_location
79
+ redirect_to Lockdown::System.fetch(:access_denied_path)
80
+ return
81
+ end
82
+ format.xml do
83
+ headers["Status"] = "Unauthorized"
84
+ headers["WWW-Authenticate"] = %(Basic realm="Web Password")
85
+ render :text => e.message, :status => "401 Unauthorized"
86
+ return
87
+ end
88
+ end
89
+ end
90
+
91
+ def path_from_hash(hsh)
92
+ hsh[:controller].to_s + "/" + hsh[:action].to_s
93
+ end
94
+
95
+ def remote_url?(domain = nil)
96
+ return false if domain.nil? || domain.strip.length == 0
97
+ request.host.downcase != domain.downcase
98
+ end
99
+
100
+ def redirect_back_or_default(default)
101
+ session[:prevpage] ? redirect_to(session[:prevpage]) : redirect_to(default)
102
+ end
103
+
104
+ end # InstanceMethods
105
+ end # Lock
106
+ end # Controller
107
+ end # Rails
108
+ end # Frameworks
109
+ end # Lockdown
110
+
@@ -0,0 +1,54 @@
1
+ module Lockdown
2
+ module Frameworks
3
+ module Rails
4
+ module View
5
+ def self.included(base)
6
+ base.send :alias_method, :link_to_open, :link_to
7
+ base.send :alias_method, :link_to, :link_to_secured
8
+
9
+ base.send :alias_method, :button_to_open, :button_to
10
+ base.send :alias_method, :button_to, :button_to_secured
11
+ end
12
+
13
+ def link_to_secured(name, options = {}, html_options = nil)
14
+ # Don't want to go through the url_for twice
15
+ url = url_for(options)
16
+ if authorized? test_path(url, html_options)
17
+ return link_to_open(name, url, html_options)
18
+ end
19
+ return ""
20
+ end
21
+
22
+ def link_to_or_show(name, options = {}, html_options = nil)
23
+ lnk = link_to(name, options, html_options)
24
+ lnk.length == 0 ? name : lnk
25
+ end
26
+
27
+ def button_to_secured(name, options = {}, html_options = nil)
28
+ url = url_for(options)
29
+ if authorized? test_path(url, html_options)
30
+ return button_to_open(name, url, html_options)
31
+ end
32
+ return ""
33
+ end
34
+
35
+ def links(*lis)
36
+ rvalue = []
37
+ lis.each{|link| rvalue << link if link.length > 0 }
38
+ rvalue.join(" | ")
39
+ end
40
+
41
+ private
42
+
43
+ def test_path(url, html_options)
44
+ if html_options.is_a?(Hash) && html_options[:method] == :delete
45
+ url += "/destroy"
46
+ elsif url.split("/").last =~ /\A\d+\z/
47
+ url += "/show"
48
+ end
49
+ url
50
+ end
51
+ end # View
52
+ end # Rails
53
+ end # Frameworks
54
+ end # Lockdown
@@ -0,0 +1,93 @@
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.send :include, Lockdown::Frameworks::Rails::Controller::Lock
19
+ Lockdown.view_helper.send :include, Lockdown::Frameworks::Rails::View
20
+ Lockdown::System.send :extend, Lockdown::Frameworks::Rails::System
21
+ end
22
+ end # class block
23
+
24
+ module Environment
25
+
26
+ def project_root
27
+ RAILS_ROOT
28
+ end
29
+
30
+ def controller_parent
31
+ ActionController::Base
32
+ end
33
+
34
+ def view_helper
35
+ ActionView::Base
36
+ end
37
+
38
+ def controller_class_name(str)
39
+ str = "#{str}Controller"
40
+ if str.include?("__")
41
+ str.split("__").collect{|p| Lockdown.camelize(p)}.join("::")
42
+ else
43
+ Lockdown.camelize(str)
44
+ end
45
+ end
46
+ end
47
+
48
+ module System
49
+ include Lockdown::Frameworks::Rails::Controller
50
+
51
+ def load_controller_classes
52
+ @controller_classes = {}
53
+
54
+ maybe_load_framework_controller_parent
55
+
56
+ Dir.chdir("#{Lockdown.project_root}/app/controllers") do
57
+ Dir["**/*.rb"].sort.each do |c|
58
+ next if c == "application.rb"
59
+ lockdown_load(c)
60
+ end
61
+ end
62
+
63
+ if ENV['RAILS_ENV'] != 'production'
64
+ if ActiveSupport.const_defined?("Dependencies")
65
+ ActiveSupport::Dependencies.clear
66
+ else
67
+ Dependencies.clear
68
+ end
69
+ end
70
+ end
71
+
72
+ def maybe_load_framework_controller_parent
73
+ if ActiveSupport.const_defined?("Dependencies")
74
+ ActiveSupport::Dependencies.require_or_load("application.rb")
75
+ else
76
+ Dependencies.require_or_load("application.rb")
77
+ end
78
+ end
79
+
80
+ def lockdown_load(file)
81
+ klass = Lockdown.class_name_from_file(file)
82
+ if ActiveSupport.const_defined?("Dependencies")
83
+ ActiveSupport::Dependencies.require_or_load(file)
84
+ else
85
+ Dependencies.require_or_load(file)
86
+ end
87
+ @controller_classes[klass] = Lockdown.qualified_const_get(klass)
88
+ end
89
+
90
+ end # System
91
+ end # Rails
92
+ end # Frameworks
93
+ end # Lockdown
@@ -1,11 +1,11 @@
1
1
  module Lockdown
2
2
  module Helper
3
- #
4
- # If str_sym is a Symbol (:users), give me back "Users"
5
- # If str_sym is a String ("Users"), give me back :users
6
- #
7
- # Was :to_title_sym for String and :to_title_str for Symbol
8
- #
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
9
  def convert_reference_name(str_sym)
10
10
  if str_sym.is_a?(Symbol)
11
11
  titleize(str_sym)
@@ -14,7 +14,7 @@ module Lockdown
14
14
  end
15
15
  end
16
16
 
17
- def lockdown_string(value)
17
+ def get_string(value)
18
18
  if value.respond_to?(:name)
19
19
  string_name(value.name)
20
20
  else
@@ -22,7 +22,7 @@ module Lockdown
22
22
  end
23
23
  end
24
24
 
25
- def lockdown_symbol(value)
25
+ def get_symbol(value)
26
26
  if value.respond_to?(:name)
27
27
  symbol_name(value.name)
28
28
  elsif value.is_a?(String)
@@ -42,12 +42,30 @@ module Lockdown
42
42
  end
43
43
 
44
44
  def administrator_group_string
45
- string_name(:administrators)
45
+ string_name(administrator_group_symbol)
46
46
  end
47
47
 
48
48
  def administrator_group_symbol
49
49
  :administrators
50
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
51
69
 
52
70
  private
53
71
 
@@ -73,16 +91,5 @@ module Lockdown
73
91
  gsub(/([a-z\d])([A-Z])/,'\1_\2').
74
92
  tr("-", "_").downcase
75
93
  end
76
-
77
- if Lockdown.rails_app?
78
- def controller_class_name(str)
79
- "#{str}Controller"
80
- end
81
- else
82
- def controller_class_name(str)
83
- str
84
- end
85
- end
86
94
  end
87
-
88
95
  end
@@ -0,0 +1,66 @@
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.send :include, Lockdown::Orms::ActiveRecord::Stamps
16
+ end
17
+ end # class block
18
+
19
+ module Helper
20
+ def orm_parent
21
+ ::ActiveRecord::Base
22
+ end
23
+
24
+ def database_execute(query)
25
+ orm_parent.connection.execute(query)
26
+ end
27
+
28
+ def database_query(query)
29
+ orm_parent.connection.execute(query)
30
+ end
31
+
32
+ def database_table_exists?(klass)
33
+ klass.table_exists?
34
+ end
35
+ end
36
+
37
+ module Stamps
38
+ def self.included(base)
39
+ base.class_eval do
40
+ alias_method :create_without_stamps, :create
41
+ alias_method :create, :create_with_stamps
42
+ alias_method :update_without_stamps, :update
43
+ alias_method :update, :update_with_stamps
44
+ end
45
+ end
46
+
47
+ def current_profile_id
48
+ Thread.current[:profile_id]
49
+ end
50
+
51
+ def create_with_stamps
52
+ profile_id = current_profile_id || Profile::SYSTEM
53
+ self[:created_by] = profile_id if self.respond_to?(:created_by)
54
+ self[:updated_by] = profile_id if self.respond_to?(:updated_by)
55
+ create_without_stamps
56
+ end
57
+
58
+ def update_with_stamps
59
+ profile_id = current_profile_id || Profile::SYSTEM
60
+ self[:updated_by] = profile_id if self.respond_to?(:updated_by)
61
+ update_without_stamps
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end