diff options
| author | n1c00o <n@nc0.fr> | 2023-02-05 14:05:26 +0100 | 
|---|---|---|
| committer | Nicolas <34602094+n1c00o@users.noreply.github.com> | 2023-02-06 22:35:54 +0100 | 
| commit | b371cb11a5877ede8847351e95c7847b5024a551 (patch) | |
| tree | 958227cf8562503246976744b89370d389de5f66 /vendor/google.golang.org/api/internal/impersonate/impersonate.go | |
| parent | 03e0c597ad5f3539ad33976fe02c11a9e39f34d6 (diff) | |
Init Go module
Diffstat (limited to 'vendor/google.golang.org/api/internal/impersonate/impersonate.go')
| -rw-r--r-- | vendor/google.golang.org/api/internal/impersonate/impersonate.go | 128 | 
1 files changed, 128 insertions, 0 deletions
diff --git a/vendor/google.golang.org/api/internal/impersonate/impersonate.go b/vendor/google.golang.org/api/internal/impersonate/impersonate.go new file mode 100644 index 0000000..b465bbc --- /dev/null +++ b/vendor/google.golang.org/api/internal/impersonate/impersonate.go @@ -0,0 +1,128 @@ +// 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 ( +	"bytes" +	"context" +	"encoding/json" +	"fmt" +	"io" +	"io/ioutil" +	"net/http" +	"time" + +	"golang.org/x/oauth2" +) + +// Config for generating impersonated credentials. +type Config struct { +	// Target is the service account to impersonate. Required. +	Target string +	// Scopes the impersonated credential should have. Required. +	Scopes []string +	// 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. +	Delegates []string +} + +// TokenSource returns an impersonated TokenSource configured with the provided +// config using ts as the base credential provider for making requests. +func TokenSource(ctx context.Context, ts oauth2.TokenSource, config *Config) (oauth2.TokenSource, error) { +	if len(config.Scopes) == 0 { +		return nil, fmt.Errorf("impersonate: scopes must be provided") +	} +	its := impersonatedTokenSource{ +		ctx:  ctx, +		ts:   ts, +		name: formatIAMServiceAccountName(config.Target), +		// Default to the longest acceptable value of one hour as the token will +		// be refreshed automatically. +		lifetime: "3600s", +	} + +	its.delegates = make([]string, len(config.Delegates)) +	for i, v := range config.Delegates { +		its.delegates[i] = formatIAMServiceAccountName(v) +	} +	its.scopes = make([]string, len(config.Scopes)) +	copy(its.scopes, config.Scopes) + +	return oauth2.ReuseTokenSource(nil, its), nil +} + +func formatIAMServiceAccountName(name string) string { +	return fmt.Sprintf("projects/-/serviceAccounts/%s", name) +} + +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 (i impersonatedTokenSource) Token() (*oauth2.Token, error) { +	hc := oauth2.NewClient(i.ctx, i.ts) +	reqBody := generateAccessTokenReq{ +		Delegates: i.delegates, +		Lifetime:  i.lifetime, +		Scope:     i.scopes, +	} +	b, err := json.Marshal(reqBody) +	if err != nil { +		return nil, fmt.Errorf("impersonate: unable to marshal request: %v", err) +	} +	url := fmt.Sprintf("https://iamcredentials.googleapis.com/v1/%s:generateAccessToken", i.name) +	req, err := http.NewRequest("POST", url, bytes.NewReader(b)) +	if err != nil { +		return nil, fmt.Errorf("impersonate: unable to create request: %v", err) +	} +	req = req.WithContext(i.ctx) +	req.Header.Set("Content-Type", "application/json") + +	resp, err := hc.Do(req) +	if err != nil { +		return nil, fmt.Errorf("impersonate: unable to generate access token: %v", err) +	} +	defer resp.Body.Close() +	body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20)) +	if err != nil { +		return nil, fmt.Errorf("impersonate: unable to read body: %v", err) +	} +	if c := resp.StatusCode; c < 200 || c > 299 { +		return nil, fmt.Errorf("impersonate: status code %d: %s", c, body) +	} + +	var accessTokenResp generateAccessTokenResp +	if err := json.Unmarshal(body, &accessTokenResp); err != nil { +		return nil, fmt.Errorf("impersonate: unable to parse response: %v", err) +	} +	expiry, err := time.Parse(time.RFC3339, accessTokenResp.ExpireTime) +	if err != nil { +		return nil, fmt.Errorf("impersonate: unable to parse expiry: %v", err) +	} +	return &oauth2.Token{ +		AccessToken: accessTokenResp.AccessToken, +		Expiry:      expiry, +	}, nil +}  | 
