access-granted 0.0.2

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 990382c04aeeeb43c67adcd3adc1fc0e4ac6b7ac
4
+ data.tar.gz: d9970ae5c29e073953f41ec55c3f19b8a0d18225
5
+ SHA512:
6
+ metadata.gz: 6ddcadc2b5e812ae350e91479047c344d705e6cb7f3011f35e695aab0ca545402a550c1e9f8c45661e64cce0228b0f44334c384615721eb2eca38938d0ea501e
7
+ data.tar.gz: 9060e6c5d8243a43f33dfe9a4b6274a68edd748d1e32930939c5c7097db0679be03f21a168ae98f031806696da654a4806c3844f866ac2aadc4ccde6f5102b51
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 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in access-granted.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'simplecov', require: false
8
+ gem 'rake'
9
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Piotrek Okoński
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,120 @@
1
+ # AccessGranted [![Build Status](https://travis-ci.org/pokonski/access-granted.png?branch=master)](https://travis-ci.org/pokonski/access-granted) [![Code Climate](https://codeclimate.com/github/pokonski/access-granted.png)](https://codeclimate.com/github/pokonski/access-granted)
2
+
3
+ Multi-role and whitelist based authorization gem for Rails. And it's lightweight (~300 lines of code)!
4
+
5
+ # Summary
6
+
7
+ AccessGranted is meant as replacement for CanCan to solve three major problems:
8
+
9
+ 1. built-in support for roles
10
+
11
+ Easy to read acess policy code where permissions are cleanly grouped into roles which may or may not apply to a user.
12
+ Additionally permissions are forced to be unique in the scope a role greatly simplifying the
13
+ permission resolving and extremely reducing the code-base.
14
+
15
+ 2. white-list based
16
+
17
+ This means that you define what a role **can** do,
18
+ not overidding permissions with `cannot` in a specific order which results in an ugly and unmaintainable code.
19
+
20
+ 3. Permissions can work on basically any object and AccessGranted is framework-agnostic,
21
+ (the only Rails-specific methods are `can?`/`cannot?`/`authorize!` helpers injected
22
+ into the framework only when it's present).
23
+
24
+ See [Usage](#usage) for an example of a complete AccessPolicy file.
25
+
26
+ ## Compatibility
27
+
28
+ This gem was created as a replacement for CanCan and therefore it requires minimum work to switch.
29
+
30
+ 1. Both `can?`/`cannot?` and `authorize!` methods work in Rails controllers and views, so
31
+ **you don't have to adjust your views at all**.
32
+ 2. Syntax for defining permissions in AccessPolicy file (Ability in CanCan) is exactly the same,
33
+ with added roles on top. See [Usage](#usage) below.
34
+ 3. **Main difference**: AccessGranted does not extend ActiveRecord in any way, so it does not have the `accessible_by?`
35
+ method to keep the code as simple as possible.
36
+ That is because `accessible_by?` was very limited making it useless in most cases (complex permissions with lambdas).
37
+
38
+
39
+ ## Installation
40
+
41
+ Add this line to your application's Gemfile:
42
+
43
+ gem 'access-granted'
44
+
45
+ And then execute:
46
+
47
+ $ bundle
48
+
49
+ Or install it yourself as:
50
+
51
+ $ gem install access-granted
52
+
53
+ ## Usage
54
+
55
+ Roles are defined using blocks (or by passing custom classes to keep things tidy).
56
+ Order of the roles is important, because they are being traversed in the top-to-bottom order. Generally at the top you will have
57
+ an admin or other important role giving the user top permissions, and as you go down you define less-privileged roles.
58
+
59
+ See full example:
60
+
61
+ ```ruby
62
+ class Policy
63
+ include AccessGranted::Policy
64
+
65
+ def configure(user)
66
+ # The most important role prohibiting banned
67
+ # users from doing anything.
68
+ # (even if they are moderators or admins)
69
+ role :banned, { is_banned: true } do
70
+ cannot [:create, :update, :destroy], Post
71
+
72
+ # same as above, :manage is just a shortcut for
73
+ # `[:create, :update, :destroy]`
74
+ cannot :manage, Comment
75
+ end
76
+
77
+ # Takes precedences over roles placed lower
78
+ # and explicitly lets admin mamange everything.
79
+ role :admin, { is_admin: true } do
80
+ can :manage, Post
81
+ can :manage, Comment
82
+ end
83
+
84
+ # You can also use Procs to determine
85
+ # if the role should apply to a given user.
86
+ role :moderator, proc {|u| u.moderator? } do
87
+ # overwrites permission that only allows removing own content in :member
88
+ # and lets moderators edit and delete all posts
89
+ can [:update, :destroy], Post
90
+
91
+ # and a new permission which lets moderators
92
+ # modify user accounts
93
+ can :update, User
94
+ end
95
+
96
+ # Applies to everyone logged in.
97
+ # The basic role.
98
+ role :member do
99
+ can :create, Post
100
+
101
+ # For more advanced permissions
102
+ # you must use blocks. Hash
103
+ # conditions should be used for
104
+ # simple checks only.
105
+ can [:update, :destroy], Post do |post|
106
+ post.user_id == user.id && post.comments.empty?
107
+ end
108
+ end
109
+ end
110
+ end
111
+ ```
112
+
113
+
114
+ ## Contributing
115
+
116
+ 1. Fork it
117
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
118
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
119
+ 4. Push to the branch (`git push origin my-new-feature`)
120
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :default => [:spec]
4
+ desc 'run Rspec specs'
5
+ task :spec do
6
+ sh 'rspec spec'
7
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'access-granted/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "access-granted"
8
+ spec.version = AccessGranted::VERSION
9
+ spec.authors = ["Piotrek Okoński"]
10
+ spec.email = ["piotrek@okonski.org"]
11
+ spec.description = %q{Whitelist and role based authorization gem}
12
+ spec.summary = %q{Elegant whitelist and role based authorization with ability to prioritize roles.}
13
+ spec.homepage = "https://github.com/pokonski/access-granted"
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{^spec/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "pry"
25
+ spec.add_development_dependency "text-table"
26
+ end
@@ -0,0 +1,16 @@
1
+ require "access-granted/version"
2
+ require "access-granted/exceptions"
3
+ require "access-granted/policy"
4
+ require "access-granted/permission"
5
+ require "access-granted/controller_methods"
6
+ require "access-granted/role"
7
+
8
+ module AccessGranted
9
+
10
+ end
11
+
12
+ if defined? ActionController::Base
13
+ ActionController::Base.class_eval do
14
+ include AccessGranted::ControllerMethods
15
+ end
16
+ end
@@ -0,0 +1,24 @@
1
+ module AccessGranted
2
+ module ControllerMethods
3
+ def current_policy
4
+ @current_policy ||= ::Policy.new(current_user)
5
+ end
6
+
7
+ def self.included(base)
8
+ base.helper_method :can?, :cannot?, :current_ability
9
+ end
10
+
11
+ def can?(*args)
12
+ current_policy.can?(*args)
13
+ end
14
+
15
+ def cannot?(*args)
16
+ current_policy.cannot?(*args)
17
+ end
18
+
19
+ def authorize!(*args)
20
+ current_policy.authorize!(*args)
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,7 @@
1
+ module AccessGranted
2
+ class Error < StandardError; end
3
+
4
+ class DuplicatePermission < Error; end;
5
+ class DuplicateRole < Error; end;
6
+ class AccessDenied < Error; end;
7
+ end
@@ -0,0 +1,47 @@
1
+ module AccessGranted
2
+ class Permission
3
+ attr_reader :action, :subject, :granted, :conditions
4
+
5
+ def initialize(granted, action, subject, conditions = {}, block = nil)
6
+ @action = action
7
+ @granted = granted
8
+ @subject = subject
9
+ @conditions = conditions
10
+ @block = block
11
+ end
12
+
13
+ def matches_action?(action)
14
+ @action == action
15
+ end
16
+
17
+ def matches_subject?(subject)
18
+ @subject == subject || subject.class == @subject
19
+ end
20
+
21
+ def matches_conditions?(subject)
22
+ if @block
23
+ @block.call(subject)
24
+ else
25
+ matches_hash_conditions?(subject)
26
+ end
27
+ end
28
+
29
+ def matches_hash_conditions?(subject)
30
+ @conditions.each_pair do |name, value|
31
+ return false if subject.send(name) != value
32
+ end
33
+ true
34
+ end
35
+
36
+ def eql?(other)
37
+ other.class == self.class &&
38
+ @action == other.action &&
39
+ @subject == other.subject &&
40
+ @granted == other.granted
41
+ end
42
+
43
+ def ==(other)
44
+ eql?(other)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,56 @@
1
+ module AccessGranted
2
+ module Policy
3
+ attr_accessor :roles
4
+
5
+ def initialize(user)
6
+ @user = user
7
+ @roles = []
8
+ @last_priority = 0
9
+ configure(@user)
10
+ end
11
+
12
+ def configure(user)
13
+ end
14
+
15
+ def role(name, conditions_or_klass = nil, conditions = nil, &block)
16
+ name = name.to_sym
17
+ if roles.select {|r| r.name == name }.any?
18
+ raise DuplicateRole, "Role '#{name}' already defined"
19
+ end
20
+ @last_priority += 1
21
+ r = if conditions_or_klass.is_a?(Class) && conditions_or_klass <= AccessGranted::Role
22
+ conditions_or_klass.new(name, @last_priority, conditions, @user, block)
23
+ else
24
+ Role.new(name, @last_priority, conditions_or_klass, @user, block)
25
+ end
26
+ roles << r
27
+ roles.sort_by! {|r| r.priority }
28
+ r
29
+ end
30
+
31
+ def can?(action, subject)
32
+ match_roles(@user).each do |role|
33
+ permission = role.find_permission(action, subject)
34
+ return permission.granted if permission
35
+ end
36
+ false
37
+ end
38
+
39
+ def cannot?(*args)
40
+ !can?(*args)
41
+ end
42
+
43
+ def match_roles(user)
44
+ roles.select do |role|
45
+ role.applies_to?(user)
46
+ end
47
+ end
48
+
49
+ def authorize!(action, subject)
50
+ if cannot?(action, subject)
51
+ raise AccessDenied
52
+ end
53
+ subject
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,91 @@
1
+ module AccessGranted
2
+ class Role
3
+ attr_reader :name, :user, :priority, :conditions, :permissions
4
+
5
+ def initialize(name, priority, conditions = nil, user = nil, block = nil)
6
+ @user = user
7
+ @name = name
8
+ @priority = priority
9
+ @conditions = conditions
10
+ @block = block
11
+ @permissions = []
12
+ @permissions_by_action = {}
13
+ if @block
14
+ instance_eval(&@block)
15
+ else
16
+ configure(@user)
17
+ end
18
+ end
19
+
20
+ def configure(user)
21
+ end
22
+
23
+ def can(action, subject, conditions = {}, &block)
24
+ add_permission(true, action, subject, conditions, block)
25
+ end
26
+
27
+ def cannot(action, subject, conditions = {}, &block)
28
+ add_permission(false, action, subject, conditions, block)
29
+ end
30
+
31
+ def can?(action, subject)
32
+ permission = find_permission(action, subject)
33
+ permission ? permission.granted : false
34
+ end
35
+
36
+ def find_permission(action, subject)
37
+ relevant_permissions(action, subject).detect do |permission|
38
+ permission.matches_conditions?(subject)
39
+ end
40
+ end
41
+
42
+ def applies_to?(user)
43
+ case @conditions
44
+ when Hash
45
+ matches_hash(user, @conditions)
46
+ when Proc
47
+ @conditions.call(user)
48
+ else
49
+ true
50
+ end
51
+ end
52
+
53
+
54
+ def relevant_permissions(action, subject)
55
+ permissions_by_action(action).select do |perm|
56
+ perm.matches_subject?(subject)
57
+ end
58
+ end
59
+
60
+ def matches_hash(user, conditions = {})
61
+ conditions.all? do |name, value|
62
+ user.send(name) == value
63
+ end
64
+ end
65
+
66
+ def add_permission(granted, action, subject, conditions, block)
67
+ prepare_actions(action).each do |a|
68
+ raise DuplicatePermission if relevant_permissions(a, subject).any?
69
+ @permissions << Permission.new(granted, a, subject, conditions, block)
70
+ @permissions_by_action[a] ||= []
71
+ @permissions_by_action[a] << @permissions.size - 1
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def prepare_actions(action)
78
+ if action == :manage
79
+ actions = [:create, :update, :destroy]
80
+ else
81
+ actions = [action].flatten
82
+ end
83
+ end
84
+
85
+ def permissions_by_action(action)
86
+ (@permissions_by_action[action] || []).map do |index|
87
+ @permissions[index]
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,3 @@
1
+ module AccessGranted
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,42 @@
1
+ require "spec_helper"
2
+
3
+ describe AccessGranted::ControllerMethods do
4
+ before(:each) do
5
+ @current_user = double("User")
6
+ @controller_class = Class.new
7
+ @controller = @controller_class.new
8
+ @controller_class.stub(:helper_method).with(:can?, :cannot?, :current_ability)
9
+ @controller_class.send(:include, AccessGranted::ControllerMethods)
10
+ @controller.stub(:current_user).and_return(@current_user)
11
+ end
12
+
13
+ it "should have current_policy method returning Policy instance" do
14
+ @controller.current_policy.should be_kind_of(AccessGranted::Policy)
15
+ end
16
+
17
+ it "provides can? and cannot? method delegated to current_policy" do
18
+ @controller.can?(:read, String).should be_false
19
+ @controller.cannot?(:read, String).should be_true
20
+ end
21
+
22
+ describe "#authorize!" do
23
+ it "raises exception when authorization fails" do
24
+ expect { @controller.authorize!(:read, String) }.to raise_error(AccessGranted::AccessDenied)
25
+ end
26
+
27
+ it "returns subject if authorization succeeds" do
28
+ klass = Class.new do
29
+ include AccessGranted::Policy
30
+
31
+ def configure(user)
32
+ role :member, 1 do
33
+ can :read, String
34
+ end
35
+ end
36
+ end
37
+ policy = klass.new(@current_user)
38
+ @controller.stub(:current_policy).and_return(policy)
39
+ @controller.authorize!(:read, String).should == String
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe AccessGranted::Permission do
4
+ subject { AccessGranted::Permission }
5
+
6
+ describe "#matches_conditions?" do
7
+ it "matches when no conditions given" do
8
+ perm = subject.new(true, :read, String)
9
+ perm.matches_conditions?(String).should be_true
10
+ end
11
+
12
+ it "matches proc conditions" do
13
+ sub = double("Element", published?: true)
14
+ perm = subject.new(true, :read, sub.class, {}, proc {|el| el.published? })
15
+ perm.matches_conditions?(sub).should be_true
16
+ end
17
+ end
18
+
19
+ describe "#matches_hash_conditions?" do
20
+ it "matches condition hash is empty" do
21
+ perm = subject.new(true, :read, String)
22
+ perm.matches_hash_conditions?(String).should be_true
23
+ end
24
+
25
+ it "matches when conditions given" do
26
+ sub = double("Element", published: true)
27
+ perm = subject.new(true, :read, sub, { published: true })
28
+ perm.matches_hash_conditions?(sub).should be_true
29
+ end
30
+
31
+ it "does not match if one of the conditions mismatches" do
32
+ sub = double("Element", published: true, readable: false)
33
+ perm = subject.new(true, :read, sub, { published: true, readable: true })
34
+ perm.matches_hash_conditions?(sub).should be_false
35
+ end
36
+ end
37
+
38
+ describe "#matches_action?" do
39
+ it "matches if actions are identical" do
40
+ perm = subject.new(true, :read, String)
41
+ perm.matches_action?(:read).should be_true
42
+ end
43
+ end
44
+
45
+ describe "#matches_subject?" do
46
+ it "matches if subjects are identical" do
47
+ perm = subject.new(true, :read, String)
48
+ expect(perm.matches_subject? String).to be_true
49
+ end
50
+
51
+ it "matches if class is equal to subject" do
52
+ perm = subject.new(true, :read, String)
53
+ expect(perm.matches_subject? "test").to be_true
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe AccessGranted::Policy do
4
+ before :each do
5
+ @policy = Class.new do
6
+ include AccessGranted::Policy
7
+ end.new(nil)
8
+ end
9
+
10
+ describe "#configure" do
11
+ before :each do
12
+ @member = double("member", is_moderator: false, is_admin: false, is_banned: false)
13
+ @mod = double("moderator", is_moderator: true, is_admin: false, is_banned: false)
14
+ @admin = double("administrator", is_moderator: false, is_admin: true, is_banned: false)
15
+ @banned = double("banned", is_moderator: false, is_admin: true, is_banned: true)
16
+ end
17
+
18
+ it "selects permission based on role priority" do
19
+ klass = Class.new do
20
+ include AccessGranted::Policy
21
+
22
+ def configure(user)
23
+ role :member do
24
+ can :read, String
25
+ end
26
+
27
+ role :moderator, { is_moderator: true } do
28
+ can :edit, String
29
+ end
30
+
31
+ role :administrator, { is_admin: true } do
32
+ can :destroy, String
33
+ end
34
+ end
35
+ end
36
+ klass.new(@member).cannot?(:destroy, String).should be_true
37
+ klass.new(@admin).can?(:destroy, String).should be_true
38
+ klass.new(@admin).can?(:read, String).should be_true
39
+ klass.new(@mod).cannot?(:destroy, String).should be_true
40
+ end
41
+
42
+ describe "#cannot" do
43
+ it "forbids action when used in higher role" do
44
+ klass = Class.new do
45
+ include AccessGranted::Policy
46
+
47
+ def configure(user)
48
+ role :banned, { is_banned: true } do
49
+ cannot :create, String
50
+ end
51
+
52
+ role :member do
53
+ can :create, String
54
+ end
55
+ end
56
+ end
57
+ klass.new(@member).can?(:create, String).should be_true
58
+ klass.new(@banned).can?(:create, String).should be_false
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "#role" do
64
+ it "allows passing role class" do
65
+ klass_role = Class.new AccessGranted::Role do
66
+ def configure(user)
67
+ can :read, String
68
+ end
69
+ end
70
+ @policy.role(:member, klass_role)
71
+ @policy.roles.first.class.should == klass_role
72
+ end
73
+
74
+ it "allows defining a default role" do
75
+ @policy.role(:member)
76
+ @policy.roles.map(&:name).should include(:member)
77
+ end
78
+
79
+ it "does not allow duplicate role names" do
80
+ @policy.role(:member)
81
+ expect { @policy.role(:member) }.to raise_error AccessGranted::DuplicateRole
82
+ end
83
+
84
+ it "allows nesting `can` calls inside a block" do
85
+ role = @policy.role(:member) do
86
+ can :read, String
87
+ end
88
+
89
+ role.can?(:read, String).should be_true
90
+ end
91
+ end
92
+
93
+ describe "#match_roles" do
94
+ it "returns all matching roles in the order of priority" do
95
+ user = double("User", is_moderator: true, is_admin: true)
96
+
97
+ @policy.role(:administrator, { is_admin: true })
98
+ @policy.role(:moderator, { is_moderator: true })
99
+ @policy.role(:member)
100
+
101
+ @policy.match_roles(user).map(&:name).should == [:administrator, :moderator, :member]
102
+ end
103
+ end
104
+
105
+ end
data/spec/role_spec.rb ADDED
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ describe AccessGranted::Role do
4
+ subject { AccessGranted::Role }
5
+
6
+ it "requires a role name" do
7
+ expect { subject.new }.to raise_error
8
+ end
9
+
10
+ it "requires priority" do
11
+ expect { subject.new(:member) }.to raise_error
12
+ end
13
+
14
+ it "creates a default role without conditions" do
15
+ subject.new(:member, 1).conditions.should be_nil
16
+ end
17
+
18
+ describe "#relevant_permissions?" do
19
+ it "returns only matching permissions" do
20
+ role = subject.new(:member, 1)
21
+ role.can :read, String
22
+ role.can :read, Hash
23
+ role.relevant_permissions(:read, String).should == [AccessGranted::Permission.new(true, :read, String)]
24
+ end
25
+ end
26
+
27
+ describe "#applies_to?" do
28
+ it "matches user when no conditions given" do
29
+ role = subject.new(:member, 1)
30
+ user = double("User")
31
+ role.applies_to?(user).should be_true
32
+ end
33
+
34
+ it "matches user by hash conditions" do
35
+ role = subject.new(:moderator, 1, { is_moderator: true })
36
+ user = double("User", is_moderator: true)
37
+ role.applies_to?(user).should be_true
38
+ end
39
+
40
+ it "doesn't match user if any of hash conditions is not met" do
41
+ role = subject.new(:moderator, 1, { is_moderator: true, is_admin: true })
42
+ user = double("User", is_moderator: true, is_admin: false)
43
+ role.applies_to?(user).should be_false
44
+ end
45
+
46
+ it "matches user by Proc conditions" do
47
+ role = subject.new(:moderator, 1, proc {|user| user.is_moderator? })
48
+ user = double("User", is_moderator?: true)
49
+ role.applies_to?(user).should be_true
50
+ end
51
+ end
52
+
53
+ describe "#can" do
54
+ before :each do
55
+ @role = AccessGranted::Role.new(:member, 1)
56
+ end
57
+
58
+ it "forbids creating actions with the same name" do
59
+ @role.can :read, String
60
+ expect { @role.can :read, String }.to raise_error AccessGranted::DuplicatePermission
61
+ end
62
+
63
+ it "accepts :manage shortcut for CRUD actions" do
64
+ @role.can :manage, String
65
+ @role.permissions.map(&:action).should include(:create, :update, :destroy)
66
+ end
67
+
68
+ describe "when action is an Array" do
69
+ it "creates multiple permissions" do
70
+ @role.can [:read, :create], String
71
+ @role.permissions.should have(2).items
72
+ end
73
+ end
74
+
75
+ describe "when no conditions given" do
76
+ it "should be able to read a class" do
77
+ @role.can :read, String
78
+ @role.can?(:read, String).should be_true
79
+ end
80
+
81
+ it "should be able to read instance of class" do
82
+ @role.can :read, String
83
+ @role.can?(:read, "text").should be_true
84
+ end
85
+ end
86
+
87
+ describe "when conditions given" do
88
+ it "should be able to read when conditions match" do
89
+ sub = double("Element", published: true)
90
+ @role.can :read, sub.class, { published: true }
91
+ @role.can?(:read, sub).should be_true
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+ require 'pry'
6
+
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ config.order = 'random'
13
+ end
14
+
15
+ module ActionController
16
+ class Base
17
+ def self.helper_method(*args)
18
+ end
19
+ end
20
+ end
21
+ require 'access-granted'
22
+
23
+ class Policy
24
+ include AccessGranted::Policy
25
+ end
26
+
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: access-granted
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Piotrek Okoński
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
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: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: text-table
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Whitelist and role based authorization gem
84
+ email:
85
+ - piotrek@okonski.org
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - .gitignore
91
+ - .rspec
92
+ - .travis.yml
93
+ - Gemfile
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - access-granted.gemspec
98
+ - lib/access-granted.rb
99
+ - lib/access-granted/controller_methods.rb
100
+ - lib/access-granted/exceptions.rb
101
+ - lib/access-granted/permission.rb
102
+ - lib/access-granted/policy.rb
103
+ - lib/access-granted/role.rb
104
+ - lib/access-granted/version.rb
105
+ - spec/controller_methods_spec.rb
106
+ - spec/permission_spec.rb
107
+ - spec/policy_spec.rb
108
+ - spec/role_spec.rb
109
+ - spec/spec_helper.rb
110
+ homepage: https://github.com/pokonski/access-granted
111
+ licenses:
112
+ - MIT
113
+ metadata: {}
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubyforge_project:
130
+ rubygems_version: 2.0.3
131
+ signing_key:
132
+ specification_version: 4
133
+ summary: Elegant whitelist and role based authorization with ability to prioritize
134
+ roles.
135
+ test_files:
136
+ - spec/controller_methods_spec.rb
137
+ - spec/permission_spec.rb
138
+ - spec/policy_spec.rb
139
+ - spec/role_spec.rb
140
+ - spec/spec_helper.rb
141
+ has_rdoc: