verifica 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|