]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/golang.org/x/oauth2/google/google.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / golang.org / x / oauth2 / google / google.go
1 // Copyright 2014 The Go 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 "context"
9 "encoding/json"
10 "errors"
11 "fmt"
12 "strings"
13 "time"
14
15 "cloud.google.com/go/compute/metadata"
16 "golang.org/x/oauth2"
17 "golang.org/x/oauth2/jwt"
18 )
19
20 // Endpoint is Google's OAuth 2.0 endpoint.
21 var Endpoint = oauth2.Endpoint{
22 AuthURL: "https://accounts.google.com/o/oauth2/auth",
23 TokenURL: "https://accounts.google.com/o/oauth2/token",
24 AuthStyle: oauth2.AuthStyleInParams,
25 }
26
27 // JWTTokenURL is Google's OAuth 2.0 token URL to use with the JWT flow.
28 const JWTTokenURL = "https://accounts.google.com/o/oauth2/token"
29
30 // ConfigFromJSON uses a Google Developers Console client_credentials.json
31 // file to construct a config.
32 // client_credentials.json can be downloaded from
33 // https://console.developers.google.com, under "Credentials". Download the Web
34 // application credentials in the JSON format and provide the contents of the
35 // file as jsonKey.
36 func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
37 type cred struct {
38 ClientID string `json:"client_id"`
39 ClientSecret string `json:"client_secret"`
40 RedirectURIs []string `json:"redirect_uris"`
41 AuthURI string `json:"auth_uri"`
42 TokenURI string `json:"token_uri"`
43 }
44 var j struct {
45 Web *cred `json:"web"`
46 Installed *cred `json:"installed"`
47 }
48 if err := json.Unmarshal(jsonKey, &j); err != nil {
49 return nil, err
50 }
51 var c *cred
52 switch {
53 case j.Web != nil:
54 c = j.Web
55 case j.Installed != nil:
56 c = j.Installed
57 default:
58 return nil, fmt.Errorf("oauth2/google: no credentials found")
59 }
60 if len(c.RedirectURIs) < 1 {
61 return nil, errors.New("oauth2/google: missing redirect URL in the client_credentials.json")
62 }
63 return &oauth2.Config{
64 ClientID: c.ClientID,
65 ClientSecret: c.ClientSecret,
66 RedirectURL: c.RedirectURIs[0],
67 Scopes: scope,
68 Endpoint: oauth2.Endpoint{
69 AuthURL: c.AuthURI,
70 TokenURL: c.TokenURI,
71 },
72 }, nil
73 }
74
75 // JWTConfigFromJSON uses a Google Developers service account JSON key file to read
76 // the credentials that authorize and authenticate the requests.
77 // Create a service account on "Credentials" for your project at
78 // https://console.developers.google.com to download a JSON key file.
79 func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) {
80 var f credentialsFile
81 if err := json.Unmarshal(jsonKey, &f); err != nil {
82 return nil, err
83 }
84 if f.Type != serviceAccountKey {
85 return nil, fmt.Errorf("google: read JWT from JSON credentials: 'type' field is %q (expected %q)", f.Type, serviceAccountKey)
86 }
87 scope = append([]string(nil), scope...) // copy
88 return f.jwtConfig(scope), nil
89 }
90
91 // JSON key file types.
92 const (
93 serviceAccountKey = "service_account"
94 userCredentialsKey = "authorized_user"
95 )
96
97 // credentialsFile is the unmarshalled representation of a credentials file.
98 type credentialsFile struct {
99 Type string `json:"type"` // serviceAccountKey or userCredentialsKey
100
101 // Service Account fields
102 ClientEmail string `json:"client_email"`
103 PrivateKeyID string `json:"private_key_id"`
104 PrivateKey string `json:"private_key"`
105 TokenURL string `json:"token_uri"`
106 ProjectID string `json:"project_id"`
107
108 // User Credential fields
109 // (These typically come from gcloud auth.)
110 ClientSecret string `json:"client_secret"`
111 ClientID string `json:"client_id"`
112 RefreshToken string `json:"refresh_token"`
113 }
114
115 func (f *credentialsFile) jwtConfig(scopes []string) *jwt.Config {
116 cfg := &jwt.Config{
117 Email: f.ClientEmail,
118 PrivateKey: []byte(f.PrivateKey),
119 PrivateKeyID: f.PrivateKeyID,
120 Scopes: scopes,
121 TokenURL: f.TokenURL,
122 }
123 if cfg.TokenURL == "" {
124 cfg.TokenURL = JWTTokenURL
125 }
126 return cfg
127 }
128
129 func (f *credentialsFile) tokenSource(ctx context.Context, scopes []string) (oauth2.TokenSource, error) {
130 switch f.Type {
131 case serviceAccountKey:
132 cfg := f.jwtConfig(scopes)
133 return cfg.TokenSource(ctx), nil
134 case userCredentialsKey:
135 cfg := &oauth2.Config{
136 ClientID: f.ClientID,
137 ClientSecret: f.ClientSecret,
138 Scopes: scopes,
139 Endpoint: Endpoint,
140 }
141 tok := &oauth2.Token{RefreshToken: f.RefreshToken}
142 return cfg.TokenSource(ctx, tok), nil
143 case "":
144 return nil, errors.New("missing 'type' field in credentials")
145 default:
146 return nil, fmt.Errorf("unknown credential type: %q", f.Type)
147 }
148 }
149
150 // ComputeTokenSource returns a token source that fetches access tokens
151 // from Google Compute Engine (GCE)'s metadata server. It's only valid to use
152 // this token source if your program is running on a GCE instance.
153 // If no account is specified, "default" is used.
154 // Further information about retrieving access tokens from the GCE metadata
155 // server can be found at https://cloud.google.com/compute/docs/authentication.
156 func ComputeTokenSource(account string) oauth2.TokenSource {
157 return oauth2.ReuseTokenSource(nil, computeSource{account: account})
158 }
159
160 type computeSource struct {
161 account string
162 }
163
164 func (cs computeSource) Token() (*oauth2.Token, error) {
165 if !metadata.OnGCE() {
166 return nil, errors.New("oauth2/google: can't get a token from the metadata service; not running on GCE")
167 }
168 acct := cs.account
169 if acct == "" {
170 acct = "default"
171 }
172 tokenJSON, err := metadata.Get("instance/service-accounts/" + acct + "/token")
173 if err != nil {
174 return nil, err
175 }
176 var res struct {
177 AccessToken string `json:"access_token"`
178 ExpiresInSec int `json:"expires_in"`
179 TokenType string `json:"token_type"`
180 }
181 err = json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&res)
182 if err != nil {
183 return nil, fmt.Errorf("oauth2/google: invalid token JSON from metadata: %v", err)
184 }
185 if res.ExpiresInSec == 0 || res.AccessToken == "" {
186 return nil, fmt.Errorf("oauth2/google: incomplete token received from metadata")
187 }
188 return &oauth2.Token{
189 AccessToken: res.AccessToken,
190 TokenType: res.TokenType,
191 Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second),
192 }, nil
193 }