Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
45397c46
Commit
45397c46
authored
Jun 16, 2014
by
Brendan Burns
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bump(code.google.com/p/goauth2/compute/serviceaccount): ef170e7cf161bc5644976d13cadc67b285e73ee8
parent
721f6571
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
172 additions
and
0 deletions
+172
-0
serviceaccount.go
...le.com/p/goauth2/compute/serviceaccount/serviceaccount.go
+172
-0
No files found.
third_party/src/code.google.com/p/goauth2/compute/serviceaccount/serviceaccount.go
0 → 100644
View file @
45397c46
// Copyright 2013 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 serviceaccount provides support for making OAuth2-authorized
// HTTP requests from Google Compute Engine instances using service accounts.
//
// See: https://developers.google.com/compute/docs/authentication
//
// Example usage:
//
// client, err := serviceaccount.NewClient(&serviceaccount.Options{})
// if err != nil {
// c.Errorf("failed to create service account client: %q", err)
// return err
// }
// client.Post("https://www.googleapis.com/compute/...", ...)
// client.Post("https://www.googleapis.com/bigquery/...", ...)
//
package
serviceaccount
import
(
"encoding/json"
"net/http"
"net/url"
"path"
"sync"
"time"
"code.google.com/p/goauth2/oauth"
)
const
(
metadataServer
=
"metadata"
serviceAccountPath
=
"/computeMetadata/v1/instance/service-accounts"
)
// Options configures a service account Client.
type
Options
struct
{
// Underlying transport of service account Client.
// If nil, http.DefaultTransport is used.
Transport
http
.
RoundTripper
// Service account name.
// If empty, "default" is used.
Account
string
}
// NewClient returns an *http.Client authorized with the service account
// configured in the Google Compute Engine instance.
func
NewClient
(
opt
*
Options
)
(
*
http
.
Client
,
error
)
{
tr
:=
http
.
DefaultTransport
account
:=
"default"
if
opt
!=
nil
{
if
opt
.
Transport
!=
nil
{
tr
=
opt
.
Transport
}
if
opt
.
Account
!=
""
{
account
=
opt
.
Account
}
}
t
:=
&
transport
{
Transport
:
tr
,
Account
:
account
,
}
// Get the initial access token.
if
_
,
err
:=
fetchToken
(
t
);
err
!=
nil
{
return
nil
,
err
}
return
&
http
.
Client
{
Transport
:
t
,
},
nil
}
type
tokenData
struct
{
AccessToken
string
`json:"access_token"`
ExpiresIn
float64
`json:"expires_in"`
TokenType
string
`json:"token_type"`
}
// transport is an oauth.Transport with a custom Refresh and RoundTrip implementation.
type
transport
struct
{
Transport
http
.
RoundTripper
Account
string
mu
sync
.
Mutex
*
oauth
.
Token
}
// Refresh renews the transport's AccessToken.
// t.mu sould be held when this is called.
func
(
t
*
transport
)
refresh
()
error
{
// https://developers.google.com/compute/docs/metadata
// v1 requires "X-Google-Metadata-Request: True" header.
tokenURL
:=
&
url
.
URL
{
Scheme
:
"http"
,
Host
:
metadataServer
,
Path
:
path
.
Join
(
serviceAccountPath
,
t
.
Account
,
"token"
),
}
req
,
err
:=
http
.
NewRequest
(
"GET"
,
tokenURL
.
String
(),
nil
)
if
err
!=
nil
{
return
err
}
req
.
Header
.
Add
(
"X-Google-Metadata-Request"
,
"True"
)
resp
,
err
:=
http
.
DefaultClient
.
Do
(
req
)
if
err
!=
nil
{
return
err
}
defer
resp
.
Body
.
Close
()
d
:=
json
.
NewDecoder
(
resp
.
Body
)
var
token
tokenData
err
=
d
.
Decode
(
&
token
)
if
err
!=
nil
{
return
err
}
t
.
Token
=
&
oauth
.
Token
{
AccessToken
:
token
.
AccessToken
,
Expiry
:
time
.
Now
()
.
Add
(
time
.
Duration
(
token
.
ExpiresIn
)
*
time
.
Second
),
}
return
nil
}
// Refresh renews the transport's AccessToken.
func
(
t
*
transport
)
Refresh
()
error
{
t
.
mu
.
Lock
()
defer
t
.
mu
.
Unlock
()
return
t
.
refresh
()
}
// Fetch token from cache or generate a new one if cache miss or expired.
func
fetchToken
(
t
*
transport
)
(
*
oauth
.
Token
,
error
)
{
// Get a new token using Refresh in case of a cache miss of if it has expired.
t
.
mu
.
Lock
()
defer
t
.
mu
.
Unlock
()
if
t
.
Token
==
nil
||
t
.
Expired
()
{
if
err
:=
t
.
refresh
();
err
!=
nil
{
return
nil
,
err
}
}
return
t
.
Token
,
nil
}
// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func
cloneRequest
(
r
*
http
.
Request
)
*
http
.
Request
{
// shallow copy of the struct
r2
:=
new
(
http
.
Request
)
*
r2
=
*
r
// deep copy of the Header
r2
.
Header
=
make
(
http
.
Header
)
for
k
,
s
:=
range
r
.
Header
{
r2
.
Header
[
k
]
=
s
}
return
r2
}
// RoundTrip issues an authorized HTTP request and returns its response.
func
(
t
*
transport
)
RoundTrip
(
req
*
http
.
Request
)
(
*
http
.
Response
,
error
)
{
token
,
err
:=
fetchToken
(
t
)
if
err
!=
nil
{
return
nil
,
err
}
// To set the Authorization header, we must make a copy of the Request
// so that we don't modify the Request we were given.
// This is required by the specification of http.RoundTripper.
newReq
:=
cloneRequest
(
req
)
newReq
.
Header
.
Set
(
"Authorization"
,
"Bearer "
+
token
.
AccessToken
)
// Make the HTTP request.
return
t
.
Transport
.
RoundTrip
(
newReq
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment