components/google-built-opentelemetry-collector/extension/oauth2clientauthextension/clientcredentialsconfig.go (66 lines of code) (raw):
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package oauth2clientauthextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/oauth2clientauthextension"
import (
"context"
"fmt"
"os"
"strings"
"time"
"go.uber.org/multierr"
"golang.org/x/oauth2"
"golang.org/x/oauth2/clientcredentials"
)
// clientCredentialsConfig is a clientcredentials.Config wrapper to allow
// values read from files in the ClientID and ClientSecret fields.
//
// Values from files can be retrieved by populating the ClientIDFile or
// the ClientSecretFile fields with the path to the file.
//
// Priority: File > Raw value
//
// Example - Retrieve secret from file:
//
// cfg := clientCredentialsConfig{
// Config: clientcredentials.Config{
// ClientID: "clientId",
// ...
// },
// ClientSecretFile: "/path/to/client/secret",
// }
type clientCredentialsConfig struct {
clientcredentials.Config
ClientIDFile string
ClientSecretFile string
ExpiryBuffer time.Duration
}
type clientCredentialsTokenSource struct {
ctx context.Context
config *clientCredentialsConfig
}
// clientCredentialsTokenSource implements TokenSource
var _ oauth2.TokenSource = (*clientCredentialsTokenSource)(nil)
func readCredentialsFile(path string) (string, error) {
f, err := os.ReadFile(path)
if err != nil {
return "", fmt.Errorf("failed to read credentials file %q: %w", path, err)
}
credential := strings.TrimSpace(string(f))
if credential == "" {
return "", fmt.Errorf("empty credentials file %q", path)
}
return credential, nil
}
func getActualValue(value, filepath string) (string, error) {
if len(filepath) > 0 {
return readCredentialsFile(filepath)
}
return value, nil
}
// createConfig creates a proper clientcredentials.Config with values retrieved
// from files, if the user has specified '*_file' values
func (c *clientCredentialsConfig) createConfig() (*clientcredentials.Config, error) {
clientID, err := getActualValue(c.ClientID, c.ClientIDFile)
if err != nil {
return nil, multierr.Combine(errNoClientIDProvided, err)
}
clientSecret, err := getActualValue(c.ClientSecret, c.ClientSecretFile)
if err != nil {
return nil, multierr.Combine(errNoClientSecretProvided, err)
}
return &clientcredentials.Config{
ClientID: clientID,
ClientSecret: clientSecret,
TokenURL: c.TokenURL,
Scopes: c.Scopes,
EndpointParams: c.EndpointParams,
}, nil
}
func (c *clientCredentialsConfig) TokenSource(ctx context.Context) oauth2.TokenSource {
return oauth2.ReuseTokenSourceWithExpiry(nil, clientCredentialsTokenSource{ctx: ctx, config: c}, c.ExpiryBuffer)
}
func (ts clientCredentialsTokenSource) Token() (*oauth2.Token, error) {
cfg, err := ts.config.createConfig()
if err != nil {
return nil, err
}
return cfg.TokenSource(ts.ctx).Token()
}