toni 0.0.1

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: c0672f47c55346d477e4489c4cefcb1f0e000c9b
4
+ data.tar.gz: 8cdca30ac45fd0d3674236da33729e9042938400
5
+ SHA512:
6
+ metadata.gz: 162bce0becb671e9bf13c50ce2667a8b096cef24bf10e0358f1e4f06d33136458994ffea265134c595f8dc9b5adf8ef7da549a0a828a5eed73a6bf8f60c04388
7
+ data.tar.gz: d20995225334b18c8ac4435ea7c3d2fdf952742679db715f44804d5f3ed1e666c56190ddc96422d0a0b4bfd2d47d5318aea306dab2cc8104ce1b42e3c175460d
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/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
4
+ - 2.0.0
5
+ addons:
6
+ code_climate:
7
+ repo_token: 53df9a1d69568057bc007b09
8
+ script: bundle exec rspec spec
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in toni.gemspec
4
+ gemspec
5
+
6
+ gem "codeclimate-test-reporter", group: :test, require: nil
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Jalyna
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,42 @@
1
+ # Toni
2
+ [![Build Status](https://travis-ci.org/jalyna/toni.svg?branch=master)](https://travis-ci.org/jalyna/toni) [![Code Climate](https://codeclimate.com/github/jalyna/toni/badges/gpa.svg)](https://codeclimate.com/github/jalyna/toni) [![Inline docs](http://inch-ci.org/github/jalyna/toni.png?branch=master)](http://inch-ci.org/github/jalyna/toni)
3
+
4
+ Toni enables you to create a centralized authorization rules configuration with a readable DSL,
5
+ similar to [declarative authorization](https://github.com/stffn/declarative_authorization), but not required to use with Ruby on Rails.
6
+ Internally the Gem is using RSpec Matchers. You can use Toni with **Sinatra** and **Ruby on Rails**.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'toni'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install toni
21
+
22
+ ## Getting Started
23
+
24
+ ### Setup Authorization Rules
25
+
26
+ TODO: Write usage instructions here
27
+
28
+ ### Ruby on Rails
29
+
30
+ TODO: Write usage instructions here
31
+
32
+ ### Sinatra
33
+
34
+ TODO: Write usage instructions here
35
+
36
+ ## Contributing
37
+
38
+ 1. Fork it
39
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
40
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
41
+ 4. Push to the branch (`git push origin my-new-feature`)
42
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,7 @@
1
+ class Toni
2
+ class AnonymousUser
3
+ def role_symbols
4
+ [:guest]
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,90 @@
1
+ require "toni/role"
2
+ require "toni/permission"
3
+ require "rspec/matchers"
4
+
5
+ class Toni
6
+ class Builder
7
+
8
+ attr_reader :roles
9
+
10
+ def initialize(authorization_rules)
11
+ @roles = {}
12
+ instance_eval authorization_rules, Toni::AUTH_FILE
13
+ end
14
+
15
+ def role(role_symbol, &block)
16
+ builder = RoleBuilder.new(role_symbol, &block)
17
+ @roles[role_symbol] = builder.role
18
+ end
19
+
20
+ class RoleBuilder
21
+
22
+ attr_reader :role
23
+
24
+ def initialize(role_symbol, &block)
25
+ @role = Role.new(role_symbol)
26
+ if block_given?
27
+ instance_eval &block
28
+ end
29
+ end
30
+
31
+ # Add an ancestor to the current role
32
+ def includes(role_symbol)
33
+ @role.add_ancestor(role_symbol)
34
+ end
35
+
36
+ # Add permissions to specific role
37
+ def has_permission_on(resource_name, options={}, &block)
38
+ builder = PermissionBuilder.new(resource_name, options, &block)
39
+ @role.add_permission(builder.permission)
40
+ end
41
+
42
+ end
43
+
44
+ class PermissionBuilder
45
+
46
+ attr_reader :permission
47
+
48
+ def initialize(resource_name, options={}, &block)
49
+ options[:to] ||= [:manage]
50
+ @permission = Permission.new(resource_name, options[:to])
51
+ if block_given?
52
+ instance_eval &block
53
+ end
54
+ end
55
+
56
+ # Attribute should always be a column in the database on the resource
57
+ def expect_attribute(method_name, &block)
58
+ expect_method(method_name, true, &block)
59
+ end
60
+
61
+ # Methods should be defined on the resource
62
+ def expect_method(method_name, is_attr = false, &block)
63
+ builder = ExpectationBuilder.new(&block)
64
+ permission.add_matcher(method_name, builder, is_attr)
65
+ end
66
+
67
+ end
68
+
69
+ class ExpectationBuilder
70
+
71
+ include ::RSpec::Matchers
72
+
73
+ def initialize(&block)
74
+ @block = block
75
+ end
76
+
77
+ def execute
78
+ unless @block.nil?
79
+ instance_eval &@block
80
+ end
81
+ end
82
+
83
+ def current_user
84
+ Toni.current_user
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,31 @@
1
+ require "toni/permission_matcher"
2
+
3
+ class Toni
4
+ class Permission
5
+
6
+ attr_reader :resource_name, :matchers, :activities
7
+
8
+ def initialize(resource_name, activities = [])
9
+ @resource_name = resource_name
10
+ @matchers = []
11
+ @activities = activities
12
+ end
13
+
14
+ def add_matcher(method_name, matcher, is_attr = false)
15
+ @matchers << PermissionMatcher.new(method_name, matcher, is_attr)
16
+ end
17
+
18
+ def permitted_to?(activity, res, options={})
19
+ resource_name == (res.is_a?(Symbol) ? res : res.class.authorization_context) &&
20
+ activities.include?(activity) && matches?(res)
21
+ end
22
+
23
+ private
24
+
25
+ def matches?(object)
26
+ return true if object.is_a?(Symbol)
27
+ matchers.all? { |m| m.execute.matches?(object) }
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ class Toni
2
+ class PermissionMatcher
3
+
4
+ attr_reader :method_name, :matcher, :is_attr
5
+
6
+ def initialize(method_name, matcher, is_attr = false)
7
+ @method_name = method_name
8
+ @matcher = matcher
9
+ @is_attr = is_attr
10
+ end
11
+
12
+ def matches?(object)
13
+ unless object.respond_to?(method_name)
14
+ raise Toni::NoMethodForMatcherError.new("#{method_name} is not defined for #{object.inspect}")
15
+ end
16
+ matcher.matches?(object.send(method_name))
17
+ end
18
+
19
+ end
20
+ end
data/lib/toni/role.rb ADDED
@@ -0,0 +1,42 @@
1
+ class Toni
2
+ class Role
3
+
4
+ attr_reader :role_symbol, :ancestors, :permissions
5
+
6
+ def initialize(role_symbol)
7
+ @role_symbol = role_symbol
8
+ @ancestors = []
9
+ @permissions = []
10
+ end
11
+
12
+ def add_ancestor(role_symbol)
13
+ @ancestors << role_symbol unless @ancestors.include?(role_symbol)
14
+ end
15
+
16
+ def add_permission(permission)
17
+ @permissions << permission
18
+ end
19
+
20
+ def permitted_to?(activity, res, options={})
21
+ unless res.is_a?(Symbol) || res.class.respond_to?(:authorization_context)
22
+ raise Toni::NoAuthorizationContextProvidedError
23
+ end
24
+ current_permissions.any? do |p|
25
+ p.permitted_to?(activity, res, options)
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def current_permissions
32
+ @permissions.concat(ancestor_permissions)
33
+ end
34
+
35
+ def ancestor_permissions
36
+ @ancestor_permissions ||= ancestors.map do |ancestor|
37
+ ancestor.permissions
38
+ end.flatten
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ class Toni
2
+ VERSION = "0.0.1"
3
+ end
data/lib/toni.rb ADDED
@@ -0,0 +1,64 @@
1
+ require "toni/version"
2
+ require "toni/anonymous_user"
3
+ require "toni/builder"
4
+
5
+ class Toni
6
+ AUTH_FILE = File.dirname(__FILE__) + "/authorization_rules.rb"
7
+
8
+ class InvalidCurrentUserError < StandardError; end
9
+ class NoAuthorizationContextProvidedError < StandardError; end
10
+ class NoMethodForMatcherError < StandardError; end
11
+ class NotAuthorizedError < StandardError; end
12
+
13
+ class << self
14
+ @@without_authorization = false
15
+
16
+ def current_user
17
+ @@curent_user ||= nil
18
+ @@curent_user || anonymous_user
19
+ end
20
+
21
+ def current_user=(user)
22
+ raise InvalidCurrentUserError if !user.nil? && !user.respond_to?(:role_symbols)
23
+ @@curent_user = user
24
+ end
25
+
26
+ def roles
27
+ @@roles ||= build
28
+ end
29
+
30
+ def permitted_to?(activity, resource_or_name, options={})
31
+ return true if @@without_authorization
32
+ permitted = current_roles.any?{ |r| r.permitted_to?(activity, resource_or_name, options) }
33
+ if options[:bang] && !permitted
34
+ raise NotAuthorizedError.new("#{current_user.inspect} is not allowed to #{activity} on #{resource_or_name.inspect}")
35
+ end
36
+
37
+ permitted
38
+ end
39
+
40
+ def current_roles
41
+ roles.select { |role_symbol, r| current_user.role_symbols.include?(role_symbol) }.values
42
+ end
43
+
44
+ def without_authorization(&block)
45
+ @@without_authorization = true
46
+ yield if block_given?
47
+ @@without_authorization = false
48
+ end
49
+
50
+ private
51
+
52
+ def build
53
+ Builder.new(authorization_rules).roles
54
+ end
55
+
56
+ def authorization_rules
57
+ File.read(AUTH_FILE)
58
+ end
59
+
60
+ def anonymous_user
61
+ @@anonymous_user ||= AnonymousUser.new
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,14 @@
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
3
+
4
+ require "active_record"
5
+
6
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
7
+ ActiveRecord::Schema.define do
8
+ self.verbose = false
9
+
10
+ create_table :test, :force => true do |t|
11
+ t.string :foo
12
+ t.string :bar
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ require "toni/anonymous_user"
2
+
3
+ describe Toni::AnonymousUser do
4
+ let(:user) { Toni::AnonymousUser.new }
5
+
6
+ describe :role_symbols do
7
+
8
+ it { expect(user).to respond_to(:role_symbols) }
9
+
10
+ it "provides a guest role by default" do
11
+ expect(user.role_symbols).to eq([:guest])
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,105 @@
1
+ require "toni/builder"
2
+
3
+ describe Toni::Builder do
4
+
5
+ let(:builder) { Toni::Builder.new("") }
6
+
7
+ describe :role do
8
+ it "creates a new role instance" do
9
+ expect(builder.role(:user)).to be_instance_of(Toni::Role)
10
+ end
11
+ end
12
+
13
+ describe :roles do
14
+ it "return hash of defined roles" do
15
+ builder.role(:user)
16
+ expect(builder.roles.keys).to eq([:user])
17
+ end
18
+ end
19
+
20
+ end
21
+
22
+ describe Toni::Builder::RoleBuilder do
23
+
24
+ let(:builder) { Toni::Builder::RoleBuilder.new(:user) }
25
+
26
+ describe :role do
27
+ it "is a Role" do
28
+ expect(builder.role).to be_instance_of(Toni::Role)
29
+ end
30
+ end
31
+
32
+ describe :includes do
33
+ it "calls add_ancestor for the given role_symbol" do
34
+ builder.includes(:parent_user)
35
+ allow(builder.role).to receive(:add_ancestor).with(:parent_user)
36
+ end
37
+ end
38
+
39
+ describe :has_permission_on do
40
+ it "calls add_permission on role" do
41
+ builder.has_permission_on(:my_resource)
42
+ allow(builder.role).to receive(:add_permission)
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ describe Toni::Builder::PermissionBuilder do
49
+
50
+ let(:builder) { Toni::Builder::PermissionBuilder.new(:resource_name) }
51
+
52
+ describe :permission do
53
+ it "is a Permission" do
54
+ expect(builder.permission).to be_instance_of(Toni::Permission)
55
+ end
56
+ end
57
+
58
+ describe :expect_attribute do
59
+ it "calls expect_method with is_attribute true" do
60
+ builder.expect_attribute(nil)
61
+ allow(builder).to receive(:expect_method).with(nil, true)
62
+ end
63
+ end
64
+
65
+ describe :expect_method do
66
+ it "calls add_matcher on permission per method_name" do
67
+ builder.expect_method(:foo) { nil }
68
+ builder.expect_method(:bar) { nil }
69
+ allow(builder.permission).to receive(:add_matcher).with(:foo, anything)
70
+ allow(builder.permission).to receive(:add_matcher).with(:bar, anything)
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ describe Toni::Builder::ExpectationBuilder do
77
+
78
+ let(:builder) { Toni::Builder::ExpectationBuilder.new }
79
+
80
+ describe :execute do
81
+ it "calls block eagerly" do
82
+ double = double()
83
+ builder = Toni::Builder::ExpectationBuilder.new do
84
+ double.call
85
+ end
86
+ expect(double).to receive(:call).once
87
+ builder.execute
88
+ end
89
+ end
90
+
91
+ describe "uses rspec matchers" do
92
+ it "calls rspec matcher methods" do
93
+ builder.be_nil
94
+ allow(RSpec::Matchers).to receive(:be_nil)
95
+ end
96
+
97
+ it "sets the called matcher" do
98
+ builder = Toni::Builder::ExpectationBuilder.new do
99
+ be(:cool)
100
+ end
101
+ expect(builder.execute).to be_instance_of(RSpec::Matchers::BuiltIn::Equal)
102
+ end
103
+ end
104
+
105
+ end
@@ -0,0 +1,80 @@
1
+ require "toni/permission_matcher"
2
+ require "toni"
3
+ require "ostruct"
4
+
5
+ describe Toni::PermissionMatcher do
6
+
7
+ let(:matcher) do
8
+ Class.new do
9
+ def matches?(actual)
10
+ false
11
+ end
12
+ end.new
13
+ end
14
+ let(:permission_matcher) { Toni::PermissionMatcher.new(:foo, matcher) }
15
+
16
+ describe :method_name do
17
+ it "sets the method_name on initialize" do
18
+ expect(Toni::PermissionMatcher.new(:method_name, nil).method_name).to eq(:method_name)
19
+ end
20
+ end
21
+
22
+ describe :matcher do
23
+ it "sets the matcher on initialize" do
24
+ expect(permission_matcher.matcher).to eq(matcher)
25
+ end
26
+ end
27
+
28
+ describe :is_attr do
29
+ it "sets the is_attr on initialize" do
30
+ expect(permission_matcher.is_attr).to eq(false)
31
+ end
32
+ end
33
+
34
+ describe :matches? do
35
+ let(:object) do
36
+ Class.new do
37
+ def self.authorization_context
38
+ :resource_name
39
+ end
40
+ def foo
41
+ nil
42
+ end
43
+ end.new
44
+ end
45
+ let(:object2) do
46
+ Class.new do
47
+ def self.authorization_context
48
+ :resource_name
49
+ end
50
+ end.new
51
+ end
52
+
53
+ it "raises NoMethodForMatcherError if method is not there" do
54
+ expect { permission_matcher.matches?(object2) }.to raise_error(Toni::NoMethodForMatcherError)
55
+ end
56
+
57
+ it "returns false if matcher does not match" do
58
+ expect(permission_matcher.matches?(object)).to eq(false)
59
+ end
60
+
61
+ it "returns true if matcher does match" do
62
+ allow(matcher).to receive(:matches?) { true }
63
+ expect(permission_matcher.matches?(object)).to eq(true)
64
+ end
65
+
66
+ it "returns true if matcher is rspec nil matcher and value is nil" do
67
+ matcher = RSpec::Matchers::BuiltIn::BeNil.new
68
+ permission_matcher = Toni::PermissionMatcher.new(:foo, matcher)
69
+ expect(permission_matcher.matches?(object)).to eq(true)
70
+ end
71
+
72
+ it "returns false if matcher is rspec nil matcher and value is not nil" do
73
+ allow(object).to receive(:foo) { "a string" }
74
+ matcher = RSpec::Matchers::BuiltIn::BeNil.new
75
+ permission_matcher = Toni::PermissionMatcher.new(:foo, matcher)
76
+ expect(permission_matcher.matches?(object)).to eq(false)
77
+ end
78
+ end
79
+
80
+ end
@@ -0,0 +1,114 @@
1
+ require "toni/permission"
2
+ require "ostruct"
3
+
4
+ describe Toni::Permission do
5
+
6
+ let(:permission) { Toni::Permission.new(:my_resource) }
7
+
8
+ describe :resource_name do
9
+ it "sets the resource_name on initialize" do
10
+ expect(Toni::Permission.new(:a_resource).resource_name).to eq(:a_resource)
11
+ end
12
+ end
13
+
14
+ describe :activities do
15
+ it "sets the activities on initialize" do
16
+ expect(Toni::Permission.new(:a_resource, [:read]).activities).to eq([:read])
17
+ end
18
+ end
19
+
20
+ describe :add_matcher do
21
+ it "adds the matcher" do
22
+ permission.add_matcher(:foo, nil)
23
+ expect(permission.matchers.first).to be_instance_of(Toni::PermissionMatcher)
24
+ end
25
+ end
26
+
27
+ describe :permitted_to? do
28
+
29
+ let(:permission) do
30
+ Toni::Permission.new(:resource_name, [:read, :create])
31
+ end
32
+
33
+ context "with resource_name" do
34
+ it "should be allowed to read resource_name" do
35
+ expect(permission.permitted_to?(:read, :resource_name)).to eq(true)
36
+ end
37
+ it "should be allowed to delete resource_name" do
38
+ expect(permission.permitted_to?(:delete, :resource_name)).to eq(false)
39
+ end
40
+ it "should be allowed to read xxx" do
41
+ expect(permission.permitted_to?(:read, :xxx)).to eq(false)
42
+ end
43
+ end
44
+
45
+ context "with matchers" do
46
+ let(:matcher) { RSpec::Matchers::BuiltIn::BeNil.new }
47
+ let(:permission) do
48
+ p = Toni::Permission.new(:resource_name, [:read, :create])
49
+ p.add_matcher(:foo, matcher)
50
+ p
51
+ end
52
+ let(:object) do
53
+ Class.new do
54
+ def self.authorization_context
55
+ :resource_name
56
+ end
57
+ end.new
58
+ end
59
+
60
+ it "always is true when only resource name is given" do
61
+ allow(permission.matchers.first).to receive(:execute) do
62
+ Class.new do
63
+ def matches?(object)
64
+ false
65
+ end
66
+ end.new
67
+ end
68
+ expect(permission.permitted_to?(:read, :resource_name)).to eq(true)
69
+ end
70
+
71
+ it "is false when object is given" do
72
+ allow(permission.matchers.first).to receive(:execute) do
73
+ Class.new do
74
+ def matches?(object)
75
+ false
76
+ end
77
+ end.new
78
+ end
79
+ expect(permission.permitted_to?(:read, object)).to eq(false)
80
+ end
81
+ end
82
+
83
+ context "with resource object" do
84
+ let(:object) do
85
+ Class.new do
86
+ def self.authorization_context
87
+ :resource_name
88
+ end
89
+ end.new
90
+ end
91
+ let(:object2) do
92
+ Class.new do
93
+ def self.authorization_context
94
+ :xxx
95
+ end
96
+ end.new
97
+ end
98
+ let(:object3) do
99
+ Class.new.new
100
+ end
101
+
102
+ it "should be allowed to read object" do
103
+ expect(permission.permitted_to?(:read, object)).to eq(true)
104
+ end
105
+ it "should be allowed to delete object" do
106
+ expect(permission.permitted_to?(:delete, object)).to eq(false)
107
+ end
108
+ it "should be allowed to read xxx" do
109
+ expect(permission.permitted_to?(:read, object2)).to eq(false)
110
+ end
111
+ end
112
+ end
113
+
114
+ end
@@ -0,0 +1,86 @@
1
+ require "toni/role"
2
+ require "toni/permission"
3
+ require "ostruct"
4
+
5
+ describe Toni::Role do
6
+
7
+ let(:role) { Toni::Role.new(:user)}
8
+ let(:permission) { Toni::Permission.new(:resource_name)}
9
+
10
+ describe :role_symbol do
11
+ it "sets the role_symbol on initialize" do
12
+ expect(Toni::Role.new(:everything).role_symbol).to eq(:everything)
13
+ end
14
+ end
15
+
16
+ describe :add_ancestor do
17
+ it "adds role symbol to ancestors" do
18
+ role.add_ancestor(:another)
19
+ expect(role.ancestors).to eq([:another])
20
+ end
21
+
22
+ it "adds role symbol only once" do
23
+ role.add_ancestor(:another)
24
+ role.add_ancestor(:another)
25
+ expect(role.ancestors).to eq([:another])
26
+ end
27
+ end
28
+
29
+ describe :add_permission do
30
+ it "adds permission to permissions" do
31
+ role.add_permission(permission)
32
+ expect(role.permissions).to eq([permission])
33
+ end
34
+ end
35
+
36
+ describe :permitted_to? do
37
+
38
+ let(:permission) do
39
+ Toni::Permission.new(:resource_name, [:read, :create])
40
+ end
41
+
42
+ let(:role) do
43
+ role = Toni::Role.new(:user)
44
+ role.add_permission(permission)
45
+ role
46
+ end
47
+
48
+ let(:object) do
49
+ Class.new.new
50
+ end
51
+
52
+ it "should raise NoAuthorizationContextProvidedError" do
53
+ expect { role.permitted_to?(:read, object) }.to raise_error(Toni::NoAuthorizationContextProvidedError)
54
+ end
55
+
56
+ it "should call permission permitted_to? and return true if permission is true" do
57
+ allow(permission).to receive(:permitted_to?).with(:read, :resource_name, anything) { true }
58
+ expect(role.permitted_to?(:read, :resource_name)).to eq(true)
59
+ end
60
+
61
+ it "should call permission permitted_to? and return false if permission is false" do
62
+ allow(permission).to receive(:permitted_to?).with(:read, :resource_name, anything) { false }
63
+ expect(role.permitted_to?(:read, :resource_name)).to eq(false)
64
+ end
65
+
66
+ context "inheritance" do
67
+ let(:parent_role) do
68
+ role = Toni::Role.new(:parent_user)
69
+ role.add_permission(permission)
70
+ role
71
+ end
72
+
73
+ let(:role) do
74
+ role = Toni::Role.new(:user)
75
+ role.add_ancestor(parent_role)
76
+ role
77
+ end
78
+
79
+ it "uses permission from parent role" do
80
+ allow(permission).to receive(:permitted_to?).with(:read, :resource_name, anything) { true }
81
+ expect(role.permitted_to?(:read, :resource_name)).to eq(true)
82
+ end
83
+ end
84
+ end
85
+
86
+ end
data/spec/toni_spec.rb ADDED
@@ -0,0 +1,75 @@
1
+ require "toni"
2
+ require "ostruct"
3
+
4
+ describe Toni do
5
+
6
+ let(:role_symbols) { [] }
7
+ let(:current_user) { OpenStruct.new(role_symbols: role_symbols) }
8
+
9
+ describe ".current_user" do
10
+ it "has a anonymous user as default" do
11
+ expect(Toni.current_user).to be_instance_of(Toni::AnonymousUser)
12
+ end
13
+ end
14
+
15
+ describe ".current_user=" do
16
+ it "raises an error when current user does not respond to role_symbols" do
17
+ expect{ Toni.current_user = OpenStruct.new }.to raise_error(Toni::InvalidCurrentUserError)
18
+ end
19
+
20
+ it "sets current user respond to role_symbols" do
21
+ Toni.current_user = current_user
22
+ expect(Toni.current_user).to eq(current_user)
23
+ end
24
+
25
+ it "uses an anonymous user when current user was set to nil" do
26
+ Toni.current_user = nil
27
+ expect(Toni.current_user).to be_instance_of(Toni::AnonymousUser)
28
+ end
29
+ end
30
+
31
+ describe ".roles" do
32
+ pending
33
+ end
34
+
35
+ describe ".current_roles" do
36
+ pending
37
+ end
38
+
39
+ describe ".without_authorization" do
40
+ pending
41
+ end
42
+
43
+ describe ".permitted_to?" do
44
+ let(:role_symbols) { [:user, :seller] }
45
+ let(:user_role) { Toni::Role.new(:user) }
46
+ let(:seller_role) { Toni::Role.new(:seller) }
47
+ let(:roles) { { user: user_role, seller: seller_role } }
48
+
49
+ before do
50
+ allow(Toni).to receive(:roles) { roles }
51
+ Toni.current_user = current_user
52
+ end
53
+
54
+ it "is not permitted_to if all roles return false" do
55
+ allow(user_role).to receive(:permitted_to?).with(:read, :resource, anything) { false }
56
+ allow(seller_role).to receive(:permitted_to?).with(:read, :resource, anything) { false }
57
+ expect(Toni.permitted_to?(:read, :resource)).to eq(false)
58
+ end
59
+
60
+ it "is permitted_to if at least user_role returns true" do
61
+ allow(user_role).to receive(:permitted_to?).with(:read, :resource, anything) { true }
62
+ allow(seller_role).to receive(:permitted_to?).with(:read, :resource, anything) { false }
63
+ expect(Toni.permitted_to?(:read, :resource)).to eq(true)
64
+ end
65
+
66
+ it "raises error if it is not permitted to and bang is true" do
67
+ allow(user_role).to receive(:permitted_to?).with(:read, :resource, anything) { false }
68
+ allow(seller_role).to receive(:permitted_to?).with(:read, :resource, anything) { false }
69
+ expect { Toni.permitted_to?(:read, :resource, bang: true) }.to raise_error(Toni::NotAuthorizedError)
70
+
71
+ end
72
+
73
+ end
74
+
75
+ end
data/toni.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'toni/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "toni"
8
+ spec.version = Toni::VERSION
9
+ spec.authors = ["Jalyna"]
10
+ spec.email = ["jalyna.schroeder@gmail.com"]
11
+ spec.description = %q{Ruby Authorization Gem using Role Based Access Control}
12
+ spec.summary = %q{Enables you to create a centralized authorization
13
+ rules configuration, similar to declarative authorization,
14
+ but not bound to Ruby on Rails. Internally the Gem is using
15
+ RSpec Matchers.}
16
+ spec.homepage = "https://github.com/jalyna/toni"
17
+ spec.license = "MIT"
18
+
19
+ spec.files = `git ls-files`.split($/)
20
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_dependency "rspec-expectations"
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency "activerecord", "~> 4.1"
29
+ spec.add_development_dependency "rails", "~> 4.1"
30
+ spec.add_development_dependency "sqlite3"
31
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: toni
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jalyna
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec-expectations
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
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: rspec
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: activerecord
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '4.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '4.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '4.1'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '4.1'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Ruby Authorization Gem using Role Based Access Control
112
+ email:
113
+ - jalyna.schroeder@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - .travis.yml
120
+ - Gemfile
121
+ - LICENSE.txt
122
+ - README.md
123
+ - Rakefile
124
+ - lib/toni.rb
125
+ - lib/toni/anonymous_user.rb
126
+ - lib/toni/builder.rb
127
+ - lib/toni/permission.rb
128
+ - lib/toni/permission_matcher.rb
129
+ - lib/toni/role.rb
130
+ - lib/toni/version.rb
131
+ - spec/spec_helper.rb
132
+ - spec/toni/anonymous_user_spec.rb
133
+ - spec/toni/builder_spec.rb
134
+ - spec/toni/permission_matcher_spec.rb
135
+ - spec/toni/permission_spec.rb
136
+ - spec/toni/role_spec.rb
137
+ - spec/toni_spec.rb
138
+ - toni.gemspec
139
+ homepage: https://github.com/jalyna/toni
140
+ licenses:
141
+ - MIT
142
+ metadata: {}
143
+ post_install_message:
144
+ rdoc_options: []
145
+ require_paths:
146
+ - lib
147
+ required_ruby_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - '>='
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - '>='
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ requirements: []
158
+ rubyforge_project:
159
+ rubygems_version: 2.0.3
160
+ signing_key:
161
+ specification_version: 4
162
+ summary: Enables you to create a centralized authorization rules configuration, similar
163
+ to declarative authorization, but not bound to Ruby on Rails. Internally the Gem
164
+ is using RSpec Matchers.
165
+ test_files:
166
+ - spec/spec_helper.rb
167
+ - spec/toni/anonymous_user_spec.rb
168
+ - spec/toni/builder_spec.rb
169
+ - spec/toni/permission_matcher_spec.rb
170
+ - spec/toni/permission_spec.rb
171
+ - spec/toni/role_spec.rb
172
+ - spec/toni_spec.rb