Class: Conjur::Command
Direct Known Subclasses
Assets, Audit, Authn, Bootstrap, Env, Field, Groups, HostFactories, Hosts, Id, Init, Layers, Plugin, Pubkeys, Resources, Roles, Secrets, Server, ShellInit, Users, Variables, DSLCommand
Defined Under Namespace
Classes: Assets, Audit, Authn, Bootstrap, Elevate, Env, Field, Groups, HostFactories, Hosts, Id, Init, Layers, Plugin, Pubkeys, Resources, Roles, RubyDSL, Script, Secrets, Server, ShellInit, Users, Variables
Constant Summary
collapse
- @@api =
nil
Class Attribute Summary collapse
Class Method Summary
collapse
-
.acting_as_option(command) ⇒ Object
-
.annotate_option(command) ⇒ Object
-
.api ⇒ Object
-
.api=(api) ⇒ Object
-
.assert_empty(args) ⇒ Object
-
.collection_option(command) ⇒ Object
-
.command(name, *a, &block) ⇒ Object
-
.command_impl_for_list(global_options, options, args) ⇒ Object
-
.command_options_for_list(c) ⇒ Object
-
.context_option(command) ⇒ Object
-
.current_role ⇒ Object
-
.current_user ⇒ Object
-
.destination_role(options) ⇒ Object
-
.display(obj, options = {}) ⇒ Object
-
.display_members(members, options) ⇒ Object
-
.elevated? ⇒ Boolean
-
.give_away_resource(obj, options) ⇒ Object
-
.has_admin?(role, other_role) ⇒ Boolean
-
.hide_docs(command) ⇒ Object
Prevent a deprecated command from being displayed in the help output.
-
.highline ⇒ Object
-
.integer?(v) ⇒ Boolean
-
.interactive_option(command) ⇒ Object
-
.method_missing(*a, &b) ⇒ Object
-
.min_version(command, version) ⇒ Object
-
.prompt_for_annotations ⇒ Object
-
.prompt_for_group(options = {}) ⇒ Object
-
.prompt_for_id(kind, label = 'id') ⇒ Object
-
.prompt_for_idnumber(label) ⇒ Object
-
.prompt_for_password ⇒ Object
-
.prompt_for_public_key ⇒ Object
-
.prompt_to_confirm(kind, properties) ⇒ Object
-
.read_till_eof(prompt = nil) ⇒ Object
-
.require_arg(args, name) ⇒ Object
-
.retire_internal_role(roleObj) ⇒ Object
-
.retire_options(command) ⇒ Object
-
.retire_resource(obj) ⇒ Object
-
.retire_role(obj) ⇒ Object
-
.validate_privileges(message, &block) ⇒ Object
-
.validate_public_key(key) ⇒ Object
-
.validate_retire_privileges(record, options) ⇒ Object
conjur_account, full_resource_id, get_kind_and_id_from_args
Class Attribute Details
.prefix ⇒ Object
Returns the value of attribute prefix.
31
32
33
|
# File 'lib/conjur/command.rb', line 31
def prefix
@prefix
end
|
Class Method Details
.acting_as_option(command) ⇒ Object
73
74
75
76
77
78
79
80
81
82
|
# File 'lib/conjur/command.rb', line 73
def acting_as_option command
return if command.flags.member?(:"as-group") command.desc 'Perform all actions as the specified Group'
command.arg_name 'GROUP'
command.flag [:'as-group']
command.desc 'Perform all actions as the specified Role'
command.arg_name 'ROLE'
command.flag [:'as-role']
end
|
.annotate_option(command) ⇒ Object
102
103
104
105
106
|
# File 'lib/conjur/command.rb', line 102
def annotate_option command
command.arg_name 'annotate'
command.desc 'Add variable annotations interactively'
command.switch [:a, :annotate]
end
|
.api ⇒ Object
54
55
56
|
# File 'lib/conjur/command.rb', line 54
def api
@@api ||= Conjur::Authn.connect
end
|
.api=(api) ⇒ Object
50
51
52
|
# File 'lib/conjur/command.rb', line 50
def api= api
@@api = api
end
|
.assert_empty(args) ⇒ Object
46
47
48
|
# File 'lib/conjur/command.rb', line 46
def assert_empty(args)
exit_now! "Received extra command arguments" unless args.empty?
end
|
.collection_option(command) ⇒ Object
84
85
86
87
88
|
# File 'lib/conjur/command.rb', line 84
def collection_option command
command.desc 'An optional prefix for created roles and resources'
command.arg_name 'collection'
command.flag [:collection]
end
|
.command(name, *a, &block) ⇒ Object
37
38
39
40
|
# File 'lib/conjur/command.rb', line 37
def command name, *a, &block
name = "#{prefix}:#{name}" if prefix
Conjur::CLI.command(name, *a, &block)
end
|
.command_impl_for_list(global_options, options, args) ⇒ Object
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
# File 'lib/conjur/command.rb', line 168
def command_impl_for_list(global_options, options, args)
opts = options.slice(:search, :limit, :options, :kind)
opts[:acting_as] = options[:role] if options[:role]
opts[:search]=opts[:search].gsub('-',' ') if opts[:search]
resources = api.resources(opts)
if options[:ids]
puts JSON.pretty_generate(resources.map(&:resourceid))
else
resources = resources.map &:attributes
unless options[:'raw-annotations']
resources = resources.map do |r|
r['annotations'] = (r['annotations'] || []).inject({}) do |hash, annot|
hash[annot['name']] = annot['value']
hash
end
r
end
end
puts JSON.pretty_generate resources
end
end
|
.command_options_for_list(c) ⇒ Object
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
# File 'lib/conjur/command.rb', line 146
def command_options_for_list(c)
return if c.flags.member?(:role) c.desc "Role to act as. By default, the current logged-in role is used."
c.arg_name 'ROLE'
c.flag [:role]
c.desc "Full-text search on resource id and annotation values"
c.flag [:s, :search]
c.desc "Maximum number of records to return"
c.flag [:l, :limit]
c.desc "Offset to start from"
c.flag [:o, :offset]
c.desc "Show only ids"
c.switch [:i, :ids]
c.desc "Show annotations in 'raw' format"
c.switch [:r, :"raw-annotations"]
end
|
.context_option(command) ⇒ Object
90
91
92
93
94
|
# File 'lib/conjur/command.rb', line 90
def context_option command
command.desc "Load context from this config file, and save it when finished. The file permissions will be 0600 by default."
command.arg_name "FILE"
command.flag [:c, :context]
end
|
.current_role ⇒ Object
452
453
454
455
456
457
458
459
|
# File 'lib/conjur/command.rb', line 452
def current_role
kind, id = api.username.split('/', 2)
if id.nil?
id = kind
kind = 'user'
end
api.role([ kind, id ].join(":"))
end
|
.current_user ⇒ Object
58
59
60
61
62
63
64
65
66
|
# File 'lib/conjur/command.rb', line 58
def current_user
username = api.username
kind, id = username.split('/')
unless kind && id
id = kind
kind = 'user'
end
api.send(kind, username)
end
|
.destination_role(options) ⇒ Object
210
211
212
213
214
215
216
217
|
# File 'lib/conjur/command.rb', line 210
def destination_role options
destination = options[:"destination-role"]
if destination
api.role(destination)
else
api.user('attic')
end
end
|
.display(obj, options = {}) ⇒ Object
315
316
317
318
319
320
321
322
323
324
325
326
327
328
|
# File 'lib/conjur/command.rb', line 315
def display(obj, options = {})
str = if obj.respond_to?(:attributes)
JSON.pretty_generate obj.attributes
elsif obj.respond_to?(:id)
obj.id
else
begin
JSON.pretty_generate(obj)
rescue JSON::GeneratorError
obj.to_json
end
end
puts str
end
|
.display_members(members, options) ⇒ Object
300
301
302
303
304
305
306
307
308
309
310
311
312
313
|
# File 'lib/conjur/command.rb', line 300
def display_members(members, options)
result = if options[:V]
members.collect {|member|
{
member: member.member.roleid,
grantor: member.grantor.roleid,
admin_option: member.admin_option
}
}
else
members.map(&:member).map(&:roleid)
end
display result
end
|
.elevated? ⇒ Boolean
219
220
221
|
# File 'lib/conjur/command.rb', line 219
def elevated?
api.privilege == 'elevate' && api.global_privilege_permitted?('elevate')
end
|
.give_away_resource(obj, options) ⇒ Object
286
287
288
289
290
291
292
293
294
295
296
297
298
|
# File 'lib/conjur/command.rb', line 286
def give_away_resource obj, options
destination = options[:"destination-role"]
destination_role = if destination
api.role(destination)
else
api.user('attic')
end
exit_now! "Role #{destination_role.roleid} doesn't exist" unless destination_role.exists?
puts "Giving ownership to '#{destination_role.roleid}'"
obj.resource.give_to destination_role
end
|
.has_admin?(role, other_role) ⇒ Boolean
461
462
463
464
465
466
467
|
# File 'lib/conjur/command.rb', line 461
def has_admin?(role, other_role)
return true if role.roleid == other_role.roleid
memberships = role.memberships.map(&:roleid)
other_role.members.any? { |m| memberships.member?(m.member.roleid) && m.admin_option }
rescue RestClient::Forbidden
false
end
|
.hide_docs(command) ⇒ Object
Prevent a deprecated command from being displayed in the help output
69
70
71
|
# File 'lib/conjur/command.rb', line 69
def hide_docs(command)
def command.nodoc; true end
end
|
.highline ⇒ Object
128
129
130
131
|
# File 'lib/conjur/command.rb', line 128
def highline
require 'highline'
@highline ||= HighLine.new($stdin,$stderr)
end
|
.integer?(v) ⇒ Boolean
342
343
344
|
# File 'lib/conjur/command.rb', line 342
def integer? v
Integer(v, 10) rescue false
end
|
.interactive_option(command) ⇒ Object
96
97
98
99
100
|
# File 'lib/conjur/command.rb', line 96
def interactive_option command
command.arg_name 'interactive'
command.desc 'Create variable interactively'
command.switch [:i, :'interactive']
end
|
.method_missing(*a, &b) ⇒ Object
33
34
35
|
# File 'lib/conjur/command.rb', line 33
def method_missing *a, &b
Conjur::CLI.send *a, &b
end
|
.min_version(command, version) ⇒ Object
108
109
110
111
112
113
114
115
116
117
|
# File 'lib/conjur/command.rb', line 108
def min_version command, version
version = Semantic::Version.new version
if version.pre == nil
version.pre = "0"
end
command.instance_variable_set(:@conjur_min_version, version)
end
|
.prompt_for_annotations ⇒ Object
119
120
121
122
123
124
125
126
|
# File 'lib/conjur/command.rb', line 119
def prompt_for_annotations
highline.say('Add annotations (a name and value for each one):')
{}.tap do |annotations|
until (name = highline.ask(' annotation name (press enter to quit annotations): ')).empty?
annotations[name] = read_till_eof(' annotation value (^D on its own line to finish):')
end
end
end
|
.prompt_for_group(options = {}) ⇒ Object
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
|
# File 'lib/conjur/command.rb', line 401
def prompt_for_group options = {}
options[:hint] ||= "press enter to own the record yourself"
group_ids = api.groups.map(&:id)
highline.ask("Enter the group which will own the record (#{options[:hint]}): ", [ "" ] + group_ids) do |q|
require 'readline'
Readline.completion_append_character = ""
Readline.completer_word_break_characters = ""
q.readline = true
q.validate = lambda{|id|
@group = nil
id.empty? || (@group = api.group(id)).exists?
}
q.responses[:not_valid] = "Group '<%= @answer %>' doesn't exist, or you don't have permission to use it"
end
@group ? @group.roleid : nil
end
|
.prompt_for_id(kind, label = 'id') ⇒ Object
346
347
348
349
350
351
352
353
354
355
356
|
# File 'lib/conjur/command.rb', line 346
def prompt_for_id kind, label = 'id'
highline.ask("Enter the #{label}: ") do |q|
q.readline = true
q.validate = lambda{|id|
!id.blank? && !api.send(kind, id).exists?
}
q.responses[:not_valid] = "<% if @answer.blank? %>"\
"#{label} cannot be blank<% else %>"\
"A #{kind} called '<%= @answer %>' already exists<% end %>"
end
end
|
.prompt_for_idnumber(label) ⇒ Object
420
421
422
423
424
425
426
427
428
|
# File 'lib/conjur/command.rb', line 420
def prompt_for_idnumber label
result = highline.ask("Enter a #{label}: ") do |q|
q.validate = lambda{|id|
id.blank? || integer?(id)
}
q.responses[:not_valid] = "The #{label} must be an integer"
end
result.blank? ? nil : result.to_i
end
|
.prompt_for_password ⇒ Object
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
|
# File 'lib/conjur/command.rb', line 430
def prompt_for_password
require 'highline'
hl = HighLine.new($stdin, $stderr)
password = hl.ask("Enter the password (it will not be echoed): "){ |q| q.echo = false }
if password.blank?
if hl.agree "No password (y/n)?"
return nil
else
return prompt_for_password
end
end
confirmation = hl.ask("Confirm the password: "){ |q| q.echo = false }
raise "Password does not match confirmation" unless password == confirmation
password
end
|
.prompt_for_public_key ⇒ Object
358
359
360
361
362
363
364
365
366
367
368
369
370
|
# File 'lib/conjur/command.rb', line 358
def prompt_for_public_key
public_key = highline.ask("Enter the public key (press enter to skip): ") do |q|
q.validate = lambda{|key|
if key.blank?
true
else
validate_public_key key
end
}
q.responses[:not_valid] = "Public key format is invalid; please try again"
end
public_key.blank? ? nil : public_key.strip
end
|
.prompt_to_confirm(kind, properties) ⇒ Object
330
331
332
333
334
335
336
337
338
339
340
|
# File 'lib/conjur/command.rb', line 330
def prompt_to_confirm kind, properties
puts
puts "A new #{kind} will be created with the following properties:"
puts
properties.select{|k,v| !v.blank?}.each do |k,v|
printf "%-10s: %s\n", k, v
end
puts
exit(0) unless %w(yes y).member?(highline.ask("Proceed? (yes/no): ").strip.downcase)
end
|
.read_till_eof(prompt = nil) ⇒ Object
133
134
135
136
137
138
139
140
141
142
143
144
|
# File 'lib/conjur/command.rb', line 133
def read_till_eof(prompt = nil)
highline.say(prompt) if prompt
[].tap do |lines|
loop do
begin
lines << highline.ask('')
rescue EOFError
break
end
end
end.join("\n")
end
|
.require_arg(args, name) ⇒ Object
42
43
44
|
# File 'lib/conjur/command.rb', line 42
def require_arg(args, name)
args.shift or raise "Missing parameter: #{name}"
end
|
.retire_internal_role(roleObj) ⇒ Object
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
|
# File 'lib/conjur/command.rb', line 270
def retire_internal_role roleObj
members = roleObj.members
self_member = members.select{|m| m.member.roleid == current_user.role.roleid}
self_member.each do |m|
members.delete m
end
members.concat self_member if self_member
members.each do |r|
member = api.role(r.member)
puts "Revoking from role #{member.roleid}"
roleObj.revoke_from member
end
end
|
.retire_options(command) ⇒ Object
199
200
201
202
203
204
205
206
207
208
|
# File 'lib/conjur/command.rb', line 199
def retire_options command
command.arg_name 'role'
command.desc "Specify a role to give the retired record to (default: the 'attic' user)"
command.long_desc %Q(When retired, all a record's roles and permissions are revoked.
As a final step, the record is 'given' (e.g. 'conjur resource give') to a destination role.
The default role to receive the record is the user 'attic'. This option can be used to specify
an alternative destination role.)
command.flag [:d, :"destination-role"]
end
|
.retire_resource(obj) ⇒ Object
243
244
245
246
247
248
249
250
251
|
# File 'lib/conjur/command.rb', line 243
def retire_resource obj
obj.resource.attributes['permissions'].each do |p|
role = api.role(p['role'])
privilege = p['privilege']
next if obj.respond_to?(:roleid) && role.roleid == obj.roleid && privilege == 'read'
puts "Denying #{privilege} privilege to #{role.roleid}"
obj.resource.deny(privilege, role)
end
end
|
.retire_role(obj) ⇒ Object
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
|
# File 'lib/conjur/command.rb', line 253
def retire_role obj
members = obj.role.members
self_member = members.select{|m| m.member.roleid == current_user.role.roleid}
self_member.each do |m|
members.delete m
end
members.concat self_member if self_member
members.each do |r|
member = api.role(r.member)
puts "Revoking from role #{member.roleid}"
obj.role.revoke_from member
end
end
|
.validate_privileges(message, &block) ⇒ Object
190
191
192
193
194
195
196
197
|
# File 'lib/conjur/command.rb', line 190
def validate_privileges message, &block
valid = begin
yield
rescue RestClient::Forbidden
false
end
exit_now! message unless valid
end
|
.validate_public_key(key) ⇒ Object
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
|
# File 'lib/conjur/command.rb', line 373
def validate_public_key key
if system('which ssh-keygen 2>&1 > /dev/null')
Conjur.log.debug "Using ssh-keygen to verify the public key\n" if Conjur.log
require 'tempfile'
tempfile = Tempfile.new 'public_key'
tempfile.write(key)
tempfile.close
`ssh-keygen -l -f #{tempfile.path}`
$? == 0
else
Conjur.log.debug "ssh-keygen is not available; falling back to simple string testing\n" if Conjur.log
begin
components = key.strip.split ' '
Base64.strict_decode64 components[1]
components.length == 3
rescue NoMethodError, ArgumentError
false
end
end
end
|
.validate_retire_privileges(record, options) ⇒ Object
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
# File 'lib/conjur/command.rb', line 223
def validate_retire_privileges record, options
return true if elevated?
if record.respond_to?(:role)
memberships = current_user.role.memberships.map(&:roleid)
validate_privileges "You can't administer this record" do
record.role.members.find{|m| memberships.member?(m.member.roleid) && m.admin_option}
end
end
validate_privileges "You don't own the record" do
current_user.role.member_of?(record.resource.ownerid)
end
role = destination_role(options)
exit_now! "Destination role '#{role.roleid}' doesn't exist" unless role.exists?
end
|