conjur-asset-dsl2 0.3.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/.dockerignore +2 -0
- data/.gitignore +14 -0
- data/.project +18 -0
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/CHANGELOG +1 -0
- data/Dockerfile.dev +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +248 -0
- data/Rakefile +18 -0
- data/backup.tar +0 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/conjur-asset-dsl2.gemspec +32 -0
- data/jenkins.sh +36 -0
- data/lib/conjur/command/dsl2.rb +175 -0
- data/lib/conjur/dsl2/executor/base.rb +50 -0
- data/lib/conjur/dsl2/executor/create.rb +117 -0
- data/lib/conjur/dsl2/executor/deny.rb +13 -0
- data/lib/conjur/dsl2/executor/give.rb +12 -0
- data/lib/conjur/dsl2/executor/grant.rb +13 -0
- data/lib/conjur/dsl2/executor/permit.rb +16 -0
- data/lib/conjur/dsl2/executor/retire.rb +7 -0
- data/lib/conjur/dsl2/executor/revoke.rb +11 -0
- data/lib/conjur/dsl2/executor/update.rb +31 -0
- data/lib/conjur/dsl2/executor.rb +99 -0
- data/lib/conjur/dsl2/invalid.rb +12 -0
- data/lib/conjur/dsl2/plan.rb +49 -0
- data/lib/conjur/dsl2/planner/base.rb +215 -0
- data/lib/conjur/dsl2/planner/grants.rb +85 -0
- data/lib/conjur/dsl2/planner/permissions.rb +80 -0
- data/lib/conjur/dsl2/planner/record.rb +102 -0
- data/lib/conjur/dsl2/planner.rb +38 -0
- data/lib/conjur/dsl2/ruby/loader.rb +263 -0
- data/lib/conjur/dsl2/types/base.rb +376 -0
- data/lib/conjur/dsl2/types/create.rb +15 -0
- data/lib/conjur/dsl2/types/deny.rb +17 -0
- data/lib/conjur/dsl2/types/give.rb +14 -0
- data/lib/conjur/dsl2/types/grant.rb +24 -0
- data/lib/conjur/dsl2/types/member.rb +14 -0
- data/lib/conjur/dsl2/types/permit.rb +22 -0
- data/lib/conjur/dsl2/types/policy.rb +129 -0
- data/lib/conjur/dsl2/types/records.rb +243 -0
- data/lib/conjur/dsl2/types/retire.rb +14 -0
- data/lib/conjur/dsl2/types/revoke.rb +14 -0
- data/lib/conjur/dsl2/types/update.rb +16 -0
- data/lib/conjur/dsl2/yaml/handler.rb +400 -0
- data/lib/conjur/dsl2/yaml/loader.rb +29 -0
- data/lib/conjur-asset-dsl2-version.rb +7 -0
- data/lib/conjur-asset-dsl2.rb +27 -0
- data/syntax.md +147 -0
- metadata +237 -0
@@ -0,0 +1,376 @@
|
|
1
|
+
module Conjur
|
2
|
+
module DSL2
|
3
|
+
module Types
|
4
|
+
# An inheritable class attribute which is cloned by subclasses so the attribute
|
5
|
+
# can be a mutable thing such as a Hash.
|
6
|
+
#
|
7
|
+
# https://raw.githubusercontent.com/apotonick/uber/master/lib/uber/inheritable_attr.rb
|
8
|
+
module InheritableAttribute
|
9
|
+
def inheritable_attr(name, options={})
|
10
|
+
instance_eval %Q{
|
11
|
+
def #{name}=(v)
|
12
|
+
@#{name} = v
|
13
|
+
end
|
14
|
+
|
15
|
+
def #{name}
|
16
|
+
return @#{name} if instance_variable_defined?(:@#{name})
|
17
|
+
@#{name} = InheritableAttribute.inherit_for(self, :#{name}, #{options})
|
18
|
+
end
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.inherit_for(klass, name, options={})
|
23
|
+
return unless klass.superclass.respond_to?(name)
|
24
|
+
|
25
|
+
value = klass.superclass.send(name) # could be nil
|
26
|
+
|
27
|
+
return value if options[:clone] == false
|
28
|
+
Clone.(value) # this could be dynamic, allowing other inheritance strategies.
|
29
|
+
end
|
30
|
+
|
31
|
+
class Clone
|
32
|
+
# The second argument allows injecting more types.
|
33
|
+
def self.call(value, uncloneable=uncloneable())
|
34
|
+
uncloneable.each { |klass| return value if value.kind_of?(klass) }
|
35
|
+
value.clone
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.uncloneable
|
39
|
+
[Symbol, TrueClass, FalseClass, NilClass]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Methods which type-check and transform attributes. Type-checking can be done by
|
45
|
+
# duck-typing, with +is_a?+, or by a procedure.
|
46
|
+
module TypeChecking
|
47
|
+
# This is the primary function of the module.
|
48
|
+
#
|
49
|
+
# +value+ an input value
|
50
|
+
# +type_name+ used only for error messages.
|
51
|
+
# +test_function+ a class or function which will determine if the value is already the correct type.
|
52
|
+
# +converter+ if the +test_function+ fails, the converter is called to coerce the type.
|
53
|
+
# It should return +nil+ if its unable to do so.
|
54
|
+
def expect_type value, type_name, test_function, converter = nil
|
55
|
+
|
56
|
+
if test_function.is_a?(Class)
|
57
|
+
cls = test_function
|
58
|
+
test_function = lambda{ value.is_a?(cls) }
|
59
|
+
end
|
60
|
+
if test_function.call
|
61
|
+
value
|
62
|
+
elsif converter && ( v = converter.call )
|
63
|
+
v
|
64
|
+
else
|
65
|
+
name = value.class.respond_to?(:short_name) ? value.class.short_name : value.class.name
|
66
|
+
raise "Expecting #{type_name}, got #{name}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Duck-type roles.
|
71
|
+
def test_role r
|
72
|
+
r.respond_to?(:role?) && r.role?
|
73
|
+
end
|
74
|
+
|
75
|
+
# Duck-type resources.
|
76
|
+
def test_resource r
|
77
|
+
r.respond_to?(:resource?) && r.resource?
|
78
|
+
end
|
79
|
+
|
80
|
+
# If it's a Record
|
81
|
+
def expect_record value
|
82
|
+
expect_type value, "Record", lambda{ value.is_a?(Record) }
|
83
|
+
end
|
84
|
+
|
85
|
+
# If it's a Layer
|
86
|
+
def expect_layer value
|
87
|
+
expect_type value, "Layer", lambda{ value.is_a?(Layer) }
|
88
|
+
end
|
89
|
+
|
90
|
+
# If it looks like a resource.
|
91
|
+
def expect_resource value
|
92
|
+
expect_type value, "Resource", lambda{ test_resource value }
|
93
|
+
end
|
94
|
+
|
95
|
+
# If it looks like a role.
|
96
|
+
def expect_role value
|
97
|
+
expect_type value, "Role", lambda{ test_role value }
|
98
|
+
end
|
99
|
+
|
100
|
+
# +value+ may be a Member; Roles can also be converted to Members.
|
101
|
+
def expect_member value
|
102
|
+
expect_type value,
|
103
|
+
"Member",
|
104
|
+
Member,
|
105
|
+
lambda{ Member.new(value) if test_role(value) }
|
106
|
+
end
|
107
|
+
|
108
|
+
# +value+ must be a Permission.
|
109
|
+
def expect_permission value
|
110
|
+
expect_type value,
|
111
|
+
"Permission",
|
112
|
+
Permission
|
113
|
+
end
|
114
|
+
|
115
|
+
# +value+ must be a String.
|
116
|
+
def expect_string value
|
117
|
+
expect_type value,
|
118
|
+
"string",
|
119
|
+
String
|
120
|
+
end
|
121
|
+
|
122
|
+
# +value+ must be a Integer.
|
123
|
+
def expect_integer value
|
124
|
+
expect_type value,
|
125
|
+
"integer",
|
126
|
+
Integer
|
127
|
+
end
|
128
|
+
|
129
|
+
# +value+ can be a Hash, or an object which implements +to_h+.
|
130
|
+
def expect_hash value
|
131
|
+
expect_type value,
|
132
|
+
"hash",
|
133
|
+
lambda{ value.is_a?(Hash)},
|
134
|
+
lambda{ value.to_h.stringify_keys if value.respond_to?(:to_h) }
|
135
|
+
end
|
136
|
+
|
137
|
+
# +v+ must be +true+ or +false+.
|
138
|
+
def expect_boolean v
|
139
|
+
v = true if v == "true"
|
140
|
+
v = false if v == "false"
|
141
|
+
expect_type v,
|
142
|
+
"boolean",
|
143
|
+
lambda{ [ true, false ].member?(v) }
|
144
|
+
end
|
145
|
+
|
146
|
+
# +values+ can be an instance of +type+ (as determined by the type-checking methods), or
|
147
|
+
# it must be an array of them.
|
148
|
+
def expect_array kind, values
|
149
|
+
# Hash gets converted to an array of key/value pairs by Array
|
150
|
+
is_hash = values.kind_of?(Hash)
|
151
|
+
values = [values] if is_hash
|
152
|
+
|
153
|
+
result = Array(values).map do |v|
|
154
|
+
send "expect_#{kind}", v
|
155
|
+
end
|
156
|
+
|
157
|
+
(values.is_a?(Array) and not is_hash) ? result : result[0]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Define type-checked attributes, using the facilities defined in
|
162
|
+
# +TypeChecking+.
|
163
|
+
module AttributeDefinition
|
164
|
+
# Define a singular field.
|
165
|
+
#
|
166
|
+
# +attr+ the name of the field
|
167
|
+
# +kind+ the type of the field, which corresponds to a +TypeChecking+ method.
|
168
|
+
# +type+ a DSL object type which the parser should use to process the field.
|
169
|
+
# This option is not used for simple kinds like :boolean and :string, because they are
|
170
|
+
# not structured objects.
|
171
|
+
def define_field attr, kind, type = nil, dsl_accessor = false
|
172
|
+
register_yaml_field attr.to_s, type if type
|
173
|
+
|
174
|
+
if dsl_accessor
|
175
|
+
define_method attr do |*args|
|
176
|
+
v = args.shift
|
177
|
+
if v
|
178
|
+
existing = self.instance_variable_get("@#{attr}")
|
179
|
+
value = if existing
|
180
|
+
Array(existing) + [ v ]
|
181
|
+
else
|
182
|
+
v
|
183
|
+
end
|
184
|
+
self.instance_variable_set("@#{attr}", self.class.expect_array(kind, value))
|
185
|
+
else
|
186
|
+
self.instance_variable_get("@#{attr}")
|
187
|
+
end
|
188
|
+
end
|
189
|
+
else
|
190
|
+
define_method attr do
|
191
|
+
self.instance_variable_get("@#{attr}")
|
192
|
+
end
|
193
|
+
end
|
194
|
+
define_method "#{attr}=" do |v|
|
195
|
+
self.instance_variable_set("@#{attr}", self.class.expect_array(kind, v))
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Define a plural field. A plural field is basically just an alias to the singular field.
|
200
|
+
# For example, a plural field called +members+ is really just an alias to +member+. Both
|
201
|
+
# +member+ and +members+ will accept single values or Arrays of values.
|
202
|
+
def define_plural_field attr, kind, type = nil, dsl_accessor = false
|
203
|
+
define_field attr, kind.to_s, type, dsl_accessor
|
204
|
+
|
205
|
+
register_yaml_field attr.to_s.pluralize, type if type
|
206
|
+
|
207
|
+
define_method attr.to_s.pluralize do |*args|
|
208
|
+
send attr, *args
|
209
|
+
end
|
210
|
+
define_method "#{attr.to_s.pluralize}=" do |v|
|
211
|
+
send "#{attr}=", v
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# This is the primary method used by concrete types to define their attributes.
|
216
|
+
#
|
217
|
+
# +attr+ the singularized attribute name.
|
218
|
+
#
|
219
|
+
# Options:
|
220
|
+
# +type+ a structured type to be constructed by the parser. If not provided, the type
|
221
|
+
# may be inferred from the attribute name (e.g. an attribute called :member is the type +Member+).
|
222
|
+
# +kind+ the symbolic name of the type. Inferred from the type, if the type is provided. Otherwise
|
223
|
+
# it's mandatory.
|
224
|
+
# +singular+ by default, attributes accept multiple values. This flag restricts the attribute
|
225
|
+
# to a single value only.
|
226
|
+
def attribute attr, options = {}
|
227
|
+
type = options[:type]
|
228
|
+
begin
|
229
|
+
type ||= Conjur::DSL2::Types.const_get(attr.to_s.capitalize)
|
230
|
+
rescue NameError
|
231
|
+
end
|
232
|
+
kind = options[:kind]
|
233
|
+
kind ||= type.short_name.downcase.to_sym if type
|
234
|
+
|
235
|
+
raise "Attribute :kind must be defined, explicitly or inferred from :type" unless kind
|
236
|
+
|
237
|
+
if options[:singular]
|
238
|
+
define_field attr, kind, type, options[:dsl_accessor]
|
239
|
+
else
|
240
|
+
define_plural_field attr, kind, type, options[:dsl_accessor]
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# Ruby type for attribute name.
|
245
|
+
def yaml_field_type name
|
246
|
+
self.yaml_fields[name]
|
247
|
+
end
|
248
|
+
|
249
|
+
# Is there a Ruby type for a named field?
|
250
|
+
def yaml_field? name
|
251
|
+
!!self.yaml_fields[name]
|
252
|
+
end
|
253
|
+
|
254
|
+
protected
|
255
|
+
|
256
|
+
# +nodoc+
|
257
|
+
def register_yaml_field field_name, type
|
258
|
+
raise "YAML field #{field_name} already defined on #{self.name} as #{self.yaml_fields[field_name]}" if self.yaml_field?(field_name)
|
259
|
+
self.yaml_fields[field_name] = type
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
# Base class for implementing structured DSL object types such as Role, User, etc.
|
264
|
+
#
|
265
|
+
# To define a type:
|
266
|
+
#
|
267
|
+
# * Inherit from this class
|
268
|
+
# * Define attributes using +attribute+
|
269
|
+
#
|
270
|
+
# Your new type will automatically be registered with the YAML parser with a tag
|
271
|
+
# corresponding to the lower-cased short name of the class.
|
272
|
+
class Base
|
273
|
+
extend InheritableAttribute
|
274
|
+
extend TypeChecking
|
275
|
+
extend AttributeDefinition
|
276
|
+
|
277
|
+
# On creation, an owner can always be specified.
|
278
|
+
attr_accessor :owner
|
279
|
+
|
280
|
+
# Stores the mapping from attribute names to Ruby class names that will be constructed
|
281
|
+
# to populate the attribute.
|
282
|
+
inheritable_attr :yaml_fields
|
283
|
+
|
284
|
+
# +nodoc+
|
285
|
+
self.yaml_fields = {}
|
286
|
+
|
287
|
+
# Things aren't roles by default
|
288
|
+
def role?
|
289
|
+
false
|
290
|
+
end
|
291
|
+
|
292
|
+
def id_attribute; 'id'; end
|
293
|
+
|
294
|
+
def custom_attribute_names
|
295
|
+
[ ]
|
296
|
+
end
|
297
|
+
|
298
|
+
def resource?
|
299
|
+
false
|
300
|
+
end
|
301
|
+
|
302
|
+
def role?
|
303
|
+
false
|
304
|
+
end
|
305
|
+
|
306
|
+
class << self
|
307
|
+
# Hook to register the YAML type.
|
308
|
+
def inherited cls
|
309
|
+
cls.register_yaml_type cls.short_name.underscore.gsub('_', '-')
|
310
|
+
end
|
311
|
+
|
312
|
+
# The last token in the ::-separated class name.
|
313
|
+
def short_name
|
314
|
+
self.name.demodulize
|
315
|
+
end
|
316
|
+
|
317
|
+
def register_yaml_type simple_name
|
318
|
+
::YAML.add_tag "!#{simple_name}", self
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
# Define DSL accessor for Role +member+ field.
|
324
|
+
module RoleMemberDSL
|
325
|
+
def self.included(base)
|
326
|
+
base.module_eval do
|
327
|
+
alias member_accessor member
|
328
|
+
|
329
|
+
def member r = nil, admin_option = false
|
330
|
+
if r
|
331
|
+
member = Member.new(r)
|
332
|
+
member.admin = true if admin_option == true
|
333
|
+
if self.member
|
334
|
+
self.member = Array(self.member).push(member)
|
335
|
+
else
|
336
|
+
self.member = member
|
337
|
+
end
|
338
|
+
else
|
339
|
+
member_accessor
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
# Define DSL accessor for Resource +role+ field.
|
347
|
+
module ResourceMemberDSL
|
348
|
+
def self.included(base)
|
349
|
+
base.module_eval do
|
350
|
+
alias role_accessor role
|
351
|
+
|
352
|
+
def role r = nil, grant_option = nil
|
353
|
+
if r
|
354
|
+
role = Member.new(r)
|
355
|
+
role.admin = true if grant_option == true
|
356
|
+
if self.role
|
357
|
+
self.role = Array(self.role) + [ role ]
|
358
|
+
else
|
359
|
+
self.role = role
|
360
|
+
end
|
361
|
+
else
|
362
|
+
role_accessor
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
module ManagedRoleDSL
|
370
|
+
def managed_role record, role_name
|
371
|
+
ManagedRole.new(record, role_name)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Conjur::DSL2::Types
|
2
|
+
class Create < Base
|
3
|
+
attribute :record
|
4
|
+
|
5
|
+
def to_s
|
6
|
+
messages = [ "Create #{record}" ]
|
7
|
+
if record.resource?
|
8
|
+
(record.annotations||{}).each do |k,v|
|
9
|
+
messages.push " Set annotation '#{k}'"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
messages.join("\n")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Conjur
|
2
|
+
module DSL2
|
3
|
+
module Types
|
4
|
+
class Deny < Base
|
5
|
+
attribute :role, kind: :role, dsl_accessor: true
|
6
|
+
attribute :privilege, kind: :string, dsl_accessor: true
|
7
|
+
attribute :resource, dsl_accessor: true
|
8
|
+
|
9
|
+
include ResourceMemberDSL
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
"Deny #{role} to '#{privilege}' #{resource}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Conjur
|
2
|
+
module DSL2
|
3
|
+
module Types
|
4
|
+
class Grant < Base
|
5
|
+
attribute :role, dsl_accessor: true
|
6
|
+
attribute :member
|
7
|
+
attribute :replace, kind: :boolean, singular: true, dsl_accessor: true
|
8
|
+
|
9
|
+
include RoleMemberDSL
|
10
|
+
include ManagedRoleDSL
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
role_str = role.kind_of?(Array) ?
|
14
|
+
role.join(', ') : role
|
15
|
+
member_str = member.kind_of?(Array) ?
|
16
|
+
member.map(&:role).join(', ') : member.role
|
17
|
+
admin = member.kind_of?(Array) ?
|
18
|
+
member.map(&:admin).all? : member.admin
|
19
|
+
"Grant #{role_str} to #{member_str}#{replace ? ' exclusively ' : ''}#{admin ? ' with admin option' : ''}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Conjur
|
2
|
+
module DSL2
|
3
|
+
module Types
|
4
|
+
class Permit < Base
|
5
|
+
attribute :role, kind: :member
|
6
|
+
attribute :privilege, kind: :string, dsl_accessor: true
|
7
|
+
attribute :resource, dsl_accessor: true
|
8
|
+
attribute :replace, kind: :boolean, singular: true, dsl_accessor: true
|
9
|
+
|
10
|
+
include ResourceMemberDSL
|
11
|
+
|
12
|
+
def initialize privilege = nil
|
13
|
+
self.privilege = privilege
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"Permit #{role.role} to '#{privilege}' #{resource}#{role.admin ? ' with grant option' : ''}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module Conjur
|
2
|
+
module DSL2
|
3
|
+
module Types
|
4
|
+
class YAMLList < Array
|
5
|
+
def tag
|
6
|
+
[ "!", self.class.name.split("::")[-1].underscore ].join
|
7
|
+
end
|
8
|
+
|
9
|
+
def encode_with coder
|
10
|
+
coder.represent_seq tag, self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Tagless
|
15
|
+
def tag; nil; end
|
16
|
+
end
|
17
|
+
|
18
|
+
module CustomStatement
|
19
|
+
def custom_statement handler, &block
|
20
|
+
record = yield
|
21
|
+
class << record
|
22
|
+
include RecordReferenceFactory
|
23
|
+
end
|
24
|
+
push record
|
25
|
+
do_scope record, &handler
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module Grants
|
30
|
+
include CustomStatement
|
31
|
+
|
32
|
+
def grant &block
|
33
|
+
custom_statement(block) do
|
34
|
+
Conjur::DSL2::Types::Grant.new
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def revoke &block
|
39
|
+
custom_statement(block) do
|
40
|
+
Conjur::DSL2::Types::Revoke.new
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module Permissions
|
46
|
+
include CustomStatement
|
47
|
+
|
48
|
+
def permit privilege, &block
|
49
|
+
custom_statement(block) do
|
50
|
+
Conjur::DSL2::Types::Permit.new(privilege)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def give &block
|
55
|
+
custom_statement(block) do
|
56
|
+
Conjur::DSL2::Types::Give.new
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def retire &block
|
61
|
+
custom_statement(block) do
|
62
|
+
Conjur::DSL2::Types::Retire.new
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Entitlements will allow creation of any record, as well as declaration
|
68
|
+
# of permit, deny, grant and revoke.
|
69
|
+
class Entitlements < YAMLList
|
70
|
+
include Tagless
|
71
|
+
include Grants
|
72
|
+
include Permissions
|
73
|
+
|
74
|
+
def policy id=nil, &block
|
75
|
+
policy = Policy.new
|
76
|
+
policy.id(id) unless id.nil?
|
77
|
+
push policy
|
78
|
+
|
79
|
+
do_scope policy, &block
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class Body < YAMLList
|
84
|
+
include Grants
|
85
|
+
include Permissions
|
86
|
+
end
|
87
|
+
|
88
|
+
# Policy includes the functionality of Entitlements, wrapped in a
|
89
|
+
# policy role, policy resource, policy id and policy version.
|
90
|
+
class Policy < Record
|
91
|
+
include ActsAsResource
|
92
|
+
include ActsAsRole
|
93
|
+
|
94
|
+
def role default_account
|
95
|
+
Role.new("#{self.account || default_account}:policy:#{id}", default_account: default_account)
|
96
|
+
end
|
97
|
+
|
98
|
+
def resource default_account
|
99
|
+
Resource.new("#{self.account || default_account}:policy:#{id}", default_account: default_account)
|
100
|
+
end
|
101
|
+
|
102
|
+
def body &block
|
103
|
+
if block_given?
|
104
|
+
singleton :body, lambda { Body.new }, &block
|
105
|
+
end
|
106
|
+
@body
|
107
|
+
end
|
108
|
+
|
109
|
+
def body= body
|
110
|
+
@body = body
|
111
|
+
end
|
112
|
+
|
113
|
+
protected
|
114
|
+
|
115
|
+
def singleton id, factory, &block
|
116
|
+
object = instance_variable_get("@#{id}")
|
117
|
+
unless object
|
118
|
+
object = factory.call
|
119
|
+
class << object
|
120
|
+
include Tagless
|
121
|
+
end
|
122
|
+
instance_variable_set("@#{id}", object)
|
123
|
+
end
|
124
|
+
do_scope object, &block
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|