Skip to content

Commit

Permalink
fix(auth): make sure quota option takes prec over env/file
Browse files Browse the repository at this point in the history
Fixes: #10795
  • Loading branch information
codyoss committed Aug 29, 2024
1 parent 6f6959b commit d83e3b0
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 4 deletions.
7 changes: 5 additions & 2 deletions auth/grpctransport/grpctransport.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const (
// Check env to decide if using google-c2p resolver for DirectPath traffic.
enableDirectPathXdsEnvVar = "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS"

quotaProjectHeaderKey = "X-Goog-User-Project"
quotaProjectHeaderKey = "X-goog-user-project"
)

var (
Expand Down Expand Up @@ -271,7 +271,10 @@ func dial(ctx context.Context, secure bool, opts *Options) (*grpc.ClientConn, er
if metadata == nil {
metadata = make(map[string]string, 1)
}
metadata[quotaProjectHeaderKey] = qp
// Don't overwrite user specified quota
if _, ok := metadata[quotaProjectHeaderKey]; !ok {
metadata[quotaProjectHeaderKey] = qp
}
}
grpcOpts = append(grpcOpts,
grpc.WithPerRPCCredentials(&grpcCredentialsProvider{
Expand Down
50 changes: 50 additions & 0 deletions auth/grpctransport/grpctransport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,56 @@ func TestGRPCKeyProvider_GetRequestMetadata(t *testing.T) {
}
}

func TestNewClient_QuotaPrecedence(t *testing.T) {
testQuota := "testquotaWins"
t.Setenv(internal.QuotaProjectEnvVar, "testquotaLoses")
l, err := net.Listen("tcp", "localhost:0")
if err != nil {
t.Fatal(err)
}
gsrv := grpc.NewServer()
defer gsrv.Stop()
echo.RegisterEchoerServer(gsrv, &fakeEchoService{
Fn: func(ctx context.Context, _ *echo.EchoRequest) (*echo.EchoReply, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
t.Error("unable to extract metadata")
return nil, errors.New("oops")
}
if got := md.Get(quotaProjectHeaderKey); len(got) != 1 || got[0] != testQuota {
t.Errorf("got %q, want %q", got, testQuota)
}
return &echo.EchoReply{}, nil
},
})
go func() {
if err := gsrv.Serve(l); err != nil {
panic(err)
}
}()

pool, err := Dial(context.Background(), false, &Options{
Metadata: map[string]string{quotaProjectHeaderKey: "testquotaWins"},
InternalOptions: &InternalOptions{
DefaultEndpointTemplate: l.Addr().String(),
},
DetectOpts: &credentials.DetectOptions{
Audience: l.Addr().String(),
CredentialsFile: "../internal/testdata/sa_universe_domain.json",
UseSelfSignedJWT: true,
},
GRPCDialOpts: []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())},
UniverseDomain: "example.com", // Also configured in sa_universe_domain.json
})
if err != nil {
t.Fatalf("NewClient() = %v", err)
}
client := echo.NewEchoerClient(pool)
if _, err := client.Echo(context.Background(), &echo.EchoRequest{}); err != nil {
t.Fatalf("client.Echo() = %v", err)
}
}

type staticTP struct {
tok *auth.Token
}
Expand Down
31 changes: 31 additions & 0 deletions auth/httptransport/httptransport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,37 @@ func TestNewClient_APIKey(t *testing.T) {
}
}

func TestNewClient_QuotaPrecedence(t *testing.T) {
testQuota := "testquotaWins"
t.Setenv(internal.QuotaProjectEnvVar, "testquotaLoses")
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if got := r.Header.Get(quotaProjectHeaderKey); got != testQuota {
t.Errorf("got %q, want %q", got, testQuota)
}
}))
defer ts.Close()

h := make(http.Header)
h.Set(quotaProjectHeaderKey, testQuota)
client, err := NewClient(&Options{
InternalOptions: &InternalOptions{
DefaultEndpointTemplate: ts.URL,
},
DetectOpts: &credentials.DetectOptions{
Audience: ts.URL,
CredentialsFile: "../internal/testdata/sa.json",
UseSelfSignedJWT: true,
},
Headers: h,
})
if err != nil {
t.Fatalf("NewClient() = %v", err)
}
if _, err := client.Get(ts.URL); err != nil {
t.Fatalf("client.Get() = %v", err)
}
}

func TestNewClient_BaseRoundTripper(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
got := r.Header.Get("Foo")
Expand Down
7 changes: 5 additions & 2 deletions auth/httptransport/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
)

const (
quotaProjectHeaderKey = "X-Goog-User-Project"
quotaProjectHeaderKey = "X-goog-user-project"
)

func newTransport(base http.RoundTripper, opts *Options) (http.RoundTripper, error) {
Expand Down Expand Up @@ -76,7 +76,10 @@ func newTransport(base http.RoundTripper, opts *Options) (http.RoundTripper, err
if headers == nil {
headers = make(map[string][]string, 1)
}
headers.Set(quotaProjectHeaderKey, qp)
// Don't overwrite user specified quota
if v := headers.Get(quotaProjectHeaderKey); v == "" {
headers.Set(quotaProjectHeaderKey, qp)
}
}
creds.TokenProvider = auth.NewCachedTokenProvider(creds.TokenProvider, nil)
trans = &authTransport{
Expand Down

0 comments on commit d83e3b0

Please sign in to comment.