ixtlan-guard 0.1.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,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate guard Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,22 @@
1
+ module Ixtlan
2
+ class ControllerGenerator < Rails::Generators::NamedBase
3
+
4
+ source_root File.expand_path('../../templates', __FILE__)
5
+
6
+ argument :actions, :type => :array, :default => [], :banner => "action action"
7
+
8
+ check_class_collision :suffix => "Guard"
9
+
10
+ def create_guard_file
11
+ template 'guard.rb', File.join('app', 'guards', class_path, "#{file_name}_guard.rb")
12
+ end
13
+
14
+ def guard_class_name
15
+ class_name
16
+ end
17
+
18
+ def aliases
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate guard Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,28 @@
1
+ require 'rails/generators/resource_helpers'
2
+ module Ixtlan
3
+ class ScaffoldGenerator < Rails::Generators::NamedBase
4
+ include Rails::Generators::ResourceHelpers
5
+
6
+ source_root File.expand_path('../../templates', __FILE__)
7
+
8
+ # check_class_collision :suffix => "Guard"
9
+
10
+ def create_guard_files
11
+ puts "ASD"
12
+ template 'guard.rb', File.join('app', 'guards', class_path, "#{plural_file_name}_guard.rb")
13
+ end
14
+
15
+ def guard_class_name
16
+ controller_class_name
17
+ end
18
+
19
+ def aliases
20
+ { :new => :create, :edit => :update }
21
+ end
22
+
23
+ def actions
24
+ ['index', 'show', 'create', 'update', 'destroy']
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,10 @@
1
+ <h1>Editing <%= singular_table_name %></h1>
2
+
3
+ <%%= render 'form' %>
4
+
5
+ <%% if allowed?(:<%= table_name %>, :show) %>
6
+ <%%= link_to 'Show', @<%= singular_table_name %> %> |
7
+ <%% end %>
8
+ <%% if allowed?(:<%= table_name %>, :index) %>
9
+ <%%= link_to 'Back', <%= index_helper %>_path %>
10
+ <%% end %>
@@ -0,0 +1,13 @@
1
+ class <%= guard_class_name %>Guard
2
+ def initialize(guard)
3
+ #guard.name = "<%= plural_file_name %>"
4
+ <% if aliases -%>
5
+ guard.aliases = <%= aliases.inspect %>
6
+ <% end -%>
7
+ guard.action_map= {
8
+ <% for action in actions -%>
9
+ :<%= action %> => [],
10
+ <% end -%>
11
+ }
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ <h1>Listing <%= plural_table_name %></h1>
2
+
3
+ <table>
4
+ <tr>
5
+ <% for attribute in attributes -%>
6
+ <th><%= attribute.human_name %></th>
7
+ <% end -%>
8
+ <th></th>
9
+ <th></th>
10
+ <th></th>
11
+ </tr>
12
+
13
+ <%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %>
14
+ <tr>
15
+ <% for attribute in attributes -%>
16
+ <td><%%= <%= singular_table_name %>.<%= attribute.name %> %></td>
17
+ <% end -%>
18
+ <%% if allowed?(:<%= table_name %>, :show) %>
19
+ <td><%%= link_to 'Show', <%= singular_table_name %> %></td>
20
+ <%% end %>
21
+ <%% if allowed?(:<%= table_name %>, :update) %>
22
+ <td><%%= link_to 'Edit', edit_<%= singular_table_name %>_path(<%= singular_table_name %>) %></td>
23
+ <%% end %>
24
+ <%% if allowed?(:<%= table_name %>, :destroy) %>
25
+ <td><%%= link_to 'Destroy', <%= singular_table_name %>, :confirm => 'Are you sure?', :method => :delete %></td>
26
+ <%% end %>
27
+ </tr>
28
+ <%% end %>
29
+ </table>
30
+
31
+ <br />
32
+
33
+ <%% if allowed?(:<%= table_name %>, :create) %>
34
+ <%%= link_to 'New <%= human_name %>', new_<%= singular_table_name %>_path %>
35
+ <%% end %>
@@ -0,0 +1,7 @@
1
+ <h1>New <%= singular_table_name %></h1>
2
+
3
+ <%%= render 'form' %>
4
+
5
+ <%% if allowed?(:<%= table_name %>, :index) %>
6
+ <%%= link_to 'Back', <%= index_helper %>_path %>
7
+ <%% end %>
@@ -0,0 +1,16 @@
1
+ <p id="notice"><%%= notice %></p>
2
+
3
+ <% for attribute in attributes -%>
4
+ <p>
5
+ <b><%= attribute.human_name %>:</b>
6
+ <%%= @<%= singular_table_name %>.<%= attribute.name %> %>
7
+ </p>
8
+
9
+ <% end -%>
10
+
11
+ <%% if allowed?(:<%= table_name %>, :update) %>
12
+ <%%= link_to 'Edit', edit_<%= singular_table_name %>_path(@<%= singular_table_name %>) %> |
13
+ <%% end %>
14
+ <%% if allowed?(:<%= table_name %>, :index) %>
15
+ <%%= link_to 'Back', <%= index_helper %>_path %>
16
+ <%% end %>
@@ -0,0 +1,23 @@
1
+ # use this extended copy of Rails::Generators::ScaffoldGenerator
2
+ # since the search path is the following:
3
+ # ["scaffold:scaffold", "rails:scaffold", "scaffold"]
4
+ # which allows to override orignal generator
5
+ # adding a Rails::Generators::ScaffoldGenerator.hook_for did not work
6
+ # since it looses the ORM config somehow
7
+ require 'rails/generators/rails/resource/resource_generator'
8
+ module Rails
9
+ module Generators
10
+ class ScaffoldGenerator < ResourceGenerator #metagenerator
11
+
12
+ remove_hook_for :resource_controller
13
+ remove_class_option :actions
14
+
15
+ hook_for :scaffold_controller, :required => true, :in => :rails
16
+ hook_for :stylesheets, :in => :rails
17
+
18
+ hook_for :ixtlan, :type => :boolean, :default => true do |controller|
19
+ invoke controller, [class_name]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ require 'ixtlan/guard'
2
+ if defined?(Rails)
3
+ require 'ixtlan/guard_railtie'
4
+ require 'ixtlan/rails_integration'
5
+ end
@@ -0,0 +1,159 @@
1
+ require 'logger'
2
+ module Ixtlan
3
+ class ControllerGuard
4
+
5
+ attr_accessor :name, :action_map, :aliases
6
+
7
+ def initialize(name)
8
+ @name = name.sub(/_guard$/, '').to_sym
9
+ class_name = name.split(/\//).collect { |part| part.split("_").each { |pp| pp.capitalize! }.join }.join("::")
10
+ Object.const_get(class_name).new(self)
11
+ end
12
+
13
+ def name=(name)
14
+ @name = name.to_sym
15
+ end
16
+
17
+ def aliases=(map)
18
+ @aliases = symbolize(map)
19
+ end
20
+
21
+ def action_map=(map)
22
+ @action_map = symbolize(map)
23
+ end
24
+
25
+ private
26
+
27
+ def symbolize(h)
28
+ result = {}
29
+
30
+ h.each do |k, v|
31
+ if v.is_a?(Hash)
32
+ result[k.to_sym] = symbolize_keys(v) unless v.size == 0
33
+ elsif v.is_a?(Array)
34
+ val = []
35
+ v.each {|vv| val << vv.to_sym }
36
+ result[k.to_sym] = val
37
+ else
38
+ result[k.to_sym] = v.to_sym
39
+ end
40
+ end
41
+
42
+ result
43
+ end
44
+
45
+ end
46
+
47
+ class Guard
48
+
49
+ attr_accessor :logger, :guard_dir, :superuser, :block
50
+
51
+ def initialize(logger = Logger.new(STDOUT), superuser = :root, guard_dir = File.join("app", "guards"), &block)
52
+ @map = {}
53
+ @aliases = {}
54
+
55
+ @block =
56
+ if block
57
+ block
58
+ else
59
+ Proc.new do |controller|
60
+ # get the groups of the current_user
61
+ user = controller.send(:current_user) if controller.respond_to? :current_user
62
+ user.groups if user
63
+ end
64
+ end
65
+ @logger = logger
66
+ @superuser = superuser
67
+ @guard_dir = guard_dir
68
+ end
69
+
70
+ def setup
71
+ if File.exists?(@guard_dir)
72
+ Dir.new(guard_dir).to_a.each do |f|
73
+ if f.match(".rb$")
74
+ require(File.join(guard_dir, f))
75
+ controller_guard = ControllerGuard.new(f.sub(/.rb$/, ''))
76
+ register(controller_guard)
77
+ end
78
+ end
79
+ logger.debug("initialized guard . . .")
80
+ else
81
+ raise GuardException.new("guard directory #{guard_dir} not found, skip loading")
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def register(controller_guard)
88
+ msg = controller_guard.action_map.collect{ |k,v| "\n\t#{k} => [#{v.join(',')}]"}
89
+ @logger.debug("#{controller_guard.name} guard: #{msg}")
90
+ @map[controller_guard.name] = controller_guard.action_map
91
+ @aliases[controller_guard.name] = controller_guard.aliases || {}
92
+ end
93
+
94
+ public
95
+
96
+ def block_groups(groups)
97
+ @blocked = (groups || []).collect { |g| g.to_sym}
98
+ end
99
+
100
+ def blocked
101
+ @blocked ||= []
102
+ end
103
+
104
+ def current_user_restricted?(controller)
105
+ groups = @block.call(controller)
106
+ if groups
107
+ p groups
108
+ p blocked
109
+ p groups.select { |g| !blocked.member?(g.to_sym) }
110
+ groups.select { |g| !blocked.member?(g.to_sym) }.size < groups.size
111
+ else
112
+ nil
113
+ end
114
+ end
115
+
116
+ def check(controller, resource, action, &block)
117
+ groups = @block.call(controller)
118
+ if groups.nil?
119
+ @logger.debug("check #{resource}##{action}: not authenticated")
120
+ return true
121
+ end
122
+ resource = resource.to_sym
123
+ action = action.to_sym
124
+ if (@map.key? resource)
125
+ action = @aliases[resource][action] || action
126
+ allowed = @map[resource][action]
127
+ if (allowed.nil?)
128
+ @logger.warn("unknown action '#{action}' for controller '#{resource}'")
129
+ raise ::Ixtlan::GuardException.new("unknown action '#{action}' for controller '#{resource}'")
130
+ else
131
+ allowed << @superuser unless allowed.member? @superuser
132
+ allow_all_groups = allowed.member?(:*)
133
+ if(allow_all_groups && block.nil?)
134
+ @logger.debug("check #{resource}##{action}: allowed for all")
135
+ return true
136
+ else
137
+ groups.each do |group|
138
+ if (allow_all_groups || allowed.member?(group.to_sym)) && !blocked.member?(group.to_sym)
139
+ if(block.nil? || block.call(group))
140
+ @logger.debug("check #{resource}##{action}: true")
141
+ return true
142
+ end
143
+ end
144
+ end
145
+ end
146
+ @logger.debug("check #{resource}##{action}: false")
147
+ return false
148
+ end
149
+ else
150
+ @logger.warn("unknown controller for '#{resource}'")
151
+ raise ::Ixtlan::GuardException.new("unknown controller for '#{resource}'")
152
+ end
153
+ end
154
+ end
155
+
156
+ class GuardException < Exception; end
157
+ class PermissionDenied < GuardException; end
158
+ end
159
+
@@ -0,0 +1,43 @@
1
+ require 'rails'
2
+ require 'ixtlan/guard'
3
+ require 'logger'
4
+
5
+ class GuardRailtie < Rails::Railtie
6
+
7
+ config.before_configuration do |app|
8
+ app.config.class.class_eval do
9
+ attr_accessor :guard
10
+ end
11
+ app.config.guard =
12
+ Ixtlan::Guard.new(Logger.new(STDERR),
13
+ :root,
14
+ File.join(Rails.root, "app", "guards"))
15
+ end
16
+
17
+ config.after_initialize do |app|
18
+ logger = app.config.logger || Rails.logger || Logger.new(STDERR)
19
+ app.config.guard.logger = logger
20
+ begin
21
+ app.config.guard.setup
22
+ rescue Ixtlan::GuardException => e
23
+ logger.warn e.message
24
+ end
25
+ end
26
+
27
+ config.generators do
28
+ require 'rails/generators'
29
+ require 'rails/generators/rails/controller/controller_generator'
30
+ require 'rails/generators/erb/scaffold/scaffold_generator'
31
+ Rails::Generators::ControllerGenerator.hook_for :ixtlan, :type => :boolean, :default => true do |controller|
32
+ invoke controller, [ class_name, actions ]
33
+ end
34
+ Erb::Generators::ScaffoldGenerator.source_paths.insert(0, File.expand_path('../../generators/ixtlan/templates', __FILE__))
35
+ #require 'rails/generators/rails/scaffold/scaffold_generator'
36
+ # somehow the check is before the value is set,
37
+ # so just ignore the require flag
38
+ #Rails::Generators::ScaffoldGenerator.class_options[:orm].instance_variable_set(:@required, false)
39
+ #Rails::Generators::ScaffoldGenerator.hook_for :ixtlan, :as => :scaffold, :type => :boolean, :default => true do |controller|
40
+ # invoke controller, [class_name]
41
+ #end
42
+ end
43
+ end
@@ -0,0 +1,55 @@
1
+ require 'ixtlan/guard'
2
+ module Ixtlan
3
+ module ActionController #:nodoc:
4
+ module Guard #:nodoc:
5
+ def self.included(base)
6
+ base.send(:include, InstanceMethods)
7
+ end
8
+ module InstanceMethods #:nodoc:
9
+
10
+ protected
11
+
12
+ def guard
13
+ Rails.configuration.guard
14
+ end
15
+
16
+ def authorization(&block)
17
+ resource_authorization(params[:controller], params[:action], &block)
18
+ end
19
+
20
+ def resource_authorization(resource, action, &block)
21
+ unless guard.check(self, resource, action, &block)
22
+ raise ::Ixtlan::PermissionDenied.new("permission denied for '#{resource}##{action}'")
23
+ end
24
+ true
25
+ end
26
+
27
+ def allowed?(action, &block)
28
+ guard.check(self, params[:controller], action, &block)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ module Allowed #:nodoc:
35
+ # Inclusion hook to make #allowed available as method
36
+ def self.included(base)
37
+ base.send(:include, InstanceMethods)
38
+ end
39
+
40
+ module InstanceMethods #:nodoc:
41
+ def allowed?(resource, action, &block)
42
+ controller.send(:guard).check(controller, resource, action, &block)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ ActionController::Base.send(:include, Ixtlan::ActionController::Guard)
49
+ ActionController::Base.send(:before_filter, :authorization)
50
+ ActionView::Base.send(:include, Ixtlan::Allowed)
51
+ module Erector
52
+ class Widget
53
+ include Ixtlan::Allowed
54
+ end
55
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+ require 'ixtlan/guard'
3
+
4
+ describe Ixtlan::Guard do
5
+
6
+ before :all do
7
+ @guard = Ixtlan::Guard.new(Logger.new(STDOUT),
8
+ :root,
9
+ File.join(File.dirname(__FILE__), "guards") )
10
+
11
+ @guard.setup
12
+ @current_user = Object.new
13
+ def @current_user.groups(g = nil)
14
+ @g = g if g
15
+ @g || []
16
+ end
17
+
18
+ @controller = Object.new
19
+ def @controller.current_user(u = nil)
20
+ @u = u if u
21
+ @u
22
+ end
23
+ @controller.current_user( @current_user )
24
+ end
25
+
26
+ it 'should fail with missing guard dir' do
27
+ lambda {Ixtlan::Guard.new(Logger.new(STDOUT),
28
+ :root,
29
+ "does_not_exists").setup }.should raise_error(Ixtlan::GuardException)
30
+ end
31
+
32
+ it 'should initialize' do
33
+ @guard.should_not be_nil
34
+ end
35
+
36
+ it 'should pass check without user' do
37
+ controller = Object.new
38
+ def controller.current_user
39
+ end
40
+ @guard.check(controller, :none, :something).should be_true
41
+ end
42
+
43
+ it 'should pass check with user being root' do
44
+ @current_user.groups([:root])
45
+ @guard.check(@controller, :users, :show).should be_true
46
+ end
47
+
48
+ it 'should not pass check with user - no groups' do
49
+ @current_user.groups([])
50
+ @guard.check(@controller, :users, :show).should be_false
51
+ end
52
+
53
+ it 'should pass unguarded check with user - no groups' do
54
+ @current_user.groups([])
55
+ @guard.check(@controller, :users, :index).should be_true
56
+ end
57
+
58
+ it 'should pass check with user on aliased action' do
59
+ @current_user.groups([:users])
60
+ @guard.check(@controller, :users, :edit).should be_true
61
+ end
62
+
63
+ it 'should pass check with user' do
64
+ @current_user.groups([:users])
65
+ @guard.check(@controller, :users, :update).should be_true
66
+ end
67
+
68
+ it 'should not pass check with user' do
69
+ @current_user.groups([:accounts])
70
+ @guard.check(@controller, :users, :update).should be_false
71
+ end
72
+
73
+ it 'should pass check with user with passing extra check' do
74
+ @current_user.groups([:users])
75
+ @guard.check(@controller, :users, :update) do |g|
76
+ true
77
+ end.should be_true
78
+ end
79
+
80
+ it 'should not pass check with user with failing extra check' do
81
+ @current_user.groups([:users])
82
+ @guard.check(@controller, :users, :update) do |g|
83
+ false
84
+ end.should be_false
85
+ end
86
+
87
+ it 'should raise exception on unknown action' do
88
+ lambda {@guard.check(@controller, :users, :unknown_action) }.should raise_error(Ixtlan::GuardException)
89
+ end
90
+
91
+ it 'should raise exception on unknown resource' do
92
+ lambda {@guard.check(@controller, :unknown_resource, :update) }.should raise_error(Ixtlan::GuardException)
93
+ end
94
+ end
@@ -0,0 +1,13 @@
1
+ class UsersGuard
2
+ def initialize(guard)
3
+ guard.name = "users"
4
+ guard.aliases= {:edit => :update}
5
+ guard.action_map= {
6
+ :index => [:*],
7
+ :show => [:users],
8
+ :create => [:users],
9
+ :update => [:users],
10
+ :destroy => [:users]
11
+ }
12
+ end
13
+ end
@@ -0,0 +1,2 @@
1
+ require 'spec_helper'
2
+ require 'ixtlan/guard_railtie'
@@ -0,0 +1,2 @@
1
+ lib_path = (Pathname(__FILE__).dirname.parent.expand_path + 'lib').to_s
2
+ $LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
metadata ADDED
@@ -0,0 +1,137 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ixtlan-guard
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - mkristian
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-10-17 00:00:00 +05:30
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rails
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 3
29
+ - 0
30
+ - 0
31
+ version: 3.0.0
32
+ type: :development
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 1
43
+ - 3
44
+ - 1
45
+ version: 1.3.1
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: cucumber
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ - 9
58
+ - 2
59
+ version: 0.9.2
60
+ type: :development
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "="
68
+ - !ruby/object:Gem::Version
69
+ segments:
70
+ - 0
71
+ - 8
72
+ - 7
73
+ version: 0.8.7
74
+ type: :development
75
+ version_requirements: *id004
76
+ description: simple authorization framework for rails controllers
77
+ email:
78
+ - m.kristian@web.de
79
+ executables: []
80
+
81
+ extensions: []
82
+
83
+ extra_rdoc_files: []
84
+
85
+ files:
86
+ - lib/ixtlan-guard.rb
87
+ - lib/generators/scaffold/scaffold/scaffold_generator.rb
88
+ - lib/generators/ixtlan/controller/USAGE
89
+ - lib/generators/ixtlan/controller/controller_generator.rb
90
+ - lib/generators/ixtlan/scaffold/USAGE
91
+ - lib/generators/ixtlan/scaffold/scaffold_generator.rb
92
+ - lib/generators/ixtlan/templates/new.html.erb
93
+ - lib/generators/ixtlan/templates/show.html.erb
94
+ - lib/generators/ixtlan/templates/guard.rb
95
+ - lib/generators/ixtlan/templates/edit.html.erb
96
+ - lib/generators/ixtlan/templates/index.html.erb
97
+ - lib/ixtlan/guard_railtie.rb
98
+ - lib/ixtlan/rails_integration.rb
99
+ - lib/ixtlan/guard.rb
100
+ - spec/guard_spec.rb
101
+ - spec/spec_helper.rb
102
+ - spec/railtie_spec.rb
103
+ - spec/guards/users_guard.rb
104
+ has_rdoc: true
105
+ homepage: http://github.com/mkristian/ixtlan-guard
106
+ licenses: []
107
+
108
+ post_install_message:
109
+ rdoc_options:
110
+ - --main
111
+ - README.textile
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ segments:
126
+ - 0
127
+ version: "0"
128
+ requirements: []
129
+
130
+ rubyforge_project:
131
+ rubygems_version: 1.3.6
132
+ signing_key:
133
+ specification_version: 3
134
+ summary: guard your controller actions
135
+ test_files:
136
+ - spec/guard_spec.rb
137
+ - spec/railtie_spec.rb