toni 0.0.1

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: 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