You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by mr...@apache.org on 2017/09/29 02:19:38 UTC

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

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

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


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

commit cef179c81f07f86413c720623995c17bd1bddd7d
Author: Vincent <sh...@us.ibm.com>
AuthorDate: Thu Sep 28 22:19:36 2017 -0400

    Add the support of certificate checking for secure mode (#39)
---
 whisk/client.go                  | 66 ++++++++++++++++++++++++++--------------
 whisk/client_test.go             | 59 ++++++++++++++++++++++++++++++-----
 whisk/testUtils.go               | 42 +++++++++++++++++++++++++
 whisk/wskprops_test.go           | 22 +-------------
 wski18n/i18n_resources.go        | 22 +++++++-------
 wski18n/resources/en_US.all.json |  8 +++++
 6 files changed, 158 insertions(+), 61 deletions(-)

diff --git a/whisk/client.go b/whisk/client.go
index aea23ec..8dfc454 100644
--- a/whisk/client.go
+++ b/whisk/client.go
@@ -113,28 +113,6 @@ func NewClient(httpClient *http.Client, config_input *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,
-            }
-        }
-
-        httpClient.Transport = &http.Transport{
-            TLSClientConfig: tlsConfig,
-        }
-    }
-
     var err error
     var errStr = ""
     if len(config.Host) == 0 {
@@ -153,6 +131,46 @@ func NewClient(httpClient *http.Client, config_input *Config) (*Client, error) {
         return nil, werr
     }
 
+    var tlsConfig *tls.Config
+    // Disable certificate checking in the environment for insecure mode
+    if config.Insecure {
+        Debug(DbgInfo, "Disabling certificate checking.\n")
+        tlsConfig = &tls.Config{
+            InsecureSkipVerify: true,
+        }
+        if config.Cert != "" && config.Key != "" {
+            if cert, err := ReadX509KeyPair(config.Cert, config.Key); err == nil {
+                tlsConfig = &tls.Config{
+                    Certificates: []tls.Certificate{cert},
+                    InsecureSkipVerify: true,
+                }
+            }
+        }
+    } else {
+        // Enable certificate checking in the environment for secure mode
+        if config.Cert != "" && config.Key != "" {
+            if cert, err := ReadX509KeyPair(config.Cert, config.Key); err == nil {
+                tlsConfig = &tls.Config{
+                    Certificates: []tls.Certificate{cert},
+                }
+            } else {
+                errStr = wski18n.T("Unable to enable the certificate checking due to the reason: {{.err}}.\n",
+                    map[string]interface{}{ "err": err })
+            }
+        } else {
+            errStr = wski18n.T("Unable to enable the certificate checking, because both of the certificate and the key are missing.\n")
+        }
+
+        if len(errStr) != 0 {
+            werr := MakeWskError(errors.New(errStr), EXIT_CODE_ERR_GENERAL, DISPLAY_MSG, NO_DISPLAY_USAGE)
+            return nil, werr
+        }
+    }
+
+    httpClient.Transport = &http.Transport{
+        TLSClientConfig: tlsConfig,
+    }
+
     if len(config.Namespace) == 0 {
         config.Namespace = "_"
     }
@@ -183,6 +201,10 @@ func NewClient(httpClient *http.Client, config_input *Config) (*Client, error) {
     return c, nil
 }
 
+var ReadX509KeyPair = func(certFile, keyFile string) (tls.Certificate, error) {
+    return tls.LoadX509KeyPair(certFile, keyFile)
+}
+
 ///////////////////////////////
 // Request/Utility Functions //
 ///////////////////////////////
diff --git a/whisk/client_test.go b/whisk/client_test.go
index 1b3e748..4425e71 100644
--- a/whisk/client_test.go
+++ b/whisk/client_test.go
@@ -25,6 +25,7 @@ import (
     "net/http"
     "fmt"
     "net/url"
+    "crypto/tls"
 )
 
 const (
@@ -36,18 +37,20 @@ const (
     FakeAuthKey = "dhajfhshfs:hjhfsjfdjfjsgfjs"
 )
 
-func GetValidConfigTest() *Config {
+func GetValidConfigTest(insecure bool) *Config {
     var config Config
     config.Host = FakeHost
     config.Namespace = FakeNamespace
     config.AuthToken = FakeAuthKey
+    config.Insecure = insecure
     return &config
 }
 
-func GetInvalidConfigMissingApiHostTest() *Config {
+func GetInvalidConfigMissingApiHostTest(insecure bool) *Config {
     var config Config
     config.Namespace = FakeNamespace
     config.AuthToken = FakeAuthKey
+    config.Insecure = insecure
     return &config
 }
 
@@ -60,19 +63,20 @@ func GetInvalidConfigMissingApiHostWithBaseURLTest() *Config {
     return &config
 }
 
-func GetValidConfigDiffApiHostAndBaseURLTest() *Config {
+func GetValidConfigDiffApiHostAndBaseURLTest(insecure bool) *Config {
     var config Config
     urlBase := fmt.Sprintf("https://%s/api", FakeHostDiff)
     config.BaseURL, _ = url.Parse(urlBase)
     config.Host = FakeHost
     config.Namespace = FakeNamespace
     config.AuthToken = FakeAuthKey
+    config.Insecure = insecure
     return &config
 }
 
-func TestNewClient(t *testing.T) {
+func TestNewClientDisablingCertificate(t *testing.T) {
     // Test the use case to pass a valid config.
-    config := GetValidConfigTest()
+    config := GetValidConfigTest(true)
     client, err := NewClient(http.DefaultClient, config)
     assert.Nil(t, err)
     assert.NotNil(t, client)
@@ -82,7 +86,7 @@ func TestNewClient(t *testing.T) {
     assert.Equal(t, FakeAuthKey, client.Config.AuthToken)
 
     // Test the use case to pass an invalid config with a missing api host.
-    config = GetInvalidConfigMissingApiHostTest()
+    config = GetInvalidConfigMissingApiHostTest(true)
     client, err = NewClient(http.DefaultClient, config)
     assert.NotNil(t, err)
     assert.Contains(t, err.Error(), "Unable to create request URL, because OpenWhisk API host is missing")
@@ -96,7 +100,7 @@ func TestNewClient(t *testing.T) {
     assert.Nil(t, client)
 
     // Test the use case to pass a valid config with both the base and api host of different values.
-    config = GetValidConfigDiffApiHostAndBaseURLTest()
+    config = GetValidConfigDiffApiHostAndBaseURLTest(true)
     client, err = NewClient(http.DefaultClient, config)
     assert.Nil(t, err)
     assert.NotNil(t, client)
@@ -105,3 +109,44 @@ func TestNewClient(t *testing.T) {
     assert.Equal(t, FakeBaseURLDiff, client.Config.BaseURL.String())
     assert.Equal(t, FakeAuthKey, client.Config.AuthToken)
 }
+
+func TestNewClientEnablingCertificate(t *testing.T) {
+    TEST_KEY_FILE := "TEST_KEY_FILE"
+    TEST_CERT_FILE := "TEST_CERT_FILE"
+
+    // Test the use case to pass a config in secure mode missing the cert and key files.
+    config := GetValidConfigTest(false)
+    _, err := NewClient(http.DefaultClient, config)
+    assert.NotNil(t, err)
+
+    // Test the use case to pass a config in secure mode with non-existing the cert and key files.
+    config = GetValidConfigTest(false)
+    config.Key = TEST_KEY_FILE
+    config.Cert = TEST_CERT_FILE
+    _, err = NewClient(http.DefaultClient, config)
+    assert.NotNil(t, err)
+
+    // Test the use case to pass a config in secure mode with invalid the cert and key files.
+    CreateFile([]string{ "testKey" }, TEST_KEY_FILE)
+    CreateFile([]string{ "testCert" }, TEST_CERT_FILE)
+    config = GetValidConfigTest(false)
+    config.Key = TEST_KEY_FILE
+    config.Cert = TEST_CERT_FILE
+    _, err = NewClient(http.DefaultClient, config)
+    assert.NotNil(t, err)
+
+    // Test the use case to pass a config in secure mode with valid the cert and key files.
+    oldReadX509KeyPair := ReadX509KeyPair
+    defer func () { ReadX509KeyPair = oldReadX509KeyPair }()
+    ReadX509KeyPair = func(certFile, keyFile string) (tls.Certificate, error) {
+        cert := tls.Certificate{}
+        return cert, nil
+    }
+    config = GetValidConfigTest(false)
+    config.Key = TEST_KEY_FILE
+    config.Cert = TEST_CERT_FILE
+    _, err = NewClient(http.DefaultClient, config)
+    assert.Nil(t, err)
+    DeleteFile(TEST_KEY_FILE)
+    DeleteFile(TEST_CERT_FILE)
+}
diff --git a/whisk/testUtils.go b/whisk/testUtils.go
new file mode 100644
index 0000000..60152fc
--- /dev/null
+++ b/whisk/testUtils.go
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package whisk
+
+import (
+    "os"
+    "fmt"
+    "bufio"
+)
+
+func CreateFile(lines []string, path string) error {
+    file, err := os.Create(path)
+    if err != nil {
+        return err
+    }
+    defer file.Close()
+
+    w := bufio.NewWriter(file)
+    for _, line := range lines {
+        fmt.Fprintln(w, line)
+    }
+    return w.Flush()
+}
+
+func DeleteFile(path string) error {
+    return os.Remove(path)
+}
diff --git a/whisk/wskprops_test.go b/whisk/wskprops_test.go
index ce2b890..eff7dbb 100644
--- a/whisk/wskprops_test.go
+++ b/whisk/wskprops_test.go
@@ -1,4 +1,4 @@
-//// +build unit
+// +build unit
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -23,8 +23,6 @@ import (
     "testing"
     "github.com/stretchr/testify/assert"
     "os"
-    "fmt"
-    "bufio"
 )
 
 const (
@@ -142,24 +140,6 @@ func (pi FakePropertiesImp) GetPropsFromWhiskProperties() *Wskprops {
     return &dep
 }
 
-func CreateFile(lines []string, path string) error {
-    file, err := os.Create(path)
-    if err != nil {
-        return err
-    }
-    defer file.Close()
-
-    w := bufio.NewWriter(file)
-    for _, line := range lines {
-        fmt.Fprintln(w, line)
-    }
-    return w.Flush()
-}
-
-func DeleteFile(path string) error {
-    return os.Remove(path)
-}
-
 func TestGetPropsFromWhiskProperties(t *testing.T) {
     lines := []string{ EXPECTED_TEST_AUTH_KEY }
     CreateFile(lines, TEST_FILE)
diff --git a/wski18n/i18n_resources.go b/wski18n/i18n_resources.go
index 206cd63..df2cfa8 100644
--- a/wski18n/i18n_resources.go
+++ b/wski18n/i18n_resources.go
@@ -109,12 +109,12 @@ func wski18nResourcesDe_deAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/de_DE.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1506031186, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/de_DE.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1500156160, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
 
-var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x98\x51\x6f\xdb\x36\x10\xc7\xdf\xfd\x29\x0e\x7a\x71\x06\xb8\xfa\x00\xdd\x53\xb0\x19\x73\xb0\xae\x31\x56\x67\x7d\x58\x86\x81\x16\xcf\xd6\x21\x12\xc9\x92\x94\x3d\xd7\xd0\x77\x1f\x48\xd9\xb5\xd7\x48\x96\x44\x2b\x59\x9e\x62\x30\xbc\xff\xfd\x78\x3c\x1e\x8f\xfa\x73\x04\xb0\x1f\x01\x00\x44\xc4\xa3\xf7\x10\x3d\x08\xb6\xcc\x10\xac\x04\xc6\x39\x68\x59\x58\x04\xa9\x2c\x49\x61\x60\xbc\xdf\xc7\x87\xdf\x65\x39\x8e [...]
+var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x58\x5f\x6f\xdb\x36\x10\x7f\xf7\xa7\x38\xf8\xc5\x19\xe0\xea\x03\x74\x4f\xc1\x66\xcc\xc1\xba\xc6\x58\x9d\xf5\x61\x19\x06\x5a\x3c\x47\x87\xc8\x3c\x95\xa4\x9c\xb9\x86\xbe\xfb\x70\x94\x5c\x67\x8d\x65\xfd\xb1\xda\xe5\xc9\x02\xcd\xfb\xdd\x8f\x77\xc7\xfb\xc3\x3f\x47\x00\xfb\x11\x00\xc0\x98\xf4\xf8\x2d\x8c\xef\x8c\x5a\xa5\x08\x9e\x41\x69\x0d\x96\x73\x8f\xc0\x99\x27\x36\x0e\x26\xfb\x7d\x54\x7d\x17\xc5\x64\x3c [...]
 
 func wski18nResourcesEn_usAllJsonBytes() ([]byte, error) {
     return bindataRead(
@@ -129,7 +129,7 @@ func wski18nResourcesEn_usAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 6538, mode: os.FileMode(420), modTime: time.Unix(1506031828, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 6974, mode: os.FileMode(420), modTime: time.Unix(1506610567, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -149,7 +149,7 @@ func wski18nResourcesEs_esAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/es_ES.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1506031186, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/es_ES.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1500156160, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -169,7 +169,7 @@ func wski18nResourcesFr_frAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/fr_FR.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1506031186, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/fr_FR.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1500156160, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -189,7 +189,7 @@ func wski18nResourcesIt_itAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/it_IT.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1506031186, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/it_IT.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1500156160, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -209,7 +209,7 @@ func wski18nResourcesJa_jaAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/ja_JA.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1506031186, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/ja_JA.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1500156160, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -229,7 +229,7 @@ func wski18nResourcesKo_krAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/ko_KR.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1506031186, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/ko_KR.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1500156160, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -249,7 +249,7 @@ func wski18nResourcesPt_brAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/pt_BR.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1506031186, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/pt_BR.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1500156160, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -269,7 +269,7 @@ func wski18nResourcesZh_hansAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/zh_Hans.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1506031186, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/zh_Hans.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1500156160, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -289,7 +289,7 @@ func wski18nResourcesZh_hantAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/zh_Hant.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1506031186, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/zh_Hant.all.json", size: 0, mode: os.FileMode(420), modTime: time.Unix(1500156160, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
diff --git a/wski18n/resources/en_US.all.json b/wski18n/resources/en_US.all.json
index 775cf4f..bd878a1 100644
--- a/wski18n/resources/en_US.all.json
+++ b/wski18n/resources/en_US.all.json
@@ -140,6 +140,14 @@
     "translation": "Unable to create request URL, because the api host '{{.host}}' is invalid: {{.err}}"
   },
   {
+    "id": "Unable to enable the certificate checking due to the reason: {{.err}}.\n",
+    "translation": "Unable to enable the certificate checking due to the reason: {{.err}}.\n"
+  },
+  {
+    "id": "Unable to enable the certificate checking, because both of the certificate and the key are missing.\n",
+    "translation": "Unable to enable the certificate checking, because both of the certificate and the key are missing.\n"
+  },
+  {
     "id": "OpenWhisk API host is missing (Please configure WHISK_APIHOST in .wskprops under the system HOME directory.)",
     "translation": "OpenWhisk API host is missing (Please configure WHISK_APIHOST in .wskprops under the system HOME directory.)"
   },

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