...

Source file src/cloud.google.com/go/auth/credentials/filetypes.go

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

     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 credentials
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  
    21  	"cloud.google.com/go/auth"
    22  	"cloud.google.com/go/auth/credentials/internal/externalaccount"
    23  	"cloud.google.com/go/auth/credentials/internal/externalaccountuser"
    24  	"cloud.google.com/go/auth/credentials/internal/gdch"
    25  	"cloud.google.com/go/auth/credentials/internal/impersonate"
    26  	internalauth "cloud.google.com/go/auth/internal"
    27  	"cloud.google.com/go/auth/internal/credsfile"
    28  )
    29  
    30  func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
    31  	fileType, err := credsfile.ParseFileType(b)
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  
    36  	var projectID, quotaProjectID, universeDomain string
    37  	var tp auth.TokenProvider
    38  	switch fileType {
    39  	case credsfile.ServiceAccountKey:
    40  		f, err := credsfile.ParseServiceAccount(b)
    41  		if err != nil {
    42  			return nil, err
    43  		}
    44  		tp, err = handleServiceAccount(f, opts)
    45  		if err != nil {
    46  			return nil, err
    47  		}
    48  		projectID = f.ProjectID
    49  		universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
    50  	case credsfile.UserCredentialsKey:
    51  		f, err := credsfile.ParseUserCredentials(b)
    52  		if err != nil {
    53  			return nil, err
    54  		}
    55  		tp, err = handleUserCredential(f, opts)
    56  		if err != nil {
    57  			return nil, err
    58  		}
    59  		quotaProjectID = f.QuotaProjectID
    60  		universeDomain = f.UniverseDomain
    61  	case credsfile.ExternalAccountKey:
    62  		f, err := credsfile.ParseExternalAccount(b)
    63  		if err != nil {
    64  			return nil, err
    65  		}
    66  		tp, err = handleExternalAccount(f, opts)
    67  		if err != nil {
    68  			return nil, err
    69  		}
    70  		quotaProjectID = f.QuotaProjectID
    71  		universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
    72  	case credsfile.ExternalAccountAuthorizedUserKey:
    73  		f, err := credsfile.ParseExternalAccountAuthorizedUser(b)
    74  		if err != nil {
    75  			return nil, err
    76  		}
    77  		tp, err = handleExternalAccountAuthorizedUser(f, opts)
    78  		if err != nil {
    79  			return nil, err
    80  		}
    81  		quotaProjectID = f.QuotaProjectID
    82  		universeDomain = f.UniverseDomain
    83  	case credsfile.ImpersonatedServiceAccountKey:
    84  		f, err := credsfile.ParseImpersonatedServiceAccount(b)
    85  		if err != nil {
    86  			return nil, err
    87  		}
    88  		tp, err = handleImpersonatedServiceAccount(f, opts)
    89  		if err != nil {
    90  			return nil, err
    91  		}
    92  		universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
    93  	case credsfile.GDCHServiceAccountKey:
    94  		f, err := credsfile.ParseGDCHServiceAccount(b)
    95  		if err != nil {
    96  			return nil, err
    97  		}
    98  		tp, err = handleGDCHServiceAccount(f, opts)
    99  		if err != nil {
   100  			return nil, err
   101  		}
   102  		projectID = f.Project
   103  		universeDomain = f.UniverseDomain
   104  	default:
   105  		return nil, fmt.Errorf("credentials: unsupported filetype %q", fileType)
   106  	}
   107  	return auth.NewCredentials(&auth.CredentialsOptions{
   108  		TokenProvider: auth.NewCachedTokenProvider(tp, &auth.CachedTokenProviderOptions{
   109  			ExpireEarly: opts.EarlyTokenRefresh,
   110  		}),
   111  		JSON:                   b,
   112  		ProjectIDProvider:      internalauth.StaticCredentialsProperty(projectID),
   113  		QuotaProjectIDProvider: internalauth.StaticCredentialsProperty(quotaProjectID),
   114  		UniverseDomainProvider: internalauth.StaticCredentialsProperty(universeDomain),
   115  	}), nil
   116  }
   117  
   118  // resolveUniverseDomain returns optsUniverseDomain if non-empty, in order to
   119  // support configuring universe-specific credentials in code. Auth flows
   120  // unsupported for universe domain should not use this func, but should instead
   121  // simply set the file universe domain on the credentials.
   122  func resolveUniverseDomain(optsUniverseDomain, fileUniverseDomain string) string {
   123  	if optsUniverseDomain != "" {
   124  		return optsUniverseDomain
   125  	}
   126  	return fileUniverseDomain
   127  }
   128  
   129  func handleServiceAccount(f *credsfile.ServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
   130  	if opts.UseSelfSignedJWT {
   131  		return configureSelfSignedJWT(f, opts)
   132  	}
   133  	opts2LO := &auth.Options2LO{
   134  		Email:        f.ClientEmail,
   135  		PrivateKey:   []byte(f.PrivateKey),
   136  		PrivateKeyID: f.PrivateKeyID,
   137  		Scopes:       opts.scopes(),
   138  		TokenURL:     f.TokenURL,
   139  		Subject:      opts.Subject,
   140  	}
   141  	if opts2LO.TokenURL == "" {
   142  		opts2LO.TokenURL = jwtTokenURL
   143  	}
   144  	return auth.New2LOTokenProvider(opts2LO)
   145  }
   146  
   147  func handleUserCredential(f *credsfile.UserCredentialsFile, opts *DetectOptions) (auth.TokenProvider, error) {
   148  	opts3LO := &auth.Options3LO{
   149  		ClientID:         f.ClientID,
   150  		ClientSecret:     f.ClientSecret,
   151  		Scopes:           opts.scopes(),
   152  		AuthURL:          googleAuthURL,
   153  		TokenURL:         opts.tokenURL(),
   154  		AuthStyle:        auth.StyleInParams,
   155  		EarlyTokenExpiry: opts.EarlyTokenRefresh,
   156  		RefreshToken:     f.RefreshToken,
   157  	}
   158  	return auth.New3LOTokenProvider(opts3LO)
   159  }
   160  
   161  func handleExternalAccount(f *credsfile.ExternalAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
   162  	externalOpts := &externalaccount.Options{
   163  		Audience:                       f.Audience,
   164  		SubjectTokenType:               f.SubjectTokenType,
   165  		TokenURL:                       f.TokenURL,
   166  		TokenInfoURL:                   f.TokenInfoURL,
   167  		ServiceAccountImpersonationURL: f.ServiceAccountImpersonationURL,
   168  		ClientSecret:                   f.ClientSecret,
   169  		ClientID:                       f.ClientID,
   170  		CredentialSource:               f.CredentialSource,
   171  		QuotaProjectID:                 f.QuotaProjectID,
   172  		Scopes:                         opts.scopes(),
   173  		WorkforcePoolUserProject:       f.WorkforcePoolUserProject,
   174  		Client:                         opts.client(),
   175  	}
   176  	if f.ServiceAccountImpersonation != nil {
   177  		externalOpts.ServiceAccountImpersonationLifetimeSeconds = f.ServiceAccountImpersonation.TokenLifetimeSeconds
   178  	}
   179  	return externalaccount.NewTokenProvider(externalOpts)
   180  }
   181  
   182  func handleExternalAccountAuthorizedUser(f *credsfile.ExternalAccountAuthorizedUserFile, opts *DetectOptions) (auth.TokenProvider, error) {
   183  	externalOpts := &externalaccountuser.Options{
   184  		Audience:     f.Audience,
   185  		RefreshToken: f.RefreshToken,
   186  		TokenURL:     f.TokenURL,
   187  		TokenInfoURL: f.TokenInfoURL,
   188  		ClientID:     f.ClientID,
   189  		ClientSecret: f.ClientSecret,
   190  		Scopes:       opts.scopes(),
   191  		Client:       opts.client(),
   192  	}
   193  	return externalaccountuser.NewTokenProvider(externalOpts)
   194  }
   195  
   196  func handleImpersonatedServiceAccount(f *credsfile.ImpersonatedServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
   197  	if f.ServiceAccountImpersonationURL == "" || f.CredSource == nil {
   198  		return nil, errors.New("missing 'source_credentials' field or 'service_account_impersonation_url' in credentials")
   199  	}
   200  
   201  	tp, err := fileCredentials(f.CredSource, opts)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  	return impersonate.NewTokenProvider(&impersonate.Options{
   206  		URL:       f.ServiceAccountImpersonationURL,
   207  		Scopes:    opts.scopes(),
   208  		Tp:        tp,
   209  		Delegates: f.Delegates,
   210  		Client:    opts.client(),
   211  	})
   212  }
   213  
   214  func handleGDCHServiceAccount(f *credsfile.GDCHServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
   215  	return gdch.NewTokenProvider(f, &gdch.Options{
   216  		STSAudience: opts.STSAudience,
   217  		Client:      opts.client(),
   218  	})
   219  }
   220  

View as plain text