mirror of https://github.com/grpc/grpc-go.git
179 lines
5.9 KiB
Go
179 lines
5.9 KiB
Go
/*
|
|
*
|
|
* Copyright 2018 gRPC authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
// Package google defines credentials for google cloud services.
|
|
package google
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"google.golang.org/grpc/credentials"
|
|
"google.golang.org/grpc/credentials/alts"
|
|
"google.golang.org/grpc/credentials/oauth"
|
|
"google.golang.org/grpc/grpclog"
|
|
"google.golang.org/grpc/internal"
|
|
)
|
|
|
|
const defaultCloudPlatformScope = "https://www.googleapis.com/auth/cloud-platform"
|
|
|
|
var logger = grpclog.Component("credentials")
|
|
|
|
// DefaultCredentialsOptions constructs options to build DefaultCredentials.
|
|
type DefaultCredentialsOptions struct {
|
|
// PerRPCCreds is a per RPC credentials that is passed to a bundle.
|
|
PerRPCCreds credentials.PerRPCCredentials
|
|
// ALTSPerRPCCreds is a per RPC credentials that, if specified, will
|
|
// supercede PerRPCCreds above for and only for ALTS connections.
|
|
ALTSPerRPCCreds credentials.PerRPCCredentials
|
|
}
|
|
|
|
// NewDefaultCredentialsWithOptions returns a credentials bundle that is
|
|
// configured to work with google services.
|
|
//
|
|
// This API is experimental.
|
|
func NewDefaultCredentialsWithOptions(opts DefaultCredentialsOptions) credentials.Bundle {
|
|
if opts.PerRPCCreds == nil {
|
|
var err error
|
|
// If the ADC ends up being Compute Engine Credentials, this context
|
|
// won't be used. Otherwise, the context dictates all the subsequent
|
|
// token requests via HTTP. So we cannot have any deadline or timeout.
|
|
opts.PerRPCCreds, err = newADC(context.TODO())
|
|
if err != nil {
|
|
logger.Warningf("NewDefaultCredentialsWithOptions: failed to create application oauth: %v", err)
|
|
}
|
|
}
|
|
if opts.ALTSPerRPCCreds != nil {
|
|
opts.PerRPCCreds = &dualPerRPCCreds{
|
|
perRPCCreds: opts.PerRPCCreds,
|
|
altsPerRPCCreds: opts.ALTSPerRPCCreds,
|
|
}
|
|
}
|
|
c := &creds{opts: opts}
|
|
bundle, err := c.NewWithMode(internal.CredsBundleModeFallback)
|
|
if err != nil {
|
|
logger.Warningf("NewDefaultCredentialsWithOptions: failed to create new creds: %v", err)
|
|
}
|
|
return bundle
|
|
}
|
|
|
|
// NewDefaultCredentials returns a credentials bundle that is configured to work
|
|
// with google services.
|
|
//
|
|
// This API is experimental.
|
|
func NewDefaultCredentials() credentials.Bundle {
|
|
return NewDefaultCredentialsWithOptions(DefaultCredentialsOptions{})
|
|
}
|
|
|
|
// NewComputeEngineCredentials returns a credentials bundle that is configured to work
|
|
// with google services. This API must only be used when running on GCE. Authentication configured
|
|
// by this API represents the GCE VM's default service account.
|
|
//
|
|
// This API is experimental.
|
|
func NewComputeEngineCredentials() credentials.Bundle {
|
|
return NewDefaultCredentialsWithOptions(DefaultCredentialsOptions{
|
|
PerRPCCreds: oauth.NewComputeEngine(),
|
|
})
|
|
}
|
|
|
|
// creds implements credentials.Bundle.
|
|
type creds struct {
|
|
opts DefaultCredentialsOptions
|
|
|
|
// Supported modes are defined in internal/internal.go.
|
|
mode string
|
|
// The active transport credentials associated with this bundle.
|
|
transportCreds credentials.TransportCredentials
|
|
// The active per RPC credentials associated with this bundle.
|
|
perRPCCreds credentials.PerRPCCredentials
|
|
}
|
|
|
|
func (c *creds) TransportCredentials() credentials.TransportCredentials {
|
|
return c.transportCreds
|
|
}
|
|
|
|
func (c *creds) PerRPCCredentials() credentials.PerRPCCredentials {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
return c.perRPCCreds
|
|
}
|
|
|
|
var (
|
|
newTLS = func() credentials.TransportCredentials {
|
|
return credentials.NewTLS(nil)
|
|
}
|
|
newALTS = func() credentials.TransportCredentials {
|
|
return alts.NewClientCreds(alts.DefaultClientOptions())
|
|
}
|
|
newADC = func(ctx context.Context) (credentials.PerRPCCredentials, error) {
|
|
return oauth.NewApplicationDefault(ctx, defaultCloudPlatformScope)
|
|
}
|
|
)
|
|
|
|
// NewWithMode should make a copy of Bundle, and switch mode. Modifying the
|
|
// existing Bundle may cause races.
|
|
func (c *creds) NewWithMode(mode string) (credentials.Bundle, error) {
|
|
newCreds := &creds{
|
|
opts: c.opts,
|
|
mode: mode,
|
|
}
|
|
|
|
// Create transport credentials.
|
|
switch mode {
|
|
case internal.CredsBundleModeFallback:
|
|
newCreds.transportCreds = newClusterTransportCreds(newTLS(), newALTS())
|
|
case internal.CredsBundleModeBackendFromBalancer, internal.CredsBundleModeBalancer:
|
|
// Only the clients can use google default credentials, so we only need
|
|
// to create new ALTS client creds here.
|
|
newCreds.transportCreds = newALTS()
|
|
default:
|
|
return nil, fmt.Errorf("unsupported mode: %v", mode)
|
|
}
|
|
|
|
if mode == internal.CredsBundleModeFallback || mode == internal.CredsBundleModeBackendFromBalancer {
|
|
newCreds.perRPCCreds = newCreds.opts.PerRPCCreds
|
|
}
|
|
|
|
return newCreds, nil
|
|
}
|
|
|
|
// dualPerRPCCreds implements credentials.PerRPCCredentials by embedding the
|
|
// fallback PerRPCCredentials and the ALTS one. It pickes one of them based on
|
|
// the channel type.
|
|
type dualPerRPCCreds struct {
|
|
perRPCCreds credentials.PerRPCCredentials
|
|
altsPerRPCCreds credentials.PerRPCCredentials
|
|
}
|
|
|
|
func (d *dualPerRPCCreds) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
|
ri, ok := credentials.RequestInfoFromContext(ctx)
|
|
if !ok {
|
|
return nil, fmt.Errorf("request info not found from context")
|
|
}
|
|
if authType := ri.AuthInfo.AuthType(); authType == "alts" {
|
|
return d.altsPerRPCCreds.GetRequestMetadata(ctx, uri...)
|
|
}
|
|
// This ensures backward compatibility even if authType is not "tls".
|
|
return d.perRPCCreds.GetRequestMetadata(ctx, uri...)
|
|
}
|
|
|
|
func (d *dualPerRPCCreds) RequireTransportSecurity() bool {
|
|
return d.altsPerRPCCreds.RequireTransportSecurity() || d.perRPCCreds.RequireTransportSecurity()
|
|
}
|