silo_manager 0.0.5 → 0.0.6
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.
- data/bin/silo_manager +614 -464
- data/lib/nexpose.rb +2809 -2738
- data/lib/options.rb +33 -33
- data/lib/test.rb +7 -7
- metadata +34 -55
data/bin/silo_manager
CHANGED
|
@@ -1,465 +1,615 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# TODO: Fix multi-byte problem (copied and pasted from PDF)
|
|
3
|
-
|
|
4
|
-
require 'rubygems'
|
|
5
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '../lib/nexpose'))
|
|
6
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '../lib/options'))
|
|
7
|
-
|
|
8
|
-
################################
|
|
9
|
-
# Multi-Tenant User Attributes #
|
|
10
|
-
################################
|
|
11
|
-
MTU_ATTRS = ['authsrcid:integer:required', 'user-name:string:required',
|
|
12
|
-
'full-name:string:required', 'email:string:optional', 'password:string:required', 'enabled:boolean:required',
|
|
13
|
-
'superuser:boolean:required']
|
|
14
|
-
|
|
15
|
-
SILO_ACCESS_ATTRS = ['all-groups:boolean:required', 'all-sites:boolean:required', 'default-silo:boolean:required',
|
|
16
|
-
'role-name:string:required', 'silo-id:string:required']
|
|
17
|
-
|
|
18
|
-
###########################
|
|
19
|
-
# Silo Profile Attributes #
|
|
20
|
-
###########################
|
|
21
|
-
SILO_PROFILE_ATTRS = ['id:string:required', 'name:string:required', 'description:string:optional',
|
|
22
|
-
'all-licensed-modules:boolean:required', 'all-global-engines:boolean:required', 'all-global-report-templates:boolean:required',
|
|
23
|
-
'all-global-scan-templates:boolean:required']
|
|
24
|
-
|
|
25
|
-
ACCEPTED_REPORT_INPUTS = ['csv', 'db', 'html', 'ns-xml', 'pdf', 'qualys-xml', 'raw-xml', 'rtf', 'scap-xml', 'text']
|
|
26
|
-
|
|
27
|
-
###################
|
|
28
|
-
# Silo Attributes #
|
|
29
|
-
###################
|
|
30
|
-
SILO_CONFIG_ATTRS = ['id:string:required', 'name:string:required', 'silo-profile-id:string:required',
|
|
31
|
-
'description:string:optional', 'max-assets:integer:required', 'max-hosted-assets:integer:required',
|
|
32
|
-
'max-users:integer:required']
|
|
33
|
-
|
|
34
|
-
MERCHANT_ATTRS = ['acquirer-relationship:boolean:required', 'agent-relationship:boolean:required',
|
|
35
|
-
'payment-application:string:required', 'payment-version:string:required', 'ecommerce:boolean:required',
|
|
36
|
-
'grocery:boolean:required', 'mail-order:boolean:required', 'petroleum:boolean:required', 'retail:boolean:required',
|
|
37
|
-
'telecommunication:boolean:required', 'travel:boolean:required', 'url:string:required', 'company:string:required',
|
|
38
|
-
'email-address:string:optional', 'first-name:string:required', 'last-name:string:required', 'phone-number:string:required',
|
|
39
|
-
'title:string:optional']
|
|
40
|
-
|
|
41
|
-
ADDRESS_ATTRS = ['city:string:required', 'country:string:required', 'line1:string:required', 'line2:string:required',
|
|
42
|
-
'state:string:required', 'zip:string:required']
|
|
43
|
-
|
|
44
|
-
QSA_ATTRS = ['url:string:required', 'company:string:required', 'email-address:string:optional', 'first-name:string:required',
|
|
45
|
-
'last-name:string:required', 'phone-number:string:required', 'title:string:optional']
|
|
46
|
-
|
|
47
|
-
ORG_ATTRS = ['url:string:required', 'company:string:required', 'email-address:string:optional', 'first-name:string:required',
|
|
48
|
-
'last-name:string:required', 'phone-number:string:required', 'title:string:optional']
|
|
49
|
-
|
|
50
|
-
#-------------------------------------------------------------------------
|
|
51
|
-
#-------------------------------------------------------------------------
|
|
52
|
-
def get_integer_input name, return_main=false, required=false
|
|
53
|
-
integer_inputed = false
|
|
54
|
-
while !integer_inputed
|
|
55
|
-
puts "Enter an integer value for #{name}:"
|
|
56
|
-
begin
|
|
57
|
-
input = gets.chomp
|
|
58
|
-
if return_main and input =~ /:main/i
|
|
59
|
-
return :main
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
if input.empty? and required
|
|
63
|
-
puts 'Input is required'
|
|
64
|
-
next
|
|
65
|
-
elsif input.empty?
|
|
66
|
-
return nil
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
begin
|
|
70
|
-
input = Integer input
|
|
71
|
-
integer_inputed = true
|
|
72
|
-
rescue Exception
|
|
73
|
-
puts "Invalid input"
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
input
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
#-------------------------------------------------------------------------
|
|
81
|
-
#-------------------------------------------------------------------------
|
|
82
|
-
def get_string_input name, return_main=false, required=false
|
|
83
|
-
success = false
|
|
84
|
-
while !success
|
|
85
|
-
puts "Enter an string value for #{name}:"
|
|
86
|
-
input = gets.chomp
|
|
87
|
-
if return_main and input =~ /:main/i
|
|
88
|
-
return :main
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
if input.empty? and required
|
|
92
|
-
puts 'Input is required'
|
|
93
|
-
next
|
|
94
|
-
elsif input.empty?
|
|
95
|
-
return nil
|
|
96
|
-
end
|
|
97
|
-
success = true
|
|
98
|
-
end
|
|
99
|
-
input
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
#-------------------------------------------------------------------------
|
|
103
|
-
#-------------------------------------------------------------------------
|
|
104
|
-
def get_boolean_input name='', return_main=false, required=false
|
|
105
|
-
boolean_inputed = false
|
|
106
|
-
while !boolean_inputed
|
|
107
|
-
puts "Enter a boolean value (true/1 or false/0) for #{name}:"
|
|
108
|
-
begin
|
|
109
|
-
input = gets.chomp
|
|
110
|
-
if return_main and input =~ /:main/i
|
|
111
|
-
return :main
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
if input.empty? and required
|
|
115
|
-
puts 'Input is required'
|
|
116
|
-
next
|
|
117
|
-
elsif input.empty?
|
|
118
|
-
return nil
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
if input =~ /true|1/i
|
|
122
|
-
input = true
|
|
123
|
-
boolean_inputed = true
|
|
124
|
-
elsif input =~ /false|0/i
|
|
125
|
-
input = false
|
|
126
|
-
boolean_inputed = true
|
|
127
|
-
else
|
|
128
|
-
puts "Invalid input!"
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
input
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
#-------------------------------------------------------------------------
|
|
136
|
-
#-------------------------------------------------------------------------
|
|
137
|
-
def process_attrs attrs, title
|
|
138
|
-
puts title
|
|
139
|
-
puts "To return to the main menu type ':main'"
|
|
140
|
-
|
|
141
|
-
input_hash = {}
|
|
142
|
-
|
|
143
|
-
attrs.each do |attr|
|
|
144
|
-
parts = attr.split ":"
|
|
145
|
-
name = parts[0] + " (#{parts[2]})"
|
|
146
|
-
required = ('required'.eql? parts[2])
|
|
147
|
-
case parts[1]
|
|
148
|
-
when /boolean/
|
|
149
|
-
input = get_boolean_input name, true, required
|
|
150
|
-
when /integer/
|
|
151
|
-
input = get_integer_input name, true, required
|
|
152
|
-
when /string/
|
|
153
|
-
input = get_string_input name, true, required
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
if input == :main
|
|
157
|
-
return nil
|
|
158
|
-
elsif input.nil?
|
|
159
|
-
# don't add the entry
|
|
160
|
-
next
|
|
161
|
-
else
|
|
162
|
-
input_hash[parts[0]] = input
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
input_hash
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
#-------------------------------------------------------------------------
|
|
171
|
-
# Gets an comma separated list of input from the user and parses
|
|
172
|
-
# it into an array
|
|
173
|
-
#
|
|
174
|
-
# integer - if true, the input values must be an integers
|
|
175
|
-
# restricted_values - Input should be of a certain type
|
|
176
|
-
#-------------------------------------------------------------------------
|
|
177
|
-
def get_value_array integer=false, restricted_values=[]
|
|
178
|
-
output = []
|
|
179
|
-
success = false
|
|
180
|
-
while !success
|
|
181
|
-
puts "Enter a comma separated list of values or nothing to skip:"
|
|
182
|
-
if not restricted_values.empty?
|
|
183
|
-
puts "Input is restricted to: #{restricted_values.inspect}"
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
input = gets.chomp
|
|
187
|
-
|
|
188
|
-
if input =~ /:main/
|
|
189
|
-
return nil
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
if input.empty?
|
|
193
|
-
return []
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
begin
|
|
197
|
-
input.split(",").each do |part|
|
|
198
|
-
|
|
199
|
-
# Do validation first
|
|
200
|
-
if not restricted_values.empty?
|
|
201
|
-
if not restricted_values.include? part
|
|
202
|
-
"This is not an allowed input: #{part.to_s}"
|
|
203
|
-
raise
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
output << (integer ? part.to_i : part.to_s)
|
|
208
|
-
end
|
|
209
|
-
success = true
|
|
210
|
-
rescue Exception
|
|
211
|
-
puts "Invalid input!"
|
|
212
|
-
if integer
|
|
213
|
-
puts "Integer input only"
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
output
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
#-------------------------------------------------------------------------
|
|
222
|
-
#-------------------------------------------------------------------------
|
|
223
|
-
def enter_data? type
|
|
224
|
-
while true
|
|
225
|
-
puts "Do you wish to enter #{type} data (yes/no)?"
|
|
226
|
-
input = gets.chomp
|
|
227
|
-
if input =~ /yes/i
|
|
228
|
-
return true
|
|
229
|
-
elsif input =~ /no/i
|
|
230
|
-
return false
|
|
231
|
-
else
|
|
232
|
-
puts "Invalid input!"
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
#-------------------------------------------------------------------------
|
|
238
|
-
# Main method that builds the input map for creating a multi-tenant user
|
|
239
|
-
#-------------------------------------------------------------------------
|
|
240
|
-
def create_multi_tenant_user
|
|
241
|
-
user_config = process_attrs MTU_ATTRS, "User Configuration"
|
|
242
|
-
if not user_config
|
|
243
|
-
return
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
silo_configs = process_attrs SILO_ACCESS_ATTRS, "Silo Configuration"
|
|
247
|
-
if not silo_configs
|
|
248
|
-
return
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
if not silo_configs['all-sites']
|
|
252
|
-
puts "Site ID values:"
|
|
253
|
-
ids = get_value_array true
|
|
254
|
-
if not ids
|
|
255
|
-
return
|
|
256
|
-
end
|
|
257
|
-
if ids and not ids.empty?
|
|
258
|
-
silo_configs['allowed-sites'] = ids
|
|
259
|
-
end
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
if not silo_configs['all-groups']
|
|
263
|
-
puts "Group ID values:"
|
|
264
|
-
ids = get_value_array true
|
|
265
|
-
if not ids
|
|
266
|
-
return
|
|
267
|
-
end
|
|
268
|
-
if ids and not ids.empty?
|
|
269
|
-
silo_configs['allowed-groups'] = ids
|
|
270
|
-
end
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
begin
|
|
274
|
-
@client_api.login
|
|
275
|
-
@client_api.create_multi_tenant_user user_config, silo_configs
|
|
276
|
-
puts "Successfully created multi-tenant user!"
|
|
277
|
-
rescue Exception => e
|
|
278
|
-
puts e.message
|
|
279
|
-
end
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
#-------------------------------------------------------------------------
|
|
283
|
-
# Main method that builds the input map for creating a silo profile
|
|
284
|
-
#-------------------------------------------------------------------------
|
|
285
|
-
def create_silo_profile
|
|
286
|
-
silo_profile_config = process_attrs SILO_PROFILE_ATTRS, "Silo Profile Configuration"
|
|
287
|
-
if not silo_profile_config
|
|
288
|
-
return
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
permissions = {}
|
|
292
|
-
|
|
293
|
-
unless silo_profile_config['all-global-report-templates']
|
|
294
|
-
puts "Global report template names:"
|
|
295
|
-
names = get_value_array
|
|
296
|
-
if not names
|
|
297
|
-
return
|
|
298
|
-
end
|
|
299
|
-
if names and not names.empty?
|
|
300
|
-
permissions['global_report_templates'] = names
|
|
301
|
-
end
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
unless silo_profile_config['all-global-engines']
|
|
305
|
-
puts "Global scan engine names:"
|
|
306
|
-
names = get_value_array
|
|
307
|
-
if not names
|
|
308
|
-
return
|
|
309
|
-
end
|
|
310
|
-
if names and not names.empty?
|
|
311
|
-
permissions['global_scan_engines'] = names
|
|
312
|
-
end
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
unless silo_profile_config['all-global-scan-templates']
|
|
316
|
-
puts "Global scan template names:"
|
|
317
|
-
names = get_value_array
|
|
318
|
-
if not names
|
|
319
|
-
return
|
|
320
|
-
end
|
|
321
|
-
if names and not names.empty?
|
|
322
|
-
permissions['global_scan_templates'] = names
|
|
323
|
-
end
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
unless silo_profile_config['all-licensed-modules']
|
|
327
|
-
puts "Licensed module names:"
|
|
328
|
-
names = get_value_array
|
|
329
|
-
if not names
|
|
330
|
-
return
|
|
331
|
-
end
|
|
332
|
-
if names and not names.empty?
|
|
333
|
-
permissions['licensed_modules'] = names
|
|
334
|
-
end
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
puts "Restricted Report Format names:"
|
|
338
|
-
names = get_value_array false, ACCEPTED_REPORT_INPUTS
|
|
339
|
-
unless names
|
|
340
|
-
return
|
|
341
|
-
end
|
|
342
|
-
if names and not names.empty?
|
|
343
|
-
permissions['restricted_report_formats'] = names
|
|
344
|
-
end
|
|
345
|
-
|
|
346
|
-
puts "Restricted Report Section names:"
|
|
347
|
-
names = get_value_array
|
|
348
|
-
unless names
|
|
349
|
-
return
|
|
350
|
-
end
|
|
351
|
-
if names and not names.empty?
|
|
352
|
-
permissions['restricted_report_sections'] = names
|
|
353
|
-
end
|
|
354
|
-
|
|
355
|
-
begin
|
|
356
|
-
@client_api.login
|
|
357
|
-
@client_api.create_silo_profile silo_profile_config, permissions
|
|
358
|
-
puts "Successfully created silo profile!"
|
|
359
|
-
rescue Exception => e
|
|
360
|
-
puts e.message
|
|
361
|
-
end
|
|
362
|
-
end
|
|
363
|
-
|
|
364
|
-
#-------------------------------------------------------------------------
|
|
365
|
-
# Main method that builds the input map for creating a silo
|
|
366
|
-
#-------------------------------------------------------------------------
|
|
367
|
-
def create_silo
|
|
368
|
-
silo_config = process_attrs SILO_CONFIG_ATTRS, "Silo Configuration"
|
|
369
|
-
if not silo_config
|
|
370
|
-
return
|
|
371
|
-
end
|
|
372
|
-
|
|
373
|
-
if (enter_data? "Organization")
|
|
374
|
-
organization_data = process_attrs ORG_ATTRS, "Organization Data"
|
|
375
|
-
address_data = process_attrs ADDRESS_ATTRS, "Address Data"
|
|
376
|
-
silo_config['organization'] = organization_data
|
|
377
|
-
silo_config['organization']['address'] = address_data
|
|
378
|
-
end
|
|
379
|
-
|
|
380
|
-
if (enter_data? "Merchant")
|
|
381
|
-
merchant_data = process_attrs MERCHANT_ATTRS , "Merchant Data"
|
|
382
|
-
merchant_address = process_attrs ADDRESS_ATTRS, "Merchant Address Data"
|
|
383
|
-
|
|
384
|
-
puts "DBA values"
|
|
385
|
-
dba = get_value_array
|
|
386
|
-
|
|
387
|
-
puts "Industry values"
|
|
388
|
-
industries = get_value_array
|
|
389
|
-
|
|
390
|
-
qsa = process_attrs QSA_ATTRS, "QSA Data"
|
|
391
|
-
qsa_address = process_attrs ADDRESS_ATTRS, "QSA Address Data"
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
silo_config['merchant'] = merchant_data
|
|
395
|
-
silo_config['merchant']['address'] = merchant_address
|
|
396
|
-
silo_config['merchant']['other_industries'] = industries
|
|
397
|
-
silo_config['merchant']['dba'] = dba
|
|
398
|
-
silo_config['merchant']['qsa'] = qsa
|
|
399
|
-
silo_config['merchant']['qsa']['address'] = qsa_address
|
|
400
|
-
end
|
|
401
|
-
|
|
402
|
-
begin
|
|
403
|
-
@client_api.login
|
|
404
|
-
@client_api.create_silo silo_config
|
|
405
|
-
puts "Successfully created silo!"
|
|
406
|
-
rescue Exception => e
|
|
407
|
-
puts e.message
|
|
408
|
-
end
|
|
409
|
-
end
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
when
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# TODO: Fix multi-byte problem (copied and pasted from PDF)
|
|
3
|
+
|
|
4
|
+
require 'rubygems'
|
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../lib/nexpose'))
|
|
6
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../lib/options'))
|
|
7
|
+
|
|
8
|
+
################################
|
|
9
|
+
# Multi-Tenant User Attributes #
|
|
10
|
+
################################
|
|
11
|
+
MTU_ATTRS = ['authsrcid:integer:required', 'user-name:string:required',
|
|
12
|
+
'full-name:string:required', 'email:string:optional', 'password:string:required', 'enabled:boolean:required',
|
|
13
|
+
'superuser:boolean:required']
|
|
14
|
+
|
|
15
|
+
SILO_ACCESS_ATTRS = ['all-groups:boolean:required', 'all-sites:boolean:required', 'default-silo:boolean:required',
|
|
16
|
+
'role-name:string:required', 'silo-id:string:required']
|
|
17
|
+
|
|
18
|
+
###########################
|
|
19
|
+
# Silo Profile Attributes #
|
|
20
|
+
###########################
|
|
21
|
+
SILO_PROFILE_ATTRS = ['id:string:required', 'name:string:required', 'description:string:optional',
|
|
22
|
+
'all-licensed-modules:boolean:required', 'all-global-engines:boolean:required', 'all-global-report-templates:boolean:required',
|
|
23
|
+
'all-global-scan-templates:boolean:required']
|
|
24
|
+
|
|
25
|
+
ACCEPTED_REPORT_INPUTS = ['csv', 'db', 'html', 'ns-xml', 'pdf', 'qualys-xml', 'raw-xml', 'rtf', 'scap-xml', 'text']
|
|
26
|
+
|
|
27
|
+
###################
|
|
28
|
+
# Silo Attributes #
|
|
29
|
+
###################
|
|
30
|
+
SILO_CONFIG_ATTRS = ['id:string:required', 'name:string:required', 'silo-profile-id:string:required',
|
|
31
|
+
'description:string:optional', 'max-assets:integer:required', 'max-hosted-assets:integer:required',
|
|
32
|
+
'max-users:integer:required']
|
|
33
|
+
|
|
34
|
+
MERCHANT_ATTRS = ['acquirer-relationship:boolean:required', 'agent-relationship:boolean:required',
|
|
35
|
+
'payment-application:string:required', 'payment-version:string:required', 'ecommerce:boolean:required',
|
|
36
|
+
'grocery:boolean:required', 'mail-order:boolean:required', 'petroleum:boolean:required', 'retail:boolean:required',
|
|
37
|
+
'telecommunication:boolean:required', 'travel:boolean:required', 'url:string:required', 'company:string:required',
|
|
38
|
+
'email-address:string:optional', 'first-name:string:required', 'last-name:string:required', 'phone-number:string:required',
|
|
39
|
+
'title:string:optional']
|
|
40
|
+
|
|
41
|
+
ADDRESS_ATTRS = ['city:string:required', 'country:string:required', 'line1:string:required', 'line2:string:required',
|
|
42
|
+
'state:string:required', 'zip:string:required']
|
|
43
|
+
|
|
44
|
+
QSA_ATTRS = ['url:string:required', 'company:string:required', 'email-address:string:optional', 'first-name:string:required',
|
|
45
|
+
'last-name:string:required', 'phone-number:string:required', 'title:string:optional']
|
|
46
|
+
|
|
47
|
+
ORG_ATTRS = ['url:string:required', 'company:string:required', 'email-address:string:optional', 'first-name:string:required',
|
|
48
|
+
'last-name:string:required', 'phone-number:string:required', 'title:string:optional']
|
|
49
|
+
|
|
50
|
+
#-------------------------------------------------------------------------
|
|
51
|
+
#-------------------------------------------------------------------------
|
|
52
|
+
def get_integer_input name, return_main=false, required=false
|
|
53
|
+
integer_inputed = false
|
|
54
|
+
while !integer_inputed
|
|
55
|
+
puts "Enter an integer value for #{name}:"
|
|
56
|
+
begin
|
|
57
|
+
input = gets.chomp
|
|
58
|
+
if return_main and input =~ /:main/i
|
|
59
|
+
return :main
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
if input.empty? and required
|
|
63
|
+
puts 'Input is required'
|
|
64
|
+
next
|
|
65
|
+
elsif input.empty?
|
|
66
|
+
return nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
begin
|
|
70
|
+
input = Integer input
|
|
71
|
+
integer_inputed = true
|
|
72
|
+
rescue Exception
|
|
73
|
+
puts "Invalid input"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
input
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
#-------------------------------------------------------------------------
|
|
81
|
+
#-------------------------------------------------------------------------
|
|
82
|
+
def get_string_input name, return_main=false, required=false
|
|
83
|
+
success = false
|
|
84
|
+
while !success
|
|
85
|
+
puts "Enter an string value for #{name}:"
|
|
86
|
+
input = gets.chomp
|
|
87
|
+
if return_main and input =~ /:main/i
|
|
88
|
+
return :main
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
if input.empty? and required
|
|
92
|
+
puts 'Input is required'
|
|
93
|
+
next
|
|
94
|
+
elsif input.empty?
|
|
95
|
+
return nil
|
|
96
|
+
end
|
|
97
|
+
success = true
|
|
98
|
+
end
|
|
99
|
+
input
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
#-------------------------------------------------------------------------
|
|
103
|
+
#-------------------------------------------------------------------------
|
|
104
|
+
def get_boolean_input name='', return_main=false, required=false
|
|
105
|
+
boolean_inputed = false
|
|
106
|
+
while !boolean_inputed
|
|
107
|
+
puts "Enter a boolean value (true/1 or false/0) for #{name}:"
|
|
108
|
+
begin
|
|
109
|
+
input = gets.chomp
|
|
110
|
+
if return_main and input =~ /:main/i
|
|
111
|
+
return :main
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
if input.empty? and required
|
|
115
|
+
puts 'Input is required'
|
|
116
|
+
next
|
|
117
|
+
elsif input.empty?
|
|
118
|
+
return nil
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
if input =~ /true|1/i
|
|
122
|
+
input = true
|
|
123
|
+
boolean_inputed = true
|
|
124
|
+
elsif input =~ /false|0/i
|
|
125
|
+
input = false
|
|
126
|
+
boolean_inputed = true
|
|
127
|
+
else
|
|
128
|
+
puts "Invalid input!"
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
input
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
#-------------------------------------------------------------------------
|
|
136
|
+
#-------------------------------------------------------------------------
|
|
137
|
+
def process_attrs attrs, title
|
|
138
|
+
puts title
|
|
139
|
+
puts "To return to the main menu type ':main'"
|
|
140
|
+
|
|
141
|
+
input_hash = {}
|
|
142
|
+
|
|
143
|
+
attrs.each do |attr|
|
|
144
|
+
parts = attr.split ":"
|
|
145
|
+
name = parts[0] + " (#{parts[2]})"
|
|
146
|
+
required = ('required'.eql? parts[2])
|
|
147
|
+
case parts[1]
|
|
148
|
+
when /boolean/
|
|
149
|
+
input = get_boolean_input name, true, required
|
|
150
|
+
when /integer/
|
|
151
|
+
input = get_integer_input name, true, required
|
|
152
|
+
when /string/
|
|
153
|
+
input = get_string_input name, true, required
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
if input == :main
|
|
157
|
+
return nil
|
|
158
|
+
elsif input.nil?
|
|
159
|
+
# don't add the entry
|
|
160
|
+
next
|
|
161
|
+
else
|
|
162
|
+
input_hash[parts[0]] = input
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
input_hash
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
#-------------------------------------------------------------------------
|
|
171
|
+
# Gets an comma separated list of input from the user and parses
|
|
172
|
+
# it into an array
|
|
173
|
+
#
|
|
174
|
+
# integer - if true, the input values must be an integers
|
|
175
|
+
# restricted_values - Input should be of a certain type
|
|
176
|
+
#-------------------------------------------------------------------------
|
|
177
|
+
def get_value_array integer=false, restricted_values=[]
|
|
178
|
+
output = []
|
|
179
|
+
success = false
|
|
180
|
+
while !success
|
|
181
|
+
puts "Enter a comma separated list of values or nothing to skip:"
|
|
182
|
+
if not restricted_values.empty?
|
|
183
|
+
puts "Input is restricted to: #{restricted_values.inspect}"
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
input = gets.chomp
|
|
187
|
+
|
|
188
|
+
if input =~ /:main/
|
|
189
|
+
return nil
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
if input.empty?
|
|
193
|
+
return []
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
begin
|
|
197
|
+
input.split(",").each do |part|
|
|
198
|
+
|
|
199
|
+
# Do validation first
|
|
200
|
+
if not restricted_values.empty?
|
|
201
|
+
if not restricted_values.include? part
|
|
202
|
+
"This is not an allowed input: #{part.to_s}"
|
|
203
|
+
raise
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
output << (integer ? part.to_i : part.to_s)
|
|
208
|
+
end
|
|
209
|
+
success = true
|
|
210
|
+
rescue Exception
|
|
211
|
+
puts "Invalid input!"
|
|
212
|
+
if integer
|
|
213
|
+
puts "Integer input only"
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
output
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
#-------------------------------------------------------------------------
|
|
222
|
+
#-------------------------------------------------------------------------
|
|
223
|
+
def enter_data? type
|
|
224
|
+
while true
|
|
225
|
+
puts "Do you wish to enter #{type} data (yes/no)?"
|
|
226
|
+
input = gets.chomp
|
|
227
|
+
if input =~ /yes/i
|
|
228
|
+
return true
|
|
229
|
+
elsif input =~ /no/i
|
|
230
|
+
return false
|
|
231
|
+
else
|
|
232
|
+
puts "Invalid input!"
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
#-------------------------------------------------------------------------
|
|
238
|
+
# Main method that builds the input map for creating a multi-tenant user
|
|
239
|
+
#-------------------------------------------------------------------------
|
|
240
|
+
def create_multi_tenant_user
|
|
241
|
+
user_config = process_attrs MTU_ATTRS, "User Configuration"
|
|
242
|
+
if not user_config
|
|
243
|
+
return
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
silo_configs = process_attrs SILO_ACCESS_ATTRS, "Silo Configuration"
|
|
247
|
+
if not silo_configs
|
|
248
|
+
return
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
if not silo_configs['all-sites']
|
|
252
|
+
puts "Site ID values:"
|
|
253
|
+
ids = get_value_array true
|
|
254
|
+
if not ids
|
|
255
|
+
return
|
|
256
|
+
end
|
|
257
|
+
if ids and not ids.empty?
|
|
258
|
+
silo_configs['allowed-sites'] = ids
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
if not silo_configs['all-groups']
|
|
263
|
+
puts "Group ID values:"
|
|
264
|
+
ids = get_value_array true
|
|
265
|
+
if not ids
|
|
266
|
+
return
|
|
267
|
+
end
|
|
268
|
+
if ids and not ids.empty?
|
|
269
|
+
silo_configs['allowed-groups'] = ids
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
begin
|
|
274
|
+
@client_api.login
|
|
275
|
+
@client_api.create_multi_tenant_user user_config, silo_configs
|
|
276
|
+
puts "Successfully created multi-tenant user!"
|
|
277
|
+
rescue Exception => e
|
|
278
|
+
puts e.message
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
#-------------------------------------------------------------------------
|
|
283
|
+
# Main method that builds the input map for creating a silo profile
|
|
284
|
+
#-------------------------------------------------------------------------
|
|
285
|
+
def create_silo_profile
|
|
286
|
+
silo_profile_config = process_attrs SILO_PROFILE_ATTRS, "Silo Profile Configuration"
|
|
287
|
+
if not silo_profile_config
|
|
288
|
+
return
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
permissions = {}
|
|
292
|
+
|
|
293
|
+
unless silo_profile_config['all-global-report-templates']
|
|
294
|
+
puts "Global report template names:"
|
|
295
|
+
names = get_value_array
|
|
296
|
+
if not names
|
|
297
|
+
return
|
|
298
|
+
end
|
|
299
|
+
if names and not names.empty?
|
|
300
|
+
permissions['global_report_templates'] = names
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
unless silo_profile_config['all-global-engines']
|
|
305
|
+
puts "Global scan engine names:"
|
|
306
|
+
names = get_value_array
|
|
307
|
+
if not names
|
|
308
|
+
return
|
|
309
|
+
end
|
|
310
|
+
if names and not names.empty?
|
|
311
|
+
permissions['global_scan_engines'] = names
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
unless silo_profile_config['all-global-scan-templates']
|
|
316
|
+
puts "Global scan template names:"
|
|
317
|
+
names = get_value_array
|
|
318
|
+
if not names
|
|
319
|
+
return
|
|
320
|
+
end
|
|
321
|
+
if names and not names.empty?
|
|
322
|
+
permissions['global_scan_templates'] = names
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
unless silo_profile_config['all-licensed-modules']
|
|
327
|
+
puts "Licensed module names:"
|
|
328
|
+
names = get_value_array
|
|
329
|
+
if not names
|
|
330
|
+
return
|
|
331
|
+
end
|
|
332
|
+
if names and not names.empty?
|
|
333
|
+
permissions['licensed_modules'] = names
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
puts "Restricted Report Format names:"
|
|
338
|
+
names = get_value_array false, ACCEPTED_REPORT_INPUTS
|
|
339
|
+
unless names
|
|
340
|
+
return
|
|
341
|
+
end
|
|
342
|
+
if names and not names.empty?
|
|
343
|
+
permissions['restricted_report_formats'] = names
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
puts "Restricted Report Section names:"
|
|
347
|
+
names = get_value_array
|
|
348
|
+
unless names
|
|
349
|
+
return
|
|
350
|
+
end
|
|
351
|
+
if names and not names.empty?
|
|
352
|
+
permissions['restricted_report_sections'] = names
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
begin
|
|
356
|
+
@client_api.login
|
|
357
|
+
@client_api.create_silo_profile silo_profile_config, permissions
|
|
358
|
+
puts "Successfully created silo profile!"
|
|
359
|
+
rescue Exception => e
|
|
360
|
+
puts e.message
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
#-------------------------------------------------------------------------
|
|
365
|
+
# Main method that builds the input map for creating a silo
|
|
366
|
+
#-------------------------------------------------------------------------
|
|
367
|
+
def create_silo
|
|
368
|
+
silo_config = process_attrs SILO_CONFIG_ATTRS, "Silo Configuration"
|
|
369
|
+
if not silo_config
|
|
370
|
+
return
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
if (enter_data? "Organization")
|
|
374
|
+
organization_data = process_attrs ORG_ATTRS, "Organization Data"
|
|
375
|
+
address_data = process_attrs ADDRESS_ATTRS, "Address Data"
|
|
376
|
+
silo_config['organization'] = organization_data
|
|
377
|
+
silo_config['organization']['address'] = address_data
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
if (enter_data? "Merchant")
|
|
381
|
+
merchant_data = process_attrs MERCHANT_ATTRS , "Merchant Data"
|
|
382
|
+
merchant_address = process_attrs ADDRESS_ATTRS, "Merchant Address Data"
|
|
383
|
+
|
|
384
|
+
puts "DBA values"
|
|
385
|
+
dba = get_value_array
|
|
386
|
+
|
|
387
|
+
puts "Industry values"
|
|
388
|
+
industries = get_value_array
|
|
389
|
+
|
|
390
|
+
qsa = process_attrs QSA_ATTRS, "QSA Data"
|
|
391
|
+
qsa_address = process_attrs ADDRESS_ATTRS, "QSA Address Data"
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
silo_config['merchant'] = merchant_data
|
|
395
|
+
silo_config['merchant']['address'] = merchant_address
|
|
396
|
+
silo_config['merchant']['other_industries'] = industries
|
|
397
|
+
silo_config['merchant']['dba'] = dba
|
|
398
|
+
silo_config['merchant']['qsa'] = qsa
|
|
399
|
+
silo_config['merchant']['qsa']['address'] = qsa_address
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
begin
|
|
403
|
+
@client_api.login
|
|
404
|
+
@client_api.create_silo silo_config
|
|
405
|
+
puts "Successfully created silo!"
|
|
406
|
+
rescue Exception => e
|
|
407
|
+
puts e.message
|
|
408
|
+
end
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def list_mtu
|
|
412
|
+
main_selected = false
|
|
413
|
+
|
|
414
|
+
while !main_selected
|
|
415
|
+
mtu_list = []
|
|
416
|
+
begin
|
|
417
|
+
@client_api.login
|
|
418
|
+
mtu_list = @client_api.list_mtu
|
|
419
|
+
rescue Exception => e
|
|
420
|
+
puts e.message
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
puts "To return to the main menu type ':main'"
|
|
424
|
+
puts "For detailed information on a specific mtu enter the id"
|
|
425
|
+
puts "Or just hit enter to list all ids"
|
|
426
|
+
|
|
427
|
+
id = get_integer_input 'MTU ID'
|
|
428
|
+
if id == :main
|
|
429
|
+
return
|
|
430
|
+
elsif id.nil?
|
|
431
|
+
mtu_list.each do |mtu_map|
|
|
432
|
+
put mtu_map[:id]
|
|
433
|
+
end
|
|
434
|
+
else
|
|
435
|
+
id_found = false
|
|
436
|
+
mtu_list.each do |mtu_map|
|
|
437
|
+
if mtu_map[:id].to_i == id
|
|
438
|
+
puts mtu_map.inspect
|
|
439
|
+
id_found = true
|
|
440
|
+
break
|
|
441
|
+
end
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
if !id_found
|
|
445
|
+
puts "MTU ID not found"
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def delete_mtu
|
|
453
|
+
while true
|
|
454
|
+
puts "To return to the main menu type ':main'"
|
|
455
|
+
puts "Enter 1 to enter an ID and 2 for name"
|
|
456
|
+
input = gets
|
|
457
|
+
name, id = nil
|
|
458
|
+
case input
|
|
459
|
+
when /1/
|
|
460
|
+
id = get_string_input 'MTU Id', true, true
|
|
461
|
+
if id == :main
|
|
462
|
+
return
|
|
463
|
+
end
|
|
464
|
+
when /2/
|
|
465
|
+
name = get_string_input 'MTU Name', true, true
|
|
466
|
+
if name == :main
|
|
467
|
+
return
|
|
468
|
+
end
|
|
469
|
+
else
|
|
470
|
+
put 'Invalid input'
|
|
471
|
+
next
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
begin
|
|
475
|
+
@client_api.login
|
|
476
|
+
@client_api.delete_mtu name, id
|
|
477
|
+
put 'Successfully deleted MTU!'
|
|
478
|
+
rescue Exception => e
|
|
479
|
+
puts e.message
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def delete_silo_profile
|
|
486
|
+
while true
|
|
487
|
+
puts "To return to the main menu type ':main'"
|
|
488
|
+
puts "Enter 1 to enter an ID and 2 for name"
|
|
489
|
+
input = gets
|
|
490
|
+
name, id = nil
|
|
491
|
+
case input
|
|
492
|
+
when /1/
|
|
493
|
+
id = get_string_input 'Silo Profile Id', true, true
|
|
494
|
+
if id == :main
|
|
495
|
+
return
|
|
496
|
+
end
|
|
497
|
+
when /2/
|
|
498
|
+
name = get_string_input 'Silo Profile Name', true, true
|
|
499
|
+
if name == :main
|
|
500
|
+
return
|
|
501
|
+
end
|
|
502
|
+
else
|
|
503
|
+
put 'Invalid input'
|
|
504
|
+
next
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
begin
|
|
508
|
+
@client_api.login
|
|
509
|
+
@client_api.delete_silo_profile name, id
|
|
510
|
+
put 'Successfully deleted silo profile!'
|
|
511
|
+
rescue Exception => e
|
|
512
|
+
puts e.message
|
|
513
|
+
end
|
|
514
|
+
end
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
def delete_silo
|
|
518
|
+
while true
|
|
519
|
+
puts "To return to the main menu type ':main'"
|
|
520
|
+
puts "Enter 1 to enter an ID and 2 for name"
|
|
521
|
+
input = gets
|
|
522
|
+
name, id = nil
|
|
523
|
+
case input
|
|
524
|
+
when /1/
|
|
525
|
+
id = get_string_input 'Silo Id', true, true
|
|
526
|
+
if id == :main
|
|
527
|
+
return
|
|
528
|
+
end
|
|
529
|
+
when /2/
|
|
530
|
+
name = get_string_input 'Silo Name', true, true
|
|
531
|
+
if name == :main
|
|
532
|
+
return
|
|
533
|
+
end
|
|
534
|
+
else
|
|
535
|
+
put 'Invalid input'
|
|
536
|
+
next
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
begin
|
|
540
|
+
@client_api.login
|
|
541
|
+
@client_api.delete_silo name, id
|
|
542
|
+
put 'Successfully deleted silo!'
|
|
543
|
+
rescue Exception => e
|
|
544
|
+
puts e.message
|
|
545
|
+
end
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
#-------------------------------------------------------------------------
|
|
550
|
+
# Main input screen
|
|
551
|
+
#-------------------------------------------------------------------------
|
|
552
|
+
def get_main_select
|
|
553
|
+
id_choosen = false
|
|
554
|
+
while !id_choosen
|
|
555
|
+
puts "\nChoose one of the following IDs:"
|
|
556
|
+
puts "1. Create a new multi-tenant user"
|
|
557
|
+
puts "2. Create a new silo-profile"
|
|
558
|
+
puts "3. Create a new silo"
|
|
559
|
+
puts "4. List multi-tenant users"
|
|
560
|
+
puts "5. Delete a multi-tenant user"
|
|
561
|
+
puts "6. Delete a silo profile"
|
|
562
|
+
puts "7. Delete a silo"
|
|
563
|
+
|
|
564
|
+
id = gets.chomp
|
|
565
|
+
if id =~ /quit/i
|
|
566
|
+
exit 0
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
begin
|
|
570
|
+
id = id.to_i
|
|
571
|
+
id_choosen = true
|
|
572
|
+
rescue Exception
|
|
573
|
+
puts "Input error"
|
|
574
|
+
end
|
|
575
|
+
end
|
|
576
|
+
id
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
###############
|
|
580
|
+
# ENTRY POINT #
|
|
581
|
+
###############
|
|
582
|
+
begin
|
|
583
|
+
options = Options.parse ARGV
|
|
584
|
+
begin
|
|
585
|
+
@client_api = Nexpose::Connection.new options.host, options.user, options.password, options.port
|
|
586
|
+
@client_api.login
|
|
587
|
+
rescue Exception => e
|
|
588
|
+
puts "Unable to connect to #{options.host}"
|
|
589
|
+
puts e.message
|
|
590
|
+
exit 1
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
while true
|
|
594
|
+
puts "To quit at anytime type 'quit'"
|
|
595
|
+
case get_main_select
|
|
596
|
+
when 1
|
|
597
|
+
create_multi_tenant_user
|
|
598
|
+
when 2
|
|
599
|
+
create_silo_profile
|
|
600
|
+
when 3
|
|
601
|
+
create_silo
|
|
602
|
+
when 4
|
|
603
|
+
list_mtu
|
|
604
|
+
when 5
|
|
605
|
+
delete_mtu
|
|
606
|
+
when 6
|
|
607
|
+
delete_silo_profile
|
|
608
|
+
when 7
|
|
609
|
+
delete_silo
|
|
610
|
+
|
|
611
|
+
else
|
|
612
|
+
puts "Invalid input"
|
|
613
|
+
end
|
|
614
|
+
end
|
|
465
615
|
end
|