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

test: integration Tests for Configurable Token Lifespan #1657

Merged
merged 6 commits into from Aug 25, 2022
Merged
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
120 changes: 95 additions & 25 deletions integration-tests/byoid/integration_test.go
Expand Up @@ -142,13 +142,9 @@ func generateGoogleToken(keyFileName string) (string, error) {
return token.AccessToken, nil
}

// testBYOID makes sure that the default credentials works for
// whatever preconditions have been set beforehand
// by using those credentials to run our client libraries.
//
// In each test we will set up whatever preconditions we need,
// and then use this function.
func testBYOID(t *testing.T, c config) {
// writeConfig writes a temporary config file to memory, and cleans it up after
// testing code is run.
func writeConfig(t *testing.T, c config, f func(name string)) {
t.Helper()

// Set up config file.
Expand All @@ -164,40 +160,59 @@ func testBYOID(t *testing.T, c config) {
}
configFile.Close()

// Once the default credentials are obtained,
// we should be able to access Google Cloud resources.
dnsService, err := dns.NewService(context.Background(), option.WithCredentialsFile(configFile.Name()))
if err != nil {
t.Fatalf("Could not establish DNS Service: %v", err)
}
f(configFile.Name())
}

_, err = dnsService.Projects.Get(projectID).Do()
if err != nil {
t.Fatalf("DNS Service failed: %v", err)
}
// testBYOID makes sure that the default credentials works for
// whatever preconditions have been set beforehand
// by using those credentials to run our client libraries.
//
// In each test we will set up whatever preconditions we need,
// and then use this function.
func testBYOID(t *testing.T, c config) {
t.Helper()

writeConfig(t, c, func(name string) {
// Once the default credentials are obtained,
// we should be able to access Google Cloud resources.
dnsService, err := dns.NewService(context.Background(), option.WithCredentialsFile(name))
if err != nil {
t.Fatalf("Could not establish DNS Service: %v", err)
}

_, err = dnsService.Projects.Get(projectID).Do()
if err != nil {
t.Fatalf("DNS Service failed: %v", err)
}
})
}

// These structs makes writing our config as json to a file much easier.
type config struct {
Type string `json:"type"`
Audience string `json:"audience"`
SubjectTokenType string `json:"subject_token_type"`
TokenURL string `json:"token_url"`
ServiceAccountImpersonationURL string `json:"service_account_impersonation_url"`
CredentialSource credentialSource `json:"credential_source"`
Type string `json:"type"`
Audience string `json:"audience"`
SubjectTokenType string `json:"subject_token_type"`
TokenURL string `json:"token_url"`
ServiceAccountImpersonationURL string `json:"service_account_impersonation_url"`
ServiceAccountImpersonation serviceAccountImpersonationInfo `json:"service_account_impersonation,omitempty"`
CredentialSource credentialSource `json:"credential_source"`
}

type serviceAccountImpersonationInfo struct {
TokenLifetimeSeconds int `json:"token_lifetime_seconds,omitempty"`
}

type credentialSource struct {
File string `json:"file,omitempty"`
URL string `json:"url,omitempty"`
Executable executableConfig `json:"executable,omitempty"`
EnvironmentID string `json:"environment_id,omitempty"`
RegionURL string `json:"region_url"`
RegionURL string `json:"region_url,omitempty"`
RegionalCredVerificationURL string `json:"regional_cred_verification_url,omitempty"`
}

type executableConfig struct {
Command string `json:"command"`
Command string `json:"command,omitempty"`
TimeoutMillis int `json:"timeout_millis,omitempty"`
OutputFile string `json:"output_file,omitempty"`
}
Expand Down Expand Up @@ -380,3 +395,58 @@ echo "{\"success\":true,\"version\":1,\"expiration_time\":%v,\"token_type\":\"ur
},
})
}

func TestConfigurableTokenLifetime(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}

// Set up Token as a file
tokenFile, err := ioutil.TempFile("", "token.txt")
if err != nil {
t.Fatalf("Error creating token file:")
}
defer os.Remove(tokenFile.Name())

tokenFile.WriteString(oidcToken)
tokenFile.Close()

const tokenLifetimeSeconds = 2800
const safetyBuffer = 5

writeConfig(t, config{
Type: "external_account",
Audience: oidcAudience,
SubjectTokenType: "urn:ietf:params:oauth:token-type:jwt",
TokenURL: "https://sts.googleapis.com/v1/token",
ServiceAccountImpersonationURL: fmt.Sprintf("https://iamcredentials.googleapis.com/v1/%s:generateAccessToken", clientID),
ServiceAccountImpersonation: serviceAccountImpersonationInfo{
TokenLifetimeSeconds: tokenLifetimeSeconds,
},
CredentialSource: credentialSource{
File: tokenFile.Name(),
},
}, func(filename string) {
b, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("Coudn't read temp config file")
}

creds, err := google.CredentialsFromJSON(context.Background(), b, "https://www.googleapis.com/auth/cloud-platform")
if err != nil {
t.Fatalf("Error retrieving credentials")
}

token, err := creds.TokenSource.Token()
if err != nil {
t.Fatalf("Error getting token")
}

now := time.Now()
expiryMax := now.Add(tokenLifetimeSeconds * time.Second)
expiryMin := expiryMax.Add(-safetyBuffer * time.Second)
if token.Expiry.Before(expiryMin) || token.Expiry.After(expiryMax) {
t.Fatalf("Expiry time not set correctly. Got %v, want %v", token.Expiry, expiryMax)
}
})
}