...

Source file src/cloud.google.com/go/auth/oauth2adapt/oauth2adapt.go

Documentation: cloud.google.com/go/auth/oauth2adapt

     1  // Copyright 2023 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package oauth2adapt helps converts types used in [cloud.google.com/go/auth]
    16  // and [golang.org/x/oauth2].
    17  package oauth2adapt
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"errors"
    23  
    24  	"cloud.google.com/go/auth"
    25  	"golang.org/x/oauth2"
    26  	"golang.org/x/oauth2/google"
    27  )
    28  
    29  // TokenProviderFromTokenSource converts any [golang.org/x/oauth2.TokenSource]
    30  // into a [cloud.google.com/go/auth.TokenProvider].
    31  func TokenProviderFromTokenSource(ts oauth2.TokenSource) auth.TokenProvider {
    32  	return &tokenProviderAdapter{ts: ts}
    33  }
    34  
    35  type tokenProviderAdapter struct {
    36  	ts oauth2.TokenSource
    37  }
    38  
    39  // Token fulfills the [cloud.google.com/go/auth.TokenProvider] interface. It
    40  // is a light wrapper around the underlying TokenSource.
    41  func (tp *tokenProviderAdapter) Token(context.Context) (*auth.Token, error) {
    42  	tok, err := tp.ts.Token()
    43  	if err != nil {
    44  		var err2 *oauth2.RetrieveError
    45  		if ok := errors.As(err, &err2); ok {
    46  			return nil, AuthErrorFromRetrieveError(err2)
    47  		}
    48  		return nil, err
    49  	}
    50  	return &auth.Token{
    51  		Value:  tok.AccessToken,
    52  		Type:   tok.Type(),
    53  		Expiry: tok.Expiry,
    54  	}, nil
    55  }
    56  
    57  // TokenSourceFromTokenProvider converts any
    58  // [cloud.google.com/go/auth.TokenProvider] into a
    59  // [golang.org/x/oauth2.TokenSource].
    60  func TokenSourceFromTokenProvider(tp auth.TokenProvider) oauth2.TokenSource {
    61  	return &tokenSourceAdapter{tp: tp}
    62  }
    63  
    64  type tokenSourceAdapter struct {
    65  	tp auth.TokenProvider
    66  }
    67  
    68  // Token fulfills the [golang.org/x/oauth2.TokenSource] interface. It
    69  // is a light wrapper around the underlying TokenProvider.
    70  func (ts *tokenSourceAdapter) Token() (*oauth2.Token, error) {
    71  	tok, err := ts.tp.Token(context.Background())
    72  	if err != nil {
    73  		var err2 *auth.Error
    74  		if ok := errors.As(err, &err2); ok {
    75  			return nil, AddRetrieveErrorToAuthError(err2)
    76  		}
    77  		return nil, err
    78  	}
    79  	return &oauth2.Token{
    80  		AccessToken: tok.Value,
    81  		TokenType:   tok.Type,
    82  		Expiry:      tok.Expiry,
    83  	}, nil
    84  }
    85  
    86  // AuthCredentialsFromOauth2Credentials converts a [golang.org/x/oauth2/google.Credentials]
    87  // to a [cloud.google.com/go/auth.Credentials].
    88  func AuthCredentialsFromOauth2Credentials(creds *google.Credentials) *auth.Credentials {
    89  	if creds == nil {
    90  		return nil
    91  	}
    92  	return auth.NewCredentials(&auth.CredentialsOptions{
    93  		TokenProvider: TokenProviderFromTokenSource(creds.TokenSource),
    94  		JSON:          creds.JSON,
    95  		ProjectIDProvider: auth.CredentialsPropertyFunc(func(ctx context.Context) (string, error) {
    96  			return creds.ProjectID, nil
    97  		}),
    98  		UniverseDomainProvider: auth.CredentialsPropertyFunc(func(ctx context.Context) (string, error) {
    99  			return creds.GetUniverseDomain()
   100  		}),
   101  	})
   102  }
   103  
   104  // Oauth2CredentialsFromAuthCredentials converts a [cloud.google.com/go/auth.Credentials]
   105  // to a [golang.org/x/oauth2/google.Credentials].
   106  func Oauth2CredentialsFromAuthCredentials(creds *auth.Credentials) *google.Credentials {
   107  	if creds == nil {
   108  		return nil
   109  	}
   110  	// Throw away errors as old credentials are not request aware. Also, no
   111  	// network requests are currently happening for this use case.
   112  	projectID, _ := creds.ProjectID(context.Background())
   113  
   114  	return &google.Credentials{
   115  		TokenSource: TokenSourceFromTokenProvider(creds.TokenProvider),
   116  		ProjectID:   projectID,
   117  		JSON:        creds.JSON(),
   118  		UniverseDomainProvider: func() (string, error) {
   119  			return creds.UniverseDomain(context.Background())
   120  		},
   121  	}
   122  }
   123  
   124  type oauth2Error struct {
   125  	ErrorCode        string `json:"error"`
   126  	ErrorDescription string `json:"error_description"`
   127  	ErrorURI         string `json:"error_uri"`
   128  }
   129  
   130  // AddRetrieveErrorToAuthError returns the same error provided and adds a
   131  // [golang.org/x/oauth2.RetrieveError] to the error chain by setting the `Err` field on the
   132  // [cloud.google.com/go/auth.Error].
   133  func AddRetrieveErrorToAuthError(err *auth.Error) *auth.Error {
   134  	if err == nil {
   135  		return nil
   136  	}
   137  	e := &oauth2.RetrieveError{
   138  		Response: err.Response,
   139  		Body:     err.Body,
   140  	}
   141  	err.Err = e
   142  	if len(err.Body) > 0 {
   143  		var oErr oauth2Error
   144  		// ignore the error as it only fills in extra details
   145  		json.Unmarshal(err.Body, &oErr)
   146  		e.ErrorCode = oErr.ErrorCode
   147  		e.ErrorDescription = oErr.ErrorDescription
   148  		e.ErrorURI = oErr.ErrorURI
   149  	}
   150  	return err
   151  }
   152  
   153  // AuthErrorFromRetrieveError returns an [cloud.google.com/go/auth.Error] that
   154  // wraps the provided [golang.org/x/oauth2.RetrieveError].
   155  func AuthErrorFromRetrieveError(err *oauth2.RetrieveError) *auth.Error {
   156  	if err == nil {
   157  		return nil
   158  	}
   159  	return &auth.Error{
   160  		Response: err.Response,
   161  		Body:     err.Body,
   162  		Err:      err,
   163  	}
   164  }
   165  

View as plain text