diff --git a/builtin/providers/google/data_source_storage_object_signed_url.go b/builtin/providers/google/data_source_storage_object_signed_url.go index fa323359b..828e9ec07 100644 --- a/builtin/providers/google/data_source_storage_object_signed_url.go +++ b/builtin/providers/google/data_source_storage_object_signed_url.go @@ -17,14 +17,13 @@ import ( "log" "net/url" "os" - "os/user" "strconv" "strings" "time" ) const gcsBaseUrl = "https://storage.googleapis.com" -const envVar = "GOOGLE_APPLICATION_CREDENTIALS" +const googleCredentialsEnvVar = "GOOGLE_APPLICATION_CREDENTIALS" func dataSourceGoogleSignedUrl() *schema.Resource { return &schema.Resource{ @@ -132,14 +131,14 @@ func dataSourceGoogleSignedUrlRead(d *schema.ResourceData, meta interface{}) err // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Construct URL finalUrl := urlData.BuildUrl() - d.SetId(finalUrl) + d.SetId(urlData.EncodedSignature()) d.Set("signed_url", finalUrl) return nil } // This looks for credentials json in the following places, -// preferring the first location found: +// in order of preference: // // 1. Credentials provided in data source `credentials` attribute. // 2. Credentials provided in the provider definition. @@ -150,15 +149,15 @@ func loadJwtConfig(d *schema.ResourceData, meta interface{}) (*jwt.Config, error credentials := "" if v, ok := d.GetOk("credentials"); ok { - log.Println("[DEBUG] using data source credentials") + log.Println("[DEBUG] using data source credentials to sign URL") credentials = v.(string) } else if config.Credentials != "" { - log.Println("[DEBUG] using provider credentials") + log.Println("[DEBUG] using provider credentials to sign URL") credentials = config.Credentials - } else if filename := os.Getenv(envVar); filename != "" { - log.Println("[DEBUG] using env GOOGLE_APPLICATION_CREDENTIALS credentials") + } else if filename := os.Getenv(googleCredentialsEnvVar); filename != "" { + log.Println("[DEBUG] using env GOOGLE_APPLICATION_CREDENTIALS credentials to sign URL") credentials = filename } @@ -179,14 +178,6 @@ func loadJwtConfig(d *schema.ResourceData, meta interface{}) (*jwt.Config, error return nil, fmt.Errorf("Credentials not found in datasource, provider configuration or GOOGLE_APPLICATION_CREDENTIALS environment variable.") } -func guessUnixHomeDir() string { - usr, err := user.Current() - if err == nil { - return usr.HomeDir - } - return os.Getenv("HOME") -} - // parsePrivateKey converts the binary contents of a private key file // to an *rsa.PrivateKey. It detects whether the private key is in a // PEM container or not. If so, it extracts the the private key @@ -258,13 +249,18 @@ func (u *UrlData) CreateSigningString() []byte { return buf.Bytes() } -// Builds the final signed URL a client can use to retrieve storage object -func (u *UrlData) BuildUrl() string { +func (u *UrlData) EncodedSignature() string { // base64 encode signature encoded := base64.StdEncoding.EncodeToString(u.Signature) // encoded signature may include /, = characters that need escaping encoded = url.QueryEscape(encoded) + return encoded +} + +// Builds the final signed URL a client can use to retrieve storage object +func (u *UrlData) BuildUrl() string { + // set url // https://cloud.google.com/storage/docs/access-control/create-signed-urls-program var urlBuffer bytes.Buffer @@ -275,7 +271,7 @@ func (u *UrlData) BuildUrl() string { urlBuffer.WriteString("&Expires=") urlBuffer.WriteString(strconv.Itoa(u.Expires)) urlBuffer.WriteString("&Signature=") - urlBuffer.WriteString(encoded) + urlBuffer.WriteString(u.EncodedSignature()) return urlBuffer.String() } diff --git a/builtin/providers/google/data_source_storage_object_signed_url_test.go b/builtin/providers/google/data_source_storage_object_signed_url_test.go index 576633de7..d97a67e30 100644 --- a/builtin/providers/google/data_source_storage_object_signed_url_test.go +++ b/builtin/providers/google/data_source_storage_object_signed_url_test.go @@ -6,12 +6,12 @@ import ( "bytes" "encoding/base64" "fmt" + "github.com/hashicorp/go-cleanhttp" "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" "golang.org/x/oauth2/google" "io/ioutil" - "net/http" "net/url" ) @@ -31,8 +31,8 @@ const fakeCredentials = `{ // The following values are derived from the output of the `gsutil signurl` command. // i.e. // gsutil signurl fake_creds.json gs://tf-test-bucket-6159205297736845881/path/to/file -// URL HTTP Method Expiration Signed URL -// gs://tf-test-bucket-6159205297736845881/path/to/file GET 2016-08-12 14:03:30 https://storage.googleapis.com/tf-test-bucket-6159205297736845881/path/to/file?GoogleAccessId=user@gcp-project.iam.gserviceaccount.com&Expires=1470967410&Signature=JJvE2Jc%2BeoagyS1qRACKBGUkgLkKjw7cGymHhtB4IzzN3nbXDqr0acRWGy0%2BEpZ3HYNDalEYsK0lR9Q0WCgty5I0JKmPIuo9hOYa1xTNH%2B22xiWsekxGV%2FcA9FXgWpi%2BFt7fBmMk4dhDe%2BuuYc7N79hd0FYuSBNW1Wp32Bluoe4SNkNAB%2BuIDd9KqPzqs09UAbBoz2y4WxXOQnRyR8GAfb8B%2FDtv62gYjtmp%2F6%2Fyr6xj7byWKZdQt8kEftQLTQmP%2F17Efjp6p%2BXo71Q0F9IhAFiqWfp3Ij8hHDSebLcVb2ULXyHNNQpHBOhFgALrFW3I6Uc3WciLEOsBS9Ej3EGdTg%3D%3D +// URL HTTP Method Expiration Signed URL +// gs://tf-test-bucket-6159205297736845881/path/to/file GET 2016-08-12 14:03:30 https://storage.googleapis.com/tf-test-bucket-6159205297736845881/path/to/file?GoogleAccessId=user@gcp-project.iam.gserviceaccount.com&Expires=1470967410&Signature=JJvE2Jc%2BeoagyS1qRACKBGUkgLkKjw7cGymHhtB4IzzN3nbXDqr0acRWGy0%2BEpZ3HYNDalEYsK0lR9Q0WCgty5I0JKmPIuo9hOYa1xTNH%2B22xiWsekxGV%2FcA9FXgWpi%2BFt7fBmMk4dhDe%2BuuYc7N79hd0FYuSBNW1Wp32Bluoe4SNkNAB%2BuIDd9KqPzqs09UAbBoz2y4WxXOQnRyR8GAfb8B%2FDtv62gYjtmp%2F6%2Fyr6xj7byWKZdQt8kEftQLTQmP%2F17Efjp6p%2BXo71Q0F9IhAFiqWfp3Ij8hHDSebLcVb2ULXyHNNQpHBOhFgALrFW3I6Uc3WciLEOsBS9Ej3EGdTg%3D%3D const testUrlPath = "/tf-test-bucket-6159205297736845881/path/to/file" const testUrlExpires = 1470967410 @@ -75,7 +75,7 @@ func TestUrlData_Signing(t *testing.T) { } -func TestUrlData_CreateUrl(t *testing.T) { +func TestUrlData_BuildUrl(t *testing.T) { // unescape and decode the expected signature encodedSig, err := url.QueryUnescape(testUrlExpectedSignatureBase64Encoded) if err != nil { @@ -107,7 +107,7 @@ func TestUrlData_CreateUrl(t *testing.T) { func TestDatasourceSignedUrl_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - //PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ resource.TestStep{ @@ -124,7 +124,7 @@ func TestDatasourceSignedUrl_accTest(t *testing.T) { bucketName := fmt.Sprintf("tf-test-bucket-%d", acctest.RandInt()) resource.Test(t, resource.TestCase{ - //PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ resource.TestStep{ @@ -163,12 +163,11 @@ func testAccGoogleSignedUrlRetrieval(n string) resource.TestCheckFunc { url := a["signed_url"] // send request to GET object using signed url - client := http.DefaultClient + client := cleanhttp.DefaultClient() response, err := client.Get(url) if err != nil { return err } - defer response.Body.Close() body, err := ioutil.ReadAll(response.Body) if err != nil {