protector-cancan 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 24a492131115dea9a185a89b83c01e3fd3dde523
4
+ data.tar.gz: 0d0ef48a9f0e1ed21f0a0bc6d46c3fcb3d513dc3
5
+ SHA512:
6
+ metadata.gz: e98380fa0ecc0a8238304ba9716dffabdf634a3e5e9dc12ca806b6ca749032e0cb2610c213bab330241b76ac28db69f263cd676f7036fe1990b3b572117a8122
7
+ data.tar.gz: 956455e9fed66a3700a14d4ec3dcee8763a1a92da5f750e0d535f32e646ef54718d879b2ae4aae355bece3d1dcb6146d572b004915e5e9f7903d164ecde0476c
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --tty
2
+ --color
3
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
6
+ gem 'pry'
7
+ gem 'rspec'
8
+
9
+ gem 'combustion', github: 'pat/combustion'
10
+ gem 'rails', '>= 4.0.0'
11
+ gem 'rspec-rails'
12
+
13
+ gem 'sqlite3', platform: :ruby
14
+ gem 'jdbc-sqlite3', platform: :jruby, require: 'jdbc/sqlite3'
15
+ gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby, github: 'jruby/activerecord-jdbc-adapter'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Boris Staal
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # Protector::Cancan
2
+
3
+ Integrates [Protector](https://github.com/inossidabile/protector) and [CanCan](https://github.com/ryanb/cancan).
4
+
5
+ Protector and CanCan are all about the same thing: access control. They however act on different fronts: Protector works on a model level and CanCan is all about controllers defense. With this gem you don't have to choose anymore: make them work together for the best result.
6
+
7
+ The integration makes CanCan aware of Protector restrictions. You still can have separate `Ability` instance and even extend (or override) what comes from Protector.
8
+
9
+ Additionally CanCan will automatically restrict instances with `current_user` during `load_resource` part.
10
+
11
+ ## Installation
12
+
13
+ You are expected to have generated CanCan ability by this moment. Proceed to [CanCan installation tutorial](https://github.com/ryanb/cancan#1-define-abilities) to make one if you don't.
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ gem 'protector-cancan'
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Now modify your `Ability` definition in the following way:
24
+
25
+ ```ruby
26
+ class Ability
27
+ include CanCan::Ability
28
+
29
+ def intialize(user)
30
+ import_protector user # <- add this
31
+ end
32
+ end
33
+ ```
34
+
35
+ ## Example
36
+
37
+ For the case when you have the following model defined:
38
+
39
+ ```ruby
40
+ class Dummy < ActiveRecord::Base
41
+ protect do |user|
42
+ can :read if user
43
+ end
44
+ end
45
+ ```
46
+
47
+ If you call `can? :read, Dummy`, the gem will evaluate `Dummy` protection block against value passed to `import_protector` (by default it's `current_user`) and expand CanCan rules with resulting meta.
48
+
49
+ So in this particular case we will get `true` if `current_user` is set and `false` otherwise.
50
+
51
+ And that's how controller is going to work:
52
+
53
+ ```ruby
54
+ class DummiesController
55
+ load_and_authorize_resources
56
+
57
+ def index # Will be accessible if current_user isn't blank
58
+ @dummies # => Dummy.restrict!(current_user)
59
+ end
60
+
61
+ def show # Will be accessible if current_user isn't blank
62
+ @dummy # => Dummy.find(params[:id]).restrict!(current_user)
63
+ end
64
+ end
65
+ ```
66
+
67
+ ## Maintainers
68
+
69
+ * Boris Staal, [@inossidabile](http://staal.io)
70
+
71
+ ## License
72
+
73
+ It is free software, and may be redistributed under the terms of MIT license.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler/setup'
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -0,0 +1,54 @@
1
+ require 'set'
2
+
3
+ module Protector
4
+ module CanCan
5
+ module Ability
6
+
7
+ def import_protector(subject)
8
+ @protector_subject = subject
9
+ @protector_subject_defined = true
10
+ end
11
+
12
+ def protector_subject
13
+ @protector_subject
14
+ end
15
+
16
+ def protector_subject?
17
+ !!@protector_subject_defined
18
+ end
19
+
20
+ def self.included(mod)
21
+ mod.class_eval do
22
+
23
+ def can_with_protector?(action, entity, *extra_args)
24
+ if entity.respond_to?(:restrict!) && @protector_subject_defined
25
+ @protector_models ||= Set.new
26
+
27
+ model = entity
28
+ model = model.class unless model.is_a?(Class)
29
+
30
+ unless @protector_models.include?(model)
31
+ meta = entity.is_a?(Class) ? entity.protector_meta.evaluate(@protector_subject)
32
+ : entity.protector_meta(@protector_subject)
33
+
34
+ meta.access.each do |action, fields|
35
+ action = :read if action == :view # *doh*
36
+ can action, model unless fields.empty?
37
+ end
38
+
39
+ can :destroy, model if meta.destroyable?
40
+
41
+ @protector_models << model
42
+ end
43
+ end
44
+
45
+ can_without_protector? action, entity, *extra_args
46
+ end
47
+
48
+ alias_method_chain :can?, :protector
49
+
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,36 @@
1
+ module Protector
2
+ module CanCan
3
+ module Resource extend ActiveSupport::Concern
4
+ included do
5
+ alias_method_chain :load_resource, :protector
6
+ alias_method_chain :load_collection, :protector
7
+ end
8
+
9
+ def load_resource_with_protector(*args)
10
+ resource = load_resource_without_protector(*args)
11
+
12
+ if resource.respond_to?(:restrict!) \
13
+ && !resource.protector_subject? \
14
+ && current_ability.protector_subject?
15
+
16
+ resource = resource.restrict!(current_ability.protector_subject)
17
+ end
18
+
19
+ resource
20
+ end
21
+
22
+ def load_collection_with_protector(*args)
23
+ collection = load_collection_without_protector(*args)
24
+
25
+ if collection.respond_to?(:restrict!) \
26
+ && !collection.protector_subject? \
27
+ && current_ability.protector_subject?
28
+
29
+ collection = collection.restrict!(current_ability.protector_subject)
30
+ end
31
+
32
+ collection
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,5 @@
1
+ module Protector
2
+ module Cancan
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ require 'protector'
2
+ require 'cancan'
3
+ require 'active_support/all'
4
+ require 'protector/cancan/ability'
5
+ require 'protector/cancan/resource'
6
+ require 'protector/cancan/version'
7
+
8
+ CanCan::Ability.send :include, Protector::CanCan::Ability
9
+ CanCan::ControllerResource.send :include, Protector::CanCan::Resource
10
+ CanCan::InheritedResource.send :include, Protector::CanCan::Resource
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'protector/cancan/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "protector-cancan"
8
+ spec.version = Protector::Cancan::VERSION
9
+ spec.authors = ["Boris Staal"]
10
+ spec.email = ["boris@staal.io"]
11
+ spec.description = %q{Integration layer between Protector and CanCan}
12
+ spec.summary = spec.description
13
+ spec.homepage = "https://github.com/inossidabile/protector-cancan"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "protector", ">= 0.5.3"
22
+ spec.add_dependency "cancan"
23
+ spec.add_dependency "activesupport"
24
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helpers/boot'
2
+
3
+ describe DummiesController do
4
+ before(:all) do
5
+ Dummy.create! id: 1
6
+ end
7
+
8
+ after(:all) do
9
+ Dummy.find(1).destroy
10
+ end
11
+
12
+ describe "entities assignation" do
13
+ context "without integration" do
14
+ it "works for index" do
15
+ expect{ get :index }.to raise_error(CanCan::AccessDenied)
16
+ end
17
+
18
+ it "works for show" do
19
+ expect{ get :show, id: 1 }.to raise_error(CanCan::AccessDenied)
20
+ end
21
+
22
+ it "works for create" do
23
+ expect{ post :create }.to raise_error(CanCan::AccessDenied)
24
+ end
25
+
26
+ it "works for edit" do
27
+ expect{ get :edit, id: 1 }.to raise_error(CanCan::AccessDenied)
28
+ end
29
+
30
+ it "works for update" do
31
+ expect{ put :edit, id: 1 }.to raise_error(CanCan::AccessDenied)
32
+ end
33
+
34
+ it "works for destroy" do
35
+ expect{ delete :destroy, id: 1 }.to raise_error(CanCan::AccessDenied)
36
+ end
37
+ end
38
+
39
+ context "with integration" do
40
+ it "works for index" do
41
+ get :index, protector: true
42
+ expect(response).to be_success
43
+ assigns(:dummies).protector_subject?.should == true
44
+ assigns(:dummies).protector_subject.should == 'user'
45
+ end
46
+
47
+ it "works for show" do
48
+ get :show, id: 1, protector: true
49
+ expect(response).to be_success
50
+ assigns(:dummy).protector_subject?.should == true
51
+ assigns(:dummy).protector_subject.should == 'user'
52
+ end
53
+
54
+ it "works for create" do
55
+ post :create, protector: true
56
+ expect(response).to be_success
57
+ assigns(:dummy).protector_subject?.should == true
58
+ assigns(:dummy).protector_subject.should == 'user'
59
+ end
60
+
61
+ it "works for edit" do
62
+ get :edit, id: 1, protector: true
63
+ expect(response).to be_success
64
+ assigns(:dummy).protector_subject?.should == true
65
+ assigns(:dummy).protector_subject.should == 'user'
66
+ end
67
+
68
+ it "works for update" do
69
+ put :edit, id: 1, protector: true
70
+ expect(response).to be_success
71
+ assigns(:dummy).protector_subject?.should == true
72
+ assigns(:dummy).protector_subject.should == 'user'
73
+ end
74
+
75
+ it "works for destroy" do
76
+ delete :destroy, id: 1, protector: true
77
+ expect(response).to be_success
78
+ assigns(:dummy).protector_subject?.should == true
79
+ assigns(:dummy).protector_subject.should == 'user'
80
+ end
81
+
82
+ it "does not override set subject" do
83
+ get :test, protector: true
84
+ expect(response).to be_success
85
+ assigns(:dummies).protector_subject?.should == true
86
+ assigns(:dummies).protector_subject.should == 'test'
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,46 @@
1
+ class DummiesController < ActionController::Base
2
+ before_filter(only: :test) do
3
+ @dummies = Dummy.restrict!('test')
4
+ end
5
+
6
+ load_and_authorize_resource
7
+
8
+ def index
9
+ render nothing: true
10
+ end
11
+
12
+ def show
13
+ render nothing: true
14
+ end
15
+
16
+ def create
17
+ render nothing: true
18
+ end
19
+
20
+ def edit
21
+ render nothing: true
22
+ end
23
+
24
+ def update
25
+ render nothing: true
26
+ end
27
+
28
+ def destroy
29
+ render nothing: true
30
+ end
31
+
32
+ def test
33
+ render nothing: true
34
+ end
35
+
36
+ protected
37
+
38
+ def current_user
39
+ 'user'
40
+ end
41
+
42
+ def current_ability
43
+ ability = params[:protector] ? ProtectorAbility : DefaultAbility
44
+ @current_ability ||= ability.new(current_user)
45
+ end
46
+ end
@@ -0,0 +1,6 @@
1
+ class DefaultAbility
2
+ include CanCan::Ability
3
+
4
+ def initialize(user)
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ class Dummy < ActiveRecord::Base
2
+ protect do |user|
3
+ can :view
4
+ can :create
5
+ can :update
6
+ can :destroy
7
+ can :test
8
+ end
9
+
10
+ belongs_to :user
11
+ end
@@ -0,0 +1,7 @@
1
+ class ProtectorAbility
2
+ include CanCan::Ability
3
+
4
+ def initialize(user)
5
+ import_protector user
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ test:
2
+ adapter: <%= "jdbc" if defined? JRUBY_VERSION %>sqlite3
3
+ database: ":memory:"
4
+ verbosity: quiet
@@ -0,0 +1,7 @@
1
+ Rails.application.routes.draw do
2
+ resources :dummies do
3
+ collection do
4
+ get :test
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table(:dummies) do |t|
3
+ t.timestamps
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ *.log
@@ -0,0 +1,64 @@
1
+ require 'spec_helpers/boot'
2
+
3
+ describe Protector::CanCan::Ability do
4
+ let(:_Model) do
5
+ Class.new(ActiveRecord::Base) do
6
+ self.table_name = 'dummies'
7
+ end
8
+ end
9
+
10
+ let(:_Ability) do
11
+ Class.new do
12
+ include CanCan::Ability
13
+ end
14
+ end
15
+
16
+ it "defaults properly" do
17
+ _Ability.new.protector_subject?.should == false
18
+ end
19
+
20
+ it "initializes properly" do
21
+ _Ability.class_eval do
22
+ def initialize(user)
23
+ import_protector user
24
+ end
25
+ end
26
+
27
+ ability = _Ability.new('user')
28
+
29
+ ability.protector_subject?.should == true
30
+ ability.protector_subject.should == 'user'
31
+ ability.can?(:read, _Model).should == false
32
+ ability.can?(:create, _Model).should == false
33
+ ability.can?(:update, _Model).should == false
34
+ ability.can?(:destroy, _Model).should == false
35
+ end
36
+
37
+ it "proxies rules" do
38
+ _Ability.class_eval do
39
+ def initialize(user)
40
+ import_protector user
41
+ end
42
+ end
43
+
44
+ _Model.class_eval do
45
+ protect do |user|
46
+ can :view
47
+ can :create
48
+ can :update
49
+ can :destroy
50
+ can :test
51
+ end
52
+ end
53
+
54
+ ability = _Ability.new('user')
55
+
56
+ ability.protector_subject?.should == true
57
+ ability.protector_subject.should == 'user'
58
+ ability.can?(:read, _Model).should == true
59
+ ability.can?(:create, _Model).should == true
60
+ ability.can?(:update, _Model).should == true
61
+ ability.can?(:destroy, _Model).should == true
62
+ ability.can?(:test, _Model).should == true
63
+ end
64
+ end
@@ -0,0 +1,19 @@
1
+ require 'rspec'
2
+ require 'combustion'
3
+
4
+ RSpec.configure do |config|
5
+ config.treat_symbols_as_metadata_keys_with_true_values = true
6
+ config.run_all_when_everything_filtered = true
7
+ config.filter_run :focus
8
+
9
+ # Run specs in random order to surface order dependencies. If you find an
10
+ # order dependency and want to debug it, you can fix the order by providing
11
+ # the seed, which is printed after each run.
12
+ # --seed 1234
13
+ config.order = 'random'
14
+ end
15
+
16
+ Combustion.initialize! :active_record, :action_controller
17
+
18
+ require 'rspec/rails'
19
+ require 'rspec/autorun'
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: protector-cancan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Boris Staal
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: protector
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: cancan
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Integration layer between Protector and CanCan
56
+ email:
57
+ - boris@staal.io
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - .rspec
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - lib/protector/cancan.rb
69
+ - lib/protector/cancan/ability.rb
70
+ - lib/protector/cancan/resource.rb
71
+ - lib/protector/cancan/version.rb
72
+ - protector-cancan.gemspec
73
+ - spec/controllers/dummies_spec.rb
74
+ - spec/internal/app/controllers/dummies_controller.rb
75
+ - spec/internal/app/models/default_ability.rb
76
+ - spec/internal/app/models/dummy.rb
77
+ - spec/internal/app/models/protector_ability.rb
78
+ - spec/internal/config/database.yml
79
+ - spec/internal/config/routes.rb
80
+ - spec/internal/db/schema.rb
81
+ - spec/internal/log/.gitignore
82
+ - spec/lib/protector/cancan/ability_spec.rb
83
+ - spec/spec_helpers/boot.rb
84
+ homepage: https://github.com/inossidabile/protector-cancan
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.0.2
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Integration layer between Protector and CanCan
108
+ test_files:
109
+ - spec/controllers/dummies_spec.rb
110
+ - spec/internal/app/controllers/dummies_controller.rb
111
+ - spec/internal/app/models/default_ability.rb
112
+ - spec/internal/app/models/dummy.rb
113
+ - spec/internal/app/models/protector_ability.rb
114
+ - spec/internal/config/database.yml
115
+ - spec/internal/config/routes.rb
116
+ - spec/internal/db/schema.rb
117
+ - spec/internal/log/.gitignore
118
+ - spec/lib/protector/cancan/ability_spec.rb
119
+ - spec/spec_helpers/boot.rb