Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(784)

Side by Side Diff: impl/prod/devserver.go

Issue 2220193002: Implement info.ServiceAccount() on devserver via info.AccessToken(...). (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/gae@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | impl/prod/info.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package prod
6
7 import (
8 "encoding/json"
9 "fmt"
10 "io/ioutil"
11 "net/http"
12 "net/url"
13 "sync"
14
15 "golang.org/x/net/context"
16
17 "google.golang.org/appengine"
18 "google.golang.org/appengine/log"
19 "google.golang.org/appengine/urlfetch"
20 )
21
22 var devAccountCache struct {
23 once sync.Once
24 account string
25 err error
26 }
27
28 // developerAccount is used on dev server to get account name matching
29 // the OAuth token produced by AccessToken.
30 //
31 // On dev server ServiceAccount returns empty string, but AccessToken(...) works
32 // and returns developer's token (the one configured with "gcloud auth"). We can
33 // use it to get the matching account name.
34 func developerAccount(gaeCtx context.Context) (string, error) {
35 if !appengine.IsDevAppServer() {
36 panic("developerAccount must not be used outside of devserver")
37 }
38 devAccountCache.once.Do(func() {
39 devAccountCache.account, devAccountCache.err = fetchDevAccount(g aeCtx)
40 if devAccountCache.err == nil {
41 log.Debugf(gaeCtx, "Devserver is running as %q", devAcco untCache.account)
42 } else {
43 log.Errorf(gaeCtx, "Failed to fetch account name associa ted with AccessToken - %s", devAccountCache.err)
44 }
45 })
46 return devAccountCache.account, devAccountCache.err
47 }
48
49 // fetchDevAccount grabs an access token and calls Google API to get associated
50 // email.
51 func fetchDevAccount(gaeCtx context.Context) (string, error) {
52 // Grab the developer's token from devserver.
53 tok, _, err := appengine.AccessToken(gaeCtx, "https://www.googleapis.com /auth/userinfo.email")
54 if err != nil {
55 return "", err
56 }
57
58 // Fetch the info dict associated with the token.
59 client := http.Client{
60 Transport: &urlfetch.Transport{Context: gaeCtx},
61 }
62 resp, err := client.Get("https://www.googleapis.com/oauth2/v3/tokeninfo? access_token=" + url.QueryEscape(tok))
63 if err != nil {
64 return "", err
65 }
66 defer func() {
67 ioutil.ReadAll(resp.Body)
68 resp.Body.Close()
69 }()
70 if resp.StatusCode >= 500 {
71 return "", fmt.Errorf("devserver: transient error when validatin g token (HTTP %d)", resp.StatusCode)
72 }
73
74 // There's more stuff in the reply, we don't need it.
75 var tokenInfo struct {
76 Email string `json:"email"`
77 Error string `json:"error_description"`
78 }
79 if err := json.NewDecoder(resp.Body).Decode(&tokenInfo); err != nil {
80 return "", fmt.Errorf("devserver: failed to deserialize token in fo JSON - %s", err)
81 }
82 switch {
83 case tokenInfo.Error != "":
84 return "", fmt.Errorf("devserver: bad token - %s", tokenInfo.Err or)
85 case tokenInfo.Email == "":
86 return "", fmt.Errorf("devserver: token is not associated with a n email")
87 }
88 return tokenInfo.Email, nil
89 }
OLDNEW
« no previous file with comments | « no previous file | impl/prod/info.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698