mirror of
https://github.com/golang/oauth2.git
synced 2025-07-21 00:00:09 +08:00
google: Wrap token sources in errWrappingTokenSource
Introduce new AuthenticationError type returned by errWrappingTokenSource.Token. The new error wrapper exposes a boolean method Temporary, identifying the underlying network error as retryable based on the following status codes: 500, 503, 408, or 429. Bump go.mod version to 1.15 refs: https://github.com/googleapis/google-api-go-client/issues/1445 Change-Id: I27c76cb0c71b918c25a640f40d0bd515b2e488fc Reviewed-on: https://go-review.googlesource.com/c/oauth2/+/403846 Reviewed-by: Cody Oss <codyoss@google.com> Reviewed-by: Tyler Bui-Palsulich <tbp@google.com>
This commit is contained in:
parent
622c5d57e4
commit
d0670ef3b1
2
go.mod
2
go.mod
@ -1,6 +1,6 @@
|
||||
module golang.org/x/oauth2
|
||||
|
||||
go 1.11
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.65.0
|
||||
|
@ -190,6 +190,7 @@ func CredentialsFromJSONWithParams(ctx context.Context, jsonData []byte, params
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts = newErrWrappingTokenSource(ts)
|
||||
return &DefaultCredentials{
|
||||
ProjectID: f.ProjectID,
|
||||
TokenSource: ts,
|
||||
|
64
google/error.go
Normal file
64
google/error.go
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2022 The Go 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 google
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// AuthenticationError indicates there was an error in the authentication flow.
|
||||
//
|
||||
// Use (*AuthenticationError).Temporary to check if the error can be retried.
|
||||
type AuthenticationError struct {
|
||||
err *oauth2.RetrieveError
|
||||
}
|
||||
|
||||
func newAuthenticationError(err error) error {
|
||||
re := &oauth2.RetrieveError{}
|
||||
if !errors.As(err, &re) {
|
||||
return err
|
||||
}
|
||||
return &AuthenticationError{
|
||||
err: re,
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary indicates that the network error has one of the following status codes and may be retried: 500, 503, 408, or 429.
|
||||
func (e *AuthenticationError) Temporary() bool {
|
||||
if e.err.Response == nil {
|
||||
return false
|
||||
}
|
||||
sc := e.err.Response.StatusCode
|
||||
return sc == 500 || sc == 503 || sc == 408 || sc == 429
|
||||
}
|
||||
|
||||
func (e *AuthenticationError) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
func (e *AuthenticationError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
type errWrappingTokenSource struct {
|
||||
src oauth2.TokenSource
|
||||
}
|
||||
|
||||
func newErrWrappingTokenSource(ts oauth2.TokenSource) oauth2.TokenSource {
|
||||
return &errWrappingTokenSource{src: ts}
|
||||
}
|
||||
|
||||
// Token returns the current token if it's still valid, else will
|
||||
// refresh the current token (using r.Context for HTTP client
|
||||
// information) and return the new one.
|
||||
func (s *errWrappingTokenSource) Token() (*oauth2.Token, error) {
|
||||
t, err := s.src.Token()
|
||||
if err != nil {
|
||||
return nil, newAuthenticationError(err)
|
||||
}
|
||||
return t, nil
|
||||
}
|
111
google/error_test.go
Normal file
111
google/error_test.go
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright 2022 The Go 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 google
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
func TestAuthenticationError_Temporary(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
code int
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "temporary with 500",
|
||||
code: 500,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "temporary with 503",
|
||||
code: 503,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "temporary with 408",
|
||||
code: 408,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "temporary with 429",
|
||||
code: 429,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "temporary with 418",
|
||||
code: 418,
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ae := &AuthenticationError{
|
||||
err: &oauth2.RetrieveError{
|
||||
Response: &http.Response{
|
||||
StatusCode: tt.code,
|
||||
},
|
||||
},
|
||||
}
|
||||
if got := ae.Temporary(); got != tt.want {
|
||||
t.Errorf("Temporary() = %v; want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrWrappingTokenSource_Token(t *testing.T) {
|
||||
tok := oauth2.Token{AccessToken: "MyAccessToken"}
|
||||
ts := errWrappingTokenSource{
|
||||
src: oauth2.StaticTokenSource(&tok),
|
||||
}
|
||||
got, err := ts.Token()
|
||||
if *got != tok {
|
||||
t.Errorf("Token() = %v; want %v", got, tok)
|
||||
}
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
type errTokenSource struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (s *errTokenSource) Token() (*oauth2.Token, error) {
|
||||
return nil, s.err
|
||||
}
|
||||
|
||||
func TestErrWrappingTokenSource_TokenError(t *testing.T) {
|
||||
re := &oauth2.RetrieveError{
|
||||
Response: &http.Response{
|
||||
StatusCode: 500,
|
||||
},
|
||||
}
|
||||
ts := errWrappingTokenSource{
|
||||
src: &errTokenSource{
|
||||
err: re,
|
||||
},
|
||||
}
|
||||
_, err := ts.Token()
|
||||
if err == nil {
|
||||
t.Fatalf("errWrappingTokenSource.Token() err = nil, want *AuthenticationError")
|
||||
}
|
||||
ae, ok := err.(*AuthenticationError)
|
||||
if !ok {
|
||||
t.Fatalf("errWrappingTokenSource.Token() err = %T, want *AuthenticationError", err)
|
||||
}
|
||||
wrappedErr := ae.Unwrap()
|
||||
if wrappedErr == nil {
|
||||
t.Fatalf("AuthenticationError.Unwrap() err = nil, want *oauth2.RetrieveError")
|
||||
}
|
||||
_, ok = wrappedErr.(*oauth2.RetrieveError)
|
||||
if !ok {
|
||||
t.Errorf("AuthenticationError.Unwrap() err = %T, want *oauth2.RetrieveError", err)
|
||||
}
|
||||
}
|
@ -66,7 +66,8 @@ func newJWTSource(jsonKey []byte, audience string, scopes []string) (oauth2.Toke
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return oauth2.ReuseTokenSource(tok, ts), nil
|
||||
rts := newErrWrappingTokenSource(oauth2.ReuseTokenSource(tok, ts))
|
||||
return rts, nil
|
||||
}
|
||||
|
||||
type jwtAccessTokenSource struct {
|
||||
|
Loading…
x
Reference in New Issue
Block a user