enfcli 4.0.0 → 5.0.0.pre.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/Dockerfile +2 -2
- data/.circleci/config.yml +5 -0
- data/Gemfile.lock +38 -26
- data/Makefile +7 -0
- data/README.md +52 -7
- data/enfcli.gemspec +28 -26
- data/format.sh +9 -0
- data/lib/enfapi.rb +184 -237
- data/lib/enfapi/dns.rb +95 -0
- data/lib/enfapi/firewall.rb +37 -0
- data/lib/enfapi/user.rb +75 -0
- data/lib/enfcli.rb +211 -111
- data/lib/enfcli/commands/captive.rb +518 -157
- data/lib/enfcli/commands/user.rb +208 -160
- data/lib/enfcli/commands/xcr.rb +151 -119
- data/lib/enfcli/commands/xdns.rb +65 -55
- data/lib/enfcli/commands/xfw.rb +37 -37
- data/lib/enfcli/commands/xiam.rb +87 -80
- data/lib/enfcli/version.rb +2 -2
- data/lib/enfthor.rb +38 -14
- metadata +65 -5
data/lib/enfcli/commands/xiam.rb
CHANGED
@@ -13,18 +13,17 @@
|
|
13
13
|
# See the License for the specific language governing permissions and
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
16
|
+
require "enfthor"
|
17
|
+
require "enfapi"
|
18
|
+
require "digest"
|
19
|
+
require "openssl"
|
20
|
+
require "ipaddr"
|
21
21
|
|
22
22
|
module EnfCli
|
23
23
|
module Cmd
|
24
|
-
|
25
24
|
class Xiam < EnfThor
|
26
25
|
no_commands {
|
27
|
-
def write_pem_file
|
26
|
+
def write_pem_file(keyfile, data)
|
28
27
|
# check if keyfile ends with .pem extension
|
29
28
|
keyfile = "#{keyfile}.pem" unless keyfile.end_with?(".pem")
|
30
29
|
|
@@ -34,17 +33,17 @@ module EnfCli
|
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
37
|
-
def write_to_file
|
36
|
+
def write_to_file(filename, data)
|
38
37
|
begin
|
39
38
|
# check if file exists
|
40
39
|
filename = EnfCli::expand_path(filename)
|
41
|
-
if File.exists?(
|
40
|
+
if File.exists?(filename)
|
42
41
|
proceed = ask("Overwrite #{filename}(type 'yes' to continue...)?")
|
43
|
-
return nil unless (proceed.downcase ==
|
42
|
+
return nil unless (proceed.downcase == "yes")
|
44
43
|
end
|
45
44
|
|
46
45
|
# write to file
|
47
|
-
open filename,
|
46
|
+
open filename, "w" do |io| io.write data end
|
48
47
|
|
49
48
|
# return success
|
50
49
|
return true
|
@@ -59,13 +58,13 @@ module EnfCli
|
|
59
58
|
|
60
59
|
def scan_group_qr_code()
|
61
60
|
# Initalize values
|
62
|
-
gpk_header =
|
63
|
-
gpk_info =
|
61
|
+
gpk_header = ""
|
62
|
+
gpk_info = ""
|
64
63
|
|
65
64
|
# Scan QR Code
|
66
|
-
gpk_header = EnfCli::ask_password(
|
65
|
+
gpk_header = EnfCli::ask_password("Scan DAA group information:")
|
67
66
|
if gpk_header.length < 16
|
68
|
-
gpk_info = EnfCli::ask_password(
|
67
|
+
gpk_info = EnfCli::ask_password("")
|
69
68
|
else
|
70
69
|
tmp_header = gpk_header[0..12]
|
71
70
|
gpk_info = gpk_header[13..gpk_header.length]
|
@@ -90,7 +89,7 @@ module EnfCli
|
|
90
89
|
def read_ec_key_file(keyfile)
|
91
90
|
# expand path
|
92
91
|
keyfile = EnfCli::expand_path(keyfile)
|
93
|
-
|
92
|
+
|
94
93
|
## return if keyfile not found
|
95
94
|
raise EnfCli::ERROR, "#{keyfile} not found!" unless File.exists?(keyfile)
|
96
95
|
|
@@ -98,16 +97,15 @@ module EnfCli
|
|
98
97
|
OpenSSL::PKey::EC.new(File.read(keyfile))
|
99
98
|
end
|
100
99
|
|
101
|
-
def display_groups
|
102
|
-
headings = [
|
103
|
-
rows = groups.map{ |hash|
|
104
|
-
[
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
]
|
100
|
+
def display_groups(groups)
|
101
|
+
headings = ["DAA Group", "Base Name", "Provisioned", "Onboarded", "Default Network", "Domain"]
|
102
|
+
rows = groups.map { |hash|
|
103
|
+
[hash[:gid],
|
104
|
+
hash[:basename],
|
105
|
+
hash[:provisioned_count],
|
106
|
+
hash[:onboarded_count],
|
107
|
+
hash[:default_network] ? hash[:default_network] : "<not set>",
|
108
|
+
hash[:domain]]
|
111
109
|
}
|
112
110
|
render_table(headings, rows)
|
113
111
|
end
|
@@ -119,23 +117,23 @@ module EnfCli
|
|
119
117
|
# create NEW_CREDENTIAL_ECDSA
|
120
118
|
new_credential = {
|
121
119
|
:type => "ecdsa_p256",
|
122
|
-
:key => pubkey
|
123
|
-
}
|
120
|
+
:key => pubkey,
|
121
|
+
}
|
124
122
|
|
125
123
|
# create NEW_ENDPOINT_AUTH
|
126
124
|
new_endpoint_auth = {
|
127
125
|
:ecdsa_credential => new_credential,
|
128
126
|
:address_request => {
|
129
|
-
:address => ipv6_address.to_s
|
130
|
-
}
|
127
|
+
:address => ipv6_address.to_s,
|
128
|
+
},
|
131
129
|
}
|
132
130
|
|
133
131
|
data = EnfApi::Iam.instance.provision_endpoint new_endpoint_auth
|
134
132
|
provisioned_ip = data[:address]
|
135
133
|
|
136
134
|
# Make sure provisioned ip is same as the requested ip
|
137
|
-
raise EnfCli::ERROR, "Provisioned IPv6 address not the same as requested" unless provisioned_ip.eql?(
|
138
|
-
|
135
|
+
raise EnfCli::ERROR, "Provisioned IPv6 address not the same as requested" unless provisioned_ip.eql?(ipv6_address.to_s)
|
136
|
+
|
139
137
|
say "Created new ipv6 endpoint #{provisioned_ip}", :green
|
140
138
|
end
|
141
139
|
|
@@ -146,7 +144,7 @@ module EnfCli
|
|
146
144
|
# create NEW_CREDENTIAL_ECDSA
|
147
145
|
new_credential = {
|
148
146
|
:type => "ecdsa_p256",
|
149
|
-
:key => pubkey
|
147
|
+
:key => pubkey,
|
150
148
|
}
|
151
149
|
|
152
150
|
EnfApi::Iam.instance.update_endpoint_key ipv6_address, new_credential
|
@@ -155,11 +153,12 @@ module EnfCli
|
|
155
153
|
end
|
156
154
|
}
|
157
155
|
|
158
|
-
option_gid = [:gid, {default: nil, type: :string, banner:
|
159
|
-
|
156
|
+
option_gid = [:gid, { default: nil, type: :string, banner: "GID",
|
157
|
+
desc: "The group to get. If not specified, scan the group QR code" }]
|
160
158
|
|
161
159
|
desc "get-group", "Get DAA Group Information"
|
162
160
|
method_option *option_gid
|
161
|
+
|
163
162
|
def get_group
|
164
163
|
try_with_rescue_in_session do
|
165
164
|
# scan if gid not in options
|
@@ -178,8 +177,9 @@ module EnfCli
|
|
178
177
|
end
|
179
178
|
|
180
179
|
desc "list-groups", "List DAA Groups Information"
|
181
|
-
method_option :'network', default: nil, type: :string, banner:
|
182
|
-
desc:
|
180
|
+
method_option :'network', default: nil, type: :string, banner: "NETWORK",
|
181
|
+
desc: "List only groups in this network"
|
182
|
+
|
183
183
|
def list_groups
|
184
184
|
try_with_rescue_in_session do
|
185
185
|
# The xiam API doesn't properly support the 'network' query
|
@@ -207,6 +207,7 @@ module EnfCli
|
|
207
207
|
desc "set-group-default-network", "Set /64 network as default for the DAA group"
|
208
208
|
method_option :'network', :type => :string, :required => true
|
209
209
|
method_option *option_gid
|
210
|
+
|
210
211
|
def set_group_default_network
|
211
212
|
try_with_rescue_in_session do
|
212
213
|
network = EnfCli::IPV6Cidr.new(options[:network]).to_s
|
@@ -221,7 +222,7 @@ module EnfCli
|
|
221
222
|
# create MODIFIED_GROUP
|
222
223
|
modified_group = {
|
223
224
|
:gid => gid,
|
224
|
-
:default_network => network
|
225
|
+
:default_network => network,
|
225
226
|
}
|
226
227
|
|
227
228
|
# Post to server
|
@@ -234,6 +235,7 @@ module EnfCli
|
|
234
235
|
desc "set-group-domain", "Set /48 domain for the DAA group"
|
235
236
|
method_option :'domain', :type => :string, :required => true
|
236
237
|
method_option *option_gid
|
238
|
+
|
237
239
|
def set_group_domain
|
238
240
|
try_with_rescue_in_session do
|
239
241
|
domain = EnfCli::IPV6Cidr.new(options[:domain]).to_s
|
@@ -248,7 +250,7 @@ module EnfCli
|
|
248
250
|
# create MODIFIED_GROUP
|
249
251
|
modified_group = {
|
250
252
|
:gid => gid,
|
251
|
-
:domain => domain
|
253
|
+
:domain => domain,
|
252
254
|
}
|
253
255
|
|
254
256
|
# Post to server
|
@@ -262,6 +264,7 @@ module EnfCli
|
|
262
264
|
method_option :'network', :type => :string, :required => true
|
263
265
|
method_option *option_gid
|
264
266
|
method_option :'set_as_default', :type => :boolean, default: false, desc: "Set the network as the default for this group"
|
267
|
+
|
265
268
|
def add_group_to_network
|
266
269
|
try_with_rescue_in_session do
|
267
270
|
network = EnfCli::IPV6Cidr.new(options[:network]).to_s
|
@@ -276,7 +279,7 @@ module EnfCli
|
|
276
279
|
if options[:set_as_default]
|
277
280
|
modified_group = {
|
278
281
|
:gid => gid,
|
279
|
-
:default_network => network
|
282
|
+
:default_network => network,
|
280
283
|
}
|
281
284
|
|
282
285
|
EnfApi::Iam.instance.update_group gid, modified_group
|
@@ -291,6 +294,7 @@ module EnfCli
|
|
291
294
|
desc "provision-group", "Provision a DAA Group"
|
292
295
|
method_option :'device-count', :type => :numeric, :required => true
|
293
296
|
method_option :'operator', :type => :array, :required => true, :banner => "OPERATOR"
|
297
|
+
|
294
298
|
def provision_group
|
295
299
|
try_with_rescue_in_session do
|
296
300
|
qr_code_info = scan_group_qr_code()
|
@@ -311,16 +315,16 @@ module EnfCli
|
|
311
315
|
new_provisioning = {
|
312
316
|
:group_id => gid,
|
313
317
|
:quantity => quantity,
|
314
|
-
:operator => operator
|
318
|
+
:operator => operator,
|
315
319
|
}
|
316
320
|
|
317
321
|
# create NEW_GROUP
|
318
322
|
new_group = {
|
319
323
|
:group_public_key => gpk,
|
320
324
|
:basename => basename,
|
321
|
-
:provisionings => [
|
325
|
+
:provisionings => [new_provisioning],
|
322
326
|
}
|
323
|
-
|
327
|
+
|
324
328
|
# Post to server
|
325
329
|
EnfApi::Iam.instance.provision_group new_group
|
326
330
|
|
@@ -330,16 +334,17 @@ module EnfCli
|
|
330
334
|
end
|
331
335
|
|
332
336
|
desc "create-endpoint-key", "Generate a pem encoded EC key pair"
|
333
|
-
method_option :'key-out-file', :type => :string, :required => true, :banner =>
|
334
|
-
method_option :'public-key-out-file', :type => :string, :required => true, :banner =>
|
337
|
+
method_option :'key-out-file', :type => :string, :required => true, :banner => "<file>"
|
338
|
+
method_option :'public-key-out-file', :type => :string, :required => true, :banner => "<file>"
|
339
|
+
|
335
340
|
def create_endpoint_key
|
336
341
|
try_with_rescue_in_session do
|
337
342
|
# get options
|
338
|
-
keyfile = options[
|
339
|
-
pubfile = options[
|
343
|
+
keyfile = options["key-out-file"]
|
344
|
+
pubfile = options["public-key-out-file"]
|
340
345
|
|
341
346
|
# Generate a key pair
|
342
|
-
key = OpenSSL::PKey::EC.new(
|
347
|
+
key = OpenSSL::PKey::EC.new("prime256v1")
|
343
348
|
key.generate_key
|
344
349
|
|
345
350
|
# write key pair to file
|
@@ -347,20 +352,21 @@ module EnfCli
|
|
347
352
|
|
348
353
|
# write public key to file
|
349
354
|
key.private_key = nil
|
350
|
-
write_pem_file pubfile, key.to_pem
|
355
|
+
write_pem_file pubfile, key.to_pem
|
351
356
|
end
|
352
357
|
end
|
353
358
|
|
354
359
|
desc "create-endpoint-cert", "Creates and signs a certificate for a particular identity using the provided private key"
|
355
|
-
method_option :'identity', :type => :string, :required => true, :banner =>
|
356
|
-
method_option :'key-in-file', :type => :string, :required => true, :banner =>
|
357
|
-
method_option :'cert-out-file', :type => :string, :required => true, :banner =>
|
360
|
+
method_option :'identity', :type => :string, :required => true, :banner => "<ipv6>"
|
361
|
+
method_option :'key-in-file', :type => :string, :required => true, :banner => "<file>"
|
362
|
+
method_option :'cert-out-file', :type => :string, :required => true, :banner => "<file>"
|
363
|
+
|
358
364
|
def create_endpoint_cert
|
359
365
|
try_with_rescue_in_session do
|
360
366
|
# get options
|
361
|
-
ipv6 = EnfCli::IPV6.new(options[
|
362
|
-
keyfile = EnfCli::expand_path(options[
|
363
|
-
certfile = EnfCli::expand_path(options[
|
367
|
+
ipv6 = EnfCli::IPV6.new(options["identity"]).to_s
|
368
|
+
keyfile = EnfCli::expand_path(options["key-in-file"])
|
369
|
+
certfile = EnfCli::expand_path(options["cert-out-file"])
|
364
370
|
|
365
371
|
# read the private key
|
366
372
|
key = read_ec_key_file keyfile
|
@@ -369,18 +375,19 @@ module EnfCli
|
|
369
375
|
cert = EnfCli::generate_ec_cert(key, ipv6)
|
370
376
|
|
371
377
|
# write to file
|
372
|
-
write_pem_file certfile, cert.to_pem
|
378
|
+
write_pem_file certfile, cert.to_pem
|
373
379
|
end
|
374
380
|
end
|
375
381
|
|
376
382
|
desc "create-endpoint-in-network", "Create an IPV6 endpoint in /64 network"
|
377
383
|
method_option :'network', :type => :string, :required => true, :banner => "<ipv6 network>"
|
378
384
|
method_option :'public-key-in-file', :type => :string, :required => true, :banner => "<file>"
|
385
|
+
|
379
386
|
def create_endpoint_in_network
|
380
387
|
try_with_rescue_in_session do
|
381
388
|
# Read options
|
382
389
|
network = EnfCli::IPV6Cidr.new(options[:network]).to_s
|
383
|
-
keyfile = EnfCli::expand_path(options[
|
390
|
+
keyfile = EnfCli::expand_path(options["public-key-in-file"])
|
384
391
|
|
385
392
|
# read keyfile
|
386
393
|
key = read_ec_key_file keyfile
|
@@ -392,49 +399,50 @@ module EnfCli
|
|
392
399
|
# create NEW_CREDENTIAL_ECDSA
|
393
400
|
new_credential = {
|
394
401
|
:type => "ecdsa_p256",
|
395
|
-
:key => pubkey
|
402
|
+
:key => pubkey,
|
396
403
|
}
|
397
|
-
|
404
|
+
|
398
405
|
# create NEW_ENDPOINT_AUTH
|
399
406
|
new_endpoint = {
|
400
407
|
:ecdsa_credential => new_credential,
|
401
408
|
:address_request => {
|
402
|
-
:network => network
|
403
|
-
}
|
409
|
+
:network => network,
|
410
|
+
},
|
404
411
|
}
|
405
412
|
|
406
413
|
data = EnfApi::Iam.instance.provision_endpoint new_endpoint
|
407
414
|
provisioned_ip = data[:address]
|
408
|
-
|
415
|
+
|
409
416
|
say "Created new ipv6 endpoint #{provisioned_ip}", :green
|
410
417
|
end
|
411
418
|
end
|
412
419
|
|
413
420
|
desc "create-endpoint-with-address", "Create an IPV6 endpoint in /64 network with user specified address"
|
414
421
|
method_option :'address', :type => :string, :required => true, :banner => "<ipv6 address>"
|
415
|
-
method_option :'public-key-in-file', :type => :string, :required => true, :banner => "<file>"
|
422
|
+
method_option :'public-key-in-file', :type => :string, :required => true, :banner => "<file>"
|
423
|
+
|
416
424
|
def create_endpoint_with_address
|
417
425
|
try_with_rescue_in_session do
|
418
426
|
# Read address
|
419
427
|
ipv6_address = EnfCli::IPV6.new options[:address]
|
420
428
|
|
421
429
|
# read key
|
422
|
-
keyfile = EnfCli::expand_path(options[
|
430
|
+
keyfile = EnfCli::expand_path(options["public-key-in-file"])
|
423
431
|
key = read_ec_key_file keyfile
|
424
432
|
pub = key.public_key
|
425
433
|
|
426
434
|
# create_endpoint
|
427
435
|
provision_endpoint ipv6_address, pub
|
428
|
-
|
429
436
|
end
|
430
437
|
end
|
431
438
|
|
432
439
|
desc "create-endpoint-from-cert", "Create an IPV6 endpoint in /64 network with address from cert"
|
433
|
-
method_option :'cert-in-file', :type => :string, :required => true, :banner => "<file>"
|
440
|
+
method_option :'cert-in-file', :type => :string, :required => true, :banner => "<file>"
|
441
|
+
|
434
442
|
def create_endpoint_from_cert
|
435
443
|
try_with_rescue_in_session do
|
436
444
|
# read options
|
437
|
-
certfile = EnfCli::expand_path(options[
|
445
|
+
certfile = EnfCli::expand_path(options["cert-in-file"])
|
438
446
|
raise EnfCli::ERROR, "#{certfile} does not exist!" unless File.exists?(certfile)
|
439
447
|
|
440
448
|
# read cert file
|
@@ -445,42 +453,43 @@ module EnfCli
|
|
445
453
|
subject = cert.subject.to_a
|
446
454
|
|
447
455
|
# get ipv6 CN record
|
448
|
-
cn = subject.select { |d| "CN".eql?(
|
449
|
-
ipv6_address =
|
456
|
+
cn = subject.select { |d| "CN".eql?(d[0].upcase) }
|
457
|
+
ipv6_address = EnfCli::IPV6.new cn[0][1]
|
450
458
|
|
451
459
|
# get the public key
|
452
460
|
pub = cert.public_key.public_key
|
453
461
|
|
454
462
|
# create_endpoint
|
455
463
|
provision_endpoint ipv6_address, pub
|
456
|
-
|
457
|
-
end
|
464
|
+
end
|
458
465
|
end
|
459
466
|
|
460
467
|
desc "update-endpoint-key", "Update an IPV6 endpoint's credentials"
|
461
468
|
method_option :'address', :type => :string, :required => true, :banner => "<ipv6 address>"
|
462
469
|
method_option :'public-key-in-file', :type => :string, :required => true, :banner => "<file>"
|
470
|
+
|
463
471
|
def update_endpoint_key
|
464
472
|
try_with_rescue_in_session do
|
465
473
|
# Read address
|
466
474
|
ipv6_address = EnfCli::IPV6.new options[:address]
|
467
475
|
|
468
476
|
# read key
|
469
|
-
keyfile = EnfCli::expand_path(options[
|
477
|
+
keyfile = EnfCli::expand_path(options["public-key-in-file"])
|
470
478
|
key = read_ec_key_file keyfile
|
471
479
|
pub = key.public_key
|
472
480
|
|
473
481
|
# update endpoint
|
474
482
|
update_endpoint_credentials ipv6_address, pub
|
475
|
-
end
|
483
|
+
end
|
476
484
|
end
|
477
485
|
|
478
486
|
desc "update-endpoint-cert", "Update an IPV6 endpoint's credentials"
|
479
|
-
method_option :'cert-in-file', :type => :string, :required => true, :banner => "<file>"
|
487
|
+
method_option :'cert-in-file', :type => :string, :required => true, :banner => "<file>"
|
488
|
+
|
480
489
|
def update_endpoint_cert
|
481
490
|
try_with_rescue_in_session do
|
482
491
|
# read options
|
483
|
-
certfile = EnfCli::expand_path(options[
|
492
|
+
certfile = EnfCli::expand_path(options["cert-in-file"])
|
484
493
|
raise EnfCli::ERROR, "#{certfile} does not exist!" unless File.exists?(certfile)
|
485
494
|
|
486
495
|
# read cert file
|
@@ -491,8 +500,8 @@ module EnfCli
|
|
491
500
|
subject = cert.subject.to_a
|
492
501
|
|
493
502
|
# get ipv6 CN record
|
494
|
-
cn = subject.select { |d| "CN".eql?(
|
495
|
-
ipv6_address =
|
503
|
+
cn = subject.select { |d| "CN".eql?(d[0].upcase) }
|
504
|
+
ipv6_address = EnfCli::IPV6.new cn[0][1]
|
496
505
|
|
497
506
|
# get the public key
|
498
507
|
pub = cert.public_key.public_key
|
@@ -501,8 +510,6 @@ module EnfCli
|
|
501
510
|
update_endpoint_credentials ipv6_address, pub
|
502
511
|
end
|
503
512
|
end
|
504
|
-
|
505
|
-
end
|
513
|
+
end
|
506
514
|
end
|
507
515
|
end
|
508
|
-
|
data/lib/enfcli/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright 2018 Xaptum,Inc
|
2
|
+
# Copyright 2018-2020 Xaptum,Inc
|
3
3
|
#
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
5
|
# you may not use this file except in compliance with the License.
|
@@ -14,5 +14,5 @@
|
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
16
|
module EnfCli
|
17
|
-
VERSION =
|
17
|
+
VERSION = "5.0.0-alpha"
|
18
18
|
end
|