forked from remote/oauth2
google/internal/externalaccount: create executable credenitals
This commit is contained in:
@@ -171,6 +171,8 @@ type CredentialSource struct {
|
||||
URL string `json:"url"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
|
||||
Executable ExecutableConfig `json:"executable"`
|
||||
|
||||
EnvironmentID string `json:"environment_id"`
|
||||
RegionURL string `json:"region_url"`
|
||||
RegionalCredVerificationURL string `json:"regional_cred_verification_url"`
|
||||
@@ -179,6 +181,12 @@ type CredentialSource struct {
|
||||
Format format `json:"format"`
|
||||
}
|
||||
|
||||
type ExecutableConfig struct {
|
||||
Command string `json:"command"`
|
||||
TimeoutMillis int `json:"timeout_millis"`
|
||||
OutputFile string `json:"output_file"`
|
||||
}
|
||||
|
||||
// parse determines the type of CredentialSource needed
|
||||
func (c *Config) parse(ctx context.Context) (baseCredentialSource, error) {
|
||||
if len(c.CredentialSource.EnvironmentID) > 3 && c.CredentialSource.EnvironmentID[:3] == "aws" {
|
||||
@@ -205,6 +213,8 @@ func (c *Config) parse(ctx context.Context) (baseCredentialSource, error) {
|
||||
return fileCredentialSource{File: c.CredentialSource.File, Format: c.CredentialSource.Format}, nil
|
||||
} else if c.CredentialSource.URL != "" {
|
||||
return urlCredentialSource{URL: c.CredentialSource.URL, Headers: c.CredentialSource.Headers, Format: c.CredentialSource.Format, ctx: ctx}, nil
|
||||
} else if c.CredentialSource.Executable.Command != "" {
|
||||
return CreateExecutableCredential(c.CredentialSource.Executable, c, ctx), nil
|
||||
}
|
||||
return nil, fmt.Errorf("oauth2/google: unable to parse credential source")
|
||||
}
|
||||
|
||||
217
google/internal/externalaccount/executablecredsource.go
Normal file
217
google/internal/externalaccount/executablecredsource.go
Normal file
@@ -0,0 +1,217 @@
|
||||
// Copyright 2022 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"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
EXECUTABLE_SUPPORTED_MAX_VERSION = 1
|
||||
)
|
||||
|
||||
var baseEnv = os.Environ
|
||||
|
||||
// runCommand is basically an alias of exec.CommandContext for testing.
|
||||
var runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
cmd := exec.CommandContext(ctx, command)
|
||||
cmd.Env = env
|
||||
|
||||
response, err := cmd.Output()
|
||||
if ctx.Err() != nil {
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
return response, err
|
||||
}
|
||||
|
||||
type executableCredentialSource struct {
|
||||
Command string
|
||||
Timeout time.Duration
|
||||
OutputFile string
|
||||
ctx context.Context
|
||||
config *Config
|
||||
}
|
||||
|
||||
// CreateExecutableCredential creates an executableCredentialSource given an ExecutableConfig.
|
||||
// It also performs defaulting and type conversions.
|
||||
func CreateExecutableCredential(ec ExecutableConfig, config *Config, ctx context.Context) (result executableCredentialSource) {
|
||||
result.Command = ec.Command
|
||||
if ec.TimeoutMillis == 0 {
|
||||
result.Timeout = 30 * time.Second
|
||||
} else {
|
||||
result.Timeout = time.Duration(ec.TimeoutMillis) * time.Millisecond
|
||||
}
|
||||
result.OutputFile = ec.OutputFile
|
||||
result.ctx = ctx
|
||||
result.config = config
|
||||
return
|
||||
}
|
||||
|
||||
type subjectTokenResponse struct {
|
||||
Version *int `json:"version"`
|
||||
Success *bool `json:"success"`
|
||||
TokenType *string `json:"token_type"`
|
||||
ExpirationTime *int64 `json:"expiration_time"`
|
||||
IdToken *string `json:"id_token"`
|
||||
SamlResponse *string `json:"saml_response"`
|
||||
Code *string `json:"code"`
|
||||
Message *string `json:"message"`
|
||||
}
|
||||
|
||||
func parseSubjectToken(response []byte) (string, error) {
|
||||
var result subjectTokenResponse
|
||||
if err := json.Unmarshal(response, &result); err != nil {
|
||||
return "", errors.New("oauth2/google: Unable to parse response JSON.")
|
||||
}
|
||||
|
||||
if result.Version == nil {
|
||||
return "", errors.New("oauth2/google: Response missing version field.")
|
||||
}
|
||||
|
||||
if result.Success == nil {
|
||||
return "", errors.New("oauth2/google: Response missing success field.")
|
||||
}
|
||||
|
||||
if !*result.Success {
|
||||
details := ""
|
||||
if result.Code != nil {
|
||||
details += fmt.Sprintf("(%v)", *result.Code)
|
||||
}
|
||||
if result.Message != nil {
|
||||
if details != "" {
|
||||
details += " "
|
||||
}
|
||||
details += *result.Message
|
||||
}
|
||||
if details == "" {
|
||||
details = "Unknown Error"
|
||||
}
|
||||
return "", fmt.Errorf("oauth2/google: Executable returned unsuccessful response: %v.", details)
|
||||
}
|
||||
|
||||
if *result.Version > EXECUTABLE_SUPPORTED_MAX_VERSION {
|
||||
return "", fmt.Errorf("oauth2/google: Executable returned unsupported version: %v.", *result.Version)
|
||||
}
|
||||
|
||||
if result.ExpirationTime == nil {
|
||||
return "", errors.New("oauth2/google: Response missing expiration_time field.")
|
||||
}
|
||||
|
||||
if result.TokenType == nil {
|
||||
return "", errors.New("oauth2/google: Response missing token_type field.")
|
||||
}
|
||||
|
||||
if *result.ExpirationTime < now().Unix() {
|
||||
return "", errors.New("oauth2/google: The token returned by the executable is expired.")
|
||||
}
|
||||
|
||||
if *result.TokenType == "urn:ietf:params:oauth:token-type:jwt" || *result.TokenType == "urn:ietf:params:oauth:token-type:id_token" {
|
||||
if result.IdToken == nil {
|
||||
return "", errors.New("oauth2/google: Response missing id_token field.")
|
||||
}
|
||||
return *result.IdToken, nil
|
||||
}
|
||||
|
||||
if *result.TokenType == "urn:ietf:params:oauth:token-type:saml2" {
|
||||
if result.SamlResponse == nil {
|
||||
return "", errors.New("oauth2/google: Response missing saml_response field.")
|
||||
}
|
||||
return *result.SamlResponse, nil
|
||||
}
|
||||
|
||||
return "", errors.New("Executable returned unsupported token type.")
|
||||
}
|
||||
|
||||
func (cs executableCredentialSource) subjectToken() (string, error) {
|
||||
if token, ok := cs.getTokenFromInMemoryCaching(); ok {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
if token, ok := cs.getTokenFromOutputFile(); ok {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
return cs.getTokenFromExecutableCommand()
|
||||
}
|
||||
|
||||
func (cs executableCredentialSource) getTokenFromInMemoryCaching() (string, bool) {
|
||||
// TODO
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (cs executableCredentialSource) getTokenFromOutputFile() (string, bool) {
|
||||
// TODO
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (cs executableCredentialSource) getEnvironment() []string {
|
||||
result := baseEnv()
|
||||
for k, v := range cs.getNewEnvironmentVariables() {
|
||||
result = append(result, fmt.Sprintf("%v=%v", k, v))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
var serviceAccountImpersonationCompiler = regexp.MustCompile("https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/(.*@.*):generateAccessToken")
|
||||
|
||||
func (cs executableCredentialSource) getNewEnvironmentVariables() map[string]string {
|
||||
result := map[string]string{
|
||||
"GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE": cs.config.Audience,
|
||||
"GOOGLE_EXTERNAL_ACCOUNT_TOKEN_TYPE": cs.config.SubjectTokenType,
|
||||
}
|
||||
|
||||
if cs.config.ServiceAccountImpersonationURL != "" {
|
||||
matches := serviceAccountImpersonationCompiler.FindStringSubmatch(cs.config.ServiceAccountImpersonationURL)
|
||||
if matches != nil {
|
||||
result["GOOGLE_EXTERNAL_ACCOUNT_IMPERSONATED_EMAIL"] = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
if cs.isInteractive() {
|
||||
result["GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE"] = "1"
|
||||
} else {
|
||||
result["GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE"] = "0"
|
||||
}
|
||||
|
||||
if cs.OutputFile != "" {
|
||||
result["GOOGLE_EXTERNAL_ACCOUNT_OUTPUT_FILE"] = cs.OutputFile
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (cs executableCredentialSource) isInteractive() bool {
|
||||
// Currently, executableCredentialSource does not yet support interactive mode.
|
||||
return false
|
||||
}
|
||||
|
||||
func (cs executableCredentialSource) getTokenFromExecutableCommand() (string, error) {
|
||||
// For security reasons, we need our consumers to set this environment variable to allow executables to be run.
|
||||
if getenv("GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES") != "1" {
|
||||
return "", errors.New("Executables need to be explicitly allowed (set GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES to '1') to run.")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithDeadline(cs.ctx, now().Add(cs.Timeout))
|
||||
defer cancel()
|
||||
|
||||
if output, err := runCommand(ctx, cs.Command, cs.getEnvironment()); err != nil {
|
||||
if err == context.DeadlineExceeded {
|
||||
return "", fmt.Errorf("oauth2/google: executable command timed out.")
|
||||
}
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
return "", fmt.Errorf("oauth2/google: executable command failed with exit code %v.", exitError.ExitCode())
|
||||
}
|
||||
return "", fmt.Errorf("oauth2/google: executable command failed: %v.", err.Error())
|
||||
} else {
|
||||
return parseSubjectToken(output)
|
||||
}
|
||||
}
|
||||
926
google/internal/externalaccount/executablecredsource_test.go
Normal file
926
google/internal/externalaccount/executablecredsource_test.go
Normal file
@@ -0,0 +1,926 @@
|
||||
// Copyright 2022 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"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Bool(b bool) *bool {
|
||||
return &b
|
||||
}
|
||||
|
||||
func Int(i int) *int {
|
||||
return &i
|
||||
}
|
||||
|
||||
func Int64(i int64) *int64 {
|
||||
return &i
|
||||
}
|
||||
|
||||
func String(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
var emptyEnv = func() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func TestCreateExecutableCredential(t *testing.T) {
|
||||
ec := ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 50000,
|
||||
}
|
||||
|
||||
ecs := CreateExecutableCredential(ec, nil, context.Background())
|
||||
if ecs.Command != "blarg" {
|
||||
t.Errorf("ecs.Command got %v but want %v", ecs.Command, "blarg")
|
||||
}
|
||||
if ecs.Timeout != 50000*time.Millisecond {
|
||||
t.Errorf("ecs.Timeout got %v but want %v", ecs.Timeout, 50000*time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateExecutableCredential_WithoutTimeout(t *testing.T) {
|
||||
ec := ExecutableConfig{
|
||||
Command: "blarg",
|
||||
}
|
||||
|
||||
ecs := CreateExecutableCredential(ec, nil, context.Background())
|
||||
if ecs.Command != "blarg" {
|
||||
t.Errorf("ecs.Command got %v but want %v", ecs.Command, "blarg")
|
||||
}
|
||||
if ecs.Timeout != 30000*time.Millisecond {
|
||||
t.Errorf("ecs.Timeout got %v but want %v", ecs.Timeout, 30000*time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func areSlicesEquivalent(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
OUTER:
|
||||
for i, aa := range a {
|
||||
for _, bb := range b {
|
||||
if aa == bb {
|
||||
continue OUTER
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestMinimalExectuableCredentialGetEnvironment(t *testing.T) {
|
||||
config := Config{
|
||||
Audience: "//iam.googleapis.com/projects/123/locations/global/workloadIdentityPools/pool/providers/oidc",
|
||||
SubjectTokenType: "urn:ietf:params:oauth:token-type:jwt",
|
||||
CredentialSource: CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ecs := CreateExecutableCredential(config.CredentialSource.Executable, &config, context.Background())
|
||||
|
||||
oldBaseEnv := baseEnv
|
||||
defer func() { baseEnv = oldBaseEnv }()
|
||||
baseEnv = func() []string {
|
||||
return []string{"A=B"}
|
||||
}
|
||||
|
||||
expectedEnvironment := []string{
|
||||
"A=B",
|
||||
fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE=%v", config.Audience),
|
||||
fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_TOKEN_TYPE=%v", config.SubjectTokenType),
|
||||
"GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE=0",
|
||||
}
|
||||
|
||||
if got, want := ecs.getEnvironment(), expectedEnvironment; !areSlicesEquivalent(got, want) {
|
||||
t.Errorf("Incorrect environment received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExectuableCredentialGetEnvironmentMalformedImpersonationUrl(t *testing.T) {
|
||||
config := Config{
|
||||
Audience: "//iam.googleapis.com/projects/123/locations/global/workloadIdentityPools/pool/providers/oidc",
|
||||
ServiceAccountImpersonationURL: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/test@project.iam.gserviceaccount.com:generateAccessToken",
|
||||
SubjectTokenType: "urn:ietf:params:oauth:token-type:jwt",
|
||||
CredentialSource: CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
OutputFile: "/path/to/generated/cached/credentials",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ecs := CreateExecutableCredential(config.CredentialSource.Executable, &config, context.Background())
|
||||
|
||||
oldBaseEnv := baseEnv
|
||||
defer func() { baseEnv = oldBaseEnv }()
|
||||
baseEnv = func() []string {
|
||||
return []string{"A=B"}
|
||||
}
|
||||
|
||||
expectedEnvironment := []string{
|
||||
"A=B",
|
||||
fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE=%v", config.Audience),
|
||||
fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_TOKEN_TYPE=%v", config.SubjectTokenType),
|
||||
"GOOGLE_EXTERNAL_ACCOUNT_IMPERSONATED_EMAIL=test@project.iam.gserviceaccount.com",
|
||||
"GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE=0",
|
||||
fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_OUTPUT_FILE=%v", config.CredentialSource.Executable.OutputFile),
|
||||
}
|
||||
|
||||
if got, want := ecs.getEnvironment(), expectedEnvironment; !areSlicesEquivalent(got, want) {
|
||||
t.Errorf("Incorrect environment received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
}
|
||||
func TestExectuableCredentialGetEnvironment(t *testing.T) {
|
||||
config := Config{
|
||||
Audience: "//iam.googleapis.com/projects/123/locations/global/workloadIdentityPools/pool/providers/oidc",
|
||||
ServiceAccountImpersonationURL: "test@project.iam.gserviceaccount.com",
|
||||
SubjectTokenType: "urn:ietf:params:oauth:token-type:jwt",
|
||||
CredentialSource: CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
OutputFile: "/path/to/generated/cached/credentials",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ecs := CreateExecutableCredential(config.CredentialSource.Executable, &config, context.Background())
|
||||
|
||||
oldBaseEnv := baseEnv
|
||||
defer func() { baseEnv = oldBaseEnv }()
|
||||
baseEnv = func() []string {
|
||||
return []string{"A=B"}
|
||||
}
|
||||
|
||||
expectedEnvironment := []string{
|
||||
"A=B",
|
||||
fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE=%v", config.Audience),
|
||||
fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_TOKEN_TYPE=%v", config.SubjectTokenType),
|
||||
"GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE=0",
|
||||
fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_OUTPUT_FILE=%v", config.CredentialSource.Executable.OutputFile),
|
||||
}
|
||||
|
||||
if got, want := ecs.getEnvironment(), expectedEnvironment; !areSlicesEquivalent(got, want) {
|
||||
t.Errorf("Incorrect environment received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenWithoutEnvironmentVariablesSet(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv := getenv
|
||||
defer func() { getenv = oldGetenv }()
|
||||
getenv = setEnvironment(map[string]string{})
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
_, err = base.subjectToken()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "Executables need to be explicitly allowed (set GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES to '1') to run."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenTimeoutOccurs(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return nil, context.DeadlineExceeded
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
_, err = base.subjectToken()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: executable command timed out."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenInvalidFormat(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return []byte("tokentokentoken"), nil
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
_, err = base.subjectToken()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: Unable to parse response JSON."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenMissingVersion(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return json.Marshal(subjectTokenResponse{
|
||||
Success: Bool(true),
|
||||
})
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
_, err = base.subjectToken()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: Response missing version field."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenMissingSuccess(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return json.Marshal(subjectTokenResponse{
|
||||
Version: Int(1),
|
||||
})
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
_, err = base.subjectToken()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: Response missing success field."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithFields(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return json.Marshal(subjectTokenResponse{
|
||||
Success: Bool(false),
|
||||
Version: Int(1),
|
||||
Code: String("404"),
|
||||
Message: String("Token Not Found"),
|
||||
})
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
_, err = base.subjectToken()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: Executable returned unsuccessful response: (404) Token Not Found."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithCode(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return json.Marshal(subjectTokenResponse{
|
||||
Success: Bool(false),
|
||||
Version: Int(1),
|
||||
Code: String("404"),
|
||||
})
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
_, err = base.subjectToken()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: Executable returned unsuccessful response: (404)."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithMessage(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return json.Marshal(subjectTokenResponse{
|
||||
Success: Bool(false),
|
||||
Version: Int(1),
|
||||
Message: String("Token Not Found"),
|
||||
})
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
_, err = base.subjectToken()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: Executable returned unsuccessful response: Token Not Found."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithoutFields(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return json.Marshal(subjectTokenResponse{
|
||||
Success: Bool(false),
|
||||
Version: Int(1),
|
||||
})
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
_, err = base.subjectToken()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: Executable returned unsuccessful response: Unknown Error."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenNewerVersion(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return json.Marshal(subjectTokenResponse{
|
||||
Success: Bool(true),
|
||||
Version: Int(2),
|
||||
})
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
_, err = base.subjectToken()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: Executable returned unsupported version: 2."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenExpired(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return json.Marshal(subjectTokenResponse{
|
||||
Success: Bool(true),
|
||||
Version: Int(1),
|
||||
ExpirationTime: Int64(now().Unix() - 1),
|
||||
TokenType: String("urn:ietf:params:oauth:token-type:jwt"),
|
||||
})
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
_, err = base.subjectToken()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: The token returned by the executable is expired."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenJwt(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return json.Marshal(subjectTokenResponse{
|
||||
Success: Bool(true),
|
||||
Version: Int(1),
|
||||
ExpirationTime: Int64(now().Unix() + 3600),
|
||||
TokenType: String("urn:ietf:params:oauth:token-type:jwt"),
|
||||
IdToken: String("tokentokentoken"),
|
||||
})
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
out, err := base.subjectToken()
|
||||
if err != nil {
|
||||
t.Fatalf("retrieveSubjectToken() failed: %v", err)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
|
||||
if got, want := out, "tokentokentoken"; got != want {
|
||||
t.Errorf("Incorrect token received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenJwtMissingIdToken(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return json.Marshal(subjectTokenResponse{
|
||||
Success: Bool(true),
|
||||
Version: Int(1),
|
||||
ExpirationTime: Int64(now().Unix() + 3600),
|
||||
TokenType: String("urn:ietf:params:oauth:token-type:jwt"),
|
||||
})
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
_, err = base.subjectToken()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: Response missing id_token field."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenIdToken(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return json.Marshal(subjectTokenResponse{
|
||||
Success: Bool(true),
|
||||
Version: Int(1),
|
||||
ExpirationTime: Int64(now().Unix() + 3600),
|
||||
TokenType: String("urn:ietf:params:oauth:token-type:id_token"),
|
||||
IdToken: String("tokentokentoken"),
|
||||
})
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
out, err := base.subjectToken()
|
||||
if err != nil {
|
||||
t.Fatalf("retrieveSubjectToken() failed: %v", err)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
|
||||
if got, want := out, "tokentokentoken"; got != want {
|
||||
t.Errorf("Incorrect token received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenSaml(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return json.Marshal(subjectTokenResponse{
|
||||
Success: Bool(true),
|
||||
Version: Int(1),
|
||||
ExpirationTime: Int64(now().Unix() + 3600),
|
||||
TokenType: String("urn:ietf:params:oauth:token-type:saml2"),
|
||||
SamlResponse: String("tokentokentoken"),
|
||||
})
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
out, err := base.subjectToken()
|
||||
if err != nil {
|
||||
t.Fatalf("retrieveSubjectToken() failed: %v", err)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
|
||||
if got, want := out, "tokentokentoken"; got != want {
|
||||
t.Errorf("Incorrect token received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenSamlMissingResponse(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
}
|
||||
|
||||
tfc := testFileConfig
|
||||
tfc.CredentialSource = cs
|
||||
|
||||
oldGetenv, oldNow, oldRunCommand := getenv, now, runCommand
|
||||
defer func() {
|
||||
getenv, now, runCommand = oldGetenv, oldNow, oldRunCommand
|
||||
}()
|
||||
|
||||
getenv = setEnvironment(map[string]string{"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
|
||||
now = setTime(defaultTime)
|
||||
deadline, deadlineSet := now(), false
|
||||
runCommand = func(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||
deadline, deadlineSet = ctx.Deadline()
|
||||
return json.Marshal(subjectTokenResponse{
|
||||
Success: Bool(true),
|
||||
Version: Int(1),
|
||||
ExpirationTime: Int64(now().Unix() + 3600),
|
||||
TokenType: String("urn:ietf:params:oauth:token-type:saml2"),
|
||||
})
|
||||
}
|
||||
|
||||
base, err := tfc.parse(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("parse() failed %v", err)
|
||||
}
|
||||
|
||||
_, err = base.subjectToken()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: Response missing saml_response field."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
t.Errorf("Command run without a deadline")
|
||||
} else if deadline != now().Add(5*time.Second) {
|
||||
t.Errorf("Command run with incorrect deadline")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user