mirror of
https://github.com/golang/oauth2.git
synced 2025-07-21 00:00:09 +08:00
google: refactor JWT parsing code internally
The ADC code and the JWT-parsing function operate on the same data format, but were using separate code paths, each of which was missing things from the other. While this presents no change in API surface, JWTConfigFromJSON now strictly checks the "type" field in the JSON file before building a config. Change-Id: I2f593a16bf4591059fbf9002bccea06e41e5e161 Reviewed-on: https://go-review.googlesource.com/32678 Reviewed-by: Jaana Burcu Dogan <jbd@google.com>
This commit is contained in:
parent
36bc61733f
commit
d5040cddfc
@ -6,7 +6,6 @@ package google
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@ -17,7 +16,6 @@ import (
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/jwt"
|
||||
)
|
||||
|
||||
// DefaultClient returns an HTTP Client that uses the
|
||||
@ -112,44 +110,9 @@ func tokenSourceFromFile(ctx context.Context, filename string, scopes []string)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var d struct {
|
||||
// Common fields
|
||||
Type string
|
||||
ClientID string `json:"client_id"`
|
||||
|
||||
// User Credential fields
|
||||
ClientSecret string `json:"client_secret"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
|
||||
// Service Account fields
|
||||
ClientEmail string `json:"client_email"`
|
||||
PrivateKeyID string `json:"private_key_id"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &d); err != nil {
|
||||
var f credentialsFile
|
||||
if err := json.Unmarshal(b, &f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch d.Type {
|
||||
case "authorized_user":
|
||||
cfg := &oauth2.Config{
|
||||
ClientID: d.ClientID,
|
||||
ClientSecret: d.ClientSecret,
|
||||
Scopes: append([]string{}, scopes...), // copy
|
||||
Endpoint: Endpoint,
|
||||
}
|
||||
tok := &oauth2.Token{RefreshToken: d.RefreshToken}
|
||||
return cfg.TokenSource(ctx, tok), nil
|
||||
case "service_account":
|
||||
cfg := &jwt.Config{
|
||||
Email: d.ClientEmail,
|
||||
PrivateKey: []byte(d.PrivateKey),
|
||||
Scopes: append([]string{}, scopes...), // copy
|
||||
TokenURL: JWTTokenURL,
|
||||
}
|
||||
return cfg.TokenSource(ctx), nil
|
||||
case "":
|
||||
return nil, errors.New("missing 'type' field in credentials")
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown credential type: %q", d.Type)
|
||||
}
|
||||
return f.tokenSource(ctx, scopes)
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/jwt"
|
||||
)
|
||||
@ -85,26 +86,73 @@ func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
|
||||
// Create a service account on "Credentials" for your project at
|
||||
// https://console.developers.google.com to download a JSON key file.
|
||||
func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) {
|
||||
var key struct {
|
||||
Email string `json:"client_email"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
PrivateKeyID string `json:"private_key_id"`
|
||||
TokenURL string `json:"token_uri"`
|
||||
}
|
||||
if err := json.Unmarshal(jsonKey, &key); err != nil {
|
||||
var f credentialsFile
|
||||
if err := json.Unmarshal(jsonKey, &f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config := &jwt.Config{
|
||||
Email: key.Email,
|
||||
PrivateKey: []byte(key.PrivateKey),
|
||||
PrivateKeyID: key.PrivateKeyID,
|
||||
Scopes: scope,
|
||||
TokenURL: key.TokenURL,
|
||||
if f.Type != serviceAccountKey {
|
||||
return nil, fmt.Errorf("google: read JWT from JSON credentials: 'type' field is %q (expected %q)", f.Type, serviceAccountKey)
|
||||
}
|
||||
if config.TokenURL == "" {
|
||||
config.TokenURL = JWTTokenURL
|
||||
scope = append([]string(nil), scope...) // copy
|
||||
return f.jwtConfig(scope), nil
|
||||
}
|
||||
|
||||
// JSON key file types.
|
||||
const (
|
||||
serviceAccountKey = "service_account"
|
||||
userCredentialsKey = "authorized_user"
|
||||
)
|
||||
|
||||
// credentialsFile is the unmarshalled representation of a credentials file.
|
||||
type credentialsFile struct {
|
||||
Type string `json:"type"` // serviceAccountKey or userCredentialsKey
|
||||
|
||||
// Service Account fields
|
||||
ClientEmail string `json:"client_email"`
|
||||
PrivateKeyID string `json:"private_key_id"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
TokenURL string `json:"token_uri"`
|
||||
|
||||
// User Credential fields
|
||||
// (These typically come from gcloud auth.)
|
||||
ClientSecret string `json:"client_secret"`
|
||||
ClientID string `json:"client_id"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
}
|
||||
|
||||
func (f *credentialsFile) jwtConfig(scopes []string) *jwt.Config {
|
||||
cfg := &jwt.Config{
|
||||
Email: f.ClientEmail,
|
||||
PrivateKey: []byte(f.PrivateKey),
|
||||
PrivateKeyID: f.PrivateKeyID,
|
||||
Scopes: scopes,
|
||||
TokenURL: f.TokenURL,
|
||||
}
|
||||
if cfg.TokenURL == "" {
|
||||
cfg.TokenURL = JWTTokenURL
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
func (f *credentialsFile) tokenSource(ctx context.Context, scopes []string) (oauth2.TokenSource, error) {
|
||||
switch f.Type {
|
||||
case serviceAccountKey:
|
||||
cfg := f.jwtConfig(scopes)
|
||||
return cfg.TokenSource(ctx), nil
|
||||
case userCredentialsKey:
|
||||
cfg := &oauth2.Config{
|
||||
ClientID: f.ClientID,
|
||||
ClientSecret: f.ClientSecret,
|
||||
Scopes: scopes,
|
||||
Endpoint: Endpoint,
|
||||
}
|
||||
tok := &oauth2.Token{RefreshToken: f.RefreshToken}
|
||||
return cfg.TokenSource(ctx, tok), nil
|
||||
case "":
|
||||
return nil, errors.New("missing 'type' field in credentials")
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown credential type: %q", f.Type)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// ComputeTokenSource returns a token source that fetches access tokens
|
||||
|
Loading…
x
Reference in New Issue
Block a user