leap_cli 1.5.6 → 1.6.2

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.
Files changed (62) hide show
  1. data/bin/leap +29 -6
  2. data/lib/leap/platform.rb +36 -1
  3. data/lib/leap_cli/commands/ca.rb +97 -20
  4. data/lib/leap_cli/commands/compile.rb +49 -8
  5. data/lib/leap_cli/commands/db.rb +13 -4
  6. data/lib/leap_cli/commands/deploy.rb +138 -29
  7. data/lib/leap_cli/commands/env.rb +76 -0
  8. data/lib/leap_cli/commands/facts.rb +10 -3
  9. data/lib/leap_cli/commands/inspect.rb +2 -2
  10. data/lib/leap_cli/commands/list.rb +10 -10
  11. data/lib/leap_cli/commands/node.rb +7 -132
  12. data/lib/leap_cli/commands/node_init.rb +169 -0
  13. data/lib/leap_cli/commands/pre.rb +4 -27
  14. data/lib/leap_cli/commands/ssh.rb +152 -0
  15. data/lib/leap_cli/commands/test.rb +22 -13
  16. data/lib/leap_cli/commands/user.rb +12 -4
  17. data/lib/leap_cli/commands/vagrant.rb +4 -4
  18. data/lib/leap_cli/config/filter.rb +175 -0
  19. data/lib/leap_cli/config/manager.rb +130 -61
  20. data/lib/leap_cli/config/node.rb +32 -0
  21. data/lib/leap_cli/config/object.rb +69 -44
  22. data/lib/leap_cli/config/object_list.rb +44 -39
  23. data/lib/leap_cli/config/secrets.rb +24 -12
  24. data/lib/leap_cli/config/tag.rb +7 -0
  25. data/lib/{core_ext → leap_cli/core_ext}/boolean.rb +0 -0
  26. data/lib/{core_ext → leap_cli/core_ext}/hash.rb +0 -0
  27. data/lib/{core_ext → leap_cli/core_ext}/json.rb +0 -0
  28. data/lib/{core_ext → leap_cli/core_ext}/nil.rb +0 -0
  29. data/lib/{core_ext → leap_cli/core_ext}/string.rb +0 -0
  30. data/lib/leap_cli/core_ext/yaml.rb +29 -0
  31. data/lib/leap_cli/exceptions.rb +24 -0
  32. data/lib/leap_cli/leapfile.rb +60 -10
  33. data/lib/{lib_ext → leap_cli/lib_ext}/capistrano_connections.rb +0 -0
  34. data/lib/{lib_ext → leap_cli/lib_ext}/gli.rb +0 -0
  35. data/lib/leap_cli/log.rb +1 -1
  36. data/lib/leap_cli/logger.rb +18 -1
  37. data/lib/leap_cli/markdown_document_listener.rb +1 -1
  38. data/lib/leap_cli/override/json.rb +11 -0
  39. data/lib/leap_cli/path.rb +20 -6
  40. data/lib/leap_cli/remote/leap_plugin.rb +2 -2
  41. data/lib/leap_cli/remote/puppet_plugin.rb +1 -1
  42. data/lib/leap_cli/remote/rsync_plugin.rb +1 -1
  43. data/lib/leap_cli/remote/tasks.rb +1 -1
  44. data/lib/leap_cli/ssh_key.rb +63 -1
  45. data/lib/leap_cli/util/remote_command.rb +19 -2
  46. data/lib/leap_cli/util/secret.rb +1 -1
  47. data/lib/leap_cli/util/x509.rb +3 -2
  48. data/lib/leap_cli/util.rb +11 -3
  49. data/lib/leap_cli/version.rb +2 -2
  50. data/lib/leap_cli.rb +24 -14
  51. data/vendor/certificate_authority/lib/certificate_authority/certificate.rb +85 -29
  52. data/vendor/certificate_authority/lib/certificate_authority/distinguished_name.rb +5 -0
  53. data/vendor/certificate_authority/lib/certificate_authority/extensions.rb +406 -41
  54. data/vendor/certificate_authority/lib/certificate_authority/key_material.rb +0 -34
  55. data/vendor/certificate_authority/lib/certificate_authority/serial_number.rb +6 -0
  56. data/vendor/certificate_authority/lib/certificate_authority/signing_request.rb +36 -1
  57. metadata +25 -24
  58. data/lib/leap_cli/commands/shell.rb +0 -89
  59. data/lib/leap_cli/config/macros.rb +0 -430
  60. data/lib/leap_cli/constants.rb +0 -7
  61. data/lib/leap_cli/requirements.rb +0 -19
  62. data/lib/lib_ext/markdown_document_listener.rb +0 -122
@@ -33,7 +33,7 @@ module CertificateAuthority
33
33
  self.serial_number = SerialNumber.new
34
34
  self.key_material = MemoryKeyMaterial.new
35
35
  self.not_before = Time.now
36
- self.not_after = Time.now + 60 * 60 * 24 * 365 #One year
36
+ self.not_after = Time.now + 60 * 60 * 24 * 365 # One year
37
37
  self.parent = self
38
38
  self.extensions = load_extensions()
39
39
 
@@ -41,12 +41,31 @@ module CertificateAuthority
41
41
 
42
42
  end
43
43
 
44
+ =begin
45
+ def self.from_openssl openssl_cert
46
+ unless openssl_cert.is_a? OpenSSL::X509::Certificate
47
+ raise "Can only construct from an OpenSSL::X509::Certificate"
48
+ end
49
+
50
+ certificate = Certificate.new
51
+ # Only subject, key_material, and body are used for signing
52
+ certificate.distinguished_name = DistinguishedName.from_openssl openssl_cert.subject
53
+ certificate.key_material.public_key = openssl_cert.public_key
54
+ certificate.openssl_body = openssl_cert
55
+ certificate.serial_number.number = openssl_cert.serial.to_i
56
+ certificate.not_before = openssl_cert.not_before
57
+ certificate.not_after = openssl_cert.not_after
58
+ # TODO extensions
59
+ certificate
60
+ end
61
+ =end
62
+
44
63
  def sign!(signing_profile={})
45
64
  raise "Invalid certificate #{self.errors.full_messages}" unless valid?
46
65
  merge_profile_with_extensions(signing_profile)
47
66
 
48
67
  openssl_cert = OpenSSL::X509::Certificate.new
49
- openssl_cert.version = 2
68
+ openssl_cert.version = 2
50
69
  openssl_cert.not_before = self.not_before
51
70
  openssl_cert.not_after = self.not_after
52
71
  openssl_cert.public_key = self.key_material.public_key
@@ -58,7 +77,6 @@ module CertificateAuthority
58
77
 
59
78
  require 'tempfile'
60
79
  t = Tempfile.new("bullshit_conf")
61
- # t = File.new("/tmp/openssl.cnf")
62
80
  ## The config requires a file even though we won't use it
63
81
  openssl_config = OpenSSL::Config.new(t.path)
64
82
 
@@ -85,7 +103,7 @@ module CertificateAuthority
85
103
  self.extensions.keys.sort{|a,b| b<=>a}.each do |k|
86
104
  e = extensions[k]
87
105
  next if e.to_s.nil? or e.to_s == "" ## If the extension returns an empty string we won't include it
88
- ext = factory.create_ext(e.openssl_identifier, e.to_s)
106
+ ext = factory.create_ext(e.openssl_identifier, e.to_s, e.critical)
89
107
  openssl_cert.add_extension(ext)
90
108
  end
91
109
 
@@ -94,9 +112,10 @@ module CertificateAuthority
94
112
  else
95
113
  digest = OpenSSL::Digest::Digest.new(signing_profile["digest"])
96
114
  end
97
- self.openssl_body = openssl_cert.sign(parent.key_material.private_key,digest)
98
- t.close! if t.is_a?(Tempfile)# We can get rid of the ridiculous temp file
99
- self.openssl_body
115
+
116
+ self.openssl_body = openssl_cert.sign(parent.key_material.private_key, digest)
117
+ ensure
118
+ t.close! if t # We can get rid of the ridiculous temp file
100
119
  end
101
120
 
102
121
  def is_signing_entity?
@@ -116,6 +135,34 @@ module CertificateAuthority
116
135
  self.openssl_body.to_pem
117
136
  end
118
137
 
138
+ def to_csr
139
+ csr = SigningRequest.new
140
+ csr.distinguished_name = self.distinguished_name
141
+ csr.key_material = self.key_material
142
+ factory = OpenSSL::X509::ExtensionFactory.new
143
+ exts = []
144
+ self.extensions.keys.each do |k|
145
+ ## Don't copy over key identifiers for CSRs
146
+ next if k == "subjectKeyIdentifier" || k == "authorityKeyIdentifier"
147
+ e = extensions[k]
148
+ ## If the extension returns an empty string we won't include it
149
+ next if e.to_s.nil? or e.to_s == ""
150
+ exts << factory.create_ext(e.openssl_identifier, e.to_s, e.critical)
151
+ end
152
+ attrval = OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence(exts)])
153
+ attrs = [
154
+ OpenSSL::X509::Attribute.new("extReq", attrval),
155
+ OpenSSL::X509::Attribute.new("msExtReq", attrval)
156
+ ]
157
+ csr.attributes = attrs
158
+ csr
159
+ end
160
+
161
+ def self.from_x509_cert(raw_cert)
162
+ openssl_cert = OpenSSL::X509::Certificate.new(raw_cert)
163
+ Certificate.from_openssl(openssl_cert)
164
+ end
165
+
119
166
  def is_root_entity?
120
167
  self.parent == self && is_signing_entity?
121
168
  end
@@ -134,6 +181,16 @@ module CertificateAuthority
134
181
  items = signing_config[k]
135
182
  items.keys.each do |profile_item_key|
136
183
  if extension.respond_to?("#{profile_item_key}=".to_sym)
184
+ if k == 'subjectAltName' && profile_item_key == 'emails'
185
+ items[profile_item_key].map do |email|
186
+ if email == 'email:copy'
187
+ fail "no email address provided for subject: #{subject.to_x509_name}" unless subject.email_address
188
+ "email:#{subject.email_address}"
189
+ else
190
+ email
191
+ end
192
+ end
193
+ end
137
194
  extension.send("#{profile_item_key}=".to_sym, items[profile_item_key] )
138
195
  else
139
196
  p "Tried applying '#{profile_item_key}' to #{extension.class} but it doesn't respond!"
@@ -142,30 +199,25 @@ module CertificateAuthority
142
199
  end
143
200
  end
144
201
 
202
+ # Enumeration of the extensions. Not the worst option since
203
+ # the likelihood of these needing to be updated is low at best.
204
+ EXTENSIONS = [
205
+ CertificateAuthority::Extensions::BasicConstraints,
206
+ CertificateAuthority::Extensions::CrlDistributionPoints,
207
+ CertificateAuthority::Extensions::SubjectKeyIdentifier,
208
+ CertificateAuthority::Extensions::AuthorityKeyIdentifier,
209
+ CertificateAuthority::Extensions::AuthorityInfoAccess,
210
+ CertificateAuthority::Extensions::KeyUsage,
211
+ CertificateAuthority::Extensions::ExtendedKeyUsage,
212
+ CertificateAuthority::Extensions::SubjectAlternativeName,
213
+ CertificateAuthority::Extensions::CertificatePolicies
214
+ ]
215
+
145
216
  def load_extensions
146
217
  extension_hash = {}
147
218
 
148
- temp_extensions = []
149
- basic_constraints = CertificateAuthority::Extensions::BasicConstraints.new
150
- temp_extensions << basic_constraints
151
- crl_distribution_points = CertificateAuthority::Extensions::CrlDistributionPoints.new
152
- temp_extensions << crl_distribution_points
153
- subject_key_identifier = CertificateAuthority::Extensions::SubjectKeyIdentifier.new
154
- temp_extensions << subject_key_identifier
155
- authority_key_identifier = CertificateAuthority::Extensions::AuthorityKeyIdentifier.new
156
- temp_extensions << authority_key_identifier
157
- authority_info_access = CertificateAuthority::Extensions::AuthorityInfoAccess.new
158
- temp_extensions << authority_info_access
159
- key_usage = CertificateAuthority::Extensions::KeyUsage.new
160
- temp_extensions << key_usage
161
- extended_key_usage = CertificateAuthority::Extensions::ExtendedKeyUsage.new
162
- temp_extensions << extended_key_usage
163
- subject_alternative_name = CertificateAuthority::Extensions::SubjectAlternativeName.new
164
- temp_extensions << subject_alternative_name
165
- certificate_policies = CertificateAuthority::Extensions::CertificatePolicies.new
166
- temp_extensions << certificate_policies
167
-
168
- temp_extensions.each do |extension|
219
+ EXTENSIONS.each do |klass|
220
+ extension = klass.new
169
221
  extension_hash[extension.openssl_identifier] = extension
170
222
  end
171
223
 
@@ -192,7 +244,11 @@ module CertificateAuthority
192
244
  certificate.serial_number.number = openssl_cert.serial.to_i
193
245
  certificate.not_before = openssl_cert.not_before
194
246
  certificate.not_after = openssl_cert.not_after
195
- # TODO extensions
247
+ EXTENSIONS.each do |klass|
248
+ _,v,c = (openssl_cert.extensions.detect { |e| e.to_a.first == klass::OPENSSL_IDENTIFIER } || []).to_a
249
+ certificate.extensions[klass::OPENSSL_IDENTIFIER] = klass.parse(v, c) if v
250
+ end
251
+
196
252
  certificate
197
253
  end
198
254
 
@@ -32,11 +32,16 @@ module CertificateAuthority
32
32
  alias :emailAddress :email_address
33
33
  alias :emailAddress= :email_address=
34
34
 
35
+ attr_accessor :serial_number
36
+ alias :serialNumber :serial_number
37
+ alias :serialNumber= :serial_number=
38
+
35
39
  def to_x509_name
36
40
  raise "Invalid Distinguished Name" unless valid?
37
41
 
38
42
  # NB: the capitalization in the strings counts
39
43
  name = OpenSSL::X509::Name.new
44
+ name.add_entry("serialNumber", serial_number) unless serial_number.blank?
40
45
  name.add_entry("C", country) unless country.blank?
41
46
  name.add_entry("ST", state) unless state.blank?
42
47
  name.add_entry("L", locality) unless locality.blank?