diff --git a/Makefile b/Makefile index 223538a66..082e82191 100644 --- a/Makefile +++ b/Makefile @@ -16,19 +16,10 @@ watch: test-ci: setup test test-unit: - BASIC_AUTH_BOSH_URL=https://lite-bosh.backup-and-restore.cf-app.com \ - UAA_BOSH_URL=https://lite-bosh-uaa.backup-and-restore.cf-app.com \ ginkgo -r bosh orchestrator ssh artifact instance factory test-unit-local: - BASIC_AUTH_BOSH_URL=https://lite-bosh.backup-and-restore.cf-app.com \ - BASIC_AUTH_BOSH_CLIENT_SECRET=`lpass show LiteBoshDirector --password` \ - BASIC_AUTH_BOSH_CERT_PATH=~/workspace/bosh-backup-and-restore-meta/certs/lite-bosh.backup-and-restore.cf-app.com.crt \ - UAA_BOSH_URL=https://lite-bosh-uaa.backup-and-restore.cf-app.com \ - UAA_BOSH_CLIENT_SECRET=`lpass show GardenBoshUAADirectorGCP --password` \ - UAA_BOSH_CERT_PATH=~/workspace/bosh-backup-and-restore-meta/certs/lite-bosh-uaa.backup-and-restore.cf-app.com.crt \ - BOSH_GATEWAY_KEY=~/workspace/bosh-backup-and-restore-meta/genesis-bosh/bosh.pem \ - ginkgo -r bosh orchestrator ssh artifact instance + ginkgo -r bosh orchestrator ssh artifact instance factory test-integration: ginkgo -r integration -nodes 4 diff --git a/ci/scripts/unit.sh b/ci/scripts/unit.sh index 4b6a6d55e..7dac8f999 100755 --- a/ci/scripts/unit.sh +++ b/ci/scripts/unit.sh @@ -9,10 +9,6 @@ ssh-add bosh-backup-and-restore-meta/keys/github export GOPATH=$PWD export PATH=$PATH:$GOPATH/bin -export BASIC_AUTH_BOSH_CERT_PATH=`pwd`/bosh-backup-and-restore-meta/certs/lite-bosh.backup-and-restore.cf-app.com.crt -export UAA_BOSH_CERT_PATH=`pwd`/bosh-backup-and-restore-meta/certs/lite-bosh-uaa.backup-and-restore.cf-app.com.crt -export BOSH_GATEWAY_KEY=`pwd`/bosh-backup-and-restore-meta/genesis-bosh/bosh.pem - cd src/github.com/pivotal-cf/bosh-backup-and-restore make test-ci make clean-docker || true \ No newline at end of file diff --git a/ci/tasks/unit.yml b/ci/tasks/unit.yml index 516eb56a2..66e452586 100644 --- a/ci/tasks/unit.yml +++ b/ci/tasks/unit.yml @@ -16,5 +16,3 @@ run: params: TEAM_GPG_KEY: DOCKER_HOST: - BASIC_AUTH_BOSH_CLIENT_SECRET: - UAA_BOSH_CLIENT_SECRET: diff --git a/factory/build_client.go b/factory/build_client.go index c3803d15e..48c4411e6 100644 --- a/factory/build_client.go +++ b/factory/build_client.go @@ -14,61 +14,69 @@ import ( boshlog "github.com/cloudfoundry/bosh-utils/logger" ) -func BuildClient(targetUrl, username, password, caCert string, logger boshlog.Logger) (orchestrator.BoshClient, error) { +func BuildClient(targetUrl, username, password, caCertFileName string, logger boshlog.Logger) (orchestrator.BoshClient, error) { config, err := director.NewConfigFromURL(targetUrl) if err != nil { return nil, fmt.Errorf("Target director URL is malformed - %s", err.Error()) } - if caCert != "" { - cert, err := ioutil.ReadFile(caCert) + var cert string + if caCertFileName != "" { + certBytes, err := ioutil.ReadFile(caCertFileName) if err != nil { return nil, err } - config.CACert = string(cert) + cert = string(certBytes) } - factory := director.NewFactory(logger) - infoDirector, err := factory.New(config, director.NewNoopTaskReporter(), director.NewNoopFileReporter()) + config.CACert = cert - info, _ := infoDirector.Info() - - if info.Auth.Type == "uaa" { - uaaURL := info.Auth.Options["url"] + directorFactory := director.NewFactory(logger) + infoDirector, err := directorFactory.New(config, director.NewNoopTaskReporter(), director.NewNoopFileReporter()) + if err != nil { + return nil, err + } - uaaURLStr, ok := uaaURL.(string) - if !ok { - return nil, fmt.Errorf("Expected URL '%s' to be a string", uaaURL) - } + info, err := infoDirector.Info() + if err != nil { + return nil, err + } - uaaConfig, err := boshuaa.NewConfigFromURL(uaaURLStr) + if info.Auth.Type == "uaa" { + uaa, err := buildUaa(info, username, password, cert, logger) if err != nil { return nil, err } - if caCert != "" { - cert, err := ioutil.ReadFile(caCert) - if err != nil { - return nil, err - } - uaaConfig.CACert = string(cert) - } - - uaaConfig.Client = username - uaaConfig.ClientSecret = password - - uaa, _ := boshuaa.NewFactory(logger).New(uaaConfig) - config.TokenFunc = boshuaa.NewClientTokenSession(uaa).TokenFunc } else { config.Client = username config.ClientSecret = password } - boshDirector, err := factory.New(config, director.NewNoopTaskReporter(), director.NewNoopFileReporter()) + boshDirector, err := directorFactory.New(config, director.NewNoopTaskReporter(), director.NewNoopFileReporter()) if err != nil { return nil, err } return bosh.NewClient(boshDirector, director.NewSSHOpts, ssh.ConnectionCreator, logger, instance.NewJobFinder(logger)), nil } + +func buildUaa(info director.Info, username, password, cert string, logger boshlog.Logger) (boshuaa.UAA, error) { + urlAsInterface := info.Auth.Options["url"] + url, ok := urlAsInterface.(string) + if !ok { + return nil, fmt.Errorf("Expected URL '%s' to be a string", urlAsInterface) + } + + uaaConfig, err := boshuaa.NewConfigFromURL(url) + if err != nil { + return nil, err + } + + uaaConfig.CACert = cert + uaaConfig.Client = username + uaaConfig.ClientSecret = password + + return boshuaa.NewFactory(logger).New(uaaConfig) +} diff --git a/factory/build_client_test.go b/factory/build_client_test.go index 5b53567fe..65e666617 100644 --- a/factory/build_client_test.go +++ b/factory/build_client_test.go @@ -4,39 +4,119 @@ import ( "log" boshlog "github.com/cloudfoundry/bosh-utils/logger" + "github.com/pivotal-cf-experimental/cf-webmock/mockhttp" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" + "github.com/pivotal-cf-experimental/cf-webmock/mockbosh" + "github.com/pivotal-cf-experimental/cf-webmock/mockuaa" "github.com/pivotal-cf/bosh-backup-and-restore/factory" ) var _ = Describe("BuildClient", func() { - logger := boshlog.New(boshlog.LevelDebug, log.New(gbytes.NewBuffer(), "[bosh-package] ", log.Lshortfile), log.New(gbytes.NewBuffer(), "[bosh-package] ", log.Lshortfile)) + var logger = boshlog.New(boshlog.LevelDebug, log.New(gbytes.NewBuffer(), "[bosh-package] ", log.Lshortfile), log.New(gbytes.NewBuffer(), "[bosh-package] ", log.Lshortfile)) - It("builds a Client that authenticates with HTTP Basic Auth", func() { - username := MustHaveEnv("BOSH_CLIENT") - password := MustHaveEnv("BASIC_AUTH_BOSH_CLIENT_SECRET") - caCertPath := MustHaveEnv("BASIC_AUTH_BOSH_CERT_PATH") - basicAuthDirectorUrl := MustHaveEnv("BASIC_AUTH_BOSH_URL") + var director *mockhttp.Server + var deploymentName = "my-little-deployment" + var sslCertPath = "../fixtures/test.crt" - client, err := factory.BuildClient(basicAuthDirectorUrl, username, password, caCertPath, logger) - Expect(err).NotTo(HaveOccurred()) + BeforeEach(func() { + director = mockbosh.NewTLS() + }) + AfterEach(func() { + director.VerifyMocks() + }) + + Context("With Basic Auth", func() { + It("build the client which makes basic auth against director", func() { + username := "foo" + password := "bar" + + director.ExpectedBasicAuth(username, password) + director.VerifyAndMock( + mockbosh.Info().WithAuthTypeBasic(), + mockbosh.Manifest(deploymentName).RespondsWith([]byte("manifest contents")), + ) + + client, err := factory.BuildClient(director.URL, username, password, sslCertPath, logger) + + Expect(err).NotTo(HaveOccurred()) + manifest, err := client.GetManifest(deploymentName) + Expect(err).NotTo(HaveOccurred()) + Expect(manifest).To(Equal("manifest contents")) + }) + }) + + Context("With UAA", func() { + var uaaServer *mockuaa.ClientCredentialsServer + + It("build the client which makes basic auth against director", func() { + username := "foo" + password := "bar" + uaaToken := "baz" + + uaaServer = mockuaa.NewClientCredentialsServerTLS(username, password, uaaToken) + + director.ExpectedAuthorizationHeader("bearer " + uaaToken) + director.VerifyAndMock( + mockbosh.Info().WithAuthTypeUAA(uaaServer.URL), + mockbosh.Manifest(deploymentName).RespondsWith([]byte("manifest contents")), + ) + + client, err := factory.BuildClient(director.URL, username, password, sslCertPath, logger) - _, err = client.GetManifest("does-not-exist") - Expect(err.Error()).To(ContainSubstring("Director responded with non-successful status code '404'")) + Expect(err).NotTo(HaveOccurred()) + manifest, err := client.GetManifest(deploymentName) + Expect(err).NotTo(HaveOccurred()) + Expect(manifest).To(Equal("manifest contents")) + }) + + It("fails if uaa url is not valid", func() { + username := "no-relevant" + password := "no-relevant" + + director.VerifyAndMock( + mockbosh.Info().WithAuthTypeUAA(""), + ) + _, err := factory.BuildClient(director.URL, username, password, sslCertPath, logger) + + Expect(err).To(HaveOccurred()) + + }) + }) + + It("fails if CA-Cert cant be read", func() { + username := "no-relevant" + password := "no-relevant" + caCertPath := "/invalid/path" + basicAuthDirectorUrl := director.URL + + _, err := factory.BuildClient(basicAuthDirectorUrl, username, password, caCertPath, logger) + Expect(err).To(HaveOccurred()) + }) + + It("fails if invalid bosh url", func() { + username := "no-relevant" + password := "no-relevant" + caCertPath := "" + basicAuthDirectorUrl := "" + + _, err := factory.BuildClient(basicAuthDirectorUrl, username, password, caCertPath, logger) + Expect(err).To(HaveOccurred()) }) - It("builds a Client that authenticates with UAA", func() { - username := MustHaveEnv("BOSH_CLIENT") - password := MustHaveEnv("UAA_BOSH_CLIENT_SECRET") - caCertPath := MustHaveEnv("UAA_BOSH_CERT_PATH") - basicAuthDirectorUrl := MustHaveEnv("UAA_BOSH_URL") + It("fails if info cant be retrieved", func() { + username := "no-relevant" + password := "no-relevant" + + director.VerifyAndMock( + mockbosh.Info().Fails("fooo!"), + ) - client, err := factory.BuildClient(basicAuthDirectorUrl, username, password, caCertPath, logger) - Expect(err).NotTo(HaveOccurred()) + _, err := factory.BuildClient(director.URL, username, password, sslCertPath, logger) - _, err = client.GetManifest("does-not-exist") - Expect(err.Error()).To(ContainSubstring("Director responded with non-successful status code '404'")) + Expect(err).To(HaveOccurred()) }) + }) diff --git a/factory/factory_suite_test.go b/factory/factory_suite_test.go index 0f2cef6b5..68da78e0e 100644 --- a/factory/factory_suite_test.go +++ b/factory/factory_suite_test.go @@ -1,8 +1,6 @@ package factory_test import ( - "os" - . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -13,9 +11,3 @@ func TestFactory(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Factory Suite") } - -func MustHaveEnv(keyname string) string { - val := os.Getenv(keyname) - Expect(val).NotTo(BeEmpty(), "Need "+keyname+" for the test") - return val -} diff --git a/glide.lock b/glide.lock index 82453a17a..6381ddbac 100644 --- a/glide.lock +++ b/glide.lock @@ -70,7 +70,7 @@ imports: - matchers/support/goraph/util - types - name: github.com/pivotal-cf-experimental/cf-webmock - version: bd38d8f402724494fb8c42a4bfe94399948acdf9 + version: 8149b92dcd9c66202758602ad81637fda199fc7a subpackages: - mockbosh - mockhttp