github.com/aclisp/heapster@v0.19.2-0.20160613100040-51756f899a96/Godeps/_workspace/src/golang.org/x/oauth2/google/default.go (about)

     1  // Copyright 2015 The oauth2 Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package google
     6  
     7  import (
     8  	"encoding/json"
     9  	"errors"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"net/http"
    13  	"os"
    14  	"path/filepath"
    15  	"runtime"
    16  
    17  	"golang.org/x/net/context"
    18  	"golang.org/x/oauth2"
    19  	"golang.org/x/oauth2/jwt"
    20  	"google.golang.org/cloud/compute/metadata"
    21  )
    22  
    23  // DefaultClient returns an HTTP Client that uses the
    24  // DefaultTokenSource to obtain authentication credentials.
    25  //
    26  // This client should be used when developing services
    27  // that run on Google App Engine or Google Compute Engine
    28  // and use "Application Default Credentials."
    29  //
    30  // For more details, see:
    31  // https://developers.google.com/accounts/docs/application-default-credentials
    32  //
    33  func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
    34  	ts, err := DefaultTokenSource(ctx, scope...)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	return oauth2.NewClient(ctx, ts), nil
    39  }
    40  
    41  // DefaultTokenSource is a token source that uses
    42  // "Application Default Credentials".
    43  //
    44  // It looks for credentials in the following places,
    45  // preferring the first location found:
    46  //
    47  //   1. A JSON file whose path is specified by the
    48  //      GOOGLE_APPLICATION_CREDENTIALS environment variable.
    49  //   2. A JSON file in a location known to the gcloud command-line tool.
    50  //      On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
    51  //      On other systems, $HOME/.config/gcloud/application_default_credentials.json.
    52  //   3. On Google App Engine it uses the appengine.AccessToken function.
    53  //   4. On Google Compute Engine, it fetches credentials from the metadata server.
    54  //      (In this final case any provided scopes are ignored.)
    55  //
    56  // For more details, see:
    57  // https://developers.google.com/accounts/docs/application-default-credentials
    58  //
    59  func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) {
    60  	// First, try the environment variable.
    61  	const envVar = "GOOGLE_APPLICATION_CREDENTIALS"
    62  	if filename := os.Getenv(envVar); filename != "" {
    63  		ts, err := tokenSourceFromFile(ctx, filename, scope)
    64  		if err != nil {
    65  			return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err)
    66  		}
    67  		return ts, nil
    68  	}
    69  
    70  	// Second, try a well-known file.
    71  	filename := wellKnownFile()
    72  	_, err := os.Stat(filename)
    73  	if err == nil {
    74  		ts, err2 := tokenSourceFromFile(ctx, filename, scope)
    75  		if err2 == nil {
    76  			return ts, nil
    77  		}
    78  		err = err2
    79  	} else if os.IsNotExist(err) {
    80  		err = nil // ignore this error
    81  	}
    82  	if err != nil {
    83  		return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err)
    84  	}
    85  
    86  	// Third, if we're on Google App Engine use those credentials.
    87  	if appengineTokenFunc != nil {
    88  		return AppEngineTokenSource(ctx, scope...), nil
    89  	}
    90  
    91  	// Fourth, if we're on Google Compute Engine use the metadata server.
    92  	if metadata.OnGCE() {
    93  		return ComputeTokenSource(""), nil
    94  	}
    95  
    96  	// None are found; return helpful error.
    97  	const url = "https://developers.google.com/accounts/docs/application-default-credentials"
    98  	return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url)
    99  }
   100  
   101  func wellKnownFile() string {
   102  	const f = "application_default_credentials.json"
   103  	if runtime.GOOS == "windows" {
   104  		return filepath.Join(os.Getenv("APPDATA"), "gcloud", f)
   105  	}
   106  	return filepath.Join(guessUnixHomeDir(), ".config", "gcloud", f)
   107  }
   108  
   109  func tokenSourceFromFile(ctx context.Context, filename string, scopes []string) (oauth2.TokenSource, error) {
   110  	b, err := ioutil.ReadFile(filename)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  	var d struct {
   115  		// Common fields
   116  		Type     string
   117  		ClientID string `json:"client_id"`
   118  
   119  		// User Credential fields
   120  		ClientSecret string `json:"client_secret"`
   121  		RefreshToken string `json:"refresh_token"`
   122  
   123  		// Service Account fields
   124  		ClientEmail  string `json:"client_email"`
   125  		PrivateKeyID string `json:"private_key_id"`
   126  		PrivateKey   string `json:"private_key"`
   127  	}
   128  	if err := json.Unmarshal(b, &d); err != nil {
   129  		return nil, err
   130  	}
   131  	switch d.Type {
   132  	case "authorized_user":
   133  		cfg := &oauth2.Config{
   134  			ClientID:     d.ClientID,
   135  			ClientSecret: d.ClientSecret,
   136  			Scopes:       append([]string{}, scopes...), // copy
   137  			Endpoint:     Endpoint,
   138  		}
   139  		tok := &oauth2.Token{RefreshToken: d.RefreshToken}
   140  		return cfg.TokenSource(ctx, tok), nil
   141  	case "service_account":
   142  		cfg := &jwt.Config{
   143  			Email:      d.ClientEmail,
   144  			PrivateKey: []byte(d.PrivateKey),
   145  			Scopes:     append([]string{}, scopes...), // copy
   146  			TokenURL:   JWTTokenURL,
   147  		}
   148  		return cfg.TokenSource(ctx), nil
   149  	case "":
   150  		return nil, errors.New("missing 'type' field in credentials")
   151  	default:
   152  		return nil, fmt.Errorf("unknown credential type: %q", d.Type)
   153  	}
   154  }