oauth.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. *
  3. * Copyright 2015 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. // Package oauth implements gRPC credentials using OAuth.
  19. package oauth
  20. import (
  21. "context"
  22. "fmt"
  23. "io/ioutil"
  24. "sync"
  25. "golang.org/x/oauth2"
  26. "golang.org/x/oauth2/google"
  27. "golang.org/x/oauth2/jwt"
  28. "google.golang.org/grpc/credentials"
  29. )
  30. // TokenSource supplies PerRPCCredentials from an oauth2.TokenSource.
  31. type TokenSource struct {
  32. oauth2.TokenSource
  33. }
  34. // GetRequestMetadata gets the request metadata as a map from a TokenSource.
  35. func (ts TokenSource) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
  36. token, err := ts.Token()
  37. if err != nil {
  38. return nil, err
  39. }
  40. return map[string]string{
  41. "authorization": token.Type() + " " + token.AccessToken,
  42. }, nil
  43. }
  44. // RequireTransportSecurity indicates whether the credentials requires transport security.
  45. func (ts TokenSource) RequireTransportSecurity() bool {
  46. return true
  47. }
  48. type jwtAccess struct {
  49. jsonKey []byte
  50. }
  51. // NewJWTAccessFromFile creates PerRPCCredentials from the given keyFile.
  52. func NewJWTAccessFromFile(keyFile string) (credentials.PerRPCCredentials, error) {
  53. jsonKey, err := ioutil.ReadFile(keyFile)
  54. if err != nil {
  55. return nil, fmt.Errorf("credentials: failed to read the service account key file: %v", err)
  56. }
  57. return NewJWTAccessFromKey(jsonKey)
  58. }
  59. // NewJWTAccessFromKey creates PerRPCCredentials from the given jsonKey.
  60. func NewJWTAccessFromKey(jsonKey []byte) (credentials.PerRPCCredentials, error) {
  61. return jwtAccess{jsonKey}, nil
  62. }
  63. func (j jwtAccess) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
  64. ts, err := google.JWTAccessTokenSourceFromJSON(j.jsonKey, uri[0])
  65. if err != nil {
  66. return nil, err
  67. }
  68. token, err := ts.Token()
  69. if err != nil {
  70. return nil, err
  71. }
  72. return map[string]string{
  73. "authorization": token.Type() + " " + token.AccessToken,
  74. }, nil
  75. }
  76. func (j jwtAccess) RequireTransportSecurity() bool {
  77. return true
  78. }
  79. // oauthAccess supplies PerRPCCredentials from a given token.
  80. type oauthAccess struct {
  81. token oauth2.Token
  82. }
  83. // NewOauthAccess constructs the PerRPCCredentials using a given token.
  84. func NewOauthAccess(token *oauth2.Token) credentials.PerRPCCredentials {
  85. return oauthAccess{token: *token}
  86. }
  87. func (oa oauthAccess) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
  88. return map[string]string{
  89. "authorization": oa.token.Type() + " " + oa.token.AccessToken,
  90. }, nil
  91. }
  92. func (oa oauthAccess) RequireTransportSecurity() bool {
  93. return true
  94. }
  95. // NewComputeEngine constructs the PerRPCCredentials that fetches access tokens from
  96. // Google Compute Engine (GCE)'s metadata server. It is only valid to use this
  97. // if your program is running on a GCE instance.
  98. // TODO(dsymonds): Deprecate and remove this.
  99. func NewComputeEngine() credentials.PerRPCCredentials {
  100. return TokenSource{google.ComputeTokenSource("")}
  101. }
  102. // serviceAccount represents PerRPCCredentials via JWT signing key.
  103. type serviceAccount struct {
  104. mu sync.Mutex
  105. config *jwt.Config
  106. t *oauth2.Token
  107. }
  108. func (s *serviceAccount) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
  109. s.mu.Lock()
  110. defer s.mu.Unlock()
  111. if !s.t.Valid() {
  112. var err error
  113. s.t, err = s.config.TokenSource(ctx).Token()
  114. if err != nil {
  115. return nil, err
  116. }
  117. }
  118. return map[string]string{
  119. "authorization": s.t.Type() + " " + s.t.AccessToken,
  120. }, nil
  121. }
  122. func (s *serviceAccount) RequireTransportSecurity() bool {
  123. return true
  124. }
  125. // NewServiceAccountFromKey constructs the PerRPCCredentials using the JSON key slice
  126. // from a Google Developers service account.
  127. func NewServiceAccountFromKey(jsonKey []byte, scope ...string) (credentials.PerRPCCredentials, error) {
  128. config, err := google.JWTConfigFromJSON(jsonKey, scope...)
  129. if err != nil {
  130. return nil, err
  131. }
  132. return &serviceAccount{config: config}, nil
  133. }
  134. // NewServiceAccountFromFile constructs the PerRPCCredentials using the JSON key file
  135. // of a Google Developers service account.
  136. func NewServiceAccountFromFile(keyFile string, scope ...string) (credentials.PerRPCCredentials, error) {
  137. jsonKey, err := ioutil.ReadFile(keyFile)
  138. if err != nil {
  139. return nil, fmt.Errorf("credentials: failed to read the service account key file: %v", err)
  140. }
  141. return NewServiceAccountFromKey(jsonKey, scope...)
  142. }
  143. // NewApplicationDefault returns "Application Default Credentials". For more
  144. // detail, see https://developers.google.com/accounts/docs/application-default-credentials.
  145. func NewApplicationDefault(ctx context.Context, scope ...string) (credentials.PerRPCCredentials, error) {
  146. t, err := google.DefaultTokenSource(ctx, scope...)
  147. if err != nil {
  148. return nil, err
  149. }
  150. return TokenSource{t}, nil
  151. }