Class: Conjur::Command
Direct Known Subclasses
Assets, Audit, Authn, Bootstrap, Env, Field, Groups, Hosts, Id, Init, Layers, Plugin, Pubkeys, Resources, Roles, Secrets, Users, Variables, DSLCommand
Defined Under Namespace
Classes: Assets, Audit, Authn, Bootstrap, Env, Field, Groups, Hosts, Id, Init, Layers, Plugin, Policy, Pubkeys, Resources, Roles, Script, Secrets, 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
-
.command(name, *a, &block) ⇒ Object
-
.command_impl_for_list(global_options, options, args) ⇒ Object
-
.command_options_for_list(c) ⇒ Object
-
.current_user ⇒ Object
-
.destination_role(options) ⇒ Object
-
.display(obj, options = {}) ⇒ Object
-
.display_members(members, options) ⇒ Object
-
.give_away_resource(obj, options) ⇒ Object
-
.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
-
.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_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.
30
31
32
|
# File 'lib/conjur/command.rb', line 30
def prefix
@prefix
end
|
Class Method Details
.acting_as_option(command) ⇒ Object
63
64
65
66
67
68
69
70
|
# File 'lib/conjur/command.rb', line 63
def acting_as_option command
return if command.flags.member?(:"as-group")
command.arg_name 'Perform all actions as the specified Group'
command.flag [:"as-group"]
command.arg_name 'Perform all actions as the specified Role'
command.flag [:"as-role"]
end
|
.annotate_option(command) ⇒ Object
78
79
80
81
82
|
# File 'lib/conjur/command.rb', line 78
def annotate_option command
command.arg_name 'annotate'
command.desc 'Add variable annotations interactively'
command.switch [:a, :annotate]
end
|
.api ⇒ Object
44
45
46
|
# File 'lib/conjur/command.rb', line 44
def api
@@api ||= Conjur::Authn.connect
end
|
.command(name, *a, &block) ⇒ Object
35
36
37
38
|
# File 'lib/conjur/command.rb', line 35
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
# File 'lib/conjur/command.rb', line 132
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
# File 'lib/conjur/command.rb', line 111
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.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
|
.current_user ⇒ Object
48
49
50
51
52
53
54
55
56
|
# File 'lib/conjur/command.rb', line 48
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
174
175
176
177
178
179
180
181
|
# File 'lib/conjur/command.rb', line 174
def destination_role options
destination = options[:"destination-role"]
if destination
api.role(destination)
else
api.user('attic')
end
end
|
.display(obj, options = {}) ⇒ Object
257
258
259
260
261
262
263
264
265
266
267
268
269
270
|
# File 'lib/conjur/command.rb', line 257
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
|
# File 'lib/conjur/command.rb', line 242
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
|
.give_away_resource(obj, options) ⇒ Object
228
229
230
231
232
233
234
235
236
237
238
239
240
|
# File 'lib/conjur/command.rb', line 228
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
|
.hide_docs(command) ⇒ Object
Prevent a deprecated command from being displayed in the help output
59
60
61
|
# File 'lib/conjur/command.rb', line 59
def hide_docs(command)
def command.nodoc; true end
end
|
.highline ⇒ Object
93
94
95
96
|
# File 'lib/conjur/command.rb', line 93
def highline
require 'highline'
@highline ||= HighLine.new($stdin,$stderr)
end
|
.integer?(v) ⇒ Boolean
284
285
286
|
# File 'lib/conjur/command.rb', line 284
def integer? v
Integer(v, 10) rescue false
end
|
.interactive_option(command) ⇒ Object
72
73
74
75
76
|
# File 'lib/conjur/command.rb', line 72
def interactive_option command
command.arg_name 'interactive'
command.desc 'Create variable interactively'
command.switch [:i, :'interactive']
end
|
.method_missing(*a, &b) ⇒ Object
31
32
33
|
# File 'lib/conjur/command.rb', line 31
def method_missing *a, &b
Conjur::CLI.send *a, &b
end
|
.prompt_for_annotations ⇒ Object
84
85
86
87
88
89
90
91
|
# File 'lib/conjur/command.rb', line 84
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
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
|
# File 'lib/conjur/command.rb', line 343
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
288
289
290
291
292
293
294
295
296
297
298
|
# File 'lib/conjur/command.rb', line 288
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
362
363
364
365
366
367
368
369
370
|
# File 'lib/conjur/command.rb', line 362
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
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
|
# File 'lib/conjur/command.rb', line 372
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
300
301
302
303
304
305
306
307
308
309
310
311
312
|
# File 'lib/conjur/command.rb', line 300
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
272
273
274
275
276
277
278
279
280
281
282
|
# File 'lib/conjur/command.rb', line 272
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
98
99
100
101
102
103
104
105
106
107
108
109
|
# File 'lib/conjur/command.rb', line 98
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
40
41
42
|
# File 'lib/conjur/command.rb', line 40
def require_arg(args, name)
args.shift or raise "Missing parameter: #{name}"
end
|
.retire_options(command) ⇒ Object
163
164
165
166
167
168
169
170
171
172
|
# File 'lib/conjur/command.rb', line 163
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
201
202
203
204
205
206
207
208
209
|
# File 'lib/conjur/command.rb', line 201
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
|
# File 'lib/conjur/command.rb', line 211
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
154
155
156
157
158
159
160
161
|
# File 'lib/conjur/command.rb', line 154
def validate_privileges message, &block
valid = begin
yield
rescue RestClient::Forbidden
false
end
exit_now! message unless valid
end
|
.validate_public_key(key) ⇒ Object
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
|
# File 'lib/conjur/command.rb', line 315
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
# File 'lib/conjur/command.rb', line 183
def validate_retire_privileges record, options
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
|