forked from remote/oauth2
Changes requested by @codyoss
This commit is contained in:
@@ -171,7 +171,7 @@ type CredentialSource struct {
|
||||
URL string `json:"url"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
|
||||
Executable ExecutableConfig `json:"executable"`
|
||||
Executable *ExecutableConfig `json:"executable"`
|
||||
|
||||
EnvironmentID string `json:"environment_id"`
|
||||
RegionURL string `json:"region_url"`
|
||||
@@ -187,7 +187,7 @@ type ExecutableConfig struct {
|
||||
OutputFile string `json:"output_file"`
|
||||
}
|
||||
|
||||
// parse determines the type of CredentialSource needed
|
||||
// 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" {
|
||||
if awsVersion, err := strconv.Atoi(c.CredentialSource.EnvironmentID[3:]); err == nil {
|
||||
@@ -213,8 +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
|
||||
} else if c.CredentialSource.Executable != nil {
|
||||
return CreateExecutableCredential(*c.CredentialSource.Executable, c, ctx), nil
|
||||
}
|
||||
return nil, fmt.Errorf("oauth2/google: unable to parse credential source")
|
||||
}
|
||||
|
||||
@@ -15,10 +15,56 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
EXECUTABLE_SUPPORTED_MAX_VERSION = 1
|
||||
const (
|
||||
executableSupportedMaxVersion = 1
|
||||
defaultTimeout = 30 * time.Second
|
||||
)
|
||||
|
||||
func missingFieldError(field string) error {
|
||||
return fmt.Errorf("oauth2/google: response missing `%v` field", field)
|
||||
}
|
||||
|
||||
func jsonParsingError() error {
|
||||
return errors.New("oauth2/google: unable to parse response JSON")
|
||||
}
|
||||
|
||||
func malformedFailureError() error {
|
||||
return errors.New("oauth2/google: response must include `error` and `message` fields when unsuccessful")
|
||||
}
|
||||
|
||||
func userDefinedError(code, message string) error {
|
||||
return fmt.Errorf("oauth2/google: executable returned unsuccessful response: (%v) %v", code, message)
|
||||
}
|
||||
|
||||
func unsupportedVersionError(version int) error {
|
||||
return fmt.Errorf("oauth2/google: executable returned unsupported version: %v", version)
|
||||
}
|
||||
|
||||
func tokenExpiredError() error {
|
||||
return errors.New("oauth2/google: the token returned by the executable is expired")
|
||||
}
|
||||
|
||||
func tokenTypeError() error {
|
||||
return errors.New("oauth2/google: executable returned unsupported token type")
|
||||
}
|
||||
|
||||
func timeoutError() error {
|
||||
return errors.New("oauth2/google: executable command timed out")
|
||||
}
|
||||
|
||||
func exitCodeError(exitCode int) error {
|
||||
return fmt.Errorf("oauth2/google: executable command failed with exit code %v", exitCode)
|
||||
}
|
||||
|
||||
func executableError(err error) error {
|
||||
return fmt.Errorf("oauth2/google: executable command failed: %v", err.Error())
|
||||
}
|
||||
|
||||
func executablesDisallowedError() error {
|
||||
return errors.New("Executables need to be explicitly allowed (set GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES to '1') to run")
|
||||
}
|
||||
|
||||
// baseEnv is an alias of os.Environ used for testing
|
||||
var baseEnv = os.Environ
|
||||
|
||||
// runCommand is basically an alias of exec.CommandContext for testing.
|
||||
@@ -46,7 +92,7 @@ type executableCredentialSource struct {
|
||||
func CreateExecutableCredential(ec ExecutableConfig, config *Config, ctx context.Context) (result executableCredentialSource) {
|
||||
result.Command = ec.Command
|
||||
if ec.TimeoutMillis == 0 {
|
||||
result.Timeout = 30 * time.Second
|
||||
result.Timeout = defaultTimeout
|
||||
} else {
|
||||
result.Timeout = time.Duration(ec.TimeoutMillis) * time.Millisecond
|
||||
}
|
||||
@@ -57,68 +103,68 @@ func CreateExecutableCredential(ec ExecutableConfig, config *Config, ctx context
|
||||
}
|
||||
|
||||
type executableResponse 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"`
|
||||
Version *int `json:"version,omitempty"`
|
||||
Success *bool `json:"success,omitempty"`
|
||||
TokenType *string `json:"token_type,omitempty"`
|
||||
ExpirationTime *int64 `json:"expiration_time,omitempty"`
|
||||
IdToken *string `json:"id_token,omitempty"`
|
||||
SamlResponse *string `json:"saml_response,omitempty"`
|
||||
Code string `json:"code,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func parseSubjectToken(response []byte) (string, error) {
|
||||
var result executableResponse
|
||||
if err := json.Unmarshal(response, &result); err != nil {
|
||||
return "", errors.New("oauth2/google: Unable to parse response JSON.")
|
||||
return "", jsonParsingError()
|
||||
}
|
||||
|
||||
if result.Version == nil {
|
||||
return "", errors.New("oauth2/google: Response missing version field.")
|
||||
return "", missingFieldError("version")
|
||||
}
|
||||
|
||||
if result.Success == nil {
|
||||
return "", errors.New("oauth2/google: Response missing success field.")
|
||||
return "", missingFieldError("success")
|
||||
}
|
||||
|
||||
if !*result.Success {
|
||||
if result.Code == "" || result.Message == "" {
|
||||
return "", errors.New("oauth2/google: Response must include `error` and `message` fields when unsuccessful.")
|
||||
return "", malformedFailureError()
|
||||
}
|
||||
return "", fmt.Errorf("oauth2/google: Executable returned unsuccessful response: (%v) %v.", result.Code, result.Message)
|
||||
return "", userDefinedError(result.Code, result.Message)
|
||||
}
|
||||
|
||||
if *result.Version > EXECUTABLE_SUPPORTED_MAX_VERSION {
|
||||
return "", fmt.Errorf("oauth2/google: Executable returned unsupported version: %v.", *result.Version)
|
||||
if *result.Version > executableSupportedMaxVersion {
|
||||
return "", unsupportedVersionError(*result.Version)
|
||||
}
|
||||
|
||||
if result.ExpirationTime == nil {
|
||||
return "", errors.New("oauth2/google: Response missing expiration_time field.")
|
||||
return "", missingFieldError("expiration_time")
|
||||
}
|
||||
|
||||
if result.TokenType == nil {
|
||||
return "", errors.New("oauth2/google: Response missing token_type field.")
|
||||
return "", missingFieldError("token_type")
|
||||
}
|
||||
|
||||
if *result.ExpirationTime < now().Unix() {
|
||||
return "", errors.New("oauth2/google: The token returned by the executable is expired.")
|
||||
return "", tokenExpiredError()
|
||||
}
|
||||
|
||||
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 "", missingFieldError("id_token")
|
||||
}
|
||||
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 "", missingFieldError("saml_response")
|
||||
}
|
||||
return *result.SamlResponse, nil
|
||||
}
|
||||
|
||||
return "", errors.New("Executable returned unsupported token type.")
|
||||
return "", tokenTypeError()
|
||||
}
|
||||
|
||||
func (cs executableCredentialSource) subjectToken() (string, error) {
|
||||
@@ -169,7 +215,7 @@ func (cs executableCredentialSource) getNewEnvironmentVariables() map[string]str
|
||||
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.")
|
||||
return "", executablesDisallowedError()
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithDeadline(cs.ctx, now().Add(cs.Timeout))
|
||||
@@ -177,12 +223,12 @@ func (cs executableCredentialSource) getTokenFromExecutableCommand() (string, er
|
||||
|
||||
if output, err := runCommand(ctx, cs.Command, cs.getEnvironment()); err != nil {
|
||||
if err == context.DeadlineExceeded {
|
||||
return "", fmt.Errorf("oauth2/google: executable command timed out.")
|
||||
return "", timeoutError()
|
||||
}
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
return "", fmt.Errorf("oauth2/google: executable command failed with exit code %v.", exitError.ExitCode())
|
||||
return "", exitCodeError(exitError.ExitCode())
|
||||
}
|
||||
return "", fmt.Errorf("oauth2/google: executable command failed: %v.", err.Error())
|
||||
return "", executableError(err)
|
||||
} else {
|
||||
return parseSubjectToken(output)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package externalaccount
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -56,7 +57,7 @@ func TestCreateExecutableCredential_WithoutTimeout(t *testing.T) {
|
||||
if ecs.Command != "blarg" {
|
||||
t.Errorf("ecs.Command got %v but want %v", ecs.Command, "blarg")
|
||||
}
|
||||
if ecs.Timeout != 30000*time.Millisecond {
|
||||
if ecs.Timeout != defaultTimeout {
|
||||
t.Errorf("ecs.Timeout got %v but want %v", ecs.Timeout, 30000*time.Millisecond)
|
||||
}
|
||||
}
|
||||
@@ -78,18 +79,18 @@ OUTER:
|
||||
return true
|
||||
}
|
||||
|
||||
func TestMinimalExectuableCredentialGetEnvironment(t *testing.T) {
|
||||
func TestMinimalExecutableCredentialGetEnvironment(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{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ecs := CreateExecutableCredential(config.CredentialSource.Executable, &config, context.Background())
|
||||
ecs := CreateExecutableCredential(*config.CredentialSource.Executable, &config, context.Background())
|
||||
|
||||
oldBaseEnv := baseEnv
|
||||
defer func() { baseEnv = oldBaseEnv }()
|
||||
@@ -105,7 +106,7 @@ func TestMinimalExectuableCredentialGetEnvironment(t *testing.T) {
|
||||
}
|
||||
|
||||
if got, want := ecs.getEnvironment(), expectedEnvironment; !areSlicesEquivalent(got, want) {
|
||||
t.Errorf("Incorrect environment received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
t.Errorf("Incorrect environment received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,14 +116,14 @@ func TestExectuableCredentialGetEnvironmentMalformedImpersonationUrl(t *testing.
|
||||
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{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
OutputFile: "/path/to/generated/cached/credentials",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ecs := CreateExecutableCredential(config.CredentialSource.Executable, &config, context.Background())
|
||||
ecs := CreateExecutableCredential(*config.CredentialSource.Executable, &config, context.Background())
|
||||
|
||||
oldBaseEnv := baseEnv
|
||||
defer func() { baseEnv = oldBaseEnv }()
|
||||
@@ -140,23 +141,24 @@ func TestExectuableCredentialGetEnvironmentMalformedImpersonationUrl(t *testing.
|
||||
}
|
||||
|
||||
if got, want := ecs.getEnvironment(), expectedEnvironment; !areSlicesEquivalent(got, want) {
|
||||
t.Errorf("Incorrect environment received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
t.Errorf("Incorrect environment received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
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{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
OutputFile: "/path/to/generated/cached/credentials",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ecs := CreateExecutableCredential(config.CredentialSource.Executable, &config, context.Background())
|
||||
ecs := CreateExecutableCredential(*config.CredentialSource.Executable, &config, context.Background())
|
||||
|
||||
oldBaseEnv := baseEnv
|
||||
defer func() { baseEnv = oldBaseEnv }()
|
||||
@@ -173,13 +175,13 @@ func TestExectuableCredentialGetEnvironment(t *testing.T) {
|
||||
}
|
||||
|
||||
if got, want := ecs.getEnvironment(), expectedEnvironment; !areSlicesEquivalent(got, want) {
|
||||
t.Errorf("Incorrect environment received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
t.Errorf("Incorrect environment received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenWithoutEnvironmentVariablesSet(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -201,14 +203,58 @@ func TestRetrieveExecutableSubjectTokenWithoutEnvironmentVariablesSet(t *testing
|
||||
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)
|
||||
if got, want := err.Error(), executablesDisallowedError().Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectExecutableErrorOccurs(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, errors.New("foo")
|
||||
}
|
||||
|
||||
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(), executableError(errors.New("foo")).Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
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 TestRetrieveExecutableSubjectTokenTimeoutOccurs(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -239,8 +285,8 @@ func TestRetrieveExecutableSubjectTokenTimeoutOccurs(t *testing.T) {
|
||||
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 got, want := err.Error(), timeoutError().Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
@@ -252,7 +298,7 @@ func TestRetrieveExecutableSubjectTokenTimeoutOccurs(t *testing.T) {
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenInvalidFormat(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -283,8 +329,8 @@ func TestRetrieveExecutableSubjectTokenInvalidFormat(t *testing.T) {
|
||||
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 got, want := err.Error(), jsonParsingError().Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
@@ -296,7 +342,7 @@ func TestRetrieveExecutableSubjectTokenInvalidFormat(t *testing.T) {
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenMissingVersion(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -329,8 +375,8 @@ func TestRetrieveExecutableSubjectTokenMissingVersion(t *testing.T) {
|
||||
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 got, want := err.Error(), missingFieldError("version").Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
@@ -342,7 +388,7 @@ func TestRetrieveExecutableSubjectTokenMissingVersion(t *testing.T) {
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenMissingSuccess(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -375,8 +421,8 @@ func TestRetrieveExecutableSubjectTokenMissingSuccess(t *testing.T) {
|
||||
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 got, want := err.Error(), missingFieldError("success").Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
@@ -388,7 +434,7 @@ func TestRetrieveExecutableSubjectTokenMissingSuccess(t *testing.T) {
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithFields(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -424,8 +470,8 @@ func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithFields(t *testing
|
||||
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 got, want := err.Error(), userDefinedError("404", "Token Not Found").Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
@@ -437,7 +483,7 @@ func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithFields(t *testing
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithCode(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -472,8 +518,8 @@ func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithCode(t *testing.T
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: Response must include `error` and `message` fields when unsuccessful."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
if got, want := err.Error(), malformedFailureError().Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
@@ -485,7 +531,7 @@ func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithCode(t *testing.T
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithMessage(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -520,8 +566,8 @@ func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithMessage(t *testin
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: Response must include `error` and `message` fields when unsuccessful."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
if got, want := err.Error(), malformedFailureError().Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
@@ -533,7 +579,7 @@ func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithMessage(t *testin
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithoutFields(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -567,8 +613,8 @@ func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithoutFields(t *test
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found none")
|
||||
}
|
||||
if got, want := err.Error(), "oauth2/google: Response must include `error` and `message` fields when unsuccessful."; got != want {
|
||||
t.Errorf("Incorrect error received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
if got, want := err.Error(), malformedFailureError().Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
@@ -580,7 +626,7 @@ func TestRetrieveExecutableSubjectTokenUnsuccessfulResponseWithoutFields(t *test
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenNewerVersion(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -614,8 +660,153 @@ func TestRetrieveExecutableSubjectTokenNewerVersion(t *testing.T) {
|
||||
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 got, want := err.Error(), unsupportedVersionError(2).Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
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 TestRetrieveExecutableSubjectTokenMissingExpiration(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(executableResponse{
|
||||
Success: Bool(true),
|
||||
Version: Int(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(), missingFieldError("expiration_time").Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
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 TestRetrieveExecutableSubjectTokenTokenTypeMissing(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(executableResponse{
|
||||
Success: Bool(true),
|
||||
Version: Int(1),
|
||||
ExpirationTime: Int64(now().Unix()),
|
||||
})
|
||||
}
|
||||
|
||||
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(), missingFieldError("token_type").Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
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 TestRetrieveExecutableSubjectTokenInvalidTokenType(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(executableResponse{
|
||||
Success: Bool(true),
|
||||
Version: Int(1),
|
||||
ExpirationTime: Int64(now().Unix()),
|
||||
TokenType: String("urn:ietf:params:oauth:token-type:invalid"),
|
||||
})
|
||||
}
|
||||
|
||||
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(), tokenTypeError().Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
@@ -627,7 +818,7 @@ func TestRetrieveExecutableSubjectTokenNewerVersion(t *testing.T) {
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenExpired(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -663,8 +854,8 @@ func TestRetrieveExecutableSubjectTokenExpired(t *testing.T) {
|
||||
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 got, want := err.Error(), tokenExpiredError().Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
@@ -676,7 +867,7 @@ func TestRetrieveExecutableSubjectTokenExpired(t *testing.T) {
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenJwt(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -721,13 +912,13 @@ func TestRetrieveExecutableSubjectTokenJwt(t *testing.T) {
|
||||
}
|
||||
|
||||
if got, want := out, "tokentokentoken"; got != want {
|
||||
t.Errorf("Incorrect token received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
t.Errorf("Incorrect token received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenJwtMissingIdToken(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -763,8 +954,8 @@ func TestRetrieveExecutableSubjectTokenJwtMissingIdToken(t *testing.T) {
|
||||
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 got, want := err.Error(), missingFieldError("id_token").Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
@@ -776,7 +967,7 @@ func TestRetrieveExecutableSubjectTokenJwtMissingIdToken(t *testing.T) {
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenIdToken(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -821,13 +1012,13 @@ func TestRetrieveExecutableSubjectTokenIdToken(t *testing.T) {
|
||||
}
|
||||
|
||||
if got, want := out, "tokentokentoken"; got != want {
|
||||
t.Errorf("Incorrect token received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
t.Errorf("Incorrect token received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenSaml(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -872,13 +1063,13 @@ func TestRetrieveExecutableSubjectTokenSaml(t *testing.T) {
|
||||
}
|
||||
|
||||
if got, want := out, "tokentokentoken"; got != want {
|
||||
t.Errorf("Incorrect token received.\nExpected: %s\nRecieved: %s", want, got)
|
||||
t.Errorf("Incorrect token received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveExecutableSubjectTokenSamlMissingResponse(t *testing.T) {
|
||||
cs := CredentialSource{
|
||||
Executable: ExecutableConfig{
|
||||
Executable: &ExecutableConfig{
|
||||
Command: "blarg",
|
||||
TimeoutMillis: 5000,
|
||||
},
|
||||
@@ -914,8 +1105,8 @@ func TestRetrieveExecutableSubjectTokenSamlMissingResponse(t *testing.T) {
|
||||
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 got, want := err.Error(), missingFieldError("saml_response").Error(); got != want {
|
||||
t.Errorf("Incorrect error received.\nReceived: %s\nExpected: %s", got, want)
|
||||
}
|
||||
|
||||
if !deadlineSet {
|
||||
|
||||
Reference in New Issue
Block a user