Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[google] Add a Bytes credentials source #663

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions google/internal/externalaccount/basecredentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ type format struct {
// One field amongst File, URL, and Executable should be filled, depending on the kind of credential in question.
// The EnvironmentID should start with AWS if being used for an AWS credential.
type CredentialSource struct {
Bytes []byte `json:"bytes"`

File string `json:"file"`

URL string `json:"url"`
Expand Down Expand Up @@ -191,6 +193,8 @@ func (c *Config) parse(ctx context.Context) (baseCredentialSource, error) {

return awsCredSource, nil
}
} else if len(c.CredentialSource.Bytes) != 0 {
return bytesCredentialSource{Bytes: c.CredentialSource.Bytes, Format: c.CredentialSource.Format}, nil
} else if c.CredentialSource.File != "" {
return fileCredentialSource{File: c.CredentialSource.File, Format: c.CredentialSource.Format}, nil
} else if c.CredentialSource.URL != "" {
Expand Down
45 changes: 45 additions & 0 deletions google/internal/externalaccount/bytescredsource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE bytes.

package externalaccount

import (
"bytes"
"encoding/json"
"errors"
"fmt"
)

type bytesCredentialSource struct {
Bytes []byte
Format format
}

func (cs bytesCredentialSource) subjectToken() (string, error) {
tokenBytes := bytes.TrimSpace(cs.Bytes)
var err error
switch cs.Format.Type {
case "json":
jsonData := make(map[string]interface{})
err = json.Unmarshal(tokenBytes, &jsonData)
if err != nil {
return "", fmt.Errorf("oauth2/google: failed to unmarshal subject token bytes: %v", err)
}
val, ok := jsonData[cs.Format.SubjectTokenFieldName]
if !ok {
return "", errors.New("oauth2/google: provided subject_token_field_name not found in credentials")
}
token, ok := val.(string)
if !ok {
return "", errors.New("oauth2/google: improperly formatted subject token")
}
return token, nil
case "text":
return string(tokenBytes), nil
case "":
return string(tokenBytes), nil
default:
return "", errors.New("oauth2/google: invalid credential_source bytes format type")
}
}
80 changes: 80 additions & 0 deletions google/internal/externalaccount/bytescredsource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package externalaccount

import (
"context"
"os"
"testing"
)

var testBytesConfig = Config{
Audience: "32555940559.apps.googleusercontent.com",
SubjectTokenType: "urn:ietf:params:oauth:token-type:jwt",
TokenURL: "http://localhost:8080/v1/token",
TokenInfoURL: "http://localhost:8080/v1/tokeninfo",
ServiceAccountImpersonationURL: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/service-gcs-admin@$PROJECT_ID.iam.gserviceaccount.com:generateAccessToken",
ClientSecret: "notsosecret",
ClientID: "rbrgnognrhongo3bi4gb9ghg9g",
}

func TestRetrieveBytesSubjectToken(t *testing.T) {
var fileSourceTests = []struct {
name string
cs CredentialSource
want string
}{
{
name: "UntypedFileSource",
cs: CredentialSource{
File: textBaseCredPath,
},
want: "street123",
},
{
name: "TextFileSource",
cs: CredentialSource{
File: textBaseCredPath,
Format: format{Type: fileTypeText},
},
want: "street123",
},
{
name: "JSONFileSource",
cs: CredentialSource{
File: jsonBaseCredPath,
Format: format{Type: fileTypeJSON, SubjectTokenFieldName: "SubjToken"},
},
want: "321road",
},
}

for _, test := range fileSourceTests {
test := test
tbc := testBytesConfig
tbc.CredentialSource = test.cs

bytes, err := os.ReadFile(test.cs.File)
if err != nil {
t.Fatalf("failed to read subject token: %v", err)
}
tbc.CredentialSource.Bytes = bytes

t.Run(test.name, func(t *testing.T) {
base, err := tbc.parse(context.Background())
if err != nil {
t.Fatalf("parse() failed %v", err)
}

out, err := base.subjectToken()
if err != nil {
t.Errorf("Method subjectToken() errored.")
} else if test.want != out {
t.Errorf("got %v but want %v", out, test.want)
}

})
}
}