You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by cs...@apache.org on 2017/11/10 17:01:07 UTC

[incubator-openwhisk] branch master updated: Add the support of certificate checking for secure mode (#2864)

This is an automated email from the ASF dual-hosted git repository.

csantanapr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk.git


The following commit(s) were added to refs/heads/master by this push:
     new 07b9b44  Add the support of certificate checking for secure mode (#2864)
07b9b44 is described below

commit 07b9b44cd9e920f796c0cc24dbd506ed62d09f6c
Author: Vincent <sh...@us.ibm.com>
AuthorDate: Fri Nov 10 12:01:04 2017 -0500

    Add the support of certificate checking for secure mode (#2864)
    
    Closes: #2863
---
 .../src/test/scala/system/basic/WskSdkTests.scala  |  55 +++++++++
 .../scala/whisk/core/cli/test/WskConfigTests.scala | 132 +++++++++++++++++++++
 tools/cli/go-whisk/whisk/client.go                 |  82 +++++++++----
 tools/cli/go-whisk/whisk/info.go                   |   4 +
 tools/cli/go-whisk/whisk/sdk.go                    |   5 +-
 .../cli/go-whisk/wski18n/resources/en_US.all.json  |  12 ++
 6 files changed, 267 insertions(+), 23 deletions(-)

diff --git a/tests/src/test/scala/system/basic/WskSdkTests.scala b/tests/src/test/scala/system/basic/WskSdkTests.scala
index 021e8ca..b36c823 100644
--- a/tests/src/test/scala/system/basic/WskSdkTests.scala
+++ b/tests/src/test/scala/system/basic/WskSdkTests.scala
@@ -18,6 +18,8 @@
 package system.basic
 
 import java.io.File
+import java.io.BufferedWriter
+import java.io.FileWriter
 
 import org.apache.commons.io.FileUtils
 import org.junit.runner.RunWith
@@ -120,4 +122,57 @@ class WskSdkTests extends TestHelpers with WskTestHelpers {
     val stdout = wsk.cli(Seq("sdk", "install", "bashauto", "--stdout")).stdout
     stdout should include(msg)
   }
+
+  def verifyMissingSecurityFile(config: String, fileName: String, expectedErrorMessage: String) = {
+    val tmpwskprops = File.createTempFile("wskprops", ".tmp")
+    val securityFile = File.createTempFile(fileName, ".pem")
+    try {
+      val writer = new BufferedWriter(new FileWriter(tmpwskprops))
+      writer.write(s"$config=${securityFile.getAbsolutePath()}\n")
+      writer.close()
+      val env = Map("WSK_CONFIG_FILE" -> tmpwskprops.getAbsolutePath())
+      val stderr = wsk
+        .cli(
+          Seq("sdk", "install", "docker", "--apihost", wskprops.apihost, "--apiversion", wskprops.apiversion),
+          env = env,
+          expectedExitCode = ERROR_EXIT)
+        .stderr
+      stderr should include regex (expectedErrorMessage)
+    } finally {
+      tmpwskprops.delete()
+      securityFile.delete()
+    }
+  }
+
+  it should "return configure the missing Key file" in {
+    verifyMissingSecurityFile("CERT", "cert", "The Key file is not configured. Please configure the missing Key file.")
+  }
+
+  it should "return configure the missing Cert file" in {
+    verifyMissingSecurityFile("KEY", "key", "The Cert file is not configured. Please configure the missing Cert file.")
+  }
+
+  it should "return unable to load the X509 key pair with both Cert and Key files missing" in {
+    val tmpwskprops = File.createTempFile("wskprops", ".tmp")
+    val certFile = File.createTempFile("cert", ".pem")
+    val keyFile = File.createTempFile("key", ".pem")
+    try {
+      val writer = new BufferedWriter(new FileWriter(tmpwskprops))
+      writer.write(s"CERT=${certFile.getAbsolutePath()}\n")
+      writer.write(s"KEY=${keyFile.getAbsolutePath()}\n")
+      writer.close()
+      val env = Map("WSK_CONFIG_FILE" -> tmpwskprops.getAbsolutePath())
+      val stderr = wsk
+        .cli(
+          Seq("sdk", "install", "docker", "--apihost", wskprops.apihost, "--apiversion", wskprops.apiversion),
+          env = env,
+          expectedExitCode = ERROR_EXIT)
+        .stderr
+      stderr should include regex ("""Unable to load the X509 key pair due to the following reason""")
+    } finally {
+      tmpwskprops.delete()
+      certFile.delete()
+      keyFile.delete()
+    }
+  }
 }
diff --git a/tests/src/test/scala/whisk/core/cli/test/WskConfigTests.scala b/tests/src/test/scala/whisk/core/cli/test/WskConfigTests.scala
index e4e14e9..220953b 100644
--- a/tests/src/test/scala/whisk/core/cli/test/WskConfigTests.scala
+++ b/tests/src/test/scala/whisk/core/cli/test/WskConfigTests.scala
@@ -279,6 +279,72 @@ class WskConfigTests extends TestHelpers with WskTestHelpers {
     }
   }
 
+  it should "return configure the missing Cert file" in {
+    val tmpwskprops = File.createTempFile("wskprops", ".tmp")
+    val keyFile = File.createTempFile("key", ".pem")
+    try {
+      val writer = new BufferedWriter(new FileWriter(tmpwskprops))
+      writer.write(s"KEY=${keyFile.getAbsolutePath()}\n")
+      writer.close()
+      val env = Map("WSK_CONFIG_FILE" -> tmpwskprops.getAbsolutePath())
+      val stderr = wsk
+        .cli(
+          Seq("property", "get", "--apibuild", "--apihost", wskprops.apihost, "--apiversion", wskprops.apiversion),
+          env = env,
+          expectedExitCode = ERROR_EXIT)
+        .stderr
+      stderr should include regex ("""The Cert file is not configured. Please configure the missing Cert file.""")
+    } finally {
+      tmpwskprops.delete()
+      keyFile.delete()
+    }
+  }
+
+  it should "return configure the missing Key file" in {
+    val tmpwskprops = File.createTempFile("wskprops", ".tmp")
+    val certFile = File.createTempFile("cert", ".pem")
+    try {
+      val writer = new BufferedWriter(new FileWriter(tmpwskprops))
+      writer.write(s"CERT=${certFile.getAbsolutePath()}\n")
+      writer.close()
+      val env = Map("WSK_CONFIG_FILE" -> tmpwskprops.getAbsolutePath())
+      val stderr = wsk
+        .cli(
+          Seq("property", "get", "--apibuild", "--apihost", wskprops.apihost, "--apiversion", wskprops.apiversion),
+          env = env,
+          expectedExitCode = ERROR_EXIT)
+        .stderr
+      stderr should include regex ("""The Key file is not configured. Please configure the missing Key file.""")
+    } finally {
+      tmpwskprops.delete()
+      certFile.delete()
+    }
+  }
+
+  it should "return unable to load the X509 key pair with both Cert and Key files missing" in {
+    val tmpwskprops = File.createTempFile("wskprops", ".tmp")
+    val certFile = File.createTempFile("cert", ".pem")
+    val keyFile = File.createTempFile("key", ".pem")
+    try {
+      val writer = new BufferedWriter(new FileWriter(tmpwskprops))
+      writer.write(s"CERT=${certFile.getAbsolutePath()}\n")
+      writer.write(s"KEY=${keyFile.getAbsolutePath()}\n")
+      writer.close()
+      val env = Map("WSK_CONFIG_FILE" -> tmpwskprops.getAbsolutePath())
+      val stderr = wsk
+        .cli(
+          Seq("property", "get", "--apibuild", "--apihost", wskprops.apihost, "--apiversion", wskprops.apiversion),
+          env = env,
+          expectedExitCode = ERROR_EXIT)
+        .stderr
+      stderr should include regex ("""Unable to load the X509 key pair due to the following reason""")
+    } finally {
+      tmpwskprops.delete()
+      certFile.delete()
+      keyFile.delete()
+    }
+  }
+
   it should "set api host with or without http prefix" in {
     val tmpwskprops = File.createTempFile("wskprops", ".tmp")
     try {
@@ -357,4 +423,70 @@ class WskConfigTests extends TestHelpers with WskTestHelpers {
     }
     tmpProps.delete()
   }
+
+  it should "return configure the missing Cert file for action" in {
+    val tmpwskprops = File.createTempFile("wskprops", ".tmp")
+    val keyFile = File.createTempFile("key", ".pem")
+    try {
+      val writer = new BufferedWriter(new FileWriter(tmpwskprops))
+      writer.write(s"KEY=${keyFile.getAbsolutePath()}\n")
+      writer.close()
+      val env = Map("WSK_CONFIG_FILE" -> tmpwskprops.getAbsolutePath())
+      val stderr = wsk
+        .cli(
+          Seq("action", "list", "--apihost", wskprops.apihost, "--apiversion", wskprops.apiversion),
+          env = env,
+          expectedExitCode = ERROR_EXIT)
+        .stderr
+      stderr should include regex ("""The Cert file is not configured. Please configure the missing Cert file.""")
+    } finally {
+      tmpwskprops.delete()
+      keyFile.delete()
+    }
+  }
+
+  it should "return configure the missing Key file for action" in {
+    val tmpwskprops = File.createTempFile("wskprops", ".tmp")
+    val certFile = File.createTempFile("cert", ".pem")
+    try {
+      val writer = new BufferedWriter(new FileWriter(tmpwskprops))
+      writer.write(s"CERT=${certFile.getAbsolutePath()}\n")
+      writer.close()
+      val env = Map("WSK_CONFIG_FILE" -> tmpwskprops.getAbsolutePath())
+      val stderr = wsk
+        .cli(
+          Seq("action", "list", "--apihost", wskprops.apihost, "--apiversion", wskprops.apiversion),
+          env = env,
+          expectedExitCode = ERROR_EXIT)
+        .stderr
+      stderr should include regex ("""The Key file is not configured. Please configure the missing Key file.""")
+    } finally {
+      tmpwskprops.delete()
+      certFile.delete()
+    }
+  }
+
+  it should "return unable to load the X509 key pair with both Cert and Key files missing for action" in {
+    val tmpwskprops = File.createTempFile("wskprops", ".tmp")
+    val certFile = File.createTempFile("cert", ".pem")
+    val keyFile = File.createTempFile("key", ".pem")
+    try {
+      val writer = new BufferedWriter(new FileWriter(tmpwskprops))
+      writer.write(s"CERT=${certFile.getAbsolutePath()}\n")
+      writer.write(s"KEY=${keyFile.getAbsolutePath()}\n")
+      writer.close()
+      val env = Map("WSK_CONFIG_FILE" -> tmpwskprops.getAbsolutePath())
+      val stderr = wsk
+        .cli(
+          Seq("action", "list", "--apihost", wskprops.apihost, "--apiversion", wskprops.apiversion),
+          env = env,
+          expectedExitCode = ERROR_EXIT)
+        .stderr
+      stderr should include regex ("""Unable to load the X509 key pair due to the following reason""")
+    } finally {
+      tmpwskprops.delete()
+      certFile.delete()
+      keyFile.delete()
+    }
+  }
 }
diff --git a/tools/cli/go-whisk/whisk/client.go b/tools/cli/go-whisk/whisk/client.go
index 12bcbd4..7d502d8 100644
--- a/tools/cli/go-whisk/whisk/client.go
+++ b/tools/cli/go-whisk/whisk/client.go
@@ -94,28 +94,6 @@ var DefaultObfuscateArr = []ObfuscateSet{
 
 func NewClient(httpClient *http.Client, config *Config) (*Client, error) {
 
-    // Disable certificate checking in the dev environment if in insecure mode
-    if config.Insecure {
-        Debug(DbgInfo, "Disabling certificate checking.\n")
-        var tlsConfig *tls.Config
-        if config.Cert != "" && config.Key != "" {
-            if cert, err := tls.LoadX509KeyPair(config.Cert, config.Key); err == nil {
-                tlsConfig = &tls.Config{
-                    Certificates: []tls.Certificate{cert},
-                    InsecureSkipVerify: true,
-                }
-            }
-        }else{
-            tlsConfig = &tls.Config{
-                InsecureSkipVerify: true,
-            }
-        }
-
-        http.DefaultClient.Transport = &http.Transport{
-            TLSClientConfig: tlsConfig,
-        }
-    }
-
     if httpClient == nil {
         httpClient = http.DefaultClient
     }
@@ -162,11 +140,67 @@ func NewClient(httpClient *http.Client, config *Config) (*Client, error) {
     return c, nil
 }
 
+func (c *Client) LoadX509KeyPair() error {
+    tlsConfig := &tls.Config {
+        InsecureSkipVerify: c.Config.Insecure,
+    }
+
+    if c.Config.Cert != "" && c.Config.Key != "" {
+    	Debug(DbgWarn, "both are fine.\n")
+    	Debug(DbgWarn, c.Config.Cert)
+    	Debug(DbgWarn, c.Config.Key)
+        if cert, err := ReadX509KeyPair(c.Config.Cert, c.Config.Key); err == nil {
+        	Debug(DbgWarn, "both are fine good.\n")
+            tlsConfig.Certificates = []tls.Certificate{cert}
+        } else {
+        	Debug(DbgWarn, "both are fine go to bad.\n")
+            errStr := wski18n.T("Unable to load the X509 key pair due to the following reason: {{.err}}",
+                map[string]interface{}{"err": err})
+            werr := MakeWskError(errors.New(errStr), EXIT_CODE_ERR_GENERAL, DISPLAY_MSG, NO_DISPLAY_USAGE)
+            return werr
+        }
+    } else if !c.Config.Insecure {
+    	if c.Config.Cert == "" {
+    	    warningStr := "The Cert file is not configured. Please configure the missing Cert file, if there is a security issue accessing the service.\n"
+            Debug(DbgWarn, warningStr)
+            if c.Config.Key != "" {
+                errStr := wski18n.T("The Cert file is not configured. Please configure the missing Cert file.\n")
+                werr := MakeWskError(errors.New(errStr), EXIT_CODE_ERR_GENERAL, DISPLAY_MSG, NO_DISPLAY_USAGE)
+                return werr
+            }
+        }
+    	if c.Config.Key == "" {
+    	    warningStr := "The Key file is not configured. Please configure the missing Key file, if there is a security issue accessing the service.\n"
+            Debug(DbgWarn, warningStr)
+            if c.Config.Cert != "" {
+                errStr := wski18n.T("The Key file is not configured. Please configure the missing Key file.\n")
+                werr := MakeWskError(errors.New(errStr), EXIT_CODE_ERR_GENERAL, DISPLAY_MSG, NO_DISPLAY_USAGE)
+                return werr
+            }
+        }
+    }
+
+    c.client.Transport = &http.Transport{
+        TLSClientConfig: tlsConfig,
+    }
+
+    return nil
+}
+
+var ReadX509KeyPair = func(certFile, keyFile string) (tls.Certificate, error) {
+    return tls.LoadX509KeyPair(certFile, keyFile)
+}
+
 ///////////////////////////////
 // Request/Utility Functions //
 ///////////////////////////////
 
 func (c *Client) NewRequest(method, urlStr string, body interface{}, includeNamespaceInUrl bool) (*http.Request, error) {
+    werr := c.LoadX509KeyPair()
+    if werr != nil {
+        return nil, werr
+    }
+
     if (includeNamespaceInUrl) {
         if c.Config.Namespace != "" {
             urlStr = fmt.Sprintf("%s/namespaces/%s/%s", c.Config.Version, c.Config.Namespace, urlStr)
@@ -608,6 +642,10 @@ func (c *Client) NewRequestUrl(
         useAuthentication bool) (*http.Request, error) {
     var requestUrl *url.URL
     var err error
+    error := c.LoadX509KeyPair()
+    if error != nil {
+        return nil, error
+    }
 
     if (appendOpenWhiskPath) {
         var urlVerNamespaceStr string
diff --git a/tools/cli/go-whisk/whisk/info.go b/tools/cli/go-whisk/whisk/info.go
index b97344c..777b822 100644
--- a/tools/cli/go-whisk/whisk/info.go
+++ b/tools/cli/go-whisk/whisk/info.go
@@ -38,6 +38,10 @@ type InfoService struct {
 
 func (s *InfoService) Get() (*Info, *http.Response, error) {
     // make a request to c.BaseURL / v1
+    err := s.client.LoadX509KeyPair()
+    if err != nil {
+        return nil, nil, err
+    }
     urlStr := fmt.Sprintf("%s/%s", s.client.BaseURL.String(), s.client.Config.Version)
     u, err := url.Parse(urlStr)
     if err != nil {
diff --git a/tools/cli/go-whisk/whisk/sdk.go b/tools/cli/go-whisk/whisk/sdk.go
index df3178a..7a67dc9 100644
--- a/tools/cli/go-whisk/whisk/sdk.go
+++ b/tools/cli/go-whisk/whisk/sdk.go
@@ -39,7 +39,10 @@ type SdkRequest struct {
 
 // Install artifact {component = docker || swift || iOS}
 func (s *SdkService) Install(relFileUrl string) (*http.Response, error) {
-
+    err := s.client.LoadX509KeyPair()
+    if err != nil {
+        return nil, err
+    }
     baseURL := s.client.Config.BaseURL
     // Remove everything but the scheme, host, and port
     baseURL.Path, baseURL.RawQuery, baseURL.Fragment = "", "", ""
diff --git a/tools/cli/go-whisk/wski18n/resources/en_US.all.json b/tools/cli/go-whisk/wski18n/resources/en_US.all.json
index e473202..45d5393 100644
--- a/tools/cli/go-whisk/wski18n/resources/en_US.all.json
+++ b/tools/cli/go-whisk/wski18n/resources/en_US.all.json
@@ -122,5 +122,17 @@
   {
     "id": "The connection failed, or timed out. (HTTP status code {{.code}})",
     "translation": "The connection failed, or timed out. (HTTP status code {{.code}})"
+  },
+  {
+    "id": "Unable to load the X509 key pair due to the following reason: {{.err}}",
+    "translation": "Unable to load the X509 key pair due to the following reason: {{.err}}"
+  },
+  {
+    "id": "The Cert file is not configured. Please configure the missing Cert file.\n",
+    "translation": "The Cert file is not configured. Please configure the missing Cert file.\n"
+  },
+  {
+    "id": "The Key file is not configured. Please configure the missing Key file.\n",
+    "translation": "The Key file is not configured. Please configure the missing Key file.\n"
   }
 ]

-- 
To stop receiving notification emails like this one, please contact
['"commits@openwhisk.apache.org" <co...@openwhisk.apache.org>'].