forked from google/oauth2l
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Port Google Authenticator Go into oauth2l/go
- Loading branch information
Showing
22 changed files
with
2,467 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
Google Authenticator | ||
====== | ||
|
||
This is the initial repository of Google Authenticator --- a _shard-agnostic_ client library that | ||
provides a unified future-proof interface for Google API authentication. | ||
|
||
The project is still at very early stage so __everything is subject to change__. | ||
|
||
Concept | ||
------- | ||
Google Authenticator is a future-proof client library that supports __Sharded Google__ and aims | ||
to simplify the developer experience with Google API authentication. | ||
|
||
|
||
Comparing with existing Google Authentication Libraries, it bring the following advantages: | ||
|
||
- __Lightweight concept:__ Decouple the authentication client from underlying workflow. | ||
Application only provides credentials and then make the API call. | ||
As a result, developers should only need minimum knowledge about the authentication workflow. | ||
|
||
- __Unified interface:__ The developer only needs to provide a general settings object. This unified credential object | ||
is an extensible structure that can contain arbitrary type of credentials. | ||
|
||
Quickstart | ||
---------- | ||
|
||
To use the authenticator library in your application simply import the package in your source | ||
code: | ||
|
||
```go | ||
import "github.com/shinfan/sgauth" | ||
``` | ||
|
||
To use the authenticator to call Google APIs, simply create a authenticator settings object with | ||
the credentials supported by Google APIs, and use the settings to create the client. | ||
For example, to call Google API with HTTP and API key: | ||
|
||
```go | ||
import "github.com/shinfan/sgauth" | ||
|
||
// Create the settings with pasted API key. | ||
settings := &sgauth.Settings{ | ||
APIKey: "YOUR_API_KEY", | ||
} | ||
// Create the HTTP client with the settings using authenticator. | ||
http, err := sgauth.NewHTTPClient(ctx, createSettings(args)) | ||
if err != nil { | ||
// Call Google API here | ||
} | ||
``` | ||
|
||
Credentials | ||
----------- | ||
|
||
To authenticate against Google API, users need to provide required credentials. | ||
The authenticator takes a general settings object that supports multiple types of credentials: | ||
|
||
- __Service account JSON__: You can explicitly set the JSON string downloaded from Pantheon so | ||
it can be used by either OAuth or JWT auth flow. If you prefer to use the JWT token authentication | ||
flow, the `aud` value has to be provided. Alternatively, you can use the OAuth flow where you | ||
need to specify the `scope` value. | ||
|
||
- __API Key__: The Google API key. | ||
|
||
- __Application Default Credentials__: If no credentials set explicitly, Google Authenticator | ||
will try to look for your service account JSON file at the default path --- the path specified | ||
by the `$GOOGLE_APPLICATION_CREDENTIAL` environment variable. | ||
|
||
Protocols | ||
--------- | ||
|
||
Google authenticator supports three protocols which are widely supported by Google APIs: | ||
__REST, gRPC, ProtoRPC__ | ||
|
||
To use the library calling __REST APIs__, simply create a HTTP client: | ||
```go | ||
import "github.com/shinfan/sgauth" | ||
|
||
// Create the settings | ||
settings := &sgauth.Settings{ | ||
// Config your credential settings | ||
} | ||
// Create the HTTP client with the settings using authenticator. | ||
http, err := sgauth.NewHTTPClient(ctx, createSettings(args)) | ||
if err != nil { | ||
// Call REST Google API here | ||
} | ||
``` | ||
|
||
Or you can use the library with a __gRPC API client__: | ||
|
||
```go | ||
import "github.com/shinfan/sgauth" | ||
|
||
// Create the settings | ||
settings := &sgauth.Settings{ | ||
// Config your credential settings | ||
} | ||
// Create the gRPC connection with the settings using authenticator. | ||
conn, err := sgauth.NewGrpcConn(ctx, createSettings(args), "YOUR_HOST", "YOUR_PORT") | ||
if err != nil { | ||
return nil, err | ||
} | ||
client := library.NewLibraryServiceClient(conn) | ||
``` | ||
|
||
To use the library calling __ProtoRPC APIs__: | ||
```go | ||
import "github.com/shinfan/sgauth" | ||
import "github.com/wora/protorpc/client" | ||
|
||
// Create the settings | ||
settings := &sgauth.Settings{ | ||
// Config your credential settings | ||
} | ||
// Create the HTTP client with the settings using authenticator. | ||
http, err := sgauth.NewHTTPClient(ctx, createSettings(args)) | ||
if err != nil { | ||
// Call REST Google API here | ||
} | ||
client := &client.Client{ | ||
HTTP: http, | ||
BaseURL: "YOUR_PROTORPC_BASE_URL", | ||
UserAgent: "protorpc/0.1", | ||
} | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// | ||
// Copyright 2018 Google Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
package sgauth | ||
|
||
import ( | ||
"sort" | ||
"strings" | ||
"sync" | ||
"time" | ||
|
||
"golang.org/x/net/context" | ||
"github.com/shinfan/sgauth/internal" | ||
) | ||
|
||
// appengineFlex is set at init time by appengineflex_hook.go. If true, we are on App Engine Flex. | ||
var appengineFlex bool | ||
|
||
// Set at init time by appengine_hook.go. If nil, we're not on App Engine. | ||
var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error) | ||
|
||
// Set at init time by appengine_hook.go. If nil, we're not on App Engine. | ||
var appengineAppIDFunc func(c context.Context) string | ||
|
||
// AppEngineTokenSource returns a token source that fetches tokens | ||
// issued to the current App Engine application's service account. | ||
// If you are implementing a 3-legged OAuth 2.0 flow on App Engine | ||
// that involves user accounts, see oauth2.Config instead. | ||
// | ||
// The provided context must have come from appengine.NewContext. | ||
func AppEngineTokenSource(ctx context.Context, scope ...string) internal.TokenSource { | ||
if appengineTokenFunc == nil { | ||
panic("google: AppEngineTokenSource can only be used on App Engine.") | ||
} | ||
scopes := append([]string{}, scope...) | ||
sort.Strings(scopes) | ||
return &appEngineTokenSource{ | ||
ctx: ctx, | ||
scopes: scopes, | ||
key: strings.Join(scopes, " "), | ||
} | ||
} | ||
|
||
// aeTokens helps the fetched tokens to be reused until their expiration. | ||
var ( | ||
aeTokensMu sync.Mutex | ||
aeTokens = make(map[string]*tokenLock) // key is space-separated scopes | ||
) | ||
|
||
type tokenLock struct { | ||
mu sync.Mutex // guards t; held while fetching or updating t | ||
t *internal.Token | ||
} | ||
|
||
type appEngineTokenSource struct { | ||
ctx context.Context | ||
scopes []string | ||
key string // to aeTokens map; space-separated scopes | ||
} | ||
|
||
func (ts *appEngineTokenSource) Token() (*internal.Token, error) { | ||
if appengineTokenFunc == nil { | ||
panic("google: AppEngineTokenSource can only be used on App Engine.") | ||
} | ||
|
||
aeTokensMu.Lock() | ||
tok, ok := aeTokens[ts.key] | ||
if !ok { | ||
tok = &tokenLock{} | ||
aeTokens[ts.key] = tok | ||
} | ||
aeTokensMu.Unlock() | ||
|
||
tok.mu.Lock() | ||
defer tok.mu.Unlock() | ||
if tok.t.Valid() { | ||
return tok.t, nil | ||
} | ||
access, exp, err := appengineTokenFunc(ts.ctx, ts.scopes...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
tok.t = &internal.Token{ | ||
AccessToken: access, | ||
Expiry: exp, | ||
} | ||
return tok.t, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// | ||
// Copyright 2018 Google Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
// +build appengine appenginevm | ||
package sgauth | ||
|
||
import "google.golang.org/appengine" | ||
|
||
func init() { | ||
appengineTokenFunc = appengine.AccessToken | ||
appengineAppIDFunc = appengine.AppID | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// | ||
// Copyright 2018 Google Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
package sgauth | ||
|
||
import ( | ||
"cloud.google.com/go/compute/metadata" | ||
"errors" | ||
"encoding/json" | ||
"strings" | ||
"fmt" | ||
"time" | ||
"github.com/shinfan/sgauth/internal" | ||
) | ||
|
||
// ComputeTokenSource returns a token source that fetches access tokens | ||
// from Google Compute Engine (GCE)'s metadata server. It's only valid to use | ||
// this token source if your program is running on a GCE instance. | ||
// If no account is specified, "default" is used. | ||
// Further information about retrieving access tokens from the GCE metadata | ||
// server can be found at https://cloud.google.com/compute/docs/authentication. | ||
func ComputeTokenSource(account string) internal.TokenSource { | ||
return internal.ReuseTokenSource(nil, computeSource{account: account}) | ||
} | ||
|
||
type computeSource struct { | ||
account string | ||
} | ||
|
||
func (cs computeSource) Token() (*internal.Token, error) { | ||
if !metadata.OnGCE() { | ||
return nil, errors.New("oauth2/google: can't get a token from the metadata service; not running on GCE") | ||
} | ||
acct := cs.account | ||
if acct == "" { | ||
acct = "default" | ||
} | ||
tokenJSON, err := metadata.Get("instance/service-accounts/" + acct + "/token") | ||
if err != nil { | ||
return nil, err | ||
} | ||
var res struct { | ||
AccessToken string `json:"access_token"` | ||
ExpiresInSec int `json:"expires_in"` | ||
TokenType string `json:"token_type"` | ||
} | ||
err = json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&res) | ||
if err != nil { | ||
return nil, fmt.Errorf("oauth2/google: invalid token JSON from metadata: %v", err) | ||
} | ||
if res.ExpiresInSec == 0 || res.AccessToken == "" { | ||
return nil, fmt.Errorf("oauth2/google: incomplete token received from metadata") | ||
} | ||
return &internal.Token{ | ||
AccessToken: res.AccessToken, | ||
TokenType: res.TokenType, | ||
Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second), | ||
}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// | ||
// Copyright 2018 Google Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
package credentials | ||
|
||
import "github.com/shinfan/sgauth/internal" | ||
|
||
// Credentials holds Google credentials, including "Application Default Credentials". | ||
// For more details, see: | ||
// https://developers.google.com/accounts/docs/application-default-credentials | ||
type Credentials struct { | ||
ProjectID string // may be empty | ||
TokenSource internal.TokenSource | ||
|
||
// JSON contains the raw bytes from a JSON credentials file. | ||
// This field may be nil if authentication is provided by the | ||
// environment and not with a credentials file, e.g. when code is | ||
// running on Google Cloud Platform. | ||
JSON []byte | ||
} |
Oops, something went wrong.