forked from remote/oauth2
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36075149c5 | ||
|
|
4abfd87339 | ||
|
|
1e7f329364 | ||
|
|
86850e0723 | ||
|
|
a6e37e7441 | ||
|
|
54b70c833f | ||
|
|
2fc4ef5a6f |
12
README.md
12
README.md
@@ -19,7 +19,7 @@ See pkg.go.dev for further documentation and examples.
|
|||||||
* [pkg.go.dev/golang.org/x/oauth2](https://pkg.go.dev/golang.org/x/oauth2)
|
* [pkg.go.dev/golang.org/x/oauth2](https://pkg.go.dev/golang.org/x/oauth2)
|
||||||
* [pkg.go.dev/golang.org/x/oauth2/google](https://pkg.go.dev/golang.org/x/oauth2/google)
|
* [pkg.go.dev/golang.org/x/oauth2/google](https://pkg.go.dev/golang.org/x/oauth2/google)
|
||||||
|
|
||||||
## Policy for new packages
|
## Policy for new endpoints
|
||||||
|
|
||||||
We no longer accept new provider-specific packages in this repo if all
|
We no longer accept new provider-specific packages in this repo if all
|
||||||
they do is add a single endpoint variable. If you just want to add a
|
they do is add a single endpoint variable. If you just want to add a
|
||||||
@@ -29,8 +29,12 @@ package.
|
|||||||
|
|
||||||
## Report Issues / Send Patches
|
## Report Issues / Send Patches
|
||||||
|
|
||||||
This repository uses Gerrit for code changes. To learn how to submit changes to
|
|
||||||
this repository, see https://golang.org/doc/contribute.html.
|
|
||||||
|
|
||||||
The main issue tracker for the oauth2 repository is located at
|
The main issue tracker for the oauth2 repository is located at
|
||||||
https://github.com/golang/oauth2/issues.
|
https://github.com/golang/oauth2/issues.
|
||||||
|
|
||||||
|
This repository uses Gerrit for code changes. To learn how to submit changes to
|
||||||
|
this repository, see https://golang.org/doc/contribute.html. In particular:
|
||||||
|
|
||||||
|
* Excluding trivial changes, all contributions should be connected to an existing issue.
|
||||||
|
* API changes must go through the [change proposal process](https://go.dev/s/proposal-process) before they can be accepted.
|
||||||
|
* The code owners are listed at [dev.golang.org/owners](https://dev.golang.org/owners#:~:text=x/oauth2).
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -10,6 +10,6 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
golang.org/x/net v0.8.0 // indirect
|
golang.org/x/net v0.9.0 // indirect
|
||||||
google.golang.org/protobuf v1.28.0 // indirect
|
google.golang.org/protobuf v1.28.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
10
go.sum
10
go.sum
@@ -17,8 +17,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -28,17 +28,17 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
|||||||
@@ -13,12 +13,15 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"time"
|
||||||
|
|
||||||
"cloud.google.com/go/compute/metadata"
|
"cloud.google.com/go/compute/metadata"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"golang.org/x/oauth2/authhandler"
|
"golang.org/x/oauth2/authhandler"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const adcSetupURL = "https://cloud.google.com/docs/authentication/external/set-up-adc"
|
||||||
|
|
||||||
// Credentials holds Google credentials, including "Application Default Credentials".
|
// Credentials holds Google credentials, including "Application Default Credentials".
|
||||||
// For more details, see:
|
// For more details, see:
|
||||||
// https://developers.google.com/accounts/docs/application-default-credentials
|
// https://developers.google.com/accounts/docs/application-default-credentials
|
||||||
@@ -66,6 +69,14 @@ type CredentialsParams struct {
|
|||||||
// The OAuth2 TokenURL default override. This value overrides the default TokenURL,
|
// The OAuth2 TokenURL default override. This value overrides the default TokenURL,
|
||||||
// unless explicitly specified by the credentials config file. Optional.
|
// unless explicitly specified by the credentials config file. Optional.
|
||||||
TokenURL string
|
TokenURL string
|
||||||
|
|
||||||
|
// EarlyTokenRefresh is the amount of time before a token expires that a new
|
||||||
|
// token will be preemptively fetched. If unset the default value is 10
|
||||||
|
// seconds.
|
||||||
|
//
|
||||||
|
// Note: This option is currently only respected when using credentials
|
||||||
|
// fetched from the GCE metadata server.
|
||||||
|
EarlyTokenRefresh time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params CredentialsParams) deepCopy() CredentialsParams {
|
func (params CredentialsParams) deepCopy() CredentialsParams {
|
||||||
@@ -153,13 +164,12 @@ func FindDefaultCredentialsWithParams(ctx context.Context, params CredentialsPar
|
|||||||
id, _ := metadata.ProjectID()
|
id, _ := metadata.ProjectID()
|
||||||
return &Credentials{
|
return &Credentials{
|
||||||
ProjectID: id,
|
ProjectID: id,
|
||||||
TokenSource: ComputeTokenSource("", params.Scopes...),
|
TokenSource: computeTokenSource("", params.EarlyTokenRefresh, params.Scopes...),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// None are found; return helpful error.
|
// None are found; return helpful error.
|
||||||
const url = "https://developers.google.com/accounts/docs/application-default-credentials"
|
return nil, fmt.Errorf("google: could not find default credentials. See %v for more information", adcSetupURL)
|
||||||
return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindDefaultCredentials invokes FindDefaultCredentialsWithParams with the specified scopes.
|
// FindDefaultCredentials invokes FindDefaultCredentialsWithParams with the specified scopes.
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
//
|
//
|
||||||
// Using workload identity federation, your application can access Google Cloud
|
// Using workload identity federation, your application can access Google Cloud
|
||||||
// resources from Amazon Web Services (AWS), Microsoft Azure or any identity
|
// resources from Amazon Web Services (AWS), Microsoft Azure or any identity
|
||||||
// provider that supports OpenID Connect (OIDC).
|
// provider that supports OpenID Connect (OIDC) or SAML 2.0.
|
||||||
// Traditionally, applications running outside Google Cloud have used service
|
// Traditionally, applications running outside Google Cloud have used service
|
||||||
// account keys to access Google Cloud resources. Using identity federation,
|
// account keys to access Google Cloud resources. Using identity federation,
|
||||||
// you can allow your workload to impersonate a service account.
|
// you can allow your workload to impersonate a service account.
|
||||||
@@ -36,26 +36,70 @@
|
|||||||
// Follow the detailed instructions on how to configure Workload Identity Federation
|
// Follow the detailed instructions on how to configure Workload Identity Federation
|
||||||
// in various platforms:
|
// in various platforms:
|
||||||
//
|
//
|
||||||
// Amazon Web Services (AWS): https://cloud.google.com/iam/docs/access-resources-aws
|
// Amazon Web Services (AWS): https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#aws
|
||||||
// Microsoft Azure: https://cloud.google.com/iam/docs/access-resources-azure
|
// Microsoft Azure: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#azure
|
||||||
// OIDC identity provider: https://cloud.google.com/iam/docs/access-resources-oidc
|
// OIDC identity provider: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#oidc
|
||||||
|
// SAML 2.0 identity provider: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#saml
|
||||||
//
|
//
|
||||||
// For OIDC and SAML providers, the library can retrieve tokens in three ways:
|
// For OIDC and SAML providers, the library can retrieve tokens in three ways:
|
||||||
// from a local file location (file-sourced credentials), from a server
|
// from a local file location (file-sourced credentials), from a server
|
||||||
// (URL-sourced credentials), or from a local executable (executable-sourced
|
// (URL-sourced credentials), or from a local executable (executable-sourced
|
||||||
// credentials).
|
// credentials).
|
||||||
// For file-sourced credentials, a background process needs to be continuously
|
// For file-sourced credentials, a background process needs to be continuously
|
||||||
// refreshing the file location with a new OIDC token prior to expiration.
|
// refreshing the file location with a new OIDC/SAML token prior to expiration.
|
||||||
// For tokens with one hour lifetimes, the token needs to be updated in the file
|
// 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.
|
// 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
|
// 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.
|
// return the OIDC/SAML token. The response can be in plain text or JSON.
|
||||||
// Additional required request headers can also be specified.
|
// Additional required request headers can also be specified.
|
||||||
// For executable-sourced credentials, an application needs to be available to
|
// For executable-sourced credentials, an application needs to be available to
|
||||||
// output the OIDC token and other information in a JSON format.
|
// output the OIDC/SAML token and other information in a JSON format.
|
||||||
// For more information on how these work (and how to implement
|
// For more information on how these work (and how to implement
|
||||||
// executable-sourced credentials), please check out:
|
// executable-sourced credentials), please check out:
|
||||||
// https://cloud.google.com/iam/docs/using-workload-identity-federation#oidc
|
// https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#create_a_credential_configuration
|
||||||
|
//
|
||||||
|
// Note that this library does not perform any validation on the token_url, token_info_url,
|
||||||
|
// or service_account_impersonation_url fields of the credential configuration.
|
||||||
|
// It is not recommended to use a credential configuration that you did not generate with
|
||||||
|
// the gcloud CLI unless you verify that the URL fields point to a googleapis.com domain.
|
||||||
|
//
|
||||||
|
// # Workforce Identity Federation
|
||||||
|
//
|
||||||
|
// Workforce identity federation lets you use an external identity provider (IdP) to
|
||||||
|
// authenticate and authorize a workforce—a group of users, such as employees, partners,
|
||||||
|
// and contractors—using IAM, so that the users can access Google Cloud services.
|
||||||
|
// Workforce identity federation extends Google Cloud's identity capabilities to support
|
||||||
|
// syncless, attribute-based single sign on.
|
||||||
|
//
|
||||||
|
// With workforce identity federation, your workforce can access Google Cloud resources
|
||||||
|
// using an external identity provider (IdP) that supports OpenID Connect (OIDC) or
|
||||||
|
// SAML 2.0 such as Azure Active Directory (Azure AD), Active Directory Federation
|
||||||
|
// Services (AD FS), Okta, and others.
|
||||||
|
//
|
||||||
|
// Follow the detailed instructions on how to configure Workload Identity Federation
|
||||||
|
// in various platforms:
|
||||||
|
//
|
||||||
|
// Azure AD: https://cloud.google.com/iam/docs/workforce-sign-in-azure-ad
|
||||||
|
// Okta: https://cloud.google.com/iam/docs/workforce-sign-in-okta
|
||||||
|
// OIDC identity provider: https://cloud.google.com/iam/docs/configuring-workforce-identity-federation#oidc
|
||||||
|
// SAML 2.0 identity provider: https://cloud.google.com/iam/docs/configuring-workforce-identity-federation#saml
|
||||||
|
//
|
||||||
|
// For workforce identity federation, the library can retrieve tokens in three ways:
|
||||||
|
// from a local file location (file-sourced credentials), from a server
|
||||||
|
// (URL-sourced credentials), or from a local executable (executable-sourced
|
||||||
|
// credentials).
|
||||||
|
// For file-sourced credentials, a background process needs to be continuously
|
||||||
|
// refreshing the file location with a new OIDC/SAML 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/SAML token. The response can be in plain text or JSON.
|
||||||
|
// Additional required request headers can also be specified.
|
||||||
|
// For executable-sourced credentials, an application needs to be available to
|
||||||
|
// output the OIDC/SAML token and other information in a JSON format.
|
||||||
|
// For more information on how these work (and how to implement
|
||||||
|
// executable-sourced credentials), please check out:
|
||||||
|
// https://cloud.google.com/iam/docs/workforce-obtaining-short-lived-credentials#generate_a_configuration_file_for_non-interactive_sign-in
|
||||||
//
|
//
|
||||||
// Note that this library does not perform any validation on the token_url, token_info_url,
|
// Note that this library does not perform any validation on the token_url, token_info_url,
|
||||||
// or service_account_impersonation_url fields of the credential configuration.
|
// or service_account_impersonation_url fields of the credential configuration.
|
||||||
@@ -86,5 +130,4 @@
|
|||||||
// same as the one obtained from the oauth2.Config returned from ConfigFromJSON or
|
// same as the one obtained from the oauth2.Config returned from ConfigFromJSON or
|
||||||
// JWTConfigFromJSON, but the Credentials may contain additional information
|
// JWTConfigFromJSON, but the Credentials may contain additional information
|
||||||
// that is useful is some circumstances.
|
// that is useful is some circumstances.
|
||||||
//
|
|
||||||
package google // import "golang.org/x/oauth2/google"
|
package google // import "golang.org/x/oauth2/google"
|
||||||
|
|||||||
@@ -231,7 +231,11 @@ func (f *credentialsFile) tokenSource(ctx context.Context, params CredentialsPar
|
|||||||
// Further information about retrieving access tokens from the GCE metadata
|
// Further information about retrieving access tokens from the GCE metadata
|
||||||
// server can be found at https://cloud.google.com/compute/docs/authentication.
|
// server can be found at https://cloud.google.com/compute/docs/authentication.
|
||||||
func ComputeTokenSource(account string, scope ...string) oauth2.TokenSource {
|
func ComputeTokenSource(account string, scope ...string) oauth2.TokenSource {
|
||||||
return oauth2.ReuseTokenSource(nil, computeSource{account: account, scopes: scope})
|
return computeTokenSource(account, 0, scope...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func computeTokenSource(account string, earlyExpiry time.Duration, scope ...string) oauth2.TokenSource {
|
||||||
|
return oauth2.ReuseTokenSourceWithExpiry(nil, computeSource{account: account, scopes: scope}, earlyExpiry)
|
||||||
}
|
}
|
||||||
|
|
||||||
type computeSource struct {
|
type computeSource struct {
|
||||||
|
|||||||
33
oauth2.go
33
oauth2.go
@@ -16,6 +16,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/oauth2/internal"
|
"golang.org/x/oauth2/internal"
|
||||||
)
|
)
|
||||||
@@ -140,7 +141,7 @@ func SetAuthURLParam(key, value string) AuthCodeOption {
|
|||||||
//
|
//
|
||||||
// State is a token to protect the user from CSRF attacks. You must
|
// State is a token to protect the user from CSRF attacks. You must
|
||||||
// always provide a non-empty string and validate that it matches the
|
// always provide a non-empty string and validate that it matches the
|
||||||
// the state query parameter on your redirect callback.
|
// state query parameter on your redirect callback.
|
||||||
// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
|
// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
|
||||||
//
|
//
|
||||||
// Opts may include AccessTypeOnline or AccessTypeOffline, as well
|
// Opts may include AccessTypeOnline or AccessTypeOffline, as well
|
||||||
@@ -290,6 +291,8 @@ type reuseTokenSource struct {
|
|||||||
|
|
||||||
mu sync.Mutex // guards t
|
mu sync.Mutex // guards t
|
||||||
t *Token
|
t *Token
|
||||||
|
|
||||||
|
expiryDelta time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Token returns the current token if it's still valid, else will
|
// Token returns the current token if it's still valid, else will
|
||||||
@@ -305,6 +308,7 @@ func (s *reuseTokenSource) Token() (*Token, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
t.expiryDelta = s.expiryDelta
|
||||||
s.t = t
|
s.t = t
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
@@ -379,3 +383,30 @@ func ReuseTokenSource(t *Token, src TokenSource) TokenSource {
|
|||||||
new: src,
|
new: src,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReuseTokenSource returns a TokenSource that acts in the same manner as the
|
||||||
|
// TokenSource returned by ReuseTokenSource, except the expiry buffer is
|
||||||
|
// configurable. The expiration time of a token is calculated as
|
||||||
|
// t.Expiry.Add(-earlyExpiry).
|
||||||
|
func ReuseTokenSourceWithExpiry(t *Token, src TokenSource, earlyExpiry time.Duration) TokenSource {
|
||||||
|
// Don't wrap a reuseTokenSource in itself. That would work,
|
||||||
|
// but cause an unnecessary number of mutex operations.
|
||||||
|
// Just build the equivalent one.
|
||||||
|
if rt, ok := src.(*reuseTokenSource); ok {
|
||||||
|
if t == nil {
|
||||||
|
// Just use it directly, but set the expiryDelta to earlyExpiry,
|
||||||
|
// so the behavior matches what the user expects.
|
||||||
|
rt.expiryDelta = earlyExpiry
|
||||||
|
return rt
|
||||||
|
}
|
||||||
|
src = rt.new
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
t.expiryDelta = earlyExpiry
|
||||||
|
}
|
||||||
|
return &reuseTokenSource{
|
||||||
|
t: t,
|
||||||
|
new: src,
|
||||||
|
expiryDelta: earlyExpiry,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
14
token.go
14
token.go
@@ -16,10 +16,10 @@ import (
|
|||||||
"golang.org/x/oauth2/internal"
|
"golang.org/x/oauth2/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
// expiryDelta determines how earlier a token should be considered
|
// defaultExpiryDelta determines how earlier a token should be considered
|
||||||
// expired than its actual expiration time. It is used to avoid late
|
// expired than its actual expiration time. It is used to avoid late
|
||||||
// expirations due to client-server time mismatches.
|
// expirations due to client-server time mismatches.
|
||||||
const expiryDelta = 10 * time.Second
|
const defaultExpiryDelta = 10 * time.Second
|
||||||
|
|
||||||
// Token represents the credentials used to authorize
|
// Token represents the credentials used to authorize
|
||||||
// the requests to access protected resources on the OAuth 2.0
|
// the requests to access protected resources on the OAuth 2.0
|
||||||
@@ -52,6 +52,11 @@ type Token struct {
|
|||||||
// raw optionally contains extra metadata from the server
|
// raw optionally contains extra metadata from the server
|
||||||
// when updating a token.
|
// when updating a token.
|
||||||
raw interface{}
|
raw interface{}
|
||||||
|
|
||||||
|
// expiryDelta is used to calculate when a token is considered
|
||||||
|
// expired, by subtracting from Expiry. If zero, defaultExpiryDelta
|
||||||
|
// is used.
|
||||||
|
expiryDelta time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type returns t.TokenType if non-empty, else "Bearer".
|
// Type returns t.TokenType if non-empty, else "Bearer".
|
||||||
@@ -127,6 +132,11 @@ func (t *Token) expired() bool {
|
|||||||
if t.Expiry.IsZero() {
|
if t.Expiry.IsZero() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expiryDelta := defaultExpiryDelta
|
||||||
|
if t.expiryDelta != 0 {
|
||||||
|
expiryDelta = t.expiryDelta
|
||||||
|
}
|
||||||
return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow())
|
return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,9 +43,13 @@ func TestTokenExpiry(t *testing.T) {
|
|||||||
want bool
|
want bool
|
||||||
}{
|
}{
|
||||||
{name: "12 seconds", tok: &Token{Expiry: now.Add(12 * time.Second)}, want: false},
|
{name: "12 seconds", tok: &Token{Expiry: now.Add(12 * time.Second)}, want: false},
|
||||||
{name: "10 seconds", tok: &Token{Expiry: now.Add(expiryDelta)}, want: false},
|
{name: "10 seconds", tok: &Token{Expiry: now.Add(defaultExpiryDelta)}, want: false},
|
||||||
{name: "10 seconds-1ns", tok: &Token{Expiry: now.Add(expiryDelta - 1*time.Nanosecond)}, want: true},
|
{name: "10 seconds-1ns", tok: &Token{Expiry: now.Add(defaultExpiryDelta - 1*time.Nanosecond)}, want: true},
|
||||||
{name: "-1 hour", tok: &Token{Expiry: now.Add(-1 * time.Hour)}, want: true},
|
{name: "-1 hour", tok: &Token{Expiry: now.Add(-1 * time.Hour)}, want: true},
|
||||||
|
{name: "12 seconds, custom expiryDelta", tok: &Token{Expiry: now.Add(12 * time.Second), expiryDelta: time.Second * 5}, want: false},
|
||||||
|
{name: "5 seconds, custom expiryDelta", tok: &Token{Expiry: now.Add(time.Second * 5), expiryDelta: time.Second * 5}, want: false},
|
||||||
|
{name: "5 seconds-1ns, custom expiryDelta", tok: &Token{Expiry: now.Add(time.Second*5 - 1*time.Nanosecond), expiryDelta: time.Second * 5}, want: true},
|
||||||
|
{name: "-1 hour, custom expiryDelta", tok: &Token{Expiry: now.Add(-1 * time.Hour), expiryDelta: time.Second * 5}, want: true},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
if got, want := tc.tok.expired(), tc.want; got != want {
|
if got, want := tc.tok.expired(), tc.want; got != want {
|
||||||
|
|||||||
Reference in New Issue
Block a user