file_provider.go

 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
15package externalaccount
16
17import (
18	"bytes"
19	"context"
20	"encoding/json"
21	"errors"
22	"fmt"
23	"os"
24
25	"cloud.google.com/go/auth/internal"
26	"cloud.google.com/go/auth/internal/credsfile"
27)
28
29const (
30	fileProviderType = "file"
31)
32
33type fileSubjectProvider struct {
34	File   string
35	Format *credsfile.Format
36}
37
38func (sp *fileSubjectProvider) subjectToken(context.Context) (string, error) {
39	tokenFile, err := os.Open(sp.File)
40	if err != nil {
41		return "", fmt.Errorf("credentials: failed to open credential file %q: %w", sp.File, err)
42	}
43	defer tokenFile.Close()
44	tokenBytes, err := internal.ReadAll(tokenFile)
45	if err != nil {
46		return "", fmt.Errorf("credentials: failed to read credential file: %w", err)
47	}
48	tokenBytes = bytes.TrimSpace(tokenBytes)
49
50	if sp.Format == nil {
51		return string(tokenBytes), nil
52	}
53	switch sp.Format.Type {
54	case fileTypeJSON:
55		jsonData := make(map[string]interface{})
56		err = json.Unmarshal(tokenBytes, &jsonData)
57		if err != nil {
58			return "", fmt.Errorf("credentials: failed to unmarshal subject token file: %w", err)
59		}
60		val, ok := jsonData[sp.Format.SubjectTokenFieldName]
61		if !ok {
62			return "", errors.New("credentials: provided subject_token_field_name not found in credentials")
63		}
64		token, ok := val.(string)
65		if !ok {
66			return "", errors.New("credentials: improperly formatted subject token")
67		}
68		return token, nil
69	case fileTypeText:
70		return string(tokenBytes), nil
71	default:
72		return "", errors.New("credentials: invalid credential_source file format type: " + sp.Format.Type)
73	}
74}
75
76func (sp *fileSubjectProvider) providerType() string {
77	return fileProviderType
78}