From 415b886f5b970ae3d80d78e918270e97cb76ce21 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Wed, 24 Oct 2018 15:08:08 +0200 Subject: [PATCH 1/4] post-processor/vagrant-cloud: validate vagrant cloud auth token doing an auth request --- post-processor/vagrant-cloud/client.go | 27 ++++++++++++++----- .../vagrant-cloud/post-processor.go | 10 ++++--- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/post-processor/vagrant-cloud/client.go b/post-processor/vagrant-cloud/client.go index a66d3eb4a..0a3a8dae3 100644 --- a/post-processor/vagrant-cloud/client.go +++ b/post-processor/vagrant-cloud/client.go @@ -36,7 +36,7 @@ func (v VagrantCloudErrors) FormatErrors() string { return strings.Join(errs, ". ") } -func (v VagrantCloudClient) New(baseUrl string, token string) *VagrantCloudClient { +func (v VagrantCloudClient) New(baseUrl string, token string) (*VagrantCloudClient, error) { c := &VagrantCloudClient{ client: &http.Client{ Transport: &http.Transport{ @@ -46,7 +46,8 @@ func (v VagrantCloudClient) New(baseUrl string, token string) *VagrantCloudClien BaseURL: baseUrl, AccessToken: token, } - return c + + return c, c.ValidateAuthentication() } func decodeBody(resp *http.Response, out interface{}) error { @@ -65,7 +66,19 @@ func encodeBody(obj interface{}) (io.Reader, error) { return buf, nil } -func (v VagrantCloudClient) Get(path string) (*http.Response, error) { +func (v *VagrantCloudClient) ValidateAuthentication() error { + resp, err := v.Get("authenticate") + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return fmt.Errorf("Invalid credentials: %s", resp.Status) + } + return nil +} + +func (v *VagrantCloudClient) Get(path string) (*http.Response, error) { params := url.Values{} params.Set("access_token", v.AccessToken) reqUrl := fmt.Sprintf("%s/%s?%s", v.BaseURL, path, params.Encode()) @@ -83,7 +96,7 @@ func (v VagrantCloudClient) Get(path string) (*http.Response, error) { return resp, err } -func (v VagrantCloudClient) Delete(path string) (*http.Response, error) { +func (v *VagrantCloudClient) Delete(path string) (*http.Response, error) { params := url.Values{} params.Set("access_token", v.AccessToken) reqUrl := fmt.Sprintf("%s/%s?%s", v.BaseURL, path, params.Encode()) @@ -101,7 +114,7 @@ func (v VagrantCloudClient) Delete(path string) (*http.Response, error) { return resp, err } -func (v VagrantCloudClient) Upload(path string, url string) (*http.Response, error) { +func (v *VagrantCloudClient) Upload(path string, url string) (*http.Response, error) { file, err := os.Open(path) if err != nil { @@ -132,7 +145,7 @@ func (v VagrantCloudClient) Upload(path string, url string) (*http.Response, err return resp, err } -func (v VagrantCloudClient) Post(path string, body interface{}) (*http.Response, error) { +func (v *VagrantCloudClient) Post(path string, body interface{}) (*http.Response, error) { params := url.Values{} params.Set("access_token", v.AccessToken) reqUrl := fmt.Sprintf("%s/%s?%s", v.BaseURL, path, params.Encode()) @@ -157,7 +170,7 @@ func (v VagrantCloudClient) Post(path string, body interface{}) (*http.Response, return resp, err } -func (v VagrantCloudClient) Put(path string) (*http.Response, error) { +func (v *VagrantCloudClient) Put(path string) (*http.Response, error) { params := url.Values{} params.Set("access_token", v.AccessToken) reqUrl := fmt.Sprintf("%s/%s?%s", v.BaseURL, path, params.Encode()) diff --git a/post-processor/vagrant-cloud/post-processor.go b/post-processor/vagrant-cloud/post-processor.go index 273d2fdb8..cb651017f 100644 --- a/post-processor/vagrant-cloud/post-processor.go +++ b/post-processor/vagrant-cloud/post-processor.go @@ -94,6 +94,13 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { } } + // create the HTTP client + p.client, err = VagrantCloudClient{}.New(p.config.VagrantCloudUrl, p.config.AccessToken) + if err != nil { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("Failed to verify authentication token: %v", err)) + } + if len(errs.Errors) > 0 { return errs } @@ -118,9 +125,6 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac ui.Message("Warning: Using Vagrant Cloud token found in ATLAS_TOKEN. Please make sure it is correct, or set VAGRANT_CLOUD_TOKEN") } - // create the HTTP client - p.client = VagrantCloudClient{}.New(p.config.VagrantCloudUrl, p.config.AccessToken) - // The name of the provider for vagrant cloud, and vagrant providerName := providerFromBuilderName(artifact.Id()) From ff4b6d4442d1721851b9ab61f36c4ecd73bd81a1 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Wed, 24 Oct 2018 15:39:09 +0200 Subject: [PATCH 2/4] pass vagrant cloud auth token as http header * stoped using url to pass the auth token and put it in the headers * added newRequest method to VagrantCloudClient that sets json and auth headesr * made VagrantCloudClient method pointers to avoid copies --- post-processor/vagrant-cloud/client.go | 53 ++++++++----------- .../vagrant-cloud/post-processor_test.go | 34 +++++++++++- 2 files changed, 55 insertions(+), 32 deletions(-) diff --git a/post-processor/vagrant-cloud/client.go b/post-processor/vagrant-cloud/client.go index 0a3a8dae3..f3cc0c66d 100644 --- a/post-processor/vagrant-cloud/client.go +++ b/post-processor/vagrant-cloud/client.go @@ -7,7 +7,6 @@ import ( "io" "log" "net/http" - "net/url" "os" "strings" ) @@ -79,16 +78,11 @@ func (v *VagrantCloudClient) ValidateAuthentication() error { } func (v *VagrantCloudClient) Get(path string) (*http.Response, error) { - params := url.Values{} - params.Set("access_token", v.AccessToken) - reqUrl := fmt.Sprintf("%s/%s?%s", v.BaseURL, path, params.Encode()) + reqUrl := fmt.Sprintf("%s/%s", v.BaseURL, path) - // Scrub API key for logs - scrubbedUrl := strings.Replace(reqUrl, v.AccessToken, "ACCESS_TOKEN", -1) - log.Printf("Post-Processor Vagrant Cloud API GET: %s", scrubbedUrl) + log.Printf("Post-Processor Vagrant Cloud API GET: %s", reqUrl) - req, err := http.NewRequest("GET", reqUrl, nil) - req.Header.Add("Content-Type", "application/json") + req, _ := v.newRequest("GET", reqUrl, nil) resp, err := v.client.Do(req) log.Printf("Post-Processor Vagrant Cloud API Response: \n\n%+v", resp) @@ -97,16 +91,15 @@ func (v *VagrantCloudClient) Get(path string) (*http.Response, error) { } func (v *VagrantCloudClient) Delete(path string) (*http.Response, error) { - params := url.Values{} - params.Set("access_token", v.AccessToken) - reqUrl := fmt.Sprintf("%s/%s?%s", v.BaseURL, path, params.Encode()) + reqUrl := fmt.Sprintf("%s/%s", v.BaseURL, path) // Scrub API key for logs scrubbedUrl := strings.Replace(reqUrl, v.AccessToken, "ACCESS_TOKEN", -1) log.Printf("Post-Processor Vagrant Cloud API DELETE: %s", scrubbedUrl) - req, err := http.NewRequest("DELETE", reqUrl, nil) + req, _ := http.NewRequest("DELETE", reqUrl, nil) req.Header.Add("Content-Type", "application/json") + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", v.AccessToken)) resp, err := v.client.Do(req) log.Printf("Post-Processor Vagrant Cloud API Response: \n\n%+v", resp) @@ -129,7 +122,7 @@ func (v *VagrantCloudClient) Upload(path string, url string) (*http.Response, er defer file.Close() - request, err := http.NewRequest("PUT", url, file) + request, err := v.newRequest("PUT", url, file) if err != nil { return nil, fmt.Errorf("Error preparing upload request: %s", err) @@ -146,9 +139,7 @@ func (v *VagrantCloudClient) Upload(path string, url string) (*http.Response, er } func (v *VagrantCloudClient) Post(path string, body interface{}) (*http.Response, error) { - params := url.Values{} - params.Set("access_token", v.AccessToken) - reqUrl := fmt.Sprintf("%s/%s?%s", v.BaseURL, path, params.Encode()) + reqUrl := fmt.Sprintf("%s/%s", v.BaseURL, path) encBody, err := encodeBody(body) @@ -156,12 +147,9 @@ func (v *VagrantCloudClient) Post(path string, body interface{}) (*http.Response return nil, fmt.Errorf("Error encoding body for request: %s", err) } - // Scrub API key for logs - scrubbedUrl := strings.Replace(reqUrl, v.AccessToken, "ACCESS_TOKEN", -1) - log.Printf("Post-Processor Vagrant Cloud API POST: %s. \n\n Body: %s", scrubbedUrl, encBody) + log.Printf("Post-Processor Vagrant Cloud API POST: %s. \n\n Body: %s", reqUrl, encBody) - req, err := http.NewRequest("POST", reqUrl, encBody) - req.Header.Add("Content-Type", "application/json") + req, _ := v.newRequest("POST", reqUrl, encBody) resp, err := v.client.Do(req) @@ -171,16 +159,11 @@ func (v *VagrantCloudClient) Post(path string, body interface{}) (*http.Response } func (v *VagrantCloudClient) Put(path string) (*http.Response, error) { - params := url.Values{} - params.Set("access_token", v.AccessToken) - reqUrl := fmt.Sprintf("%s/%s?%s", v.BaseURL, path, params.Encode()) + reqUrl := fmt.Sprintf("%s/%s", v.BaseURL, path) - // Scrub API key for logs - scrubbedUrl := strings.Replace(reqUrl, v.AccessToken, "ACCESS_TOKEN", -1) - log.Printf("Post-Processor Vagrant Cloud API PUT: %s", scrubbedUrl) + log.Printf("Post-Processor Vagrant Cloud API PUT: %s", reqUrl) - req, err := http.NewRequest("PUT", reqUrl, nil) - req.Header.Add("Content-Type", "application/json") + req, _ := v.newRequest("PUT", reqUrl, nil) resp, err := v.client.Do(req) @@ -188,3 +171,13 @@ func (v *VagrantCloudClient) Put(path string) (*http.Response, error) { return resp, err } + +func (v *VagrantCloudClient) newRequest(method, url string, body io.Reader) (*http.Request, error) { + req, err := http.NewRequest(method, url, body) + if err != nil { + return nil, err + } + req.Header.Add("Content-Type", "application/json") + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", v.AccessToken)) + return req, err +} diff --git a/post-processor/vagrant-cloud/post-processor_test.go b/post-processor/vagrant-cloud/post-processor_test.go index 29d786fa3..c21a2fd2a 100644 --- a/post-processor/vagrant-cloud/post-processor_test.go +++ b/post-processor/vagrant-cloud/post-processor_test.go @@ -2,6 +2,9 @@ package vagrantcloud import ( "bytes" + "fmt" + "net/http" + "net/http/httptest" "os" "testing" @@ -25,9 +28,25 @@ func testBadConfig() map[string]interface{} { } } +func newSecureServer(token string, handler http.HandlerFunc) *httptest.Server { + token = fmt.Sprintf("Bearer %s", token) + return httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + if req.Header.Get("authorization") != token { + http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + return + } + if handler != nil { + handler(rw, req) + } + })) +} + func TestPostProcessor_Configure_fromVagrantEnv(t *testing.T) { var p PostProcessor config := testGoodConfig() + server := newSecureServer("bar", nil) + defer server.Close() + config["vagrant_cloud_url"] = server.URL config["access_token"] = "" os.Setenv("VAGRANT_CLOUD_TOKEN", "bar") defer func() { @@ -48,6 +67,9 @@ func TestPostProcessor_Configure_fromAtlasEnv(t *testing.T) { var p PostProcessor config := testGoodConfig() config["access_token"] = "" + server := newSecureServer("foo", nil) + defer server.Close() + config["vagrant_cloud_url"] = server.URL os.Setenv("ATLAS_TOKEN", "foo") defer func() { os.Setenv("ATLAS_TOKEN", "") @@ -68,15 +90,23 @@ func TestPostProcessor_Configure_fromAtlasEnv(t *testing.T) { } func TestPostProcessor_Configure_Good(t *testing.T) { + config := testGoodConfig() + server := newSecureServer("foo", nil) + defer server.Close() + config["vagrant_cloud_url"] = server.URL var p PostProcessor - if err := p.Configure(testGoodConfig()); err != nil { + if err := p.Configure(config); err != nil { t.Fatalf("err: %s", err) } } func TestPostProcessor_Configure_Bad(t *testing.T) { + config := testBadConfig() + server := newSecureServer("foo", nil) + defer server.Close() + config["vagrant_cloud_url"] = server.URL var p PostProcessor - if err := p.Configure(testBadConfig()); err == nil { + if err := p.Configure(config); err == nil { t.Fatalf("should have err") } } From aa2ebec8fd26753f848c309d7f27a26c926ca681 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 25 Oct 2018 10:25:37 +0200 Subject: [PATCH 3/4] remove duplicate error message from --- post-processor/vagrant-cloud/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/post-processor/vagrant-cloud/client.go b/post-processor/vagrant-cloud/client.go index f3cc0c66d..4f8ac62bb 100644 --- a/post-processor/vagrant-cloud/client.go +++ b/post-processor/vagrant-cloud/client.go @@ -72,7 +72,7 @@ func (v *VagrantCloudClient) ValidateAuthentication() error { } defer resp.Body.Close() if resp.StatusCode != 200 { - return fmt.Errorf("Invalid credentials: %s", resp.Status) + return fmt.Errorf(resp.Status) } return nil } From 7b10079507c49a2b3f4ef7a6a7399d86dbd2cfa5 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 25 Oct 2018 10:28:12 +0200 Subject: [PATCH 4/4] fail if the request could not be created --- post-processor/vagrant-cloud/client.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/post-processor/vagrant-cloud/client.go b/post-processor/vagrant-cloud/client.go index 4f8ac62bb..318427dbf 100644 --- a/post-processor/vagrant-cloud/client.go +++ b/post-processor/vagrant-cloud/client.go @@ -82,7 +82,10 @@ func (v *VagrantCloudClient) Get(path string) (*http.Response, error) { log.Printf("Post-Processor Vagrant Cloud API GET: %s", reqUrl) - req, _ := v.newRequest("GET", reqUrl, nil) + req, err := v.newRequest("GET", reqUrl, nil) + if err != nil { + return nil, err + } resp, err := v.client.Do(req) log.Printf("Post-Processor Vagrant Cloud API Response: \n\n%+v", resp) @@ -97,7 +100,10 @@ func (v *VagrantCloudClient) Delete(path string) (*http.Response, error) { scrubbedUrl := strings.Replace(reqUrl, v.AccessToken, "ACCESS_TOKEN", -1) log.Printf("Post-Processor Vagrant Cloud API DELETE: %s", scrubbedUrl) - req, _ := http.NewRequest("DELETE", reqUrl, nil) + req, err := http.NewRequest("DELETE", reqUrl, nil) + if err != nil { + return nil, err + } req.Header.Add("Content-Type", "application/json") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", v.AccessToken)) resp, err := v.client.Do(req) @@ -149,7 +155,10 @@ func (v *VagrantCloudClient) Post(path string, body interface{}) (*http.Response log.Printf("Post-Processor Vagrant Cloud API POST: %s. \n\n Body: %s", reqUrl, encBody) - req, _ := v.newRequest("POST", reqUrl, encBody) + req, err := v.newRequest("POST", reqUrl, encBody) + if err != nil { + return nil, err + } resp, err := v.client.Do(req) @@ -163,7 +172,10 @@ func (v *VagrantCloudClient) Put(path string) (*http.Response, error) { log.Printf("Post-Processor Vagrant Cloud API PUT: %s", reqUrl) - req, _ := v.newRequest("PUT", reqUrl, nil) + req, err := v.newRequest("PUT", reqUrl, nil) + if err != nil { + return nil, err + } resp, err := v.client.Do(req)