verifica 1.0.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 +7 -0
- data/CHANGELOG.md +12 -0
- data/LICENSE +21 -0
- data/README.md +449 -0
- data/lib/verifica/ace.rb +79 -0
- data/lib/verifica/acl.rb +208 -0
- data/lib/verifica/acl_builder.rb +63 -0
- data/lib/verifica/authorization_result.rb +152 -0
- data/lib/verifica/authorizer.rb +187 -0
- data/lib/verifica/configuration.rb +41 -0
- data/lib/verifica/errors.rb +84 -0
- data/lib/verifica/resource_configuration.rb +57 -0
- data/lib/verifica/sid.rb +215 -0
- data/lib/verifica/version.rb +5 -0
- data/lib/verifica.rb +122 -0
- data/verifica.gemspec +41 -0
- metadata +127 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Verifica
|
4
|
+
# Base class for all Verifica exceptions
|
5
|
+
#
|
6
|
+
# @api public
|
7
|
+
class Error < StandardError
|
8
|
+
# @return [String] detailed description of the error if it's available or +message+ if not
|
9
|
+
#
|
10
|
+
# @api public
|
11
|
+
def explain
|
12
|
+
message
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Raised when {#action} on the given {#resource} isn't allowed for authorization {#subject} (e.g. current user)
|
17
|
+
#
|
18
|
+
# @api public
|
19
|
+
class AuthorizationError < Error
|
20
|
+
# @api private
|
21
|
+
attr_reader :result
|
22
|
+
|
23
|
+
# @api private
|
24
|
+
def initialize(result)
|
25
|
+
@result = result
|
26
|
+
super(result.message)
|
27
|
+
end
|
28
|
+
|
29
|
+
# (see AuthorizationResult#subject)
|
30
|
+
def subject
|
31
|
+
result.subject
|
32
|
+
end
|
33
|
+
|
34
|
+
# (see AuthorizationResult#subject_type)
|
35
|
+
def subject_type
|
36
|
+
result.subject_type
|
37
|
+
end
|
38
|
+
|
39
|
+
# (see AuthorizationResult#subject_id)
|
40
|
+
def subject_id
|
41
|
+
result.subject_id
|
42
|
+
end
|
43
|
+
|
44
|
+
# (see AuthorizationResult#subject_sids)
|
45
|
+
def subject_sids
|
46
|
+
result.subject_sids
|
47
|
+
end
|
48
|
+
|
49
|
+
# (see AuthorizationResult#resource)
|
50
|
+
def resource
|
51
|
+
result.resource
|
52
|
+
end
|
53
|
+
|
54
|
+
# (see AuthorizationResult#resource_type)
|
55
|
+
def resource_type
|
56
|
+
result.resource_type
|
57
|
+
end
|
58
|
+
|
59
|
+
# (see AuthorizationResult#resource_id)
|
60
|
+
def resource_id
|
61
|
+
result.resource_id
|
62
|
+
end
|
63
|
+
|
64
|
+
# (see AuthorizationResult#action)
|
65
|
+
def action
|
66
|
+
result.action
|
67
|
+
end
|
68
|
+
|
69
|
+
# (see AuthorizationResult#acl)
|
70
|
+
def acl
|
71
|
+
result.acl
|
72
|
+
end
|
73
|
+
|
74
|
+
# (see AuthorizationResult#context)
|
75
|
+
def context
|
76
|
+
result.context
|
77
|
+
end
|
78
|
+
|
79
|
+
# (see AuthorizationResult#explain)
|
80
|
+
def explain
|
81
|
+
result.explain
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
module Verifica
|
6
|
+
# Configuration object for resources registered in {Authorizer}
|
7
|
+
#
|
8
|
+
# @see Verifica.authorizer Usage examples
|
9
|
+
# @note Use {Configuration#register_resource} instead of this class directly
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
class ResourceConfiguration
|
13
|
+
# @return [Symbol] type of the resource
|
14
|
+
#
|
15
|
+
# @api public
|
16
|
+
attr_reader :resource_type
|
17
|
+
|
18
|
+
# @return [Set<Symbol>] set of actions possible for this resource type
|
19
|
+
#
|
20
|
+
# @api public
|
21
|
+
attr_reader :possible_actions
|
22
|
+
|
23
|
+
# @return [#call] Access Control List provider for this resource type
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
attr_reader :acl_provider
|
27
|
+
|
28
|
+
# @see Verifica.authorizer Usage examples
|
29
|
+
# @note Use {Configuration#register_resource} instead of this constructor directly
|
30
|
+
#
|
31
|
+
# @api public
|
32
|
+
def initialize(resource_type, possible_actions, acl_provider)
|
33
|
+
@resource_type = resource_type.to_sym
|
34
|
+
@possible_actions = action_set(possible_actions).freeze
|
35
|
+
if acl_provider.nil?
|
36
|
+
raise Error, "'#{@resource_type}' resource acl_provider should not be nil"
|
37
|
+
end
|
38
|
+
@acl_provider = acl_provider
|
39
|
+
freeze
|
40
|
+
end
|
41
|
+
|
42
|
+
private def action_set(possible_actions)
|
43
|
+
if possible_actions.empty?
|
44
|
+
raise Error, "Empty possible actions for '#{@resource_type}' resource. Probably a bug?"
|
45
|
+
end
|
46
|
+
|
47
|
+
action_set = possible_actions.map(&:to_sym).to_set
|
48
|
+
if action_set.size < possible_actions.size
|
49
|
+
duplicates = possible_actions.tally.select { |_, count| count > 1 }.keys
|
50
|
+
raise Error, "'#{duplicates}' possible actions for '#{@resource_type}' resource are specified several times. " \
|
51
|
+
"Probably code copy-paste and a bug?"
|
52
|
+
end
|
53
|
+
|
54
|
+
action_set
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/verifica/sid.rb
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Verifica
|
4
|
+
# Security Identifier (SID)
|
5
|
+
#
|
6
|
+
# Typically SID is an immutable string (you could use other objects too, string just makes it easier to understand)
|
7
|
+
# which describes certain fact about a security subject
|
8
|
+
# (current user, external service with given API key and scope of permissions, etc.).
|
9
|
+
# Each subject has a list of SIDs associated with it.
|
10
|
+
# For example, SIDs of a superuser may look like: +["root"]+,
|
11
|
+
# and SIDs of a regular user with ID +123+ may look like: +["authenticated", "user:123"]+.
|
12
|
+
#
|
13
|
+
# Essentially SIDs act as a link between the security subject and Access Control List for each resource in your system.
|
14
|
+
#
|
15
|
+
# @note This is an optional, convenience module. It adds methods that represent SIDs common for many web applications
|
16
|
+
# so you'll spend less time inventing your own convention. But you are free to use any other convention for SIDs.
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# class User
|
20
|
+
# include Verifica::Sid
|
21
|
+
#
|
22
|
+
# def id
|
23
|
+
# # ...
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# def superuser?
|
27
|
+
# # ...
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# def org_id
|
31
|
+
# # ...
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# def subject_sids(**)
|
35
|
+
# if superuser?
|
36
|
+
# [root_sid]
|
37
|
+
# else
|
38
|
+
# [authenticated_sid, user_sid(id), organization_sid(org_id)]
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# @see Acl
|
44
|
+
module Sid
|
45
|
+
ANONYMOUS_SID = "anonymous"
|
46
|
+
AUTHENTICATED_SID = "authenticated"
|
47
|
+
ROOT_SID = "root"
|
48
|
+
private_constant :ANONYMOUS_SID, :AUTHENTICATED_SID, :ROOT_SID
|
49
|
+
|
50
|
+
# Security Identifier of the anonymous subject. Essentially this is a public SID.
|
51
|
+
# Use it when certain resources need to be available to anyone.
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
# class PostAclProvider
|
55
|
+
# include Verifica::Sid
|
56
|
+
#
|
57
|
+
# def call(post, **)
|
58
|
+
# Verifica::Acl.build do |acl|
|
59
|
+
# if post.public?
|
60
|
+
# acl.allow anonymous_sid, [:read]
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# # ...
|
64
|
+
# end
|
65
|
+
# end
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# @return [String]
|
69
|
+
#
|
70
|
+
# @api public
|
71
|
+
def anonymous_sid
|
72
|
+
ANONYMOUS_SID
|
73
|
+
end
|
74
|
+
|
75
|
+
# Security Identifier of any authenticated subject (current user, external service, etc.).
|
76
|
+
#
|
77
|
+
# @example
|
78
|
+
# class PostAclProvider
|
79
|
+
# include Verifica::Sid
|
80
|
+
#
|
81
|
+
# def call(post)
|
82
|
+
# Verifica::Acl.build do |acl|
|
83
|
+
# if post.public?
|
84
|
+
# acl.allow authenticated_sid, [:read, :comment]
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# # ...
|
88
|
+
# end
|
89
|
+
# end
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# @return [String]
|
93
|
+
#
|
94
|
+
# @api public
|
95
|
+
def authenticated_sid
|
96
|
+
AUTHENTICATED_SID
|
97
|
+
end
|
98
|
+
|
99
|
+
# Security Identifier of the superuser. The name is taken from Unix terminology as it provides a clear separation
|
100
|
+
# between true admins and semi-admins common in web applications (e.g. organization admin, chat room admin, etc.).
|
101
|
+
# Typically you allow all actions for this SID on all resources.
|
102
|
+
#
|
103
|
+
# @example
|
104
|
+
# class PostAclProvider
|
105
|
+
# include Verifica::Sid
|
106
|
+
#
|
107
|
+
# ALL_ACTIONS = [:read, :write, :delete, :comment]
|
108
|
+
# ROOT_ACL = Acl.build { |acl| acl.allow root_sid, ALL_ACTIONS }
|
109
|
+
#
|
110
|
+
# def call(post, **)
|
111
|
+
# ROOT_ACL.build do |acl|
|
112
|
+
# if post.public?
|
113
|
+
# acl.allow authenticated_sid, [:read, :comment]
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# # ...
|
117
|
+
# end
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# @return [String]
|
122
|
+
#
|
123
|
+
# @api public
|
124
|
+
def root_sid
|
125
|
+
ROOT_SID
|
126
|
+
end
|
127
|
+
|
128
|
+
# Security Identifier of the regular user with given +user_id+.
|
129
|
+
#
|
130
|
+
# @note An argument can't be +nil+ for safety reasons.
|
131
|
+
# +nil+ can cause unpredictable consequences like two separate users sharing the same SID and access rights
|
132
|
+
#
|
133
|
+
# @example
|
134
|
+
# class PostAclProvider
|
135
|
+
# include Verifica::Sid
|
136
|
+
#
|
137
|
+
# def call(post, **)
|
138
|
+
# Verifica::Acl.build do |acl|
|
139
|
+
# acl.allow user_sid(post.author_id), [:read, :comment, :write, :delete]
|
140
|
+
#
|
141
|
+
# # ...
|
142
|
+
# end
|
143
|
+
# end
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
# @return [String]
|
147
|
+
#
|
148
|
+
# @api public
|
149
|
+
def user_sid(user_id)
|
150
|
+
if user_id.nil?
|
151
|
+
raise ArgumentError, "Nil 'user_id' is unsafe. Use empty string if you absolutely need this behavior"
|
152
|
+
end
|
153
|
+
|
154
|
+
"user:#{user_id}".freeze
|
155
|
+
end
|
156
|
+
|
157
|
+
# Security Identifier of the subject with given +role_id+.
|
158
|
+
#
|
159
|
+
# @note (see #user_sid)
|
160
|
+
#
|
161
|
+
# @example
|
162
|
+
# class PostAclProvider
|
163
|
+
# include Verifica::Sid
|
164
|
+
#
|
165
|
+
# def call(post, **)
|
166
|
+
# Verifica::Acl.build do |acl|
|
167
|
+
# acl.allow role_sid("moderator"), [:read, :comment, :delete]
|
168
|
+
#
|
169
|
+
# # ...
|
170
|
+
# end
|
171
|
+
# end
|
172
|
+
# end
|
173
|
+
#
|
174
|
+
# @return [String]
|
175
|
+
#
|
176
|
+
# @api public
|
177
|
+
def role_sid(role_id)
|
178
|
+
if role_id.nil?
|
179
|
+
raise ArgumentError, "Nil 'role_id' is unsafe. Use empty string if you absolutely need this behavior"
|
180
|
+
end
|
181
|
+
|
182
|
+
"role:#{role_id}".freeze
|
183
|
+
end
|
184
|
+
|
185
|
+
# Security Identifier of the subject who is a member of the organization with given +organization_id+
|
186
|
+
#
|
187
|
+
# @note (see #user_sid)
|
188
|
+
#
|
189
|
+
# @example
|
190
|
+
# class PostAclProvider
|
191
|
+
# include Verifica::Sid
|
192
|
+
#
|
193
|
+
# def call(post, **)
|
194
|
+
# Verifica::Acl.build do |acl|
|
195
|
+
# if post.internal?
|
196
|
+
# acl.allow organization_sid(post.organization_id), [:read, :comment]
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
# # ...
|
200
|
+
# end
|
201
|
+
# end
|
202
|
+
# end
|
203
|
+
#
|
204
|
+
# @return [String]
|
205
|
+
#
|
206
|
+
# @api public
|
207
|
+
def organization_sid(organization_id)
|
208
|
+
if organization_id.nil?
|
209
|
+
raise ArgumentError, "Nil 'organization_id' is unsafe. Use empty string if you absolutely need this behavior"
|
210
|
+
end
|
211
|
+
|
212
|
+
"org:#{organization_id}".freeze
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
data/lib/verifica.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "verifica/acl"
|
4
|
+
require_relative "verifica/authorization_result"
|
5
|
+
require_relative "verifica/authorizer"
|
6
|
+
require_relative "verifica/configuration"
|
7
|
+
require_relative "verifica/errors"
|
8
|
+
require_relative "verifica/sid"
|
9
|
+
require_relative "verifica/version"
|
10
|
+
|
11
|
+
# Verifica is Ruby's most scalable authorization solution ready to handle sophisticated authorization rules.
|
12
|
+
#
|
13
|
+
# - Framework and database agnostic
|
14
|
+
# - Scalable. Start from 10, grow to 10M records in the database while having the same authorization architecture
|
15
|
+
# - Supports any actor in your application. Traditional +current_user+, external service, API client, you name it
|
16
|
+
# - No global state. Only local, immutable objects
|
17
|
+
# - Plain old Ruby, zero dependencies, no magic
|
18
|
+
#
|
19
|
+
# Verifica is designed around Access Control List. ACL clearly separates authorization rules definition
|
20
|
+
# (who can do what for any given resource) and execution (can +current_user+ delete this post?).
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# require 'verifica'
|
24
|
+
#
|
25
|
+
# User = Struct.new(:id, :role, keyword_init: true) do
|
26
|
+
# # Verifica expects each security subject to respond to #subject_id, #subject_type, and #subject_sids
|
27
|
+
# alias_method :subject_id, :id
|
28
|
+
# def subject_type = :user
|
29
|
+
#
|
30
|
+
# def subject_sids(**)
|
31
|
+
# role == "root" ? ["root"] : ["authenticated", "user:#{id}"]
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# Video = Struct.new(:id, :author_id, :public, keyword_init: true) do
|
36
|
+
# # Verifica expects each secured resource to respond to #resource_id, and #resource_type
|
37
|
+
# alias_method :resource_id, :id
|
38
|
+
# def resource_type = :video
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# video_acl_provider = lambda do |video, **|
|
42
|
+
# Verifica::Acl.build do |acl|
|
43
|
+
# acl.allow "root", [:read, :write, :delete, :comment]
|
44
|
+
# acl.allow "user:#{video.author_id}", [:read, :write, :delete, :comment]
|
45
|
+
#
|
46
|
+
# if video.public
|
47
|
+
# acl.allow "authenticated", [:read, :comment]
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# authorizer = Verifica.authorizer do |config|
|
53
|
+
# config.register_resource :video, [:read, :write, :delete, :comment], video_acl_provider
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# public_video = Video.new(id: 1, author_id: 1000, public: true)
|
57
|
+
# private_video = Video.new(id: 2, author_id: 1000, public: true)
|
58
|
+
#
|
59
|
+
# superuser = User.new(id: 777, role: "root")
|
60
|
+
# video_author = User.new(id: 1000, role: "user")
|
61
|
+
# other_user = User.new(id: 2000, role: "user")
|
62
|
+
#
|
63
|
+
# authorizer.authorized?(superuser, private_video, :delete)
|
64
|
+
# # true
|
65
|
+
#
|
66
|
+
# authorizer.authorized?(video_author, private_video, :delete)
|
67
|
+
# # true
|
68
|
+
#
|
69
|
+
# authorizer.authorized?(other_user, private_video, :read)
|
70
|
+
# # false
|
71
|
+
#
|
72
|
+
# authorizer.authorized?(other_user, public_video, :comment)
|
73
|
+
# # true
|
74
|
+
#
|
75
|
+
# authorizer.authorize(other_user, public_video, :write)
|
76
|
+
# # raises Verifica::AuthorizationError: Authorization FAILURE. Subject 'user' id='2000'. Resource 'video' id='1'. Action 'write'
|
77
|
+
#
|
78
|
+
# @api public
|
79
|
+
module Verifica
|
80
|
+
EMPTY_ARRAY = [].freeze
|
81
|
+
private_constant :EMPTY_ARRAY
|
82
|
+
|
83
|
+
# Empty, frozen Access Control List. Semantically means that no actions are allowed
|
84
|
+
#
|
85
|
+
# @api public
|
86
|
+
EMPTY_ACL = Verifica::Acl.new(EMPTY_ARRAY).freeze
|
87
|
+
|
88
|
+
# Creates a new {Configuration} and yields it to the given block
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# post_acl_provider = lambda do |post, **|
|
92
|
+
# Verifica::Acl.build do |acl|
|
93
|
+
# acl.allow "root", [:read, :write, :delete, :comment]
|
94
|
+
# acl.allow "user:#{post.author_id}", [:read, :write, :delete, :comment]
|
95
|
+
#
|
96
|
+
# if post.public
|
97
|
+
# acl.allow "authenticated", [:read, :comment]
|
98
|
+
# end
|
99
|
+
# end
|
100
|
+
# end
|
101
|
+
#
|
102
|
+
# user_acl_provider = lambda do |user, **|
|
103
|
+
# Verifica::Acl.build do |acl|
|
104
|
+
# acl.allow "root", [:read, :write, :delete]
|
105
|
+
# acl.allow "user:#{user.id}", [:read, :write]
|
106
|
+
# end
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
# authorizer = Verifica.authorizer do |config|
|
110
|
+
# config.register_resource :post, [:read, :write, :delete, :comment], post_acl_provider
|
111
|
+
# config.register_resource :user, [:read, :write, :delete], user_acl_provider
|
112
|
+
# end
|
113
|
+
#
|
114
|
+
# @return [Authorizer] a new Authorizer configured by the given block
|
115
|
+
#
|
116
|
+
# @api public
|
117
|
+
def self.authorizer
|
118
|
+
config = Configuration.new
|
119
|
+
yield config
|
120
|
+
Authorizer.new(config.resources)
|
121
|
+
end
|
122
|
+
end
|
data/verifica.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/verifica/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "verifica"
|
7
|
+
spec.authors = ["Maxim Gurin"]
|
8
|
+
spec.email = ["mg@maximgurin.com"]
|
9
|
+
spec.version = Verifica::VERSION
|
10
|
+
spec.license = "MIT"
|
11
|
+
|
12
|
+
spec.summary = "The most scalable authorization solution for Ruby"
|
13
|
+
spec.homepage = "https://github.com/maximgurin/verifica"
|
14
|
+
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "verifica.gemspec", "lib/**/*"]
|
15
|
+
spec.bindir = "bin"
|
16
|
+
spec.executables = []
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
spec.description = <<~DESCRIPTION
|
19
|
+
Verifica is Ruby's most scalable authorization solution, ready to handle sophisticated authorization rules.
|
20
|
+
Verifica is framework and database agnostic and designed around Access Control Lists.
|
21
|
+
ACL powers a straightforward and unified authorization flow for any user and resource,
|
22
|
+
regardless of how tricky the authorization rules are.
|
23
|
+
|
24
|
+
Verifica aims to solve the issue when authorization rules become too complex to be expressed in a single
|
25
|
+
SQL query. And at the same time the database is too big to execute these rules in the application code.
|
26
|
+
DESCRIPTION
|
27
|
+
|
28
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
29
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
30
|
+
spec.metadata["changelog_uri"] = "https://github.com/maximgurin/verifica/blob/main/CHANGELOG.md"
|
31
|
+
spec.metadata["source_code_uri"] = "https://github.com/maximgurin/verifica"
|
32
|
+
spec.metadata["bug_tracker_uri"] = "https://github.com/maximgurin/verifica/issues"
|
33
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
34
|
+
|
35
|
+
spec.required_ruby_version = ">= 3.0.0"
|
36
|
+
|
37
|
+
spec.add_development_dependency "bundler"
|
38
|
+
spec.add_development_dependency "rake"
|
39
|
+
spec.add_development_dependency "rspec"
|
40
|
+
spec.add_development_dependency "yard"
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: verifica
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Maxim Gurin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-01-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
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: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: yard
|
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
|
+
description: |
|
70
|
+
Verifica is Ruby's most scalable authorization solution, ready to handle sophisticated authorization rules.
|
71
|
+
Verifica is framework and database agnostic and designed around Access Control Lists.
|
72
|
+
ACL powers a straightforward and unified authorization flow for any user and resource,
|
73
|
+
regardless of how tricky the authorization rules are.
|
74
|
+
|
75
|
+
Verifica aims to solve the issue when authorization rules become too complex to be expressed in a single
|
76
|
+
SQL query. And at the same time the database is too big to execute these rules in the application code.
|
77
|
+
email:
|
78
|
+
- mg@maximgurin.com
|
79
|
+
executables: []
|
80
|
+
extensions: []
|
81
|
+
extra_rdoc_files: []
|
82
|
+
files:
|
83
|
+
- CHANGELOG.md
|
84
|
+
- LICENSE
|
85
|
+
- README.md
|
86
|
+
- lib/verifica.rb
|
87
|
+
- lib/verifica/ace.rb
|
88
|
+
- lib/verifica/acl.rb
|
89
|
+
- lib/verifica/acl_builder.rb
|
90
|
+
- lib/verifica/authorization_result.rb
|
91
|
+
- lib/verifica/authorizer.rb
|
92
|
+
- lib/verifica/configuration.rb
|
93
|
+
- lib/verifica/errors.rb
|
94
|
+
- lib/verifica/resource_configuration.rb
|
95
|
+
- lib/verifica/sid.rb
|
96
|
+
- lib/verifica/version.rb
|
97
|
+
- verifica.gemspec
|
98
|
+
homepage: https://github.com/maximgurin/verifica
|
99
|
+
licenses:
|
100
|
+
- MIT
|
101
|
+
metadata:
|
102
|
+
allowed_push_host: https://rubygems.org
|
103
|
+
homepage_uri: https://github.com/maximgurin/verifica
|
104
|
+
changelog_uri: https://github.com/maximgurin/verifica/blob/main/CHANGELOG.md
|
105
|
+
source_code_uri: https://github.com/maximgurin/verifica
|
106
|
+
bug_tracker_uri: https://github.com/maximgurin/verifica/issues
|
107
|
+
rubygems_mfa_required: 'true'
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 3.0.0
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
requirements: []
|
123
|
+
rubygems_version: 3.4.3
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: The most scalable authorization solution for Ruby
|
127
|
+
test_files: []
|