urlcredsource.go raw
1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package externalaccount
6
7 import (
8 "context"
9 "encoding/json"
10 "errors"
11 "fmt"
12 "io"
13 "net/http"
14
15 "golang.org/x/oauth2"
16 )
17
18 type urlCredentialSource struct {
19 URL string
20 Headers map[string]string
21 Format Format
22 ctx context.Context
23 }
24
25 func (cs urlCredentialSource) credentialSourceType() string {
26 return "url"
27 }
28
29 func (cs urlCredentialSource) subjectToken() (string, error) {
30 client := oauth2.NewClient(cs.ctx, nil)
31 req, err := http.NewRequest("GET", cs.URL, nil)
32 if err != nil {
33 return "", fmt.Errorf("oauth2/google/externalaccount: HTTP request for URL-sourced credential failed: %v", err)
34 }
35 req = req.WithContext(cs.ctx)
36
37 for key, val := range cs.Headers {
38 req.Header.Add(key, val)
39 }
40 resp, err := client.Do(req)
41 if err != nil {
42 return "", fmt.Errorf("oauth2/google/externalaccount: invalid response when retrieving subject token: %v", err)
43 }
44 defer resp.Body.Close()
45
46 respBody, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
47 if err != nil {
48 return "", fmt.Errorf("oauth2/google/externalaccount: invalid body in subject token URL query: %v", err)
49 }
50 if c := resp.StatusCode; c < 200 || c > 299 {
51 return "", fmt.Errorf("oauth2/google/externalaccount: status code %d: %s", c, respBody)
52 }
53
54 switch cs.Format.Type {
55 case "json":
56 jsonData := make(map[string]any)
57 err = json.Unmarshal(respBody, &jsonData)
58 if err != nil {
59 return "", fmt.Errorf("oauth2/google/externalaccount: failed to unmarshal subject token file: %v", err)
60 }
61 val, ok := jsonData[cs.Format.SubjectTokenFieldName]
62 if !ok {
63 return "", errors.New("oauth2/google/externalaccount: provided subject_token_field_name not found in credentials")
64 }
65 token, ok := val.(string)
66 if !ok {
67 return "", errors.New("oauth2/google/externalaccount: improperly formatted subject token")
68 }
69 return token, nil
70 case "text":
71 return string(respBody), nil
72 case "":
73 return string(respBody), nil
74 default:
75 return "", errors.New("oauth2/google/externalaccount: invalid credential_source file format type")
76 }
77
78 }
79