toni 0.0.1 → 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 +4 -4
- data/.travis.yml +2 -1
- data/Gemfile +4 -1
- data/README.md +104 -5
- data/examples/sinatra/README.md +9 -0
- data/examples/sinatra/app.rb +33 -0
- data/examples/sinatra/config/authorization_rules.rb +7 -0
- data/examples/sinatra/config.ru +2 -0
- data/examples/sinatra/spec/authorization_rules_spec.rb +20 -0
- data/examples/sinatra/spec/spec_helper.rb +10 -0
- data/examples/sinatra/user.rb +7 -0
- data/lib/toni/anonymous_user.rb +1 -1
- data/lib/toni/builder.rb +10 -3
- data/lib/toni/permission.rb +4 -4
- data/lib/toni/permission_matcher.rb +38 -4
- data/lib/toni/role.rb +4 -4
- data/lib/toni/rspec_helper.rb +27 -0
- data/lib/toni/sinatra.rb +33 -0
- data/lib/toni/version.rb +2 -2
- data/lib/toni.rb +15 -15
- data/spec/spec_helper.rb +6 -1
- data/spec/toni/anonymous_user_spec.rb +1 -0
- data/spec/toni/builder_spec.rb +38 -7
- data/spec/toni/permission_matcher_spec.rb +40 -0
- data/spec/toni/permission_spec.rb +1 -0
- data/spec/toni/role_spec.rb +1 -0
- data/spec/toni/rspec_helper_spec.rb +37 -0
- data/spec/toni/sinatra_spec.rb +78 -0
- data/spec/toni_spec.rb +32 -3
- data/toni.gemspec +1 -1
- metadata +16 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ac2b196171e40bf0d69e5c191c4a9435ce3855a
|
4
|
+
data.tar.gz: 587bbdcb7dd9a86db28551388a8efe786b6ceaa6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bdadf5d1db3e86f10963fda52f7b810d2f1ad87c071a0959d871f3f28a9bbac9dae2e28838eeaa7bfb3e4eb9f60ecf7fe88476cb2bff28e00de6415fd940b177
|
7
|
+
data.tar.gz: aa782e08c89471234beb82c2690f29c6ed0f8a10dc9e597e2ef8cd159784bf86d59278daf56e318301d43d6b83324d4c00e5fb6331618e64e2abca87c3752902
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -3,4 +3,7 @@ source 'https://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in toni.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
gem "codeclimate-test-reporter", group: :test, require: nil
|
6
|
+
gem "codeclimate-test-reporter", group: :test, require: nil
|
7
|
+
gem "sqlite3", group: :test, platform: :ruby
|
8
|
+
gem "jdbc-sqlite3", group: :test, platform: :jruby
|
9
|
+
gem "activerecord-jdbcsqlite3-adapter", group: :test, platform: :jruby
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# Toni
|
2
|
-
[](https://travis-ci.org/jalyna/toni) [](https://codeclimate.com/github/jalyna/toni) [](http://inch-ci.org/github/jalyna/toni)
|
2
|
+
[](http://badge.fury.io/rb/toni) [](https://travis-ci.org/jalyna/toni) [](https://codeclimate.com/github/jalyna/toni) [](https://codeclimate.com/github/jalyna/toni) [](http://inch-ci.org/github/jalyna/toni)
|
3
3
|
|
4
4
|
Toni enables you to create a centralized authorization rules configuration with a readable DSL,
|
5
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**.
|
6
|
+
Internally the Gem is using RSpec Matchers. You can use Toni with **[Sinatra](#sinatra)** and **[Ruby on Rails](#ruby-on-rails)**.
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
@@ -23,14 +23,113 @@ Or install it yourself as:
|
|
23
23
|
|
24
24
|
### Setup Authorization Rules
|
25
25
|
|
26
|
-
|
26
|
+
To setup the rules that your toni uses you have to create a `authorization_rules.rb` file e.g. in your config folder:
|
27
27
|
|
28
|
-
|
28
|
+
```ruby
|
29
|
+
# Guest role gets automatically assigned if you don't have a current_user
|
30
|
+
role :guest do
|
31
|
+
has_permission_on :books, to: :read
|
32
|
+
end
|
29
33
|
|
30
|
-
|
34
|
+
role :author do
|
35
|
+
has_permission_on :books, to: [:create, :read, :update, :delete] do
|
36
|
+
expect_attribute :author_id { eq(current_user.id) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
role :admin do
|
41
|
+
has_permission_on :books, to: [:create, :read, :update, :delete]
|
42
|
+
has_permission_on :users, to: :delete do
|
43
|
+
expect_attribute :id { not.eq(current_user.id) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
### Assign Roles
|
49
|
+
|
50
|
+
To provide roles it is necessary to pass a `current_user` that provides a `role_symbols` method.
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
class User
|
54
|
+
def role_symbols
|
55
|
+
[:user, :admin]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
Toni.current_user = User.new
|
60
|
+
```
|
61
|
+
|
62
|
+
What logic this method contains is up to you.
|
31
63
|
|
32
64
|
### Sinatra
|
33
65
|
|
66
|
+
The Toni Sinatra Module provides some usefule helpers and an error handling which can be useful
|
67
|
+
if you want to map not authorized errors. And there is a `permitted_to` method where you can pass a block that gets executed when the current user has the demanded permissions.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
require "toni/sinatra"
|
71
|
+
|
72
|
+
class AuthorizationApp < Sinatra::Base
|
73
|
+
# Register Toni Sinatra
|
74
|
+
register Toni::Sinatra
|
75
|
+
|
76
|
+
before do
|
77
|
+
# Set user after authentication
|
78
|
+
Toni.current_user = User.new
|
79
|
+
end
|
80
|
+
|
81
|
+
not_authorized do |e|
|
82
|
+
# Map NotAuthorizedError to 403
|
83
|
+
halt 403
|
84
|
+
end
|
85
|
+
|
86
|
+
set :show_exceptions, false
|
87
|
+
|
88
|
+
get '/' do
|
89
|
+
# This won't throw an exception, remove bang: false if you
|
90
|
+
# want that the not_authorized error handler is called
|
91
|
+
permitted_to(:read, :books, bang: false) do
|
92
|
+
"You can read books!"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
get '/another_page' do
|
97
|
+
without_authorization do
|
98
|
+
"Hello world"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
```
|
103
|
+
|
104
|
+
A more detailed example can be found in [examples/sinatra](examples/sinatra).
|
105
|
+
|
106
|
+
### Testing with RSpec
|
107
|
+
|
108
|
+
To setup Toni's RspecHelper you have to change `spec_helper.rb`:
|
109
|
+
```ruby
|
110
|
+
require "toni/rspec_helper"
|
111
|
+
RSpec.configure { |c| c.include Toni::RSpecHelper }
|
112
|
+
```
|
113
|
+
|
114
|
+
Then you are able to test permissions with following matcher:
|
115
|
+
```ruby
|
116
|
+
expect(user).to have_permission_on :books, to: :read
|
117
|
+
expect(user).to_not have_permission_on :books, to: :create
|
118
|
+
```
|
119
|
+
|
120
|
+
By default your specs are running with authorization. If you want to exclude parts or execute with a specific user you can use:
|
121
|
+
```ruby
|
122
|
+
without_authorization do
|
123
|
+
book.create
|
124
|
+
end
|
125
|
+
|
126
|
+
with_user(user) do
|
127
|
+
book.save
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
### Ruby on Rails
|
132
|
+
|
34
133
|
TODO: Write usage instructions here
|
35
134
|
|
36
135
|
## Contributing
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'toni'
|
2
|
+
require 'toni/sinatra'
|
3
|
+
require 'sinatra'
|
4
|
+
require 'CGI'
|
5
|
+
require './user'
|
6
|
+
|
7
|
+
class AuthorizationApp < Sinatra::Base
|
8
|
+
register Toni::Sinatra
|
9
|
+
|
10
|
+
before do
|
11
|
+
# Set user after authentication
|
12
|
+
Toni.current_user = User.new
|
13
|
+
end
|
14
|
+
|
15
|
+
not_authorized do |e|
|
16
|
+
# Map NotAuthorizedError to 403
|
17
|
+
halt 403, CGI.escapeHTML(e.message)
|
18
|
+
end
|
19
|
+
|
20
|
+
set :show_exceptions, false
|
21
|
+
|
22
|
+
get '/' do
|
23
|
+
permitted_to(:read, :books, bang: false) do
|
24
|
+
"You can read books!"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
get '/create' do
|
29
|
+
permitted_to(:create, :books) do
|
30
|
+
"You can create books"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Authorization Rules" do
|
4
|
+
describe "user" do
|
5
|
+
it "is permitted to read books" do
|
6
|
+
user = double("user", role_symbols: [:user])
|
7
|
+
expect(user).to have_permission_on :books, to: :read
|
8
|
+
end
|
9
|
+
it "is not permitted to create books" do
|
10
|
+
user = double("user", role_symbols: [:user])
|
11
|
+
expect(user).to_not have_permission_on :books, to: :create
|
12
|
+
end
|
13
|
+
end
|
14
|
+
describe "admin" do
|
15
|
+
it "is permitted to create books" do
|
16
|
+
user = double("user", role_symbols: [:admin])
|
17
|
+
expect(user).to have_permission_on :books, to: :create
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/toni/anonymous_user.rb
CHANGED
data/lib/toni/builder.rb
CHANGED
@@ -2,7 +2,7 @@ require "toni/role"
|
|
2
2
|
require "toni/permission"
|
3
3
|
require "rspec/matchers"
|
4
4
|
|
5
|
-
|
5
|
+
module Toni
|
6
6
|
class Builder
|
7
7
|
|
8
8
|
attr_reader :roles
|
@@ -46,8 +46,7 @@ class Toni
|
|
46
46
|
attr_reader :permission
|
47
47
|
|
48
48
|
def initialize(resource_name, options={}, &block)
|
49
|
-
options[:to]
|
50
|
-
@permission = Permission.new(resource_name, options[:to])
|
49
|
+
@permission = Permission.new(resource_name, [*options[:to]])
|
51
50
|
if block_given?
|
52
51
|
instance_eval &block
|
53
52
|
end
|
@@ -84,6 +83,14 @@ class Toni
|
|
84
83
|
Toni.current_user
|
85
84
|
end
|
86
85
|
|
86
|
+
def not
|
87
|
+
Toni::PermissionMatcher::NotMatcher.new
|
88
|
+
end
|
89
|
+
|
90
|
+
def permitted_to(activity)
|
91
|
+
Toni::PermissionMatcher::PermittedToMatcher.new(activity)
|
92
|
+
end
|
93
|
+
|
87
94
|
end
|
88
95
|
|
89
96
|
end
|
data/lib/toni/permission.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
require "toni/permission_matcher"
|
2
2
|
|
3
|
-
|
3
|
+
module Toni
|
4
4
|
class Permission
|
5
5
|
|
6
6
|
attr_reader :resource_name, :matchers, :activities
|
7
7
|
|
8
8
|
def initialize(resource_name, activities = [])
|
9
|
-
@resource_name
|
10
|
-
@matchers
|
11
|
-
@activities
|
9
|
+
@resource_name = resource_name
|
10
|
+
@matchers = []
|
11
|
+
@activities = activities
|
12
12
|
end
|
13
13
|
|
14
14
|
def add_matcher(method_name, matcher, is_attr = false)
|
@@ -1,12 +1,12 @@
|
|
1
|
-
|
1
|
+
module Toni
|
2
2
|
class PermissionMatcher
|
3
3
|
|
4
4
|
attr_reader :method_name, :matcher, :is_attr
|
5
5
|
|
6
6
|
def initialize(method_name, matcher, is_attr = false)
|
7
|
-
@method_name
|
8
|
-
@matcher
|
9
|
-
@is_attr
|
7
|
+
@method_name = method_name
|
8
|
+
@matcher = matcher
|
9
|
+
@is_attr = is_attr
|
10
10
|
end
|
11
11
|
|
12
12
|
def matches?(object)
|
@@ -16,5 +16,39 @@ class Toni
|
|
16
16
|
matcher.matches?(object.send(method_name))
|
17
17
|
end
|
18
18
|
|
19
|
+
class NotMatcher
|
20
|
+
attr_reader :matcher
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@matcher = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing(method_name, *args)
|
27
|
+
builder = Toni::Builder::ExpectationBuilder.new
|
28
|
+
if builder.respond_to?(method_name)
|
29
|
+
@matcher = builder.send(method_name, *args)
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def matches?(object)
|
36
|
+
raise Toni::MissingMatcherError if @matcher.nil?
|
37
|
+
!@matcher.matches?(object)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class PermittedToMatcher
|
42
|
+
|
43
|
+
def initialize(activity)
|
44
|
+
@activity = activity
|
45
|
+
end
|
46
|
+
|
47
|
+
def matches?(object)
|
48
|
+
Toni.permitted_to?(@activity, object)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
19
53
|
end
|
20
54
|
end
|
data/lib/toni/role.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
|
1
|
+
module Toni
|
2
2
|
class Role
|
3
3
|
|
4
4
|
attr_reader :role_symbol, :ancestors, :permissions
|
5
5
|
|
6
6
|
def initialize(role_symbol)
|
7
|
-
@role_symbol
|
8
|
-
@ancestors
|
9
|
-
@permissions
|
7
|
+
@role_symbol = role_symbol
|
8
|
+
@ancestors = []
|
9
|
+
@permissions = []
|
10
10
|
end
|
11
11
|
|
12
12
|
def add_ancestor(role_symbol)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rspec/expectations'
|
2
|
+
require 'toni'
|
3
|
+
|
4
|
+
module Toni
|
5
|
+
module RSpecHelper
|
6
|
+
extend RSpec::Matchers::DSL
|
7
|
+
|
8
|
+
def with_user(user, &block)
|
9
|
+
Toni.current_user = user
|
10
|
+
result = yield
|
11
|
+
Toni.current_user = nil
|
12
|
+
result
|
13
|
+
end
|
14
|
+
|
15
|
+
def without_authorization(&block)
|
16
|
+
Toni.without_authorization(&block)
|
17
|
+
end
|
18
|
+
|
19
|
+
matcher :have_permission_on do |resource_or_name, options = {}|
|
20
|
+
match do |user|
|
21
|
+
with_user(user) do
|
22
|
+
[*options[:to]].all? { |a| Toni.permitted_to?(a, resource_or_name) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/toni/sinatra.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
module Toni
|
4
|
+
module Sinatra
|
5
|
+
module AuthorizationHelper
|
6
|
+
def permitted_to(activity, resource_or_name, options={}, &block)
|
7
|
+
options[:bang] = true unless options.key?(:bang)
|
8
|
+
if Toni.permitted_to?(activity, resource_or_name, options)
|
9
|
+
block.call if block_given?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def without_authorization(&block)
|
14
|
+
Toni.without_authorization(&block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module AuthorizationErrorHandler
|
19
|
+
def not_authorized(&block)
|
20
|
+
error do
|
21
|
+
if env['sinatra.error'].instance_of? Toni::NotAuthorizedError
|
22
|
+
instance_exec env['sinatra.error'], &block if block_given?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.registered(app)
|
29
|
+
app.helpers AuthorizationHelper
|
30
|
+
app.register AuthorizationErrorHandler
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/toni/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.0.
|
1
|
+
module Toni
|
2
|
+
VERSION = "0.0.2"
|
3
3
|
end
|
data/lib/toni.rb
CHANGED
@@ -2,36 +2,35 @@ require "toni/version"
|
|
2
2
|
require "toni/anonymous_user"
|
3
3
|
require "toni/builder"
|
4
4
|
|
5
|
-
|
6
|
-
AUTH_FILE =
|
5
|
+
module Toni
|
6
|
+
AUTH_FILE = "config/authorization_rules.rb"
|
7
7
|
|
8
8
|
class InvalidCurrentUserError < StandardError; end
|
9
9
|
class NoAuthorizationContextProvidedError < StandardError; end
|
10
10
|
class NoMethodForMatcherError < StandardError; end
|
11
11
|
class NotAuthorizedError < StandardError; end
|
12
|
+
class MissingMatcherError < StandardError; end
|
12
13
|
|
13
14
|
class << self
|
14
|
-
@@without_authorization = false
|
15
|
-
|
16
15
|
def current_user
|
17
|
-
|
18
|
-
|
16
|
+
@curent_user ||= nil
|
17
|
+
@curent_user || anonymous_user
|
19
18
|
end
|
20
19
|
|
21
20
|
def current_user=(user)
|
22
21
|
raise InvalidCurrentUserError if !user.nil? && !user.respond_to?(:role_symbols)
|
23
|
-
|
22
|
+
@curent_user = user
|
24
23
|
end
|
25
24
|
|
26
25
|
def roles
|
27
|
-
|
26
|
+
@roles ||= build
|
28
27
|
end
|
29
28
|
|
30
29
|
def permitted_to?(activity, resource_or_name, options={})
|
31
|
-
return true if
|
30
|
+
return true if @without_authorization
|
32
31
|
permitted = current_roles.any?{ |r| r.permitted_to?(activity, resource_or_name, options) }
|
33
32
|
if options[:bang] && !permitted
|
34
|
-
raise NotAuthorizedError.new("#{current_user.inspect} is not allowed to #{activity} on #{resource_or_name.inspect}")
|
33
|
+
raise NotAuthorizedError.new("#{current_user.to_s} with #{current_user.role_symbols.inspect} is not allowed to #{activity} on #{resource_or_name.inspect}")
|
35
34
|
end
|
36
35
|
|
37
36
|
permitted
|
@@ -42,9 +41,10 @@ class Toni
|
|
42
41
|
end
|
43
42
|
|
44
43
|
def without_authorization(&block)
|
45
|
-
|
46
|
-
|
47
|
-
|
44
|
+
@without_authorization = true
|
45
|
+
result = block_given? ? yield : nil
|
46
|
+
@without_authorization = false
|
47
|
+
result
|
48
48
|
end
|
49
49
|
|
50
50
|
private
|
@@ -58,7 +58,7 @@ class Toni
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def anonymous_user
|
61
|
-
|
61
|
+
@anonymous_user ||= AnonymousUser.new
|
62
62
|
end
|
63
63
|
end
|
64
|
-
end
|
64
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,7 +3,12 @@ CodeClimate::TestReporter.start
|
|
3
3
|
|
4
4
|
require "active_record"
|
5
5
|
|
6
|
-
|
6
|
+
if ENV["RUBY_VERSION"].include?("jruby")
|
7
|
+
ActiveRecord::Base.establish_connection(:adapter => "jdbcsqlite3", :database => ":memory:")
|
8
|
+
else
|
9
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
10
|
+
end
|
11
|
+
|
7
12
|
ActiveRecord::Schema.define do
|
8
13
|
self.verbose = false
|
9
14
|
|
data/spec/toni/builder_spec.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "spec_helper"
|
1
2
|
require "toni/builder"
|
2
3
|
|
3
4
|
describe Toni::Builder do
|
@@ -31,15 +32,15 @@ describe Toni::Builder::RoleBuilder do
|
|
31
32
|
|
32
33
|
describe :includes do
|
33
34
|
it "calls add_ancestor for the given role_symbol" do
|
35
|
+
expect(builder.role).to receive(:add_ancestor).with(:parent_user)
|
34
36
|
builder.includes(:parent_user)
|
35
|
-
allow(builder.role).to receive(:add_ancestor).with(:parent_user)
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
39
40
|
describe :has_permission_on do
|
40
41
|
it "calls add_permission on role" do
|
42
|
+
expect(builder.role).to receive(:add_permission)
|
41
43
|
builder.has_permission_on(:my_resource)
|
42
|
-
allow(builder.role).to receive(:add_permission)
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
@@ -49,6 +50,17 @@ describe Toni::Builder::PermissionBuilder do
|
|
49
50
|
|
50
51
|
let(:builder) { Toni::Builder::PermissionBuilder.new(:resource_name) }
|
51
52
|
|
53
|
+
describe :initialize do
|
54
|
+
it "sets the activtities" do
|
55
|
+
builder = Toni::Builder::PermissionBuilder.new(:resource_name, to: [:create, :read])
|
56
|
+
expect(builder.permission.activities).to eq([:create, :read])
|
57
|
+
end
|
58
|
+
it "sets single activtities" do
|
59
|
+
builder = Toni::Builder::PermissionBuilder.new(:resource_name, to: :read)
|
60
|
+
expect(builder.permission.activities).to eq([:read])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
52
64
|
describe :permission do
|
53
65
|
it "is a Permission" do
|
54
66
|
expect(builder.permission).to be_instance_of(Toni::Permission)
|
@@ -57,17 +69,17 @@ describe Toni::Builder::PermissionBuilder do
|
|
57
69
|
|
58
70
|
describe :expect_attribute do
|
59
71
|
it "calls expect_method with is_attribute true" do
|
72
|
+
expect(builder).to receive(:expect_method).with(nil, true)
|
60
73
|
builder.expect_attribute(nil)
|
61
|
-
allow(builder).to receive(:expect_method).with(nil, true)
|
62
74
|
end
|
63
75
|
end
|
64
76
|
|
65
77
|
describe :expect_method do
|
66
78
|
it "calls add_matcher on permission per method_name" do
|
79
|
+
expect(builder.permission).to receive(:add_matcher).with(:foo, anything, false)
|
80
|
+
expect(builder.permission).to receive(:add_matcher).with(:bar, anything, false)
|
67
81
|
builder.expect_method(:foo) { nil }
|
68
82
|
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
83
|
end
|
72
84
|
end
|
73
85
|
|
@@ -78,7 +90,7 @@ describe Toni::Builder::ExpectationBuilder do
|
|
78
90
|
let(:builder) { Toni::Builder::ExpectationBuilder.new }
|
79
91
|
|
80
92
|
describe :execute do
|
81
|
-
it "calls block
|
93
|
+
it "calls block lazely" do
|
82
94
|
double = double()
|
83
95
|
builder = Toni::Builder::ExpectationBuilder.new do
|
84
96
|
double.call
|
@@ -90,8 +102,8 @@ describe Toni::Builder::ExpectationBuilder do
|
|
90
102
|
|
91
103
|
describe "uses rspec matchers" do
|
92
104
|
it "calls rspec matcher methods" do
|
93
|
-
builder.be_nil
|
94
105
|
allow(RSpec::Matchers).to receive(:be_nil)
|
106
|
+
builder.be_nil
|
95
107
|
end
|
96
108
|
|
97
109
|
it "sets the called matcher" do
|
@@ -102,4 +114,23 @@ describe Toni::Builder::ExpectationBuilder do
|
|
102
114
|
end
|
103
115
|
end
|
104
116
|
|
117
|
+
describe :not do
|
118
|
+
it "should create a NotMatcher" do
|
119
|
+
expect(builder.not).to be_instance_of(Toni::PermissionMatcher::NotMatcher)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe :permitted_to do
|
124
|
+
it "should create a PermittedToMatcher" do
|
125
|
+
expect(builder.permitted_to(:read)).to be_instance_of(Toni::PermissionMatcher::PermittedToMatcher)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe :current_user do
|
130
|
+
it "gets the toni user" do
|
131
|
+
expect(Toni).to receive(:current_user)
|
132
|
+
builder.current_user
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
105
136
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "spec_helper"
|
1
2
|
require "toni/permission_matcher"
|
2
3
|
require "toni"
|
3
4
|
require "ostruct"
|
@@ -77,4 +78,43 @@ describe Toni::PermissionMatcher do
|
|
77
78
|
end
|
78
79
|
end
|
79
80
|
|
81
|
+
end
|
82
|
+
|
83
|
+
describe Toni::PermissionMatcher::NotMatcher do
|
84
|
+
|
85
|
+
let(:not_matcher) { Toni::PermissionMatcher::NotMatcher.new }
|
86
|
+
|
87
|
+
describe :method_missing do
|
88
|
+
it "looks up method in ExpectationBuilder" do
|
89
|
+
expect { not_matcher.be_truthy }.to_not raise_error
|
90
|
+
end
|
91
|
+
it "throws error when method does not exist" do
|
92
|
+
expect { not_matcher.that_does_not_exist }.to raise_error
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe :matches? do
|
97
|
+
it "raises error when matcher is nil" do
|
98
|
+
expect { not_matcher.matches?(nil) }.to raise_error(Toni::MissingMatcherError)
|
99
|
+
end
|
100
|
+
it "uses matches method of matcher and flips the boolean" do
|
101
|
+
not_matcher.eq(nil)
|
102
|
+
expect(not_matcher.matches?(nil)).to eq(false)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
describe Toni::PermissionMatcher::PermittedToMatcher do
|
109
|
+
|
110
|
+
let(:permitted_to_matcher) { Toni::PermissionMatcher::PermittedToMatcher.new(:read) }
|
111
|
+
|
112
|
+
describe :matches? do
|
113
|
+
it "calls Toni.permitted_to? for given attribute" do
|
114
|
+
double = double
|
115
|
+
expect(Toni).to receive(:permitted_to?).with(:read, double)
|
116
|
+
permitted_to_matcher.matches?(double)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
80
120
|
end
|
data/spec/toni/role_spec.rb
CHANGED
@@ -0,0 +1,37 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "toni/rspec_helper"
|
3
|
+
|
4
|
+
describe Toni::RSpecHelper do
|
5
|
+
include Toni::RSpecHelper
|
6
|
+
|
7
|
+
describe :without_authorization do
|
8
|
+
it "calls Toni without_authorization" do
|
9
|
+
expect(Toni).to receive(:without_authorization)
|
10
|
+
without_authorization
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe :with_user do
|
15
|
+
it "calls block with given user and return the result of the block" do
|
16
|
+
user = double("user")
|
17
|
+
expect(Toni).to receive(:current_user=).with(user)
|
18
|
+
expect(Toni).to receive(:current_user=).with(nil)
|
19
|
+
expect(with_user(user) { 1 }).to eq(1)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "have_permission_on matcher" do
|
24
|
+
it "returns true if all permissions are true for the given activities" do
|
25
|
+
user = double("user", role_symbols: [])
|
26
|
+
expect(Toni).to receive(:permitted_to?).with(:create, :books) { true }
|
27
|
+
expect(Toni).to receive(:permitted_to?).with(:read, :books) { true }
|
28
|
+
expect(user).to have_permission_on(:books, to: [:create, :read])
|
29
|
+
end
|
30
|
+
it "returns false if one permissions is not true for the given activities" do
|
31
|
+
user = double("user", role_symbols: [])
|
32
|
+
expect(Toni).to receive(:permitted_to?).with(:create, :books) { true }
|
33
|
+
expect(Toni).to receive(:permitted_to?).with(:read, :books) { false }
|
34
|
+
expect(user).not_to have_permission_on(:books, to: [:create, :read])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "toni/sinatra"
|
3
|
+
require "rack/test"
|
4
|
+
|
5
|
+
describe Toni::Sinatra::AuthorizationHelper do
|
6
|
+
let(:helper) {
|
7
|
+
Class.new do
|
8
|
+
include Toni::Sinatra::AuthorizationHelper
|
9
|
+
end.new
|
10
|
+
}
|
11
|
+
|
12
|
+
describe :permitted_to do
|
13
|
+
it "calls permitted_to? of toni, sets bang to true and calls the given block" do
|
14
|
+
double = double("block")
|
15
|
+
expect(Toni).to receive(:permitted_to?).with(:read, :books, bang: true) { true }
|
16
|
+
expect(double).to receive(:call)
|
17
|
+
helper.permitted_to(:read, :books) do
|
18
|
+
double.call
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "does not call the block if it is not permitted to" do
|
23
|
+
double = double("block")
|
24
|
+
expect(Toni).to receive(:permitted_to?).with(:read, :books, bang: false) { false }
|
25
|
+
expect(double).to_not receive(:call)
|
26
|
+
helper.permitted_to(:read, :books, bang: false) do
|
27
|
+
double.call
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe :without_authorization do
|
33
|
+
it "calls toni without_authorization" do
|
34
|
+
expect(Toni).to receive(:without_authorization)
|
35
|
+
helper.without_authorization
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe Toni::Sinatra::AuthorizationErrorHandler do
|
41
|
+
include Rack::Test::Methods
|
42
|
+
|
43
|
+
let(:app) {
|
44
|
+
Class.new(Sinatra::Base) do
|
45
|
+
register Toni::Sinatra
|
46
|
+
|
47
|
+
set :show_exceptions, false
|
48
|
+
set :raise_errors, false
|
49
|
+
|
50
|
+
not_authorized do |e|
|
51
|
+
halt 403, e.message
|
52
|
+
end
|
53
|
+
|
54
|
+
get '/' do
|
55
|
+
permitted_to(:read, :books) do
|
56
|
+
"permitted"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
}
|
61
|
+
|
62
|
+
describe :not_authorized do
|
63
|
+
it "does not call error handler when permitted to" do
|
64
|
+
allow(Toni).to receive(:permitted_to?).with(:read, :books, anything) { true }
|
65
|
+
get '/'
|
66
|
+
expect(last_response.body).to eq("permitted")
|
67
|
+
end
|
68
|
+
|
69
|
+
it "calls error handler when permitted to" do
|
70
|
+
allow(Toni).to receive(:permitted_to?).with(:read, :books, anything) do
|
71
|
+
raise Toni::NotAuthorizedError.new("not authorized")
|
72
|
+
end
|
73
|
+
get '/'
|
74
|
+
expect(last_response.status).to eq(403)
|
75
|
+
expect(last_response.body).to eq("not authorized")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/spec/toni_spec.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "spec_helper"
|
1
2
|
require "toni"
|
2
3
|
require "ostruct"
|
3
4
|
|
@@ -6,6 +7,19 @@ describe Toni do
|
|
6
7
|
let(:role_symbols) { [] }
|
7
8
|
let(:current_user) { OpenStruct.new(role_symbols: role_symbols) }
|
8
9
|
|
10
|
+
before do
|
11
|
+
allow(File).to receive(:read).with(Toni::AUTH_FILE) do
|
12
|
+
<<-eos
|
13
|
+
role :guest do
|
14
|
+
has_permission_on :x, to: [:read, :delete]
|
15
|
+
end
|
16
|
+
role :user do
|
17
|
+
has_permission_on :test, to: [:read, :create]
|
18
|
+
end
|
19
|
+
eos
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
9
23
|
describe ".current_user" do
|
10
24
|
it "has a anonymous user as default" do
|
11
25
|
expect(Toni.current_user).to be_instance_of(Toni::AnonymousUser)
|
@@ -29,15 +43,30 @@ describe Toni do
|
|
29
43
|
end
|
30
44
|
|
31
45
|
describe ".roles" do
|
32
|
-
|
46
|
+
it "reads roles from auth_file" do
|
47
|
+
expect(Toni.roles.keys).to eq([:guest, :user])
|
48
|
+
end
|
33
49
|
end
|
34
50
|
|
35
51
|
describe ".current_roles" do
|
36
|
-
|
52
|
+
let(:role_symbols) { [:user] }
|
53
|
+
it "gets the roles that are in the role_symbols methods" do
|
54
|
+
Toni.current_user = current_user
|
55
|
+
expect(Toni.current_roles).to eq([Toni.roles[:user]])
|
56
|
+
end
|
37
57
|
end
|
38
58
|
|
39
59
|
describe ".without_authorization" do
|
40
|
-
|
60
|
+
it "executes block without authorization and returns result of the given block" do
|
61
|
+
with_authorization = Toni.permitted_to?(:something, :test)
|
62
|
+
without_authorization = false
|
63
|
+
expect(Toni.without_authorization do
|
64
|
+
without_authorization = Toni.permitted_to?(:something, :test)
|
65
|
+
3
|
66
|
+
end).to eq(3)
|
67
|
+
expect(with_authorization).to eq(false)
|
68
|
+
expect(without_authorization).to eq(true)
|
69
|
+
end
|
41
70
|
end
|
42
71
|
|
43
72
|
describe ".permitted_to?" do
|
data/toni.gemspec
CHANGED
@@ -27,5 +27,5 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency "rspec"
|
28
28
|
spec.add_development_dependency "activerecord", "~> 4.1"
|
29
29
|
spec.add_development_dependency "rails", "~> 4.1"
|
30
|
-
spec.add_development_dependency "
|
30
|
+
spec.add_development_dependency "sinatra"
|
31
31
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: toni
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jalyna
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec-expectations
|
@@ -95,7 +95,7 @@ dependencies:
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '4.1'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: sinatra
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - '>='
|
@@ -121,12 +121,21 @@ files:
|
|
121
121
|
- LICENSE.txt
|
122
122
|
- README.md
|
123
123
|
- Rakefile
|
124
|
+
- examples/sinatra/README.md
|
125
|
+
- examples/sinatra/app.rb
|
126
|
+
- examples/sinatra/config.ru
|
127
|
+
- examples/sinatra/config/authorization_rules.rb
|
128
|
+
- examples/sinatra/spec/authorization_rules_spec.rb
|
129
|
+
- examples/sinatra/spec/spec_helper.rb
|
130
|
+
- examples/sinatra/user.rb
|
124
131
|
- lib/toni.rb
|
125
132
|
- lib/toni/anonymous_user.rb
|
126
133
|
- lib/toni/builder.rb
|
127
134
|
- lib/toni/permission.rb
|
128
135
|
- lib/toni/permission_matcher.rb
|
129
136
|
- lib/toni/role.rb
|
137
|
+
- lib/toni/rspec_helper.rb
|
138
|
+
- lib/toni/sinatra.rb
|
130
139
|
- lib/toni/version.rb
|
131
140
|
- spec/spec_helper.rb
|
132
141
|
- spec/toni/anonymous_user_spec.rb
|
@@ -134,6 +143,8 @@ files:
|
|
134
143
|
- spec/toni/permission_matcher_spec.rb
|
135
144
|
- spec/toni/permission_spec.rb
|
136
145
|
- spec/toni/role_spec.rb
|
146
|
+
- spec/toni/rspec_helper_spec.rb
|
147
|
+
- spec/toni/sinatra_spec.rb
|
137
148
|
- spec/toni_spec.rb
|
138
149
|
- toni.gemspec
|
139
150
|
homepage: https://github.com/jalyna/toni
|
@@ -169,4 +180,6 @@ test_files:
|
|
169
180
|
- spec/toni/permission_matcher_spec.rb
|
170
181
|
- spec/toni/permission_spec.rb
|
171
182
|
- spec/toni/role_spec.rb
|
183
|
+
- spec/toni/rspec_helper_spec.rb
|
184
|
+
- spec/toni/sinatra_spec.rb
|
172
185
|
- spec/toni_spec.rb
|