@@ -7,13 +7,22 @@ package google
7
7
import (
8
8
"context"
9
9
"fmt"
10
+ "regexp"
11
+ "strings"
10
12
"sync"
11
13
"time"
12
14
13
15
"golang.org/x/oauth2"
14
16
"google.golang.org/api/iamcredentials/v1"
15
17
)
16
18
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
+
17
26
// DelegateTokenSource allows a TokenSource issued to a user or
18
27
// service account to impersonate another. The target service account
19
28
// must grant the orginating principal the
@@ -25,7 +34,7 @@ import (
25
34
// rootSource *must* include scopes that contains
26
35
// "https://www.googleapis.com/auth/iam"
27
36
// or
28
- // "https://www.googleapis.com/auth/cloud- platform"
37
+ // "https://www.googleapis.com/auth/cloud. platform"
29
38
// principal (string): The service account to impersonate.
30
39
// new_scopes ([]string): Scopes to request during the
31
40
// authorization grant.
@@ -54,6 +63,29 @@ func DelegateTokenSource(ctx context.Context, rootSource oauth2.TokenSource,
54
63
principal string , lifetime time.Duration , delegates []string ,
55
64
newScopes []string ) (oauth2.TokenSource , error ) {
56
65
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
+
57
89
return & delegateTokenSource {
58
90
ctx : ctx ,
59
91
rootSource : rootSource ,
@@ -73,11 +105,6 @@ type delegateTokenSource struct {
73
105
newScopes []string
74
106
}
75
107
76
- var (
77
- mu sync.Mutex
78
- tok * oauth2.Token
79
- )
80
-
81
108
func (ts * delegateTokenSource ) Token () (* oauth2.Token , error ) {
82
109
83
110
mu .Lock ()
@@ -91,7 +118,7 @@ func (ts *delegateTokenSource) Token() (*oauth2.Token, error) {
91
118
92
119
service , err := iamcredentials .New (client )
93
120
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 )
95
122
}
96
123
name := "projects/-/serviceAccounts/" + ts .principal
97
124
tokenRequest := & iamcredentials.GenerateAccessTokenRequest {
@@ -101,12 +128,12 @@ func (ts *delegateTokenSource) Token() (*oauth2.Token, error) {
101
128
}
102
129
at , err := service .Projects .ServiceAccounts .GenerateAccessToken (name , tokenRequest ).Do ()
103
130
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 )
105
132
}
106
133
107
134
expireAt , err := time .Parse (time .RFC3339 , at .ExpireTime )
108
135
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 )
110
137
}
111
138
112
139
tok = & oauth2.Token {
0 commit comments