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 impersonate is used to impersonate Google Credentials.
package impersonate

import (
	
	
	
	
	
	
	
	

	
)
Config for generating impersonated credentials.
Target is the service account to impersonate. Required.
Scopes the impersonated credential should have. Required.
Delegates are the service accounts in a delegation chain. Each service account must be granted roles/iam.serviceAccountTokenCreator on the next service account in the chain. Optional.
TokenSource returns an impersonated TokenSource configured with the provided config using ts as the base credential provider for making requests.
func ( context.Context,  oauth2.TokenSource,  *Config) (oauth2.TokenSource, error) {
	if len(.Scopes) == 0 {
		return nil, fmt.Errorf("impersonate: scopes must be provided")
	}
	 := impersonatedTokenSource{
		ctx:  ,
		ts:   ,
Default to the longest acceptable value of one hour as the token will be refreshed automatically.
		lifetime: "3600s",
	}

	.delegates = make([]string, len(.Delegates))
	for ,  := range .Delegates {
		.delegates[] = formatIAMServiceAccountName()
	}
	.scopes = make([]string, len(.Scopes))
	copy(.scopes, .Scopes)

	return oauth2.ReuseTokenSource(nil, ), nil
}

func ( string) string {
	return fmt.Sprintf("projects/-/serviceAccounts/%s", )
}

type generateAccessTokenReq struct {
	Delegates []string `json:"delegates,omitempty"`
	Lifetime  string   `json:"lifetime,omitempty"`
	Scope     []string `json:"scope,omitempty"`
}

type generateAccessTokenResp struct {
	AccessToken string `json:"accessToken"`
	ExpireTime  string `json:"expireTime"`
}

type impersonatedTokenSource struct {
	ctx context.Context
	ts  oauth2.TokenSource

	name      string
	lifetime  string
	scopes    []string
	delegates []string
}
Token returns an impersonated Token.
func ( impersonatedTokenSource) () (*oauth2.Token, error) {
	 := oauth2.NewClient(.ctx, .ts)
	 := generateAccessTokenReq{
		Delegates: .delegates,
		Lifetime:  .lifetime,
		Scope:     .scopes,
	}
	,  := json.Marshal()
	if  != nil {
		return nil, fmt.Errorf("impersonate: unable to marshal request: %v", )
	}
	 := fmt.Sprintf("https://iamcredentials.googleapis.com/v1/%s:generateAccessToken", .name)
	,  := http.NewRequest("POST", , bytes.NewReader())
	if  != nil {
		return nil, fmt.Errorf("impersonate: unable to create request: %v", )
	}
	 = .WithContext(.ctx)
	.Header.Set("Content-Type", "application/json")

	,  := .Do()
	if  != nil {
		return nil, fmt.Errorf("impersonate: unable to generate access token: %v", )
	}
	defer .Body.Close()
	,  := ioutil.ReadAll(io.LimitReader(.Body, 1<<20))
	if  != nil {
		return nil, fmt.Errorf("impersonate: unable to read body: %v", )
	}
	if  := .StatusCode;  < 200 ||  > 299 {
		return nil, fmt.Errorf("impersonate: status code %d: %s", , )
	}

	var  generateAccessTokenResp
	if  := json.Unmarshal(, &);  != nil {
		return nil, fmt.Errorf("impersonate: unable to parse response: %v", )
	}
	,  := time.Parse(time.RFC3339, .ExpireTime)
	if  != nil {
		return nil, fmt.Errorf("impersonate: unable to parse expiry: %v", )
	}
	return &oauth2.Token{
		AccessToken: .AccessToken,
		Expiry:      ,
	}, nil