Commit 48e246c1 authored by Brendan Burns's avatar Brendan Burns

bump(code.google.com/p/goauth2/oauth): cf9c96faa9885b8cf351c2d79d9a929f3eebd4ec

parent 5d2eb7df
// Copyright 2011 The goauth2 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This program makes a call to the specified API, authenticated with OAuth2.
// a list of example APIs can be found at https://code.google.com/oauthplayground/
package main
import (
"flag"
"fmt"
"io"
"log"
"os"
"code.google.com/p/goauth2/oauth"
)
var (
clientId = flag.String("id", "", "Client ID")
clientSecret = flag.String("secret", "", "Client Secret")
scope = flag.String("scope", "https://www.googleapis.com/auth/userinfo.profile", "OAuth scope")
redirectURL = flag.String("redirect_url", "oob", "Redirect URL")
authURL = flag.String("auth_url", "https://accounts.google.com/o/oauth2/auth", "Authentication URL")
tokenURL = flag.String("token_url", "https://accounts.google.com/o/oauth2/token", "Token URL")
requestURL = flag.String("request_url", "https://www.googleapis.com/oauth2/v1/userinfo", "API request")
code = flag.String("code", "", "Authorization Code")
cachefile = flag.String("cache", "cache.json", "Token cache file")
)
const usageMsg = `
To obtain a request token you must specify both -id and -secret.
To obtain Client ID and Secret, see the "OAuth 2 Credentials" section under
the "API Access" tab on this page: https://code.google.com/apis/console/
Once you have completed the OAuth flow, the credentials should be stored inside
the file specified by -cache and you may run without the -id and -secret flags.
`
func main() {
flag.Parse()
// Set up a configuration.
config := &oauth.Config{
ClientId: *clientId,
ClientSecret: *clientSecret,
RedirectURL: *redirectURL,
Scope: *scope,
AuthURL: *authURL,
TokenURL: *tokenURL,
TokenCache: oauth.CacheFile(*cachefile),
}
// Set up a Transport using the config.
transport := &oauth.Transport{Config: config}
// Try to pull the token from the cache; if this fails, we need to get one.
token, err := config.TokenCache.Token()
if err != nil {
if *clientId == "" || *clientSecret == "" {
flag.Usage()
fmt.Fprint(os.Stderr, usageMsg)
os.Exit(2)
}
if *code == "" {
// Get an authorization code from the data provider.
// ("Please ask the user if I can access this resource.")
url := config.AuthCodeURL("")
fmt.Println("Visit this URL to get a code, then run again with -code=YOUR_CODE\n")
fmt.Println(url)
return
}
// Exchange the authorization code for an access token.
// ("Here's the code you gave the user, now give me a token!")
token, err = transport.Exchange(*code)
if err != nil {
log.Fatal("Exchange:", err)
}
// (The Exchange method will automatically cache the token.)
fmt.Printf("Token is cached in %v\n", config.TokenCache)
}
// Make the actual request using the cached token to authenticate.
// ("Here's the token, let me in!")
transport.Token = token
// Make the request.
r, err := transport.Client().Get(*requestURL)
if err != nil {
log.Fatal("Get:", err)
}
defer r.Body.Close()
// Write the response to standard output.
io.Copy(os.Stdout, r.Body)
// Send final carriage return, just to be neat.
fmt.Println()
}
{"web":{"auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","client_email":"XXXXXXXXXXXX@developer.gserviceaccount.com","client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/XXXXXXXXXXXX@developer.gserviceaccount.com","client_id":"XXXXXXXXXXXX.apps.googleusercontent.com","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs"}}
Bag Attributes
friendlyName: privatekey
localKeyID: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Key Attributes: <No Attributes>
-----BEGIN PRIVATE KEY-----
XXXXxyXXXXXXXxxyxxxX9y0XXYXXXXYXXxXyxxXxXxXXXyXXXXx4yx1xy1xyYxxY
1XxYy38YxXxxxyXxyyxx+xxxxyx1Y1xYx7yx2/Y1XyyXYYYxY5YXxX0xY/Y642yX
zYYxYXzXYxY0Y8y9YxyYXxxX40YyXxxXX4XXxx7XxXxxXyXxYYXxXyxX5XY0Yy2X
1YX0XXyy6YXyXx9XxXxyXX9XXYXxXxXXXXXXxYXYY3Y8Yy311XYYY81XyY14Xyyx
xXyx7xxXXXxxxxyyyX4YYYXyYyYXyxX4XYXYyxXYyx9xy23xXYyXyxYxXxx1XXXY
y98yX6yYxyyyX4Xyx1Xy/0yxxYxXxYYx2xx7yYXXXxYXXXxyXyyYYxx5XX2xxyxy
y6Yyyx0XX3YYYyx9YYXXXX7y0yxXXy+90XYz1y2xyx7yXxX+8X0xYxXXYxxyxYYy
YXx8Yy4yX0Xyxxx6yYX92yxy1YYYzyyyyxy55x/yyXXXYYXYXXzXXxYYxyXY8XXX
+y9+yXxX7XxxyYYxxXYxyY623xxXxYX59x5Y6yYyXYY4YxXXYXXXYxXYxXxXXx6x
YXX7XxXX2X0XY7YXyYy1XXxYXxXxYY1xXXxxxyy+07zXYxYxxXyyxxyxXx1XYy5X
5XYzyxYxXXYyX9XX7xX8xXxx+XXYyYXXXX5YY1x8Yxyx54Xy/1XXyyYXY5YxYyxY
XyyxXyX/YxxXXXxXXYXxyxx63xX/xxyYXXyYzx0XY+YxX5xyYyyxxxXXYX/94XXy
Xx63xYxXyXY3/XXxyyXX15XXXyz08XYY5YYXY/YXy/96x68XyyXXxYyXy4xYXx5x
7yxxyxxYxXxyx3y=
-----END PRIVATE KEY-----
// Copyright 2011 The goauth2 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This program makes a read only call to the Google Cloud Storage API,
// authenticated with OAuth2. A list of example APIs can be found at
// https://code.google.com/oauthplayground/
package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
"code.google.com/p/goauth2/oauth/jwt"
)
const scope = "https://www.googleapis.com/auth/devstorage.read_only"
var (
secretsFile = flag.String("s", "", "JSON encoded secrets for the service account")
pemFile = flag.String("k", "", "private pem key file for the service account")
)
const usageMsg = `
You must specify -k and -s.
To obtain client secrets and pem, see the "OAuth 2 Credentials" section under
the "API Access" tab on this page: https://code.google.com/apis/console/
Google Cloud Storage must also be turned on in the API console.
`
func main() {
flag.Parse()
if *secretsFile == "" || *pemFile == "" {
flag.Usage()
fmt.Println(usageMsg)
return
}
// Read the secret file bytes into the config.
secretBytes, err := ioutil.ReadFile(*secretsFile)
if err != nil {
log.Fatal("error reading secerets file:", err)
}
var config struct {
Web struct {
ClientEmail string `json:"client_email"`
ClientID string `json:"client_id"`
TokenURI string `json:"token_uri"`
}
}
err = json.Unmarshal(secretBytes, &config)
if err != nil {
log.Fatal("error unmarshalling secerets:", err)
}
// Get the project ID from the client ID.
projectID := strings.SplitN(config.Web.ClientID, "-", 2)[0]
// Read the pem file bytes for the private key.
keyBytes, err := ioutil.ReadFile(*pemFile)
if err != nil {
log.Fatal("error reading private key file:", err)
}
// Craft the ClaimSet and JWT token.
t := jwt.NewToken(config.Web.ClientEmail, scope, keyBytes)
t.ClaimSet.Aud = config.Web.TokenURI
// We need to provide a client.
c := &http.Client{}
// Get the access token.
o, err := t.Assert(c)
if err != nil {
log.Fatal("assertion error:", err)
}
// Refresh token will be missing, but this access_token will be good
// for one hour.
fmt.Printf("access_token = %v\n", o.AccessToken)
fmt.Printf("refresh_token = %v\n", o.RefreshToken)
fmt.Printf("expires %v\n", o.Expiry)
// Form the request to list Google Cloud Storage buckets.
req, err := http.NewRequest("GET", "https://storage.googleapis.com/", nil)
if err != nil {
log.Fatal("http.NewRequest:", err)
}
req.Header.Set("Authorization", "OAuth "+o.AccessToken)
req.Header.Set("x-goog-api-version", "2")
req.Header.Set("x-goog-project-id", projectID)
// Make the request.
r, err := c.Do(req)
if err != nil {
log.Fatal("API request error:", err)
}
defer r.Body.Close()
// Write the response to standard output.
res, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Fatal("error reading API request results:", err)
}
fmt.Printf("\nRESULT:\n%s\n", res)
}
// Copyright 2011 The goauth2 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package oauth
import (
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path/filepath"
"runtime"
"testing"
"time"
)
var requests = []struct {
path, query, auth string // request
contenttype, body string // response
}{
{
path: "/token",
query: "grant_type=authorization_code&code=c0d3&client_id=cl13nt1d&client_secret=s3cr3t",
contenttype: "application/json",
auth: "Basic Y2wxM250MWQ6czNjcjN0",
body: `
{
"access_token":"token1",
"refresh_token":"refreshtoken1",
"id_token":"idtoken1",
"expires_in":3600
}
`,
},
{path: "/secure", auth: "Bearer token1", body: "first payload"},
{
path: "/token",
query: "grant_type=refresh_token&refresh_token=refreshtoken1&client_id=cl13nt1d&client_secret=s3cr3t",
contenttype: "application/json",
auth: "Basic Y2wxM250MWQ6czNjcjN0",
body: `
{
"access_token":"token2",
"refresh_token":"refreshtoken2",
"id_token":"idtoken2",
"expires_in":3600
}
`,
},
{path: "/secure", auth: "Bearer token2", body: "second payload"},
{
path: "/token",
query: "grant_type=refresh_token&refresh_token=refreshtoken2&client_id=cl13nt1d&client_secret=s3cr3t",
contenttype: "application/x-www-form-urlencoded",
body: "access_token=token3&refresh_token=refreshtoken3&id_token=idtoken3&expires_in=3600",
auth: "Basic Y2wxM250MWQ6czNjcjN0",
},
{path: "/secure", auth: "Bearer token3", body: "third payload"},
}
func TestOAuth(t *testing.T) {
// Set up test server.
n := 0
handler := func(w http.ResponseWriter, r *http.Request) {
if n >= len(requests) {
t.Errorf("too many requests: %d", n)
return
}
req := requests[n]
n++
// Check request.
if g, w := r.URL.Path, req.path; g != w {
t.Errorf("request[%d] got path %s, want %s", n, g, w)
}
want, _ := url.ParseQuery(req.query)
for k := range want {
if g, w := r.FormValue(k), want.Get(k); g != w {
t.Errorf("query[%s] = %s, want %s", k, g, w)
}
}
if g, w := r.Header.Get("Authorization"), req.auth; w != "" && g != w {
t.Errorf("Authorization: %v, want %v", g, w)
}
// Send response.
w.Header().Set("Content-Type", req.contenttype)
io.WriteString(w, req.body)
}
server := httptest.NewServer(http.HandlerFunc(handler))
defer server.Close()
config := &Config{
ClientId: "cl13nt1d",
ClientSecret: "s3cr3t",
Scope: "https://example.net/scope",
AuthURL: server.URL + "/auth",
TokenURL: server.URL + "/token",
}
// TODO(adg): test AuthCodeURL
transport := &Transport{Config: config}
_, err := transport.Exchange("c0d3")
if err != nil {
t.Fatalf("Exchange: %v", err)
}
checkToken(t, transport.Token, "token1", "refreshtoken1", "idtoken1")
c := transport.Client()
resp, err := c.Get(server.URL + "/secure")
if err != nil {
t.Fatalf("Get: %v", err)
}
checkBody(t, resp, "first payload")
// test automatic refresh
transport.Expiry = time.Now().Add(-time.Hour)
resp, err = c.Get(server.URL + "/secure")
if err != nil {
t.Fatalf("Get: %v", err)
}
checkBody(t, resp, "second payload")
checkToken(t, transport.Token, "token2", "refreshtoken2", "idtoken2")
// refresh one more time, but get URL-encoded token instead of JSON
transport.Expiry = time.Now().Add(-time.Hour)
resp, err = c.Get(server.URL + "/secure")
if err != nil {
t.Fatalf("Get: %v", err)
}
checkBody(t, resp, "third payload")
checkToken(t, transport.Token, "token3", "refreshtoken3", "idtoken3")
}
func checkToken(t *testing.T, tok *Token, access, refresh, id string) {
if g, w := tok.AccessToken, access; g != w {
t.Errorf("AccessToken = %q, want %q", g, w)
}
if g, w := tok.RefreshToken, refresh; g != w {
t.Errorf("RefreshToken = %q, want %q", g, w)
}
if g, w := tok.Extra["id_token"], id; g != w {
t.Errorf("Extra['id_token'] = %q, want %q", g, w)
}
exp := tok.Expiry.Sub(time.Now())
if (time.Hour-time.Second) > exp || exp > time.Hour {
t.Errorf("Expiry = %v, want ~1 hour", exp)
}
}
func checkBody(t *testing.T, r *http.Response, body string) {
b, err := ioutil.ReadAll(r.Body)
if err != nil {
t.Error("reading reponse body: %v, want %q", err, body)
}
if g, w := string(b), body; g != w {
t.Errorf("request body mismatch: got %q, want %q", g, w)
}
}
func TestCachePermissions(t *testing.T) {
if runtime.GOOS == "windows" {
// Windows doesn't support file mode bits.
return
}
td, err := ioutil.TempDir("", "oauth-test")
if err != nil {
t.Fatalf("ioutil.TempDir: %v", err)
}
defer os.RemoveAll(td)
tempFile := filepath.Join(td, "cache-file")
cf := CacheFile(tempFile)
if err := cf.PutToken(new(Token)); err != nil {
t.Fatalf("PutToken: %v", err)
}
fi, err := os.Stat(tempFile)
if err != nil {
t.Fatalf("os.Stat: %v", err)
}
if fi.Mode()&0077 != 0 {
t.Errorf("Created cache file has mode %#o, want non-accessible to group+other", fi.Mode())
}
}
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