update golang.org/x/oauth2 to support gcp workload identity
Signed-off-by: Akhil Rane <akhil131192@gmail.com>
This commit is contained in:
parent
3b7b534569
commit
105070d951
46 changed files with 4373 additions and 931 deletions
|
@ -1,3 +1,4 @@
|
|||
cloud.google.com/go 0300d0cf7e473a4a23d1089b3c8069ef28638f4c
|
||||
github.com/Azure/azure-sdk-for-go 4650843026a7fdec254a8d9cf893693a254edd0b
|
||||
github.com/Azure/go-autorest eaa7994b2278094c904d31993d26f56324db3052
|
||||
github.com/sirupsen/logrus 3d4380f53a34dcdc95f0c1db702615992b38d9a4
|
||||
|
@ -37,7 +38,7 @@ github.com/yvasiyarov/gorelic a9bba5b9ab508a086f9a12b8c51fab68478e2128
|
|||
github.com/yvasiyarov/newrelic_platform_go b21fdbd4370f3717f3bbd2bf41c223bc273068e6
|
||||
golang.org/x/crypto c10c31b5e94b6f7a0283272dc2bb27163dcea24b
|
||||
golang.org/x/net 4876518f9e71663000c348837735820161a42df7
|
||||
golang.org/x/oauth2 045497edb6234273d67dbc25da3f2ddbc4c4cacf
|
||||
golang.org/x/oauth2 a8dc77f794b698f200a57b3bbd77da000f86124e
|
||||
golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
|
||||
google.golang.org/api 9bf6e6e569ff057f75d9604a46c52928f17d2b54
|
||||
google.golang.org/appengine 12d5545dc1cfa6047a286d5e853841b6471f4c19
|
||||
|
|
202
vendor/cloud.google.com/go/LICENSE
generated
vendored
Normal file
202
vendor/cloud.google.com/go/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
137
vendor/cloud.google.com/go/README.md
generated
vendored
Normal file
137
vendor/cloud.google.com/go/README.md
generated
vendored
Normal file
|
@ -0,0 +1,137 @@
|
|||
# Google Cloud Client Libraries for Go
|
||||
|
||||
[![Go Reference](https://pkg.go.dev/badge/cloud.google.com/go.svg)](https://pkg.go.dev/cloud.google.com/go)
|
||||
|
||||
Go packages for [Google Cloud Platform](https://cloud.google.com) services.
|
||||
|
||||
``` go
|
||||
import "cloud.google.com/go"
|
||||
```
|
||||
|
||||
To install the packages on your system, *do not clone the repo*. Instead:
|
||||
|
||||
1. Change to your project directory:
|
||||
|
||||
```bash
|
||||
cd /my/cloud/project
|
||||
```
|
||||
1. Get the package you want to use. Some products have their own module, so it's
|
||||
best to `go get` the package(s) you want to use:
|
||||
|
||||
```
|
||||
$ go get cloud.google.com/go/firestore # Replace with the package you want to use.
|
||||
```
|
||||
|
||||
**NOTE:** Some of these packages are under development, and may occasionally
|
||||
make backwards-incompatible changes.
|
||||
|
||||
## Supported APIs
|
||||
|
||||
For an updated list of all of our released APIs please see our
|
||||
[reference docs](https://cloud.google.com/go/docs/reference).
|
||||
|
||||
## [Go Versions Supported](#supported-versions)
|
||||
|
||||
Our libraries are compatible with at least the three most recent, major Go
|
||||
releases. They are currently compatible with:
|
||||
|
||||
- Go 1.17
|
||||
- Go 1.16
|
||||
- Go 1.15
|
||||
|
||||
## Authorization
|
||||
|
||||
By default, each API will use [Google Application Default Credentials](https://developers.google.com/identity/protocols/application-default-credentials)
|
||||
for authorization credentials used in calling the API endpoints. This will allow your
|
||||
application to run in many environments without requiring explicit configuration.
|
||||
|
||||
[snip]:# (auth)
|
||||
```go
|
||||
client, err := storage.NewClient(ctx)
|
||||
```
|
||||
|
||||
To authorize using a
|
||||
[JSON key file](https://cloud.google.com/iam/docs/managing-service-account-keys),
|
||||
pass
|
||||
[`option.WithCredentialsFile`](https://pkg.go.dev/google.golang.org/api/option#WithCredentialsFile)
|
||||
to the `NewClient` function of the desired package. For example:
|
||||
|
||||
[snip]:# (auth-JSON)
|
||||
```go
|
||||
client, err := storage.NewClient(ctx, option.WithCredentialsFile("path/to/keyfile.json"))
|
||||
```
|
||||
|
||||
You can exert more control over authorization by using the
|
||||
[`golang.org/x/oauth2`](https://pkg.go.dev/golang.org/x/oauth2) package to
|
||||
create an `oauth2.TokenSource`. Then pass
|
||||
[`option.WithTokenSource`](https://pkg.go.dev/google.golang.org/api/option#WithTokenSource)
|
||||
to the `NewClient` function:
|
||||
[snip]:# (auth-ts)
|
||||
```go
|
||||
tokenSource := ...
|
||||
client, err := storage.NewClient(ctx, option.WithTokenSource(tokenSource))
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome. Please, see the
|
||||
[CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md)
|
||||
document for details.
|
||||
|
||||
Please note that this project is released with a Contributor Code of Conduct.
|
||||
By participating in this project you agree to abide by its terms.
|
||||
See [Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md#contributor-code-of-conduct)
|
||||
for more information.
|
||||
|
||||
[cloud-asset]: https://cloud.google.com/security-command-center/docs/how-to-asset-inventory
|
||||
[cloud-automl]: https://cloud.google.com/automl
|
||||
[cloud-build]: https://cloud.google.com/cloud-build/
|
||||
[cloud-bigquery]: https://cloud.google.com/bigquery/
|
||||
[cloud-bigtable]: https://cloud.google.com/bigtable/
|
||||
[cloud-compute]: https://cloud.google.com/compute
|
||||
[cloud-container]: https://cloud.google.com/containers/
|
||||
[cloud-containeranalysis]: https://cloud.google.com/container-registry/docs/container-analysis
|
||||
[cloud-dataproc]: https://cloud.google.com/dataproc/
|
||||
[cloud-datastore]: https://cloud.google.com/datastore/
|
||||
[cloud-dialogflow]: https://cloud.google.com/dialogflow-enterprise/
|
||||
[cloud-debugger]: https://cloud.google.com/debugger/
|
||||
[cloud-dlp]: https://cloud.google.com/dlp/
|
||||
[cloud-errors]: https://cloud.google.com/error-reporting/
|
||||
[cloud-firestore]: https://cloud.google.com/firestore/
|
||||
[cloud-iam]: https://cloud.google.com/iam/
|
||||
[cloud-iot]: https://cloud.google.com/iot-core/
|
||||
[cloud-irm]: https://cloud.google.com/incident-response/docs/concepts
|
||||
[cloud-kms]: https://cloud.google.com/kms/
|
||||
[cloud-pubsub]: https://cloud.google.com/pubsub/
|
||||
[cloud-pubsublite]: https://cloud.google.com/pubsub/lite
|
||||
[cloud-storage]: https://cloud.google.com/storage/
|
||||
[cloud-language]: https://cloud.google.com/natural-language
|
||||
[cloud-logging]: https://cloud.google.com/logging/
|
||||
[cloud-natural-language]: https://cloud.google.com/natural-language/
|
||||
[cloud-memorystore]: https://cloud.google.com/memorystore/
|
||||
[cloud-monitoring]: https://cloud.google.com/monitoring/
|
||||
[cloud-oslogin]: https://cloud.google.com/compute/docs/oslogin/rest
|
||||
[cloud-phishingprotection]: https://cloud.google.com/phishing-protection/
|
||||
[cloud-securitycenter]: https://cloud.google.com/security-command-center/
|
||||
[cloud-scheduler]: https://cloud.google.com/scheduler
|
||||
[cloud-spanner]: https://cloud.google.com/spanner/
|
||||
[cloud-speech]: https://cloud.google.com/speech
|
||||
[cloud-talent]: https://cloud.google.com/solutions/talent-solution/
|
||||
[cloud-tasks]: https://cloud.google.com/tasks/
|
||||
[cloud-texttospeech]: https://cloud.google.com/texttospeech/
|
||||
[cloud-talent]: https://cloud.google.com/solutions/talent-solution/
|
||||
[cloud-trace]: https://cloud.google.com/trace/
|
||||
[cloud-translate]: https://cloud.google.com/translate
|
||||
[cloud-recaptcha]: https://cloud.google.com/recaptcha-enterprise/
|
||||
[cloud-recommender]: https://cloud.google.com/recommendations/
|
||||
[cloud-video]: https://cloud.google.com/video-intelligence/
|
||||
[cloud-vision]: https://cloud.google.com/vision
|
||||
[cloud-webrisk]: https://cloud.google.com/web-risk/
|
||||
|
||||
## Links
|
||||
|
||||
- [Go on Google Cloud](https://cloud.google.com/go/home)
|
||||
- [Getting started with Go on Google Cloud](https://cloud.google.com/go/getting-started)
|
||||
- [App Engine Quickstart](https://cloud.google.com/appengine/docs/standard/go/quickstart)
|
||||
- [Cloud Functions Quickstart](https://cloud.google.com/functions/docs/quickstart-go)
|
||||
- [Cloud Run Quickstart](https://cloud.google.com/run/docs/quickstarts/build-and-deploy#go)
|
9
vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclinetest.h
generated
vendored
Normal file
9
vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclinetest.h
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
// +build ignore
|
||||
|
||||
// Empty include file to generate z symbols
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// EOF
|
472
vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclntab.go
generated
vendored
Normal file
472
vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclntab.go
generated
vendored
Normal file
|
@ -0,0 +1,472 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*
|
||||
* Line tables
|
||||
*/
|
||||
|
||||
package gosym
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// A LineTable is a data structure mapping program counters to line numbers.
|
||||
//
|
||||
// In Go 1.1 and earlier, each function (represented by a Func) had its own LineTable,
|
||||
// and the line number corresponded to a numbering of all source lines in the
|
||||
// program, across all files. That absolute line number would then have to be
|
||||
// converted separately to a file name and line number within the file.
|
||||
//
|
||||
// In Go 1.2, the format of the data changed so that there is a single LineTable
|
||||
// for the entire program, shared by all Funcs, and there are no absolute line
|
||||
// numbers, just line numbers within specific files.
|
||||
//
|
||||
// For the most part, LineTable's methods should be treated as an internal
|
||||
// detail of the package; callers should use the methods on Table instead.
|
||||
type LineTable struct {
|
||||
Data []byte
|
||||
PC uint64
|
||||
Line int
|
||||
|
||||
// Go 1.2 state
|
||||
mu sync.Mutex
|
||||
go12 int // is this in Go 1.2 format? -1 no, 0 unknown, 1 yes
|
||||
binary binary.ByteOrder
|
||||
quantum uint32
|
||||
ptrsize uint32
|
||||
functab []byte
|
||||
nfunctab uint32
|
||||
filetab []byte
|
||||
nfiletab uint32
|
||||
fileMap map[string]uint32
|
||||
}
|
||||
|
||||
// NOTE(rsc): This is wrong for GOARCH=arm, which uses a quantum of 4,
|
||||
// but we have no idea whether we're using arm or not. This only
|
||||
// matters in the old (pre-Go 1.2) symbol table format, so it's not worth
|
||||
// fixing.
|
||||
const oldQuantum = 1
|
||||
|
||||
func (t *LineTable) parse(targetPC uint64, targetLine int) (b []byte, pc uint64, line int) {
|
||||
// The PC/line table can be thought of as a sequence of
|
||||
// <pc update>* <line update>
|
||||
// batches. Each update batch results in a (pc, line) pair,
|
||||
// where line applies to every PC from pc up to but not
|
||||
// including the pc of the next pair.
|
||||
//
|
||||
// Here we process each update individually, which simplifies
|
||||
// the code, but makes the corner cases more confusing.
|
||||
b, pc, line = t.Data, t.PC, t.Line
|
||||
for pc <= targetPC && line != targetLine && len(b) > 0 {
|
||||
code := b[0]
|
||||
b = b[1:]
|
||||
switch {
|
||||
case code == 0:
|
||||
if len(b) < 4 {
|
||||
b = b[0:0]
|
||||
break
|
||||
}
|
||||
val := binary.BigEndian.Uint32(b)
|
||||
b = b[4:]
|
||||
line += int(val)
|
||||
case code <= 64:
|
||||
line += int(code)
|
||||
case code <= 128:
|
||||
line -= int(code - 64)
|
||||
default:
|
||||
pc += oldQuantum * uint64(code-128)
|
||||
continue
|
||||
}
|
||||
pc += oldQuantum
|
||||
}
|
||||
return b, pc, line
|
||||
}
|
||||
|
||||
func (t *LineTable) slice(pc uint64) *LineTable {
|
||||
data, pc, line := t.parse(pc, -1)
|
||||
return &LineTable{Data: data, PC: pc, Line: line}
|
||||
}
|
||||
|
||||
// PCToLine returns the line number for the given program counter.
|
||||
// Callers should use Table's PCToLine method instead.
|
||||
func (t *LineTable) PCToLine(pc uint64) int {
|
||||
if t.isGo12() {
|
||||
return t.go12PCToLine(pc)
|
||||
}
|
||||
_, _, line := t.parse(pc, -1)
|
||||
return line
|
||||
}
|
||||
|
||||
// LineToPC returns the program counter for the given line number,
|
||||
// considering only program counters before maxpc.
|
||||
// Callers should use Table's LineToPC method instead.
|
||||
func (t *LineTable) LineToPC(line int, maxpc uint64) uint64 {
|
||||
if t.isGo12() {
|
||||
return 0
|
||||
}
|
||||
_, pc, line1 := t.parse(maxpc, line)
|
||||
if line1 != line {
|
||||
return 0
|
||||
}
|
||||
// Subtract quantum from PC to account for post-line increment
|
||||
return pc - oldQuantum
|
||||
}
|
||||
|
||||
// NewLineTable returns a new PC/line table
|
||||
// corresponding to the encoded data.
|
||||
// Text must be the start address of the
|
||||
// corresponding text segment.
|
||||
func NewLineTable(data []byte, text uint64) *LineTable {
|
||||
return &LineTable{Data: data, PC: text, Line: 0}
|
||||
}
|
||||
|
||||
// Go 1.2 symbol table format.
|
||||
// See golang.org/s/go12symtab.
|
||||
//
|
||||
// A general note about the methods here: rather than try to avoid
|
||||
// index out of bounds errors, we trust Go to detect them, and then
|
||||
// we recover from the panics and treat them as indicative of a malformed
|
||||
// or incomplete table.
|
||||
//
|
||||
// The methods called by symtab.go, which begin with "go12" prefixes,
|
||||
// are expected to have that recovery logic.
|
||||
|
||||
// isGo12 reports whether this is a Go 1.2 (or later) symbol table.
|
||||
func (t *LineTable) isGo12() bool {
|
||||
t.go12Init()
|
||||
return t.go12 == 1
|
||||
}
|
||||
|
||||
const go12magic = 0xfffffffb
|
||||
|
||||
// uintptr returns the pointer-sized value encoded at b.
|
||||
// The pointer size is dictated by the table being read.
|
||||
func (t *LineTable) uintptr(b []byte) uint64 {
|
||||
if t.ptrsize == 4 {
|
||||
return uint64(t.binary.Uint32(b))
|
||||
}
|
||||
return t.binary.Uint64(b)
|
||||
}
|
||||
|
||||
// go12init initializes the Go 1.2 metadata if t is a Go 1.2 symbol table.
|
||||
func (t *LineTable) go12Init() {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
if t.go12 != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// If we panic parsing, assume it's not a Go 1.2 symbol table.
|
||||
recover()
|
||||
}()
|
||||
|
||||
// Check header: 4-byte magic, two zeros, pc quantum, pointer size.
|
||||
t.go12 = -1 // not Go 1.2 until proven otherwise
|
||||
if len(t.Data) < 16 || t.Data[4] != 0 || t.Data[5] != 0 ||
|
||||
(t.Data[6] != 1 && t.Data[6] != 4) || // pc quantum
|
||||
(t.Data[7] != 4 && t.Data[7] != 8) { // pointer size
|
||||
return
|
||||
}
|
||||
|
||||
switch uint32(go12magic) {
|
||||
case binary.LittleEndian.Uint32(t.Data):
|
||||
t.binary = binary.LittleEndian
|
||||
case binary.BigEndian.Uint32(t.Data):
|
||||
t.binary = binary.BigEndian
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
t.quantum = uint32(t.Data[6])
|
||||
t.ptrsize = uint32(t.Data[7])
|
||||
|
||||
t.nfunctab = uint32(t.uintptr(t.Data[8:]))
|
||||
t.functab = t.Data[8+t.ptrsize:]
|
||||
functabsize := t.nfunctab*2*t.ptrsize + t.ptrsize
|
||||
fileoff := t.binary.Uint32(t.functab[functabsize:])
|
||||
t.functab = t.functab[:functabsize]
|
||||
t.filetab = t.Data[fileoff:]
|
||||
t.nfiletab = t.binary.Uint32(t.filetab)
|
||||
t.filetab = t.filetab[:t.nfiletab*4]
|
||||
|
||||
t.go12 = 1 // so far so good
|
||||
}
|
||||
|
||||
// go12Funcs returns a slice of Funcs derived from the Go 1.2 pcln table.
|
||||
func (t *LineTable) go12Funcs() []Func {
|
||||
// Assume it is malformed and return nil on error.
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
|
||||
n := len(t.functab) / int(t.ptrsize) / 2
|
||||
funcs := make([]Func, n)
|
||||
for i := range funcs {
|
||||
f := &funcs[i]
|
||||
f.Entry = uint64(t.uintptr(t.functab[2*i*int(t.ptrsize):]))
|
||||
f.End = uint64(t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):]))
|
||||
info := t.Data[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):]
|
||||
f.LineTable = t
|
||||
f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:]))
|
||||
f.Sym = &Sym{
|
||||
Value: f.Entry,
|
||||
Type: 'T',
|
||||
Name: t.string(t.binary.Uint32(info[t.ptrsize:])),
|
||||
GoType: 0,
|
||||
Func: f,
|
||||
}
|
||||
}
|
||||
return funcs
|
||||
}
|
||||
|
||||
// findFunc returns the func corresponding to the given program counter.
|
||||
func (t *LineTable) findFunc(pc uint64) []byte {
|
||||
if pc < t.uintptr(t.functab) || pc >= t.uintptr(t.functab[len(t.functab)-int(t.ptrsize):]) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// The function table is a list of 2*nfunctab+1 uintptrs,
|
||||
// alternating program counters and offsets to func structures.
|
||||
f := t.functab
|
||||
nf := t.nfunctab
|
||||
for nf > 0 {
|
||||
m := nf / 2
|
||||
fm := f[2*t.ptrsize*m:]
|
||||
if t.uintptr(fm) <= pc && pc < t.uintptr(fm[2*t.ptrsize:]) {
|
||||
return t.Data[t.uintptr(fm[t.ptrsize:]):]
|
||||
} else if pc < t.uintptr(fm) {
|
||||
nf = m
|
||||
} else {
|
||||
f = f[(m+1)*2*t.ptrsize:]
|
||||
nf -= m + 1
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readvarint reads, removes, and returns a varint from *pp.
|
||||
func (t *LineTable) readvarint(pp *[]byte) uint32 {
|
||||
var v, shift uint32
|
||||
p := *pp
|
||||
for shift = 0; ; shift += 7 {
|
||||
b := p[0]
|
||||
p = p[1:]
|
||||
v |= (uint32(b) & 0x7F) << shift
|
||||
if b&0x80 == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
*pp = p
|
||||
return v
|
||||
}
|
||||
|
||||
// string returns a Go string found at off.
|
||||
func (t *LineTable) string(off uint32) string {
|
||||
for i := off; ; i++ {
|
||||
if t.Data[i] == 0 {
|
||||
return string(t.Data[off:i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// step advances to the next pc, value pair in the encoded table.
|
||||
func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool {
|
||||
uvdelta := t.readvarint(p)
|
||||
if uvdelta == 0 && !first {
|
||||
return false
|
||||
}
|
||||
if uvdelta&1 != 0 {
|
||||
uvdelta = ^(uvdelta >> 1)
|
||||
} else {
|
||||
uvdelta >>= 1
|
||||
}
|
||||
vdelta := int32(uvdelta)
|
||||
pcdelta := t.readvarint(p) * t.quantum
|
||||
*pc += uint64(pcdelta)
|
||||
*val += vdelta
|
||||
return true
|
||||
}
|
||||
|
||||
// pcvalue reports the value associated with the target pc.
|
||||
// off is the offset to the beginning of the pc-value table,
|
||||
// and entry is the start PC for the corresponding function.
|
||||
func (t *LineTable) pcvalue(off uint32, entry, targetpc uint64) int32 {
|
||||
if off == 0 {
|
||||
return -1
|
||||
}
|
||||
p := t.Data[off:]
|
||||
|
||||
val := int32(-1)
|
||||
pc := entry
|
||||
for t.step(&p, &pc, &val, pc == entry) {
|
||||
if targetpc < pc {
|
||||
return val
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// findFileLine scans one function in the binary looking for a
|
||||
// program counter in the given file on the given line.
|
||||
// It does so by running the pc-value tables mapping program counter
|
||||
// to file number. Since most functions come from a single file, these
|
||||
// are usually short and quick to scan. If a file match is found, then the
|
||||
// code goes to the expense of looking for a simultaneous line number match.
|
||||
func (t *LineTable) findFileLine(entry uint64, filetab, linetab uint32, filenum, line int32) uint64 {
|
||||
if filetab == 0 || linetab == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
fp := t.Data[filetab:]
|
||||
fl := t.Data[linetab:]
|
||||
fileVal := int32(-1)
|
||||
filePC := entry
|
||||
lineVal := int32(-1)
|
||||
linePC := entry
|
||||
fileStartPC := filePC
|
||||
for t.step(&fp, &filePC, &fileVal, filePC == entry) {
|
||||
if fileVal == filenum && fileStartPC < filePC {
|
||||
// fileVal is in effect starting at fileStartPC up to
|
||||
// but not including filePC, and it's the file we want.
|
||||
// Run the PC table looking for a matching line number
|
||||
// or until we reach filePC.
|
||||
lineStartPC := linePC
|
||||
for linePC < filePC && t.step(&fl, &linePC, &lineVal, linePC == entry) {
|
||||
// lineVal is in effect until linePC, and lineStartPC < filePC.
|
||||
if lineVal == line {
|
||||
if fileStartPC <= lineStartPC {
|
||||
return lineStartPC
|
||||
}
|
||||
if fileStartPC < linePC {
|
||||
return fileStartPC
|
||||
}
|
||||
}
|
||||
lineStartPC = linePC
|
||||
}
|
||||
}
|
||||
fileStartPC = filePC
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// go12PCToLine maps program counter to line number for the Go 1.2 pcln table.
|
||||
func (t *LineTable) go12PCToLine(pc uint64) (line int) {
|
||||
return t.go12PCToVal(pc, t.ptrsize+5*4)
|
||||
}
|
||||
|
||||
// go12PCToSPAdj maps program counter to Stack Pointer adjustment for the Go 1.2 pcln table.
|
||||
func (t *LineTable) go12PCToSPAdj(pc uint64) (spadj int) {
|
||||
return t.go12PCToVal(pc, t.ptrsize+3*4)
|
||||
}
|
||||
|
||||
func (t *LineTable) go12PCToVal(pc uint64, fOffset uint32) (val int) {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
val = -1
|
||||
}
|
||||
}()
|
||||
|
||||
f := t.findFunc(pc)
|
||||
if f == nil {
|
||||
return -1
|
||||
}
|
||||
entry := t.uintptr(f)
|
||||
linetab := t.binary.Uint32(f[fOffset:])
|
||||
return int(t.pcvalue(linetab, entry, pc))
|
||||
}
|
||||
|
||||
// go12PCToFile maps program counter to file name for the Go 1.2 pcln table.
|
||||
func (t *LineTable) go12PCToFile(pc uint64) (file string) {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
file = ""
|
||||
}
|
||||
}()
|
||||
|
||||
f := t.findFunc(pc)
|
||||
if f == nil {
|
||||
return ""
|
||||
}
|
||||
entry := t.uintptr(f)
|
||||
filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
|
||||
fno := t.pcvalue(filetab, entry, pc)
|
||||
if fno <= 0 {
|
||||
return ""
|
||||
}
|
||||
return t.string(t.binary.Uint32(t.filetab[4*fno:]))
|
||||
}
|
||||
|
||||
// go12LineToPC maps a (file, line) pair to a program counter for the Go 1.2 pcln table.
|
||||
func (t *LineTable) go12LineToPC(file string, line int) (pc uint64) {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
pc = 0
|
||||
}
|
||||
}()
|
||||
|
||||
t.initFileMap()
|
||||
filenum := t.fileMap[file]
|
||||
if filenum == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Scan all functions.
|
||||
// If this turns out to be a bottleneck, we could build a map[int32][]int32
|
||||
// mapping file number to a list of functions with code from that file.
|
||||
for i := uint32(0); i < t.nfunctab; i++ {
|
||||
f := t.Data[t.uintptr(t.functab[2*t.ptrsize*i+t.ptrsize:]):]
|
||||
entry := t.uintptr(f)
|
||||
filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
|
||||
linetab := t.binary.Uint32(f[t.ptrsize+5*4:])
|
||||
pc := t.findFileLine(entry, filetab, linetab, int32(filenum), int32(line))
|
||||
if pc != 0 {
|
||||
return pc
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// initFileMap initializes the map from file name to file number.
|
||||
func (t *LineTable) initFileMap() {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
if t.fileMap != nil {
|
||||
return
|
||||
}
|
||||
m := make(map[string]uint32)
|
||||
|
||||
for i := uint32(1); i < t.nfiletab; i++ {
|
||||
s := t.string(t.binary.Uint32(t.filetab[4*i:]))
|
||||
m[s] = i
|
||||
}
|
||||
t.fileMap = m
|
||||
}
|
||||
|
||||
// go12MapFiles adds to m a key for every file in the Go 1.2 LineTable.
|
||||
// Every key maps to obj. That's not a very interesting map, but it provides
|
||||
// a way for callers to obtain the list of files in the program.
|
||||
func (t *LineTable) go12MapFiles(m map[string]*Obj, obj *Obj) {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
|
||||
t.initFileMap()
|
||||
for file := range t.fileMap {
|
||||
m[file] = obj
|
||||
}
|
||||
}
|
731
vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/symtab.go
generated
vendored
Normal file
731
vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/symtab.go
generated
vendored
Normal file
|
@ -0,0 +1,731 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package gosym implements access to the Go symbol
|
||||
// and line number tables embedded in Go binaries generated
|
||||
// by the gc compilers.
|
||||
package gosym
|
||||
|
||||
// The table format is a variant of the format used in Plan 9's a.out
|
||||
// format, documented at http://plan9.bell-labs.com/magic/man2html/6/a.out.
|
||||
// The best reference for the differences between the Plan 9 format
|
||||
// and the Go format is the runtime source, specifically ../../runtime/symtab.c.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
* Symbols
|
||||
*/
|
||||
|
||||
// A Sym represents a single symbol table entry.
|
||||
type Sym struct {
|
||||
Value uint64
|
||||
Type byte
|
||||
Name string
|
||||
GoType uint64
|
||||
// If this symbol if a function symbol, the corresponding Func
|
||||
Func *Func
|
||||
}
|
||||
|
||||
// Static reports whether this symbol is static (not visible outside its file).
|
||||
func (s *Sym) Static() bool { return s.Type >= 'a' }
|
||||
|
||||
// PackageName returns the package part of the symbol name,
|
||||
// or the empty string if there is none.
|
||||
func (s *Sym) PackageName() string {
|
||||
if i := strings.Index(s.Name, "."); i != -1 {
|
||||
return s.Name[0:i]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ReceiverName returns the receiver type name of this symbol,
|
||||
// or the empty string if there is none.
|
||||
func (s *Sym) ReceiverName() string {
|
||||
l := strings.Index(s.Name, ".")
|
||||
r := strings.LastIndex(s.Name, ".")
|
||||
if l == -1 || r == -1 || l == r {
|
||||
return ""
|
||||
}
|
||||
return s.Name[l+1 : r]
|
||||
}
|
||||
|
||||
// BaseName returns the symbol name without the package or receiver name.
|
||||
func (s *Sym) BaseName() string {
|
||||
if i := strings.LastIndex(s.Name, "."); i != -1 {
|
||||
return s.Name[i+1:]
|
||||
}
|
||||
return s.Name
|
||||
}
|
||||
|
||||
// A Func collects information about a single function.
|
||||
type Func struct {
|
||||
Entry uint64
|
||||
*Sym
|
||||
End uint64
|
||||
Params []*Sym
|
||||
Locals []*Sym
|
||||
FrameSize int
|
||||
LineTable *LineTable
|
||||
Obj *Obj
|
||||
}
|
||||
|
||||
// An Obj represents a collection of functions in a symbol table.
|
||||
//
|
||||
// The exact method of division of a binary into separate Objs is an internal detail
|
||||
// of the symbol table format.
|
||||
//
|
||||
// In early versions of Go each source file became a different Obj.
|
||||
//
|
||||
// In Go 1 and Go 1.1, each package produced one Obj for all Go sources
|
||||
// and one Obj per C source file.
|
||||
//
|
||||
// In Go 1.2, there is a single Obj for the entire program.
|
||||
type Obj struct {
|
||||
// Funcs is a list of functions in the Obj.
|
||||
Funcs []Func
|
||||
|
||||
// In Go 1.1 and earlier, Paths is a list of symbols corresponding
|
||||
// to the source file names that produced the Obj.
|
||||
// In Go 1.2, Paths is nil.
|
||||
// Use the keys of Table.Files to obtain a list of source files.
|
||||
Paths []Sym // meta
|
||||
}
|
||||
|
||||
/*
|
||||
* Symbol tables
|
||||
*/
|
||||
|
||||
// Table represents a Go symbol table. It stores all of the
|
||||
// symbols decoded from the program and provides methods to translate
|
||||
// between symbols, names, and addresses.
|
||||
type Table struct {
|
||||
Syms []Sym
|
||||
Funcs []Func
|
||||
Files map[string]*Obj // nil for Go 1.2 and later binaries
|
||||
Objs []Obj // nil for Go 1.2 and later binaries
|
||||
|
||||
go12line *LineTable // Go 1.2 line number table
|
||||
}
|
||||
|
||||
type sym struct {
|
||||
value uint64
|
||||
gotype uint64
|
||||
typ byte
|
||||
name []byte
|
||||
}
|
||||
|
||||
var (
|
||||
littleEndianSymtab = []byte{0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00}
|
||||
bigEndianSymtab = []byte{0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00}
|
||||
oldLittleEndianSymtab = []byte{0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00}
|
||||
)
|
||||
|
||||
func walksymtab(data []byte, fn func(sym) error) error {
|
||||
if len(data) == 0 { // missing symtab is okay
|
||||
return nil
|
||||
}
|
||||
var order binary.ByteOrder = binary.BigEndian
|
||||
newTable := false
|
||||
switch {
|
||||
case bytes.HasPrefix(data, oldLittleEndianSymtab):
|
||||
// Same as Go 1.0, but little endian.
|
||||
// Format was used during interim development between Go 1.0 and Go 1.1.
|
||||
// Should not be widespread, but easy to support.
|
||||
data = data[6:]
|
||||
order = binary.LittleEndian
|
||||
case bytes.HasPrefix(data, bigEndianSymtab):
|
||||
newTable = true
|
||||
case bytes.HasPrefix(data, littleEndianSymtab):
|
||||
newTable = true
|
||||
order = binary.LittleEndian
|
||||
}
|
||||
var ptrsz int
|
||||
if newTable {
|
||||
if len(data) < 8 {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
ptrsz = int(data[7])
|
||||
if ptrsz != 4 && ptrsz != 8 {
|
||||
return &DecodingError{7, "invalid pointer size", ptrsz}
|
||||
}
|
||||
data = data[8:]
|
||||
}
|
||||
var s sym
|
||||
p := data
|
||||
for len(p) >= 4 {
|
||||
var typ byte
|
||||
if newTable {
|
||||
// Symbol type, value, Go type.
|
||||
typ = p[0] & 0x3F
|
||||
wideValue := p[0]&0x40 != 0
|
||||
goType := p[0]&0x80 != 0
|
||||
if typ < 26 {
|
||||
typ += 'A'
|
||||
} else {
|
||||
typ += 'a' - 26
|
||||
}
|
||||
s.typ = typ
|
||||
p = p[1:]
|
||||
if wideValue {
|
||||
if len(p) < ptrsz {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
// fixed-width value
|
||||
if ptrsz == 8 {
|
||||
s.value = order.Uint64(p[0:8])
|
||||
p = p[8:]
|
||||
} else {
|
||||
s.value = uint64(order.Uint32(p[0:4]))
|
||||
p = p[4:]
|
||||
}
|
||||
} else {
|
||||
// varint value
|
||||
s.value = 0
|
||||
shift := uint(0)
|
||||
for len(p) > 0 && p[0]&0x80 != 0 {
|
||||
s.value |= uint64(p[0]&0x7F) << shift
|
||||
shift += 7
|
||||
p = p[1:]
|
||||
}
|
||||
if len(p) == 0 {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
s.value |= uint64(p[0]) << shift
|
||||
p = p[1:]
|
||||
}
|
||||
if goType {
|
||||
if len(p) < ptrsz {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
// fixed-width go type
|
||||
if ptrsz == 8 {
|
||||
s.gotype = order.Uint64(p[0:8])
|
||||
p = p[8:]
|
||||
} else {
|
||||
s.gotype = uint64(order.Uint32(p[0:4]))
|
||||
p = p[4:]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Value, symbol type.
|
||||
s.value = uint64(order.Uint32(p[0:4]))
|
||||
if len(p) < 5 {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
typ = p[4]
|
||||
if typ&0x80 == 0 {
|
||||
return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
|
||||
}
|
||||
typ &^= 0x80
|
||||
s.typ = typ
|
||||
p = p[5:]
|
||||
}
|
||||
|
||||
// Name.
|
||||
var i int
|
||||
var nnul int
|
||||
for i = 0; i < len(p); i++ {
|
||||
if p[i] == 0 {
|
||||
nnul = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
switch typ {
|
||||
case 'z', 'Z':
|
||||
p = p[i+nnul:]
|
||||
for i = 0; i+2 <= len(p); i += 2 {
|
||||
if p[i] == 0 && p[i+1] == 0 {
|
||||
nnul = 2
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(p) < i+nnul {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
s.name = p[0:i]
|
||||
i += nnul
|
||||
p = p[i:]
|
||||
|
||||
if !newTable {
|
||||
if len(p) < 4 {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
// Go type.
|
||||
s.gotype = uint64(order.Uint32(p[:4]))
|
||||
p = p[4:]
|
||||
}
|
||||
fn(s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewTable decodes the Go symbol table in data,
|
||||
// returning an in-memory representation.
|
||||
func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
|
||||
var n int
|
||||
err := walksymtab(symtab, func(s sym) error {
|
||||
n++
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var t Table
|
||||
if pcln.isGo12() {
|
||||
t.go12line = pcln
|
||||
}
|
||||
fname := make(map[uint16]string)
|
||||
t.Syms = make([]Sym, 0, n)
|
||||
nf := 0
|
||||
nz := 0
|
||||
lasttyp := uint8(0)
|
||||
err = walksymtab(symtab, func(s sym) error {
|
||||
n := len(t.Syms)
|
||||
t.Syms = t.Syms[0 : n+1]
|
||||
ts := &t.Syms[n]
|
||||
ts.Type = s.typ
|
||||
ts.Value = uint64(s.value)
|
||||
ts.GoType = uint64(s.gotype)
|
||||
switch s.typ {
|
||||
default:
|
||||
// rewrite name to use . instead of · (c2 b7)
|
||||
w := 0
|
||||
b := s.name
|
||||
for i := 0; i < len(b); i++ {
|
||||
if b[i] == 0xc2 && i+1 < len(b) && b[i+1] == 0xb7 {
|
||||
i++
|
||||
b[i] = '.'
|
||||
}
|
||||
b[w] = b[i]
|
||||
w++
|
||||
}
|
||||
ts.Name = string(s.name[0:w])
|
||||
case 'z', 'Z':
|
||||
if lasttyp != 'z' && lasttyp != 'Z' {
|
||||
nz++
|
||||
}
|
||||
for i := 0; i < len(s.name); i += 2 {
|
||||
eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
|
||||
elt, ok := fname[eltIdx]
|
||||
if !ok {
|
||||
return &DecodingError{-1, "bad filename code", eltIdx}
|
||||
}
|
||||
if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' {
|
||||
ts.Name += "/"
|
||||
}
|
||||
ts.Name += elt
|
||||
}
|
||||
}
|
||||
switch s.typ {
|
||||
case 'T', 't', 'L', 'l':
|
||||
nf++
|
||||
case 'f':
|
||||
fname[uint16(s.value)] = ts.Name
|
||||
}
|
||||
lasttyp = s.typ
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t.Funcs = make([]Func, 0, nf)
|
||||
t.Files = make(map[string]*Obj)
|
||||
|
||||
var obj *Obj
|
||||
if t.go12line != nil {
|
||||
// Put all functions into one Obj.
|
||||
t.Objs = make([]Obj, 1)
|
||||
obj = &t.Objs[0]
|
||||
t.go12line.go12MapFiles(t.Files, obj)
|
||||
} else {
|
||||
t.Objs = make([]Obj, 0, nz)
|
||||
}
|
||||
|
||||
// Count text symbols and attach frame sizes, parameters, and
|
||||
// locals to them. Also, find object file boundaries.
|
||||
lastf := 0
|
||||
for i := 0; i < len(t.Syms); i++ {
|
||||
sym := &t.Syms[i]
|
||||
switch sym.Type {
|
||||
case 'Z', 'z': // path symbol
|
||||
if t.go12line != nil {
|
||||
// Go 1.2 binaries have the file information elsewhere. Ignore.
|
||||
break
|
||||
}
|
||||
// Finish the current object
|
||||
if obj != nil {
|
||||
obj.Funcs = t.Funcs[lastf:]
|
||||
}
|
||||
lastf = len(t.Funcs)
|
||||
|
||||
// Start new object
|
||||
n := len(t.Objs)
|
||||
t.Objs = t.Objs[0 : n+1]
|
||||
obj = &t.Objs[n]
|
||||
|
||||
// Count & copy path symbols
|
||||
var end int
|
||||
for end = i + 1; end < len(t.Syms); end++ {
|
||||
if c := t.Syms[end].Type; c != 'Z' && c != 'z' {
|
||||
break
|
||||
}
|
||||
}
|
||||
obj.Paths = t.Syms[i:end]
|
||||
i = end - 1 // loop will i++
|
||||
|
||||
// Record file names
|
||||
depth := 0
|
||||
for j := range obj.Paths {
|
||||
s := &obj.Paths[j]
|
||||
if s.Name == "" {
|
||||
depth--
|
||||
} else {
|
||||
if depth == 0 {
|
||||
t.Files[s.Name] = obj
|
||||
}
|
||||
depth++
|
||||
}
|
||||
}
|
||||
|
||||
case 'T', 't', 'L', 'l': // text symbol
|
||||
if n := len(t.Funcs); n > 0 {
|
||||
t.Funcs[n-1].End = sym.Value
|
||||
}
|
||||
if sym.Name == "etext" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Count parameter and local (auto) syms
|
||||
var np, na int
|
||||
var end int
|
||||
countloop:
|
||||
for end = i + 1; end < len(t.Syms); end++ {
|
||||
switch t.Syms[end].Type {
|
||||
case 'T', 't', 'L', 'l', 'Z', 'z':
|
||||
break countloop
|
||||
case 'p':
|
||||
np++
|
||||
case 'a':
|
||||
na++
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the function symbol
|
||||
n := len(t.Funcs)
|
||||
t.Funcs = t.Funcs[0 : n+1]
|
||||
fn := &t.Funcs[n]
|
||||
sym.Func = fn
|
||||
fn.Params = make([]*Sym, 0, np)
|
||||
fn.Locals = make([]*Sym, 0, na)
|
||||
fn.Sym = sym
|
||||
fn.Entry = sym.Value
|
||||
fn.Obj = obj
|
||||
if t.go12line != nil {
|
||||
// All functions share the same line table.
|
||||
// It knows how to narrow down to a specific
|
||||
// function quickly.
|
||||
fn.LineTable = t.go12line
|
||||
} else if pcln != nil {
|
||||
fn.LineTable = pcln.slice(fn.Entry)
|
||||
pcln = fn.LineTable
|
||||
}
|
||||
for j := i; j < end; j++ {
|
||||
s := &t.Syms[j]
|
||||
switch s.Type {
|
||||
case 'm':
|
||||
fn.FrameSize = int(s.Value)
|
||||
case 'p':
|
||||
n := len(fn.Params)
|
||||
fn.Params = fn.Params[0 : n+1]
|
||||
fn.Params[n] = s
|
||||
case 'a':
|
||||
n := len(fn.Locals)
|
||||
fn.Locals = fn.Locals[0 : n+1]
|
||||
fn.Locals[n] = s
|
||||
}
|
||||
}
|
||||
i = end - 1 // loop will i++
|
||||
}
|
||||
}
|
||||
|
||||
if t.go12line != nil && nf == 0 {
|
||||
t.Funcs = t.go12line.go12Funcs()
|
||||
}
|
||||
if obj != nil {
|
||||
obj.Funcs = t.Funcs[lastf:]
|
||||
}
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
// PCToFunc returns the function containing the program counter pc,
|
||||
// or nil if there is no such function.
|
||||
func (t *Table) PCToFunc(pc uint64) *Func {
|
||||
funcs := t.Funcs
|
||||
for len(funcs) > 0 {
|
||||
m := len(funcs) / 2
|
||||
fn := &funcs[m]
|
||||
switch {
|
||||
case pc < fn.Entry:
|
||||
funcs = funcs[0:m]
|
||||
case fn.Entry <= pc && pc < fn.End:
|
||||
return fn
|
||||
default:
|
||||
funcs = funcs[m+1:]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PCToLine looks up line number information for a program counter.
|
||||
// If there is no information, it returns fn == nil.
|
||||
func (t *Table) PCToLine(pc uint64) (file string, line int, fn *Func) {
|
||||
if fn = t.PCToFunc(pc); fn == nil {
|
||||
return
|
||||
}
|
||||
if t.go12line != nil {
|
||||
file = t.go12line.go12PCToFile(pc)
|
||||
line = t.go12line.go12PCToLine(pc)
|
||||
} else {
|
||||
file, line = fn.Obj.lineFromAline(fn.LineTable.PCToLine(pc))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PCToSPAdj returns the stack pointer adjustment for a program counter.
|
||||
func (t *Table) PCToSPAdj(pc uint64) (spadj int) {
|
||||
if fn := t.PCToFunc(pc); fn == nil {
|
||||
return 0
|
||||
}
|
||||
if t.go12line != nil {
|
||||
return t.go12line.go12PCToSPAdj(pc)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// LineToPC looks up the first program counter on the given line in
|
||||
// the named file. It returns UnknownPathError or UnknownLineError if
|
||||
// there is an error looking up this line.
|
||||
func (t *Table) LineToPC(file string, line int) (pc uint64, fn *Func, err error) {
|
||||
obj, ok := t.Files[file]
|
||||
if !ok {
|
||||
return 0, nil, UnknownFileError(file)
|
||||
}
|
||||
|
||||
if t.go12line != nil {
|
||||
pc := t.go12line.go12LineToPC(file, line)
|
||||
if pc == 0 {
|
||||
return 0, nil, &UnknownLineError{file, line}
|
||||
}
|
||||
return pc, t.PCToFunc(pc), nil
|
||||
}
|
||||
|
||||
abs, err := obj.alineFromLine(file, line)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for i := range obj.Funcs {
|
||||
f := &obj.Funcs[i]
|
||||
pc := f.LineTable.LineToPC(abs, f.End)
|
||||
if pc != 0 {
|
||||
return pc, f, nil
|
||||
}
|
||||
}
|
||||
return 0, nil, &UnknownLineError{file, line}
|
||||
}
|
||||
|
||||
// LookupSym returns the text, data, or bss symbol with the given name,
|
||||
// or nil if no such symbol is found.
|
||||
func (t *Table) LookupSym(name string) *Sym {
|
||||
// TODO(austin) Maybe make a map
|
||||
for i := range t.Syms {
|
||||
s := &t.Syms[i]
|
||||
switch s.Type {
|
||||
case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b':
|
||||
if s.Name == name {
|
||||
return s
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LookupFunc returns the text, data, or bss symbol with the given name,
|
||||
// or nil if no such symbol is found.
|
||||
func (t *Table) LookupFunc(name string) *Func {
|
||||
for i := range t.Funcs {
|
||||
f := &t.Funcs[i]
|
||||
if f.Sym.Name == name {
|
||||
return f
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SymByAddr returns the text, data, or bss symbol starting at the given address.
|
||||
func (t *Table) SymByAddr(addr uint64) *Sym {
|
||||
for i := range t.Syms {
|
||||
s := &t.Syms[i]
|
||||
switch s.Type {
|
||||
case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b':
|
||||
if s.Value == addr {
|
||||
return s
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
* Object files
|
||||
*/
|
||||
|
||||
// This is legacy code for Go 1.1 and earlier, which used the
|
||||
// Plan 9 format for pc-line tables. This code was never quite
|
||||
// correct. It's probably very close, and it's usually correct, but
|
||||
// we never quite found all the corner cases.
|
||||
//
|
||||
// Go 1.2 and later use a simpler format, documented at golang.org/s/go12symtab.
|
||||
|
||||
func (o *Obj) lineFromAline(aline int) (string, int) {
|
||||
type stackEnt struct {
|
||||
path string
|
||||
start int
|
||||
offset int
|
||||
prev *stackEnt
|
||||
}
|
||||
|
||||
noPath := &stackEnt{"", 0, 0, nil}
|
||||
tos := noPath
|
||||
|
||||
pathloop:
|
||||
for _, s := range o.Paths {
|
||||
val := int(s.Value)
|
||||
switch {
|
||||
case val > aline:
|
||||
break pathloop
|
||||
|
||||
case val == 1:
|
||||
// Start a new stack
|
||||
tos = &stackEnt{s.Name, val, 0, noPath}
|
||||
|
||||
case s.Name == "":
|
||||
// Pop
|
||||
if tos == noPath {
|
||||
return "<malformed symbol table>", 0
|
||||
}
|
||||
tos.prev.offset += val - tos.start
|
||||
tos = tos.prev
|
||||
|
||||
default:
|
||||
// Push
|
||||
tos = &stackEnt{s.Name, val, 0, tos}
|
||||
}
|
||||
}
|
||||
|
||||
if tos == noPath {
|
||||
return "", 0
|
||||
}
|
||||
return tos.path, aline - tos.start - tos.offset + 1
|
||||
}
|
||||
|
||||
func (o *Obj) alineFromLine(path string, line int) (int, error) {
|
||||
if line < 1 {
|
||||
return 0, &UnknownLineError{path, line}
|
||||
}
|
||||
|
||||
for i, s := range o.Paths {
|
||||
// Find this path
|
||||
if s.Name != path {
|
||||
continue
|
||||
}
|
||||
|
||||
// Find this line at this stack level
|
||||
depth := 0
|
||||
var incstart int
|
||||
line += int(s.Value)
|
||||
pathloop:
|
||||
for _, s := range o.Paths[i:] {
|
||||
val := int(s.Value)
|
||||
switch {
|
||||
case depth == 1 && val >= line:
|
||||
return line - 1, nil
|
||||
|
||||
case s.Name == "":
|
||||
depth--
|
||||
if depth == 0 {
|
||||
break pathloop
|
||||
} else if depth == 1 {
|
||||
line += val - incstart
|
||||
}
|
||||
|
||||
default:
|
||||
if depth == 1 {
|
||||
incstart = val
|
||||
}
|
||||
depth++
|
||||
}
|
||||
}
|
||||
return 0, &UnknownLineError{path, line}
|
||||
}
|
||||
return 0, UnknownFileError(path)
|
||||
}
|
||||
|
||||
/*
|
||||
* Errors
|
||||
*/
|
||||
|
||||
// UnknownFileError represents a failure to find the specific file in
|
||||
// the symbol table.
|
||||
type UnknownFileError string
|
||||
|
||||
func (e UnknownFileError) Error() string { return "unknown file: " + string(e) }
|
||||
|
||||
// UnknownLineError represents a failure to map a line to a program
|
||||
// counter, either because the line is beyond the bounds of the file
|
||||
// or because there is no code on the given line.
|
||||
type UnknownLineError struct {
|
||||
File string
|
||||
Line int
|
||||
}
|
||||
|
||||
func (e *UnknownLineError) Error() string {
|
||||
return "no code at " + e.File + ":" + strconv.Itoa(e.Line)
|
||||
}
|
||||
|
||||
// DecodingError represents an error during the decoding of
|
||||
// the symbol table.
|
||||
type DecodingError struct {
|
||||
off int
|
||||
msg string
|
||||
val interface{}
|
||||
}
|
||||
|
||||
func (e *DecodingError) Error() string {
|
||||
msg := e.msg
|
||||
if e.val != nil {
|
||||
msg += fmt.Sprintf(" '%v'", e.val)
|
||||
}
|
||||
msg += fmt.Sprintf(" at byte %#x", e.off)
|
||||
return msg
|
||||
}
|
40
vendor/cloud.google.com/go/compute/README.md
generated
vendored
Normal file
40
vendor/cloud.google.com/go/compute/README.md
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Compute API
|
||||
|
||||
[![Go Reference](https://pkg.go.dev/badge/cloud.google.com/go/compute.svg)](https://pkg.go.dev/cloud.google.com/go/compute)
|
||||
|
||||
Go Client Library for Compute API.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get cloud.google.com/go/compute
|
||||
```
|
||||
|
||||
## Stability
|
||||
|
||||
The stability of this module is indicated by SemVer.
|
||||
|
||||
However, a `v1+` module may have breaking changes in two scenarios:
|
||||
|
||||
* Packages with `alpha` or `beta` in the import path
|
||||
* The GoDoc has an explicit stability disclaimer (for example, for an experimental feature).
|
||||
|
||||
## Go Version Support
|
||||
|
||||
See the [Go Versions Supported](https://github.com/googleapis/google-cloud-go#go-versions-supported)
|
||||
section in the root directory's README.
|
||||
|
||||
## Authorization
|
||||
|
||||
See the [Authorization](https://github.com/googleapis/google-cloud-go#authorization)
|
||||
section in the root directory's README.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome. Please, see the [CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md)
|
||||
document for details.
|
||||
|
||||
Please note that this project is released with a Contributor Code of Conduct.
|
||||
By participating in this project you agree to abide by its terms. See
|
||||
[Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md#contributor-code-of-conduct)
|
||||
for more information.
|
13
vendor/cloud.google.com/go/compute/go.mod
generated
vendored
Normal file
13
vendor/cloud.google.com/go/compute/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
module cloud.google.com/go/compute
|
||||
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.100.2
|
||||
github.com/google/go-cmp v0.5.7
|
||||
github.com/googleapis/gax-go/v2 v2.3.0
|
||||
google.golang.org/api v0.74.0
|
||||
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac
|
||||
google.golang.org/grpc v1.45.0
|
||||
google.golang.org/protobuf v1.28.0
|
||||
)
|
541
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
Normal file
541
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
Normal file
|
@ -0,0 +1,541 @@
|
|||
// Copyright 2014 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package metadata provides access to Google Compute Engine (GCE)
|
||||
// metadata and API service accounts.
|
||||
//
|
||||
// This package is a wrapper around the GCE metadata service,
|
||||
// as documented at https://developers.google.com/compute/docs/metadata.
|
||||
package metadata // import "cloud.google.com/go/compute/metadata"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// metadataIP is the documented metadata server IP address.
|
||||
metadataIP = "169.254.169.254"
|
||||
|
||||
// metadataHostEnv is the environment variable specifying the
|
||||
// GCE metadata hostname. If empty, the default value of
|
||||
// metadataIP ("169.254.169.254") is used instead.
|
||||
// This is variable name is not defined by any spec, as far as
|
||||
// I know; it was made up for the Go package.
|
||||
metadataHostEnv = "GCE_METADATA_HOST"
|
||||
|
||||
userAgent = "gcloud-golang/0.1"
|
||||
)
|
||||
|
||||
type cachedValue struct {
|
||||
k string
|
||||
trim bool
|
||||
mu sync.Mutex
|
||||
v string
|
||||
}
|
||||
|
||||
var (
|
||||
projID = &cachedValue{k: "project/project-id", trim: true}
|
||||
projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
|
||||
instID = &cachedValue{k: "instance/id", trim: true}
|
||||
)
|
||||
|
||||
var defaultClient = &Client{hc: newDefaultHTTPClient()}
|
||||
|
||||
func newDefaultHTTPClient() *http.Client {
|
||||
return &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 2 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NotDefinedError is returned when requested metadata is not defined.
|
||||
//
|
||||
// The underlying string is the suffix after "/computeMetadata/v1/".
|
||||
//
|
||||
// This error is not returned if the value is defined to be the empty
|
||||
// string.
|
||||
type NotDefinedError string
|
||||
|
||||
func (suffix NotDefinedError) Error() string {
|
||||
return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
|
||||
}
|
||||
|
||||
func (c *cachedValue) get(cl *Client) (v string, err error) {
|
||||
defer c.mu.Unlock()
|
||||
c.mu.Lock()
|
||||
if c.v != "" {
|
||||
return c.v, nil
|
||||
}
|
||||
if c.trim {
|
||||
v, err = cl.getTrimmed(c.k)
|
||||
} else {
|
||||
v, err = cl.Get(c.k)
|
||||
}
|
||||
if err == nil {
|
||||
c.v = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
onGCEOnce sync.Once
|
||||
onGCE bool
|
||||
)
|
||||
|
||||
// OnGCE reports whether this process is running on Google Compute Engine.
|
||||
func OnGCE() bool {
|
||||
onGCEOnce.Do(initOnGCE)
|
||||
return onGCE
|
||||
}
|
||||
|
||||
func initOnGCE() {
|
||||
onGCE = testOnGCE()
|
||||
}
|
||||
|
||||
func testOnGCE() bool {
|
||||
// The user explicitly said they're on GCE, so trust them.
|
||||
if os.Getenv(metadataHostEnv) != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
resc := make(chan bool, 2)
|
||||
|
||||
// Try two strategies in parallel.
|
||||
// See https://github.com/googleapis/google-cloud-go/issues/194
|
||||
go func() {
|
||||
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
|
||||
req.Header.Set("User-Agent", userAgent)
|
||||
res, err := newDefaultHTTPClient().Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
resc <- false
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
resc <- res.Header.Get("Metadata-Flavor") == "Google"
|
||||
}()
|
||||
|
||||
go func() {
|
||||
resolver := &net.Resolver{}
|
||||
addrs, err := resolver.LookupHost(ctx, "metadata.google.internal")
|
||||
if err != nil || len(addrs) == 0 {
|
||||
resc <- false
|
||||
return
|
||||
}
|
||||
resc <- strsContains(addrs, metadataIP)
|
||||
}()
|
||||
|
||||
tryHarder := systemInfoSuggestsGCE()
|
||||
if tryHarder {
|
||||
res := <-resc
|
||||
if res {
|
||||
// The first strategy succeeded, so let's use it.
|
||||
return true
|
||||
}
|
||||
// Wait for either the DNS or metadata server probe to
|
||||
// contradict the other one and say we are running on
|
||||
// GCE. Give it a lot of time to do so, since the system
|
||||
// info already suggests we're running on a GCE BIOS.
|
||||
timer := time.NewTimer(5 * time.Second)
|
||||
defer timer.Stop()
|
||||
select {
|
||||
case res = <-resc:
|
||||
return res
|
||||
case <-timer.C:
|
||||
// Too slow. Who knows what this system is.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// There's no hint from the system info that we're running on
|
||||
// GCE, so use the first probe's result as truth, whether it's
|
||||
// true or false. The goal here is to optimize for speed for
|
||||
// users who are NOT running on GCE. We can't assume that
|
||||
// either a DNS lookup or an HTTP request to a blackholed IP
|
||||
// address is fast. Worst case this should return when the
|
||||
// metaClient's Transport.ResponseHeaderTimeout or
|
||||
// Transport.Dial.Timeout fires (in two seconds).
|
||||
return <-resc
|
||||
}
|
||||
|
||||
// systemInfoSuggestsGCE reports whether the local system (without
|
||||
// doing network requests) suggests that we're running on GCE. If this
|
||||
// returns true, testOnGCE tries a bit harder to reach its metadata
|
||||
// server.
|
||||
func systemInfoSuggestsGCE() bool {
|
||||
if runtime.GOOS != "linux" {
|
||||
// We don't have any non-Linux clues available, at least yet.
|
||||
return false
|
||||
}
|
||||
slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name")
|
||||
name := strings.TrimSpace(string(slurp))
|
||||
return name == "Google" || name == "Google Compute Engine"
|
||||
}
|
||||
|
||||
// Subscribe calls Client.Subscribe on the default client.
|
||||
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||
return defaultClient.Subscribe(suffix, fn)
|
||||
}
|
||||
|
||||
// Get calls Client.Get on the default client.
|
||||
func Get(suffix string) (string, error) { return defaultClient.Get(suffix) }
|
||||
|
||||
// ProjectID returns the current instance's project ID string.
|
||||
func ProjectID() (string, error) { return defaultClient.ProjectID() }
|
||||
|
||||
// NumericProjectID returns the current instance's numeric project ID.
|
||||
func NumericProjectID() (string, error) { return defaultClient.NumericProjectID() }
|
||||
|
||||
// InternalIP returns the instance's primary internal IP address.
|
||||
func InternalIP() (string, error) { return defaultClient.InternalIP() }
|
||||
|
||||
// ExternalIP returns the instance's primary external (public) IP address.
|
||||
func ExternalIP() (string, error) { return defaultClient.ExternalIP() }
|
||||
|
||||
// Email calls Client.Email on the default client.
|
||||
func Email(serviceAccount string) (string, error) { return defaultClient.Email(serviceAccount) }
|
||||
|
||||
// Hostname returns the instance's hostname. This will be of the form
|
||||
// "<instanceID>.c.<projID>.internal".
|
||||
func Hostname() (string, error) { return defaultClient.Hostname() }
|
||||
|
||||
// InstanceTags returns the list of user-defined instance tags,
|
||||
// assigned when initially creating a GCE instance.
|
||||
func InstanceTags() ([]string, error) { return defaultClient.InstanceTags() }
|
||||
|
||||
// InstanceID returns the current VM's numeric instance ID.
|
||||
func InstanceID() (string, error) { return defaultClient.InstanceID() }
|
||||
|
||||
// InstanceName returns the current VM's instance ID string.
|
||||
func InstanceName() (string, error) { return defaultClient.InstanceName() }
|
||||
|
||||
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||
func Zone() (string, error) { return defaultClient.Zone() }
|
||||
|
||||
// InstanceAttributes calls Client.InstanceAttributes on the default client.
|
||||
func InstanceAttributes() ([]string, error) { return defaultClient.InstanceAttributes() }
|
||||
|
||||
// ProjectAttributes calls Client.ProjectAttributes on the default client.
|
||||
func ProjectAttributes() ([]string, error) { return defaultClient.ProjectAttributes() }
|
||||
|
||||
// InstanceAttributeValue calls Client.InstanceAttributeValue on the default client.
|
||||
func InstanceAttributeValue(attr string) (string, error) {
|
||||
return defaultClient.InstanceAttributeValue(attr)
|
||||
}
|
||||
|
||||
// ProjectAttributeValue calls Client.ProjectAttributeValue on the default client.
|
||||
func ProjectAttributeValue(attr string) (string, error) {
|
||||
return defaultClient.ProjectAttributeValue(attr)
|
||||
}
|
||||
|
||||
// Scopes calls Client.Scopes on the default client.
|
||||
func Scopes(serviceAccount string) ([]string, error) { return defaultClient.Scopes(serviceAccount) }
|
||||
|
||||
func strsContains(ss []string, s string) bool {
|
||||
for _, v := range ss {
|
||||
if v == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// A Client provides metadata.
|
||||
type Client struct {
|
||||
hc *http.Client
|
||||
}
|
||||
|
||||
// NewClient returns a Client that can be used to fetch metadata.
|
||||
// Returns the client that uses the specified http.Client for HTTP requests.
|
||||
// If nil is specified, returns the default client.
|
||||
func NewClient(c *http.Client) *Client {
|
||||
if c == nil {
|
||||
return defaultClient
|
||||
}
|
||||
|
||||
return &Client{hc: c}
|
||||
}
|
||||
|
||||
// getETag returns a value from the metadata service as well as the associated ETag.
|
||||
// This func is otherwise equivalent to Get.
|
||||
func (c *Client) getETag(suffix string) (value, etag string, err error) {
|
||||
ctx := context.TODO()
|
||||
// Using a fixed IP makes it very difficult to spoof the metadata service in
|
||||
// a container, which is an important use-case for local testing of cloud
|
||||
// deployments. To enable spoofing of the metadata service, the environment
|
||||
// variable GCE_METADATA_HOST is first inspected to decide where metadata
|
||||
// requests shall go.
|
||||
host := os.Getenv(metadataHostEnv)
|
||||
if host == "" {
|
||||
// Using 169.254.169.254 instead of "metadata" here because Go
|
||||
// binaries built with the "netgo" tag and without cgo won't
|
||||
// know the search suffix for "metadata" is
|
||||
// ".google.internal", and this IP address is documented as
|
||||
// being stable anyway.
|
||||
host = metadataIP
|
||||
}
|
||||
suffix = strings.TrimLeft(suffix, "/")
|
||||
u := "http://" + host + "/computeMetadata/v1/" + suffix
|
||||
req, err := http.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
req.Header.Set("Metadata-Flavor", "Google")
|
||||
req.Header.Set("User-Agent", userAgent)
|
||||
var res *http.Response
|
||||
var reqErr error
|
||||
retryer := newRetryer()
|
||||
for {
|
||||
res, reqErr = c.hc.Do(req)
|
||||
var code int
|
||||
if res != nil {
|
||||
code = res.StatusCode
|
||||
}
|
||||
if delay, shouldRetry := retryer.Retry(code, reqErr); shouldRetry {
|
||||
if err := sleep(ctx, delay); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
if reqErr != nil {
|
||||
return "", "", reqErr
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode == http.StatusNotFound {
|
||||
return "", "", NotDefinedError(suffix)
|
||||
}
|
||||
all, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
return "", "", &Error{Code: res.StatusCode, Message: string(all)}
|
||||
}
|
||||
return string(all), res.Header.Get("Etag"), nil
|
||||
}
|
||||
|
||||
// Get returns a value from the metadata service.
|
||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||
//
|
||||
// If the GCE_METADATA_HOST environment variable is not defined, a default of
|
||||
// 169.254.169.254 will be used instead.
|
||||
//
|
||||
// If the requested metadata is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
func (c *Client) Get(suffix string) (string, error) {
|
||||
val, _, err := c.getETag(suffix)
|
||||
return val, err
|
||||
}
|
||||
|
||||
func (c *Client) getTrimmed(suffix string) (s string, err error) {
|
||||
s, err = c.Get(suffix)
|
||||
s = strings.TrimSpace(s)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) lines(suffix string) ([]string, error) {
|
||||
j, err := c.Get(suffix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := strings.Split(strings.TrimSpace(j), "\n")
|
||||
for i := range s {
|
||||
s[i] = strings.TrimSpace(s[i])
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// ProjectID returns the current instance's project ID string.
|
||||
func (c *Client) ProjectID() (string, error) { return projID.get(c) }
|
||||
|
||||
// NumericProjectID returns the current instance's numeric project ID.
|
||||
func (c *Client) NumericProjectID() (string, error) { return projNum.get(c) }
|
||||
|
||||
// InstanceID returns the current VM's numeric instance ID.
|
||||
func (c *Client) InstanceID() (string, error) { return instID.get(c) }
|
||||
|
||||
// InternalIP returns the instance's primary internal IP address.
|
||||
func (c *Client) InternalIP() (string, error) {
|
||||
return c.getTrimmed("instance/network-interfaces/0/ip")
|
||||
}
|
||||
|
||||
// Email returns the email address associated with the service account.
|
||||
// The account may be empty or the string "default" to use the instance's
|
||||
// main account.
|
||||
func (c *Client) Email(serviceAccount string) (string, error) {
|
||||
if serviceAccount == "" {
|
||||
serviceAccount = "default"
|
||||
}
|
||||
return c.getTrimmed("instance/service-accounts/" + serviceAccount + "/email")
|
||||
}
|
||||
|
||||
// ExternalIP returns the instance's primary external (public) IP address.
|
||||
func (c *Client) ExternalIP() (string, error) {
|
||||
return c.getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
|
||||
}
|
||||
|
||||
// Hostname returns the instance's hostname. This will be of the form
|
||||
// "<instanceID>.c.<projID>.internal".
|
||||
func (c *Client) Hostname() (string, error) {
|
||||
return c.getTrimmed("instance/hostname")
|
||||
}
|
||||
|
||||
// InstanceTags returns the list of user-defined instance tags,
|
||||
// assigned when initially creating a GCE instance.
|
||||
func (c *Client) InstanceTags() ([]string, error) {
|
||||
var s []string
|
||||
j, err := c.Get("instance/tags")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// InstanceName returns the current VM's instance ID string.
|
||||
func (c *Client) InstanceName() (string, error) {
|
||||
return c.getTrimmed("instance/name")
|
||||
}
|
||||
|
||||
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||
func (c *Client) Zone() (string, error) {
|
||||
zone, err := c.getTrimmed("instance/zone")
|
||||
// zone is of the form "projects/<projNum>/zones/<zoneName>".
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return zone[strings.LastIndex(zone, "/")+1:], nil
|
||||
}
|
||||
|
||||
// InstanceAttributes returns the list of user-defined attributes,
|
||||
// assigned when initially creating a GCE VM instance. The value of an
|
||||
// attribute can be obtained with InstanceAttributeValue.
|
||||
func (c *Client) InstanceAttributes() ([]string, error) { return c.lines("instance/attributes/") }
|
||||
|
||||
// ProjectAttributes returns the list of user-defined attributes
|
||||
// applying to the project as a whole, not just this VM. The value of
|
||||
// an attribute can be obtained with ProjectAttributeValue.
|
||||
func (c *Client) ProjectAttributes() ([]string, error) { return c.lines("project/attributes/") }
|
||||
|
||||
// InstanceAttributeValue returns the value of the provided VM
|
||||
// instance attribute.
|
||||
//
|
||||
// If the requested attribute is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
//
|
||||
// InstanceAttributeValue may return ("", nil) if the attribute was
|
||||
// defined to be the empty string.
|
||||
func (c *Client) InstanceAttributeValue(attr string) (string, error) {
|
||||
return c.Get("instance/attributes/" + attr)
|
||||
}
|
||||
|
||||
// ProjectAttributeValue returns the value of the provided
|
||||
// project attribute.
|
||||
//
|
||||
// If the requested attribute is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
//
|
||||
// ProjectAttributeValue may return ("", nil) if the attribute was
|
||||
// defined to be the empty string.
|
||||
func (c *Client) ProjectAttributeValue(attr string) (string, error) {
|
||||
return c.Get("project/attributes/" + attr)
|
||||
}
|
||||
|
||||
// Scopes returns the service account scopes for the given account.
|
||||
// The account may be empty or the string "default" to use the instance's
|
||||
// main account.
|
||||
func (c *Client) Scopes(serviceAccount string) ([]string, error) {
|
||||
if serviceAccount == "" {
|
||||
serviceAccount = "default"
|
||||
}
|
||||
return c.lines("instance/service-accounts/" + serviceAccount + "/scopes")
|
||||
}
|
||||
|
||||
// Subscribe subscribes to a value from the metadata service.
|
||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||
// The suffix may contain query parameters.
|
||||
//
|
||||
// Subscribe calls fn with the latest metadata value indicated by the provided
|
||||
// suffix. If the metadata value is deleted, fn is called with the empty string
|
||||
// and ok false. Subscribe blocks until fn returns a non-nil error or the value
|
||||
// is deleted. Subscribe returns the error value returned from the last call to
|
||||
// fn, which may be nil when ok == false.
|
||||
func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||
const failedSubscribeSleep = time.Second * 5
|
||||
|
||||
// First check to see if the metadata value exists at all.
|
||||
val, lastETag, err := c.getETag(suffix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := fn(val, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ok := true
|
||||
if strings.ContainsRune(suffix, '?') {
|
||||
suffix += "&wait_for_change=true&last_etag="
|
||||
} else {
|
||||
suffix += "?wait_for_change=true&last_etag="
|
||||
}
|
||||
for {
|
||||
val, etag, err := c.getETag(suffix + url.QueryEscape(lastETag))
|
||||
if err != nil {
|
||||
if _, deleted := err.(NotDefinedError); !deleted {
|
||||
time.Sleep(failedSubscribeSleep)
|
||||
continue // Retry on other errors.
|
||||
}
|
||||
ok = false
|
||||
}
|
||||
lastETag = etag
|
||||
|
||||
if err := fn(val, ok); err != nil || !ok {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Error contains an error response from the server.
|
||||
type Error struct {
|
||||
// Code is the HTTP response status code.
|
||||
Code int
|
||||
// Message is the server response message.
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return fmt.Sprintf("compute: Received %d `%s`", e.Code, e.Message)
|
||||
}
|
114
vendor/cloud.google.com/go/compute/metadata/retry.go
generated
vendored
Normal file
114
vendor/cloud.google.com/go/compute/metadata/retry.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
|||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
maxRetryAttempts = 5
|
||||
)
|
||||
|
||||
var (
|
||||
syscallRetryable = func(err error) bool { return false }
|
||||
)
|
||||
|
||||
// defaultBackoff is basically equivalent to gax.Backoff without the need for
|
||||
// the dependency.
|
||||
type defaultBackoff struct {
|
||||
max time.Duration
|
||||
mul float64
|
||||
cur time.Duration
|
||||
}
|
||||
|
||||
func (b *defaultBackoff) Pause() time.Duration {
|
||||
d := time.Duration(1 + rand.Int63n(int64(b.cur)))
|
||||
b.cur = time.Duration(float64(b.cur) * b.mul)
|
||||
if b.cur > b.max {
|
||||
b.cur = b.max
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// sleep is the equivalent of gax.Sleep without the need for the dependency.
|
||||
func sleep(ctx context.Context, d time.Duration) error {
|
||||
t := time.NewTimer(d)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Stop()
|
||||
return ctx.Err()
|
||||
case <-t.C:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func newRetryer() *metadataRetryer {
|
||||
return &metadataRetryer{bo: &defaultBackoff{
|
||||
cur: 100 * time.Millisecond,
|
||||
max: 30 * time.Second,
|
||||
mul: 2,
|
||||
}}
|
||||
}
|
||||
|
||||
type backoff interface {
|
||||
Pause() time.Duration
|
||||
}
|
||||
|
||||
type metadataRetryer struct {
|
||||
bo backoff
|
||||
attempts int
|
||||
}
|
||||
|
||||
func (r *metadataRetryer) Retry(status int, err error) (time.Duration, bool) {
|
||||
if status == http.StatusOK {
|
||||
return 0, false
|
||||
}
|
||||
retryOk := shouldRetry(status, err)
|
||||
if !retryOk {
|
||||
return 0, false
|
||||
}
|
||||
if r.attempts == maxRetryAttempts {
|
||||
return 0, false
|
||||
}
|
||||
r.attempts++
|
||||
return r.bo.Pause(), true
|
||||
}
|
||||
|
||||
func shouldRetry(status int, err error) bool {
|
||||
if 500 <= status && status <= 599 {
|
||||
return true
|
||||
}
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
return true
|
||||
}
|
||||
// Transient network errors should be retried.
|
||||
if syscallRetryable(err) {
|
||||
return true
|
||||
}
|
||||
if err, ok := err.(interface{ Temporary() bool }); ok {
|
||||
if err.Temporary() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if err, ok := err.(interface{ Unwrap() error }); ok {
|
||||
return shouldRetry(status, err.Unwrap())
|
||||
}
|
||||
return false
|
||||
}
|
26
vendor/cloud.google.com/go/compute/metadata/retry_linux.go
generated
vendored
Normal file
26
vendor/cloud.google.com/go/compute/metadata/retry_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package metadata
|
||||
|
||||
import "syscall"
|
||||
|
||||
func init() {
|
||||
// Initialize syscallRetryable to return true on transient socket-level
|
||||
// errors. These errors are specific to Linux.
|
||||
syscallRetryable = func(err error) bool { return err == syscall.ECONNRESET || err == syscall.ECONNREFUSED }
|
||||
}
|
19
vendor/cloud.google.com/go/go.mod
generated
vendored
Normal file
19
vendor/cloud.google.com/go/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
module cloud.google.com/go
|
||||
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.5.0
|
||||
cloud.google.com/go/storage v1.22.0
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/google/go-cmp v0.5.7
|
||||
github.com/google/martian/v3 v3.3.2
|
||||
github.com/googleapis/gax-go/v2 v2.3.0
|
||||
go.opencensus.io v0.23.0
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f
|
||||
google.golang.org/api v0.74.0
|
||||
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac
|
||||
google.golang.org/grpc v1.45.0
|
||||
google.golang.org/protobuf v1.28.0
|
||||
)
|
2
vendor/golang.org/x/oauth2/LICENSE
generated
vendored
2
vendor/golang.org/x/oauth2/LICENSE
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2009 The oauth2 Authors. All rights reserved.
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
|
62
vendor/golang.org/x/oauth2/README.md
generated
vendored
62
vendor/golang.org/x/oauth2/README.md
generated
vendored
|
@ -1,5 +1,6 @@
|
|||
# OAuth2 for Go
|
||||
|
||||
[![Go Reference](https://pkg.go.dev/badge/golang.org/x/oauth2.svg)](https://pkg.go.dev/golang.org/x/oauth2)
|
||||
[![Build Status](https://travis-ci.org/golang/oauth2.svg?branch=master)](https://travis-ci.org/golang/oauth2)
|
||||
|
||||
oauth2 package contains a client implementation for OAuth 2.0 spec.
|
||||
|
@ -10,55 +11,26 @@ oauth2 package contains a client implementation for OAuth 2.0 spec.
|
|||
go get golang.org/x/oauth2
|
||||
~~~~
|
||||
|
||||
See godoc for further documentation and examples.
|
||||
Or you can manually git clone the repository to
|
||||
`$(go env GOPATH)/src/golang.org/x/oauth2`.
|
||||
|
||||
* [godoc.org/golang.org/x/oauth2](http://godoc.org/golang.org/x/oauth2)
|
||||
* [godoc.org/golang.org/x/oauth2/google](http://godoc.org/golang.org/x/oauth2/google)
|
||||
See pkg.go.dev for further documentation and examples.
|
||||
|
||||
* [pkg.go.dev/golang.org/x/oauth2](https://pkg.go.dev/golang.org/x/oauth2)
|
||||
* [pkg.go.dev/golang.org/x/oauth2/google](https://pkg.go.dev/golang.org/x/oauth2/google)
|
||||
|
||||
## App Engine
|
||||
## Policy for new packages
|
||||
|
||||
In change 96e89be (March 2015) we removed the `oauth2.Context2` type in favor
|
||||
of the [`context.Context`](https://golang.org/x/net/context#Context) type from
|
||||
the `golang.org/x/net/context` package
|
||||
We no longer accept new provider-specific packages in this repo if all
|
||||
they do is add a single endpoint variable. If you just want to add a
|
||||
single endpoint, add it to the
|
||||
[pkg.go.dev/golang.org/x/oauth2/endpoints](https://pkg.go.dev/golang.org/x/oauth2/endpoints)
|
||||
package.
|
||||
|
||||
This means its no longer possible to use the "Classic App Engine"
|
||||
`appengine.Context` type with the `oauth2` package. (You're using
|
||||
Classic App Engine if you import the package `"appengine"`.)
|
||||
## Report Issues / Send Patches
|
||||
|
||||
To work around this, you may use the new `"google.golang.org/appengine"`
|
||||
package. This package has almost the same API as the `"appengine"` package,
|
||||
but it can be fetched with `go get` and used on "Managed VMs" and well as
|
||||
Classic App Engine.
|
||||
|
||||
See the [new `appengine` package's readme](https://github.com/golang/appengine#updating-a-go-app-engine-app)
|
||||
for information on updating your app.
|
||||
|
||||
If you don't want to update your entire app to use the new App Engine packages,
|
||||
you may use both sets of packages in parallel, using only the new packages
|
||||
with the `oauth2` package.
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
newappengine "google.golang.org/appengine"
|
||||
newurlfetch "google.golang.org/appengine/urlfetch"
|
||||
|
||||
"appengine"
|
||||
)
|
||||
|
||||
func handler(w http.ResponseWriter, r *http.Request) {
|
||||
var c appengine.Context = appengine.NewContext(r)
|
||||
c.Infof("Logging a message with the old package")
|
||||
|
||||
var ctx context.Context = newappengine.NewContext(r)
|
||||
client := &http.Client{
|
||||
Transport: &oauth2.Transport{
|
||||
Source: google.AppEngineTokenSource(ctx, "scope"),
|
||||
Base: &newurlfetch.Transport{Context: ctx},
|
||||
},
|
||||
}
|
||||
client.Get("...")
|
||||
}
|
||||
This repository uses Gerrit for code changes. To learn how to submit changes to
|
||||
this repository, see https://golang.org/doc/contribute.html.
|
||||
|
||||
The main issue tracker for the oauth2 repository is located at
|
||||
https://github.com/golang/oauth2/issues.
|
||||
|
|
56
vendor/golang.org/x/oauth2/authhandler/authhandler.go
generated
vendored
Normal file
56
vendor/golang.org/x/oauth2/authhandler/authhandler.go
generated
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package authhandler implements a TokenSource to support
|
||||
// "three-legged OAuth 2.0" via a custom AuthorizationHandler.
|
||||
package authhandler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// AuthorizationHandler is a 3-legged-OAuth helper that prompts
|
||||
// the user for OAuth consent at the specified auth code URL
|
||||
// and returns an auth code and state upon approval.
|
||||
type AuthorizationHandler func(authCodeURL string) (code string, state string, err error)
|
||||
|
||||
// TokenSource returns an oauth2.TokenSource that fetches access tokens
|
||||
// using 3-legged-OAuth flow.
|
||||
//
|
||||
// The provided context.Context is used for oauth2 Exchange operation.
|
||||
//
|
||||
// The provided oauth2.Config should be a full configuration containing AuthURL,
|
||||
// TokenURL, and Scope.
|
||||
//
|
||||
// An environment-specific AuthorizationHandler is used to obtain user consent.
|
||||
//
|
||||
// Per the OAuth protocol, a unique "state" string should be specified here.
|
||||
// This token source will verify that the "state" is identical in the request
|
||||
// and response before exchanging the auth code for OAuth token to prevent CSRF
|
||||
// attacks.
|
||||
func TokenSource(ctx context.Context, config *oauth2.Config, state string, authHandler AuthorizationHandler) oauth2.TokenSource {
|
||||
return oauth2.ReuseTokenSource(nil, authHandlerSource{config: config, ctx: ctx, authHandler: authHandler, state: state})
|
||||
}
|
||||
|
||||
type authHandlerSource struct {
|
||||
ctx context.Context
|
||||
config *oauth2.Config
|
||||
authHandler AuthorizationHandler
|
||||
state string
|
||||
}
|
||||
|
||||
func (source authHandlerSource) Token() (*oauth2.Token, error) {
|
||||
url := source.config.AuthCodeURL(source.state)
|
||||
code, state, err := source.authHandler(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if state != source.state {
|
||||
return nil, errors.New("state mismatch in 3-legged-OAuth flow")
|
||||
}
|
||||
return source.config.Exchange(source.ctx, code)
|
||||
}
|
25
vendor/golang.org/x/oauth2/client_appengine.go
generated
vendored
25
vendor/golang.org/x/oauth2/client_appengine.go
generated
vendored
|
@ -1,25 +0,0 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
// App Engine hooks.
|
||||
|
||||
package oauth2
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2/internal"
|
||||
"google.golang.org/appengine/urlfetch"
|
||||
)
|
||||
|
||||
func init() {
|
||||
internal.RegisterContextClientFunc(contextClientAppEngine)
|
||||
}
|
||||
|
||||
func contextClientAppEngine(ctx context.Context) (*http.Client, error) {
|
||||
return urlfetch.Client(ctx), nil
|
||||
}
|
9
vendor/golang.org/x/oauth2/go.mod
generated
vendored
Normal file
9
vendor/golang.org/x/oauth2/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
module golang.org/x/oauth2
|
||||
|
||||
go 1.11
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.65.0
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202
|
||||
google.golang.org/appengine v1.6.6
|
||||
)
|
90
vendor/golang.org/x/oauth2/google/appengine.go
generated
vendored
90
vendor/golang.org/x/oauth2/google/appengine.go
generated
vendored
|
@ -5,82 +5,34 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// Set at init time by appenginevm_hook.go. If true, we are on App Engine Managed VMs.
|
||||
var appengineVM bool
|
||||
|
||||
// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
|
||||
// Set at init time by appengine_gen1.go. If nil, we're not on App Engine standard first generation (<= Go 1.9) or App Engine flexible.
|
||||
var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
|
||||
|
||||
// AppEngineTokenSource returns a token source that fetches tokens
|
||||
// issued to the current App Engine application's service account.
|
||||
// If you are implementing a 3-legged OAuth 2.0 flow on App Engine
|
||||
// that involves user accounts, see oauth2.Config instead.
|
||||
// Set at init time by appengine_gen1.go. If nil, we're not on App Engine standard first generation (<= Go 1.9) or App Engine flexible.
|
||||
var appengineAppIDFunc func(c context.Context) string
|
||||
|
||||
// AppEngineTokenSource returns a token source that fetches tokens from either
|
||||
// the current application's service account or from the metadata server,
|
||||
// depending on the App Engine environment. See below for environment-specific
|
||||
// details. If you are implementing a 3-legged OAuth 2.0 flow on App Engine that
|
||||
// involves user accounts, see oauth2.Config instead.
|
||||
//
|
||||
// The provided context must have come from appengine.NewContext.
|
||||
// First generation App Engine runtimes (<= Go 1.9):
|
||||
// AppEngineTokenSource returns a token source that fetches tokens issued to the
|
||||
// current App Engine application's service account. The provided context must have
|
||||
// come from appengine.NewContext.
|
||||
//
|
||||
// Second generation App Engine runtimes (>= Go 1.11) and App Engine flexible:
|
||||
// AppEngineTokenSource is DEPRECATED on second generation runtimes and on the
|
||||
// flexible environment. It delegates to ComputeTokenSource, and the provided
|
||||
// context and scopes are not used. Please use DefaultTokenSource (or ComputeTokenSource,
|
||||
// which DefaultTokenSource will use in this case) instead.
|
||||
func AppEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
|
||||
if appengineTokenFunc == nil {
|
||||
panic("google: AppEngineTokenSource can only be used on App Engine.")
|
||||
}
|
||||
scopes := append([]string{}, scope...)
|
||||
sort.Strings(scopes)
|
||||
return &appEngineTokenSource{
|
||||
ctx: ctx,
|
||||
scopes: scopes,
|
||||
key: strings.Join(scopes, " "),
|
||||
}
|
||||
}
|
||||
|
||||
// aeTokens helps the fetched tokens to be reused until their expiration.
|
||||
var (
|
||||
aeTokensMu sync.Mutex
|
||||
aeTokens = make(map[string]*tokenLock) // key is space-separated scopes
|
||||
)
|
||||
|
||||
type tokenLock struct {
|
||||
mu sync.Mutex // guards t; held while fetching or updating t
|
||||
t *oauth2.Token
|
||||
}
|
||||
|
||||
type appEngineTokenSource struct {
|
||||
ctx context.Context
|
||||
scopes []string
|
||||
key string // to aeTokens map; space-separated scopes
|
||||
}
|
||||
|
||||
func (ts *appEngineTokenSource) Token() (*oauth2.Token, error) {
|
||||
if appengineTokenFunc == nil {
|
||||
panic("google: AppEngineTokenSource can only be used on App Engine.")
|
||||
}
|
||||
|
||||
aeTokensMu.Lock()
|
||||
tok, ok := aeTokens[ts.key]
|
||||
if !ok {
|
||||
tok = &tokenLock{}
|
||||
aeTokens[ts.key] = tok
|
||||
}
|
||||
aeTokensMu.Unlock()
|
||||
|
||||
tok.mu.Lock()
|
||||
defer tok.mu.Unlock()
|
||||
if tok.t.Valid() {
|
||||
return tok.t, nil
|
||||
}
|
||||
access, exp, err := appengineTokenFunc(ts.ctx, ts.scopes...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tok.t = &oauth2.Token{
|
||||
AccessToken: access,
|
||||
Expiry: exp,
|
||||
}
|
||||
return tok.t, nil
|
||||
return appEngineTokenSource(ctx, scope...)
|
||||
}
|
||||
|
|
78
vendor/golang.org/x/oauth2/google/appengine_gen1.go
generated
vendored
Normal file
78
vendor/golang.org/x/oauth2/google/appengine_gen1.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build appengine
|
||||
// +build appengine
|
||||
|
||||
// This file applies to App Engine first generation runtimes (<= Go 1.9).
|
||||
|
||||
package google
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
"google.golang.org/appengine"
|
||||
)
|
||||
|
||||
func init() {
|
||||
appengineTokenFunc = appengine.AccessToken
|
||||
appengineAppIDFunc = appengine.AppID
|
||||
}
|
||||
|
||||
// See comment on AppEngineTokenSource in appengine.go.
|
||||
func appEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
|
||||
scopes := append([]string{}, scope...)
|
||||
sort.Strings(scopes)
|
||||
return &gaeTokenSource{
|
||||
ctx: ctx,
|
||||
scopes: scopes,
|
||||
key: strings.Join(scopes, " "),
|
||||
}
|
||||
}
|
||||
|
||||
// aeTokens helps the fetched tokens to be reused until their expiration.
|
||||
var (
|
||||
aeTokensMu sync.Mutex
|
||||
aeTokens = make(map[string]*tokenLock) // key is space-separated scopes
|
||||
)
|
||||
|
||||
type tokenLock struct {
|
||||
mu sync.Mutex // guards t; held while fetching or updating t
|
||||
t *oauth2.Token
|
||||
}
|
||||
|
||||
type gaeTokenSource struct {
|
||||
ctx context.Context
|
||||
scopes []string
|
||||
key string // to aeTokens map; space-separated scopes
|
||||
}
|
||||
|
||||
func (ts *gaeTokenSource) Token() (*oauth2.Token, error) {
|
||||
aeTokensMu.Lock()
|
||||
tok, ok := aeTokens[ts.key]
|
||||
if !ok {
|
||||
tok = &tokenLock{}
|
||||
aeTokens[ts.key] = tok
|
||||
}
|
||||
aeTokensMu.Unlock()
|
||||
|
||||
tok.mu.Lock()
|
||||
defer tok.mu.Unlock()
|
||||
if tok.t.Valid() {
|
||||
return tok.t, nil
|
||||
}
|
||||
access, exp, err := appengineTokenFunc(ts.ctx, ts.scopes...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tok.t = &oauth2.Token{
|
||||
AccessToken: access,
|
||||
Expiry: exp,
|
||||
}
|
||||
return tok.t, nil
|
||||
}
|
28
vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go
generated
vendored
Normal file
28
vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !appengine
|
||||
// +build !appengine
|
||||
|
||||
// This file applies to App Engine second generation runtimes (>= Go 1.11) and App Engine flexible.
|
||||
|
||||
package google
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
var logOnce sync.Once // only spam about deprecation once
|
||||
|
||||
// See comment on AppEngineTokenSource in appengine.go.
|
||||
func appEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
|
||||
logOnce.Do(func() {
|
||||
log.Print("google: AppEngineTokenSource is deprecated on App Engine standard second generation runtimes (>= Go 1.11) and App Engine flexible. Please use DefaultTokenSource or ComputeTokenSource.")
|
||||
})
|
||||
return ComputeTokenSource("")
|
||||
}
|
13
vendor/golang.org/x/oauth2/google/appengine_hook.go
generated
vendored
13
vendor/golang.org/x/oauth2/google/appengine_hook.go
generated
vendored
|
@ -1,13 +0,0 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
package google
|
||||
|
||||
import "google.golang.org/appengine"
|
||||
|
||||
func init() {
|
||||
appengineTokenFunc = appengine.AccessToken
|
||||
}
|
14
vendor/golang.org/x/oauth2/google/appenginevm_hook.go
generated
vendored
14
vendor/golang.org/x/oauth2/google/appenginevm_hook.go
generated
vendored
|
@ -1,14 +0,0 @@
|
|||
// Copyright 2015 The oauth2 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appenginevm
|
||||
|
||||
package google
|
||||
|
||||
import "google.golang.org/appengine"
|
||||
|
||||
func init() {
|
||||
appengineVM = true
|
||||
appengineTokenFunc = appengine.AccessToken
|
||||
}
|
226
vendor/golang.org/x/oauth2/google/default.go
generated
vendored
226
vendor/golang.org/x/oauth2/google/default.go
generated
vendored
|
@ -5,8 +5,8 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
@ -14,22 +14,62 @@ import (
|
|||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/jwt"
|
||||
"google.golang.org/cloud/compute/metadata"
|
||||
"golang.org/x/oauth2/authhandler"
|
||||
)
|
||||
|
||||
// Credentials holds Google credentials, including "Application Default Credentials".
|
||||
// For more details, see:
|
||||
// https://developers.google.com/accounts/docs/application-default-credentials
|
||||
// Credentials from external accounts (workload identity federation) are used to
|
||||
// identify a particular application from an on-prem or non-Google Cloud platform
|
||||
// including Amazon Web Services (AWS), Microsoft Azure or any identity provider
|
||||
// that supports OpenID Connect (OIDC).
|
||||
type Credentials struct {
|
||||
ProjectID string // may be empty
|
||||
TokenSource oauth2.TokenSource
|
||||
|
||||
// JSON contains the raw bytes from a JSON credentials file.
|
||||
// This field may be nil if authentication is provided by the
|
||||
// environment and not with a credentials file, e.g. when code is
|
||||
// running on Google Cloud Platform.
|
||||
JSON []byte
|
||||
}
|
||||
|
||||
// DefaultCredentials is the old name of Credentials.
|
||||
//
|
||||
// Deprecated: use Credentials instead.
|
||||
type DefaultCredentials = Credentials
|
||||
|
||||
// CredentialsParams holds user supplied parameters that are used together
|
||||
// with a credentials file for building a Credentials object.
|
||||
type CredentialsParams struct {
|
||||
// Scopes is the list OAuth scopes. Required.
|
||||
// Example: https://www.googleapis.com/auth/cloud-platform
|
||||
Scopes []string
|
||||
|
||||
// Subject is the user email used for domain wide delegation (see
|
||||
// https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority).
|
||||
// Optional.
|
||||
Subject string
|
||||
|
||||
// AuthHandler is the AuthorizationHandler used for 3-legged OAuth flow. Optional.
|
||||
AuthHandler authhandler.AuthorizationHandler
|
||||
|
||||
// State is a unique string used with AuthHandler. Optional.
|
||||
State string
|
||||
}
|
||||
|
||||
func (params CredentialsParams) deepCopy() CredentialsParams {
|
||||
paramsCopy := params
|
||||
paramsCopy.Scopes = make([]string, len(params.Scopes))
|
||||
copy(paramsCopy.Scopes, params.Scopes)
|
||||
return paramsCopy
|
||||
}
|
||||
|
||||
// DefaultClient returns an HTTP Client that uses the
|
||||
// DefaultTokenSource to obtain authentication credentials.
|
||||
//
|
||||
// This client should be used when developing services
|
||||
// that run on Google App Engine or Google Compute Engine
|
||||
// and use "Application Default Credentials."
|
||||
//
|
||||
// For more details, see:
|
||||
// https://developers.google.com/accounts/docs/application-default-credentials
|
||||
//
|
||||
func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
|
||||
ts, err := DefaultTokenSource(ctx, scope...)
|
||||
if err != nil {
|
||||
|
@ -38,60 +78,76 @@ func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
|
|||
return oauth2.NewClient(ctx, ts), nil
|
||||
}
|
||||
|
||||
// DefaultTokenSource is a token source that uses
|
||||
// DefaultTokenSource returns the token source for
|
||||
// "Application Default Credentials".
|
||||
// It is a shortcut for FindDefaultCredentials(ctx, scope).TokenSource.
|
||||
func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) {
|
||||
creds, err := FindDefaultCredentials(ctx, scope...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return creds.TokenSource, nil
|
||||
}
|
||||
|
||||
// FindDefaultCredentialsWithParams searches for "Application Default Credentials".
|
||||
//
|
||||
// It looks for credentials in the following places,
|
||||
// preferring the first location found:
|
||||
//
|
||||
// 1. A JSON file whose path is specified by the
|
||||
// GOOGLE_APPLICATION_CREDENTIALS environment variable.
|
||||
// For workload identity federation, refer to
|
||||
// https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation on
|
||||
// how to generate the JSON configuration file for on-prem/non-Google cloud
|
||||
// platforms.
|
||||
// 2. A JSON file in a location known to the gcloud command-line tool.
|
||||
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
|
||||
// On other systems, $HOME/.config/gcloud/application_default_credentials.json.
|
||||
// 3. On Google App Engine it uses the appengine.AccessToken function.
|
||||
// 4. On Google Compute Engine and Google App Engine Managed VMs, it fetches
|
||||
// 3. On Google App Engine standard first generation runtimes (<= Go 1.9) it uses
|
||||
// the appengine.AccessToken function.
|
||||
// 4. On Google Compute Engine, Google App Engine standard second generation runtimes
|
||||
// (>= Go 1.11), and Google App Engine flexible environment, it fetches
|
||||
// credentials from the metadata server.
|
||||
// (In this final case any provided scopes are ignored.)
|
||||
//
|
||||
// For more details, see:
|
||||
// https://developers.google.com/accounts/docs/application-default-credentials
|
||||
//
|
||||
func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) {
|
||||
func FindDefaultCredentialsWithParams(ctx context.Context, params CredentialsParams) (*Credentials, error) {
|
||||
// Make defensive copy of the slices in params.
|
||||
params = params.deepCopy()
|
||||
|
||||
// First, try the environment variable.
|
||||
const envVar = "GOOGLE_APPLICATION_CREDENTIALS"
|
||||
if filename := os.Getenv(envVar); filename != "" {
|
||||
ts, err := tokenSourceFromFile(ctx, filename, scope)
|
||||
creds, err := readCredentialsFile(ctx, filename, params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err)
|
||||
}
|
||||
return ts, nil
|
||||
return creds, nil
|
||||
}
|
||||
|
||||
// Second, try a well-known file.
|
||||
filename := wellKnownFile()
|
||||
_, err := os.Stat(filename)
|
||||
if err == nil {
|
||||
ts, err2 := tokenSourceFromFile(ctx, filename, scope)
|
||||
if err2 == nil {
|
||||
return ts, nil
|
||||
}
|
||||
err = err2
|
||||
} else if os.IsNotExist(err) {
|
||||
err = nil // ignore this error
|
||||
}
|
||||
if err != nil {
|
||||
if creds, err := readCredentialsFile(ctx, filename, params); err == nil {
|
||||
return creds, nil
|
||||
} else if !os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err)
|
||||
}
|
||||
|
||||
// Third, if we're on Google App Engine use those credentials.
|
||||
if appengineTokenFunc != nil && !appengineVM {
|
||||
return AppEngineTokenSource(ctx, scope...), nil
|
||||
// Third, if we're on a Google App Engine standard first generation runtime (<= Go 1.9)
|
||||
// use those credentials. App Engine standard second generation runtimes (>= Go 1.11)
|
||||
// and App Engine flexible use ComputeTokenSource and the metadata server.
|
||||
if appengineTokenFunc != nil {
|
||||
return &DefaultCredentials{
|
||||
ProjectID: appengineAppIDFunc(ctx),
|
||||
TokenSource: AppEngineTokenSource(ctx, params.Scopes...),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Fourth, if we're on Google Compute Engine use the metadata server.
|
||||
// Fourth, if we're on Google Compute Engine, an App Engine standard second generation runtime,
|
||||
// or App Engine flexible, use the metadata server.
|
||||
if metadata.OnGCE() {
|
||||
return ComputeTokenSource(""), nil
|
||||
id, _ := metadata.ProjectID()
|
||||
return &DefaultCredentials{
|
||||
ProjectID: id,
|
||||
TokenSource: ComputeTokenSource("", params.Scopes...),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// None are found; return helpful error.
|
||||
|
@ -99,6 +155,55 @@ func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSourc
|
|||
return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url)
|
||||
}
|
||||
|
||||
// FindDefaultCredentials invokes FindDefaultCredentialsWithParams with the specified scopes.
|
||||
func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials, error) {
|
||||
var params CredentialsParams
|
||||
params.Scopes = scopes
|
||||
return FindDefaultCredentialsWithParams(ctx, params)
|
||||
}
|
||||
|
||||
// CredentialsFromJSONWithParams obtains Google credentials from a JSON value. The JSON can
|
||||
// represent either a Google Developers Console client_credentials.json file (as in ConfigFromJSON),
|
||||
// a Google Developers service account key file, a gcloud user credentials file (a.k.a. refresh
|
||||
// token JSON), or the JSON configuration file for workload identity federation in non-Google cloud
|
||||
// platforms (see https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation).
|
||||
func CredentialsFromJSONWithParams(ctx context.Context, jsonData []byte, params CredentialsParams) (*Credentials, error) {
|
||||
// Make defensive copy of the slices in params.
|
||||
params = params.deepCopy()
|
||||
|
||||
// First, attempt to parse jsonData as a Google Developers Console client_credentials.json.
|
||||
config, _ := ConfigFromJSON(jsonData, params.Scopes...)
|
||||
if config != nil {
|
||||
return &Credentials{
|
||||
ProjectID: "",
|
||||
TokenSource: authhandler.TokenSource(ctx, config, params.State, params.AuthHandler),
|
||||
JSON: jsonData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Otherwise, parse jsonData as one of the other supported credentials files.
|
||||
var f credentialsFile
|
||||
if err := json.Unmarshal(jsonData, &f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts, err := f.tokenSource(ctx, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &DefaultCredentials{
|
||||
ProjectID: f.ProjectID,
|
||||
TokenSource: ts,
|
||||
JSON: jsonData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CredentialsFromJSON invokes CredentialsFromJSONWithParams with the specified scopes.
|
||||
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) {
|
||||
var params CredentialsParams
|
||||
params.Scopes = scopes
|
||||
return CredentialsFromJSONWithParams(ctx, jsonData, params)
|
||||
}
|
||||
|
||||
func wellKnownFile() string {
|
||||
const f = "application_default_credentials.json"
|
||||
if runtime.GOOS == "windows" {
|
||||
|
@ -107,49 +212,10 @@ func wellKnownFile() string {
|
|||
return filepath.Join(guessUnixHomeDir(), ".config", "gcloud", f)
|
||||
}
|
||||
|
||||
func tokenSourceFromFile(ctx context.Context, filename string, scopes []string) (oauth2.TokenSource, error) {
|
||||
func readCredentialsFile(ctx context.Context, filename string, params CredentialsParams) (*DefaultCredentials, error) {
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var d struct {
|
||||
// Common fields
|
||||
Type string
|
||||
ClientID string `json:"client_id"`
|
||||
|
||||
// User Credential fields
|
||||
ClientSecret string `json:"client_secret"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
|
||||
// Service Account fields
|
||||
ClientEmail string `json:"client_email"`
|
||||
PrivateKeyID string `json:"private_key_id"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch d.Type {
|
||||
case "authorized_user":
|
||||
cfg := &oauth2.Config{
|
||||
ClientID: d.ClientID,
|
||||
ClientSecret: d.ClientSecret,
|
||||
Scopes: append([]string{}, scopes...), // copy
|
||||
Endpoint: Endpoint,
|
||||
}
|
||||
tok := &oauth2.Token{RefreshToken: d.RefreshToken}
|
||||
return cfg.TokenSource(ctx, tok), nil
|
||||
case "service_account":
|
||||
cfg := &jwt.Config{
|
||||
Email: d.ClientEmail,
|
||||
PrivateKey: []byte(d.PrivateKey),
|
||||
Scopes: append([]string{}, scopes...), // copy
|
||||
TokenURL: JWTTokenURL,
|
||||
}
|
||||
return cfg.TokenSource(ctx), nil
|
||||
case "":
|
||||
return nil, errors.New("missing 'type' field in credentials")
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown credential type: %q", d.Type)
|
||||
}
|
||||
return CredentialsFromJSONWithParams(ctx, b, params)
|
||||
}
|
||||
|
|
79
vendor/golang.org/x/oauth2/google/doc.go
generated
vendored
Normal file
79
vendor/golang.org/x/oauth2/google/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package google provides support for making OAuth2 authorized and authenticated
|
||||
// HTTP requests to Google APIs. It supports the Web server flow, client-side
|
||||
// credentials, service accounts, Google Compute Engine service accounts,
|
||||
// Google App Engine service accounts and workload identity federation
|
||||
// from non-Google cloud platforms.
|
||||
//
|
||||
// A brief overview of the package follows. For more information, please read
|
||||
// https://developers.google.com/accounts/docs/OAuth2
|
||||
// and
|
||||
// https://developers.google.com/accounts/docs/application-default-credentials.
|
||||
// For more information on using workload identity federation, refer to
|
||||
// https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation.
|
||||
//
|
||||
// OAuth2 Configs
|
||||
//
|
||||
// Two functions in this package return golang.org/x/oauth2.Config values from Google credential
|
||||
// data. Google supports two JSON formats for OAuth2 credentials: one is handled by ConfigFromJSON,
|
||||
// the other by JWTConfigFromJSON. The returned Config can be used to obtain a TokenSource or
|
||||
// create an http.Client.
|
||||
//
|
||||
// Workload Identity Federation
|
||||
//
|
||||
// Using workload identity federation, your application can access Google Cloud
|
||||
// resources from Amazon Web Services (AWS), Microsoft Azure or any identity
|
||||
// provider that supports OpenID Connect (OIDC).
|
||||
// Traditionally, applications running outside Google Cloud have used service
|
||||
// account keys to access Google Cloud resources. Using identity federation,
|
||||
// you can allow your workload to impersonate a service account.
|
||||
// This lets you access Google Cloud resources directly, eliminating the
|
||||
// maintenance and security burden associated with service account keys.
|
||||
//
|
||||
// Follow the detailed instructions on how to configure Workload Identity Federation
|
||||
// in various platforms:
|
||||
//
|
||||
// Amazon Web Services (AWS): https://cloud.google.com/iam/docs/access-resources-aws
|
||||
// Microsoft Azure: https://cloud.google.com/iam/docs/access-resources-azure
|
||||
// OIDC identity provider: https://cloud.google.com/iam/docs/access-resources-oidc
|
||||
//
|
||||
// For OIDC providers, the library can retrieve OIDC tokens either from a
|
||||
// local file location (file-sourced credentials) or from a local server
|
||||
// (URL-sourced credentials).
|
||||
// For file-sourced credentials, a background process needs to be continuously
|
||||
// refreshing the file location with a new OIDC token prior to expiration.
|
||||
// For tokens with one hour lifetimes, the token needs to be updated in the file
|
||||
// every hour. The token can be stored directly as plain text or in JSON format.
|
||||
// For URL-sourced credentials, a local server needs to host a GET endpoint to
|
||||
// return the OIDC token. The response can be in plain text or JSON.
|
||||
// Additional required request headers can also be specified.
|
||||
//
|
||||
//
|
||||
// Credentials
|
||||
//
|
||||
// The Credentials type represents Google credentials, including Application Default
|
||||
// Credentials.
|
||||
//
|
||||
// Use FindDefaultCredentials to obtain Application Default Credentials.
|
||||
// FindDefaultCredentials looks in some well-known places for a credentials file, and
|
||||
// will call AppEngineTokenSource or ComputeTokenSource as needed.
|
||||
//
|
||||
// Application Default Credentials also support workload identity federation to
|
||||
// access Google Cloud resources from non-Google Cloud platforms including Amazon
|
||||
// Web Services (AWS), Microsoft Azure or any identity provider that supports
|
||||
// OpenID Connect (OIDC). Workload identity federation is recommended for
|
||||
// non-Google Cloud environments as it avoids the need to download, manage and
|
||||
// store service account private keys locally.
|
||||
//
|
||||
// DefaultClient and DefaultTokenSource are convenience methods. They first call FindDefaultCredentials,
|
||||
// then use the credentials to construct an http.Client or an oauth2.TokenSource.
|
||||
//
|
||||
// Use CredentialsFromJSON to obtain credentials from either of the two JSON formats
|
||||
// described in OAuth2 Configs, above. The TokenSource in the returned value is the
|
||||
// same as the one obtained from the oauth2.Config returned from ConfigFromJSON or
|
||||
// JWTConfigFromJSON, but the Credentials may contain additional information
|
||||
// that is useful is some circumstances.
|
||||
package google // import "golang.org/x/oauth2/google"
|
173
vendor/golang.org/x/oauth2/google/google.go
generated
vendored
173
vendor/golang.org/x/oauth2/google/google.go
generated
vendored
|
@ -2,44 +2,39 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package google provides support for making OAuth2 authorized and
|
||||
// authenticated HTTP requests to Google APIs.
|
||||
// It supports the Web server flow, client-side credentials, service accounts,
|
||||
// Google Compute Engine service accounts, and Google App Engine service
|
||||
// accounts.
|
||||
//
|
||||
// For more information, please read
|
||||
// https://developers.google.com/accounts/docs/OAuth2
|
||||
// and
|
||||
// https://developers.google.com/accounts/docs/application-default-credentials.
|
||||
package google // import "golang.org/x/oauth2/google"
|
||||
package google
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google/internal/externalaccount"
|
||||
"golang.org/x/oauth2/jwt"
|
||||
"google.golang.org/cloud/compute/metadata"
|
||||
)
|
||||
|
||||
// Endpoint is Google's OAuth 2.0 endpoint.
|
||||
// Endpoint is Google's OAuth 2.0 default endpoint.
|
||||
var Endpoint = oauth2.Endpoint{
|
||||
AuthURL: "https://accounts.google.com/o/oauth2/auth",
|
||||
TokenURL: "https://accounts.google.com/o/oauth2/token",
|
||||
TokenURL: "https://oauth2.googleapis.com/token",
|
||||
AuthStyle: oauth2.AuthStyleInParams,
|
||||
}
|
||||
|
||||
// JWTTokenURL is Google's OAuth 2.0 token URL to use with the JWT flow.
|
||||
const JWTTokenURL = "https://accounts.google.com/o/oauth2/token"
|
||||
const JWTTokenURL = "https://oauth2.googleapis.com/token"
|
||||
|
||||
// ConfigFromJSON uses a Google Developers Console client_credentials.json
|
||||
// file to construct a config.
|
||||
// client_credentials.json can be downloadable from https://console.developers.google.com,
|
||||
// under "APIs & Auth" > "Credentials". Download the Web application credentials in the
|
||||
// JSON format and provide the contents of the file as jsonKey.
|
||||
// client_credentials.json can be downloaded from
|
||||
// https://console.developers.google.com, under "Credentials". Download the Web
|
||||
// application credentials in the JSON format and provide the contents of the
|
||||
// file as jsonKey.
|
||||
func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
|
||||
type cred struct {
|
||||
ClientID string `json:"client_id"`
|
||||
|
@ -81,36 +76,129 @@ func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
|
|||
|
||||
// JWTConfigFromJSON uses a Google Developers service account JSON key file to read
|
||||
// the credentials that authorize and authenticate the requests.
|
||||
// Create a service account on "Credentials" page under "APIs & Auth" for your
|
||||
// project at https://console.developers.google.com to download a JSON key file.
|
||||
// Create a service account on "Credentials" for your project at
|
||||
// https://console.developers.google.com to download a JSON key file.
|
||||
func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) {
|
||||
var key struct {
|
||||
Email string `json:"client_email"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
}
|
||||
if err := json.Unmarshal(jsonKey, &key); err != nil {
|
||||
var f credentialsFile
|
||||
if err := json.Unmarshal(jsonKey, &f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &jwt.Config{
|
||||
Email: key.Email,
|
||||
PrivateKey: []byte(key.PrivateKey),
|
||||
Scopes: scope,
|
||||
TokenURL: JWTTokenURL,
|
||||
}, nil
|
||||
if f.Type != serviceAccountKey {
|
||||
return nil, fmt.Errorf("google: read JWT from JSON credentials: 'type' field is %q (expected %q)", f.Type, serviceAccountKey)
|
||||
}
|
||||
scope = append([]string(nil), scope...) // copy
|
||||
return f.jwtConfig(scope, ""), nil
|
||||
}
|
||||
|
||||
// JSON key file types.
|
||||
const (
|
||||
serviceAccountKey = "service_account"
|
||||
userCredentialsKey = "authorized_user"
|
||||
externalAccountKey = "external_account"
|
||||
)
|
||||
|
||||
// credentialsFile is the unmarshalled representation of a credentials file.
|
||||
type credentialsFile struct {
|
||||
Type string `json:"type"`
|
||||
|
||||
// Service Account fields
|
||||
ClientEmail string `json:"client_email"`
|
||||
PrivateKeyID string `json:"private_key_id"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
AuthURL string `json:"auth_uri"`
|
||||
TokenURL string `json:"token_uri"`
|
||||
ProjectID string `json:"project_id"`
|
||||
|
||||
// User Credential fields
|
||||
// (These typically come from gcloud auth.)
|
||||
ClientSecret string `json:"client_secret"`
|
||||
ClientID string `json:"client_id"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
|
||||
// External Account fields
|
||||
Audience string `json:"audience"`
|
||||
SubjectTokenType string `json:"subject_token_type"`
|
||||
TokenURLExternal string `json:"token_url"`
|
||||
TokenInfoURL string `json:"token_info_url"`
|
||||
ServiceAccountImpersonationURL string `json:"service_account_impersonation_url"`
|
||||
CredentialSource externalaccount.CredentialSource `json:"credential_source"`
|
||||
QuotaProjectID string `json:"quota_project_id"`
|
||||
}
|
||||
|
||||
func (f *credentialsFile) jwtConfig(scopes []string, subject string) *jwt.Config {
|
||||
cfg := &jwt.Config{
|
||||
Email: f.ClientEmail,
|
||||
PrivateKey: []byte(f.PrivateKey),
|
||||
PrivateKeyID: f.PrivateKeyID,
|
||||
Scopes: scopes,
|
||||
TokenURL: f.TokenURL,
|
||||
Subject: subject, // This is the user email to impersonate
|
||||
}
|
||||
if cfg.TokenURL == "" {
|
||||
cfg.TokenURL = JWTTokenURL
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
func (f *credentialsFile) tokenSource(ctx context.Context, params CredentialsParams) (oauth2.TokenSource, error) {
|
||||
switch f.Type {
|
||||
case serviceAccountKey:
|
||||
cfg := f.jwtConfig(params.Scopes, params.Subject)
|
||||
return cfg.TokenSource(ctx), nil
|
||||
case userCredentialsKey:
|
||||
cfg := &oauth2.Config{
|
||||
ClientID: f.ClientID,
|
||||
ClientSecret: f.ClientSecret,
|
||||
Scopes: params.Scopes,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: f.AuthURL,
|
||||
TokenURL: f.TokenURL,
|
||||
AuthStyle: oauth2.AuthStyleInParams,
|
||||
},
|
||||
}
|
||||
if cfg.Endpoint.AuthURL == "" {
|
||||
cfg.Endpoint.AuthURL = Endpoint.AuthURL
|
||||
}
|
||||
if cfg.Endpoint.TokenURL == "" {
|
||||
cfg.Endpoint.TokenURL = Endpoint.TokenURL
|
||||
}
|
||||
tok := &oauth2.Token{RefreshToken: f.RefreshToken}
|
||||
return cfg.TokenSource(ctx, tok), nil
|
||||
case externalAccountKey:
|
||||
cfg := &externalaccount.Config{
|
||||
Audience: f.Audience,
|
||||
SubjectTokenType: f.SubjectTokenType,
|
||||
TokenURL: f.TokenURLExternal,
|
||||
TokenInfoURL: f.TokenInfoURL,
|
||||
ServiceAccountImpersonationURL: f.ServiceAccountImpersonationURL,
|
||||
ClientSecret: f.ClientSecret,
|
||||
ClientID: f.ClientID,
|
||||
CredentialSource: f.CredentialSource,
|
||||
QuotaProjectID: f.QuotaProjectID,
|
||||
Scopes: params.Scopes,
|
||||
}
|
||||
return cfg.TokenSource(ctx), nil
|
||||
case "":
|
||||
return nil, errors.New("missing 'type' field in credentials")
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown credential type: %q", f.Type)
|
||||
}
|
||||
}
|
||||
|
||||
// ComputeTokenSource returns a token source that fetches access tokens
|
||||
// from Google Compute Engine (GCE)'s metadata server. It's only valid to use
|
||||
// this token source if your program is running on a GCE instance.
|
||||
// If no account is specified, "default" is used.
|
||||
// If no scopes are specified, a set of default scopes are automatically granted.
|
||||
// Further information about retrieving access tokens from the GCE metadata
|
||||
// server can be found at https://cloud.google.com/compute/docs/authentication.
|
||||
func ComputeTokenSource(account string) oauth2.TokenSource {
|
||||
return oauth2.ReuseTokenSource(nil, computeSource{account: account})
|
||||
func ComputeTokenSource(account string, scope ...string) oauth2.TokenSource {
|
||||
return oauth2.ReuseTokenSource(nil, computeSource{account: account, scopes: scope})
|
||||
}
|
||||
|
||||
type computeSource struct {
|
||||
account string
|
||||
scopes []string
|
||||
}
|
||||
|
||||
func (cs computeSource) Token() (*oauth2.Token, error) {
|
||||
|
@ -121,7 +209,13 @@ func (cs computeSource) Token() (*oauth2.Token, error) {
|
|||
if acct == "" {
|
||||
acct = "default"
|
||||
}
|
||||
tokenJSON, err := metadata.Get("instance/service-accounts/" + acct + "/token")
|
||||
tokenURI := "instance/service-accounts/" + acct + "/token"
|
||||
if len(cs.scopes) > 0 {
|
||||
v := url.Values{}
|
||||
v.Set("scopes", strings.Join(cs.scopes, ","))
|
||||
tokenURI = tokenURI + "?" + v.Encode()
|
||||
}
|
||||
tokenJSON, err := metadata.Get(tokenURI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -137,9 +231,16 @@ func (cs computeSource) Token() (*oauth2.Token, error) {
|
|||
if res.ExpiresInSec == 0 || res.AccessToken == "" {
|
||||
return nil, fmt.Errorf("oauth2/google: incomplete token received from metadata")
|
||||
}
|
||||
return &oauth2.Token{
|
||||
tok := &oauth2.Token{
|
||||
AccessToken: res.AccessToken,
|
||||
TokenType: res.TokenType,
|
||||
Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second),
|
||||
}, nil
|
||||
}
|
||||
// NOTE(cbro): add hidden metadata about where the token is from.
|
||||
// This is needed for detection by client libraries to know that credentials come from the metadata server.
|
||||
// This may be removed in a future version of this library.
|
||||
return tok.WithExtra(map[string]interface{}{
|
||||
"oauth2.google.tokenSource": "compute-metadata",
|
||||
"oauth2.google.serviceAccount": acct,
|
||||
}), nil
|
||||
}
|
||||
|
|
470
vendor/golang.org/x/oauth2/google/internal/externalaccount/aws.go
generated
vendored
Normal file
470
vendor/golang.org/x/oauth2/google/internal/externalaccount/aws.go
generated
vendored
Normal file
|
@ -0,0 +1,470 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package externalaccount
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type awsSecurityCredentials struct {
|
||||
AccessKeyID string `json:"AccessKeyID"`
|
||||
SecretAccessKey string `json:"SecretAccessKey"`
|
||||
SecurityToken string `json:"Token"`
|
||||
}
|
||||
|
||||
// awsRequestSigner is a utility class to sign http requests using a AWS V4 signature.
|
||||
type awsRequestSigner struct {
|
||||
RegionName string
|
||||
AwsSecurityCredentials awsSecurityCredentials
|
||||
}
|
||||
|
||||
// getenv aliases os.Getenv for testing
|
||||
var getenv = os.Getenv
|
||||
|
||||
const (
|
||||
// AWS Signature Version 4 signing algorithm identifier.
|
||||
awsAlgorithm = "AWS4-HMAC-SHA256"
|
||||
|
||||
// The termination string for the AWS credential scope value as defined in
|
||||
// https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
|
||||
awsRequestType = "aws4_request"
|
||||
|
||||
// The AWS authorization header name for the security session token if available.
|
||||
awsSecurityTokenHeader = "x-amz-security-token"
|
||||
|
||||
// The AWS authorization header name for the auto-generated date.
|
||||
awsDateHeader = "x-amz-date"
|
||||
|
||||
awsTimeFormatLong = "20060102T150405Z"
|
||||
awsTimeFormatShort = "20060102"
|
||||
)
|
||||
|
||||
func getSha256(input []byte) (string, error) {
|
||||
hash := sha256.New()
|
||||
if _, err := hash.Write(input); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(hash.Sum(nil)), nil
|
||||
}
|
||||
|
||||
func getHmacSha256(key, input []byte) ([]byte, error) {
|
||||
hash := hmac.New(sha256.New, key)
|
||||
if _, err := hash.Write(input); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return hash.Sum(nil), nil
|
||||
}
|
||||
|
||||
func cloneRequest(r *http.Request) *http.Request {
|
||||
r2 := new(http.Request)
|
||||
*r2 = *r
|
||||
if r.Header != nil {
|
||||
r2.Header = make(http.Header, len(r.Header))
|
||||
|
||||
// Find total number of values.
|
||||
headerCount := 0
|
||||
for _, headerValues := range r.Header {
|
||||
headerCount += len(headerValues)
|
||||
}
|
||||
copiedHeaders := make([]string, headerCount) // shared backing array for headers' values
|
||||
|
||||
for headerKey, headerValues := range r.Header {
|
||||
headerCount = copy(copiedHeaders, headerValues)
|
||||
r2.Header[headerKey] = copiedHeaders[:headerCount:headerCount]
|
||||
copiedHeaders = copiedHeaders[headerCount:]
|
||||
}
|
||||
}
|
||||
return r2
|
||||
}
|
||||
|
||||
func canonicalPath(req *http.Request) string {
|
||||
result := req.URL.EscapedPath()
|
||||
if result == "" {
|
||||
return "/"
|
||||
}
|
||||
return path.Clean(result)
|
||||
}
|
||||
|
||||
func canonicalQuery(req *http.Request) string {
|
||||
queryValues := req.URL.Query()
|
||||
for queryKey := range queryValues {
|
||||
sort.Strings(queryValues[queryKey])
|
||||
}
|
||||
return queryValues.Encode()
|
||||
}
|
||||
|
||||
func canonicalHeaders(req *http.Request) (string, string) {
|
||||
// Header keys need to be sorted alphabetically.
|
||||
var headers []string
|
||||
lowerCaseHeaders := make(http.Header)
|
||||
for k, v := range req.Header {
|
||||
k := strings.ToLower(k)
|
||||
if _, ok := lowerCaseHeaders[k]; ok {
|
||||
// include additional values
|
||||
lowerCaseHeaders[k] = append(lowerCaseHeaders[k], v...)
|
||||
} else {
|
||||
headers = append(headers, k)
|
||||
lowerCaseHeaders[k] = v
|
||||
}
|
||||
}
|
||||
sort.Strings(headers)
|
||||
|
||||
var fullHeaders bytes.Buffer
|
||||
for _, header := range headers {
|
||||
headerValue := strings.Join(lowerCaseHeaders[header], ",")
|
||||
fullHeaders.WriteString(header)
|
||||
fullHeaders.WriteRune(':')
|
||||
fullHeaders.WriteString(headerValue)
|
||||
fullHeaders.WriteRune('\n')
|
||||
}
|
||||
|
||||
return strings.Join(headers, ";"), fullHeaders.String()
|
||||
}
|
||||
|
||||
func requestDataHash(req *http.Request) (string, error) {
|
||||
var requestData []byte
|
||||
if req.Body != nil {
|
||||
requestBody, err := req.GetBody()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer requestBody.Close()
|
||||
|
||||
requestData, err = ioutil.ReadAll(io.LimitReader(requestBody, 1<<20))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return getSha256(requestData)
|
||||
}
|
||||
|
||||
func requestHost(req *http.Request) string {
|
||||
if req.Host != "" {
|
||||
return req.Host
|
||||
}
|
||||
return req.URL.Host
|
||||
}
|
||||
|
||||
func canonicalRequest(req *http.Request, canonicalHeaderColumns, canonicalHeaderData string) (string, error) {
|
||||
dataHash, err := requestDataHash(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", req.Method, canonicalPath(req), canonicalQuery(req), canonicalHeaderData, canonicalHeaderColumns, dataHash), nil
|
||||
}
|
||||
|
||||
// SignRequest adds the appropriate headers to an http.Request
|
||||
// or returns an error if something prevented this.
|
||||
func (rs *awsRequestSigner) SignRequest(req *http.Request) error {
|
||||
signedRequest := cloneRequest(req)
|
||||
timestamp := now()
|
||||
|
||||
signedRequest.Header.Add("host", requestHost(req))
|
||||
|
||||
if rs.AwsSecurityCredentials.SecurityToken != "" {
|
||||
signedRequest.Header.Add(awsSecurityTokenHeader, rs.AwsSecurityCredentials.SecurityToken)
|
||||
}
|
||||
|
||||
if signedRequest.Header.Get("date") == "" {
|
||||
signedRequest.Header.Add(awsDateHeader, timestamp.Format(awsTimeFormatLong))
|
||||
}
|
||||
|
||||
authorizationCode, err := rs.generateAuthentication(signedRequest, timestamp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signedRequest.Header.Set("Authorization", authorizationCode)
|
||||
|
||||
req.Header = signedRequest.Header
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rs *awsRequestSigner) generateAuthentication(req *http.Request, timestamp time.Time) (string, error) {
|
||||
canonicalHeaderColumns, canonicalHeaderData := canonicalHeaders(req)
|
||||
|
||||
dateStamp := timestamp.Format(awsTimeFormatShort)
|
||||
serviceName := ""
|
||||
if splitHost := strings.Split(requestHost(req), "."); len(splitHost) > 0 {
|
||||
serviceName = splitHost[0]
|
||||
}
|
||||
|
||||
credentialScope := fmt.Sprintf("%s/%s/%s/%s", dateStamp, rs.RegionName, serviceName, awsRequestType)
|
||||
|
||||
requestString, err := canonicalRequest(req, canonicalHeaderColumns, canonicalHeaderData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
requestHash, err := getSha256([]byte(requestString))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
stringToSign := fmt.Sprintf("%s\n%s\n%s\n%s", awsAlgorithm, timestamp.Format(awsTimeFormatLong), credentialScope, requestHash)
|
||||
|
||||
signingKey := []byte("AWS4" + rs.AwsSecurityCredentials.SecretAccessKey)
|
||||
for _, signingInput := range []string{
|
||||
dateStamp, rs.RegionName, serviceName, awsRequestType, stringToSign,
|
||||
} {
|
||||
signingKey, err = getHmacSha256(signingKey, []byte(signingInput))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s", awsAlgorithm, rs.AwsSecurityCredentials.AccessKeyID, credentialScope, canonicalHeaderColumns, hex.EncodeToString(signingKey)), nil
|
||||
}
|
||||
|
||||
type awsCredentialSource struct {
|
||||
EnvironmentID string
|
||||
RegionURL string
|
||||
RegionalCredVerificationURL string
|
||||
CredVerificationURL string
|
||||
TargetResource string
|
||||
requestSigner *awsRequestSigner
|
||||
region string
|
||||
ctx context.Context
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
type awsRequestHeader struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type awsRequest struct {
|
||||
URL string `json:"url"`
|
||||
Method string `json:"method"`
|
||||
Headers []awsRequestHeader `json:"headers"`
|
||||
}
|
||||
|
||||
func (cs awsCredentialSource) doRequest(req *http.Request) (*http.Response, error) {
|
||||
if cs.client == nil {
|
||||
cs.client = oauth2.NewClient(cs.ctx, nil)
|
||||
}
|
||||
return cs.client.Do(req.WithContext(cs.ctx))
|
||||
}
|
||||
|
||||
func (cs awsCredentialSource) subjectToken() (string, error) {
|
||||
if cs.requestSigner == nil {
|
||||
awsSecurityCredentials, err := cs.getSecurityCredentials()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if cs.region, err = cs.getRegion(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cs.requestSigner = &awsRequestSigner{
|
||||
RegionName: cs.region,
|
||||
AwsSecurityCredentials: awsSecurityCredentials,
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the signed request to AWS STS GetCallerIdentity API.
|
||||
// Use the required regional endpoint. Otherwise, the request will fail.
|
||||
req, err := http.NewRequest("POST", strings.Replace(cs.RegionalCredVerificationURL, "{region}", cs.region, 1), nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// The full, canonical resource name of the workload identity pool
|
||||
// provider, with or without the HTTPS prefix.
|
||||
// Including this header as part of the signature is recommended to
|
||||
// ensure data integrity.
|
||||
if cs.TargetResource != "" {
|
||||
req.Header.Add("x-goog-cloud-target-resource", cs.TargetResource)
|
||||
}
|
||||
cs.requestSigner.SignRequest(req)
|
||||
|
||||
/*
|
||||
The GCP STS endpoint expects the headers to be formatted as:
|
||||
# [
|
||||
# {key: 'x-amz-date', value: '...'},
|
||||
# {key: 'Authorization', value: '...'},
|
||||
# ...
|
||||
# ]
|
||||
# And then serialized as:
|
||||
# quote(json.dumps({
|
||||
# url: '...',
|
||||
# method: 'POST',
|
||||
# headers: [{key: 'x-amz-date', value: '...'}, ...]
|
||||
# }))
|
||||
*/
|
||||
|
||||
awsSignedReq := awsRequest{
|
||||
URL: req.URL.String(),
|
||||
Method: "POST",
|
||||
}
|
||||
for headerKey, headerList := range req.Header {
|
||||
for _, headerValue := range headerList {
|
||||
awsSignedReq.Headers = append(awsSignedReq.Headers, awsRequestHeader{
|
||||
Key: headerKey,
|
||||
Value: headerValue,
|
||||
})
|
||||
}
|
||||
}
|
||||
sort.Slice(awsSignedReq.Headers, func(i, j int) bool {
|
||||
headerCompare := strings.Compare(awsSignedReq.Headers[i].Key, awsSignedReq.Headers[j].Key)
|
||||
if headerCompare == 0 {
|
||||
return strings.Compare(awsSignedReq.Headers[i].Value, awsSignedReq.Headers[j].Value) < 0
|
||||
}
|
||||
return headerCompare < 0
|
||||
})
|
||||
|
||||
result, err := json.Marshal(awsSignedReq)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return url.QueryEscape(string(result)), nil
|
||||
}
|
||||
|
||||
func (cs *awsCredentialSource) getRegion() (string, error) {
|
||||
if envAwsRegion := getenv("AWS_REGION"); envAwsRegion != "" {
|
||||
return envAwsRegion, nil
|
||||
}
|
||||
if envAwsRegion := getenv("AWS_DEFAULT_REGION"); envAwsRegion != "" {
|
||||
return envAwsRegion, nil
|
||||
}
|
||||
|
||||
if cs.RegionURL == "" {
|
||||
return "", errors.New("oauth2/google: unable to determine AWS region")
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", cs.RegionURL, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp, err := cs.doRequest(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return "", fmt.Errorf("oauth2/google: unable to retrieve AWS region - %s", string(respBody))
|
||||
}
|
||||
|
||||
// This endpoint will return the region in format: us-east-2b.
|
||||
// Only the us-east-2 part should be used.
|
||||
respBodyEnd := 0
|
||||
if len(respBody) > 1 {
|
||||
respBodyEnd = len(respBody) - 1
|
||||
}
|
||||
return string(respBody[:respBodyEnd]), nil
|
||||
}
|
||||
|
||||
func (cs *awsCredentialSource) getSecurityCredentials() (result awsSecurityCredentials, err error) {
|
||||
if accessKeyID := getenv("AWS_ACCESS_KEY_ID"); accessKeyID != "" {
|
||||
if secretAccessKey := getenv("AWS_SECRET_ACCESS_KEY"); secretAccessKey != "" {
|
||||
return awsSecurityCredentials{
|
||||
AccessKeyID: accessKeyID,
|
||||
SecretAccessKey: secretAccessKey,
|
||||
SecurityToken: getenv("AWS_SESSION_TOKEN"),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
roleName, err := cs.getMetadataRoleName()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
credentials, err := cs.getMetadataSecurityCredentials(roleName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if credentials.AccessKeyID == "" {
|
||||
return result, errors.New("oauth2/google: missing AccessKeyId credential")
|
||||
}
|
||||
|
||||
if credentials.SecretAccessKey == "" {
|
||||
return result, errors.New("oauth2/google: missing SecretAccessKey credential")
|
||||
}
|
||||
|
||||
return credentials, nil
|
||||
}
|
||||
|
||||
func (cs *awsCredentialSource) getMetadataSecurityCredentials(roleName string) (awsSecurityCredentials, error) {
|
||||
var result awsSecurityCredentials
|
||||
|
||||
req, err := http.NewRequest("GET", fmt.Sprintf("%s/%s", cs.CredVerificationURL, roleName), nil)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp, err := cs.doRequest(req)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return result, fmt.Errorf("oauth2/google: unable to retrieve AWS security credentials - %s", string(respBody))
|
||||
}
|
||||
|
||||
err = json.Unmarshal(respBody, &result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (cs *awsCredentialSource) getMetadataRoleName() (string, error) {
|
||||
if cs.CredVerificationURL == "" {
|
||||
return "", errors.New("oauth2/google: unable to determine the AWS metadata server security credentials endpoint")
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", cs.CredVerificationURL, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp, err := cs.doRequest(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return "", fmt.Errorf("oauth2/google: unable to retrieve AWS role name - %s", string(respBody))
|
||||
}
|
||||
|
||||
return string(respBody), nil
|
||||
}
|
184
vendor/golang.org/x/oauth2/google/internal/externalaccount/basecredentials.go
generated
vendored
Normal file
184
vendor/golang.org/x/oauth2/google/internal/externalaccount/basecredentials.go
generated
vendored
Normal file
|
@ -0,0 +1,184 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package externalaccount
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"golang.org/x/oauth2"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// now aliases time.Now for testing
|
||||
var now = func() time.Time {
|
||||
return time.Now().UTC()
|
||||
}
|
||||
|
||||
// Config stores the configuration for fetching tokens with external credentials.
|
||||
type Config struct {
|
||||
// Audience is the Secure Token Service (STS) audience which contains the resource name for the workload
|
||||
// identity pool or the workforce pool and the provider identifier in that pool.
|
||||
Audience string
|
||||
// SubjectTokenType is the STS token type based on the Oauth2.0 token exchange spec
|
||||
// e.g. `urn:ietf:params:oauth:token-type:jwt`.
|
||||
SubjectTokenType string
|
||||
// TokenURL is the STS token exchange endpoint.
|
||||
TokenURL string
|
||||
// TokenInfoURL is the token_info endpoint used to retrieve the account related information (
|
||||
// user attributes like account identifier, eg. email, username, uid, etc). This is
|
||||
// needed for gCloud session account identification.
|
||||
TokenInfoURL string
|
||||
// ServiceAccountImpersonationURL is the URL for the service account impersonation request. This is only
|
||||
// required for workload identity pools when APIs to be accessed have not integrated with UberMint.
|
||||
ServiceAccountImpersonationURL string
|
||||
// ClientSecret is currently only required if token_info endpoint also
|
||||
// needs to be called with the generated GCP access token. When provided, STS will be
|
||||
// called with additional basic authentication using client_id as username and client_secret as password.
|
||||
ClientSecret string
|
||||
// ClientID is only required in conjunction with ClientSecret, as described above.
|
||||
ClientID string
|
||||
// CredentialSource contains the necessary information to retrieve the token itself, as well
|
||||
// as some environmental information.
|
||||
CredentialSource CredentialSource
|
||||
// QuotaProjectID is injected by gCloud. If the value is non-empty, the Auth libraries
|
||||
// will set the x-goog-user-project which overrides the project associated with the credentials.
|
||||
QuotaProjectID string
|
||||
// Scopes contains the desired scopes for the returned access token.
|
||||
Scopes []string
|
||||
}
|
||||
|
||||
// TokenSource Returns an external account TokenSource struct. This is to be called by package google to construct a google.Credentials.
|
||||
func (c *Config) TokenSource(ctx context.Context) oauth2.TokenSource {
|
||||
ts := tokenSource{
|
||||
ctx: ctx,
|
||||
conf: c,
|
||||
}
|
||||
if c.ServiceAccountImpersonationURL == "" {
|
||||
return oauth2.ReuseTokenSource(nil, ts)
|
||||
}
|
||||
scopes := c.Scopes
|
||||
ts.conf.Scopes = []string{"https://www.googleapis.com/auth/cloud-platform"}
|
||||
imp := impersonateTokenSource{
|
||||
ctx: ctx,
|
||||
url: c.ServiceAccountImpersonationURL,
|
||||
scopes: scopes,
|
||||
ts: oauth2.ReuseTokenSource(nil, ts),
|
||||
}
|
||||
return oauth2.ReuseTokenSource(nil, imp)
|
||||
}
|
||||
|
||||
// Subject token file types.
|
||||
const (
|
||||
fileTypeText = "text"
|
||||
fileTypeJSON = "json"
|
||||
)
|
||||
|
||||
type format struct {
|
||||
// Type is either "text" or "json". When not provided "text" type is assumed.
|
||||
Type string `json:"type"`
|
||||
// SubjectTokenFieldName is only required for JSON format. This would be "access_token" for azure.
|
||||
SubjectTokenFieldName string `json:"subject_token_field_name"`
|
||||
}
|
||||
|
||||
// CredentialSource stores the information necessary to retrieve the credentials for the STS exchange.
|
||||
// Either the File or the URL field should be filled, depending on the kind of credential in question.
|
||||
// The EnvironmentID should start with AWS if being used for an AWS credential.
|
||||
type CredentialSource struct {
|
||||
File string `json:"file"`
|
||||
|
||||
URL string `json:"url"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
|
||||
EnvironmentID string `json:"environment_id"`
|
||||
RegionURL string `json:"region_url"`
|
||||
RegionalCredVerificationURL string `json:"regional_cred_verification_url"`
|
||||
CredVerificationURL string `json:"cred_verification_url"`
|
||||
Format format `json:"format"`
|
||||
}
|
||||
|
||||
// parse determines the type of CredentialSource needed
|
||||
func (c *Config) parse(ctx context.Context) (baseCredentialSource, error) {
|
||||
if len(c.CredentialSource.EnvironmentID) > 3 && c.CredentialSource.EnvironmentID[:3] == "aws" {
|
||||
if awsVersion, err := strconv.Atoi(c.CredentialSource.EnvironmentID[3:]); err == nil {
|
||||
if awsVersion != 1 {
|
||||
return nil, fmt.Errorf("oauth2/google: aws version '%d' is not supported in the current build", awsVersion)
|
||||
}
|
||||
return awsCredentialSource{
|
||||
EnvironmentID: c.CredentialSource.EnvironmentID,
|
||||
RegionURL: c.CredentialSource.RegionURL,
|
||||
RegionalCredVerificationURL: c.CredentialSource.RegionalCredVerificationURL,
|
||||
CredVerificationURL: c.CredentialSource.URL,
|
||||
TargetResource: c.Audience,
|
||||
ctx: ctx,
|
||||
}, nil
|
||||
}
|
||||
} else if c.CredentialSource.File != "" {
|
||||
return fileCredentialSource{File: c.CredentialSource.File, Format: c.CredentialSource.Format}, nil
|
||||
} else if c.CredentialSource.URL != "" {
|
||||
return urlCredentialSource{URL: c.CredentialSource.URL, Headers: c.CredentialSource.Headers, Format: c.CredentialSource.Format, ctx: ctx}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("oauth2/google: unable to parse credential source")
|
||||
}
|
||||
|
||||
type baseCredentialSource interface {
|
||||
subjectToken() (string, error)
|
||||
}
|
||||
|
||||
// tokenSource is the source that handles external credentials. It is used to retrieve Tokens.
|
||||
type tokenSource struct {
|
||||
ctx context.Context
|
||||
conf *Config
|
||||
}
|
||||
|
||||
// Token allows tokenSource to conform to the oauth2.TokenSource interface.
|
||||
func (ts tokenSource) Token() (*oauth2.Token, error) {
|
||||
conf := ts.conf
|
||||
|
||||
credSource, err := conf.parse(ts.ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
subjectToken, err := credSource.subjectToken()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stsRequest := stsTokenExchangeRequest{
|
||||
GrantType: "urn:ietf:params:oauth:grant-type:token-exchange",
|
||||
Audience: conf.Audience,
|
||||
Scope: conf.Scopes,
|
||||
RequestedTokenType: "urn:ietf:params:oauth:token-type:access_token",
|
||||
SubjectToken: subjectToken,
|
||||
SubjectTokenType: conf.SubjectTokenType,
|
||||
}
|
||||
header := make(http.Header)
|
||||
header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
clientAuth := clientAuthentication{
|
||||
AuthStyle: oauth2.AuthStyleInHeader,
|
||||
ClientID: conf.ClientID,
|
||||
ClientSecret: conf.ClientSecret,
|
||||
}
|
||||
stsResp, err := exchangeToken(ts.ctx, conf.TokenURL, &stsRequest, clientAuth, header, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accessToken := &oauth2.Token{
|
||||
AccessToken: stsResp.AccessToken,
|
||||
TokenType: stsResp.TokenType,
|
||||
}
|
||||
if stsResp.ExpiresIn < 0 {
|
||||
return nil, fmt.Errorf("oauth2/google: got invalid expiry from security token service")
|
||||
} else if stsResp.ExpiresIn >= 0 {
|
||||
accessToken.Expiry = now().Add(time.Duration(stsResp.ExpiresIn) * time.Second)
|
||||
}
|
||||
|
||||
if stsResp.RefreshToken != "" {
|
||||
accessToken.RefreshToken = stsResp.RefreshToken
|
||||
}
|
||||
return accessToken, nil
|
||||
}
|
44
vendor/golang.org/x/oauth2/google/internal/externalaccount/clientauth.go
generated
vendored
Normal file
44
vendor/golang.org/x/oauth2/google/internal/externalaccount/clientauth.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package externalaccount
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"golang.org/x/oauth2"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// clientAuthentication represents an OAuth client ID and secret and the mechanism for passing these credentials as stated in rfc6749#2.3.1.
|
||||
type clientAuthentication struct {
|
||||
// AuthStyle can be either basic or request-body
|
||||
AuthStyle oauth2.AuthStyle
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
}
|
||||
|
||||
// InjectAuthentication is used to add authentication to a Secure Token Service exchange
|
||||
// request. It modifies either the passed url.Values or http.Header depending on the desired
|
||||
// authentication format.
|
||||
func (c *clientAuthentication) InjectAuthentication(values url.Values, headers http.Header) {
|
||||
if c.ClientID == "" || c.ClientSecret == "" || values == nil || headers == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch c.AuthStyle {
|
||||
case oauth2.AuthStyleInHeader: // AuthStyleInHeader corresponds to basic authentication as defined in rfc7617#2
|
||||
plainHeader := c.ClientID + ":" + c.ClientSecret
|
||||
headers.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(plainHeader)))
|
||||
case oauth2.AuthStyleInParams: // AuthStyleInParams corresponds to request-body authentication with ClientID and ClientSecret in the message body.
|
||||
values.Set("client_id", c.ClientID)
|
||||
values.Set("client_secret", c.ClientSecret)
|
||||
case oauth2.AuthStyleAutoDetect:
|
||||
values.Set("client_id", c.ClientID)
|
||||
values.Set("client_secret", c.ClientSecret)
|
||||
default:
|
||||
values.Set("client_id", c.ClientID)
|
||||
values.Set("client_secret", c.ClientSecret)
|
||||
}
|
||||
}
|
18
vendor/golang.org/x/oauth2/google/internal/externalaccount/err.go
generated
vendored
Normal file
18
vendor/golang.org/x/oauth2/google/internal/externalaccount/err.go
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package externalaccount
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Error for handling OAuth related error responses as stated in rfc6749#5.2.
|
||||
type Error struct {
|
||||
Code string
|
||||
URI string
|
||||
Description string
|
||||
}
|
||||
|
||||
func (err *Error) Error() string {
|
||||
return fmt.Sprintf("got error code %s from %s: %s", err.Code, err.URI, err.Description)
|
||||
}
|
57
vendor/golang.org/x/oauth2/google/internal/externalaccount/filecredsource.go
generated
vendored
Normal file
57
vendor/golang.org/x/oauth2/google/internal/externalaccount/filecredsource.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package externalaccount
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
type fileCredentialSource struct {
|
||||
File string
|
||||
Format format
|
||||
}
|
||||
|
||||
func (cs fileCredentialSource) subjectToken() (string, error) {
|
||||
tokenFile, err := os.Open(cs.File)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("oauth2/google: failed to open credential file %q", cs.File)
|
||||
}
|
||||
defer tokenFile.Close()
|
||||
tokenBytes, err := ioutil.ReadAll(io.LimitReader(tokenFile, 1<<20))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("oauth2/google: failed to read credential file: %v", err)
|
||||
}
|
||||
tokenBytes = bytes.TrimSpace(tokenBytes)
|
||||
switch cs.Format.Type {
|
||||
case "json":
|
||||
jsonData := make(map[string]interface{})
|
||||
err = json.Unmarshal(tokenBytes, &jsonData)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("oauth2/google: failed to unmarshal subject token file: %v", err)
|
||||
}
|
||||
val, ok := jsonData[cs.Format.SubjectTokenFieldName]
|
||||
if !ok {
|
||||
return "", errors.New("oauth2/google: provided subject_token_field_name not found in credentials")
|
||||
}
|
||||
token, ok := val.(string)
|
||||
if !ok {
|
||||
return "", errors.New("oauth2/google: improperly formatted subject token")
|
||||
}
|
||||
return token, nil
|
||||
case "text":
|
||||
return string(tokenBytes), nil
|
||||
case "":
|
||||
return string(tokenBytes), nil
|
||||
default:
|
||||
return "", errors.New("oauth2/google: invalid credential_source file format type")
|
||||
}
|
||||
|
||||
}
|
83
vendor/golang.org/x/oauth2/google/internal/externalaccount/impersonate.go
generated
vendored
Normal file
83
vendor/golang.org/x/oauth2/google/internal/externalaccount/impersonate.go
generated
vendored
Normal file
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package externalaccount
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"golang.org/x/oauth2"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// generateAccesstokenReq is used for service account impersonation
|
||||
type generateAccessTokenReq struct {
|
||||
Delegates []string `json:"delegates,omitempty"`
|
||||
Lifetime string `json:"lifetime,omitempty"`
|
||||
Scope []string `json:"scope,omitempty"`
|
||||
}
|
||||
|
||||
type impersonateTokenResponse struct {
|
||||
AccessToken string `json:"accessToken"`
|
||||
ExpireTime string `json:"expireTime"`
|
||||
}
|
||||
|
||||
type impersonateTokenSource struct {
|
||||
ctx context.Context
|
||||
ts oauth2.TokenSource
|
||||
|
||||
url string
|
||||
scopes []string
|
||||
}
|
||||
|
||||
// Token performs the exchange to get a temporary service account token to allow access to GCP.
|
||||
func (its impersonateTokenSource) Token() (*oauth2.Token, error) {
|
||||
reqBody := generateAccessTokenReq{
|
||||
Lifetime: "3600s",
|
||||
Scope: its.scopes,
|
||||
}
|
||||
b, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oauth2/google: unable to marshal request: %v", err)
|
||||
}
|
||||
client := oauth2.NewClient(its.ctx, its.ts)
|
||||
req, err := http.NewRequest("POST", its.url, bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oauth2/google: unable to create impersonation request: %v", err)
|
||||
}
|
||||
req = req.WithContext(its.ctx)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oauth2/google: unable to generate access token: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oauth2/google: unable to read body: %v", err)
|
||||
}
|
||||
if c := resp.StatusCode; c < 200 || c > 299 {
|
||||
return nil, fmt.Errorf("oauth2/google: status code %d: %s", c, body)
|
||||
}
|
||||
|
||||
var accessTokenResp impersonateTokenResponse
|
||||
if err := json.Unmarshal(body, &accessTokenResp); err != nil {
|
||||
return nil, fmt.Errorf("oauth2/google: unable to parse response: %v", err)
|
||||
}
|
||||
expiry, err := time.Parse(time.RFC3339, accessTokenResp.ExpireTime)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oauth2/google: unable to parse expiry: %v", err)
|
||||
}
|
||||
return &oauth2.Token{
|
||||
AccessToken: accessTokenResp.AccessToken,
|
||||
Expiry: expiry,
|
||||
TokenType: "Bearer",
|
||||
}, nil
|
||||
}
|
104
vendor/golang.org/x/oauth2/google/internal/externalaccount/sts_exchange.go
generated
vendored
Normal file
104
vendor/golang.org/x/oauth2/google/internal/externalaccount/sts_exchange.go
generated
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package externalaccount
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// exchangeToken performs an oauth2 token exchange with the provided endpoint.
|
||||
// The first 4 fields are all mandatory. headers can be used to pass additional
|
||||
// headers beyond the bare minimum required by the token exchange. options can
|
||||
// be used to pass additional JSON-structured options to the remote server.
|
||||
func exchangeToken(ctx context.Context, endpoint string, request *stsTokenExchangeRequest, authentication clientAuthentication, headers http.Header, options map[string]interface{}) (*stsTokenExchangeResponse, error) {
|
||||
|
||||
client := oauth2.NewClient(ctx, nil)
|
||||
|
||||
data := url.Values{}
|
||||
data.Set("audience", request.Audience)
|
||||
data.Set("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange")
|
||||
data.Set("requested_token_type", "urn:ietf:params:oauth:token-type:access_token")
|
||||
data.Set("subject_token_type", request.SubjectTokenType)
|
||||
data.Set("subject_token", request.SubjectToken)
|
||||
data.Set("scope", strings.Join(request.Scope, " "))
|
||||
if options != nil {
|
||||
opts, err := json.Marshal(options)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oauth2/google: failed to marshal additional options: %v", err)
|
||||
}
|
||||
data.Set("options", string(opts))
|
||||
}
|
||||
|
||||
authentication.InjectAuthentication(data, headers)
|
||||
encodedData := data.Encode()
|
||||
|
||||
req, err := http.NewRequest("POST", endpoint, strings.NewReader(encodedData))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oauth2/google: failed to properly build http request: %v", err)
|
||||
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
for key, list := range headers {
|
||||
for _, val := range list {
|
||||
req.Header.Add(key, val)
|
||||
}
|
||||
}
|
||||
req.Header.Add("Content-Length", strconv.Itoa(len(encodedData)))
|
||||
|
||||
resp, err := client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oauth2/google: invalid response from Secure Token Server: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
|
||||
if c := resp.StatusCode; c < 200 || c > 299 {
|
||||
return nil, fmt.Errorf("oauth2/google: status code %d: %s", c, body)
|
||||
}
|
||||
var stsResp stsTokenExchangeResponse
|
||||
err = json.Unmarshal(body, &stsResp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oauth2/google: failed to unmarshal response body from Secure Token Server: %v", err)
|
||||
|
||||
}
|
||||
|
||||
return &stsResp, nil
|
||||
}
|
||||
|
||||
// stsTokenExchangeRequest contains fields necessary to make an oauth2 token exchange.
|
||||
type stsTokenExchangeRequest struct {
|
||||
ActingParty struct {
|
||||
ActorToken string
|
||||
ActorTokenType string
|
||||
}
|
||||
GrantType string
|
||||
Resource string
|
||||
Audience string
|
||||
Scope []string
|
||||
RequestedTokenType string
|
||||
SubjectToken string
|
||||
SubjectTokenType string
|
||||
}
|
||||
|
||||
// stsTokenExchangeResponse is used to decode the remote server response during an oauth2 token exchange.
|
||||
type stsTokenExchangeResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
IssuedTokenType string `json:"issued_token_type"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
Scope string `json:"scope"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
}
|
74
vendor/golang.org/x/oauth2/google/internal/externalaccount/urlcredsource.go
generated
vendored
Normal file
74
vendor/golang.org/x/oauth2/google/internal/externalaccount/urlcredsource.go
generated
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package externalaccount
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/oauth2"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type urlCredentialSource struct {
|
||||
URL string
|
||||
Headers map[string]string
|
||||
Format format
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (cs urlCredentialSource) subjectToken() (string, error) {
|
||||
client := oauth2.NewClient(cs.ctx, nil)
|
||||
req, err := http.NewRequest("GET", cs.URL, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("oauth2/google: HTTP request for URL-sourced credential failed: %v", err)
|
||||
}
|
||||
req = req.WithContext(cs.ctx)
|
||||
|
||||
for key, val := range cs.Headers {
|
||||
req.Header.Add(key, val)
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("oauth2/google: invalid response when retrieving subject token: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("oauth2/google: invalid body in subject token URL query: %v", err)
|
||||
}
|
||||
if c := resp.StatusCode; c < 200 || c > 299 {
|
||||
return "", fmt.Errorf("oauth2/google: status code %d: %s", c, respBody)
|
||||
}
|
||||
|
||||
switch cs.Format.Type {
|
||||
case "json":
|
||||
jsonData := make(map[string]interface{})
|
||||
err = json.Unmarshal(respBody, &jsonData)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("oauth2/google: failed to unmarshal subject token file: %v", err)
|
||||
}
|
||||
val, ok := jsonData[cs.Format.SubjectTokenFieldName]
|
||||
if !ok {
|
||||
return "", errors.New("oauth2/google: provided subject_token_field_name not found in credentials")
|
||||
}
|
||||
token, ok := val.(string)
|
||||
if !ok {
|
||||
return "", errors.New("oauth2/google: improperly formatted subject token")
|
||||
}
|
||||
return token, nil
|
||||
case "text":
|
||||
return string(respBody), nil
|
||||
case "":
|
||||
return string(respBody), nil
|
||||
default:
|
||||
return "", errors.New("oauth2/google: invalid credential_source file format type")
|
||||
}
|
||||
|
||||
}
|
30
vendor/golang.org/x/oauth2/google/jwt.go
generated
vendored
30
vendor/golang.org/x/oauth2/google/jwt.go
generated
vendored
|
@ -7,6 +7,7 @@ package google
|
|||
import (
|
||||
"crypto/rsa"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
|
@ -24,6 +25,28 @@ import (
|
|||
// optimization supported by a few Google services.
|
||||
// Unless you know otherwise, you should use JWTConfigFromJSON instead.
|
||||
func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.TokenSource, error) {
|
||||
return newJWTSource(jsonKey, audience, nil)
|
||||
}
|
||||
|
||||
// JWTAccessTokenSourceWithScope uses a Google Developers service account JSON
|
||||
// key file to read the credentials that authorize and authenticate the
|
||||
// requests, and returns a TokenSource that does not use any OAuth2 flow but
|
||||
// instead creates a JWT and sends that as the access token.
|
||||
// The scope is typically a list of URLs that specifies the scope of the
|
||||
// credentials.
|
||||
//
|
||||
// Note that this is not a standard OAuth flow, but rather an
|
||||
// optimization supported by a few Google services.
|
||||
// Unless you know otherwise, you should use JWTConfigFromJSON instead.
|
||||
func JWTAccessTokenSourceWithScope(jsonKey []byte, scope ...string) (oauth2.TokenSource, error) {
|
||||
return newJWTSource(jsonKey, "", scope)
|
||||
}
|
||||
|
||||
func newJWTSource(jsonKey []byte, audience string, scopes []string) (oauth2.TokenSource, error) {
|
||||
if len(scopes) == 0 && audience == "" {
|
||||
return nil, fmt.Errorf("google: missing scope/audience for JWT access token")
|
||||
}
|
||||
|
||||
cfg, err := JWTConfigFromJSON(jsonKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("google: could not parse JSON key: %v", err)
|
||||
|
@ -35,7 +58,9 @@ func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.Token
|
|||
ts := &jwtAccessTokenSource{
|
||||
email: cfg.Email,
|
||||
audience: audience,
|
||||
scopes: scopes,
|
||||
pk: pk,
|
||||
pkID: cfg.PrivateKeyID,
|
||||
}
|
||||
tok, err := ts.Token()
|
||||
if err != nil {
|
||||
|
@ -46,22 +71,27 @@ func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.Token
|
|||
|
||||
type jwtAccessTokenSource struct {
|
||||
email, audience string
|
||||
scopes []string
|
||||
pk *rsa.PrivateKey
|
||||
pkID string
|
||||
}
|
||||
|
||||
func (ts *jwtAccessTokenSource) Token() (*oauth2.Token, error) {
|
||||
iat := time.Now()
|
||||
exp := iat.Add(time.Hour)
|
||||
scope := strings.Join(ts.scopes, " ")
|
||||
cs := &jws.ClaimSet{
|
||||
Iss: ts.email,
|
||||
Sub: ts.email,
|
||||
Aud: ts.audience,
|
||||
Scope: scope,
|
||||
Iat: iat.Unix(),
|
||||
Exp: exp.Unix(),
|
||||
}
|
||||
hdr := &jws.Header{
|
||||
Algorithm: "RS256",
|
||||
Typ: "JWT",
|
||||
KeyID: string(ts.pkID),
|
||||
}
|
||||
msg, err := jws.Encode(hdr, cs, ts.pk)
|
||||
if err != nil {
|
||||
|
|
47
vendor/golang.org/x/oauth2/google/sdk.go
generated
vendored
47
vendor/golang.org/x/oauth2/google/sdk.go
generated
vendored
|
@ -5,9 +5,12 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/user"
|
||||
|
@ -16,9 +19,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/internal"
|
||||
)
|
||||
|
||||
type sdkCredentials struct {
|
||||
|
@ -76,7 +77,7 @@ func NewSDKConfig(account string) (*SDKConfig, error) {
|
|||
return nil, fmt.Errorf("oauth2/google: failed to load SDK properties: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
ini, err := internal.ParseINI(f)
|
||||
ini, err := parseINI(f)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oauth2/google: failed to parse SDK properties %q: %v", propertiesPath, err)
|
||||
}
|
||||
|
@ -146,6 +147,34 @@ func (c *SDKConfig) Scopes() []string {
|
|||
return c.conf.Scopes
|
||||
}
|
||||
|
||||
func parseINI(ini io.Reader) (map[string]map[string]string, error) {
|
||||
result := map[string]map[string]string{
|
||||
"": {}, // root section
|
||||
}
|
||||
scanner := bufio.NewScanner(ini)
|
||||
currentSection := ""
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if strings.HasPrefix(line, ";") {
|
||||
// comment.
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
|
||||
currentSection = strings.TrimSpace(line[1 : len(line)-1])
|
||||
result[currentSection] = map[string]string{}
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(line, "=", 2)
|
||||
if len(parts) == 2 && parts[0] != "" {
|
||||
result[currentSection][strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, fmt.Errorf("error scanning ini: %v", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// sdkConfigPath tries to guess where the gcloud config is located.
|
||||
// It can be overridden during tests.
|
||||
var sdkConfigPath = func() (string, error) {
|
||||
|
@ -160,9 +189,13 @@ var sdkConfigPath = func() (string, error) {
|
|||
}
|
||||
|
||||
func guessUnixHomeDir() string {
|
||||
usr, err := user.Current()
|
||||
if err == nil {
|
||||
return usr.HomeDir
|
||||
// Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470
|
||||
if v := os.Getenv("HOME"); v != "" {
|
||||
return v
|
||||
}
|
||||
return os.Getenv("HOME")
|
||||
// Else, fall back to user.Current:
|
||||
if u, err := user.Current(); err == nil {
|
||||
return u.HomeDir
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
14
vendor/golang.org/x/oauth2/internal/client_appengine.go
generated
vendored
Normal file
14
vendor/golang.org/x/oauth2/internal/client_appengine.go
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build appengine
|
||||
// +build appengine
|
||||
|
||||
package internal
|
||||
|
||||
import "google.golang.org/appengine/urlfetch"
|
||||
|
||||
func init() {
|
||||
appengineClientHook = urlfetch.Client
|
||||
}
|
6
vendor/golang.org/x/oauth2/internal/doc.go
generated
vendored
Normal file
6
vendor/golang.org/x/oauth2/internal/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package internal contains support packages for oauth2 package.
|
||||
package internal
|
41
vendor/golang.org/x/oauth2/internal/oauth2.go
generated
vendored
41
vendor/golang.org/x/oauth2/internal/oauth2.go
generated
vendored
|
@ -2,18 +2,14 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package internal contains support packages for oauth2 package.
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseKey converts the binary contents of a private key file
|
||||
|
@ -30,7 +26,7 @@ func ParseKey(key []byte) (*rsa.PrivateKey, error) {
|
|||
if err != nil {
|
||||
parsedKey, err = x509.ParsePKCS1PrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("private key should be a PEM or plain PKSC1 or PKCS8; parse error: %v", err)
|
||||
return nil, fmt.Errorf("private key should be a PEM or plain PKCS1 or PKCS8; parse error: %v", err)
|
||||
}
|
||||
}
|
||||
parsed, ok := parsedKey.(*rsa.PrivateKey)
|
||||
|
@ -39,38 +35,3 @@ func ParseKey(key []byte) (*rsa.PrivateKey, error) {
|
|||
}
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func ParseINI(ini io.Reader) (map[string]map[string]string, error) {
|
||||
result := map[string]map[string]string{
|
||||
"": map[string]string{}, // root section
|
||||
}
|
||||
scanner := bufio.NewScanner(ini)
|
||||
currentSection := ""
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if strings.HasPrefix(line, ";") {
|
||||
// comment.
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
|
||||
currentSection = strings.TrimSpace(line[1 : len(line)-1])
|
||||
result[currentSection] = map[string]string{}
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(line, "=", 2)
|
||||
if len(parts) == 2 && parts[0] != "" {
|
||||
result[currentSection][strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, fmt.Errorf("error scanning ini: %v", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func CondVal(v string) []string {
|
||||
if v == "" {
|
||||
return nil
|
||||
}
|
||||
return []string{v}
|
||||
}
|
||||
|
|
232
vendor/golang.org/x/oauth2/internal/token.go
generated
vendored
232
vendor/golang.org/x/oauth2/internal/token.go
generated
vendored
|
@ -2,25 +2,28 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package internal contains support packages for oauth2 package.
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
)
|
||||
|
||||
// Token represents the crendentials used to authorize
|
||||
// Token represents the credentials used to authorize
|
||||
// the requests to access protected resources on the OAuth 2.0
|
||||
// provider's backend.
|
||||
//
|
||||
|
@ -60,22 +63,21 @@ type tokenJSON struct {
|
|||
TokenType string `json:"token_type"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresIn expirationTime `json:"expires_in"` // at least PayPal returns string, while most return number
|
||||
Expires expirationTime `json:"expires"` // broken Facebook spelling of expires_in
|
||||
}
|
||||
|
||||
func (e *tokenJSON) expiry() (t time.Time) {
|
||||
if v := e.ExpiresIn; v != 0 {
|
||||
return time.Now().Add(time.Duration(v) * time.Second)
|
||||
}
|
||||
if v := e.Expires; v != 0 {
|
||||
return time.Now().Add(time.Duration(v) * time.Second)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type expirationTime int32
|
||||
|
||||
func (e *expirationTime) UnmarshalJSON(b []byte) error {
|
||||
if len(b) == 0 || string(b) == "null" {
|
||||
return nil
|
||||
}
|
||||
var n json.Number
|
||||
err := json.Unmarshal(b, &n)
|
||||
if err != nil {
|
||||
|
@ -85,95 +87,162 @@ func (e *expirationTime) UnmarshalJSON(b []byte) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i > math.MaxInt32 {
|
||||
i = math.MaxInt32
|
||||
}
|
||||
*e = expirationTime(i)
|
||||
return nil
|
||||
}
|
||||
|
||||
var brokenAuthHeaderProviders = []string{
|
||||
"https://accounts.google.com/",
|
||||
"https://api.dropbox.com/",
|
||||
"https://api.instagram.com/",
|
||||
"https://api.netatmo.net/",
|
||||
"https://api.odnoklassniki.ru/",
|
||||
"https://api.pushbullet.com/",
|
||||
"https://api.soundcloud.com/",
|
||||
"https://api.twitch.tv/",
|
||||
"https://app.box.com/",
|
||||
"https://connect.stripe.com/",
|
||||
"https://login.microsoftonline.com/",
|
||||
"https://login.salesforce.com/",
|
||||
"https://oauth.sandbox.trainingpeaks.com/",
|
||||
"https://oauth.trainingpeaks.com/",
|
||||
"https://oauth.vk.com/",
|
||||
"https://openapi.baidu.com/",
|
||||
"https://slack.com/",
|
||||
"https://test-sandbox.auth.corp.google.com",
|
||||
"https://test.salesforce.com/",
|
||||
"https://user.gini.net/",
|
||||
"https://www.douban.com/",
|
||||
"https://www.googleapis.com/",
|
||||
"https://www.linkedin.com/",
|
||||
"https://www.strava.com/oauth/",
|
||||
"https://www.wunderlist.com/oauth/",
|
||||
"https://api.patreon.com/",
|
||||
// RegisterBrokenAuthHeaderProvider previously did something. It is now a no-op.
|
||||
//
|
||||
// Deprecated: this function no longer does anything. Caller code that
|
||||
// wants to avoid potential extra HTTP requests made during
|
||||
// auto-probing of the provider's auth style should set
|
||||
// Endpoint.AuthStyle.
|
||||
func RegisterBrokenAuthHeaderProvider(tokenURL string) {}
|
||||
|
||||
// AuthStyle is a copy of the golang.org/x/oauth2 package's AuthStyle type.
|
||||
type AuthStyle int
|
||||
|
||||
const (
|
||||
AuthStyleUnknown AuthStyle = 0
|
||||
AuthStyleInParams AuthStyle = 1
|
||||
AuthStyleInHeader AuthStyle = 2
|
||||
)
|
||||
|
||||
// authStyleCache is the set of tokenURLs we've successfully used via
|
||||
// RetrieveToken and which style auth we ended up using.
|
||||
// It's called a cache, but it doesn't (yet?) shrink. It's expected that
|
||||
// the set of OAuth2 servers a program contacts over time is fixed and
|
||||
// small.
|
||||
var authStyleCache struct {
|
||||
sync.Mutex
|
||||
m map[string]AuthStyle // keyed by tokenURL
|
||||
}
|
||||
|
||||
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
|
||||
brokenAuthHeaderProviders = append(brokenAuthHeaderProviders, tokenURL)
|
||||
// ResetAuthCache resets the global authentication style cache used
|
||||
// for AuthStyleUnknown token requests.
|
||||
func ResetAuthCache() {
|
||||
authStyleCache.Lock()
|
||||
defer authStyleCache.Unlock()
|
||||
authStyleCache.m = nil
|
||||
}
|
||||
|
||||
// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
|
||||
// implements the OAuth2 spec correctly
|
||||
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
|
||||
// In summary:
|
||||
// - Reddit only accepts client secret in the Authorization header
|
||||
// - Dropbox accepts either it in URL param or Auth header, but not both.
|
||||
// - Google only accepts URL param (not spec compliant?), not Auth header
|
||||
// - Stripe only accepts client secret in Auth header with Bearer method, not Basic
|
||||
func providerAuthHeaderWorks(tokenURL string) bool {
|
||||
for _, s := range brokenAuthHeaderProviders {
|
||||
if strings.HasPrefix(tokenURL, s) {
|
||||
// Some sites fail to implement the OAuth2 spec fully.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Assume the provider implements the spec properly
|
||||
// otherwise. We can add more exceptions as they're
|
||||
// discovered. We will _not_ be adding configurable hooks
|
||||
// to this package to let users select server bugs.
|
||||
return true
|
||||
// lookupAuthStyle reports which auth style we last used with tokenURL
|
||||
// when calling RetrieveToken and whether we have ever done so.
|
||||
func lookupAuthStyle(tokenURL string) (style AuthStyle, ok bool) {
|
||||
authStyleCache.Lock()
|
||||
defer authStyleCache.Unlock()
|
||||
style, ok = authStyleCache.m[tokenURL]
|
||||
return
|
||||
}
|
||||
|
||||
func RetrieveToken(ctx context.Context, ClientID, ClientSecret, TokenURL string, v url.Values) (*Token, error) {
|
||||
hc, err := ContextClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// setAuthStyle adds an entry to authStyleCache, documented above.
|
||||
func setAuthStyle(tokenURL string, v AuthStyle) {
|
||||
authStyleCache.Lock()
|
||||
defer authStyleCache.Unlock()
|
||||
if authStyleCache.m == nil {
|
||||
authStyleCache.m = make(map[string]AuthStyle)
|
||||
}
|
||||
v.Set("client_id", ClientID)
|
||||
bustedAuth := !providerAuthHeaderWorks(TokenURL)
|
||||
if bustedAuth && ClientSecret != "" {
|
||||
v.Set("client_secret", ClientSecret)
|
||||
authStyleCache.m[tokenURL] = v
|
||||
}
|
||||
|
||||
// newTokenRequest returns a new *http.Request to retrieve a new token
|
||||
// from tokenURL using the provided clientID, clientSecret, and POST
|
||||
// body parameters.
|
||||
//
|
||||
// inParams is whether the clientID & clientSecret should be encoded
|
||||
// as the POST body. An 'inParams' value of true means to send it in
|
||||
// the POST body (along with any values in v); false means to send it
|
||||
// in the Authorization header.
|
||||
func newTokenRequest(tokenURL, clientID, clientSecret string, v url.Values, authStyle AuthStyle) (*http.Request, error) {
|
||||
if authStyle == AuthStyleInParams {
|
||||
v = cloneURLValues(v)
|
||||
if clientID != "" {
|
||||
v.Set("client_id", clientID)
|
||||
}
|
||||
req, err := http.NewRequest("POST", TokenURL, strings.NewReader(v.Encode()))
|
||||
if clientSecret != "" {
|
||||
v.Set("client_secret", clientSecret)
|
||||
}
|
||||
}
|
||||
req, err := http.NewRequest("POST", tokenURL, strings.NewReader(v.Encode()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
if !bustedAuth {
|
||||
req.SetBasicAuth(ClientID, ClientSecret)
|
||||
if authStyle == AuthStyleInHeader {
|
||||
req.SetBasicAuth(url.QueryEscape(clientID), url.QueryEscape(clientSecret))
|
||||
}
|
||||
r, err := hc.Do(req)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func cloneURLValues(v url.Values) url.Values {
|
||||
v2 := make(url.Values, len(v))
|
||||
for k, vv := range v {
|
||||
v2[k] = append([]string(nil), vv...)
|
||||
}
|
||||
return v2
|
||||
}
|
||||
|
||||
func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values, authStyle AuthStyle) (*Token, error) {
|
||||
needsAuthStyleProbe := authStyle == 0
|
||||
if needsAuthStyleProbe {
|
||||
if style, ok := lookupAuthStyle(tokenURL); ok {
|
||||
authStyle = style
|
||||
needsAuthStyleProbe = false
|
||||
} else {
|
||||
authStyle = AuthStyleInHeader // the first way we'll try
|
||||
}
|
||||
}
|
||||
req, err := newTokenRequest(tokenURL, clientID, clientSecret, v, authStyle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
token, err := doTokenRoundTrip(ctx, req)
|
||||
if err != nil && needsAuthStyleProbe {
|
||||
// If we get an error, assume the server wants the
|
||||
// clientID & clientSecret in a different form.
|
||||
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
|
||||
// In summary:
|
||||
// - Reddit only accepts client secret in the Authorization header
|
||||
// - Dropbox accepts either it in URL param or Auth header, but not both.
|
||||
// - Google only accepts URL param (not spec compliant?), not Auth header
|
||||
// - Stripe only accepts client secret in Auth header with Bearer method, not Basic
|
||||
//
|
||||
// We used to maintain a big table in this code of all the sites and which way
|
||||
// they went, but maintaining it didn't scale & got annoying.
|
||||
// So just try both ways.
|
||||
authStyle = AuthStyleInParams // the second way we'll try
|
||||
req, _ = newTokenRequest(tokenURL, clientID, clientSecret, v, authStyle)
|
||||
token, err = doTokenRoundTrip(ctx, req)
|
||||
}
|
||||
if needsAuthStyleProbe && err == nil {
|
||||
setAuthStyle(tokenURL, authStyle)
|
||||
}
|
||||
// Don't overwrite `RefreshToken` with an empty value
|
||||
// if this was a token refreshing request.
|
||||
if token != nil && token.RefreshToken == "" {
|
||||
token.RefreshToken = v.Get("refresh_token")
|
||||
}
|
||||
return token, err
|
||||
}
|
||||
|
||||
func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) {
|
||||
r, err := ctxhttp.Do(ctx, ContextClient(ctx), req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer r.Body.Close()
|
||||
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
|
||||
r.Body.Close()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
||||
}
|
||||
if code := r.StatusCode; code < 200 || code > 299 {
|
||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", r.Status, body)
|
||||
return nil, &RetrieveError{
|
||||
Response: r,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
|
||||
var token *Token
|
||||
|
@ -191,12 +260,6 @@ func RetrieveToken(ctx context.Context, ClientID, ClientSecret, TokenURL string,
|
|||
Raw: vals,
|
||||
}
|
||||
e := vals.Get("expires_in")
|
||||
if e == "" {
|
||||
// TODO(jbd): Facebook's OAuth2 implementation is broken and
|
||||
// returns expires_in field in expires. Remove the fallback to expires,
|
||||
// when Facebook fixes their implementation.
|
||||
e = vals.Get("expires")
|
||||
}
|
||||
expires, _ := strconv.Atoi(e)
|
||||
if expires != 0 {
|
||||
token.Expiry = time.Now().Add(time.Duration(expires) * time.Second)
|
||||
|
@ -215,10 +278,17 @@ func RetrieveToken(ctx context.Context, ClientID, ClientSecret, TokenURL string,
|
|||
}
|
||||
json.Unmarshal(body, &token.Raw) // no error checks for optional fields
|
||||
}
|
||||
// Don't overwrite `RefreshToken` with an empty value
|
||||
// if this was a token refreshing request.
|
||||
if token.RefreshToken == "" {
|
||||
token.RefreshToken = v.Get("refresh_token")
|
||||
if token.AccessToken == "" {
|
||||
return nil, errors.New("oauth2: server response missing access_token")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
type RetrieveError struct {
|
||||
Response *http.Response
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (r *RetrieveError) Error() string {
|
||||
return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body)
|
||||
}
|
||||
|
|
50
vendor/golang.org/x/oauth2/internal/transport.go
generated
vendored
50
vendor/golang.org/x/oauth2/internal/transport.go
generated
vendored
|
@ -2,13 +2,11 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package internal contains support packages for oauth2 package.
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// HTTPClient is the context key to use with golang.org/x/net/context's
|
||||
|
@ -20,50 +18,16 @@ var HTTPClient ContextKey
|
|||
// because nobody else can create a ContextKey, being unexported.
|
||||
type ContextKey struct{}
|
||||
|
||||
// ContextClientFunc is a func which tries to return an *http.Client
|
||||
// given a Context value. If it returns an error, the search stops
|
||||
// with that error. If it returns (nil, nil), the search continues
|
||||
// down the list of registered funcs.
|
||||
type ContextClientFunc func(context.Context) (*http.Client, error)
|
||||
var appengineClientHook func(context.Context) *http.Client
|
||||
|
||||
var contextClientFuncs []ContextClientFunc
|
||||
|
||||
func RegisterContextClientFunc(fn ContextClientFunc) {
|
||||
contextClientFuncs = append(contextClientFuncs, fn)
|
||||
}
|
||||
|
||||
func ContextClient(ctx context.Context) (*http.Client, error) {
|
||||
func ContextClient(ctx context.Context) *http.Client {
|
||||
if ctx != nil {
|
||||
if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
|
||||
return hc, nil
|
||||
return hc
|
||||
}
|
||||
}
|
||||
for _, fn := range contextClientFuncs {
|
||||
c, err := fn(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if appengineClientHook != nil {
|
||||
return appengineClientHook(ctx)
|
||||
}
|
||||
if c != nil {
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
return http.DefaultClient, nil
|
||||
}
|
||||
|
||||
func ContextTransport(ctx context.Context) http.RoundTripper {
|
||||
hc, err := ContextClient(ctx)
|
||||
// This is a rare error case (somebody using nil on App Engine).
|
||||
if err != nil {
|
||||
return ErrorTransport{err}
|
||||
}
|
||||
return hc.Transport
|
||||
}
|
||||
|
||||
// ErrorTransport returns the specified error on RoundTrip.
|
||||
// This RoundTripper should be used in rare error cases where
|
||||
// error handling can be postponed to response handling time.
|
||||
type ErrorTransport struct{ Err error }
|
||||
|
||||
func (t ErrorTransport) RoundTrip(*http.Request) (*http.Response, error) {
|
||||
return nil, t.Err
|
||||
return http.DefaultClient
|
||||
}
|
||||
|
|
60
vendor/golang.org/x/oauth2/jws/jws.go
generated
vendored
60
vendor/golang.org/x/oauth2/jws/jws.go
generated
vendored
|
@ -2,8 +2,16 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package jws provides encoding and decoding utilities for
|
||||
// signed JWS messages.
|
||||
// Package jws provides a partial implementation
|
||||
// of JSON Web Signature encoding and decoding.
|
||||
// It exists to support the golang.org/x/oauth2 package.
|
||||
//
|
||||
// See RFC 7515.
|
||||
//
|
||||
// Deprecated: this package is not intended for public use and might be
|
||||
// removed in the future. It exists for internal use only.
|
||||
// Please switch to another JWS package or copy this package into your own
|
||||
// source tree.
|
||||
package jws // import "golang.org/x/oauth2/jws"
|
||||
|
||||
import (
|
||||
|
@ -64,7 +72,7 @@ func (c *ClaimSet) encode() (string, error) {
|
|||
}
|
||||
|
||||
if len(c.PrivateClaims) == 0 {
|
||||
return base64Encode(b), nil
|
||||
return base64.RawURLEncoding.EncodeToString(b), nil
|
||||
}
|
||||
|
||||
// Marshal private claim set and then append it to b.
|
||||
|
@ -82,7 +90,7 @@ func (c *ClaimSet) encode() (string, error) {
|
|||
}
|
||||
b[len(b)-1] = ',' // Replace closing curly brace with a comma.
|
||||
b = append(b, prv[1:]...) // Append private claims.
|
||||
return base64Encode(b), nil
|
||||
return base64.RawURLEncoding.EncodeToString(b), nil
|
||||
}
|
||||
|
||||
// Header represents the header for the signed JWS payloads.
|
||||
|
@ -92,6 +100,9 @@ type Header struct {
|
|||
|
||||
// Represents the token type.
|
||||
Typ string `json:"typ"`
|
||||
|
||||
// The optional hint of which key is being used.
|
||||
KeyID string `json:"kid,omitempty"`
|
||||
}
|
||||
|
||||
func (h *Header) encode() (string, error) {
|
||||
|
@ -99,7 +110,7 @@ func (h *Header) encode() (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64Encode(b), nil
|
||||
return base64.RawURLEncoding.EncodeToString(b), nil
|
||||
}
|
||||
|
||||
// Decode decodes a claim set from a JWS payload.
|
||||
|
@ -110,7 +121,7 @@ func Decode(payload string) (*ClaimSet, error) {
|
|||
// TODO(jbd): Provide more context about the error.
|
||||
return nil, errors.New("jws: invalid token received")
|
||||
}
|
||||
decoded, err := base64Decode(s[1])
|
||||
decoded, err := base64.RawURLEncoding.DecodeString(s[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -137,7 +148,7 @@ func EncodeWithSigner(header *Header, c *ClaimSet, sg Signer) (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%s.%s", ss, base64Encode(sig)), nil
|
||||
return fmt.Sprintf("%s.%s", ss, base64.RawURLEncoding.EncodeToString(sig)), nil
|
||||
}
|
||||
|
||||
// Encode encodes a signed JWS with provided header and claim set.
|
||||
|
@ -145,28 +156,27 @@ func EncodeWithSigner(header *Header, c *ClaimSet, sg Signer) (string, error) {
|
|||
func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) {
|
||||
sg := func(data []byte) (sig []byte, err error) {
|
||||
h := sha256.New()
|
||||
h.Write([]byte(data))
|
||||
h.Write(data)
|
||||
return rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
|
||||
}
|
||||
return EncodeWithSigner(header, c, sg)
|
||||
}
|
||||
|
||||
// base64Encode returns and Base64url encoded version of the input string with any
|
||||
// trailing "=" stripped.
|
||||
func base64Encode(b []byte) string {
|
||||
return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
|
||||
}
|
||||
|
||||
// base64Decode decodes the Base64url encoded string
|
||||
func base64Decode(s string) ([]byte, error) {
|
||||
// add back missing padding
|
||||
switch len(s) % 4 {
|
||||
case 1:
|
||||
s += "==="
|
||||
case 2:
|
||||
s += "=="
|
||||
case 3:
|
||||
s += "="
|
||||
// Verify tests whether the provided JWT token's signature was produced by the private key
|
||||
// associated with the supplied public key.
|
||||
func Verify(token string, key *rsa.PublicKey) error {
|
||||
parts := strings.Split(token, ".")
|
||||
if len(parts) != 3 {
|
||||
return errors.New("jws: invalid token received, token must have 3 parts")
|
||||
}
|
||||
return base64.URLEncoding.DecodeString(s)
|
||||
|
||||
signedContent := parts[0] + "." + parts[1]
|
||||
signatureString, err := base64.RawURLEncoding.DecodeString(parts[2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h := sha256.New()
|
||||
h.Write([]byte(signedContent))
|
||||
return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), []byte(signatureString))
|
||||
}
|
||||
|
|
38
vendor/golang.org/x/oauth2/jwt/jwt.go
generated
vendored
38
vendor/golang.org/x/oauth2/jwt/jwt.go
generated
vendored
|
@ -9,6 +9,7 @@
|
|||
package jwt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -18,7 +19,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/internal"
|
||||
"golang.org/x/oauth2/jws"
|
||||
|
@ -46,6 +46,10 @@ type Config struct {
|
|||
//
|
||||
PrivateKey []byte
|
||||
|
||||
// PrivateKeyID contains an optional hint indicating which key is being
|
||||
// used.
|
||||
PrivateKeyID string
|
||||
|
||||
// Subject is the optional user to impersonate.
|
||||
Subject string
|
||||
|
||||
|
@ -57,6 +61,19 @@ type Config struct {
|
|||
|
||||
// Expires optionally specifies how long the token is valid for.
|
||||
Expires time.Duration
|
||||
|
||||
// Audience optionally specifies the intended audience of the
|
||||
// request. If empty, the value of TokenURL is used as the
|
||||
// intended audience.
|
||||
Audience string
|
||||
|
||||
// PrivateClaims optionally specifies custom private claims in the JWT.
|
||||
// See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
|
||||
PrivateClaims map[string]interface{}
|
||||
|
||||
// UseIDToken optionally specifies whether ID token should be used instead
|
||||
// of access token when the server returns both.
|
||||
UseIDToken bool
|
||||
}
|
||||
|
||||
// TokenSource returns a JWT TokenSource using the configuration
|
||||
|
@ -91,6 +108,7 @@ func (js jwtSource) Token() (*oauth2.Token, error) {
|
|||
Iss: js.conf.Email,
|
||||
Scope: strings.Join(js.conf.Scopes, " "),
|
||||
Aud: js.conf.TokenURL,
|
||||
PrivateClaims: js.conf.PrivateClaims,
|
||||
}
|
||||
if subject := js.conf.Subject; subject != "" {
|
||||
claimSet.Sub = subject
|
||||
|
@ -101,7 +119,12 @@ func (js jwtSource) Token() (*oauth2.Token, error) {
|
|||
if t := js.conf.Expires; t > 0 {
|
||||
claimSet.Exp = time.Now().Add(t).Unix()
|
||||
}
|
||||
payload, err := jws.Encode(defaultHeader, claimSet, pk)
|
||||
if aud := js.conf.Audience; aud != "" {
|
||||
claimSet.Aud = aud
|
||||
}
|
||||
h := *defaultHeader
|
||||
h.KeyID = js.conf.PrivateKeyID
|
||||
payload, err := jws.Encode(&h, claimSet, pk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -118,7 +141,10 @@ func (js jwtSource) Token() (*oauth2.Token, error) {
|
|||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
||||
}
|
||||
if c := resp.StatusCode; c < 200 || c > 299 {
|
||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", resp.Status, body)
|
||||
return nil, &oauth2.RetrieveError{
|
||||
Response: resp,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
// tokenRes is the JSON response body.
|
||||
var tokenRes struct {
|
||||
|
@ -149,5 +175,11 @@ func (js jwtSource) Token() (*oauth2.Token, error) {
|
|||
}
|
||||
token.Expiry = time.Unix(claimSet.Exp, 0)
|
||||
}
|
||||
if js.conf.UseIDToken {
|
||||
if tokenRes.IDToken == "" {
|
||||
return nil, fmt.Errorf("oauth2: response doesn't have JWT token")
|
||||
}
|
||||
token.AccessToken = tokenRes.IDToken
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
|
118
vendor/golang.org/x/oauth2/oauth2.go
generated
vendored
118
vendor/golang.org/x/oauth2/oauth2.go
generated
vendored
|
@ -3,40 +3,41 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package oauth2 provides support for making
|
||||
// OAuth2 authorized and authenticated HTTP requests.
|
||||
// OAuth2 authorized and authenticated HTTP requests,
|
||||
// as specified in RFC 6749.
|
||||
// It can additionally grant authorization with Bearer JWT.
|
||||
package oauth2 // import "golang.org/x/oauth2"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2/internal"
|
||||
)
|
||||
|
||||
// NoContext is the default context you should supply if not using
|
||||
// your own context.Context (see https://golang.org/x/net/context).
|
||||
//
|
||||
// Deprecated: Use context.Background() or context.TODO() instead.
|
||||
var NoContext = context.TODO()
|
||||
|
||||
// RegisterBrokenAuthHeaderProvider registers an OAuth2 server
|
||||
// identified by the tokenURL prefix as an OAuth2 implementation
|
||||
// which doesn't support the HTTP Basic authentication
|
||||
// scheme to authenticate with the authorization server.
|
||||
// Once a server is registered, credentials (client_id and client_secret)
|
||||
// will be passed as query parameters rather than being present
|
||||
// in the Authorization header.
|
||||
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
|
||||
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
|
||||
internal.RegisterBrokenAuthHeaderProvider(tokenURL)
|
||||
}
|
||||
// RegisterBrokenAuthHeaderProvider previously did something. It is now a no-op.
|
||||
//
|
||||
// Deprecated: this function no longer does anything. Caller code that
|
||||
// wants to avoid potential extra HTTP requests made during
|
||||
// auto-probing of the provider's auth style should set
|
||||
// Endpoint.AuthStyle.
|
||||
func RegisterBrokenAuthHeaderProvider(tokenURL string) {}
|
||||
|
||||
// Config describes a typical 3-legged OAuth2 flow, with both the
|
||||
// client application information and the server's endpoint URLs.
|
||||
// For the client credentials 2-legged OAuth2 flow, see the clientcredentials
|
||||
// package (https://golang.org/x/oauth2/clientcredentials).
|
||||
type Config struct {
|
||||
// ClientID is the application's ID.
|
||||
ClientID string
|
||||
|
@ -66,13 +67,38 @@ type TokenSource interface {
|
|||
Token() (*Token, error)
|
||||
}
|
||||
|
||||
// Endpoint contains the OAuth 2.0 provider's authorization and token
|
||||
// Endpoint represents an OAuth 2.0 provider's authorization and token
|
||||
// endpoint URLs.
|
||||
type Endpoint struct {
|
||||
AuthURL string
|
||||
TokenURL string
|
||||
|
||||
// AuthStyle optionally specifies how the endpoint wants the
|
||||
// client ID & client secret sent. The zero value means to
|
||||
// auto-detect.
|
||||
AuthStyle AuthStyle
|
||||
}
|
||||
|
||||
// AuthStyle represents how requests for tokens are authenticated
|
||||
// to the server.
|
||||
type AuthStyle int
|
||||
|
||||
const (
|
||||
// AuthStyleAutoDetect means to auto-detect which authentication
|
||||
// style the provider wants by trying both ways and caching
|
||||
// the successful way for the future.
|
||||
AuthStyleAutoDetect AuthStyle = 0
|
||||
|
||||
// AuthStyleInParams sends the "client_id" and "client_secret"
|
||||
// in the POST body as application/x-www-form-urlencoded parameters.
|
||||
AuthStyleInParams AuthStyle = 1
|
||||
|
||||
// AuthStyleInHeader sends the client_id and client_password
|
||||
// using HTTP Basic Authorization. This is an optional style
|
||||
// described in the OAuth2 RFC 6749 section 2.3.1.
|
||||
AuthStyleInHeader AuthStyle = 2
|
||||
)
|
||||
|
||||
var (
|
||||
// AccessTypeOnline and AccessTypeOffline are options passed
|
||||
// to the Options.AuthCodeURL method. They modify the
|
||||
|
@ -91,7 +117,7 @@ var (
|
|||
// ApprovalForce forces the users to view the consent dialog
|
||||
// and confirm the permissions request at the URL returned
|
||||
// from AuthCodeURL, even if they've already done so.
|
||||
ApprovalForce AuthCodeOption = SetAuthURLParam("approval_prompt", "force")
|
||||
ApprovalForce AuthCodeOption = SetAuthURLParam("prompt", "consent")
|
||||
)
|
||||
|
||||
// An AuthCodeOption is passed to Config.AuthCodeURL.
|
||||
|
@ -113,21 +139,30 @@ func SetAuthURLParam(key, value string) AuthCodeOption {
|
|||
// that asks for permissions for the required scopes explicitly.
|
||||
//
|
||||
// State is a token to protect the user from CSRF attacks. You must
|
||||
// always provide a non-zero string and validate that it matches the
|
||||
// always provide a non-empty string and validate that it matches the
|
||||
// the state query parameter on your redirect callback.
|
||||
// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
|
||||
//
|
||||
// Opts may include AccessTypeOnline or AccessTypeOffline, as well
|
||||
// as ApprovalForce.
|
||||
// It can also be used to pass the PKCE challenge.
|
||||
// See https://www.oauth.com/oauth2-servers/pkce/ for more info.
|
||||
func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(c.Endpoint.AuthURL)
|
||||
v := url.Values{
|
||||
"response_type": {"code"},
|
||||
"client_id": {c.ClientID},
|
||||
"redirect_uri": internal.CondVal(c.RedirectURL),
|
||||
"scope": internal.CondVal(strings.Join(c.Scopes, " ")),
|
||||
"state": internal.CondVal(state),
|
||||
}
|
||||
if c.RedirectURL != "" {
|
||||
v.Set("redirect_uri", c.RedirectURL)
|
||||
}
|
||||
if len(c.Scopes) > 0 {
|
||||
v.Set("scope", strings.Join(c.Scopes, " "))
|
||||
}
|
||||
if state != "" {
|
||||
// TODO(light): Docs say never to omit state; don't allow empty.
|
||||
v.Set("state", state)
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt.setValue(v)
|
||||
|
@ -150,15 +185,17 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
|
|||
// and when other authorization grant types are not available."
|
||||
// See https://tools.ietf.org/html/rfc6749#section-4.3 for more info.
|
||||
//
|
||||
// The HTTP client to use is derived from the context.
|
||||
// If nil, http.DefaultClient is used.
|
||||
// The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
|
||||
func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) {
|
||||
return retrieveToken(ctx, c, url.Values{
|
||||
v := url.Values{
|
||||
"grant_type": {"password"},
|
||||
"username": {username},
|
||||
"password": {password},
|
||||
"scope": internal.CondVal(strings.Join(c.Scopes, " ")),
|
||||
})
|
||||
}
|
||||
if len(c.Scopes) > 0 {
|
||||
v.Set("scope", strings.Join(c.Scopes, " "))
|
||||
}
|
||||
return retrieveToken(ctx, c, v)
|
||||
}
|
||||
|
||||
// Exchange converts an authorization code into a token.
|
||||
|
@ -166,18 +203,25 @@ func (c *Config) PasswordCredentialsToken(ctx context.Context, username, passwor
|
|||
// It is used after a resource provider redirects the user back
|
||||
// to the Redirect URI (the URL obtained from AuthCodeURL).
|
||||
//
|
||||
// The HTTP client to use is derived from the context.
|
||||
// If a client is not provided via the context, http.DefaultClient is used.
|
||||
// The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
|
||||
//
|
||||
// The code will be in the *http.Request.FormValue("code"). Before
|
||||
// calling Exchange, be sure to validate FormValue("state").
|
||||
func (c *Config) Exchange(ctx context.Context, code string) (*Token, error) {
|
||||
return retrieveToken(ctx, c, url.Values{
|
||||
//
|
||||
// Opts may include the PKCE verifier code if previously used in AuthCodeURL.
|
||||
// See https://www.oauth.com/oauth2-servers/pkce/ for more info.
|
||||
func (c *Config) Exchange(ctx context.Context, code string, opts ...AuthCodeOption) (*Token, error) {
|
||||
v := url.Values{
|
||||
"grant_type": {"authorization_code"},
|
||||
"code": {code},
|
||||
"redirect_uri": internal.CondVal(c.RedirectURL),
|
||||
"scope": internal.CondVal(strings.Join(c.Scopes, " ")),
|
||||
})
|
||||
}
|
||||
if c.RedirectURL != "" {
|
||||
v.Set("redirect_uri", c.RedirectURL)
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt.setValue(v)
|
||||
}
|
||||
return retrieveToken(ctx, c, v)
|
||||
}
|
||||
|
||||
// Client returns an HTTP client using the provided token.
|
||||
|
@ -288,20 +332,20 @@ var HTTPClient internal.ContextKey
|
|||
// NewClient creates an *http.Client from a Context and TokenSource.
|
||||
// The returned client is not valid beyond the lifetime of the context.
|
||||
//
|
||||
// Note that if a custom *http.Client is provided via the Context it
|
||||
// is used only for token acquisition and is not used to configure the
|
||||
// *http.Client returned from NewClient.
|
||||
//
|
||||
// As a special case, if src is nil, a non-OAuth2 client is returned
|
||||
// using the provided context. This exists to support related OAuth2
|
||||
// packages.
|
||||
func NewClient(ctx context.Context, src TokenSource) *http.Client {
|
||||
if src == nil {
|
||||
c, err := internal.ContextClient(ctx)
|
||||
if err != nil {
|
||||
return &http.Client{Transport: internal.ErrorTransport{err}}
|
||||
}
|
||||
return c
|
||||
return internal.ContextClient(ctx)
|
||||
}
|
||||
return &http.Client{
|
||||
Transport: &Transport{
|
||||
Base: internal.ContextTransport(ctx),
|
||||
Base: internal.ContextClient(ctx).Transport,
|
||||
Source: ReuseTokenSource(nil, src),
|
||||
},
|
||||
}
|
||||
|
|
28
vendor/golang.org/x/oauth2/token.go
generated
vendored
28
vendor/golang.org/x/oauth2/token.go
generated
vendored
|
@ -5,13 +5,14 @@
|
|||
package oauth2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2/internal"
|
||||
)
|
||||
|
||||
|
@ -20,7 +21,7 @@ import (
|
|||
// expirations due to client-server time mismatches.
|
||||
const expiryDelta = 10 * time.Second
|
||||
|
||||
// Token represents the crendentials used to authorize
|
||||
// Token represents the credentials used to authorize
|
||||
// the requests to access protected resources on the OAuth 2.0
|
||||
// provider's backend.
|
||||
//
|
||||
|
@ -117,13 +118,16 @@ func (t *Token) Extra(key string) interface{} {
|
|||
return v
|
||||
}
|
||||
|
||||
// timeNow is time.Now but pulled out as a variable for tests.
|
||||
var timeNow = time.Now
|
||||
|
||||
// expired reports whether the token is expired.
|
||||
// t must be non-nil.
|
||||
func (t *Token) expired() bool {
|
||||
if t.Expiry.IsZero() {
|
||||
return false
|
||||
}
|
||||
return t.Expiry.Add(-expiryDelta).Before(time.Now())
|
||||
return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow())
|
||||
}
|
||||
|
||||
// Valid reports whether t is non-nil, has an AccessToken, and is not expired.
|
||||
|
@ -150,9 +154,25 @@ func tokenFromInternal(t *internal.Token) *Token {
|
|||
// This token is then mapped from *internal.Token into an *oauth2.Token which is returned along
|
||||
// with an error..
|
||||
func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) {
|
||||
tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v)
|
||||
tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v, internal.AuthStyle(c.Endpoint.AuthStyle))
|
||||
if err != nil {
|
||||
if rErr, ok := err.(*internal.RetrieveError); ok {
|
||||
return nil, (*RetrieveError)(rErr)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return tokenFromInternal(tk), nil
|
||||
}
|
||||
|
||||
// RetrieveError is the error returned when the token endpoint returns a
|
||||
// non-2XX HTTP status code.
|
||||
type RetrieveError struct {
|
||||
Response *http.Response
|
||||
// Body is the body that was consumed by reading Response.Body.
|
||||
// It may be truncated.
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (r *RetrieveError) Error() string {
|
||||
return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body)
|
||||
}
|
||||
|
|
91
vendor/golang.org/x/oauth2/transport.go
generated
vendored
91
vendor/golang.org/x/oauth2/transport.go
generated
vendored
|
@ -6,7 +6,7 @@ package oauth2
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
@ -25,15 +25,20 @@ type Transport struct {
|
|||
// Base is the base RoundTripper used to make HTTP requests.
|
||||
// If nil, http.DefaultTransport is used.
|
||||
Base http.RoundTripper
|
||||
|
||||
mu sync.Mutex // guards modReq
|
||||
modReq map[*http.Request]*http.Request // original -> modified
|
||||
}
|
||||
|
||||
// RoundTrip authorizes and authenticates the request with an
|
||||
// access token. If no token exists or token is expired,
|
||||
// tries to refresh/fetch a new token.
|
||||
// access token from Transport's Source.
|
||||
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
reqBodyClosed := false
|
||||
if req.Body != nil {
|
||||
defer func() {
|
||||
if !reqBodyClosed {
|
||||
req.Body.Close()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if t.Source == nil {
|
||||
return nil, errors.New("oauth2: Transport's Source is nil")
|
||||
}
|
||||
|
@ -44,31 +49,22 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|||
|
||||
req2 := cloneRequest(req) // per RoundTripper contract
|
||||
token.SetAuthHeader(req2)
|
||||
t.setModReq(req, req2)
|
||||
res, err := t.base().RoundTrip(req2)
|
||||
if err != nil {
|
||||
t.setModReq(req, nil)
|
||||
return nil, err
|
||||
}
|
||||
res.Body = &onEOFReader{
|
||||
rc: res.Body,
|
||||
fn: func() { t.setModReq(req, nil) },
|
||||
}
|
||||
return res, nil
|
||||
|
||||
// req.Body is assumed to be closed by the base RoundTripper.
|
||||
reqBodyClosed = true
|
||||
return t.base().RoundTrip(req2)
|
||||
}
|
||||
|
||||
// CancelRequest cancels an in-flight request by closing its connection.
|
||||
var cancelOnce sync.Once
|
||||
|
||||
// CancelRequest does nothing. It used to be a legacy cancellation mechanism
|
||||
// but now only it only logs on first use to warn that it's deprecated.
|
||||
//
|
||||
// Deprecated: use contexts for cancellation instead.
|
||||
func (t *Transport) CancelRequest(req *http.Request) {
|
||||
type canceler interface {
|
||||
CancelRequest(*http.Request)
|
||||
}
|
||||
if cr, ok := t.base().(canceler); ok {
|
||||
t.mu.Lock()
|
||||
modReq := t.modReq[req]
|
||||
delete(t.modReq, req)
|
||||
t.mu.Unlock()
|
||||
cr.CancelRequest(modReq)
|
||||
}
|
||||
cancelOnce.Do(func() {
|
||||
log.Printf("deprecated: golang.org/x/oauth2: Transport.CancelRequest no longer does anything; use contexts")
|
||||
})
|
||||
}
|
||||
|
||||
func (t *Transport) base() http.RoundTripper {
|
||||
|
@ -78,19 +74,6 @@ func (t *Transport) base() http.RoundTripper {
|
|||
return http.DefaultTransport
|
||||
}
|
||||
|
||||
func (t *Transport) setModReq(orig, mod *http.Request) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
if t.modReq == nil {
|
||||
t.modReq = make(map[*http.Request]*http.Request)
|
||||
}
|
||||
if mod == nil {
|
||||
delete(t.modReq, orig)
|
||||
} else {
|
||||
t.modReq[orig] = mod
|
||||
}
|
||||
}
|
||||
|
||||
// cloneRequest returns a clone of the provided *http.Request.
|
||||
// The clone is a shallow copy of the struct and its Header map.
|
||||
func cloneRequest(r *http.Request) *http.Request {
|
||||
|
@ -104,29 +87,3 @@ func cloneRequest(r *http.Request) *http.Request {
|
|||
}
|
||||
return r2
|
||||
}
|
||||
|
||||
type onEOFReader struct {
|
||||
rc io.ReadCloser
|
||||
fn func()
|
||||
}
|
||||
|
||||
func (r *onEOFReader) Read(p []byte) (n int, err error) {
|
||||
n, err = r.rc.Read(p)
|
||||
if err == io.EOF {
|
||||
r.runFunc()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *onEOFReader) Close() error {
|
||||
err := r.rc.Close()
|
||||
r.runFunc()
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *onEOFReader) runFunc() {
|
||||
if fn := r.fn; fn != nil {
|
||||
fn()
|
||||
r.fn = nil
|
||||
}
|
||||
}
|
||||
|
|
327
vendor/google.golang.org/cloud/compute/metadata/metadata.go
generated
vendored
327
vendor/google.golang.org/cloud/compute/metadata/metadata.go
generated
vendored
|
@ -1,327 +0,0 @@
|
|||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package metadata provides access to Google Compute Engine (GCE)
|
||||
// metadata and API service accounts.
|
||||
//
|
||||
// This package is a wrapper around the GCE metadata service,
|
||||
// as documented at https://developers.google.com/compute/docs/metadata.
|
||||
package metadata // import "google.golang.org/cloud/compute/metadata"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"google.golang.org/cloud/internal"
|
||||
)
|
||||
|
||||
type cachedValue struct {
|
||||
k string
|
||||
trim bool
|
||||
mu sync.Mutex
|
||||
v string
|
||||
}
|
||||
|
||||
var (
|
||||
projID = &cachedValue{k: "project/project-id", trim: true}
|
||||
projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
|
||||
instID = &cachedValue{k: "instance/id", trim: true}
|
||||
)
|
||||
|
||||
var metaClient = &http.Client{
|
||||
Transport: &internal.Transport{
|
||||
Base: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 750 * time.Millisecond,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
ResponseHeaderTimeout: 750 * time.Millisecond,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// NotDefinedError is returned when requested metadata is not defined.
|
||||
//
|
||||
// The underlying string is the suffix after "/computeMetadata/v1/".
|
||||
//
|
||||
// This error is not returned if the value is defined to be the empty
|
||||
// string.
|
||||
type NotDefinedError string
|
||||
|
||||
func (suffix NotDefinedError) Error() string {
|
||||
return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
|
||||
}
|
||||
|
||||
// Get returns a value from the metadata service.
|
||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||
//
|
||||
// If the GCE_METADATA_HOST environment variable is not defined, a default of
|
||||
// 169.254.169.254 will be used instead.
|
||||
//
|
||||
// If the requested metadata is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
func Get(suffix string) (string, error) {
|
||||
val, _, err := getETag(suffix)
|
||||
return val, err
|
||||
}
|
||||
|
||||
// getETag returns a value from the metadata service as well as the associated
|
||||
// ETag. This func is otherwise equivalent to Get.
|
||||
func getETag(suffix string) (value, etag string, err error) {
|
||||
// Using a fixed IP makes it very difficult to spoof the metadata service in
|
||||
// a container, which is an important use-case for local testing of cloud
|
||||
// deployments. To enable spoofing of the metadata service, the environment
|
||||
// variable GCE_METADATA_HOST is first inspected to decide where metadata
|
||||
// requests shall go.
|
||||
host := os.Getenv("GCE_METADATA_HOST")
|
||||
if host == "" {
|
||||
// Using 169.254.169.254 instead of "metadata" here because Go
|
||||
// binaries built with the "netgo" tag and without cgo won't
|
||||
// know the search suffix for "metadata" is
|
||||
// ".google.internal", and this IP address is documented as
|
||||
// being stable anyway.
|
||||
host = "169.254.169.254"
|
||||
}
|
||||
url := "http://" + host + "/computeMetadata/v1/" + suffix
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
req.Header.Set("Metadata-Flavor", "Google")
|
||||
res, err := metaClient.Do(req)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode == http.StatusNotFound {
|
||||
return "", "", NotDefinedError(suffix)
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
return "", "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url)
|
||||
}
|
||||
all, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return string(all), res.Header.Get("Etag"), nil
|
||||
}
|
||||
|
||||
func getTrimmed(suffix string) (s string, err error) {
|
||||
s, err = Get(suffix)
|
||||
s = strings.TrimSpace(s)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *cachedValue) get() (v string, err error) {
|
||||
defer c.mu.Unlock()
|
||||
c.mu.Lock()
|
||||
if c.v != "" {
|
||||
return c.v, nil
|
||||
}
|
||||
if c.trim {
|
||||
v, err = getTrimmed(c.k)
|
||||
} else {
|
||||
v, err = Get(c.k)
|
||||
}
|
||||
if err == nil {
|
||||
c.v = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var onGCE struct {
|
||||
sync.Mutex
|
||||
set bool
|
||||
v bool
|
||||
}
|
||||
|
||||
// OnGCE reports whether this process is running on Google Compute Engine.
|
||||
func OnGCE() bool {
|
||||
defer onGCE.Unlock()
|
||||
onGCE.Lock()
|
||||
if onGCE.set {
|
||||
return onGCE.v
|
||||
}
|
||||
onGCE.set = true
|
||||
|
||||
// We use the DNS name of the metadata service here instead of the IP address
|
||||
// because we expect that to fail faster in the not-on-GCE case.
|
||||
res, err := metaClient.Get("http://metadata.google.internal")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
onGCE.v = res.Header.Get("Metadata-Flavor") == "Google"
|
||||
return onGCE.v
|
||||
}
|
||||
|
||||
// Subscribe subscribes to a value from the metadata service.
|
||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||
//
|
||||
// Subscribe calls fn with the latest metadata value indicated by the provided
|
||||
// suffix. If the metadata value is deleted, fn is called with the empty string
|
||||
// and ok false. Subscribe blocks until fn returns a non-nil error or the value
|
||||
// is deleted. Subscribe returns the error value returned from the last call to
|
||||
// fn, which may be nil when ok == false.
|
||||
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||
const failedSubscribeSleep = time.Second * 5
|
||||
|
||||
// First check to see if the metadata value exists at all.
|
||||
val, lastETag, err := getETag(suffix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := fn(val, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ok := true
|
||||
suffix += "?wait_for_change=true&last_etag="
|
||||
for {
|
||||
val, etag, err := getETag(suffix + url.QueryEscape(lastETag))
|
||||
if err != nil {
|
||||
if _, deleted := err.(NotDefinedError); !deleted {
|
||||
time.Sleep(failedSubscribeSleep)
|
||||
continue // Retry on other errors.
|
||||
}
|
||||
ok = false
|
||||
}
|
||||
lastETag = etag
|
||||
|
||||
if err := fn(val, ok); err != nil || !ok {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ProjectID returns the current instance's project ID string.
|
||||
func ProjectID() (string, error) { return projID.get() }
|
||||
|
||||
// NumericProjectID returns the current instance's numeric project ID.
|
||||
func NumericProjectID() (string, error) { return projNum.get() }
|
||||
|
||||
// InternalIP returns the instance's primary internal IP address.
|
||||
func InternalIP() (string, error) {
|
||||
return getTrimmed("instance/network-interfaces/0/ip")
|
||||
}
|
||||
|
||||
// ExternalIP returns the instance's primary external (public) IP address.
|
||||
func ExternalIP() (string, error) {
|
||||
return getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
|
||||
}
|
||||
|
||||
// Hostname returns the instance's hostname. This will be of the form
|
||||
// "<instanceID>.c.<projID>.internal".
|
||||
func Hostname() (string, error) {
|
||||
return getTrimmed("instance/hostname")
|
||||
}
|
||||
|
||||
// InstanceTags returns the list of user-defined instance tags,
|
||||
// assigned when initially creating a GCE instance.
|
||||
func InstanceTags() ([]string, error) {
|
||||
var s []string
|
||||
j, err := Get("instance/tags")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// InstanceID returns the current VM's numeric instance ID.
|
||||
func InstanceID() (string, error) {
|
||||
return instID.get()
|
||||
}
|
||||
|
||||
// InstanceName returns the current VM's instance ID string.
|
||||
func InstanceName() (string, error) {
|
||||
host, err := Hostname()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.Split(host, ".")[0], nil
|
||||
}
|
||||
|
||||
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||
func Zone() (string, error) {
|
||||
zone, err := getTrimmed("instance/zone")
|
||||
// zone is of the form "projects/<projNum>/zones/<zoneName>".
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return zone[strings.LastIndex(zone, "/")+1:], nil
|
||||
}
|
||||
|
||||
// InstanceAttributes returns the list of user-defined attributes,
|
||||
// assigned when initially creating a GCE VM instance. The value of an
|
||||
// attribute can be obtained with InstanceAttributeValue.
|
||||
func InstanceAttributes() ([]string, error) { return lines("instance/attributes/") }
|
||||
|
||||
// ProjectAttributes returns the list of user-defined attributes
|
||||
// applying to the project as a whole, not just this VM. The value of
|
||||
// an attribute can be obtained with ProjectAttributeValue.
|
||||
func ProjectAttributes() ([]string, error) { return lines("project/attributes/") }
|
||||
|
||||
func lines(suffix string) ([]string, error) {
|
||||
j, err := Get(suffix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := strings.Split(strings.TrimSpace(j), "\n")
|
||||
for i := range s {
|
||||
s[i] = strings.TrimSpace(s[i])
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// InstanceAttributeValue returns the value of the provided VM
|
||||
// instance attribute.
|
||||
//
|
||||
// If the requested attribute is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
//
|
||||
// InstanceAttributeValue may return ("", nil) if the attribute was
|
||||
// defined to be the empty string.
|
||||
func InstanceAttributeValue(attr string) (string, error) {
|
||||
return Get("instance/attributes/" + attr)
|
||||
}
|
||||
|
||||
// ProjectAttributeValue returns the value of the provided
|
||||
// project attribute.
|
||||
//
|
||||
// If the requested attribute is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
//
|
||||
// ProjectAttributeValue may return ("", nil) if the attribute was
|
||||
// defined to be the empty string.
|
||||
func ProjectAttributeValue(attr string) (string, error) {
|
||||
return Get("project/attributes/" + attr)
|
||||
}
|
||||
|
||||
// Scopes returns the service account scopes for the given account.
|
||||
// The account may be empty or the string "default" to use the instance's
|
||||
// main account.
|
||||
func Scopes(serviceAccount string) ([]string, error) {
|
||||
if serviceAccount == "" {
|
||||
serviceAccount = "default"
|
||||
}
|
||||
return lines("instance/service-accounts/" + serviceAccount + "/scopes")
|
||||
}
|
Loading…
Reference in a new issue