mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-01-11 03:11:50 +00:00
65 lines
1.9 KiB
Go
65 lines
1.9 KiB
Go
package http
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"sync"
|
|
|
|
"golang.org/x/oauth2"
|
|
"golang.org/x/oauth2/google"
|
|
)
|
|
|
|
// gcpRoundTripper wraps http.RoundTripper to add Google Cloud authentication.
|
|
// It delays GCP authentication initialization until the first actual request is made.
|
|
// This avoids unnecessary credential loading when ar+https protocol is not actually used.
|
|
//
|
|
// It uses Application Default Credentials (ADC) which checks:
|
|
// 1. GOOGLE_APPLICATION_CREDENTIALS environment variable
|
|
// 2. gcloud auth application-default credentials
|
|
// 3. GCE/GKE metadata server
|
|
// See https://cloud.google.com/docs/authentication/application-default-credentials for usage details.
|
|
type gcpRoundTripper struct {
|
|
base http.RoundTripper
|
|
initOnce sync.Once
|
|
tokenSrc oauth2.TokenSource
|
|
initErr error
|
|
}
|
|
|
|
func (t *gcpRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
// Lazy initialization: only initialize GCP credentials on first request
|
|
t.initOnce.Do(func() {
|
|
creds, err := google.FindDefaultCredentials(context.Background(),
|
|
"https://www.googleapis.com/auth/cloud-platform")
|
|
if err != nil {
|
|
t.initErr = fmt.Errorf("failed to find default credentials: %w", err)
|
|
return
|
|
}
|
|
t.tokenSrc = creds.TokenSource
|
|
})
|
|
|
|
reqCopy := req.Clone(req.Context())
|
|
reqCopy.URL.Scheme = strings.TrimPrefix(reqCopy.URL.Scheme, "ar+")
|
|
|
|
// Fall back to base transport if GCP auth initialization failed
|
|
if t.initErr != nil {
|
|
return t.base.RoundTrip(reqCopy)
|
|
}
|
|
|
|
token, err := t.tokenSrc.Token()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get OAuth2 token: %w", err)
|
|
}
|
|
token.SetAuthHeader(reqCopy)
|
|
|
|
return t.base.RoundTrip(reqCopy)
|
|
}
|
|
|
|
// NewGCPRoundTripper creates a new RoundTripper that handles GCP authentication for ar+https protocol.
|
|
func NewGCPRoundTripper(base http.RoundTripper) http.RoundTripper {
|
|
return &gcpRoundTripper{
|
|
base: base,
|
|
}
|
|
}
|