Commit cab923dd authored by Quentin Smith's avatar Quentin Smith

storage/appengine: support service account OAuth

Change-Id: I8c284c7d8f1a567c740bfe78c2b8f1ee5e662e72
Reviewed-on: https://go-review.googlesource.com/38395Reviewed-by: default avatarChris Broadfoot <cbro@golang.org>
Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent e40c7081
...@@ -8,10 +8,12 @@ ...@@ -8,10 +8,12 @@
package appengine package appengine
import ( import (
"errors"
"fmt" "fmt"
"log" "log"
"net/http" "net/http"
"os" "os"
"strings"
"time" "time"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
...@@ -19,8 +21,10 @@ import ( ...@@ -19,8 +21,10 @@ import (
"golang.org/x/perf/storage/app" "golang.org/x/perf/storage/app"
"golang.org/x/perf/storage/db" "golang.org/x/perf/storage/db"
"golang.org/x/perf/storage/fs/gcs" "golang.org/x/perf/storage/fs/gcs"
oauth2 "google.golang.org/api/oauth2/v2"
"google.golang.org/appengine" "google.golang.org/appengine"
aelog "google.golang.org/appengine/log" aelog "google.golang.org/appengine/log"
"google.golang.org/appengine/urlfetch"
"google.golang.org/appengine/user" "google.golang.org/appengine/user"
) )
...@@ -46,15 +50,11 @@ func mustGetenv(k string) string { ...@@ -46,15 +50,11 @@ func mustGetenv(k string) string {
func auth(w http.ResponseWriter, r *http.Request) (string, error) { func auth(w http.ResponseWriter, r *http.Request) (string, error) {
ctx := appengine.NewContext(r) ctx := appengine.NewContext(r)
u := user.Current(ctx) u, err := reqUser(ctx, r)
if u == nil && r.Header.Get("Authorization") != "" {
var err error
u, err = user.CurrentOAuth(ctx, "https://www.googleapis.com/auth/userinfo.email")
if err != nil { if err != nil {
return "", err return "", err
} }
} if u == "" {
if u == nil {
url, err := user.LoginURL(ctx, r.URL.String()) url, err := user.LoginURL(ctx, r.URL.String())
if err != nil { if err != nil {
return "", err return "", err
...@@ -62,7 +62,50 @@ func auth(w http.ResponseWriter, r *http.Request) (string, error) { ...@@ -62,7 +62,50 @@ func auth(w http.ResponseWriter, r *http.Request) (string, error) {
http.Redirect(w, r, url, http.StatusFound) http.Redirect(w, r, url, http.StatusFound)
return "", app.ErrResponseWritten return "", app.ErrResponseWritten
} }
return u, nil
}
// reqUser gets the username from the request, trying AE user authentication, AE OAuth authentication, and Google OAuth authentication, in that order.
// If the request contains no authentication, "", nil is returned.
// If the request contains bogus authentication, an error is returned.
func reqUser(ctx context.Context, r *http.Request) (string, error) {
u := user.Current(ctx)
if u != nil {
return u.Email, nil return u.Email, nil
}
if r.Header.Get("Authorization") == "" {
return "", nil
}
u, err := user.CurrentOAuth(ctx, "https://www.googleapis.com/auth/userinfo.email")
if err == nil {
return u.Email, nil
}
return oauthServiceUser(ctx, r)
}
// oauthServiceUser authenticates the OAuth token from r's headers.
// This is necessary because user.CurrentOAuth does not work if the token is for a service account.
func oauthServiceUser(ctx context.Context, r *http.Request) (string, error) {
tok := r.Header.Get("Authorization")
if !strings.HasPrefix(tok, "Bearer ") {
return "", errors.New("unknown Authorization header")
}
tok = tok[len("Bearer "):]
hc := urlfetch.Client(ctx)
service, err := oauth2.New(hc)
if err != nil {
return "", err
}
info, err := service.Tokeninfo().AccessToken(tok).Do()
if err != nil {
return "", err
}
if !info.VerifiedEmail || info.Email == "" {
return "", errors.New("token does not contain verified e-mail address")
}
return info.Email, nil
} }
// appHandler is the default handler, registered to serve "/". // appHandler is the default handler, registered to serve "/".
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment