permission_policy 0.0.6 → 0.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d197b0a408448eb634f15c4229434f643229daca
4
- data.tar.gz: a3861829e10f0738d884080167e91f76cb802736
3
+ metadata.gz: cf58d8db5cb145457f2477e95784d7083d1ae3a9
4
+ data.tar.gz: 6186f34bf9b8171db1b061123e37d78c975c25b2
5
5
  SHA512:
6
- metadata.gz: aa90267b5878dbdad8f3140a0ac8f5e08a2db1e8aa06e8d6e742eb36d07491a4fc91989d23a7b6844e7bf9fb42f73a4019ba1e620c105fff55624bb69405ca88
7
- data.tar.gz: 12974cc8b86fabea2530d79872816bcd1bc94810d9fcbc1270f2fe193921b0b7f92ba93d6bae8938cd2b126b3befa36cc8b0468769522c062402169c774a6cd7
6
+ metadata.gz: a01d8c7b01188ab26ad30d5ee23ea8e7c7f4c25c71f88a2bd5310849d09c6a3c2da8f30b12d091cd6fd0ca62f0133c435ad019c30dc58df931314ae339f481fe
7
+ data.tar.gz: 14fdc5e33244dd581c6f48cf940b24e1bec4f1297e526246c7a81457570c1b2b5625098256d3d2c58d76b24ee8b9ad0810313485f5921beb0debaff7d8d59f9d
data/CHANGELOG.md CHANGED
@@ -1,4 +1,8 @@
1
1
 
2
+ # 0.1.0
3
+
4
+ * [REFACTORING] change the way *configuration* is handled (breaking changes)
5
+
2
6
  # 0.0.6
3
7
 
4
8
  * [ENHANCEMENT] moar convenience with `skip_verify_authorization`
data/README.md CHANGED
@@ -6,6 +6,21 @@
6
6
  * dependencies
7
7
 
8
8
 
9
+ ## Authorization is hard
10
+
11
+ There are plenty of diferent solutions to this problem.
12
+ Because the requirements can be very difficult and as the system grows the problems become even worse. Exspecially when you need to support change.
13
+ The hardest part may be thight coupling and issues with encapsulation through the whole application.
14
+ To avoid repetitive and grwoing if/else branches you want a single responsible system.
15
+
16
+ In general, the permission policy defines and controls whether a current **object** (usually the user) can perform a specific **action** on a given **subject**. This decision is commonly based on one or more
17
+ factors:
18
+
19
+ * role
20
+ * type (or a set of attributes)
21
+ * enabled features / areas of the application
22
+
23
+
9
24
  ## Installation
10
25
 
11
26
  Add this line to your application's Gemfile:
@@ -122,6 +137,13 @@ You can extend the permission policy by:
122
137
  - implement new permission strategies, which help the policy to find the 'decider'
123
138
 
124
139
 
140
+ ## possible ideas/improvements:
141
+
142
+ - support skip_verify_authorization only:/except: [:actions]
143
+ - register features and roles in the policy
144
+ - raise NoSuchFeature
145
+ - get available "permissions" for role/subject/feature
146
+
125
147
  ## Contributing
126
148
 
127
149
  1. Fork it ( https://github.com/[my-github-username]/permission_policy/fork )
@@ -4,8 +4,9 @@ module PermissionPolicy
4
4
 
5
5
  def initialize(context)
6
6
  @preconditions = []
7
+ @context = context
7
8
 
8
- PermissionPolicy.preconditions.each do |precondition|
9
+ context.authorization_preconditions.each do |precondition|
9
10
  set! precondition, context.public_send(precondition)
10
11
  @preconditions << precondition
11
12
  end
@@ -40,7 +41,9 @@ module PermissionPolicy
40
41
 
41
42
  # Finds the matching strategy which can decide if the action is allowed by lazy checking
42
43
  def strategy_for(*args)
43
- PermissionPolicy.strategies.lazy.map { |klass| Strategies.const_get(klass).new(self, *args) }.find(&:match?)
44
+ @context.authorization_strategies.lazy.map do |klass|
45
+ Strategies.const_get(klass).new(self, *args)
46
+ end.find(&:match?)
44
47
  end
45
48
 
46
49
  def set!(var, value)
@@ -1,38 +1,4 @@
1
1
  module PermissionPolicy
2
- class Configuration < OpenStruct
3
- def preconditions
4
- precondition_attributes || [:current_user]
5
- end
6
-
7
- def strategies
8
- strategy_order || [:UnknownStrategy]
9
- end
10
-
11
- def verification
12
- verify_authorization || false
13
- end
14
- end
15
-
16
- class << self
17
- attr_accessor :configuration
18
-
19
- extend Forwardable
20
- delegate [:preconditions, :strategies, :verification] => :config
21
-
22
- def configure
23
- yield(config)
24
- end
25
-
26
- def config
27
- self.configuration ||= Configuration.new
28
- end
29
-
30
- def authorize_with(*args)
31
- configure { |c| c.precondition_attributes = *args }
32
- end
33
-
34
- def verify_authorization!(setting)
35
- configure { |c| c.verify_authorization = setting }
36
- end
2
+ class Configuration
37
3
  end
38
4
  end
@@ -3,16 +3,20 @@ require 'active_support/concern'
3
3
  module PermissionPolicy
4
4
  module ControllerAdditions
5
5
  module ClassMethods
6
- def authorize_with(*args)
7
- PermissionPolicy.authorize_with(*args)
6
+ def authorize_with(*preconditions)
7
+ define_method('authorization_preconditions') { preconditions }
8
8
  end
9
9
 
10
10
  def verify_authorization!
11
- PermissionPolicy.verify_authorization!(true)
11
+ define_method('authorization_verification?') { true }
12
12
  end
13
13
 
14
14
  def skip_verify_authorization
15
- PermissionPolicy.verify_authorization!(false)
15
+ define_method('authorization_verification?') { false }
16
+ end
17
+
18
+ def authorization_strategies(*strategies)
19
+ define_method('authorization_strategies') { strategies }
16
20
  end
17
21
  end
18
22
 
@@ -23,7 +27,7 @@ module PermissionPolicy
23
27
  helper_method :allowed?
24
28
  delegate :allowed?, to: :permission_policy
25
29
  delegate :authorize!, to: :permission_policy
26
- after_action -> { verify_authorization if PermissionPolicy.verification }
30
+ after_action -> { verify_authorization if authorization_verification? }
27
31
  end
28
32
 
29
33
  def permission_policy
@@ -1,3 +1,3 @@
1
1
  module PermissionPolicy
2
- VERSION = '0.0.6'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -1,13 +1,9 @@
1
1
  module PermissionPolicy
2
2
  RSpec.describe 'Authorization' do
3
- before do
4
- PermissionPolicy.authorize_with :my_user, :my_account
5
- end
6
-
7
- subject { PermissionPolicy::Authorization.new(context) }
3
+ subject { PermissionPolicy::Authorization.new(controller_context) }
8
4
 
9
5
  context 'valid' do
10
- let(:context) { double('context', my_user: 'foo', my_account: 'bar') }
6
+ let(:controller_context) { double('context', authorization_preconditions: [:my_user, :my_account], my_user: 'foo', my_account: 'bar') }
11
7
 
12
8
  it 'sets attribute readers for each precondition' do
13
9
  expect(subject.my_user).to eq('foo')
@@ -20,7 +16,7 @@ module PermissionPolicy
20
16
  end
21
17
 
22
18
  context 'invalid' do
23
- let(:context) { double('context', my_user: nil, my_account: nil) }
19
+ let(:controller_context) { double('context', authorization_preconditions: [:my_user, :my_account], my_user: nil, my_account: nil) }
24
20
 
25
21
  it 'raises missing precondition error' do
26
22
  expect { subject }.to raise_error('missing precondition: my_user')
@@ -1,13 +1,4 @@
1
1
  module PermissionPolicy
2
2
  RSpec.describe Configuration do
3
- before { PermissionPolicy.configuration = nil }
4
-
5
- it 'has a default precondition' do
6
- expect(subject.preconditions).to eq([:current_user])
7
- end
8
-
9
- it 'has a default strategy' do
10
- expect(subject.strategies).to eq([:UnknownStrategy])
11
- end
12
3
  end
13
4
  end
@@ -6,38 +6,118 @@ class MetalTestController < ActionController::Metal
6
6
  include PermissionPolicy::ControllerAdditions::InstanceMethods
7
7
  extend PermissionPolicy::ControllerAdditions::ClassMethods
8
8
 
9
+ authorize_with :foo, :bar
10
+ verify_authorization!
11
+ authorization_strategies :TestStrategy, :UnknownStrategy
12
+
9
13
  def foo
14
+ 'foo'
10
15
  end
11
16
 
12
17
  def bar
18
+ 'bar'
19
+ end
20
+
21
+ def baz
22
+ 'baz'
23
+ end
24
+ end
25
+
26
+ class TestController < MetalTestController
27
+ def not_authorized_action
28
+ 'you will never see me'
29
+ end
30
+
31
+ def not_allowed_action
32
+ authorize! :something
33
+ 'you also wont see me, but get a different error'
34
+ end
35
+
36
+ def allowed_action
37
+ authorize! :view, subject: 'some_subject'
38
+ 'ok go ahead'
39
+ end
40
+ end
41
+
42
+ class TestStrategy < PermissionPolicy::Strategies::BaseStrategy
43
+ def match?
44
+ options[:subject] == 'some_subject'
45
+ end
46
+
47
+ def allowed?
48
+ { view: true, manage: false }[action]
49
+ end
50
+ end
51
+
52
+ class SkipTestController < MetalTestController
53
+ authorize_with :baz
54
+ skip_verify_authorization
55
+
56
+ def skipped_authorization
57
+ 'ohai'
13
58
  end
14
59
  end
15
60
 
16
61
 
17
62
  module PermissionPolicy
18
63
  RSpec.describe 'ControllerAdditions' do
19
- subject { MetalTestController.new }
20
64
 
21
- context 'authorization' do
22
- before do
23
- MetalTestController.authorize_with :foo, :bar
24
- is_expected.to receive(:foo) { 'foo' }
25
- is_expected.to receive(:bar) { 'bar' }
65
+ context 'instance_methods' do
66
+ subject { MetalTestController.new }
67
+
68
+ describe 'authorization' do
69
+ it 'is available through #permission_policy' do
70
+ expect(subject.permission_policy).to be_kind_of(PermissionPolicy::Authorization)
71
+ end
72
+
73
+ it 'is initialized with precondition foo' do
74
+ expect(subject.permission_policy.foo).to eq('foo')
75
+ end
76
+
77
+ it 'is initialized with precondition bar' do
78
+ expect(subject.permission_policy.bar).to eq('bar')
79
+ end
26
80
  end
27
81
 
28
- it 'is available throuth #permission_policy' do
29
- expect(subject.permission_policy).to be_kind_of(PermissionPolicy::Authorization)
82
+ describe 'helpers' do
83
+ it { is_expected.to respond_to :authorize! }
84
+ it { is_expected.to respond_to :allowed? }
30
85
  end
86
+ end
87
+
88
+ context 'class_methods' do
89
+ subject { TestController.new }
90
+
91
+ describe '#verify_authorization!' do
92
+ context 'no call to #authorize!' do
93
+ it 'is not verified' do
94
+ expect { subject.process_action :not_authorized_action }.to raise_error PermissionPolicy::NotVerified
95
+ end
96
+ end
97
+
98
+ context 'with #authorize! but not allowed' do
99
+ it 'is still not allowed' do
100
+ expect { subject.process_action :not_allowed_action }.to raise_error PermissionPolicy::NotAllowed
101
+ end
102
+ end
31
103
 
32
- it 'is initialized with preconditions' do
33
- expect(subject.permission_policy.foo).to eq('foo')
34
- expect(subject.permission_policy.bar).to eq('bar')
104
+ context '#authorized! and allowed' do
105
+ it 'is allowed' do
106
+ expect(subject.process_action :allowed_action).to eq('ok go ahead')
107
+ end
108
+ end
35
109
  end
36
110
  end
37
111
 
38
- context 'helpers' do
39
- it { is_expected.to respond_to :authorize! }
40
- it { is_expected.to respond_to :allowed? }
112
+ describe '#skip_verify_authorization' do
113
+ subject { SkipTestController.new }
114
+
115
+ context 'with :only option' do
116
+ it 'skips this action' do
117
+ expect(subject.process_action :skipped_authorization).to eq('ohai')
118
+ end
119
+ end
41
120
  end
121
+
42
122
  end
43
123
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: permission_policy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marco Schaden
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-01-30 00:00:00.000000000 Z
12
+ date: 2015-02-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport