diff options
author | Remigiusz Janeczek <remigiusz.janeczek@nokia.com> | 2020-10-22 09:18:12 +0200 |
---|---|---|
committer | Remigiusz Janeczek <remigiusz.janeczek@nokia.com> | 2020-10-22 16:00:36 +0000 |
commit | ee23e5f54f96807b1f1fff0b45238a247d3dd8e0 (patch) | |
tree | ec390b860e0c10810bd778a1b68dbfc8ab12c64a /certServiceK8sExternalProvider/src/certserviceclient | |
parent | aa23960c5d444dea307e0934b446f12ab0256689 (diff) |
[OOM-K8S-CERT-EXTERNAL-PROVIDER] Add client for CertService API
Issue-ID: OOM-2559
Signed-off-by: Remigiusz Janeczek <remigiusz.janeczek@nokia.com>
Change-Id: I3bf6c36b9eec7a661202b18eb7765e332ccfbc07
Diffstat (limited to 'certServiceK8sExternalProvider/src/certserviceclient')
4 files changed, 343 insertions, 0 deletions
diff --git a/certServiceK8sExternalProvider/src/certserviceclient/cert_service_client.go b/certServiceK8sExternalProvider/src/certserviceclient/cert_service_client.go new file mode 100644 index 00000000..870a3eda --- /dev/null +++ b/certServiceK8sExternalProvider/src/certserviceclient/cert_service_client.go @@ -0,0 +1,73 @@ +/* + * ============LICENSE_START======================================================= + * oom-certservice-k8s-external-provider + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package certserviceclient + +import ( + "encoding/base64" + "encoding/json" + "net/http" +) + +const ( + CsrHeaderName = "CSR" + PkHeaderName = "PK" +) + +type CertServiceClient interface { + GetCertificates(csr []byte, key []byte) (*CertificatesResponse, error) +} + +type CertServiceClientImpl struct { + certificationUrl string + httpClient HTTPClient +} + +type HTTPClient interface { + Do(req *http.Request) (*http.Response, error) +} + +type CertificatesResponse struct { + CertificateChain []string `json:"certificateChain"` + TrustedCertificates []string `json:"trustedCertificates"` +} + +func (client *CertServiceClientImpl) GetCertificates(csr []byte, key []byte) (*CertificatesResponse, error) { + + request, err := http.NewRequest("GET", client.certificationUrl, nil) + if err != nil { + return nil, err + } + + request.Header.Add(CsrHeaderName, base64.StdEncoding.EncodeToString(csr)) + request.Header.Add(PkHeaderName, base64.StdEncoding.EncodeToString(key)) + response, err := client.httpClient.Do(request) + if err != nil { + return nil, err + } + + var certificatesResponse CertificatesResponse + err = json.NewDecoder(response.Body).Decode(&certificatesResponse) + if err != nil { + return nil, err + } + + return &certificatesResponse, err +} diff --git a/certServiceK8sExternalProvider/src/certserviceclient/cert_service_client_factory.go b/certServiceK8sExternalProvider/src/certserviceclient/cert_service_client_factory.go new file mode 100644 index 00000000..198f2294 --- /dev/null +++ b/certServiceK8sExternalProvider/src/certserviceclient/cert_service_client_factory.go @@ -0,0 +1,74 @@ +/* + * ============LICENSE_START======================================================= + * oom-certservice-k8s-external-provider + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package certserviceclient + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + "net/http" + "net/url" + "path" +) + +func CreateCertServiceClient(baseUrl string, caName string, keyPemBase64 []byte, certPemBase64 []byte, cacertPemBase64 []byte) (*CertServiceClientImpl, error) { + cert, err := tls.X509KeyPair(certPemBase64, keyPemBase64) + if err != nil { + return nil, err + } + x509.NewCertPool() + caCertPool := x509.NewCertPool() + ok := caCertPool.AppendCertsFromPEM(cacertPemBase64) + if !ok { + return nil, fmt.Errorf("couldn't certs from cacert") + } + httpClient := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + Certificates: []tls.Certificate{cert}, + }, + }, + } + certificationUrl, err := parseUrl(baseUrl, caName) + if err != nil { + return nil, err + } + client := CertServiceClientImpl{ + certificationUrl: certificationUrl.String(), + httpClient: httpClient, + } + + return &client, nil +} + +func parseUrl(baseUrl string, caName string) (*url.URL, error) { + parsedUrl, err := url.Parse(baseUrl) + if err != nil { + return nil, err + } + if caName == "" { + return nil, fmt.Errorf("caName cannot be empty") + } + + parsedUrl.Path = path.Join(parsedUrl.Path, caName) + return parsedUrl, nil +} diff --git a/certServiceK8sExternalProvider/src/certserviceclient/cert_service_client_factory_test.go b/certServiceK8sExternalProvider/src/certserviceclient/cert_service_client_factory_test.go new file mode 100644 index 00000000..50a6d796 --- /dev/null +++ b/certServiceK8sExternalProvider/src/certserviceclient/cert_service_client_factory_test.go @@ -0,0 +1,95 @@ +/* + * ============LICENSE_START======================================================= + * oom-certservice-k8s-external-provider + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package certserviceclient + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "onap.org/oom-certservice/k8s-external-provider/src/testdata" +) + +const ( + validUrl = "https://oom-cert-service:8443/v1/certificate/" + validUrl2 = "https://oom-cert-service:8443/v1/certificate" + invalidUrl = "https://oom-cert service:8443/v1/certificate" + caName = "RA" + expectedCertificationUrl = "https://oom-cert-service:8443/v1/certificate/RA" +) + +func Test_shouldCreateCertServiceClient(t *testing.T) { + shouldCreateCertServiceClientWithExpectedUrl(t, expectedCertificationUrl, validUrl) + shouldCreateCertServiceClientWithExpectedUrl(t, expectedCertificationUrl, validUrl2) +} + +func shouldCreateCertServiceClientWithExpectedUrl(t *testing.T, expectedCertificationUrl string, baseUrl string) { + client, err := CreateCertServiceClient(baseUrl, caName, testdata.KeyBytes, testdata.CertBytes, testdata.CacertBytes) + + assert.NotNil(t, client) + assert.Nil(t, err) + assert.Equal(t, expectedCertificationUrl, client.certificationUrl) +} + +func Test_shouldReturnError_whenUrlInvalid(t *testing.T) { + client, err := CreateCertServiceClient(invalidUrl, caName, testdata.KeyBytes, testdata.CertBytes, testdata.CacertBytes) + + assert.Nil(t, client) + assert.Error(t, err) +} + +func Test_shouldReturnError_whenCanameEmpty(t *testing.T) { + client, err := CreateCertServiceClient(validUrl, "", testdata.KeyBytes, testdata.CertBytes, testdata.CacertBytes) + + assert.Nil(t, client) + assert.Error(t, err) +} + +func Test_shouldReturnError_whenKeyNotMatchingCert(t *testing.T) { + client, err := CreateCertServiceClient(validUrl, caName, testdata.NotMatchingKeyBytes, testdata.CertBytes, testdata.CacertBytes) + + assert.Nil(t, client) + assert.Error(t, err) +} + +func Test_shouldReturnError_whenKeyInvalid(t *testing.T) { + //Cert used as key + client, err := CreateCertServiceClient(validUrl, caName, testdata.CertBytes, testdata.CertBytes, testdata.CacertBytes) + + assert.Nil(t, client) + assert.Error(t, err) +} + +func Test_shouldReturnError_whenCertInvalid(t *testing.T) { + //Cacert used as cert + client, err := CreateCertServiceClient(validUrl, caName, testdata.KeyBytes, testdata.CacertBytes, testdata.CacertBytes) + + assert.Nil(t, client) + assert.Error(t, err) +} + +func Test_shouldReturnError_whenCacertInvalid(t *testing.T) { + //Key used as cacert + client, err := CreateCertServiceClient(validUrl, caName, testdata.KeyBytes, testdata.CertBytes, testdata.KeyBytes) + + assert.Nil(t, client) + assert.Error(t, err) +} diff --git a/certServiceK8sExternalProvider/src/certserviceclient/cert_service_client_test.go b/certServiceK8sExternalProvider/src/certserviceclient/cert_service_client_test.go new file mode 100644 index 00000000..1e15d43e --- /dev/null +++ b/certServiceK8sExternalProvider/src/certserviceclient/cert_service_client_test.go @@ -0,0 +1,101 @@ +/* + * ============LICENSE_START======================================================= + * oom-certservice-k8s-external-provider + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package certserviceclient + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" + + "onap.org/oom-certservice/k8s-external-provider/src/testdata" +) + +const ( + certificationUrl = "https://oom-cert-service:8443/v1/certificate/RA" +) + + +func Test_shouldParseCertificateResponseCorrectly(t *testing.T) { + responseJson := `{"certificateChain": ["cert-0", "cert-1"], "trustedCertificates": ["trusted-cert-0", "trusted-cert-1"]}` + responseJsonReader := ioutil.NopCloser(bytes.NewReader([]byte(responseJson))) + client := CertServiceClientImpl{ + certificationUrl: certificationUrl, + httpClient: &httpClientMock{ + DoFunc: func(req *http.Request) (response *http.Response, e error) { + mockedResponse := &http.Response{ + Body: responseJsonReader, + } + return mockedResponse, nil + }, + }, + } + response, _ := client.GetCertificates(testdata.CsrBytes, testdata.PkBytes) + assert.ElementsMatch(t, []string{"cert-0", "cert-1"}, response.CertificateChain) + assert.ElementsMatch(t, []string{"trusted-cert-0", "trusted-cert-1"}, response.TrustedCertificates) +} + +func Test_shouldReturnError_whenResponseIsNotJson(t *testing.T) { + responseJson := `not a json` + responseJsonReader := ioutil.NopCloser(bytes.NewReader([]byte(responseJson))) + client := CertServiceClientImpl{ + certificationUrl: certificationUrl, + httpClient: &httpClientMock{ + DoFunc: func(req *http.Request) (response *http.Response, e error) { + mockedResponse := &http.Response{ + Body: responseJsonReader, + } + return mockedResponse, nil + }, + }, + } + response, err := client.GetCertificates(testdata.CsrBytes, testdata.PkBytes) + + assert.Nil(t, response) + assert.Error(t, err) +} + +func Test_shouldReturnError_whenHttpClientReturnsError(t *testing.T) { + client := CertServiceClientImpl{ + certificationUrl: certificationUrl, + httpClient: &httpClientMock{ + DoFunc: func(req *http.Request) (response *http.Response, err error) { + return nil, fmt.Errorf("mock error") + }, + }, + } + response, err := client.GetCertificates(testdata.CsrBytes, testdata.PkBytes) + + assert.Nil(t, response) + assert.Error(t, err) +} + + +type httpClientMock struct { + DoFunc func(*http.Request) (*http.Response, error) +} + +func (client httpClientMock) Do(req *http.Request) (*http.Response, error) { + return client.DoFunc(req) +} |