1
0
Fork 0
forked from forgejo/forgejo
This commit is contained in:
techknowlogick 2021-02-28 18:08:33 -05:00 committed by GitHub
parent 030646eea4
commit 47f6a4ec3f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
947 changed files with 26119 additions and 7062 deletions

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build appengine
// +build appengine
// This file applies to App Engine first generation runtimes (<= Go 1.9).

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !appengine
// +build !appengine
// This file applies to App Engine second generation runtimes (>= Go 1.11) and App Engine flexible.

View file

@ -21,6 +21,10 @@ import (
// Credentials holds Google credentials, including "Application Default Credentials".
// For more details, see:
// https://developers.google.com/accounts/docs/application-default-credentials
// Credentials from external accounts (workload identity federation) are used to
// identify a particular application from an on-prem or non-Google Cloud platform
// including Amazon Web Services (AWS), Microsoft Azure or any identity provider
// that supports OpenID Connect (OIDC).
type Credentials struct {
ProjectID string // may be empty
TokenSource oauth2.TokenSource
@ -65,6 +69,10 @@ func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSourc
//
// 1. A JSON file whose path is specified by the
// GOOGLE_APPLICATION_CREDENTIALS environment variable.
// For workload identity federation, refer to
// https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation on
// how to generate the JSON configuration file for on-prem/non-Google cloud
// platforms.
// 2. A JSON file in a location known to the gcloud command-line tool.
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
// On other systems, $HOME/.config/gcloud/application_default_credentials.json.
@ -119,8 +127,10 @@ func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials
// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can
// represent either a Google Developers Console client_credentials.json file (as in
// ConfigFromJSON) or a Google Developers service account key file (as in
// JWTConfigFromJSON).
// ConfigFromJSON), a Google Developers service account key file (as in
// JWTConfigFromJSON) or the JSON configuration file for workload identity federation
// in non-Google cloud platforms (see
// https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation).
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) {
var f credentialsFile
if err := json.Unmarshal(jsonData, &f); err != nil {

View file

@ -4,13 +4,16 @@
// Package google provides support for making OAuth2 authorized and authenticated
// HTTP requests to Google APIs. It supports the Web server flow, client-side
// credentials, service accounts, Google Compute Engine service accounts, and Google
// App Engine service accounts.
// credentials, service accounts, Google Compute Engine service accounts, Google
// App Engine service accounts and workload identity federation from non-Google
// cloud platforms.
//
// A brief overview of the package follows. For more information, please read
// https://developers.google.com/accounts/docs/OAuth2
// and
// https://developers.google.com/accounts/docs/application-default-credentials.
// For more information on using workload identity federation, refer to
// https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation.
//
// OAuth2 Configs
//
@ -19,6 +22,35 @@
// the other by JWTConfigFromJSON. The returned Config can be used to obtain a TokenSource or
// create an http.Client.
//
// Workload Identity Federation
//
// Using workload identity federation, your application can access Google Cloud
// resources from Amazon Web Services (AWS), Microsoft Azure or any identity
// provider that supports OpenID Connect (OIDC).
// Traditionally, applications running outside Google Cloud have used service
// account keys to access Google Cloud resources. Using identity federation,
// you can allow your workload to impersonate a service account.
// This lets you access Google Cloud resources directly, eliminating the
// maintenance and security burden associated with service account keys.
//
// Follow the detailed instructions on how to configure Workload Identity Federation
// in various platforms:
//
// Amazon Web Services (AWS): https://cloud.google.com/iam/docs/access-resources-aws
// Microsoft Azure: https://cloud.google.com/iam/docs/access-resources-azure
// OIDC identity provider: https://cloud.google.com/iam/docs/access-resources-oidc
//
// For OIDC providers, the library can retrieve OIDC tokens either from a
// local file location (file-sourced credentials) or from a local server
// (URL-sourced credentials).
// For file-sourced credentials, a background process needs to be continuously
// refreshing the file location with a new OIDC token prior to expiration.
// For tokens with one hour lifetimes, the token needs to be updated in the file
// every hour. The token can be stored directly as plain text or in JSON format.
// For URL-sourced credentials, a local server needs to host a GET endpoint to
// return the OIDC token. The response can be in plain text or JSON.
// Additional required request headers can also be specified.
//
//
// Credentials
//
@ -29,6 +61,13 @@
// FindDefaultCredentials looks in some well-known places for a credentials file, and
// will call AppEngineTokenSource or ComputeTokenSource as needed.
//
// Application Default Credentials also support workload identity federation to
// access Google Cloud resources from non-Google Cloud platforms including Amazon
// Web Services (AWS), Microsoft Azure or any identity provider that supports
// OpenID Connect (OIDC). Workload identity federation is recommended for
// non-Google Cloud environments as it avoids the need to download, manage and
// store service account private keys locally.
//
// DefaultClient and DefaultTokenSource are convenience methods. They first call FindDefaultCredentials,
// then use the credentials to construct an http.Client or an oauth2.TokenSource.
//

View file

@ -45,7 +45,7 @@ func (c *Config) TokenSource(ctx context.Context) oauth2.TokenSource {
ctx: ctx,
url: c.ServiceAccountImpersonationURL,
scopes: scopes,
ts: oauth2.ReuseTokenSource(nil, ts),
ts: oauth2.ReuseTokenSource(nil, ts),
}
return oauth2.ReuseTokenSource(nil, imp)
}
@ -96,7 +96,7 @@ func (c *Config) parse(ctx context.Context) (baseCredentialSource, error) {
} else if c.CredentialSource.File != "" {
return fileCredentialSource{File: c.CredentialSource.File, Format: c.CredentialSource.Format}, nil
} else if c.CredentialSource.URL != "" {
return urlCredentialSource{URL: c.CredentialSource.URL, Format: c.CredentialSource.Format, ctx: ctx}, nil
return urlCredentialSource{URL: c.CredentialSource.URL, Headers: c.CredentialSource.Headers, Format: c.CredentialSource.Format, ctx: ctx}, nil
}
return nil, fmt.Errorf("oauth2/google: unable to parse credential source")
}
@ -124,7 +124,7 @@ func (ts tokenSource) Token() (*oauth2.Token, error) {
if err != nil {
return nil, err
}
stsRequest := STSTokenExchangeRequest{
stsRequest := stsTokenExchangeRequest{
GrantType: "urn:ietf:params:oauth:grant-type:token-exchange",
Audience: conf.Audience,
Scope: conf.Scopes,
@ -134,12 +134,12 @@ func (ts tokenSource) Token() (*oauth2.Token, error) {
}
header := make(http.Header)
header.Add("Content-Type", "application/x-www-form-urlencoded")
clientAuth := ClientAuthentication{
clientAuth := clientAuthentication{
AuthStyle: oauth2.AuthStyleInHeader,
ClientID: conf.ClientID,
ClientSecret: conf.ClientSecret,
}
stsResp, err := ExchangeToken(ts.ctx, conf.TokenURL, &stsRequest, clientAuth, header, nil)
stsResp, err := exchangeToken(ts.ctx, conf.TokenURL, &stsRequest, clientAuth, header, nil)
if err != nil {
return nil, err
}

View file

@ -11,15 +11,15 @@ import (
"net/url"
)
// ClientAuthentication represents an OAuth client ID and secret and the mechanism for passing these credentials as stated in rfc6749#2.3.1.
type ClientAuthentication struct {
// clientAuthentication represents an OAuth client ID and secret and the mechanism for passing these credentials as stated in rfc6749#2.3.1.
type clientAuthentication struct {
// AuthStyle can be either basic or request-body
AuthStyle oauth2.AuthStyle
ClientID string
ClientSecret string
}
func (c *ClientAuthentication) InjectAuthentication(values url.Values, headers http.Header) {
func (c *clientAuthentication) InjectAuthentication(values url.Values, headers http.Header) {
if c.ClientID == "" || c.ClientSecret == "" || values == nil || headers == nil {
return
}

View file

@ -9,6 +9,7 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strconv"
@ -17,11 +18,11 @@ import (
"golang.org/x/oauth2"
)
// ExchangeToken performs an oauth2 token exchange with the provided endpoint.
// exchangeToken performs an oauth2 token exchange with the provided endpoint.
// The first 4 fields are all mandatory. headers can be used to pass additional
// headers beyond the bare minimum required by the token exchange. options can
// be used to pass additional JSON-structured options to the remote server.
func ExchangeToken(ctx context.Context, endpoint string, request *STSTokenExchangeRequest, authentication ClientAuthentication, headers http.Header, options map[string]interface{}) (*STSTokenExchangeResponse, error) {
func exchangeToken(ctx context.Context, endpoint string, request *stsTokenExchangeRequest, authentication clientAuthentication, headers http.Header, options map[string]interface{}) (*stsTokenExchangeResponse, error) {
client := oauth2.NewClient(ctx, nil)
@ -63,9 +64,12 @@ func ExchangeToken(ctx context.Context, endpoint string, request *STSTokenExchan
}
defer resp.Body.Close()
bodyJson := json.NewDecoder(io.LimitReader(resp.Body, 1<<20))
var stsResp STSTokenExchangeResponse
err = bodyJson.Decode(&stsResp)
body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
if c := resp.StatusCode; c < 200 || c > 299 {
return nil, fmt.Errorf("oauth2/google: status code %d: %s", c, body)
}
var stsResp stsTokenExchangeResponse
err = json.Unmarshal(body, &stsResp)
if err != nil {
return nil, fmt.Errorf("oauth2/google: failed to unmarshal response body from Secure Token Server: %v", err)
@ -74,8 +78,8 @@ func ExchangeToken(ctx context.Context, endpoint string, request *STSTokenExchan
return &stsResp, nil
}
// STSTokenExchangeRequest contains fields necessary to make an oauth2 token exchange.
type STSTokenExchangeRequest struct {
// stsTokenExchangeRequest contains fields necessary to make an oauth2 token exchange.
type stsTokenExchangeRequest struct {
ActingParty struct {
ActorToken string
ActorTokenType string
@ -89,8 +93,8 @@ type STSTokenExchangeRequest struct {
SubjectTokenType string
}
// STSTokenExchangeResponse is used to decode the remote server response during an oauth2 token exchange.
type STSTokenExchangeResponse struct {
// stsTokenExchangeResponse is used to decode the remote server response during an oauth2 token exchange.
type stsTokenExchangeResponse struct {
AccessToken string `json:"access_token"`
IssuedTokenType string `json:"issued_token_type"`
TokenType string `json:"token_type"`

View file

@ -39,15 +39,18 @@ func (cs urlCredentialSource) subjectToken() (string, error) {
}
defer resp.Body.Close()
tokenBytes, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err != nil {
return "", fmt.Errorf("oauth2/google: invalid body in subject token URL query: %v", err)
}
if c := resp.StatusCode; c < 200 || c > 299 {
return "", fmt.Errorf("oauth2/google: status code %d: %s", c, respBody)
}
switch cs.Format.Type {
case "json":
jsonData := make(map[string]interface{})
err = json.Unmarshal(tokenBytes, &jsonData)
err = json.Unmarshal(respBody, &jsonData)
if err != nil {
return "", fmt.Errorf("oauth2/google: failed to unmarshal subject token file: %v", err)
}
@ -61,9 +64,9 @@ func (cs urlCredentialSource) subjectToken() (string, error) {
}
return token, nil
case "text":
return string(tokenBytes), nil
return string(respBody), nil
case "":
return string(tokenBytes), nil
return string(respBody), nil
default:
return "", errors.New("oauth2/google: invalid credential_source file format type")
}

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build appengine
// +build appengine
package internal