conjur-asset-dsl2 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|