google: Add support for CredentialsParams, Client ID json, and JWT Subject

*Add support for Google Developers Console client_credentials.json as a TokenSource.
*Add support for JWT Subject (for domain-wide delegation when using service account as credentials source.)
*Add support for non-default AuthURL and TokenURL for authorized user credentials source.

To support this change, two new exported functions FindDefaultCredentialsWithParams and CredentialsFromJSONWithParams are introduced.

Change-Id: Ib467822e2c14e02f8ae68586665c439960cfbd5c
GitHub-Last-Rev: eb92ab4a212ad9ca72837d6e89e3c5f7e106a51c
GitHub-Pull-Request: golang/oauth2#490
Reviewed-on: https://go-review.googlesource.com/c/oauth2/+/311589
Reviewed-by: Shin Fan <shinfan@google.com>
Reviewed-by: Cody Oss <codyoss@google.com>
Trust: Shin Fan <shinfan@google.com>
Trust: Cody Oss <codyoss@google.com>
This commit is contained in:
Andy Zhao
2021-04-27 15:31:33 +00:00
committed by Shin Fan
parent 5e61552d6c
commit 81ed05c6b5
2 changed files with 94 additions and 25 deletions

View File

@@ -19,7 +19,7 @@ import (
"golang.org/x/oauth2/jwt"
)
// Endpoint is Google's OAuth 2.0 endpoint.
// Endpoint is Google's OAuth 2.0 default endpoint.
var Endpoint = oauth2.Endpoint{
AuthURL: "https://accounts.google.com/o/oauth2/auth",
TokenURL: "https://oauth2.googleapis.com/token",
@@ -87,7 +87,7 @@ func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) {
return nil, fmt.Errorf("google: read JWT from JSON credentials: 'type' field is %q (expected %q)", f.Type, serviceAccountKey)
}
scope = append([]string(nil), scope...) // copy
return f.jwtConfig(scope), nil
return f.jwtConfig(scope, ""), nil
}
// JSON key file types.
@@ -99,12 +99,13 @@ const (
// credentialsFile is the unmarshalled representation of a credentials file.
type credentialsFile struct {
Type string `json:"type"` // serviceAccountKey or userCredentialsKey
Type string `json:"type"`
// Service Account fields
ClientEmail string `json:"client_email"`
PrivateKeyID string `json:"private_key_id"`
PrivateKey string `json:"private_key"`
AuthURL string `json:"auth_uri"`
TokenURL string `json:"token_uri"`
ProjectID string `json:"project_id"`
@@ -124,13 +125,14 @@ type credentialsFile struct {
QuotaProjectID string `json:"quota_project_id"`
}
func (f *credentialsFile) jwtConfig(scopes []string) *jwt.Config {
func (f *credentialsFile) jwtConfig(scopes []string, subject string) *jwt.Config {
cfg := &jwt.Config{
Email: f.ClientEmail,
PrivateKey: []byte(f.PrivateKey),
PrivateKeyID: f.PrivateKeyID,
Scopes: scopes,
TokenURL: f.TokenURL,
Subject: subject, // This is the user email to impersonate
}
if cfg.TokenURL == "" {
cfg.TokenURL = JWTTokenURL
@@ -138,17 +140,27 @@ func (f *credentialsFile) jwtConfig(scopes []string) *jwt.Config {
return cfg
}
func (f *credentialsFile) tokenSource(ctx context.Context, scopes []string) (oauth2.TokenSource, error) {
func (f *credentialsFile) tokenSource(ctx context.Context, params CredentialsParams) (oauth2.TokenSource, error) {
switch f.Type {
case serviceAccountKey:
cfg := f.jwtConfig(scopes)
cfg := f.jwtConfig(params.Scopes, params.Subject)
return cfg.TokenSource(ctx), nil
case userCredentialsKey:
cfg := &oauth2.Config{
ClientID: f.ClientID,
ClientSecret: f.ClientSecret,
Scopes: scopes,
Endpoint: Endpoint,
Scopes: params.Scopes,
Endpoint: oauth2.Endpoint{
AuthURL: f.AuthURL,
TokenURL: f.TokenURL,
AuthStyle: oauth2.AuthStyleInParams,
},
}
if cfg.Endpoint.AuthURL == "" {
cfg.Endpoint.AuthURL = Endpoint.AuthURL
}
if cfg.Endpoint.TokenURL == "" {
cfg.Endpoint.TokenURL = Endpoint.TokenURL
}
tok := &oauth2.Token{RefreshToken: f.RefreshToken}
return cfg.TokenSource(ctx, tok), nil
@@ -163,7 +175,7 @@ func (f *credentialsFile) tokenSource(ctx context.Context, scopes []string) (oau
ClientID: f.ClientID,
CredentialSource: f.CredentialSource,
QuotaProjectID: f.QuotaProjectID,
Scopes: scopes,
Scopes: params.Scopes,
}
return cfg.TokenSource(ctx), nil
case "":