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

oauth: Allow access to Google API regional endpoints via Google Default Credentials #4713

Merged
merged 4 commits into from Sep 7, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
8 changes: 7 additions & 1 deletion credentials/oauth/oauth.go
Expand Up @@ -29,6 +29,8 @@ import (
"golang.org/x/oauth2/google"
"golang.org/x/oauth2/jwt"
"google.golang.org/grpc/credentials"

credinternal "google.golang.org/grpc/internal/credentials"
)

// TokenSource supplies PerRPCCredentials from an oauth2.TokenSource.
Expand Down Expand Up @@ -75,9 +77,13 @@ func NewJWTAccessFromKey(jsonKey []byte) (credentials.PerRPCCredentials, error)
}

func (j jwtAccess) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
aud, err := credinternal.RemoveServiceNameFromJwtURI(uri[0])
if err != nil {
return nil, err
}
// TODO: the returned TokenSource is reusable. Store it in a sync.Map, with
// uri as the key, to avoid recreating for every RPC.
ts, err := google.JWTAccessTokenSourceFromJSON(j.jsonKey, uri[0])
ts, err := google.JWTAccessTokenSourceFromJSON(j.jsonKey, aud)
if err != nil {
return nil, err
}
Expand Down
16 changes: 15 additions & 1 deletion internal/credentials/util.go
Expand Up @@ -18,7 +18,10 @@

package credentials

import "crypto/tls"
import (
"crypto/tls"
"net/url"
)

const alpnProtoStrH2 = "h2"

Expand Down Expand Up @@ -48,3 +51,14 @@ func CloneTLSConfig(cfg *tls.Config) *tls.Config {

return cfg.Clone()
}

// RemoveServiceNameFromJwtURI removes RPC service name
dfawley marked this conversation as resolved.
Show resolved Hide resolved
// from URI that will be used as audience in a self-signed
// JWT token. It follows https://google.aip.dev/auth/4111.
func RemoveServiceNameFromJwtURI(uri string) (string, error) {
dfawley marked this conversation as resolved.
Show resolved Hide resolved
parsed, err := url.Parse(uri)
if err != nil {
return "", err
}
return parsed.Scheme + "://" + parsed.Host + "/", nil
dfawley marked this conversation as resolved.
Show resolved Hide resolved
}
26 changes: 26 additions & 0 deletions internal/credentials/util_test.go
Expand Up @@ -58,3 +58,29 @@ func (s) TestAppendH2ToNextProtos(t *testing.T) {
})
}
}

func (s) TestRemoveServiceNameFromJwtURI(t *testing.T) {
tests := []struct {
name string
uri string
want string
}{
{
name: "invalid URI",
dfawley marked this conversation as resolved.
Show resolved Hide resolved
uri: "ht tp://foo.com",
want: "",
},
{
name: "valid URI",
uri: "https://foo.com/go/",
want: "https://foo.com/",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got, _ := RemoveServiceNameFromJwtURI(tt.uri); got != tt.want {
t.Errorf("RemoveServiceNameFromJwtURI() = %v, want %v", got, tt.want)
}
})
}
}