Skip to content

Commit df9bbd8

Browse files
committed
add input validation
1 parent e8ef4a0 commit df9bbd8

File tree

1 file changed

+36
-9
lines changed

1 file changed

+36
-9
lines changed

google/delegate.go

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,22 @@ package google
77
import (
88
"context"
99
"fmt"
10+
"regexp"
11+
"strings"
1012
"sync"
1113
"time"
1214

1315
"golang.org/x/oauth2"
1416
"google.golang.org/api/iamcredentials/v1"
1517
)
1618

19+
var (
20+
mu sync.Mutex
21+
tok *oauth2.Token
22+
)
23+
24+
const emailRegex string = "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"
25+
1726
// DelegateTokenSource allows a TokenSource issued to a user or
1827
// service account to impersonate another. The target service account
1928
// must grant the orginating principal the
@@ -25,7 +34,7 @@ import (
2534
// rootSource *must* include scopes that contains
2635
// "https://www.googleapis.com/auth/iam"
2736
// or
28-
// "https://www.googleapis.com/auth/cloud-platform"
37+
// "https://www.googleapis.com/auth/cloud.platform"
2938
// principal (string): The service account to impersonate.
3039
// new_scopes ([]string): Scopes to request during the
3140
// authorization grant.
@@ -54,6 +63,29 @@ func DelegateTokenSource(ctx context.Context, rootSource oauth2.TokenSource,
5463
principal string, lifetime time.Duration, delegates []string,
5564
newScopes []string) (oauth2.TokenSource, error) {
5665

66+
reEmail := regexp.MustCompile(emailRegex)
67+
scopePrefix := "https://www.googleapis.com/auth/"
68+
69+
if rootSource == nil {
70+
return nil, fmt.Errorf("oauth2/google: rootSource cannot be nil")
71+
}
72+
if !reEmail.MatchString(principal) {
73+
return nil, fmt.Errorf("oauth2/google: principal must be a serviceAccount email address")
74+
}
75+
if lifetime <= time.Duration(3600) {
76+
return nil, fmt.Errorf("oauth2/google: lifetime must be less than or equal to 3600 seconds")
77+
}
78+
for _, d := range delegates {
79+
if !reEmail.MatchString(d) {
80+
return nil, fmt.Errorf("oauth2/google: delegates must be a serviceAccount email address: %v", d)
81+
}
82+
}
83+
for _, s := range newScopes {
84+
if !strings.HasPrefix(s, scopePrefix) {
85+
return nil, fmt.Errorf("oauth2/google: scopes must be a Google Auth scope url: %v", s)
86+
}
87+
}
88+
5789
return &delegateTokenSource{
5890
ctx: ctx,
5991
rootSource: rootSource,
@@ -73,11 +105,6 @@ type delegateTokenSource struct {
73105
newScopes []string
74106
}
75107

76-
var (
77-
mu sync.Mutex
78-
tok *oauth2.Token
79-
)
80-
81108
func (ts *delegateTokenSource) Token() (*oauth2.Token, error) {
82109

83110
mu.Lock()
@@ -91,7 +118,7 @@ func (ts *delegateTokenSource) Token() (*oauth2.Token, error) {
91118

92119
service, err := iamcredentials.New(client)
93120
if err != nil {
94-
return nil, fmt.Errorf("google: Error creating IAMCredentials: %v", err)
121+
return nil, fmt.Errorf("oauth2/google: Error creating IAMCredentials: %v", err)
95122
}
96123
name := "projects/-/serviceAccounts/" + ts.principal
97124
tokenRequest := &iamcredentials.GenerateAccessTokenRequest{
@@ -101,12 +128,12 @@ func (ts *delegateTokenSource) Token() (*oauth2.Token, error) {
101128
}
102129
at, err := service.Projects.ServiceAccounts.GenerateAccessToken(name, tokenRequest).Do()
103130
if err != nil {
104-
return nil, fmt.Errorf("google: Error calling iamcredentials.GenerateAccessToken: %v", err)
131+
return nil, fmt.Errorf("oauth2/google: Error calling iamcredentials.GenerateAccessToken: %v", err)
105132
}
106133

107134
expireAt, err := time.Parse(time.RFC3339, at.ExpireTime)
108135
if err != nil {
109-
return nil, fmt.Errorf("google: Error parsing ExpireTime from iamcredentials: %v", err)
136+
return nil, fmt.Errorf("oauth2/google: Error parsing ExpireTime from iamcredentials: %v", err)
110137
}
111138

112139
tok = &oauth2.Token{

0 commit comments

Comments
 (0)