mirror of
https://github.com/rocky-linux/peridot.git
synced 2024-10-18 23:45:08 +00:00
222 lines
7.4 KiB
Go
222 lines
7.4 KiB
Go
|
// Copyright 2023 Google LLC
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
package credentials
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
|
||
|
"cloud.google.com/go/auth"
|
||
|
"cloud.google.com/go/auth/credentials/internal/externalaccount"
|
||
|
"cloud.google.com/go/auth/credentials/internal/externalaccountuser"
|
||
|
"cloud.google.com/go/auth/credentials/internal/gdch"
|
||
|
"cloud.google.com/go/auth/credentials/internal/impersonate"
|
||
|
internalauth "cloud.google.com/go/auth/internal"
|
||
|
"cloud.google.com/go/auth/internal/credsfile"
|
||
|
)
|
||
|
|
||
|
func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
|
||
|
fileType, err := credsfile.ParseFileType(b)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
var projectID, quotaProjectID, universeDomain string
|
||
|
var tp auth.TokenProvider
|
||
|
switch fileType {
|
||
|
case credsfile.ServiceAccountKey:
|
||
|
f, err := credsfile.ParseServiceAccount(b)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
tp, err = handleServiceAccount(f, opts)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
projectID = f.ProjectID
|
||
|
universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
||
|
case credsfile.UserCredentialsKey:
|
||
|
f, err := credsfile.ParseUserCredentials(b)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
tp, err = handleUserCredential(f, opts)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
quotaProjectID = f.QuotaProjectID
|
||
|
universeDomain = f.UniverseDomain
|
||
|
case credsfile.ExternalAccountKey:
|
||
|
f, err := credsfile.ParseExternalAccount(b)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
tp, err = handleExternalAccount(f, opts)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
quotaProjectID = f.QuotaProjectID
|
||
|
universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
||
|
case credsfile.ExternalAccountAuthorizedUserKey:
|
||
|
f, err := credsfile.ParseExternalAccountAuthorizedUser(b)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
tp, err = handleExternalAccountAuthorizedUser(f, opts)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
quotaProjectID = f.QuotaProjectID
|
||
|
universeDomain = f.UniverseDomain
|
||
|
case credsfile.ImpersonatedServiceAccountKey:
|
||
|
f, err := credsfile.ParseImpersonatedServiceAccount(b)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
tp, err = handleImpersonatedServiceAccount(f, opts)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
||
|
case credsfile.GDCHServiceAccountKey:
|
||
|
f, err := credsfile.ParseGDCHServiceAccount(b)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
tp, err = handleGDCHServiceAccount(f, opts)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
projectID = f.Project
|
||
|
universeDomain = f.UniverseDomain
|
||
|
default:
|
||
|
return nil, fmt.Errorf("credentials: unsupported filetype %q", fileType)
|
||
|
}
|
||
|
return auth.NewCredentials(&auth.CredentialsOptions{
|
||
|
TokenProvider: auth.NewCachedTokenProvider(tp, &auth.CachedTokenProviderOptions{
|
||
|
ExpireEarly: opts.EarlyTokenRefresh,
|
||
|
}),
|
||
|
JSON: b,
|
||
|
ProjectIDProvider: internalauth.StaticCredentialsProperty(projectID),
|
||
|
QuotaProjectIDProvider: internalauth.StaticCredentialsProperty(quotaProjectID),
|
||
|
UniverseDomainProvider: internalauth.StaticCredentialsProperty(universeDomain),
|
||
|
}), nil
|
||
|
}
|
||
|
|
||
|
// resolveUniverseDomain returns optsUniverseDomain if non-empty, in order to
|
||
|
// support configuring universe-specific credentials in code. Auth flows
|
||
|
// unsupported for universe domain should not use this func, but should instead
|
||
|
// simply set the file universe domain on the credentials.
|
||
|
func resolveUniverseDomain(optsUniverseDomain, fileUniverseDomain string) string {
|
||
|
if optsUniverseDomain != "" {
|
||
|
return optsUniverseDomain
|
||
|
}
|
||
|
return fileUniverseDomain
|
||
|
}
|
||
|
|
||
|
func handleServiceAccount(f *credsfile.ServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||
|
if opts.UseSelfSignedJWT {
|
||
|
return configureSelfSignedJWT(f, opts)
|
||
|
}
|
||
|
opts2LO := &auth.Options2LO{
|
||
|
Email: f.ClientEmail,
|
||
|
PrivateKey: []byte(f.PrivateKey),
|
||
|
PrivateKeyID: f.PrivateKeyID,
|
||
|
Scopes: opts.scopes(),
|
||
|
TokenURL: f.TokenURL,
|
||
|
Subject: opts.Subject,
|
||
|
Client: opts.client(),
|
||
|
}
|
||
|
if opts2LO.TokenURL == "" {
|
||
|
opts2LO.TokenURL = jwtTokenURL
|
||
|
}
|
||
|
return auth.New2LOTokenProvider(opts2LO)
|
||
|
}
|
||
|
|
||
|
func handleUserCredential(f *credsfile.UserCredentialsFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||
|
opts3LO := &auth.Options3LO{
|
||
|
ClientID: f.ClientID,
|
||
|
ClientSecret: f.ClientSecret,
|
||
|
Scopes: opts.scopes(),
|
||
|
AuthURL: googleAuthURL,
|
||
|
TokenURL: opts.tokenURL(),
|
||
|
AuthStyle: auth.StyleInParams,
|
||
|
EarlyTokenExpiry: opts.EarlyTokenRefresh,
|
||
|
RefreshToken: f.RefreshToken,
|
||
|
Client: opts.client(),
|
||
|
}
|
||
|
return auth.New3LOTokenProvider(opts3LO)
|
||
|
}
|
||
|
|
||
|
func handleExternalAccount(f *credsfile.ExternalAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||
|
externalOpts := &externalaccount.Options{
|
||
|
Audience: f.Audience,
|
||
|
SubjectTokenType: f.SubjectTokenType,
|
||
|
TokenURL: f.TokenURL,
|
||
|
TokenInfoURL: f.TokenInfoURL,
|
||
|
ServiceAccountImpersonationURL: f.ServiceAccountImpersonationURL,
|
||
|
ClientSecret: f.ClientSecret,
|
||
|
ClientID: f.ClientID,
|
||
|
CredentialSource: f.CredentialSource,
|
||
|
QuotaProjectID: f.QuotaProjectID,
|
||
|
Scopes: opts.scopes(),
|
||
|
WorkforcePoolUserProject: f.WorkforcePoolUserProject,
|
||
|
Client: opts.client(),
|
||
|
}
|
||
|
if f.ServiceAccountImpersonation != nil {
|
||
|
externalOpts.ServiceAccountImpersonationLifetimeSeconds = f.ServiceAccountImpersonation.TokenLifetimeSeconds
|
||
|
}
|
||
|
return externalaccount.NewTokenProvider(externalOpts)
|
||
|
}
|
||
|
|
||
|
func handleExternalAccountAuthorizedUser(f *credsfile.ExternalAccountAuthorizedUserFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||
|
externalOpts := &externalaccountuser.Options{
|
||
|
Audience: f.Audience,
|
||
|
RefreshToken: f.RefreshToken,
|
||
|
TokenURL: f.TokenURL,
|
||
|
TokenInfoURL: f.TokenInfoURL,
|
||
|
ClientID: f.ClientID,
|
||
|
ClientSecret: f.ClientSecret,
|
||
|
Scopes: opts.scopes(),
|
||
|
Client: opts.client(),
|
||
|
}
|
||
|
return externalaccountuser.NewTokenProvider(externalOpts)
|
||
|
}
|
||
|
|
||
|
func handleImpersonatedServiceAccount(f *credsfile.ImpersonatedServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||
|
if f.ServiceAccountImpersonationURL == "" || f.CredSource == nil {
|
||
|
return nil, errors.New("missing 'source_credentials' field or 'service_account_impersonation_url' in credentials")
|
||
|
}
|
||
|
|
||
|
tp, err := fileCredentials(f.CredSource, opts)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return impersonate.NewTokenProvider(&impersonate.Options{
|
||
|
URL: f.ServiceAccountImpersonationURL,
|
||
|
Scopes: opts.scopes(),
|
||
|
Tp: tp,
|
||
|
Delegates: f.Delegates,
|
||
|
Client: opts.client(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func handleGDCHServiceAccount(f *credsfile.GDCHServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||
|
return gdch.NewTokenProvider(f, &gdch.Options{
|
||
|
STSAudience: opts.STSAudience,
|
||
|
Client: opts.client(),
|
||
|
})
|
||
|
}
|