grant 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Near Infinity Corporation
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,73 @@
1
+ = Grant
2
+
3
+ Grant is a Ruby gem and Rails plugin that forces you to make explicit security decisions about the operations performed on your ActiveRecord models. It provides a declarative way to specify rules granting permission to perform CRUD operations on ActiveRecord objects.
4
+
5
+ Grant does not allow you to specify which operations are restricted. Instead, it restricts all CRUD operations unless they're explicitly granted to the user. It also restricts adding or removing items to/from has_many and has_and_belongs_to_many associations. Only allowing operations explicitly granted forces you to make conscious security decisions. Grant will not help you make those decisions, but it won't let you forget to.
6
+
7
+ Additional information beyond that found in this README is available on the wiki[https://github.com/nearinfinity/grant/wiki].
8
+
9
+ = Installation
10
+
11
+ To install the Grant gem, simply run
12
+
13
+ gem install grant
14
+
15
+ To use it with a Rails 3 project or other project using Bundler, add the following line to your Gemfile
16
+
17
+ gem 'grant'
18
+
19
+ For your Rails 2.x project, add the following to your environment.rb file
20
+
21
+ config.gem 'grant'
22
+
23
+ Lastly, Grant can also be installed as a Rails plugin
24
+
25
+ script/plugin install git://github.com/nearinfinity/grant.git
26
+
27
+ = Setup
28
+
29
+ Grant needs to know who the current user is, but with no standard for doing so you'll have to do a little work to set things up. You simply need to set your current user model object as the Grant current user before any CRUD operations are performed. For example, in a Rails application you could add the following to your application_controller.rb
30
+
31
+ class ApplicationController < ActionController::Base
32
+ before_filter :set_current_user
33
+
34
+ private
35
+
36
+ def set_current_user
37
+ Grant::User.current_user = @current_user
38
+ end
39
+ end
40
+
41
+ = Usage
42
+
43
+ To enable model security you simply include the Grant::ModelSecurity module in your model class. In the example below you see three grant statements. The first grants find (aka read) permission all the time. The second example grants create, update, and destroy permission when the passed block evaluates to true, which in this case happens when the model is editable by the current user. Similarly, the third grant statement permits additions and removals from the tags association when it's block evaluates to true. A Grant::Error is raised if any grant block evaluates to false or nil.
44
+
45
+ class Book < ActiveRecord::Base
46
+ include Grant::ModelSecurity
47
+
48
+ has_many :tags
49
+ grant(:find) { true }
50
+ grant(:create, :update, :destroy) { |user, model| model.editable_by_user? user }
51
+ grant(:add => :tags, :remove => :tags) { |user, model, associated_model| model.editable_by_user? user }
52
+
53
+ def editable_by_user? user
54
+ user.administrator? || user.has_role?(:editor)
55
+ end
56
+ end
57
+
58
+ The valid actions to pass to a grant statement are :find, :create, :update, :destroy, :add, and :remove. The first four options are passed as symbols while :add and :remove are hash keys to association names they protect. Any number of options can be passed to a single grant statement, which is very useful if each of the actions share the same logic for determining access.
59
+
60
+ = Integration
61
+
62
+ There may be some instances where you need to perform an action on your model object without Grant stepping in and stopping you. In those cases you can include the Grant::Integration module for help.
63
+
64
+ class BooksController < ApplicationController
65
+ include Grant::Integration
66
+
67
+ def update
68
+ book = Book.find(params[:id])
69
+ without_grant { book.update_attributes(params[:book]) } # Grant is disabled for the entire block
70
+ end
71
+ end
72
+
73
+ Copyright (c) 2010 Near Infinity Corporation, released under the MIT license
@@ -0,0 +1,8 @@
1
+ require 'grant/integration'
2
+ require 'grant/model_security'
3
+ require 'grant/user'
4
+ require 'grant/version'
5
+
6
+ module Grant
7
+ class Error < StandardError; end
8
+ end
@@ -0,0 +1,26 @@
1
+ module Grant
2
+ class ConfigParser
3
+
4
+ def self.extract_config(args)
5
+ hash = (args.pop if args.last.is_a?(::Hash)) || {}
6
+ normalize_config args, hash
7
+ validate_config args, hash
8
+
9
+ [args, hash]
10
+ end
11
+
12
+ private
13
+
14
+ def self.normalize_config(actions, associations)
15
+ actions.each_with_index { |item, index| actions[index] = item.to_sym unless item.kind_of? Symbol }
16
+ associations.each_pair { |k, v| associations[k.to_sym] = associations.delete(k) unless k.kind_of? Symbol }
17
+ end
18
+
19
+ def self.validate_config(actions, associations)
20
+ raise Grant::Error.new("at least one :create, :find, :update, or :destroy action must be specified") if actions.empty? && associations.empty?
21
+ raise Grant::Error.new(":create, :find, :update, and :destroy are the only valid actions") unless actions.all? { |a| [:create, :find, :update, :destroy].include? a }
22
+ raise Grant::Error.new(":add and :remove are the only valid association specifications") unless associations.keys.all? { |k| [:add, :remove].include? k }
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,49 @@
1
+ require 'grant/thread_status'
2
+
3
+ module Grant
4
+ module Integration
5
+
6
+ def without_grant
7
+ previously_disabled = grant_disabled?
8
+ disable_grant
9
+
10
+ begin
11
+ result = yield if block_given?
12
+ ensure
13
+ enable_grant unless previously_disabled
14
+ end
15
+
16
+ result
17
+ end
18
+
19
+ def with_grant
20
+ previously_disabled = grant_disabled?
21
+ enable_grant
22
+
23
+ begin
24
+ result = yield if block_given?
25
+ ensure
26
+ disable_grant if previously_disabled
27
+ end
28
+
29
+ result
30
+ end
31
+
32
+ def disable_grant
33
+ Grant::ThreadStatus.disable
34
+ end
35
+
36
+ def enable_grant
37
+ Grant::ThreadStatus.enable
38
+ end
39
+
40
+ def grant_disabled?
41
+ Grant::ThreadStatus.disabled?
42
+ end
43
+
44
+ def grant_enabled?
45
+ Grant::ThreadStatus.enabled?
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,101 @@
1
+ require 'grant/config_parser'
2
+ require 'grant/user'
3
+ require 'grant/thread_status'
4
+
5
+ module Grant
6
+ module ModelSecurity
7
+
8
+ def self.included(base)
9
+ [:create, :update, :destroy, :find].each do |action|
10
+ callback = (action == :find ? "after_#{action}" : "before_#{action}")
11
+ base.class_eval <<-RUBY
12
+ def grant_#{callback}
13
+ grant_raise_error(grant_current_user, '#{action}', self) unless grant_disabled?
14
+ end
15
+ RUBY
16
+ base.send callback.to_sym, "grant_#{callback}".to_sym
17
+ end
18
+
19
+ base.extend ClassMethods
20
+ end
21
+
22
+ # ActiveRecord won't call the after_find handler unless it see's a specific after_find method defined
23
+ def after_find; end
24
+
25
+ def grant_current_user
26
+ Grant::User.current_user
27
+ end
28
+
29
+ def grant_disabled?
30
+ Grant::ThreadStatus.disabled? || @grant_disabled
31
+ end
32
+
33
+ def grant_raise_error(user, action, model, association_id=nil, associated_model=nil)
34
+ msg = ["#{action} permission",
35
+ "not granted to #{user.class.name}:#{user.id}",
36
+ "for resource #{model.class.name}:#{model.id}"]
37
+ msg.insert(1, "to #{association_id}:#{associated_model.class.name} association") if association_id && associated_model
38
+
39
+ raise Grant::Error.new(msg.join(' '))
40
+ end
41
+
42
+ module ClassMethods
43
+ def grant(*args, &blk)
44
+ actions, associations = Grant::ConfigParser.extract_config(args)
45
+
46
+ associations.each_pair do |action, association_ids|
47
+ Array(association_ids).each do |association_id|
48
+ grant_callback = "grant_#{action}_#{association_id}".to_sym
49
+ define_method(grant_callback) do |associated_model|
50
+ grant_raise_error(grant_current_user, action, self, association_id, associated_model) unless grant_disabled? || blk.call(grant_current_user, self, associated_model)
51
+ end
52
+ end
53
+ end
54
+
55
+ actions.each do |action|
56
+ grant_callback = (action.to_sym == :find ? "grant_after_find" : "grant_before_#{action}").to_sym
57
+ define_method(grant_callback) do
58
+ grant_raise_error(grant_current_user, action, self) unless grant_disabled? || blk.call(grant_current_user, self)
59
+ end
60
+ end
61
+ end
62
+
63
+ def has_and_belongs_to_many(association_id, options={}, &extension)
64
+ add_grant_association_callback(:add, association_id, options)
65
+ add_grant_association_callback(:remove, association_id, options)
66
+ super
67
+ end
68
+
69
+ def has_many(association_id, options={}, &extension)
70
+ add_grant_association_callback(:add, association_id, options)
71
+ add_grant_association_callback(:remove, association_id, options)
72
+ super
73
+ end
74
+
75
+ private
76
+
77
+ def add_grant_association_callback(action, association_id, options)
78
+ callback_name = "before_#{action}".to_sym
79
+ callback = "grant_#{action}_#{association_id}".to_sym
80
+ unless self.instance_methods.include? callback.to_s
81
+ class_eval <<-RUBY
82
+ def #{callback}(associated_model)
83
+ grant_raise_error(grant_current_user, '#{action}', self, '#{association_id}', associated_model) unless grant_disabled?
84
+ end
85
+ RUBY
86
+ end
87
+
88
+ if options.has_key? callback_name
89
+ if options[callback_name].kind_of? Array
90
+ options[callback_name].insert(0, callback)
91
+ else
92
+ options[callback_name] = [callback, options[callback_name]]
93
+ end
94
+ else
95
+ options[callback_name] = callback
96
+ end
97
+ end
98
+
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,22 @@
1
+ require 'grant/integration'
2
+
3
+ module Grant
4
+ module SpecHelpers
5
+ include Grant::Integration
6
+
7
+ def self.included(base)
8
+ base.class_eval do
9
+ before(:each) do
10
+ disable_grant
11
+ end
12
+
13
+ after(:each) do
14
+ enable_grant
15
+ end
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+
22
+
@@ -0,0 +1,18 @@
1
+ module Grant
2
+ class ThreadLocal
3
+
4
+ def initialize(initial_value)
5
+ @thread_symbol = "#{rand}#{Time.now.to_f}"
6
+ set initial_value
7
+ end
8
+
9
+ def set(value)
10
+ Thread.current[@thread_symbol] = value
11
+ end
12
+
13
+ def get
14
+ Thread.current[@thread_symbol]
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ require 'grant/thread_local'
2
+
3
+ module Grant
4
+ module ThreadStatus
5
+
6
+ def self.enabled?
7
+ status
8
+ end
9
+
10
+ def self.disabled?
11
+ !status
12
+ end
13
+
14
+ def self.enable
15
+ set_status true
16
+ end
17
+
18
+ def self.disable
19
+ set_status false
20
+ end
21
+
22
+ private
23
+ def self.status
24
+ @status = Grant::ThreadLocal.new(true) if @status.nil?
25
+ @status.get
26
+ end
27
+
28
+ def self.set_status(status)
29
+ @status = Grant::ThreadLocal.new(true) if @status.nil?
30
+ @status.set status
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,16 @@
1
+ module Grant
2
+ module User
3
+ def current_user
4
+ Thread.current[@@current_user_symbol]
5
+ end
6
+
7
+ def current_user=(user)
8
+ Thread.current[@@current_user_symbol] = user
9
+ end
10
+
11
+ module_function :current_user, :current_user=
12
+
13
+ private
14
+ @@current_user_symbol = :grant_current_user_symbol
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module Grant
2
+ VERSION = "1.0.1"
3
+ end
@@ -0,0 +1,61 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'grant'
3
+
4
+ describe Grant::ConfigParser do
5
+
6
+ describe 'Configuration' do
7
+ it "should parse actions and associations from a config array" do
8
+ config = Grant::ConfigParser.extract_config([:create, 'update', {:add => [:people, :places], 'remove' => :people}])
9
+ config.should_not be_nil
10
+ config.should have(2).items
11
+ config[0].should =~ [:create, :update]
12
+ config[1].should == {:add => [:people, :places], :remove => :people}
13
+ end
14
+
15
+ it "should parse actions from a config array when associations are absent" do
16
+ config = Grant::ConfigParser.extract_config([:create, :update])
17
+ config.should_not be_nil
18
+ config.should have(2).items
19
+ config[0].should =~ [:create, :update]
20
+ config[1].should == {}
21
+ end
22
+
23
+ it "should parse actions and associations from a config array when options are absent" do
24
+ config = Grant::ConfigParser.extract_config([:create, 'update', {:add => ['people', :places]}])
25
+ config.should_not be_nil
26
+ config.should have(2).items
27
+ config[0].should =~ [:create, :update]
28
+ config[1].should == {:add => ['people', :places]}
29
+ end
30
+
31
+ it "should parse actions" do
32
+ config = Grant::ConfigParser.extract_config([:create])
33
+ config.should_not be_nil
34
+ config.should have(2).items
35
+ config[0].should =~ [:create]
36
+ config[1].should == {}
37
+ end
38
+
39
+ end
40
+
41
+ describe 'Configuration Validation' do
42
+ it "should raise a Grant::Error if no action or association is specified" do
43
+ lambda {
44
+ Grant::ConfigParser.instance_eval { validate_config([], {}) }
45
+ }.should raise_error(Grant::Error)
46
+ end
47
+
48
+ it "should raise a Grant::Error if an invalid action is specified" do
49
+ lambda {
50
+ Grant::ConfigParser.instance_eval { validate_config([:create, :udate], {:add => [:people, :places]}) }
51
+ }.should raise_error(Grant::Error)
52
+ end
53
+
54
+ it "should raise a Grant::Error if an invalid association is specified" do
55
+ lambda {
56
+ Grant::ConfigParser.instance_eval { validate_config([:destroy], {:add => :people, :update => :places}) }
57
+ }.should raise_error(Grant::Error)
58
+ end
59
+ end
60
+
61
+ end
@@ -0,0 +1,66 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'grant'
3
+
4
+ describe Grant::Integration do
5
+ include Grant::Integration
6
+
7
+ it "should have the ability to disable Grant" do
8
+ disable_grant
9
+ grant_disabled?.should be_true
10
+ Grant::ThreadStatus.should be_disabled
11
+ end
12
+
13
+ it "should have the ability to enable Grant" do
14
+ disable_grant
15
+ enable_grant
16
+ grant_enabled?.should be_true
17
+ Grant::ThreadStatus.should be_enabled
18
+ end
19
+
20
+ it "should have the ability to check if grant is enabled" do
21
+ enable_grant
22
+ grant_enabled?.should be_true
23
+ end
24
+
25
+ it "should have the ability to check if grant is disabled" do
26
+ disable_grant
27
+ grant_disabled?.should be_true
28
+ end
29
+
30
+ it "should be able to execute a block of code with grant temporarily disabled but switched back to enabled afterwards" do
31
+ enable_grant
32
+ without_grant do
33
+ grant_disabled?.should be_true
34
+ Grant::ThreadStatus.should be_disabled
35
+ end
36
+ grant_enabled?.should be_true
37
+ end
38
+
39
+ it "should be able to execute a block of code with grant disabled and remain disabled afterwards if it was beforehand" do
40
+ disable_grant
41
+ without_grant do
42
+ grant_disabled?.should be_true
43
+ Grant::ThreadStatus.should be_disabled
44
+ end
45
+ grant_disabled?.should be_true
46
+ end
47
+
48
+ it "should be able to execute a block of code with grant temporarily enabled but switched back to disabled afterwards" do
49
+ disable_grant
50
+ with_grant do
51
+ grant_enabled?.should be_true
52
+ Grant::ThreadStatus.should be_enabled
53
+ end
54
+ grant_disabled?.should be_true
55
+ end
56
+
57
+ it "should be able to execute a block of code with grant enabled and remain enabled afterwards if it was beforehand" do
58
+ enable_grant
59
+ with_grant do
60
+ grant_enabled?.should be_true
61
+ Grant::ThreadStatus.should be_enabled
62
+ end
63
+ grant_enabled?.should be_true
64
+ end
65
+
66
+ end
@@ -0,0 +1,162 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'grant'
3
+
4
+ describe Grant::ModelSecurity do
5
+
6
+ before(:each) do
7
+ Grant::User.current_user = (Class.new do
8
+ def id; 1 end
9
+ end).new
10
+ end
11
+
12
+ describe 'module include' do
13
+ it 'should establish failing ActiveRecord callbacks for before_create, before_update, before_destroy, and after_find when included' do
14
+ verify_standard_callbacks(new_model_class.new)
15
+ end
16
+
17
+ it 'should establish failing ActiveRecord callbacks for any has_many or has_and_belongs_to_many associations' do
18
+ c = new_model_class
19
+ c.instance_eval do
20
+ has_many :users
21
+ has_and_belongs_to_many :groups
22
+ end
23
+ verify_association_callbacks(c.new)
24
+ end
25
+ end
26
+
27
+ describe '#grant' do
28
+ it 'should allow after_find callback to succeed when granted' do
29
+ c = new_model_class.instance_eval { grant(:find) { true }; self }
30
+ verify_standard_callbacks(c.new, :find)
31
+ end
32
+
33
+ it 'should allow before_create callback to succeed when granted' do
34
+ c = new_model_class.instance_eval { grant(:create) { true }; self }
35
+ verify_standard_callbacks(c.new, :create)
36
+ end
37
+
38
+ it 'should allow before_update callback to succeed when granted' do
39
+ c = new_model_class.instance_eval { grant(:update) { true }; self }
40
+ verify_standard_callbacks(c.new, :update)
41
+ end
42
+
43
+ it 'should allow before_destroy callback to succeed when granted' do
44
+ c = new_model_class.instance_eval { grant(:destroy) { true }; self }
45
+ verify_standard_callbacks(c.new, :destroy)
46
+ end
47
+
48
+ it 'should allow multiple callbacks to be specified with one grant statment' do
49
+ c = new_model_class.instance_eval { grant(:create, :update) { true }; self }
50
+ verify_standard_callbacks(c.new, :create, :update)
51
+
52
+ c = new_model_class.instance_eval { grant(:create, :update, :destroy) { true }; self }
53
+ verify_standard_callbacks(c.new, :create, :update, :destroy)
54
+
55
+ c = new_model_class.instance_eval { grant(:create, :update, :destroy, :find) { true }; self }
56
+ verify_standard_callbacks(c.new, :create, :update, :destroy, :find)
57
+ end
58
+
59
+ it 'should allow adding to an association to succeed when granted' do
60
+ c = new_model_class
61
+ c.instance_eval do
62
+ has_many :users
63
+ has_and_belongs_to_many :groups
64
+ grant(:add => [:users, :groups]) { true }
65
+ end
66
+ verify_association_callbacks(c.new, :add_users, :add_groups)
67
+ end
68
+
69
+ it 'should allow adding to an association to succeed when granted above association declarations' do
70
+ c = new_model_class
71
+ c.instance_eval do
72
+ grant(:add => [:users, :groups]) { true }
73
+ has_many :users
74
+ has_and_belongs_to_many :groups, :before_add => [:bogus1, :bogus2]
75
+ define_method(:bogus1) {}
76
+ define_method(:bogus2) {}
77
+ end
78
+ verify_association_callbacks(c.new, :add_users, :add_groups)
79
+ end
80
+
81
+ it 'should allow removing from an association to succeed when granted' do
82
+ c = new_model_class
83
+ c.instance_eval do
84
+ has_many :users
85
+ has_and_belongs_to_many :groups, :before_remove => :bogus1
86
+ grant(:remove => [:users, :groups]) { true }
87
+ define_method(:bogus1) {}
88
+ end
89
+ verify_association_callbacks(c.new, :remove_users, :remove_groups)
90
+ end
91
+
92
+ it 'should allow removing from an association to succeed when granted above association declarations' do
93
+ c = new_model_class
94
+ c.instance_eval do
95
+ grant(:remove => [:users, :groups]) { true }
96
+ has_many :users
97
+ has_and_belongs_to_many :groups
98
+ end
99
+ verify_association_callbacks(c.new, :remove_users, :remove_groups)
100
+ end
101
+ end
102
+
103
+ def verify_standard_callbacks(instance, *succeeding_callbacks)
104
+ verify_callbacks([:create, :update, :destroy, :find], instance, nil, succeeding_callbacks)
105
+ end
106
+
107
+ def verify_association_callbacks(instance, *succeeding_callbacks)
108
+ verify_callbacks([:add_users, :remove_users, :add_groups, :remove_groups], instance, new_model_class.new, succeeding_callbacks)
109
+ end
110
+
111
+ def verify_callbacks(all_actions, instance, associated_model, succeeding_callbacks)
112
+ all_actions.each do |action|
113
+ expectation = succeeding_callbacks.include?(action) ? :should_not : :should
114
+ lambda { instance.send(action, associated_model) }.send(expectation, raise_error(Grant::Error))
115
+ end
116
+ end
117
+
118
+ def new_model_class
119
+ Class.new(ActiveRecordMock) do
120
+ include Grant::ModelSecurity
121
+ end
122
+ end
123
+
124
+ class ActiveRecordMock
125
+ def id; 1 end
126
+
127
+ def self.before_create(method)
128
+ define_method(:create) { send method }
129
+ end
130
+
131
+ def self.before_update(method)
132
+ define_method(:update) { send method }
133
+ end
134
+
135
+ def self.before_destroy(method)
136
+ define_method(:destroy) { send method }
137
+ end
138
+
139
+ def self.after_find(method)
140
+ define_method(:find) { send method }
141
+ end
142
+
143
+ def self.has_many(association_id, options, &extension)
144
+ define_method("add_#{association_id}".to_sym) do |associated_model|
145
+ Array(options[:before_add]).each { |callback| send(callback, associated_model) }
146
+ end
147
+ define_method("remove_#{association_id}".to_sym) do |associated_model|
148
+ Array(options[:before_remove]).each { |callback| send(callback, associated_model) }
149
+ end
150
+ end
151
+
152
+ def self.has_and_belongs_to_many(association_id, options, &extension)
153
+ define_method("add_#{association_id}".to_sym) do |associated_model|
154
+ Array(options[:before_add]).each { |callback| send(callback, associated_model) }
155
+ end
156
+ define_method("remove_#{association_id}".to_sym) do |associated_model|
157
+ Array(options[:before_remove]).each { |callback| send(callback, associated_model) }
158
+ end
159
+ end
160
+ end
161
+
162
+ end
@@ -0,0 +1,45 @@
1
+ require 'rspec'
2
+
3
+ # Requires supporting files with custom matchers and macros, etc,
4
+ # in ./support/ and its subdirectories.
5
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
6
+
7
+ RSpec.configure do |config|
8
+ # If you're not using ActiveRecord you should remove these
9
+ # lines, delete config/database.yml and disable :active_record
10
+ # in your config/boot.rb
11
+ # config.use_transactional_fixtures = true
12
+ # config.use_instantiated_fixtures = false
13
+
14
+ # == Fixtures
15
+ #
16
+ # You can declare fixtures for each example_group like this:
17
+ # describe "...." do
18
+ # fixtures :table_a, :table_b
19
+ #
20
+ # Alternatively, if you prefer to declare them only once, you can
21
+ # do so right here. Just uncomment the next line and replace the fixture
22
+ # names with your fixtures.
23
+ #
24
+ # config.global_fixtures = :all
25
+ #
26
+ # If you declare global fixtures, be aware that they will be declared
27
+ # for all of your examples, even those that don't use them.
28
+ #
29
+ # You can also declare which fixtures to use (for example fixtures for test/fixtures):
30
+ #
31
+ # config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
32
+ #
33
+ # == Mock Framework
34
+ #
35
+ # RSpec uses it's own mocking framework by default. If you prefer to
36
+ # use mocha, flexmock or RR, uncomment the appropriate line:
37
+ #
38
+ # config.mock_with :mocha
39
+ # config.mock_with :flexmock
40
+ # config.mock_with :rr
41
+ #
42
+ # == Notes
43
+ #
44
+ # For more information take a look at Spec::Runner::Configuration and Spec::Runner
45
+ end
@@ -0,0 +1,14 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'grant/thread_local'
3
+
4
+ describe Grant::ThreadLocal do
5
+ it "should properly set and get thread-local variables" do
6
+ val = "val"
7
+ tl = Grant::ThreadLocal.new(val)
8
+ tl.get.should == val
9
+
10
+ val2 = "val2"
11
+ tl.set val2
12
+ tl.get.should == val2
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'grant'
3
+
4
+ describe Grant::ThreadStatus do
5
+ it "should be enabled if set to enabled" do
6
+ Grant::ThreadStatus.enable
7
+ Grant::ThreadStatus.should be_enabled
8
+ Grant::ThreadStatus.should_not be_disabled
9
+ end
10
+
11
+ it "should be disabled if set to disabled" do
12
+ Grant::ThreadStatus.disable
13
+ Grant::ThreadStatus.should_not be_enabled
14
+ Grant::ThreadStatus.should be_disabled
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'grant/user'
3
+
4
+ describe Grant::User do
5
+ it "should return the same user that's set on the same thread" do
6
+ user = "user"
7
+ Grant::User.current_user = user
8
+ Grant::User.current_user.should == user
9
+ end
10
+
11
+ it "should not return the same user from a different thread" do
12
+ user = "user"
13
+ user2 = "user2"
14
+
15
+ Grant::User.current_user = user
16
+
17
+ Thread.new do
18
+ Grant::User.current_user.should be_nil
19
+ Grant::User.current_user = user2
20
+ Grant::User.current_user.should == user2
21
+ end
22
+
23
+ Grant::User.current_user.should == user
24
+ end
25
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: grant
3
+ version: !ruby/object:Gem::Version
4
+ hash: 21
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 1
10
+ version: 1.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jeff Kunkle
14
+ - Matt Wizeman
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-12-29 00:00:00 -05:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: rspec
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ type: :development
35
+ version_requirements: *id001
36
+ description: Grant is a Ruby gem and Rails plugin that forces you to make explicit security decisions about the operations performed on your ActiveRecord models.
37
+ email:
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - lib/grant/config_parser.rb
46
+ - lib/grant/integration.rb
47
+ - lib/grant/model_security.rb
48
+ - lib/grant/spec_helpers.rb
49
+ - lib/grant/thread_local.rb
50
+ - lib/grant/thread_status.rb
51
+ - lib/grant/user.rb
52
+ - lib/grant/version.rb
53
+ - lib/grant.rb
54
+ - LICENSE
55
+ - README.rdoc
56
+ - spec/config_parser_spec.rb
57
+ - spec/integration_spec.rb
58
+ - spec/model_security_spec.rb
59
+ - spec/spec_helper.rb
60
+ - spec/thread_local_spec.rb
61
+ - spec/thread_status_spec.rb
62
+ - spec/user_spec.rb
63
+ has_rdoc: true
64
+ homepage: http://github.com/nearinfinity/grant
65
+ licenses:
66
+ - MIT
67
+ post_install_message:
68
+ rdoc_options: []
69
+
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ hash: 23
87
+ segments:
88
+ - 1
89
+ - 3
90
+ - 6
91
+ version: 1.3.6
92
+ requirements: []
93
+
94
+ rubyforge_project:
95
+ rubygems_version: 1.3.7
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: Conscious security constraints for your ActiveRecord model objects
99
+ test_files:
100
+ - spec/config_parser_spec.rb
101
+ - spec/integration_spec.rb
102
+ - spec/model_security_spec.rb
103
+ - spec/spec_helper.rb
104
+ - spec/thread_local_spec.rb
105
+ - spec/thread_status_spec.rb
106
+ - spec/user_spec.rb