You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@openwhisk.apache.org by GitBox <gi...@apache.org> on 2017/11/10 17:01:09 UTC

[GitHub] csantanapr closed pull request #2864: Add the support of certificate checking for secure mode

csantanapr closed pull request #2864: Add the support of certificate checking for secure mode
URL: https://github.com/apache/incubator-openwhisk/pull/2864
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/tests/src/test/scala/system/basic/WskSdkTests.scala b/tests/src/test/scala/system/basic/WskSdkTests.scala
index 021e8cace1..b36c823db2 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 e4e14e9215..220953ba08 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 12bcbd409c..7d502d8a1b 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 b97344c90e..777b8223fc 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 df3178aa75..7a67dc9b6a 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 e473202f81..45d5393fd2 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"
   }
 ]


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services