lockdown 0.5.22 → 0.6.0

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.
@@ -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