From 30f42d5869f65d3171878b4d6d94e9c3813f02cf Mon Sep 17 00:00:00 2001
From: elijah <elijah@riseup.net>
Date: Fri, 23 Nov 2012 01:49:23 -0800
Subject: initial work toward 'leap test'. for now, it generates an openvpn
 config for client testing. try 'leap init-test'

---
 lib/leap_cli/commands/ca.rb   | 43 ++++++++++++++++++++++--
 lib/leap_cli/commands/test.rb | 26 +++++++++++++++
 lib/leap_cli/path.rb          | 76 +++++++++++++++++++++----------------------
 lib/leap_cli/util.rb          |  9 +++++
 4 files changed, 113 insertions(+), 41 deletions(-)
 create mode 100644 lib/leap_cli/commands/test.rb

(limited to 'lib')

diff --git a/lib/leap_cli/commands/ca.rb b/lib/leap_cli/commands/ca.rb
index 5aa0cde..05bdb2b 100644
--- a/lib/leap_cli/commands/ca.rb
+++ b/lib/leap_cli/commands/ca.rb
@@ -144,7 +144,7 @@ module LeapCli; module Commands
           cert.not_before = today
           cert.not_after  = years_from_today(1)
           cert.parent = ca_root
-          cert.sign! test_cert_signing_profile
+          cert.sign! domain_test_signing_profile
           write_file! [:commercial_cert, manager.provider.domain], cert.to_pem
           log "please replace this file with the real certificate you get from a CA using #{Path.relative_path([:commercial_csr, manager.provider.domain])}"
         end
@@ -217,6 +217,19 @@ module LeapCli; module Commands
     write_file!([:node_x509_cert, node.name], cert.to_pem)
   end
 
+  def generate_test_client_cert
+    cert = CertificateAuthority::Certificate.new
+    cert.serial_number.number = cert_serial_number(manager.provider.domain)
+    cert.subject.common_name = random_common_name(manager.provider.domain)
+    cert.not_before = today
+    cert.not_after  = years_from_today(1)
+    cert.key_material.generate_key(1024) # just for testing, remember!
+    cert.parent = ca_root
+    cert.sign! client_test_signing_profile
+    write_file! :test_client_key, cert.key_material.private_key.to_pem
+    write_file! :test_client_cert, cert.to_pem
+  end
+
   def ca_root
     @ca_root ||= begin
       load_certificate_file(:ca_cert, :ca_key)
@@ -277,7 +290,7 @@ module LeapCli; module Commands
   # with our own CA (for testing purposes). Typically, this cert would
   # be purchased from a commercial CA, and not signed this way.
   #
-  def test_cert_signing_profile
+  def domain_test_signing_profile
     {
       "digest" => "SHA256",
       "extensions" => {
@@ -291,6 +304,24 @@ module LeapCli; module Commands
     }
   end
 
+  #
+  # This is used when signing a dummy client certificate that is only to be
+  # used for testing.
+  #
+  def client_test_signing_profile
+    {
+      "digest" => "SHA256",
+      "extensions" => {
+        "keyUsage" => {
+          "usage" => ["digitalSignature", "keyAgreement"]
+        },
+        "extendedKeyUsage" => {
+          "usage" => ["clientAuth"]
+        }
+      }
+    }
+  end
+
   def dns_names_for_node(node)
     names = [node.domain.internal]
     if node['dns'] && node.dns['aliases'] && node.dns.aliases.any?
@@ -310,6 +341,14 @@ module LeapCli; module Commands
     Digest::MD5.hexdigest("#{domain_name} -- #{Time.now}").to_i(16)
   end
 
+  #
+  # for the random common name, we need a text string that will be unique across all certs.
+  # ruby 1.8 doesn't have a built-in uuid generator, or we would use SecureRandom.uuid
+  #
+  def random_common_name(domain_name)
+    cert_serial_number(domain_name).to_s(36)
+  end
+
   def today
     t = Time.now
     Time.utc t.year, t.month, t.day
diff --git a/lib/leap_cli/commands/test.rb b/lib/leap_cli/commands/test.rb
new file mode 100644
index 0000000..dc08652
--- /dev/null
+++ b/lib/leap_cli/commands/test.rb
@@ -0,0 +1,26 @@
+module LeapCli; module Commands
+
+  desc 'Creates files needed to run tests'
+  command :'init-test' do |c|
+    c.action do |global_options,options,args|
+      generate_test_client_cert
+      generate_test_client_openvpn_config
+    end
+  end
+
+  desc 'Run tests'
+  command :test do |c|
+    c.action do |global_options,options,args|
+      log 'not yet implemented'
+    end
+  end
+
+  private
+
+  def generate_test_client_openvpn_config
+    template = read_file! Path.find_file(:test_client_openvpn_template)
+    config = Util.erb_eval(template, binding)
+    write_file! :test_client_openvpn_config, config
+  end
+
+end; end
diff --git a/lib/leap_cli/path.rb b/lib/leap_cli/path.rb
index 98f4f99..27ffcce 100644
--- a/lib/leap_cli/path.rb
+++ b/lib/leap_cli/path.rb
@@ -19,6 +19,10 @@ module LeapCli; module Path
     :service_config   => 'services/#{arg}.json',
     :tag_config       => 'tags/#{arg}.json',
 
+    # input templates
+    :provider_json_template => 'files/service-definitions/provider.json.erb',
+    :eip_service_json_template => 'files/service-definitions/eip-service.json.erb',
+
     # input data files
     :commercial_cert  => 'files/cert/#{arg}.crt',
     :commercial_key   => 'files/cert/#{arg}.key',
@@ -38,9 +42,15 @@ module LeapCli; module Path
     :commercial_csr   => 'files/cert/#{arg}.csr',
     :commercial_cert  => 'files/cert/#{arg}.crt',
     :commercial_ca_cert  => 'files/cert/commercial_ca.crt',
-    :node_x509_key    => 'files/nodes/#{arg}/#{arg}.key',
-    :node_x509_cert   => 'files/nodes/#{arg}/#{arg}.crt',
-    :vagrantfile      => 'test/Vagrantfile'
+    :node_x509_key       => 'files/nodes/#{arg}/#{arg}.key',
+    :node_x509_cert      => 'files/nodes/#{arg}/#{arg}.crt',
+    :vagrantfile         => 'test/Vagrantfile',
+
+    # testing files
+    :test_client_key     => 'test/cert/client.key',
+    :test_client_cert    => 'test/cert/client.crt',
+    :test_client_openvpn_config   => 'test/openvpn/client.ovpn',
+    :test_client_openvpn_template => 'test/openvpn/client.ovpn.erb'
   }
 
   #
@@ -103,42 +113,30 @@ module LeapCli; module Path
   # all the places we search for a file when using find_file.
   # this is perhaps too many places.
   #
-  def self.search_path
-    @search_path ||= begin
-      search_path = []
-      [Path.provider_base, Path.provider].each do |provider|
-        files_dir = named_path(:files_dir, provider)
-        search_path << provider
-        search_path << named_path(:files_dir, provider)
-        search_path << named_path(:nodes_dir, files_dir)
-        search_path << named_path(:services_dir, files_dir)
-        search_path << named_path(:tags_dir, files_dir)
-      end
-      search_path
-    end
-  end
-
-  #
-  # tries to find a file somewhere with 'filename' (which is probably in the form [node.name, filename])
-  #
-  def self.find_file(filename)
-    # named path?
-    if filename.is_a? Array
-      path = named_path(filename, Path.provider_base)
-      return path if File.exists?(path)
-      path = named_path(filename, provider)
-      return path if File.exists?(path)
-    end
-
-    # otherwise, lets search
-    search_path.each do |path_root|
-      path = [path_root, name, filename].join('/')
-      return path if File.exists?(path)
-    end
-    search_path.each do |path_root|
-      path = [path_root, filename].join('/')
-      return path if File.exists?(path)
-    end
+  # def self.search_path
+  #   @search_path ||= begin
+  #     search_path = []
+  #     [Path.provider_base, Path.provider].each do |provider|
+  #       #files_dir = named_path(:files_dir, provider)
+  #       search_path << provider
+  #       #search_path << named_path(:files_dir, provider)
+  #       #search_path << named_path(:nodes_dir, files_dir)
+  #       #search_path << named_path(:services_dir, files_dir)
+  #       #search_path << named_path(:tags_dir, files_dir)
+  #     end
+  #     search_path
+  #   end
+  # end
+
+  #
+  # tries to find a file somewhere
+  #
+  def self.find_file(arg)
+    file_path = named_path(arg, Path.provider)
+    return file_path if File.exists?(file_path)
+
+    file_path = named_path(arg, Path.provider_base)
+    return file_path if File.exists?(file_path)
 
     # give up
     return nil
diff --git a/lib/leap_cli/util.rb b/lib/leap_cli/util.rb
index 0b0fb9e..c3adbdc 100644
--- a/lib/leap_cli/util.rb
+++ b/lib/leap_cli/util.rb
@@ -1,6 +1,7 @@
 require 'digest/md5'
 require 'paint'
 require 'fileutils'
+require 'erb'
 
 module LeapCli
 
@@ -276,6 +277,14 @@ module LeapCli
       STDOUT.puts
     end
 
+    ##
+    ## ERB
+    ##
+
+    def erb_eval(string, binding=nil)
+      ERB.new(string, nil, '%<>-').result(binding)
+    end
+
   end
 end
 
-- 
cgit v1.2.3